Skip to content

feat(idef0): 3D isometric layered-overview minimap in the Map-view corner - #170

Merged
explosivebit merged 17 commits into
developfrom
feat/idef0-3d-iso-view
Jul 8, 2026
Merged

explosivebit merged 17 commits into
developfrom
feat/idef0-3d-iso-view

Conversation

@explosivebit

Copy link
Copy Markdown
Contributor

Summary

Replaces the 2D minimap in the Map view's bottom-right corner with a
lazy-loaded 3D isometric layered-overview minimap (exploded-pyramid IDEF0
stack). The other 8 graph views keep their unchanged 2D minimap; the main 2D
composed-map is untouched.

  • 3D corner widget (widgets/iso-map/, SOLID/FSD-decomposed): Threlte v8 +
    three, OrthographicCamera + OrbitControls, stacked isometric zone planes,
    node boxes, dashed frustum, depth control (1/2/3 + ascend) + show/hide toggle.
  • Bidirectional 3D↔2D drill sync via a new three-free shared-drill-bus
    singleton (plain-data focus chain): clicking a zone in 3D descends the 2D map
    and vice-versa; 3D always reflects the 2D focus. The 2D path never imports three.
  • Lazy load: three/@threlte load only on Map-view mount (dynamic import,
    browser-guarded, <svelte:boundary> fallback) — zero WebGL on the other views.
  • Bundle surgery: stubbed unused draco/basis loaders (−1.5 MB), pushed three
    out of SSR → dist 6.0 MB → 3.29 MiB (< 3.5 MiB cap).
  • Dropped the throwaway /iso-spike dev route — the corner minimap is the only surface.

Why

The composed-map's flat 2D minimap couldn't convey the layered depth structure
of the IDEF0 decomposition. The 3D exploded-pyramid overview shows the whole
altitude stack at a glance and stays in lock-step with the 2D drill state.

Driving Forgeplan chain (all active, guardian PASS):

  • PRD-039 — requirement (child of PRD-036 composed-map)
  • RFC-036 — lazy iso-map widget + shared-drill-bus design
  • ADR-011 — ship three.js+Threlte lazy chunk; raise dist cap 3→3.5 MiB
    (amends PRD-030 NFR-001 / SC-4 / rule 21)
  • Evidence EVID-099..107 (dist-cap, code-review + re-review, rule-22 security
    governance, render-proof, AC-3/AC-1 interaction proof, 2 guardian gates).

Test plan

  • svelte-check0 errors (8 pre-existing a11y warnings).
  • vitest798/798 pass (incl. 16 new shared-drill-bus + iso-view-state
    sync tests: idempotence, bidirectional sync, mid-animation convergence).
  • npm run buildPASS, dist 3.29 MiB < 3.5 MiB cap, both images;
    three isolated to a lazy client chunk, 0 markers in the SSR bundle.
  • Live Playwright interaction proof (EVID-106): depth 1/2/3 state change,
    ascend descend→climb→re-disable, show/hide toggle round-trip, and every
    non-Map view confirmed to keep its 2D minimap with three never mounted.
  • rule-22 security audit (EVID-104): 0 new server/network surface — the one
    new client GET consumes the already-allow-listed read-only /api/map/layers/<zone>.

Refs: PRD-039

🤖 Generated with Claude Code

