Adds per-overlay pattern fills so factions and regions can be visually
distinguished when they overlap (issue #25). Each faction note and each
region note now carries a pattern, scale, and opacity in its
frontmatter, edited via the existing FactionEditor / GeoRegionEditor
modals (dropdown + sliders + live preview swatch).
Pattern set (10 total): solid (the existing flat fill, default),
diagonal stripes ↗ / ↖, crosshatch, polka dots, grid, zigzag,
triangles, scales, checker.
On screen: SVG <pattern> defs are deduped per (key,color,scale) and
referenced from each overlay path's fill. Stroke stays solid color so
blob boundaries remain crisp. Per-overlay opacity replaces the
hardcoded 0.45 group opacity.
PNG export: mirrored via Canvas patterns built from an offscreen tile
per (key,color,scale), cached for the render pass.
Backwards compatible — overlays without the new frontmatter keys fall
back to solid + 0.45 opacity, matching pre-1.3.0 behavior.
makeDraggable previously used position: absolute with top/left 50%, which
relies on the nearest positioned ancestor being .modal-container. Any
plugin or theme that establishes a CSS containing block on an ancestor
(via transform/will-change/filter/contain) silently re-roots the modal
against that inner element, so it opens partway off-screen — as
reported in hexmaker#26.
Switch to position: fixed and compute the centered top/left in JS
against window.innerWidth/innerHeight, clamped 8px inside the viewport.
position: fixed bypasses most ancestor-containing-block issues; the JS
clamp catches the remaining edge cases (transformed ancestors that also
hijack fixed positioning).
Drag listeners now bind to modalEl.ownerDocument so dragging works
correctly inside popout windows.
Setup wizard now generates the terrain description/encounter tables and
roller-link preamble as part of Step 3, so freshly onboarded vaults have
the full table scaffolding ready to use.
New "Coordinate placement" setting (top/middle/bottom, default bottom)
controls where the x_y label sits inside each hex, addressing
hexmaker#22 — keeps the label from clashing with a centered terrain
icon.
- Sentence-case: rephrase "GM" → "Game master"; remove disable comments;
autofixer lowercases "🎲 Open tables view" / "← Back" to comply
- no-static-styles-assignment: dynamic colors now use CSS custom properties
(--duckmage-bg / --duckmage-border-color / --duckmage-fg) consumed by
existing classes; static positions moved to small modifier classes
(duckmage-rt-roll-btn-spaced, duckmage-wf-steps-list, etc.); terrain
toolbar uses is-terrain-preview / is-eyedropper-active toggles;
createIconEl uses new duckmage-masked-icon class
- Popout-window compat: setTimeout / clearTimeout / requestAnimationFrame
→ window.X; document.X → activeDocument.X across all view/modal files
- Unnecessary `as ArrayBuffer`: replace `data.buffer.slice(...) as ArrayBuffer`
with `new ArrayBuffer + Uint8Array.set` — gets a real ArrayBuffer without
the assertion (also avoids ArrayBufferLike narrowing)
- Deprecated SettingTab.display(): extract body into private renderSettings();
display() and post-action refresh both call it
- eslint.config: add activeDocument + activeWindow to globals so the renamed
identifiers don't trip no-undef
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a unified export pipeline under src/export/ with exporters for single notes,
structured hexes, maps (with reference table), random tables, and workflows
(with rolled samples). PDF rendering reuses Obsidian's MarkdownRenderer + theme
CSS; map PNG/PDF goes through a dedicated canvas renderer.
UI surface:
- "Export" tab in MapModal (PNG/PDF with overlay + size options)
- "Export" link in HexEditorModal + HexExportModal
- "Export PDF/Markdown" links in RandomTableView header
- "Export…" button in WorkflowEditorModal + WorkflowExportModal
- Commands: export current note (PDF/MD), current hex, current workflow
- File-menu items on any .md file: Export to PDF / Markdown
Other:
- New `exportFolder` setting (defaults to {worldFolder}/exports)
- hexGeometry: add hexSize / hexCenter / hexPolygonPoints / gridBoundingBox
- HexTableView + HexEditorModal: first-wins on duplicate palette names
(matches HexMapView's .find() behaviour)
- Tests: unit + integration suites for all exporters; sim-vault fixture
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
feat: Ctrl/Cmd+click hex to open submap in new tab
When no drawing tool is active, Ctrl+click (Cmd+click on Mac) on a hex
with a linked submap opens that submap in a new Obsidian tab. Regular
left-click navigation (same tab) is unchanged.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
feat: tabbed Maps modal; faction hover tooltip; map starting coordinates; default map/submap sizes in settings
- Maps modal refactored into three tabs: Maps (switch/delete), Properties (rename, terrain theme), New map (labeled fields, size presets)
- Faction overlay hover shows each faction on its own line with color swatch via custom floating tooltip div
- New map and submap creation accept starting X/Y coordinates; hex filenames and labels both reflect the chosen origin (gridOffset initialized accordingly)
- Map switching via modal now goes through switchToMap so viewport save/restore applies correctly
- Added defaultNewMapCols/Rows and defaultSubmapCols/Rows settings; new-map forms pre-fill from these
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Right-click context menu shows "Open submap: <name>" when the hex has
a duckmage-submap link; clicking calls navigateToMap so Back works.
- switchToMap now saves/restores per-map viewport (zoom, panX, panY,
fontSize). First visit to a map fits the full grid into view via
fitGridToView(); subsequent visits restore the last-known position.
- fitGridToView resets the baked font-size before measuring so the
scale calculation is always relative to the base font size.
- Fix: navigating Back was landing off-map because bakeZoom() encodes
the visual zoom into viewportEl.style.fontSize and resets this.zoom=1.
Saving/restoring fontSize alongside zoom/pan prevents the submap's
baked scale from bleeding into the parent map's viewport.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wire up delegated click handler on the rendered markdown container so
.internal-link anchors (produced by MarkdownRenderer) open the target
note in a new tab via openLinkText. Previously the links rendered
visually but did nothing on click.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- folder tree view in link-table modal (collapsed by default, filter expands all)
- shared renderFolderTree utility; RandomTableView refactored to use it
- submap picker: filterable list replaces combo-dropdown; terrain theme swatch per map
- map terrain theme: per-map terrainType field drives submap center-dot color and swatch in switch-map list
- erase mode for paths/factions/regions: "Remove" tile + enters erase immediately
- submap link tool: blip animation on hex after linking
- hex map view header updates to active map name on switch
- fix: link-table modal scopes folder tree to tablesFolder only (was leaking vault-wide folders)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Tokens placed per-hex link to vault notes; support circle/square shape,
sm/md/lg size, fill color, optional border color, icon, and description
- TokenInfoModal shows note content (formatted via MarkdownRenderer, images
included) with jump-to-hex, open-note, edit, and two-step remove actions
- Edit flow reopens TokenModal pre-filled; proxy notes handle multiple tokens
referencing the same source note
- Icon picker replaced with scrollable palette grid (2-row cap, drag-to-reorder,
hide/show) in both HexEditorModal and TokenModal; order persisted in settings
- Token layer toggle added to layers menu (default on)
- Fix metadata-cache race on token delete (wasToken check prevents missed updates)
- Token preview rendered inline in TokenModal title row; real-time color preview
via native input event on color pickers
- Bump version to 1.1.6
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix map pixelation on zoom: bake CSS scale() into viewport font-size after
scroll wheel settles so the DOM renders natively at the zoomed resolution
instead of upscaling a compositor bitmap; redraw SVG overlays after bake
- Fix terrain brush size persisting when switching to icon tool: reset
paintBrushSize to 1 on icon mode entry
- Add shrink (−) buttons paired with each expand (+) button: fade in on hover,
positioned to the right for top/bottom and below for left/right; clicking a
clean row/col shrinks immediately and trashes the hex notes; clicking a dirty
row/col shows a red OK? confirm state (3 s timeout) before deleting
- Fix stale terrain showing after delete+re-expand: pass null terrain/icon
overrides for newly-added edge hexes so cached frontmatter from deleted files
cannot bleed through
- Add iconsFolder to onboarding wizard folder generation step
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Override onExternalSettingsChange() so Obsidian Sync delivering a new
data.json from another device immediately reloads settings and refreshes
all open HexMapView and HexTableView instances — no manual restart needed
- Add autoRegisterMapsFromVault() on startup: scans hexFolder subfolders and
registers any that are missing from settings.maps, inferring grid size and
offset from the x_y.md filenames. Handles the case where data.json arrives
stale or empty but the vault folders already exist (e.g. sync timing, first
install on a new device)
Closes#4
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace hover-fade "Delete" button with a fixed 20×20px ✕ button always
visible in each map row
- Hide the ✕ entirely when only one map remains (deletion blocked)
- Remove red background from confirmation row; use muted text instead
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New SetupWizardView (ItemView): 4-step welcome → folders → map → done
- Wizard auto-opens on first install (setupComplete/setupDismissed flags)
- Folder step creates all world subfolders and ensures hex template exists
- Map step creates the first hex grid; done step shows recommended next steps
- "Open hex map" from done step opens map with terrain picker + toolbar open
- Re-run wizard button added to settings tab
- Fix: loadAvailableIcons() now runs inside onLayoutReady (vault readiness)
- Fix: migrateHexFilesToDefaultRegion() no longer creates world/hexes/default
on fresh installs — scans candidates first, early-returns if none found
- Fix: loadHexTemplate() falls back to built-in default instead of returning null
- Fix: terrain toolbar button re-opens picker when clicked while active
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove unnecessary type assertions in IconPickerModal (createEl("input") already returns HTMLInputElement)
- Fix sentence-case violation: "Remove GM icon" → "Remove icon" in HexEditorModal tooltip
- Annotate frontmatter["region"] accesses as unknown to satisfy no-unsafe-assignment
- Wire npm run lint into /rebuild command so issues are caught locally before submission
- Document no-unnecessary-type-assertion and mid-sentence acronym patterns in /lint guidance
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>