explosivebit and others added 17 commits July 8, 2026 19:48
Throwaway /iso-spike route de-risking a true-3D IDEF0 exploded-pyramid map
view. Threlte v8 + three; R1 non-centered nesting (child plane explodes
under the parent zone-box, not centered), dashed MeshLine frustum
connectors (attenuate=false), ICOM boundary arrows via real classifyIcom
(ADR-007). Spike-scoped (// TODO(spike)); pre-RFC.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…stages

Checkpoint of the workflow build: IsoScene monolith split into ui/ (12
components), lib/ (4), model/ (1). Matte material, dynamic re-layering +
depthWindow accordion, node & layer hover-cards. 4 known svelte-check
implicit-any errors to fix next. Spike-scoped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…epthWindow

Thin translucent paper sheets (PLATE_THICKNESS/opacity down), hover
highlights individual element not whole sheet, leader-line cards gated
behind showInfoCards=false (minimap), windowPlanes root-anchored
(first N levels expand downward), dashed-connector depthTest/renderOrder
visibility fix, A11yProxy 3-kind union guard. svelte-check 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…reverse collapse

Clicking a zone explodes its sub-layer chain downward (R1 nesting),
dashed frustum connectors now render corner-to-corner (depthTest:false
+ renderOrder), breadcrumb + ascend, depthWindow caps depth. Fixed
each_key_duplicate in IsoA11yProxy (same node id across two expanded
planes). svelte-check 0, live-verified explode + connectors + 0 console.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…s shows

At depthWindow=2, descending into a deeper plane pushed the new level
past the display window, hiding it as a sliver until you manually bumped
the control to 3. Now focusZone grows depthWindow to min(3, chainLen+1)
after each descend, so the layer you click into is always expanded.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Dim/desaturate by distance-from-deepest (drilled-into plane stays full,
ancestors recede), wider PLANE_GAP, softer depth desaturation, ancestor
node boxes darken with depth. Partial declutter — spatial overlap from R1
nesting remains (needs a layout/camera decision, not just dimming).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Only the drilled-into (deepest) plane renders node boxes; ancestor
planes collapse to faint zone-frame outlines (context, not clutter).
At rest (root) the root still shows full detail; drilling fades context
to frames and details the focus. Clears the dense-node overlap.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move IsoScene + ui/ + lib/ + model/ into a widgets/iso-map/ slice
(internal structure preserved, relative imports intact). /iso-spike
route now imports from the widget (route->widget, FSD-legal). Prep for
mounting the 3D iso in the Map view's minimap corner. svelte-check 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
IsoMinimap (container-sized host reusing the shared mapPoller) + a lazy
IsoMapCorner wrapper; DependencyGraph shows it in the bottom-right corner
only on the Map view, keeping the 2D Minimap on the other 6 views. Main
2D ComposedMapView untouched. three/Threlte dynamic-imported (client
code-split). svelte-check 0, dev live-verified (Map view: 2D map + 3D
corner, 0 console errors).

KNOWN SHIP-BLOCKER: dist build = 6.0M vs 3M cap (three in SSR bundle +
unused draco/basis loaders from @threlte/extras). Bundle surgery next.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Kill unused @threlte/extras draco/basis loaders (~1.5M) via a vite alias
stub (vite/stubs/three-loaders.ts); ssr=false + browser-guarded dynamic
import for /iso-spike and IsoMapCorner so three is fully OUT of the SSR
server bundle (0 three markers in dist/index.js). Remaining over-cap is
three+threlte itself (808K, lazy client chunk). Still 0.29M over the 3M
cap — cap decision pending.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The 3D Map-view corner (three.js + Threlte, ~808K lazy client chunk)
pushes dist to ~3.4M. Cap raised to 3.5M per user decision; three is
loaded only when the Map view opens (deferred download, no cold-start
cost). TODO(iso-adr): amend PRD-030 NFR-005 via ADR before ship.

npm run build now passes: images built stable + nightly, dist 3.4M.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… only surface

The 3D iso view now lives entirely in widgets/iso-map, consumed by the
Map-view corner (IsoMapCorner). The /iso-spike dev route was a public
route that would have shipped in the app AND was the last SSR path
pulling three into the server bundle. Removing it: no user-facing
throwaway route, three fully client-lazy. Map corner live-verified,
npm run build passes (dist 3.4M), svelte-check 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…control toggle

New widgets/composed-map/model/shared-drill-bus.svelte.ts — a plain-data
module singleton holding the shared focus chain (NO three/@threlte import,
so the 2D/SSR path stays three-free). ComposedMapView (2D) and iso-view-
state (3D) both read/write it: descend/ascend in EITHER view drives the
other. 3D reflects + highlights the 2D's current focus and always shows
the current depth expanded. IsoControls (1/2/3+ascend) gains a hide/show
toggle. Live-verified both directions (3D zone-click -> 2D descends to
Decision Trail; 2D 'All' -> 3D resets to root), 0 console errors,
svelte-check 0, vite build green, three still lazy/code-split.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fix the build.mjs cap comment: the amended cap is PRD-030 NFR-001 / SC-4
/ rule 21 (not NFR-005 — that's the flag-lifecycle policy), and the
deliberate 3->3.5 MiB bump is now recorded in ADR-011. Resolves the
TODO(iso-adr) placeholder.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ry, doc/RFC drift

- HIGH: sync-drop race — 3D now records a pending focus-chain target when
  an update lands mid-animation and re-applies it on animation settle, so
  the 3D always converges to the 2D (RFC-036 NFR-004 / INV-E no-drift).
- MED: IsoMapCorner wraps the 3D mount in <svelte:boundary> so a runtime
  WebGL/init failure shows an honest fallback (FR-007), not a broken corner.
- docs: dropped the stale 'throwaway spike' comment, deduped the
  TODO(iso-promote) copies, removed the phantom TODO(iso-draco-basis),
  aligned shared-drill-bus public API names to the RFC-036 contract.
svelte-check 0, vitest 782/782, npm run build passes (dist 3.4M both images).
TODO: shared-drill-bus unit tests still owed (EVID-100 finding #2).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…D-100 #2)

16 new tests: shared-drill-bus reducer idempotence + bidirectional 3D<->2D
sync contract + mid-animation pending-retry convergence (the sync-drop-race
fix under test). vitest 782 -> 798, svelte-check 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Record + activate the Forgeplan artifact chain for the 3D isometric
layered-overview minimap shipped into the Map-view corner:

- PRD-039  requirement (child of PRD-036 composed-map)
- RFC-036  lazy iso-map widget, 2D-synced via three-free shared-drill-bus
- ADR-011  ship three.js+Threlte lazy chunk; raise dist cap 3->3.5 MiB
           (amends PRD-030 NFR-001 / SC-4 / rule 21)
- EVID-099..107  dist-cap build, code review + re-review, security
           rule-22 governance, render-proof, AC-3/AC-1 interaction proof,
           and two guardian gates (final: PASS, both prior gaps closed).

Guardian re-gate (EVID-107) PASS: R_eff>0 on all three, both EVID-105
gaps closed and verified in source, blast radius viewer-only + reversible.

Refs: PRD-039

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@explosivebit
explosivebit merged commit e29a005 into develop Jul 8, 2026
3 checks passed
@explosivebit
explosivebit deleted the feat/idef0-3d-iso-view branch July 8, 2026 21:44
explosivebit added a commit that referenced this pull request Jul 9, 2026
…oarding, 3D-iso) (#172)

## Summary

Release **v0.3.0** (MINOR) — cuts the entire IDEF0 composed-map program
from
`develop` to `main`. 152 commits since `v0.2.4`, no breaking changes.

Headline features landed since v0.2.4:
- **Composed-map (T4)** — the 9th "Map" graph view: curated zoned
composition
with render-proof against the `forgeplan.map/v1` contract (PRD-036 /
SPEC-006 / RFC-030).
- **Recursive drill-down** — descend/climb/breadcrumb into zones, prefer
map-pack-emitted per-zone layers with client-derived fallback (PRD-037 /
RFC-031).
- **Onboarding tour (Pillar B)** — `/onboard` route + deterministic
zone-walk
  camera tour (#167).
- **Live local-agent guide (Pillar C)** — daemon + Agent SDK + two-tier
chat
(Tier-0 map-grounded, Tier-1 live), floatable/dockable chat panel v2
(#169,
  PRD-038 / RFC-034 / RFC-035 / ADR-010).
- **3D isometric Map-corner minimap** — Threlte v8 lazy chunk,
bidirectional
3D↔2D drill sync, dist cap raised 3→3.5 MiB (#170, PRD-039 / RFC-036 /
ADR-011).

## Version bump

- `package.json` + `template/package.json`: `0.2.4` → `0.3.0`.

## Release checklist

- [x] Version bumped in both package manifests
- [ ] CI matrix (ubuntu / macos / windows) green on this PR
- [ ] Merge to `main` (merge commit)
- [ ] Annotated tag `v0.3.0` on `main` + push
- [ ] GitHub Release published (fires `release.yml` → npm with
provenance)
- [ ] Back-merge `release/v0.3.0` → `develop`

## Test plan

Full CI matrix on this PR must pass. No new code beyond the version
bump; all
feature work was already CI-verified on `develop` (each of
#167/#169/#170/#171
merged green).

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant