@vibecook/ice 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/README.md +37 -2
  2. package/dist/chunk-5SJYHQI4.js +636 -0
  3. package/dist/chunk-5SJYHQI4.js.map +1 -0
  4. package/dist/{chunk-5S7GSXJG.js → chunk-DXU3RZZS.js} +2913 -1180
  5. package/dist/chunk-DXU3RZZS.js.map +1 -0
  6. package/dist/{chunk-FIAXPNNY.js → chunk-IASTQMU5.js} +130 -551
  7. package/dist/chunk-IASTQMU5.js.map +1 -0
  8. package/dist/{chunk-BCJ47SX7.js → chunk-OR5FNVUE.js} +460 -1
  9. package/dist/chunk-OR5FNVUE.js.map +1 -0
  10. package/dist/devtools.js +508 -372
  11. package/dist/devtools.js.map +1 -1
  12. package/dist/dom.js +3 -11
  13. package/dist/ground.js +715 -0
  14. package/dist/ground.js.map +1 -0
  15. package/dist/index.js +70 -2
  16. package/dist/kernel.js +31 -1
  17. package/dist/r3f.js +599 -62
  18. package/dist/r3f.js.map +1 -1
  19. package/dist/react.js +34 -418
  20. package/dist/react.js.map +1 -1
  21. package/dist/types/packages/core/src/catalog/camera-derived.d.ts +41 -3
  22. package/dist/types/packages/core/src/catalog/gesture.d.ts +39 -3
  23. package/dist/types/packages/core/src/catalog/graph.d.ts +7 -6
  24. package/dist/types/packages/core/src/catalog/index.d.ts +1 -0
  25. package/dist/types/packages/core/src/catalog/insert.d.ts +31 -0
  26. package/dist/types/packages/core/src/catalog/pointer.d.ts +11 -0
  27. package/dist/types/packages/core/src/catalog/scene.d.ts +37 -4
  28. package/dist/types/packages/core/src/catalog/selection-presence.d.ts +7 -0
  29. package/dist/types/packages/core/src/catalog/settings-resources.d.ts +21 -0
  30. package/dist/types/packages/core/src/doc/autosave.d.ts +15 -2
  31. package/dist/types/packages/core/src/doc/bootstrap.d.ts +29 -0
  32. package/dist/types/packages/core/src/doc/channels.d.ts +9 -0
  33. package/dist/types/packages/core/src/doc/doc-commit-sink.d.ts +2 -1
  34. package/dist/types/packages/core/src/doc/doc-kit.d.ts +16 -1
  35. package/dist/types/packages/core/src/doc/envelope.d.ts +2 -1
  36. package/dist/types/packages/core/src/doc/migrate.d.ts +8 -6
  37. package/dist/types/packages/core/src/doc/schema-migrate.d.ts +50 -0
  38. package/dist/types/packages/core/src/doc/version-gate.d.ts +3 -0
  39. package/dist/types/packages/core/src/engine/commit-sink.d.ts +24 -2
  40. package/dist/types/packages/core/src/engine/frame-info.d.ts +16 -1
  41. package/dist/types/packages/core/src/facade/create-canvas-engine.d.ts +70 -6
  42. package/dist/types/packages/core/src/guards/guarded-tx.d.ts +4 -2
  43. package/dist/types/packages/core/src/helpers/churn-guard.d.ts +40 -0
  44. package/dist/types/packages/core/src/index.d.ts +13 -7
  45. package/dist/types/packages/core/src/input/queue.d.ts +11 -0
  46. package/dist/types/packages/core/src/nav/nested-canvas.d.ts +47 -11
  47. package/dist/types/packages/core/src/ops/arrange.d.ts +15 -0
  48. package/dist/types/packages/core/src/ops/insert.d.ts +62 -0
  49. package/dist/types/packages/core/src/ops/point-pick.d.ts +11 -7
  50. package/dist/types/packages/core/src/ops/sibling-order.d.ts +70 -0
  51. package/dist/types/packages/core/src/schema/meta.d.ts +1 -0
  52. package/dist/types/packages/core/src/settings/defaults.d.ts +45 -0
  53. package/dist/types/packages/core/src/settings/ground-config.d.ts +55 -0
  54. package/dist/types/packages/core/src/systems/chrome.d.ts +6 -2
  55. package/dist/types/packages/core/src/systems/insert-ghost.d.ts +25 -0
  56. package/dist/types/packages/core/src/systems/l1-pick.d.ts +25 -11
  57. package/dist/types/packages/core/src/systems/l2-recognize.d.ts +10 -4
  58. package/dist/types/packages/core/src/systems/l3-behave.d.ts +6 -4
  59. package/dist/types/packages/core/src/systems/l3-claim.d.ts +7 -3
  60. package/dist/types/packages/core/src/systems/l3-drop.d.ts +3 -1
  61. package/dist/types/packages/core/src/systems/l3-resize.d.ts +3 -1
  62. package/dist/types/packages/core/src/systems/l3-snap.d.ts +25 -7
  63. package/dist/types/packages/core/src/systems/nav-flight.d.ts +95 -0
  64. package/dist/types/packages/core/src/widget/define-widget.d.ts +39 -0
  65. package/dist/types/packages/core/src/widget/mount-store.d.ts +11 -3
  66. package/dist/types/packages/core/src/widget/set-props.d.ts +16 -0
  67. package/dist/types/packages/core/src/widget/spawn.d.ts +21 -1
  68. package/dist/types/packages/devtools/src/attach.d.ts +77 -0
  69. package/dist/types/packages/devtools/src/dock.d.ts +38 -0
  70. package/dist/types/packages/devtools/src/gl-panel.d.ts +69 -0
  71. package/dist/types/packages/devtools/src/index.d.ts +8 -6
  72. package/dist/types/packages/dom/src/index.d.ts +1 -3
  73. package/dist/types/packages/dom/src/measure-wiring.d.ts +2 -2
  74. package/dist/types/packages/dom/src/pointer-adapter.d.ts +21 -1
  75. package/dist/types/packages/dom/src/reflectors/dom-widgets.d.ts +5 -0
  76. package/dist/types/packages/ground/src/index.d.ts +52 -0
  77. package/dist/types/packages/ground/src/layer.d.ts +40 -0
  78. package/dist/types/packages/ground/src/pass.d.ts +41 -0
  79. package/dist/types/packages/ground/src/passes/grid.d.ts +21 -0
  80. package/dist/types/packages/ground/src/passes/guides-collect.d.ts +14 -0
  81. package/dist/types/packages/ground/src/passes/guides.d.ts +3 -0
  82. package/dist/types/packages/ground/src/passes/soup-collect.d.ts +35 -0
  83. package/dist/types/packages/ground/src/passes/soup-mesh.d.ts +8 -0
  84. package/dist/types/packages/ground/src/passes/wires-collect.d.ts +31 -0
  85. package/dist/types/packages/ground/src/passes/wires.d.ts +10 -0
  86. package/dist/types/packages/ground/src/renderer.d.ts +15 -0
  87. package/dist/types/packages/ice/src/ground.d.ts +1 -0
  88. package/dist/types/packages/kernel/src/bezier.d.ts +15 -0
  89. package/dist/types/packages/kernel/src/coords.d.ts +15 -0
  90. package/dist/types/packages/kernel/src/easing.d.ts +11 -0
  91. package/dist/types/packages/kernel/src/index.d.ts +3 -0
  92. package/dist/types/packages/kernel/src/layout.d.ts +118 -0
  93. package/dist/types/packages/kernel/src/nav-flight.d.ts +93 -0
  94. package/dist/types/packages/r3f/src/bridge.d.ts +73 -12
  95. package/dist/types/packages/r3f/src/composite-material.d.ts +9 -0
  96. package/dist/types/packages/r3f/src/compositor-pass.d.ts +22 -0
  97. package/dist/types/packages/r3f/src/gl-root.d.ts +76 -1
  98. package/dist/types/packages/r3f/src/gl-router.d.ts +10 -0
  99. package/dist/types/packages/r3f/src/index.d.ts +3 -2
  100. package/dist/types/packages/r3f/src/island-state.d.ts +44 -0
  101. package/dist/types/packages/r3f/src/preview-capture.d.ts +19 -0
  102. package/dist/types/packages/r3f/src/self-sustain.d.ts +39 -0
  103. package/dist/types/packages/r3f/src/use-island-frame.d.ts +16 -1
  104. package/dist/types/packages/react/src/engine-context.d.ts +8 -0
  105. package/dist/types/packages/react/src/index.d.ts +4 -2
  106. package/dist/types/packages/react/src/infinite-canvas.d.ts +40 -6
  107. package/dist/types/packages/react/src/preview-snapshots.d.ts +17 -0
  108. package/dist/types/packages/react/src/widget-preview.d.ts +14 -0
  109. package/package.json +13 -8
  110. package/dist/chunk-5S7GSXJG.js.map +0 -1
  111. package/dist/chunk-BCJ47SX7.js.map +0 -1
  112. package/dist/chunk-FIAXPNNY.js.map +0 -1
  113. package/dist/types/packages/devtools/src/panel.d.ts +0 -48
  114. package/dist/types/packages/dom/src/reflectors/grid.d.ts +0 -63
  115. package/dist/types/packages/dom/src/reflectors/wires.d.ts +0 -88
package/dist/r3f.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../r3f/src/island-state.ts","../../r3f/src/dev-write-trap.ts","../../r3f/src/bridge.ts","../../r3f/src/compositor-pass.ts","../../r3f/src/gl-root.tsx","../../r3f/src/composite-material.ts","../../r3f/src/island.tsx","../../r3f/src/use-island-frame.ts","../../r3f/src/pool.ts","../../r3f/src/resource-registry.ts","../../r3f/src/gl-router.ts"],"sourcesContent":["/**\n * Module-side island render state (design-004 §3 fix #3: ZERO render→ECS\n * writes — v1 kept this as an ECS component `R3FRenderState` and wrote it\n * from inside `useFrame`, which the engine laws ban; band/generation/paint\n * bookkeeping now lives here, outside the world entirely).\n *\n * One entry per GL widget the compositor has ever touched this session.\n * Entries OUTLIVE island unmount (cull) — that is the retention decoupling:\n * a culled widget's entry keeps its `fboGeneration`/`paintedAt` so re-entry\n * composites from the retained texture (phase Warm) instead of re-waking.\n * Entries die only on entity death, world reset, or `drop()`.\n *\n * Pure state + counters; no three.js, no ECS, no timing — the GLViews frame\n * pass reads/writes it synchronously.\n */\nimport type { IslandPhase } from \"@ice/kernel\";\n\n/** Resolution + band an island's FBO was last painted at (v1 `paintedAt`). */\nexport interface PaintedAt {\n readonly w: number;\n readonly h: number;\n readonly dpr: number;\n /** The zoom BAND painted at (not live zoom) — hysteresis compares against it. */\n readonly band: number;\n}\n\nexport interface IslandRenderState {\n phase: IslandPhase;\n /** Bumped by dirt (props Tier-3, size dirt, manual invalidate). */\n paintGeneration: number;\n /** Generation last painted into the FBO; -1 = no valid texture (fresh or evicted). */\n fboGeneration: number;\n paintedAt: PaintedAt;\n /** Live `useIslandFrame` subscriptions (animation signal while > 0). */\n animRefs: number;\n /** The widget type declared `animated` (repaint every visible frame). */\n animatedDecl: boolean;\n /**\n * Monotonic stamp of the last repaint — the stagger's FAIRNESS key. Without\n * it, more Hot islands than maxRepaintsPerFrame starves the same island\n * every pass (5 Hot vs cap 4 froze the shapes card, 2026-07-12).\n */\n lastPaintSeq: number;\n /**\n * Composite-quad scale (lift-on-hold): scales the CARD on the canvas —\n * texture, rounded alpha corners and all — instead of the scene content\n * (which the card-sized frustum would crop into hard corners, 2026-07-12\n * field report). ≠1 also pops render order over neighbors.\n */\n compositeScale: number;\n}\n\nconst FRESH_PAINTED_AT: PaintedAt = { w: 0, h: 0, dpr: 1, band: 0 };\n\nexport interface IslandStateStore {\n /** Get-or-create (Cold, unpainted). */\n ensure(key: number): IslandRenderState;\n get(key: number): IslandRenderState | undefined;\n all(): IterableIterator<[number, IslandRenderState]>;\n /** Island dirt: the next frame pass must repaint this island. */\n bumpPaint(key: number): void;\n markPainted(key: number, at: PaintedAt): void;\n /** FBO released (eviction/death): the quad hides until first repaint. */\n markEvicted(key: number): void;\n addAnimRef(key: number): void;\n removeAnimRef(key: number): void;\n /** Animation signal: declared `animated` OR any live `useIslandFrame`. */\n isAnimating(key: number): boolean;\n setAnimatedDecl(key: number, animated: boolean): void;\n drop(key: number): void;\n clear(): void;\n}\n\nexport function createIslandStateStore(): IslandStateStore {\n const entries = new Map<number, IslandRenderState>();\n let paintSeq = 0;\n\n const ensure = (key: number): IslandRenderState => {\n let s = entries.get(key);\n if (s === undefined) {\n s = {\n phase: \"Cold\",\n paintGeneration: 0,\n fboGeneration: -1,\n paintedAt: FRESH_PAINTED_AT,\n animRefs: 0,\n animatedDecl: false,\n lastPaintSeq: 0,\n compositeScale: 1,\n };\n entries.set(key, s);\n }\n return s;\n };\n\n return {\n ensure,\n get: (key) => entries.get(key),\n all: () => entries.entries(),\n bumpPaint(key) {\n ensure(key).paintGeneration += 1;\n },\n markPainted(key, at) {\n const s = ensure(key);\n s.fboGeneration = s.paintGeneration;\n s.paintedAt = at;\n s.lastPaintSeq = ++paintSeq;\n },\n markEvicted(key) {\n const s = entries.get(key);\n if (s !== undefined) s.fboGeneration = -1;\n },\n addAnimRef(key) {\n ensure(key).animRefs += 1;\n },\n removeAnimRef(key) {\n const s = entries.get(key);\n if (s !== undefined && s.animRefs > 0) s.animRefs -= 1;\n },\n isAnimating(key) {\n const s = entries.get(key);\n return s !== undefined && (s.animatedDecl || s.animRefs > 0);\n },\n setAnimatedDecl(key, animated) {\n ensure(key).animatedDecl = animated;\n },\n drop(key) {\n entries.delete(key);\n },\n clear() {\n entries.clear();\n },\n };\n}\n","/**\n * The zero-render→ECS-writes DEV assertion (M7 exit criterion; design-004 §3\n * fix #3). While a compositor frame pass runs — including island paints and\n * `useIslandFrame` callbacks — every world mutation throws with attribution.\n *\n * strata 0.4.0 (petition 4 LANDED): one persistent `world.devOnWrite`\n * registration + an armed flag. The hook is DEV-only, synchronous, and\n * PRE-MUTATION with throws propagating to the mutator's caller — so a throw\n * while armed is a clean veto whose stack names the offender. Fired from\n * strata's internal chokepoints, it covers every route the old own-property\n * mutator shadows could miss: bound/destructured method references, document\n * transactions, sync/attach drains, undo echoes, and any mutator added\n * upstream later. (Raw `batch.col()` column pokes remain the documented\n * carve-out — no chokepoint exists by design.)\n *\n * `enabled` is the app-side production gate the 0.4.0 notes ask for: in an\n * un-shimmed browser production bundle strata's own DEV flag can evaluate\n * true, so registration is gated HERE (default off; demos/traces opt in).\n */\nimport type { World } from \"@ice/core\";\n\nexport interface RenderWriteTrap {\n /** Arm the trap (begin twice without end is a bug — throws). */\n begin(): void;\n /** Disarm; always call in `finally`. */\n end(): void;\n /** Unregister the hook entirely (bridge teardown). */\n dispose(): void;\n readonly enabled: boolean;\n}\n\nexport function createRenderWriteTrap(world: World, enabled: boolean): RenderWriteTrap {\n let armed = false;\n let unregister: (() => void) | null = null;\n\n if (enabled) {\n unregister = world.devOnWrite((kind) => {\n if (!armed) return;\n throw new Error(\n `ice: world mutation (${kind}) during the GL render pass — the render path never writes ECS (design-004 §3). Move the write to a system, an input fact, or an app op OUTSIDE useIslandFrame/render.`,\n );\n });\n }\n\n return {\n enabled,\n begin() {\n if (!enabled) return;\n if (armed) throw new Error(\"ice: render write trap begin() while already armed.\");\n armed = true;\n },\n end() {\n armed = false;\n },\n dispose() {\n armed = false;\n unregister?.();\n unregister = null;\n },\n };\n}\n","/**\n * The GL bridge — the engine↔R3F seam (design-004 §3, two-level invalidation).\n *\n * Owns everything ENGINE-facing: the module-side island state, the island\n * registry (scene+camera handles the frame pass iterates), per-island dirt\n * observers, the `r3fInvalidator` reflector, `useIslandFrame` callbacks, the\n * render write trap, and entity-death cleanup. Everything GL-facing (FBO\n * pool, quads, the actual passes) lives in `GLViews`, whose lifetime is the\n * Canvas/context's — the bridge outlives Canvas remounts (HMR) and carries\n * the invalidation wiring across them.\n *\n * Two-level invalidation, mechanized:\n * - COMPOSITE dirt (cheap — re-run the frame pass, sample cached textures):\n * camera/viewport via the reflector; per-island Position/StackZ Tier-3;\n * island enter/exit via register/unregister. All call `requestFrame()`.\n * - ISLAND dirt (expensive — repaint the FBO): per-island props-group and\n * Size Tier-3 → `bumpPaint()` + `requestFrame()`; the animation signal\n * (declared `animated` / live `useIslandFrame` refs) and band crossings\n * are evaluated IN the frame pass (band repaints suppressed while\n * `Camera.gesturing`; the gesture-end camera write re-fires the reflector,\n * so the once-at-gesture-end repaint needs no extra machinery).\n *\n * Runtime-three-free (type-only imports): unit tests drive the bridge with a\n * real world and fake scene/camera handles, no GL context.\n */\nimport type { OrthographicCamera, Scene } from \"three\";\nimport {\n Camera,\n PrefabId,\n Position,\n Size,\n StackZ,\n Viewport,\n widgets,\n type Engine,\n type Entity,\n} from \"@ice/core\";\nimport { createIslandStateStore, type IslandStateStore } from \"./island-state\";\nimport { createRenderWriteTrap, type RenderWriteTrap } from \"./dev-write-trap\";\n\nexport interface IslandHandle {\n readonly scene: Scene;\n readonly camera: OrthographicCamera;\n}\n\n/** `useIslandFrame` callback: dt in ms, fired only on frames its island paints. */\nexport type IslandFrameCallback = (dtMs: number) => void;\n\nexport interface GLBridgeOpts {\n /** Arm the zero-render→ECS-writes trap (DEV builds / traces). Default false. */\n readonly devAssertRenderWrites?: boolean;\n}\n\nexport interface GLBridge {\n readonly engine: Engine;\n readonly state: IslandStateStore;\n readonly renderAssert: RenderWriteTrap;\n /**\n * Island mount (the `<Island>` component): registers the scene/camera pair,\n * stamps `animatedDecl` from the widget type, and arms the per-island dirt\n * observers. The returned cleanup removes handle + observers ONLY — state\n * and any pooled FBO survive (retention is decoupled from cull; they die on\n * entity death, reset, or eviction).\n */\n registerIsland(entity: Entity, handle: IslandHandle): () => void;\n islandFor(entity: Entity): IslandHandle | undefined;\n islands(): IterableIterator<[Entity, IslandHandle]>;\n /** Subscribe a paint-time callback; holds an animation ref while live. */\n addFrameCallback(entity: Entity, cb: IslandFrameCallback): () => void;\n frameCallbacksFor(entity: Entity): readonly IslandFrameCallback[];\n /** Composite invalidation — schedule a frame pass (coalesced). */\n requestFrame(): void;\n /** Island invalidation — this island must repaint (props/size/manual dirt). */\n bumpPaint(entity: Entity): void;\n /** Composite-quad lift scale (1 = rest). Scales the CARD on the canvas, corners intact. */\n setCompositeScale(entity: Entity, scale: number): void;\n /** GLViews wires R3F's demand-loop `invalidate` here (null on unmount). */\n setInvalidate(fn: (() => void) | null): void;\n /** Tear down reflector + observers + state (doc close / app teardown). */\n uninstall(): void;\n}\n\nexport function createGLBridge(engine: Engine, opts: GLBridgeOpts = {}): GLBridge {\n const world = engine.world;\n const state = createIslandStateStore();\n const islands = new Map<Entity, IslandHandle>();\n const frameCbs = new Map<Entity, Set<IslandFrameCallback>>();\n const renderAssert = createRenderWriteTrap(world, opts.devAssertRenderWrites === true);\n\n // --- composite invalidation plumbing --------------------------------------\n let invalidate: (() => void) | null = null;\n let pending = false; // a requestFrame that arrived before GLViews mounted\n const requestFrame = (): void => {\n if (invalidate !== null) invalidate();\n else pending = true;\n };\n\n // Camera (pan/zoom/gesturing edges) + viewport (resize/dpr) are the global\n // composite dirt sources; everything entity-shaped is observed per island\n // (only GL widgets wake the canvas — a static GL board ignores DOM churn).\n const removeReflector = engine.registerReflector({\n name: \"r3fInvalidator\",\n observe: { resources: [Camera, Viewport] },\n flush: () => requestFrame(),\n });\n\n // Death/reset: drop state so the frame pass releases the pooled FBO on its\n // next reconcile (the bridge is three-free — it never touches the pool).\n const removeWorldObserver = world.observe({\n onDestroy: (e) => {\n if (state.get(e as Entity) !== undefined) {\n state.drop(e as Entity);\n frameCbs.delete(e as Entity);\n requestFrame();\n }\n },\n onReset: () => {\n state.clear();\n frameCbs.clear();\n requestFrame();\n },\n });\n\n return {\n engine,\n state,\n renderAssert,\n\n registerIsland(entity, handle) {\n islands.set(entity, handle);\n const s = state.ensure(entity);\n\n // `animated` declaration comes from the widget type (design-004 §3\n // animation contract — explicit opt-in; plain useFrame is unattributable).\n const type = world.get(entity, PrefabId)?.id;\n const widget = typeof type === \"string\" ? widgets.get(type) : undefined;\n state.setAnimatedDecl(entity, widget?.animated === true);\n\n // Per-island dirt (Tier-3, equality-suppressed, fired at notify()):\n const unsubs: (() => void)[] = [\n // island dirt — content resolution/props changed, FBO stale:\n world.reactive.observeValue(entity, Size, () => {\n state.bumpPaint(entity);\n requestFrame();\n }),\n // composite dirt — quad transform/order changed, texture still good:\n world.reactive.observeValue(entity, Position, () => requestFrame()),\n world.reactive.observeValue(entity, StackZ, () => requestFrame()),\n ];\n for (const group of widget?.groups ?? []) {\n unsubs.push(\n world.reactive.observeValue(entity, group.component, () => {\n state.bumpPaint(entity);\n requestFrame();\n }),\n );\n }\n\n // A re-entering island with a retained FBO composites immediately\n // (Warm); a fresh one is Waking — either way the pass must run.\n if (s.fboGeneration < 0) state.bumpPaint(entity);\n requestFrame();\n\n return () => {\n for (const u of unsubs) u();\n islands.delete(entity);\n requestFrame(); // exit dirt: the quad may need to hide/recompose\n };\n },\n\n islandFor: (entity) => islands.get(entity),\n islands: () => islands.entries(),\n\n addFrameCallback(entity, cb) {\n let set = frameCbs.get(entity);\n if (set === undefined) {\n set = new Set();\n frameCbs.set(entity, set);\n }\n set.add(cb);\n state.addAnimRef(entity);\n requestFrame(); // the island turns Hot next pass\n return () => {\n set.delete(cb);\n state.removeAnimRef(entity);\n };\n },\n\n frameCallbacksFor(entity) {\n const set = frameCbs.get(entity);\n return set === undefined ? [] : [...set];\n },\n\n requestFrame,\n bumpPaint(entity) {\n state.bumpPaint(entity);\n requestFrame();\n },\n\n setCompositeScale(entity, scale) {\n const s = state.ensure(entity);\n if (s.compositeScale === scale) return; // change-only — no idle churn\n s.compositeScale = scale;\n requestFrame(); // composite-level only: no island repaint needed\n },\n\n setInvalidate(fn) {\n invalidate = fn;\n if (fn !== null && pending) {\n pending = false;\n fn();\n }\n },\n\n uninstall() {\n removeReflector();\n removeWorldObserver();\n renderAssert.dispose();\n islands.clear();\n frameCbs.clear();\n state.clear();\n invalidate = null;\n },\n };\n}\n","/**\n * The compositor frame pass (design-004 §3) — ONE function, dependency-\n * injected so the M7 exit traces (FBO budget under zoom/cull storms, zero\n * render→ECS writes) run headlessly with fakes while `GLViews` binds it to\n * the real renderer/pool/quads.\n *\n * Order per invalidation (v1 Compositor.useFrame, re-cut law-clean):\n * 1. camera/viewport read → composite frustum (kernel — Law 13) + dynamic\n * DPR (min(dpr,1) while `Camera.gesturing`, restore on idle);\n * 2. phase update per island-state entry (kernel `computeIslandPhase`,\n * module-side state ONLY — no ECS writes anywhere in the pass);\n * 3. `useIslandFrame` callbacks for Hot islands (paint-attributed — this\n * is why plain `useFrame` is not the contract);\n * 4. paint pass, Waking-first, staggered by `maxRepaintsPerFrame`; band\n * repaints suppressed while gesturing (the composite's bilinear stretch\n * is the accepted transient) and picked up on the first idle pass;\n * 5. eviction to budget (kernel `selectEvictions`; Hot/Waking immune);\n * 6. quad reconcile: transform from Position/Size (kernel Y-flip), texture\n * from the pool, `StackZ` render order with grabbed widgets on top\n * (design-004 §1: renderOrder-top within P2 suffices), `pool.touch` on\n * every composited quad (still-Warm textures must not look LRU-stale);\n * 7. composite render to the backbuffer;\n * 8. self-sustain report (`anyHot`/`pendingPaints` → caller invalidates).\n *\n * The world is READ ONLY here (reads outside the tick are verified-\n * unrestricted); the caller arms the render write trap around the whole pass.\n */\nimport {\n computeIslandPhase,\n compositeCameraFrustum,\n fboPixelSize,\n isOutOfBand,\n selectBand,\n selectEvictions,\n worldRectToComposite,\n type EvictionCandidate,\n} from \"@ice/kernel\";\nimport { Camera, Grab, Position, Size, StackZ, Viewport, Visible, type Entity, type World } from \"@ice/core\";\nimport type { GLBridge } from \"./bridge\";\n\n/** Render order far above any sane StackZ — the grabbed quad draws last. */\nconst GRABBED_RENDER_ORDER = 1e9;\n\n// --- injected surfaces (GLViews binds three.js; traces bind fakes) ----------\n\nexport interface TargetLike {\n /** Opaque texture handle threaded to the quad (three: `.texture`). */\n readonly texture: unknown;\n}\n\nexport interface PoolLike {\n acquire(key: number, worldW: number, worldH: number, effectiveDpr: number): TargetLike;\n get(key: number): TargetLike | null;\n touch(key: number): void;\n release(key: number): void;\n bytesUsed(): number;\n entryInfos(): readonly { key: number; bytes: number; lastUsedMs: number }[];\n}\n\nexport interface QuadLike {\n setTransform(x: number, y: number, sx: number, sy: number): void;\n setTexture(t: unknown): void;\n setVisible(v: boolean): void;\n setRenderOrder(n: number): void;\n}\n\nexport interface QuadsLike {\n ensure(key: number): QuadLike;\n remove(key: number): void;\n keys(): readonly number[];\n}\n\nexport interface GlLike {\n setRenderTarget(t: TargetLike | null): void;\n /** Clear the CURRENT target to transparent black. */\n clear(): void;\n render(scene: object, camera: object): void;\n setPixelRatio(n: number): void;\n getPixelRatio(): number;\n}\n\nexport interface CompCameraLike {\n setFrustum(f: { left: number; right: number; top: number; bottom: number; x: number; y: number }): void;\n /**\n * The ACTUAL camera object handed to `gl.render` for the composite pass —\n * three's renderer instanceof-checks it, so this must be the real\n * `OrthographicCamera`, NOT this adapter. (Field bug 2026-07-10: the pass\n * rendered with the adapter itself; three threw \"camera is not an instance\n * of THREE.Camera\" every frame and P2 never composited. The headless fakes\n * couldn't catch it — both types erase to `object` and the fake render is\n * a no-op.)\n */\n readonly raw: object;\n}\n\nexport interface IslandCameraLike {\n setFrustum(halfW: number, halfH: number): void;\n}\n\nexport interface PassContext {\n readonly world: World;\n readonly bridge: GLBridge;\n readonly pool: PoolLike;\n readonly quads: QuadsLike;\n readonly gl: GlLike;\n readonly compCamera: CompCameraLike;\n /** Adapt an island's ortho camera (three or fake) for frustum writes. */\n readonly islandCamera: (entity: Entity) => IslandCameraLike | undefined;\n readonly compositeScene: object;\n readonly maxFboBytes: number;\n readonly maxRepaintsPerFrame: number;\n readonly dtMs: number;\n}\n\nexport interface PassStats {\n repainted: number;\n /** Paint-needing islands deferred by the stagger cap — caller re-invalidates. */\n pendingPaints: number;\n evicted: number;\n fboBytes: number;\n anyHot: boolean;\n}\n\nexport function runCompositorPass(ctx: PassContext): PassStats {\n const { world, bridge, pool, quads, gl } = ctx;\n const stats: PassStats = { repainted: 0, pendingPaints: 0, evicted: 0, fboBytes: 0, anyHot: false };\n\n const cam = world.getResource(Camera);\n const vp = world.getResource(Viewport);\n if (cam === undefined || vp === undefined || vp.w === 0) return stats;\n\n // 1. composite camera + dynamic DPR ---------------------------------------\n ctx.compCamera.setFrustum(compositeCameraFrustum(cam, vp.w, vp.h));\n const idleDpr = vp.dpr > 0 ? vp.dpr : 1;\n const targetDpr = cam.gesturing ? Math.min(idleDpr, 1) : idleDpr;\n if (gl.getPixelRatio() !== targetDpr) gl.setPixelRatio(targetDpr);\n\n // 2. phases (module-side state only) --------------------------------------\n // `active` is the M8 nested-canvas input — always true until then.\n const phaseOf = (e: number): ReturnType<typeof computeIslandPhase> => {\n const alive = world.isAlive(e as Entity);\n const visible = alive && world.hasTag(e as Entity, Visible) && bridge.islandFor(e as Entity) !== undefined;\n const s = bridge.state.get(e);\n const hasFbo = s !== undefined && s.fboGeneration >= 0 && pool.get(e) !== null;\n return computeIslandPhase(true, visible, bridge.state.isAnimating(e), hasFbo);\n };\n for (const [e, s] of bridge.state.all()) {\n s.phase = phaseOf(e);\n if (s.phase === \"Hot\") stats.anyHot = true;\n }\n\n // 3+4. paint pass (Waking first, staggered) --------------------------------\n const band = selectBand(cam.zoom);\n const effectiveDpr = gl.getPixelRatio() * band;\n const toPaint: Entity[] = [];\n for (const [e, s] of bridge.state.all()) {\n if (bridge.islandFor(e as Entity) === undefined) continue; // unmounted: retained texture only\n const wantsPhase = s.phase === \"Hot\" || s.phase === \"Waking\";\n const genDirty = s.paintGeneration > s.fboGeneration;\n const bandStale = !cam.gesturing && s.fboGeneration >= 0 && isOutOfBand(cam.zoom, s.paintedAt.band);\n if (wantsPhase || genDirty || bandStale) toPaint.push(e as Entity);\n }\n // Order: never-painted first (cold paints jump the queue), then LEAST\n // RECENTLY PAINTED — the fairness key. Insertion order starved the same\n // island every pass once Hot count exceeded the stagger cap (five Hot vs\n // cap four froze the shapes card at boot, 2026-07-12 field report).\n toPaint.sort((a, b) => {\n const sa = bridge.state.get(a);\n const sb = bridge.state.get(b);\n const coldA = sa !== undefined && sa.fboGeneration < 0 ? 0 : 1;\n const coldB = sb !== undefined && sb.fboGeneration < 0 ? 0 : 1;\n if (coldA !== coldB) return coldA - coldB;\n return (sa?.lastPaintSeq ?? 0) - (sb?.lastPaintSeq ?? 0);\n });\n\n const cap = Math.max(1, ctx.maxRepaintsPerFrame);\n for (const e of toPaint) {\n if (stats.repainted >= cap) {\n stats.pendingPaints = toPaint.length - stats.repainted;\n break;\n }\n const handle = bridge.islandFor(e);\n const s = bridge.state.get(e);\n const size = world.isAlive(e) ? world.get(e, Size) : undefined;\n if (handle === undefined || s === undefined || size === undefined || size.w <= 0 || size.h <= 0) continue;\n\n // Hot content ticks exactly when it paints — the attribution contract.\n if (s.phase === \"Hot\") {\n for (const cb of bridge.frameCallbacksFor(e)) cb(ctx.dtMs);\n }\n\n ctx.islandCamera(e)?.setFrustum(size.w / 2, size.h / 2);\n const fbo = pool.acquire(e, size.w, size.h, effectiveDpr);\n gl.setRenderTarget(fbo);\n try {\n // A throwing island must not leave its FBO bound — that would corrupt\n // the composite into the backbuffer (v1 lesson, kept).\n gl.clear();\n gl.render(handle.scene, handle.camera);\n } finally {\n gl.setRenderTarget(null);\n }\n const px = fboPixelSize(size.w, size.h, effectiveDpr, 1);\n bridge.state.markPainted(e, { w: px.width, h: px.height, dpr: effectiveDpr, band });\n stats.repainted += 1;\n }\n\n // 5. eviction to budget (Hot/Waking immune — kernel policy) ----------------\n if (pool.bytesUsed() > ctx.maxFboBytes) {\n const candidates: EvictionCandidate<number>[] = [];\n for (const info of pool.entryInfos()) {\n const s = bridge.state.get(info.key);\n // Phases RECOMPUTED post-paint: an island that woke and painted this\n // very pass is Warm now, not Waking — the stage-2 snapshot would grant\n // it spurious eviction immunity and let a first-paint storm blow the\n // budget (caught by the storm trace).\n const phase = s === undefined ? \"Dormant\" : phaseOf(info.key);\n if (s !== undefined) s.phase = phase;\n candidates.push({\n id: info.key,\n phase,\n bytes: info.bytes,\n lastUsedMs: info.lastUsedMs,\n });\n }\n for (const key of selectEvictions(candidates, pool.bytesUsed(), ctx.maxFboBytes)) {\n if (bridge.state.get(key)?.phase === \"Dormant\") {\n // Tunable-budget breadcrumb (v1 kept it; \"no silent caps\").\n console.debug(`[ice/r3f] evicting Dormant island ${key} — consider raising the FBO budget`);\n }\n pool.release(key);\n bridge.state.markEvicted(key);\n stats.evicted += 1;\n }\n }\n\n // 6. quad reconcile ---------------------------------------------------------\n // Membership = island-state entries (they outlive cull; bridge drops them on\n // death/reset). Pool entries with no state entry are stale (post-reset) —\n // release them; quads with no state entry are removed.\n const liveKeys = new Set<number>();\n for (const [e] of bridge.state.all()) liveKeys.add(e);\n for (const info of pool.entryInfos()) {\n if (!liveKeys.has(info.key)) pool.release(info.key);\n }\n for (const key of quads.keys()) {\n if (!liveKeys.has(key)) quads.remove(key);\n }\n for (const [e, s] of bridge.state.all()) {\n const quad = quads.ensure(e);\n const alive = world.isAlive(e as Entity);\n const fbo = pool.get(e);\n const pos = alive ? world.get(e as Entity, Position) : undefined;\n const size = alive ? world.get(e as Entity, Size) : undefined;\n if (fbo === null || s.fboGeneration < 0 || pos === undefined || size === undefined) {\n // Evicted-while-retained fallback: hidden until first repaint\n // (design-004 §3 — instant reactivation holds only when the FBO survived).\n quad.setVisible(false);\n continue;\n }\n const q = worldRectToComposite({ x: pos.x, y: pos.y, width: size.w, height: size.h });\n // Lift-on-hold scales the QUAD (center-anchored — q.x/q.y is the rect\n // center): texture + rounded alpha corners scale together, and the card\n // overlaps its neighbors — scaling the SCENE instead crops the corners\n // at the card-sized frustum (2026-07-12 field report).\n const lift = s.compositeScale;\n quad.setTransform(q.x, q.y, q.sx * lift, q.sy * lift);\n quad.setTexture(fbo.texture);\n const grabbed = world.get(e as Entity, Grab) !== undefined;\n quad.setRenderOrder(grabbed || lift !== 1 ? GRABBED_RENDER_ORDER : (world.get(e as Entity, StackZ)?.z ?? 0));\n quad.setVisible(true);\n pool.touch(e);\n }\n\n // 7. composite to the backbuffer -------------------------------------------\n gl.setRenderTarget(null);\n gl.clear();\n gl.render(ctx.compositeScene, ctx.compCamera.raw);\n\n stats.fboBytes = pool.bytesUsed();\n return stats;\n}\n","/**\n * GLViews — the P2 root (design-004 §1/§3). Mount ONE inside an R3F\n * `<Canvas frameloop=\"demand\">` that the app positions as the GL-views plane\n * (absolute inset-0, `pointer-events: none` — the router owns GL hit\n * testing; the canvas element never sees pointers).\n *\n * Owns everything whose lifetime IS the GL context's: the FBO pool, the\n * shared unit-quad geometry, the per-widget composite quads, the composite\n * camera, and the priority-1 `useFrame` that runs `runCompositorPass` (which\n * suppresses R3F's default render — the pass owns the whole frame). Island\n * membership mirrors `WidgetRoot`: the same widget mount store, filtered to\n * `surface: \"gl\"`, hidden (culled) entries unmounted — their FBOs stay\n * pooled, that's the retention decoupling.\n *\n * StrictMode/HMR: pool + quads are lazy-init'd and re-created if a previous\n * instance was disposed (v1 lesson — cleanup-then-remount reuses the\n * component instance, so refs may point at disposed objects).\n */\nimport { useFrame, useThree } from \"@react-three/fiber\";\nimport {\n createElement,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n type ReactElement,\n} from \"react\";\nimport { Mesh, OrthographicCamera, PlaneGeometry, type Texture, type WebGLRenderTarget } from \"three\";\nimport {\n PrefabId,\n RUNTIME_BUDGETS,\n widgets,\n type Engine,\n type Entity,\n type WidgetMountStore,\n} from \"@ice/core\";\nimport type { GLBridge } from \"./bridge\";\nimport { CompositeMaterial } from \"./composite-material\";\nimport {\n runCompositorPass,\n type GlLike,\n type QuadLike,\n type QuadsLike,\n type TargetLike,\n} from \"./compositor-pass\";\nimport { Island } from \"./island\";\nimport { RenderTargetPool } from \"./pool\";\n\nexport interface GLViewsProps {\n readonly engine: Engine;\n readonly bridge: GLBridge;\n readonly store: WidgetMountStore;\n /** FBO byte budget (default `RUNTIME_BUDGETS.fboBytes`, 256 MB). */\n readonly maxFboBytes?: number;\n /** Repaint stagger per composited frame (v1 default 4). */\n readonly maxRepaintsPerFrame?: number;\n /**\n * Shared IBL: stamped as `scene.environment` on EVERY island's private\n * scene (arrival/change repaints all islands). Load it app-side (e.g.\n * drei's useEnvironment in a Suspense boundary) — undefined until then is\n * fine; islands paint unlit-by-IBL and repaint when it lands.\n */\n readonly environment?: Texture | null;\n}\n\nexport function GLViews({\n engine,\n bridge,\n store,\n maxFboBytes = RUNTIME_BUDGETS.fboBytes,\n maxRepaintsPerFrame = 4,\n environment,\n}: GLViewsProps): ReactElement {\n const world = engine.world;\n const gl = useThree((s) => s.gl);\n const scene = useThree((s) => s.scene);\n const set = useThree((s) => s.set);\n const invalidate = useThree((s) => s.invalidate);\n\n // --- context-lifetime resources (lazy + disposed-aware, v1 pattern) ------\n const poolRef = useRef<RenderTargetPool | null>(null);\n if (poolRef.current === null || poolRef.current.isDisposed()) {\n poolRef.current = new RenderTargetPool();\n }\n const pool = poolRef.current;\n\n const quadGeometry = useMemo(() => new PlaneGeometry(1, 1), []);\n const compCamera = useMemo(() => new OrthographicCamera(0, 1, 0, -1, 0.1, 10000), []);\n\n // Make the composite camera the Canvas default so R3F utilities that read\n // `state.camera` (raycaster defaults etc.) have a sensible reference.\n useEffect(() => {\n set({ camera: compCamera as unknown as never });\n }, [set, compCamera]);\n\n // Composite quads: engine-neutral meshes in the default scene ({opacity}\n // is the whole per-widget composite fact; app looks are app hooks).\n const quadsRef = useRef(new Map<number, Mesh>());\n const quads: QuadsLike = useMemo(\n () => ({\n ensure(key: number): QuadLike {\n let mesh = quadsRef.current.get(key);\n if (mesh === undefined) {\n mesh = new Mesh(quadGeometry, new CompositeMaterial());\n mesh.frustumCulled = false;\n mesh.visible = false; // hidden until the island has painted once\n scene.add(mesh);\n quadsRef.current.set(key, mesh);\n }\n const m = mesh;\n return {\n setTransform: (x, y, sx, sy) => {\n m.position.set(x, y, 0);\n m.scale.set(sx, sy, 1);\n },\n setTexture: (t) => (m.material as CompositeMaterial).setMap(t as WebGLRenderTarget[\"texture\"]),\n setVisible: (v) => {\n m.visible = v;\n },\n setRenderOrder: (n) => {\n m.renderOrder = n;\n },\n };\n },\n remove(key: number) {\n const mesh = quadsRef.current.get(key);\n if (mesh !== undefined) {\n scene.remove(mesh);\n (mesh.material as CompositeMaterial).dispose();\n quadsRef.current.delete(key);\n }\n },\n keys: () => [...quadsRef.current.keys()],\n }),\n [scene, quadGeometry],\n );\n\n // Renderer adapter (explicit clear color: transparent black, v1 contract).\n const glLike: GlLike = useMemo(\n () => ({\n setRenderTarget: (t) => gl.setRenderTarget(t as WebGLRenderTarget | null),\n clear: () => {\n gl.setClearColor(0x000000, 0);\n gl.clear(true, true, false);\n },\n render: (s, c) => gl.render(s as never, c as never),\n setPixelRatio: (n) => gl.setPixelRatio(n),\n getPixelRatio: () => gl.getPixelRatio(),\n }),\n [gl],\n );\n\n // Wire the bridge's demand-loop hook for the life of this Canvas.\n useEffect(() => {\n bridge.setInvalidate(() => invalidate());\n return () => bridge.setInvalidate(null);\n }, [bridge, invalidate]);\n\n // Teardown: quads + pool die with the context (island state survives in\n // the bridge — a remounted Canvas re-wakes islands from Waking).\n useEffect(() => {\n const quadMap = quadsRef.current;\n return () => {\n for (const mesh of quadMap.values()) {\n scene.remove(mesh);\n (mesh.material as CompositeMaterial).dispose();\n }\n quadMap.clear();\n pool.dispose();\n for (const [key] of bridge.state.all()) bridge.state.markEvicted(key);\n };\n }, [scene, pool, bridge]);\n\n // The pass. Priority 1 suppresses R3F's default render — we own the frame.\n useFrame((_, delta) => {\n bridge.renderAssert.begin();\n let stats: ReturnType<typeof runCompositorPass>;\n try {\n stats = runCompositorPass({\n world,\n bridge,\n pool,\n quads,\n gl: glLike,\n compCamera: {\n raw: compCamera, // the REAL camera — gl.render instanceof-checks it\n setFrustum: (f) => {\n compCamera.left = f.left;\n compCamera.right = f.right;\n compCamera.top = f.top;\n compCamera.bottom = f.bottom;\n compCamera.position.set(f.x, f.y, 1000);\n compCamera.updateProjectionMatrix();\n },\n },\n islandCamera: (entity) => {\n const handle = bridge.islandFor(entity);\n if (handle === undefined) return undefined;\n return {\n setFrustum: (halfW, halfH) => {\n handle.camera.left = -halfW;\n handle.camera.right = halfW;\n handle.camera.top = halfH;\n handle.camera.bottom = -halfH;\n handle.camera.updateProjectionMatrix();\n },\n };\n },\n compositeScene: scene,\n maxFboBytes,\n maxRepaintsPerFrame,\n dtMs: delta * 1000,\n });\n } finally {\n bridge.renderAssert.end();\n }\n // Self-sustain: Hot islands and stagger-deferred paints keep the demand\n // loop spinning; otherwise it parks until the next invalidation.\n if (stats.anyHot || stats.pendingPaints > 0) invalidate();\n }, 1);\n\n // --- island membership (mount store → gl-surface islands) -----------------\n const entries = useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);\n const islands: ReactElement[] = [];\n for (const entry of entries) {\n if (entry.hidden) continue; // culled: island unmounts, FBO stays pooled\n if (!world.isAlive(entry.entity)) continue;\n const type = world.get(entry.entity, PrefabId)?.id;\n const widget = typeof type === \"string\" ? widgets.get(type) : undefined;\n if (widget === undefined || widget.surface !== \"gl\") continue;\n islands.push(\n createElement(Island, {\n key: String(entry.entity),\n bridge,\n world,\n entity: entry.entity as Entity,\n widget,\n ...(environment !== undefined ? { environment } : {}),\n }),\n );\n }\n return createElement(\"group\", null, islands);\n}\n","import { ShaderMaterial } from \"three\";\nimport type { Texture } from \"three\";\n\n/**\n * Neutral composite material for the island compositor (design-004 §3). One\n * instance per island quad: it samples the island's FBO texture and writes it to\n * the canvas backbuffer at `uOpacity`, with no look of its own.\n *\n * Ported from v1 `CompositionMaterial`\n * (../infinite-canvas .../r3f/compositor/CompositionMaterial.ts) STRIPPED to the\n * engine-neutral core per design-004 §3 rev 2: the v1 app-specific uniforms and\n * shader branches — `uDraggedRect`/`uIsDragged` drag-promote clip, the\n * `uHotPoint`/`uHotStrength`/`uIsOverlapTarget` overlap glow, the rim band, and\n * the module-level `sharedGlowUniforms` — are DELETED. Userland looks belong in\n * userland materials, not the compositor.\n *\n * What is KEPT verbatim is the colour-management contract: the FBO already holds\n * sRGB-encoded, display-ready values (RenderTargetPool sets\n * `texture.colorSpace = SRGBColorSpace`), so this pass must sample-and-write\n * WITHOUT tone mapping. See the fragment-shader note below for the sRGB\n * double-encode trap and why the `<colorspace_fragment>` chunk is still required.\n */\n\nconst VERTEX_SHADER = /* glsl */ `\nvarying vec2 vUv;\nvoid main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n}\n`;\n\n// Fragment shader. There is deliberately NO <tonemapping_fragment> chunk — the\n// FBO holds sRGB values already, so tone mapping would double-process them.\n//\n// The trailing <colorspace_fragment> chunk IS required, and this is the subtle\n// part (the sRGB double-encode trap): Three's texture sampler auto-DECODES the\n// sRGB FBO to linear during texture2D (because RenderTargetPool declares the\n// target's colorSpace = SRGBColorSpace). Without re-encoding to the renderer's\n// outputColorSpace (also sRGB) via <colorspace_fragment>, those linear values\n// would land in the backbuffer and read as washed-out / desaturated. So: no tone\n// map, but DO re-encode — a straight round-trip that leaves the island's pixels\n// exactly as painted.\nconst FRAGMENT_SHADER = /* glsl */ `\nuniform sampler2D map;\nuniform float uOpacity;\nvarying vec2 vUv;\n\nvoid main() {\n vec4 c = texture2D(map, vUv);\n if (c.a < 0.001) discard;\n c.a *= uOpacity;\n gl_FragColor = c;\n #include <colorspace_fragment>\n}\n`;\n\n/**\n * Per-island composite material. Each island quad gets its own instance so the\n * per-quad `map` uniform is independent; Three compiles the shader once and\n * reuses the program across instances since they share source (verify in dev via\n * `renderer.info.programs.length === 1` for the composite shader).\n */\nexport class CompositeMaterial extends ShaderMaterial {\n // Direct handles onto our two uniform cells. ShaderMaterial types `uniforms`\n // as an index signature, so `this.uniforms.map` reads as possibly-undefined\n // under strict indexing; holding the cells we created sidesteps that and keeps\n // the setters allocation-free.\n private readonly mapUniform: { value: Texture | null };\n private readonly opacityUniform: { value: number };\n\n constructor() {\n const uniforms = {\n map: { value: null as Texture | null },\n uOpacity: { value: 1 },\n };\n super({\n vertexShader: VERTEX_SHADER,\n fragmentShader: FRAGMENT_SHADER,\n uniforms,\n transparent: true,\n depthWrite: false,\n // Explicit: this pass must never tone-map (the FBO is already display-\n // ready). v1 left toneMapped at the ShaderMaterial default and relied on\n // the absent tonemapping chunk alone (CompositionMaterial.ts:140-142); we\n // set it false so the no-tone-map contract holds even if the shader ever\n // gains chunks. Behaviour is identical for the current shader.\n toneMapped: false,\n });\n // ShaderMaterial keeps the passed `uniforms` object by reference, so these\n // handles stay in sync with `this.uniforms`.\n this.mapUniform = uniforms.map;\n this.opacityUniform = uniforms.uOpacity;\n }\n\n /** Bind the island's FBO texture (null clears). */\n setMap(map: Texture | null): void {\n this.mapUniform.value = map;\n }\n\n /** Composite opacity. Pass-through — no clamping; callers pass valid 0..1. */\n setOpacity(opacity: number): void {\n this.opacityUniform.value = opacity;\n }\n\n // dispose() is inherited from ShaderMaterial — it fires the dispose event that\n // frees the compiled program; no override needed.\n}\n","/**\n * One island = one GL widget's private Scene + center-origin Y-up ortho\n * camera, mounted via R3F `createPortal` so the content tree (hooks, state,\n * drei) lives OUTSIDE the composite scene and paints into a pooled FBO\n * (design-004 §3; the island-space convention is kernel's — Law 13).\n *\n * Deliberately thin: registration/unregistration is the ONLY effect. The\n * camera frustum is written by the frame pass at paint time from the live\n * `Size` (v1 set it from a React effect AND bumped an ECS component — both\n * moved out; islands never write ECS). Unmount (cull) drops scene + camera;\n * the FBO and island state survive in the pool/bridge — retention is\n * decoupled from culling by design.\n */\nimport { createPortal } from \"@react-three/fiber\";\nimport { createElement, useEffect, useMemo, type ComponentType, type ReactElement } from \"react\";\nimport { OrthographicCamera, Scene, type Texture } from \"three\";\nimport type { Entity, WidgetType, World } from \"@ice/core\";\nimport type { WidgetComponentProps } from \"@ice/react\";\nimport type { GLBridge } from \"./bridge\";\nimport { IslandContext } from \"./use-island-frame\";\n\nexport interface IslandProps {\n readonly bridge: GLBridge;\n readonly world: World;\n readonly entity: Entity;\n readonly widget: WidgetType;\n /** Shared IBL for this island's private scene (see GLViews.environment). */\n readonly environment?: Texture | null;\n}\n\nexport function Island({ bridge, world, entity, widget, environment }: IslandProps): ReactElement | null {\n const scene = useMemo(() => new Scene(), []);\n const camera = useMemo(() => {\n // Generous depth range (ortho — free): at z=100 a large card's rotating\n // geometry (e.g. a 329px torus knot's lobe swinging toward the camera)\n // crossed the near plane and clipped (field report 2026-07-12).\n const cam = new OrthographicCamera(-1, 1, 1, -1, 0.1, 2000);\n cam.position.set(0, 0, 500); // +Z looking at the XY content plane\n cam.lookAt(0, 0, 0);\n return cam;\n }, []);\n\n useEffect(\n () => bridge.registerIsland(entity, { scene, camera }),\n [bridge, entity, scene, camera],\n );\n\n // Shared environment (v1's Compositor propagated its env map to every widget\n // scene; v3 islands are private, so propagation is this explicit stamp). The\n // HDR usually arrives AFTER the first cold paint — bumpPaint repaints even\n // static (animated:false) islands with the new lighting.\n useEffect(() => {\n scene.environment = environment ?? null;\n bridge.bumpPaint(entity);\n }, [environment, scene, bridge, entity]);\n\n const View = widget.component as ComponentType<WidgetComponentProps>;\n if (View == null) return null;\n\n return createPortal(\n createElement(\n IslandContext.Provider,\n { value: { bridge, entity } },\n createElement(View, { entity, world }),\n ),\n scene,\n ) as unknown as ReactElement;\n}\n","/**\n * The island animation contract (design-004 §3, rev 2 corrected).\n *\n * Plain `useFrame` CANNOT drive island repaints: R3F portals share the\n * root's single commingled `internal.subscribers` array, so a subscription\n * cannot be attributed to an island without probing R3F internals (banned).\n * `useIslandFrame` is the engine's wrapper: it registers the callback WITH\n * the island (bridge-side), which (a) holds the island's animation signal\n * while subscribed — the island turns Hot and repaints every visible frame —\n * and (b) fires the callback exactly when its island paints, so content\n * mutation and texture refresh can never desynchronize.\n *\n * The callback runs INSIDE the render pass: it may mutate three objects in\n * the island scene freely, but any ECS write throws under the DEV render\n * write trap (M7 exit). Engine state changes belong in systems or ops.\n */\nimport { createContext, useCallback, useContext, useEffect, useRef } from \"react\";\nimport type { Entity } from \"@ice/core\";\nimport type { GLBridge, IslandFrameCallback } from \"./bridge\";\n\nexport interface IslandContextValue {\n readonly bridge: GLBridge;\n readonly entity: Entity;\n}\n\n/** Provided per-island by `<Island>`; null outside island content. */\nexport const IslandContext = createContext<IslandContextValue | null>(null);\n\nexport function useIslandContext(): IslandContextValue {\n const ctx = useContext(IslandContext);\n if (ctx === null) {\n throw new Error(\"ice: useIslandFrame/useIslandInvalidate must run inside a GL widget's island.\");\n }\n return ctx;\n}\n\n/** Per-frame tick while mounted (island goes Hot). `cb(dtMs)` on paint. */\nexport function useIslandFrame(cb: IslandFrameCallback): void {\n const { bridge, entity } = useIslandContext();\n const ref = useRef(cb);\n ref.current = cb; // latest closure runs without re-subscribing\n useEffect(() => bridge.addFrameCallback(entity, (dt) => ref.current(dt)), [bridge, entity]);\n}\n\n/**\n * One-shot repaint scheduler for content that changes outside React's render\n * cycle (imperative subscriptions, sockets). Bumps the island's paint\n * generation + wakes the demand loop.\n */\nexport function useIslandInvalidate(): () => void {\n const { bridge, entity } = useIslandContext();\n return useCallback(() => bridge.bumpPaint(entity), [bridge, entity]);\n}\n\n/**\n * Composite-quad lift: scales the CARD on the canvas (texture + rounded alpha\n * corners together) and pops it over neighbors while ≠1. Scaling scene content\n * instead crops the corners at the card-sized frustum — the 2026-07-12\n * hard-corner field report. Resets to 1 on unmount.\n */\nexport function useIslandLift(scale: number): void {\n const { bridge, entity } = useIslandContext();\n useEffect(() => {\n bridge.setCompositeScale(entity, scale);\n }, [bridge, entity, scale]);\n useEffect(() => () => bridge.setCompositeScale(entity, 1), [bridge, entity]);\n}\n","import { SRGBColorSpace, WebGLRenderTarget } from \"three\";\n\n/**\n * Per-island FBO pool (design-004 §3). Each compositor island paints into its\n * own persistent `WebGLRenderTarget` instead of the shared canvas backbuffer,\n * so the compositor can sample islands as textures and stack them with correct\n * z / opacity.\n *\n * Ported from v1 `WidgetRenderTargetPool` (../infinite-canvas\n * .../r3f/compositor/WidgetRenderTargetPool.ts) with the design-004 §3 rev 2\n * deltas: the pool is keyed by a plain `number` (the caller's island/entity id)\n * and imports NOTHING from the ECS — it is a pure three resource, so it never\n * depends on the entity representation. Timestamps are injected (see `now`) so\n * the LRU is deterministic under test.\n *\n * Acquire returns an existing FBO when its pixel resolution matches the request;\n * otherwise the old FBO is disposed and a new one is created at the new\n * resolution. Eviction under memory pressure is a higher layer's concern — this\n * pool grows monotonically until islands are `release`d.\n */\n\n/**\n * Colour bytes per pixel for the default RGBA8 render-target format.\n *\n * v1 accounted a flat `BYTES_PER_PIXEL = 8` constant\n * (WidgetRenderTargetPool.ts:8) reasoning \"RGBA8 colour + packed depth/stencil\".\n * We keep the identical byte total but express it in the design-004 §3 form\n * `colour × (samples > 1 ? 2 : 1)`: 4 colour bytes, doubled when MSAA adds the\n * resolve buffer. Because {@link SAMPLES} is 4 (> 1) this yields 8 bytes/pixel —\n * byte-for-byte the v1 figure — while remaining correct if the sample count ever\n * changes.\n */\nconst COLOR_BYTES_PER_PIXEL = 4;\n\n/**\n * MSAA sample count. Matches the canvas's antialias setting so island edges look\n * the same as a direct-to-canvas pass (v1 WidgetRenderTargetPool.ts:73).\n */\nconst SAMPLES = 4;\n\n/** GPU bytes for one target at the given pixel size (see {@link COLOR_BYTES_PER_PIXEL}). */\nfunction targetBytes(pixelWidth: number, pixelHeight: number): number {\n return pixelWidth * pixelHeight * COLOR_BYTES_PER_PIXEL * (SAMPLES > 1 ? 2 : 1);\n}\n\ninterface PoolEntry {\n rt: WebGLRenderTarget;\n /** Pixel width = worldWidth × effectiveDpr, rounded, clamped ≥ 1. */\n pixelWidth: number;\n pixelHeight: number;\n effectiveDpr: number;\n bytes: number;\n /** Injected-clock timestamp of the most recent acquire/touch — drives LRU. */\n lastUsedMs: number;\n}\n\n/** Snapshot row returned by {@link RenderTargetPool.entryInfos}. */\nexport interface PoolEntryInfo {\n key: number;\n bytes: number;\n lastUsedMs: number;\n}\n\nexport class RenderTargetPool {\n private entries = new Map<number, PoolEntry>();\n private totalBytes = 0;\n private disposed = false;\n private readonly now: () => number;\n\n /**\n * @param now Injected monotonic clock for LRU timestamps. Defaults to\n * `performance.now()`; tests pass a deterministic stub so `lastUsedMs`\n * assertions do not depend on wall-clock timing.\n */\n constructor(now: () => number = () => performance.now()) {\n this.now = now;\n }\n\n /**\n * Get or create an FBO for `key` at the requested world size and effective\n * device-pixel-ratio. Returns the existing target unchanged when its pixel\n * dimensions already match; otherwise disposes the stale target and allocates\n * a new one sized to the new resolution.\n */\n acquire(key: number, worldW: number, worldH: number, effectiveDpr: number): WebGLRenderTarget {\n if (this.disposed) {\n throw new Error(\"RenderTargetPool: cannot acquire after dispose\");\n }\n const pixelWidth = Math.max(1, Math.round(worldW * effectiveDpr));\n const pixelHeight = Math.max(1, Math.round(worldH * effectiveDpr));\n const nowMs = this.now();\n\n const existing = this.entries.get(key);\n if (existing && existing.pixelWidth === pixelWidth && existing.pixelHeight === pixelHeight) {\n existing.lastUsedMs = nowMs;\n return existing.rt;\n }\n\n if (existing) {\n existing.rt.dispose();\n this.totalBytes -= existing.bytes;\n }\n\n const rt = new WebGLRenderTarget(pixelWidth, pixelHeight, { samples: SAMPLES });\n // sRGB colour space — without this, Three writes tone-mapped LINEAR values\n // to the FBO. The composite shader samples raw and outputs raw, and the\n // canvas backbuffer would then read the linear values as sRGB → washed-out /\n // dark. SRGBColorSpace tells Three's built-in materials to sRGB-encode when\n // writing here, so the FBO already holds display-ready values (design-004 §3;\n // the composite shader must NOT re-encode — see composite-material.ts).\n rt.texture.colorSpace = SRGBColorSpace;\n const bytes = targetBytes(pixelWidth, pixelHeight);\n this.entries.set(key, { rt, pixelWidth, pixelHeight, effectiveDpr, bytes, lastUsedMs: nowMs });\n this.totalBytes += bytes;\n return rt;\n }\n\n /** Look up an FBO without creating one. */\n get(key: number): WebGLRenderTarget | null {\n return this.entries.get(key)?.rt ?? null;\n }\n\n /**\n * Refresh `lastUsedMs` without re-acquiring. The compositor calls this for\n * every island it samples in the composition pass — without it, warm islands\n * that never repaint would freeze their timestamp at their last paint and the\n * LRU would treat still-visible islands as stale (design-004 §3).\n */\n touch(key: number): void {\n const entry = this.entries.get(key);\n if (!entry) return;\n entry.lastUsedMs = this.now();\n }\n\n /**\n * Release `key`'s FBO. Returns true if something was released. Safe after\n * dispose — returns false rather than corrupting the byte counter or\n * double-disposing the target.\n */\n release(key: number): boolean {\n if (this.disposed) return false;\n const entry = this.entries.get(key);\n if (!entry) return false;\n entry.rt.dispose();\n // Clamp at zero so out-of-order teardown never drives the counter negative.\n this.totalBytes = Math.max(0, this.totalBytes - entry.bytes);\n this.entries.delete(key);\n return true;\n }\n\n /** Total GPU bytes consumed by the pool. */\n bytesUsed(): number {\n return this.totalBytes;\n }\n\n /** Number of FBOs currently held. */\n size(): number {\n return this.entries.size;\n }\n\n /** True after `dispose()` — callers should re-create the pool instead of using it. */\n isDisposed(): boolean {\n return this.disposed;\n }\n\n /** Iterate live entries (key + target). */\n forEach(cb: (key: number, rt: WebGLRenderTarget) => void): void {\n for (const [key, entry] of this.entries) cb(key, entry.rt);\n }\n\n /**\n * Snapshot of every live entry's `bytes` + `lastUsedMs` — the input an\n * eviction pass ranks by LRU.\n */\n entryInfos(): PoolEntryInfo[] {\n const out: PoolEntryInfo[] = [];\n for (const [key, entry] of this.entries) {\n out.push({ key, bytes: entry.bytes, lastUsedMs: entry.lastUsedMs });\n }\n return out;\n }\n\n /** Dispose every FBO. After this, acquire throws and release returns false. */\n dispose(): void {\n if (this.disposed) return;\n for (const entry of this.entries.values()) entry.rt.dispose();\n this.entries.clear();\n this.totalBytes = 0;\n this.disposed = true;\n }\n}\n","import type { BufferGeometry, Material, Texture } from \"three\";\n\n/**\n * Ref-counted cache of shared GPU resources keyed by a caller-supplied\n * `cacheKey` (design-004 §3). Geometries, materials, and textures are pooled so\n * many islands of the same archetype share one instance instead of each\n * allocating its own copy.\n *\n * Ported ~verbatim from v1 `ResourceRegistry`\n * (../infinite-canvas .../r3f/compositor/ResourceRegistry.ts). Three's\n * geometries / materials / textures all expose `.dispose()` and are safe to\n * share across scenes; the registry disposes the underlying resource only after\n * every holder has called the matching `release*`.\n */\n\n/** Anything the registry can own — Three resources all satisfy this. */\ntype Disposable = { dispose: () => void };\n\ninterface Entry<T extends Disposable> {\n resource: T;\n refCount: number;\n}\n\nexport class ResourceRegistry {\n private geometries = new Map<string, Entry<BufferGeometry>>();\n private materials = new Map<string, Entry<Material>>();\n private textures = new Map<string, Entry<Texture>>();\n private disposed = false;\n\n acquireGeometry<T extends BufferGeometry>(key: string, factory: () => T): T {\n const existing = this.geometries.get(key);\n if (existing) {\n existing.refCount++;\n return existing.resource as T;\n }\n const resource = factory();\n this.geometries.set(key, { resource, refCount: 1 });\n return resource;\n }\n releaseGeometry(key: string): void {\n this.releaseFrom(this.geometries, key);\n }\n\n acquireMaterial<T extends Material>(key: string, factory: () => T): T {\n const existing = this.materials.get(key);\n if (existing) {\n existing.refCount++;\n return existing.resource as T;\n }\n const resource = factory();\n this.materials.set(key, { resource, refCount: 1 });\n return resource;\n }\n releaseMaterial(key: string): void {\n this.releaseFrom(this.materials, key);\n }\n\n acquireTexture<T extends Texture>(key: string, factory: () => T): T {\n const existing = this.textures.get(key);\n if (existing) {\n existing.refCount++;\n return existing.resource as T;\n }\n const resource = factory();\n this.textures.set(key, { resource, refCount: 1 });\n return resource;\n }\n releaseTexture(key: string): void {\n this.releaseFrom(this.textures, key);\n }\n\n /** Number of distinct shared geometries currently held. */\n geometryCount(): number {\n return this.geometries.size;\n }\n\n /** Number of distinct shared materials currently held. */\n materialCount(): number {\n return this.materials.size;\n }\n\n /** Number of distinct shared textures currently held. */\n textureCount(): number {\n return this.textures.size;\n }\n\n /**\n * Estimated GPU bytes for shared geometry attribute buffers. Best-effort —\n * actual footprint depends on driver alignment, but a useful relative metric\n * for the profiler.\n */\n geometryBytes(): number {\n let total = 0;\n for (const { resource } of this.geometries.values()) {\n for (const attr of Object.values(resource.attributes)) {\n if (\"array\" in attr && (attr.array as ArrayBufferView).byteLength) {\n total += (attr.array as ArrayBufferView).byteLength;\n }\n }\n if (resource.index) {\n total += (resource.index.array as ArrayBufferView).byteLength;\n }\n }\n return total;\n }\n\n /** Dispose every resource and clear the registry. */\n dispose(): void {\n if (this.disposed) return;\n for (const { resource } of this.geometries.values()) resource.dispose();\n for (const { resource } of this.materials.values()) resource.dispose();\n for (const { resource } of this.textures.values()) resource.dispose();\n this.geometries.clear();\n this.materials.clear();\n this.textures.clear();\n this.disposed = true;\n }\n\n /** True after `dispose()` — callers should re-create the registry instead of using it. */\n isDisposed(): boolean {\n return this.disposed;\n }\n\n private releaseFrom<T extends Disposable>(map: Map<string, Entry<T>>, key: string): void {\n const entry = map.get(key);\n if (!entry) return;\n entry.refCount--;\n if (entry.refCount <= 0) {\n // Defer disposal by one microtask. Under React StrictMode the effect\n // cleanup fires immediately, followed by a remount + new acquire — without\n // the defer, the resource is disposed before the remount can re-acquire\n // it. The microtask gives the re-acquire a chance to bump refCount back\n // above 0; if it does not, we dispose for real.\n queueMicrotask(() => {\n const current = map.get(key);\n if (current && current.refCount <= 0) {\n current.resource.dispose();\n map.delete(key);\n }\n });\n }\n }\n}\n","/**\n * The pointer router's GL path (design-004 §4, rev 2 corrected).\n *\n * At EVENT time (outside the tick — world reads are verified-unrestricted)\n * the router runs its own synchronous point-pick against THE spatial index\n * via core's `pickTopAt` — the identical narrow-phase the in-tick `picking`\n * system runs, so the two can never disagree. It does NOT consult last-frame\n * `Targets`: that relation is absent for a touch's first event (the pointer\n * entity doesn't exist yet at down) and stale for fast mouse crossings —\n * rev 1 of the design ate the first tap on every interactive GL widget.\n * `Targets` remains the in-tick authority; this pick is a routing decision,\n * not a second truth.\n *\n * Hit a GL-view widget → island-local convert (kernel, THE Y-flip) → raycast\n * the island's scene through its ortho camera → dispatch synthetic events to\n * the intersected objects' R3F handlers. A handler calling\n * `stopPropagation()` claims the event: the adapter flags the fact\n * `surfaceHandled` and recognizers skip it (`HandledByWidget`, the M4 spine).\n *\n * Capture semantics (per island): a claimed down captures the pointer — its\n * moves/ups go to that island until up/cancel, mirroring how DOM widget\n * content holds `setPointerCapture` for sustained interactions. Hover\n * enter/leave are synthesized from pick transitions on buttonless moves.\n *\n * R3F-INTERNAL-ADJACENT (the one acknowledged spot, implementation-plan\n * risks): handlers are read from `object.__r3f.handlers` — the instance\n * state R3F v9 attaches to every declaratively-created three object. No\n * other R3F internal is touched; the dispatcher owns its own event shape.\n * Mid-event ordering note (design-004 §4): handlers may run engine ops —\n * legal; such mutations land immediately while the same event's position\n * facts land next tick via the queue.\n */\nimport { Raycaster, Vector2, type Intersection, type Object3D } from \"three\";\nimport { screenToWorld, worldToIsland } from \"@ice/kernel\";\nimport type { SpatialIndex } from \"@ice/kernel\";\nimport {\n Camera,\n PrefabId,\n Position,\n Size,\n pickTopAt,\n widgets,\n type Entity,\n type World,\n} from \"@ice/core\";\nimport type { GLBridge } from \"./bridge\";\n\n/** The synthetic event island handlers receive (R3F-handler-compatible core). */\nexport interface IslandPointerEvent {\n readonly type: string;\n readonly nativeEvent: PointerEvent;\n /** Island-local intersection point (three world = island space). */\n readonly point: Intersection[\"point\"] | undefined;\n readonly distance: number;\n readonly object: Object3D;\n readonly eventObject: Object3D;\n readonly intersections: readonly Intersection[];\n readonly entity: Entity;\n stopPropagation(): void;\n readonly stopped: boolean;\n}\n\ntype HandlerName =\n | \"onPointerDown\"\n | \"onPointerMove\"\n | \"onPointerUp\"\n | \"onPointerCancel\"\n | \"onPointerOver\"\n | \"onPointerOut\"\n | \"onClick\";\n\n/** R3F v9 instance state — the single internal-adjacent touchpoint. */\ninterface R3FInstance {\n eventCount?: number;\n handlers?: Partial<Record<HandlerName, (ev: IslandPointerEvent) => void>>;\n}\n\nfunction handlersOf(obj: Object3D): R3FInstance[\"handlers\"] | undefined {\n const inst = (obj as unknown as { __r3f?: R3FInstance }).__r3f;\n if (inst === undefined || (inst.eventCount ?? 0) === 0) return undefined;\n return inst.handlers;\n}\n\nexport interface GLPointerRouterDeps {\n readonly world: World;\n readonly bridge: GLBridge;\n readonly index: SpatialIndex<Entity>;\n}\n\nexport interface GLPointerRouter {\n /** The adapter's `glRoute` seam. True = island content claimed the event. */\n route(kind: \"down\" | \"move\" | \"up\" | \"cancel\", screenX: number, screenY: number, native: PointerEvent): boolean;\n}\n\nexport function createGLPointerRouter({ world, bridge, index }: GLPointerRouterDeps): GLPointerRouter {\n const raycaster = new Raycaster();\n const ndc = new Vector2();\n\n // pointerId → captured island + the down's claiming object (click pairing).\n const captures = new Map<number, { entity: Entity; downObject: Object3D | undefined }>();\n // entity → objects currently hovered (buttonless-move enter/leave synth).\n const hovered = new Map<Entity, Set<Object3D>>();\n // pointerId → unclaimed down's topmost object (click pairing without a claim).\n const unclaimedDowns = new Map<number, { entity: Entity; object: Object3D }>();\n\n /** Screen → (GL widget entity, island intersections); undefined off-GL. */\n const castAt = (\n screenX: number,\n screenY: number,\n ): { entity: Entity; hits: Intersection[] } | undefined => {\n const cam = world.getResource(Camera);\n if (cam === undefined) return undefined;\n const w = screenToWorld(screenX, screenY, cam);\n const hit = pickTopAt(world, index, w.x, w.y, 0);\n if (hit === undefined) return undefined;\n const type = world.get(hit, PrefabId)?.id;\n const widget = typeof type === \"string\" ? widgets.get(type) : undefined;\n if (widget === undefined || widget.surface !== \"gl\") return undefined;\n const handle = bridge.islandFor(hit);\n const pos = world.get(hit, Position);\n const size = world.get(hit, Size);\n if (handle === undefined || pos === undefined || size === undefined || size.w <= 0 || size.h <= 0) {\n return undefined; // culled island (no scene) — the retained texture is not interactive\n }\n const local = worldToIsland(w.x, w.y, { x: pos.x, y: pos.y, width: size.w, height: size.h });\n ndc.set(local.x / (size.w / 2), local.y / (size.h / 2));\n // The event-time raycast must not depend on paint order (a tap can land\n // before the island's first paint sets the camera frustum): write the\n // frustum from the live Size and refresh matrices here. Event-rate, small\n // trees — cheap.\n const cam3 = handle.camera;\n cam3.left = -size.w / 2;\n cam3.right = size.w / 2;\n cam3.top = size.h / 2;\n cam3.bottom = -size.h / 2;\n cam3.updateProjectionMatrix();\n cam3.updateMatrixWorld(true);\n handle.scene.updateMatrixWorld(true);\n raycaster.setFromCamera(ndc, cam3);\n return { entity: hit, hits: raycaster.intersectObjects(handle.scene.children, true) };\n };\n\n /** R3F bubbling: per intersection, walk up; dedupe eventObjects; stop on stopPropagation. */\n const dispatch = (\n type: HandlerName,\n eventType: string,\n entity: Entity,\n hits: readonly Intersection[],\n native: PointerEvent,\n only?: Object3D,\n ): { stopped: boolean; claimedBy: Object3D | undefined } => {\n const visited = new Set<Object3D>();\n let stopped = false;\n let claimedBy: Object3D | undefined;\n const targets: { obj: Object3D; hit: Intersection | undefined }[] = [];\n if (hits.length === 0 && only !== undefined) {\n targets.push({ obj: only, hit: undefined }); // captured island, ray off content\n }\n for (const hit of hits) {\n for (let obj: Object3D | null = hit.object; obj !== null; obj = obj.parent) {\n if (visited.has(obj)) continue;\n visited.add(obj);\n targets.push({ obj, hit });\n }\n }\n for (const { obj, hit } of targets) {\n const fn = handlersOf(obj)?.[type];\n if (fn === undefined) continue;\n let localStop = false;\n const ev: IslandPointerEvent = {\n type: eventType,\n nativeEvent: native,\n point: hit?.point,\n distance: hit?.distance ?? 0,\n object: hit?.object ?? obj,\n eventObject: obj,\n intersections: hits,\n entity,\n stopPropagation() {\n localStop = true;\n },\n get stopped() {\n return localStop;\n },\n };\n fn(ev);\n if (localStop) {\n stopped = true;\n claimedBy = obj;\n break;\n }\n }\n return { stopped, claimedBy };\n };\n\n /** Buttonless-move hover synth: over/out from pick transitions. */\n const syncHover = (\n now: { entity: Entity; hits: Intersection[] } | undefined,\n native: PointerEvent,\n ): void => {\n const nowEntity = now?.entity;\n const nowObjs = new Set<Object3D>();\n if (now !== undefined) {\n for (const hit of now.hits) {\n for (let obj: Object3D | null = hit.object; obj !== null; obj = obj.parent) nowObjs.add(obj);\n }\n }\n for (const [entity, prev] of hovered) {\n const gone: Object3D[] = [];\n for (const obj of prev) {\n if (entity !== nowEntity || !nowObjs.has(obj)) gone.push(obj);\n }\n for (const obj of gone) {\n prev.delete(obj);\n handlersOf(obj)?.onPointerOut?.({\n type: \"pointerout\",\n nativeEvent: native,\n point: undefined,\n distance: 0,\n object: obj,\n eventObject: obj,\n intersections: [],\n entity,\n stopPropagation() {},\n stopped: false,\n });\n }\n if (prev.size === 0) hovered.delete(entity);\n }\n if (now !== undefined && nowEntity !== undefined) {\n let set = hovered.get(nowEntity);\n if (set === undefined) {\n set = new Set();\n hovered.set(nowEntity, set);\n }\n for (const obj of nowObjs) {\n if (set.has(obj) || handlersOf(obj) === undefined) continue;\n set.add(obj);\n handlersOf(obj)?.onPointerOver?.({\n type: \"pointerover\",\n nativeEvent: native,\n point: undefined,\n distance: 0,\n object: obj,\n eventObject: obj,\n intersections: now.hits,\n entity: nowEntity,\n stopPropagation() {},\n stopped: false,\n });\n }\n }\n };\n\n return {\n route(kind, screenX, screenY, native) {\n if (kind === \"down\") {\n const cast = castAt(screenX, screenY);\n if (cast === undefined) {\n unclaimedDowns.delete(native.pointerId);\n return false;\n }\n const { stopped, claimedBy } = dispatch(\"onPointerDown\", \"pointerdown\", cast.entity, cast.hits, native);\n if (stopped) {\n unclaimedDowns.delete(native.pointerId);\n captures.set(native.pointerId, { entity: cast.entity, downObject: claimedBy });\n return true;\n }\n // UNCLAIMED down over an island: remember the topmost object so a\n // clean up on the same object still yields a click (native-R3F\n // parity; v1 RFC-008 coexistence — the engine's tap runs too, so a\n // cube click can log AND select, 2026-07-12 field report).\n const top = cast.hits[0]?.object;\n if (top !== undefined) unclaimedDowns.set(native.pointerId, { entity: cast.entity, object: top });\n return false;\n }\n\n const capture = captures.get(native.pointerId);\n\n if (kind === \"move\") {\n if (capture !== undefined) {\n const cast = castAt(screenX, screenY);\n const hits = cast !== undefined && cast.entity === capture.entity ? cast.hits : [];\n dispatch(\"onPointerMove\", \"pointermove\", capture.entity, hits, native, capture.downObject);\n return true;\n }\n if (native.buttons === 0) {\n const cast = castAt(screenX, screenY);\n syncHover(cast, native);\n // Native-R3F hover parity (2026-07-12 field report — v1's hover-driven\n // widgets, e.g. the shapes swarm, read point-carrying moves WITHOUT a\n // press): buttonless moves over an island dispatch onPointerMove with\n // the pick's island-local point. Never claims — the engine still sees\n // the move (no gesture is active buttonless, so nothing competes).\n if (cast !== undefined) {\n dispatch(\"onPointerMove\", \"pointermove\", cast.entity, cast.hits, native);\n }\n }\n return false;\n }\n\n // up | cancel\n if (capture === undefined) {\n // Unclaimed click pairing: down and up on the same topmost object.\n const pending = unclaimedDowns.get(native.pointerId);\n unclaimedDowns.delete(native.pointerId);\n if (kind === \"up\" && pending !== undefined) {\n const cast = castAt(screenX, screenY);\n if (cast !== undefined && cast.entity === pending.entity && cast.hits[0]?.object === pending.object) {\n dispatch(\"onClick\", \"click\", cast.entity, cast.hits, native, pending.object);\n }\n }\n return false;\n }\n captures.delete(native.pointerId);\n const cast = castAt(screenX, screenY);\n const hits = cast !== undefined && cast.entity === capture.entity ? cast.hits : [];\n if (kind === \"up\") {\n const { claimedBy } = dispatch(\"onPointerUp\", \"pointerup\", capture.entity, hits, native, capture.downObject);\n // Click pairs down+up on the same claiming object (R3F semantics).\n const clickTarget = claimedBy ?? capture.downObject;\n if (clickTarget !== undefined && clickTarget === capture.downObject) {\n dispatch(\"onClick\", \"click\", capture.entity, hits, native, clickTarget);\n }\n } else {\n dispatch(\"onPointerCancel\", \"pointercancel\", capture.entity, hits, native, capture.downObject);\n }\n return true;\n },\n };\n}\n"],"mappings":"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","names":["createElement","useEffect","useMemo","useRef","OrthographicCamera","useEffect","useEffect","useRef","useMemo","OrthographicCamera","useEffect","createElement","cast","hits"]}
1
+ {"version":3,"sources":["../../r3f/src/island-state.ts","../../r3f/src/dev-write-trap.ts","../../r3f/src/bridge.ts","../../r3f/src/compositor-pass.ts","../../r3f/src/gl-root.tsx","../../r3f/src/composite-material.ts","../../r3f/src/island.tsx","../../r3f/src/use-island-frame.ts","../../r3f/src/pool.ts","../../r3f/src/self-sustain.ts","../../r3f/src/resource-registry.ts","../../r3f/src/gl-router.ts","../../r3f/src/preview-capture.tsx"],"sourcesContent":["/**\n * Module-side island render state (design-004 §3 fix #3: ZERO render→ECS\n * writes — v1 kept this as an ECS component `R3FRenderState` and wrote it\n * from inside `useFrame`, which the engine laws ban; band/generation/paint\n * bookkeeping now lives here, outside the world entirely).\n *\n * One entry per GL widget the compositor has ever touched this session.\n * Entries OUTLIVE island unmount (cull) — that is the retention decoupling:\n * a culled widget's entry keeps its `fboGeneration`/`paintedAt` so re-entry\n * composites from the retained texture (phase Warm) instead of re-waking.\n * Entries die only on entity death, world reset, or `drop()`.\n *\n * Pure state + counters; no three.js, no ECS, no timing — the GLViews frame\n * pass reads/writes it synchronously.\n */\nimport type { IslandPhase } from \"@ice/kernel\";\n\n/** Resolution + band an island's FBO was last painted at (v1 `paintedAt`). */\nexport interface PaintedAt {\n readonly w: number;\n readonly h: number;\n readonly dpr: number;\n /** The zoom BAND painted at (not live zoom) — hysteresis compares against it. */\n readonly band: number;\n}\n\nexport interface IslandRenderState {\n phase: IslandPhase;\n /** Bumped by dirt (props Tier-3, size dirt, manual invalidate). */\n paintGeneration: number;\n /** Generation last painted into the FBO; -1 = no valid texture (fresh or evicted). */\n fboGeneration: number;\n paintedAt: PaintedAt;\n /** Live `useIslandFrame` subscriptions (animation signal while > 0). */\n animRefs: number;\n /** The widget type declared `animated` (repaint every visible frame). */\n animatedDecl: boolean;\n /**\n * Monotonic stamp of the last repaint — the stagger's FAIRNESS key. Without\n * it, more Hot islands than maxRepaintsPerFrame starves the same island\n * every pass (5 Hot vs cap 4 froze the shapes card, 2026-07-12).\n */\n lastPaintSeq: number;\n /**\n * Animation time OWED to this island's `useIslandFrame` callbacks: every\n * pass a Hot island is paint-eligible adds the pass dtMs; the paint that\n * finally runs delivers the whole balance and zeroes it. Without this, a\n * stagger-deferred island simply LOST the deferred passes' time — 5 Hot vs\n * cap 4 ran every animation at 4/5 speed (2026-07-20 rate probe), violating\n * design-004's \"the cap changes cadence, never speed\". Freeze semantics are\n * preserved: frozen islands are not paint-eligible, so a stage hold still\n * PAUSES animation rather than banking it.\n */\n pendingDtMs: number;\n /**\n * Composite-quad scale (lift-on-hold): scales the CARD on the canvas —\n * texture, rounded alpha corners and all — instead of the scene content\n * (which the card-sized frustum would crop into hard corners, 2026-07-12\n * field report). ≠1 also pops render order over neighbors.\n *\n * This is the DRAWN value: the compositor pass eases it toward\n * `liftTarget` (dtMs-driven spring). GL widgets have no CSS transitions, so\n * the DOM-lift parity (2026-07-13 field report: \"GL lift snaps\") lives in\n * the pass, not in userland.\n */\n compositeScale: number;\n /** Where the lift is headed; `setCompositeScale` retargets from the drawn value. */\n liftTarget: number;\n /** Drawn value at (re)target time — the ease runs liftFrom → liftTarget. */\n liftFrom: number;\n /** Accumulated pass dtMs since the last retarget; ≥ liftMs ⇒ settled. */\n liftElapsedMs: number;\n /** Transition duration in ms; 0 = snap (the pre-ease behavior). */\n liftMs: number;\n /**\n * Composite-quad opacity channel (the lift's fade twin): the DRAWN value the\n * pass eases toward `opacityTarget` and MULTIPLIES with the widget's durable\n * `Opacity` cell — presentation-transient (chrome-grade, e.g. the drag-lift\n * fade) stacked over the doc-level fact, never written to ECS.\n */\n compositeOpacity: number;\n /** Where the fade is headed; `setCompositeOpacity` retargets from the drawn value. */\n opacityTarget: number;\n /** Drawn value at (re)target time — the ease runs opacityFrom → opacityTarget. */\n opacityFrom: number;\n /** Accumulated pass dtMs since the last retarget; ≥ opacityMs ⇒ settled. */\n opacityElapsedMs: number;\n /** Transition duration in ms; 0 = snap. */\n opacityMs: number;\n}\n\n/**\n * Default lift transition — the GL twin of the DOM card-lift idiom (180ms\n * springy pop; the curve itself lives in the compositor pass).\n */\nexport const LIFT_DEFAULT_MS = 180;\n\nconst FRESH_PAINTED_AT: PaintedAt = { w: 0, h: 0, dpr: 1, band: 0 };\n\nexport interface IslandStateStore {\n /** Get-or-create (Cold, unpainted). */\n ensure(key: number): IslandRenderState;\n get(key: number): IslandRenderState | undefined;\n all(): IterableIterator<[number, IslandRenderState]>;\n /** Island dirt: the next frame pass must repaint this island. */\n bumpPaint(key: number): void;\n markPainted(key: number, at: PaintedAt): void;\n /** FBO released (eviction/death): the quad hides until first repaint. */\n markEvicted(key: number): void;\n addAnimRef(key: number): void;\n removeAnimRef(key: number): void;\n /** Animation signal: declared `animated` OR any live `useIslandFrame`. */\n isAnimating(key: number): boolean;\n setAnimatedDecl(key: number, animated: boolean): void;\n drop(key: number): void;\n clear(): void;\n}\n\nexport function createIslandStateStore(): IslandStateStore {\n const entries = new Map<number, IslandRenderState>();\n let paintSeq = 0;\n\n const ensure = (key: number): IslandRenderState => {\n let s = entries.get(key);\n if (s === undefined) {\n s = {\n phase: \"Cold\",\n paintGeneration: 0,\n fboGeneration: -1,\n paintedAt: FRESH_PAINTED_AT,\n animRefs: 0,\n animatedDecl: false,\n lastPaintSeq: 0,\n pendingDtMs: 0,\n compositeScale: 1,\n liftTarget: 1,\n liftFrom: 1,\n liftElapsedMs: 0,\n liftMs: 0,\n compositeOpacity: 1,\n opacityTarget: 1,\n opacityFrom: 1,\n opacityElapsedMs: 0,\n opacityMs: 0,\n };\n entries.set(key, s);\n }\n return s;\n };\n\n return {\n ensure,\n get: (key) => entries.get(key),\n all: () => entries.entries(),\n bumpPaint(key) {\n ensure(key).paintGeneration += 1;\n },\n markPainted(key, at) {\n const s = ensure(key);\n s.fboGeneration = s.paintGeneration;\n s.paintedAt = at;\n s.lastPaintSeq = ++paintSeq;\n },\n markEvicted(key) {\n const s = entries.get(key);\n if (s !== undefined) s.fboGeneration = -1;\n },\n addAnimRef(key) {\n ensure(key).animRefs += 1;\n },\n removeAnimRef(key) {\n const s = entries.get(key);\n if (s !== undefined && s.animRefs > 0) s.animRefs -= 1;\n },\n isAnimating(key) {\n const s = entries.get(key);\n return s !== undefined && (s.animatedDecl || s.animRefs > 0);\n },\n setAnimatedDecl(key, animated) {\n ensure(key).animatedDecl = animated;\n },\n drop(key) {\n entries.delete(key);\n },\n clear() {\n entries.clear();\n },\n };\n}\n","/**\n * The zero-render→ECS-writes DEV assertion (M7 exit criterion; design-004 §3\n * fix #3). While a compositor frame pass runs — including island paints and\n * `useIslandFrame` callbacks — every world mutation throws with attribution.\n *\n * strata 0.4.0 (petition 4 LANDED): one persistent `world.devOnWrite`\n * registration + an armed flag. The hook is DEV-only, synchronous, and\n * PRE-MUTATION with throws propagating to the mutator's caller — so a throw\n * while armed is a clean veto whose stack names the offender. Fired from\n * strata's internal chokepoints, it covers every route the old own-property\n * mutator shadows could miss: bound/destructured method references, document\n * transactions, sync/attach drains, undo echoes, and any mutator added\n * upstream later. (Raw `batch.col()` column pokes remain the documented\n * carve-out — no chokepoint exists by design.)\n *\n * `enabled` is the app-side production gate the 0.4.0 notes ask for: in an\n * un-shimmed browser production bundle strata's own DEV flag can evaluate\n * true, so registration is gated HERE (default off; demos/traces opt in).\n */\nimport type { World } from \"@ice/core\";\n\nexport interface RenderWriteTrap {\n /** Arm the trap (begin twice without end is a bug — throws). */\n begin(): void;\n /** Disarm; always call in `finally`. */\n end(): void;\n /** Unregister the hook entirely (bridge teardown). */\n dispose(): void;\n readonly enabled: boolean;\n}\n\nexport function createRenderWriteTrap(world: World, enabled: boolean): RenderWriteTrap {\n let armed = false;\n let unregister: (() => void) | null = null;\n\n if (enabled) {\n unregister = world.devOnWrite((kind) => {\n if (!armed) return;\n throw new Error(\n `ice: world mutation (${kind}) during the GL render pass — the render path never writes ECS (design-004 §3). Move the write to a system, an input fact, or an app op OUTSIDE useIslandFrame/render.`,\n );\n });\n }\n\n return {\n enabled,\n begin() {\n if (!enabled) return;\n if (armed) throw new Error(\"ice: render write trap begin() while already armed.\");\n armed = true;\n },\n end() {\n armed = false;\n },\n dispose() {\n armed = false;\n unregister?.();\n unregister = null;\n },\n };\n}\n","/**\n * The GL bridge — the engine↔R3F seam (design-004 §3, two-level invalidation).\n *\n * Owns everything ENGINE-facing: the module-side island state, the island\n * registry (scene+camera handles the frame pass iterates), per-island dirt\n * observers, the `r3fInvalidator`/`r3fAdvance` reflectors, `useIslandFrame`\n * callbacks, the render write trap, and entity-death cleanup. Everything\n * GL-facing (FBO pool, quads, the actual passes) lives in `GLViews`, whose\n * lifetime is the Canvas/context's — the bridge outlives Canvas remounts\n * (HMR) and carries the frame wiring across them.\n *\n * Two-level invalidation, mechanized:\n * - COMPOSITE dirt (cheap — re-run the frame pass, sample cached textures):\n * camera/viewport via the reflector; per-island Position Tier-3; the frame\n * ChildOf reorder wake (petition 8 — quad renderOrder is sibling order);\n * island enter/exit via register/unregister. All call `requestFrame()`.\n * - ISLAND dirt (expensive — repaint the FBO): per-island props-group and\n * Size Tier-3 → `bumpPaint()` + `requestFrame()`; the animation signal\n * (declared `animated` / live `useIslandFrame` refs) and band crossings\n * are evaluated IN the frame pass (band repaints suppressed while\n * `Camera.gesturing`; the gesture-end camera write re-fires the reflector,\n * so the once-at-gesture-end repaint needs no extra machinery).\n *\n * REFLECT-PHASE ADVANCE (design-004 §3 amendment, 2026-07-20 — the pan-lag\n * fix): the composite render is driven FROM the engine's reflect phase, not\n * from R3F's demand loop. `requestFrame()` only latches `wantsFrame`; the\n * `r3fAdvance` reflector (`always: true` — registered right after the\n * observed invalidator so same-flush dirt is consumed) calls the wired\n * `renderNow` (R3F `advance`) synchronously. DOM plane transforms and the GL\n * composite therefore commit in the SAME task and present in the same frame.\n * The prior wiring (`invalidate()` → R3F's own rAF) could only arm R3F for\n * the NEXT frame, and rAF registration order between the two loops is sticky\n * luck — field-measured on 2026-07-20: R3F rendering the PREVIOUS frame's\n * camera while the DOM plane showed the current one, a permanent one-frame\n * smear under fast pans. Ambient animation rides the same seam: the pass\n * reports its self-sustain plan via `schedulePass`, and the due-time check\n * replaces the old wake-up timer (the engine loop runs every frame anyway).\n * The Canvas must mount `frameloop=\"never\"` — a self-scheduling loop would\n * re-render out of phase again.\n *\n * Runtime-three-free (type-only imports): unit tests drive the bridge with a\n * real world and fake scene/camera handles, no GL context.\n */\nimport type { OrthographicCamera, Scene } from \"three\";\nimport {\n Camera,\n Opacity,\n PrefabId,\n Position,\n Size,\n StageMode,\n Viewport,\n createSiblingOrderIndex,\n widgets,\n type Engine,\n type Entity,\n type SiblingOrderIndex,\n} from \"@ice/core\";\nimport { LIFT_DEFAULT_MS, createIslandStateStore, type IslandStateStore } from \"./island-state\";\nimport { createRenderWriteTrap, type RenderWriteTrap } from \"./dev-write-trap\";\n\nexport interface IslandHandle {\n readonly scene: Scene;\n readonly camera: OrthographicCamera;\n}\n\n/** `useIslandFrame` callback: dt in ms, fired only on frames its island paints. */\nexport type IslandFrameCallback = (dtMs: number) => void;\n\nexport interface GLBridgeOpts {\n /** Arm the zero-render→ECS-writes trap (DEV builds / traces). Default false. */\n readonly devAssertRenderWrites?: boolean;\n /**\n * Injected monotonic clock for the ambient-animation due-time (tests pass a\n * stub — the pool's injected-`now` precedent). Default `performance.now`.\n */\n readonly now?: () => number;\n}\n\nexport interface GLBridge {\n readonly engine: Engine;\n readonly state: IslandStateStore;\n readonly renderAssert: RenderWriteTrap;\n /**\n * The frame ordinal cache (petition 8): the compositor pass reads quad\n * renderOrder from it, and its `ordinals()` read resets the staleness the\n * bridge's reorder wake filters on — bridge and pass MUST share it.\n */\n readonly order: SiblingOrderIndex;\n /**\n * Island mount (the `<Island>` component): registers the scene/camera pair,\n * stamps `animatedDecl` from the widget type, and arms the per-island dirt\n * observers. The returned cleanup removes handle + observers ONLY — state\n * and any pooled FBO survive (retention is decoupled from cull; they die on\n * entity death, reset, or eviction).\n */\n registerIsland(entity: Entity, handle: IslandHandle): () => void;\n islandFor(entity: Entity): IslandHandle | undefined;\n islands(): IterableIterator<[Entity, IslandHandle]>;\n /** Subscribe a paint-time callback; holds an animation ref while live. */\n addFrameCallback(entity: Entity, cb: IslandFrameCallback): () => void;\n frameCallbacksFor(entity: Entity): readonly IslandFrameCallback[];\n /**\n * Composite invalidation — latch a frame pass (coalesced). Consumed by the\n * `r3fAdvance` reflector on the NEXT engine flush: dirt raised during a\n * step (observers, the invalidator reflector) renders the SAME frame; dirt\n * raised outside a step (React effects) renders on the next tick.\n */\n requestFrame(): void;\n /** Island invalidation — this island must repaint (props/size/manual dirt). */\n bumpPaint(entity: Entity): void;\n /**\n * Composite-quad lift scale (1 = rest). Scales the CARD on the canvas,\n * corners intact. Sets the TARGET: the compositor pass eases the drawn\n * value there over `durationMs` (default 180 — the DOM card-lift spring;\n * 0 snaps). Mid-flight retargets restart from the current drawn value.\n */\n setCompositeScale(entity: Entity, scale: number, durationMs?: number): void;\n /**\n * Composite-quad opacity (1 = rest) — the lift's fade twin. MULTIPLIES the\n * widget's durable `Opacity` cell in the pass (presentation-transient over\n * the doc fact). Sets the TARGET: the pass eases the drawn value there over\n * `durationMs` (default 180; 0 snaps); mid-flight retargets restart from the\n * current drawn value.\n */\n setCompositeOpacity(entity: Entity, opacity: number, durationMs?: number): void;\n /**\n * GLViews wires R3F's `advance` here (null on unmount). Called ONLY by the\n * `r3fAdvance` reflector, synchronously inside the engine's reflect phase —\n * the same task the DOM reflectors write in, so both surfaces present the\n * same camera. While unwired, latched dirt survives and renders on the\n * first flush after (re)mount.\n */\n setRenderNow(fn: ((nowMs: number) => void) | null): void;\n /**\n * The pass reports how the frame loop continues (`selfSustainPlan`):\n * `\"now\"` latches an immediate next frame (lift eases, stagger backlogs —\n * native refresh); a number arms the ambient-animation due-time (the\n * `maxAnimationFps` cap — replaces the old wake-up timer); `\"none\"` parks.\n * Each pass re-reports, so the due-time is always the LAST pass's plan.\n */\n schedulePass(plan: \"none\" | \"now\" | number): void;\n /** Tear down reflector + observers + state (doc close / app teardown). */\n uninstall(): void;\n}\n\nexport function createGLBridge(engine: Engine, opts: GLBridgeOpts = {}): GLBridge {\n const world = engine.world;\n const state = createIslandStateStore();\n const islands = new Map<Entity, IslandHandle>();\n const frameCbs = new Map<Entity, Set<IslandFrameCallback>>();\n const renderAssert = createRenderWriteTrap(world, opts.devAssertRenderWrites === true);\n\n // --- composite frame plumbing (reflect-phase advance) ---------------------\n const now = opts.now ?? ((): number => performance.now());\n let renderNow: ((nowMs: number) => void) | null = null;\n let wantsFrame = false; // latched dirt — consumed by the r3fAdvance flush\n let animDueAt: number | null = null; // ambient-animation due-time (rate cap)\n let rendering = false;\n const requestFrame = (): void => {\n wantsFrame = true;\n };\n\n // Camera (pan/zoom/gesturing edges) + viewport (resize/dpr) are the global\n // composite dirt sources; everything entity-shaped is observed per island\n // (only GL widgets wake the canvas — a static GL board ignores DOM churn).\n const removeReflector = engine.registerReflector({\n name: \"r3fInvalidator\",\n // StageMode: a background-hold flip must re-fire the pass — freezing on\n // take, and (critically) REPAINTING Hot islands on release. The observe\n // list also keeps strata enforcement armed (a rig must observe — the\n // always-flush advance reflector below deliberately observes nothing).\n observe: { resources: [Camera, Viewport, StageMode] },\n flush: () => requestFrame(),\n });\n\n // The frame driver: flushes EVERY engine frame (always), consumes the latch\n // and the animation due-time, and renders synchronously — in the same\n // reflect phase the DOM planes write in, so chrome and GL content present\n // the same camera atomically. Registered AFTER the invalidator so its dirt\n // lands in the same flush. State is cleared BEFORE renderNow: requestFrame\n // calls from inside the pass (frame callbacks, lift retargets) re-latch for\n // the next frame instead of recursing, and schedulePass (called at the\n // pass tail) re-arms the due-time after the clear.\n const removeAdvanceReflector = engine.registerReflector({\n name: \"r3fAdvance\",\n always: true,\n flush: () => {\n if (rendering) return;\n const t = now();\n if (!wantsFrame && (animDueAt === null || t < animDueAt)) return;\n if (renderNow === null) return; // unmounted: dirt stays latched\n wantsFrame = false;\n animDueAt = null; // consumed — the pass re-reports via schedulePass\n rendering = true;\n try {\n renderNow(t);\n } finally {\n rendering = false;\n }\n },\n });\n\n // Composite dirt — a reorder in the current frame moves quad renderOrder\n // (petition 8; replaces the per-island StackZ Tier-3). The wake names\n // ChildOf (pure reorders fire it); the orderStamp staleness check drops\n // other-frame churn, and the pass's `ordinals()` read resets it.\n const order = createSiblingOrderIndex(world);\n const removeOrderObserver = order.observe(() => {\n if (order.stale()) requestFrame();\n });\n\n // Death/reset: drop state so the frame pass releases the pooled FBO on its\n // next reconcile (the bridge is three-free — it never touches the pool).\n const removeWorldObserver = world.observe({\n onDestroy: (e) => {\n if (state.get(e as Entity) !== undefined) {\n state.drop(e as Entity);\n frameCbs.delete(e as Entity);\n requestFrame();\n }\n },\n onReset: () => {\n state.clear();\n frameCbs.clear();\n requestFrame();\n },\n });\n\n return {\n engine,\n state,\n renderAssert,\n order,\n\n registerIsland(entity, handle) {\n islands.set(entity, handle);\n const s = state.ensure(entity);\n\n // `animated` declaration comes from the widget type (design-004 §3\n // animation contract — explicit opt-in; plain useFrame is unattributable).\n const type = world.get(entity, PrefabId)?.id;\n const widget = typeof type === \"string\" ? widgets.get(type) : undefined;\n state.setAnimatedDecl(entity, widget?.animated === true);\n\n // Per-island dirt (Tier-3, equality-suppressed, fired at notify()):\n const unsubs: (() => void)[] = [\n // island dirt — content resolution/props changed, FBO stale:\n world.reactive.observeValue(entity, Size, () => {\n state.bumpPaint(entity);\n requestFrame();\n }),\n // composite dirt — quad transform changed, texture still good (order\n // dirt is bridge-scoped: the ChildOf reorder wake above):\n world.reactive.observeValue(entity, Position, () => requestFrame()),\n // composite dirt — the durable Opacity cell rides the quad's uOpacity,\n // never the island's FBO (a fade must not repaint the content):\n world.reactive.observeValue(entity, Opacity, () => requestFrame()),\n ];\n for (const group of widget?.groups ?? []) {\n unsubs.push(\n world.reactive.observeValue(entity, group.component, () => {\n state.bumpPaint(entity);\n requestFrame();\n }),\n );\n }\n\n // A re-entering island with a retained FBO composites immediately\n // (Warm); a fresh one is Waking — either way the pass must run.\n if (s.fboGeneration < 0) state.bumpPaint(entity);\n requestFrame();\n\n return () => {\n for (const u of unsubs) u();\n islands.delete(entity);\n requestFrame(); // exit dirt: the quad may need to hide/recompose\n };\n },\n\n islandFor: (entity) => islands.get(entity),\n islands: () => islands.entries(),\n\n addFrameCallback(entity, cb) {\n let set = frameCbs.get(entity);\n if (set === undefined) {\n set = new Set();\n frameCbs.set(entity, set);\n }\n set.add(cb);\n state.addAnimRef(entity);\n requestFrame(); // the island turns Hot next pass\n return () => {\n set.delete(cb);\n state.removeAnimRef(entity);\n };\n },\n\n frameCallbacksFor(entity) {\n const set = frameCbs.get(entity);\n return set === undefined ? [] : [...set];\n },\n\n requestFrame,\n bumpPaint(entity) {\n state.bumpPaint(entity);\n requestFrame();\n },\n\n setCompositeScale(entity, scale, durationMs = LIFT_DEFAULT_MS) {\n const s = state.ensure(entity);\n if (s.liftTarget === scale) return; // change-only — no idle churn\n s.liftTarget = scale;\n if (durationMs <= 0) {\n s.compositeScale = scale; // snap (the pre-ease behavior)\n s.liftMs = 0;\n s.liftElapsedMs = 0;\n } else {\n s.liftFrom = s.compositeScale; // retarget from the DRAWN value — no jump\n s.liftMs = durationMs;\n s.liftElapsedMs = 0;\n }\n requestFrame(); // composite-level only: no island repaint needed\n },\n\n setCompositeOpacity(entity, opacity, durationMs = LIFT_DEFAULT_MS) {\n const s = state.ensure(entity);\n if (s.opacityTarget === opacity) return; // change-only — no idle churn\n s.opacityTarget = opacity;\n if (durationMs <= 0) {\n s.compositeOpacity = opacity; // snap\n s.opacityMs = 0;\n s.opacityElapsedMs = 0;\n } else {\n s.opacityFrom = s.compositeOpacity; // retarget from the DRAWN value — no jump\n s.opacityMs = durationMs;\n s.opacityElapsedMs = 0;\n }\n requestFrame(); // composite-level only: no island repaint needed\n },\n\n setRenderNow(fn) {\n renderNow = fn;\n // No immediate render on wire-up: latched dirt renders on the next\n // engine flush (the loop runs every rAF) — same one-frame mount cost\n // as the old pending→invalidate path, without rendering mid-effect.\n },\n\n schedulePass(plan) {\n if (plan === \"now\") {\n wantsFrame = true;\n animDueAt = null;\n } else if (plan === \"none\") {\n animDueAt = null; // a latched wantsFrame from other sources survives\n } else {\n animDueAt = now() + plan;\n }\n },\n\n uninstall() {\n removeReflector();\n removeAdvanceReflector();\n removeOrderObserver();\n removeWorldObserver();\n renderAssert.dispose();\n islands.clear();\n frameCbs.clear();\n state.clear();\n renderNow = null;\n wantsFrame = false;\n animDueAt = null;\n },\n };\n}\n","/**\n * The compositor frame pass (design-004 §3) — ONE function, dependency-\n * injected so the M7 exit traces (FBO budget under zoom/cull storms, zero\n * render→ECS writes) run headlessly with fakes while `GLViews` binds it to\n * the real renderer/pool/quads.\n *\n * Order per invalidation (v1 Compositor.useFrame, re-cut law-clean):\n * 1. camera/viewport read → composite frustum (kernel — Law 13) + dynamic\n * DPR (min(dpr,1) while `Camera.gesturing`, restore on idle);\n * 2. phase update per island-state entry (kernel `computeIslandPhase`,\n * module-side state ONLY — no ECS writes anywhere in the pass);\n * 3. `useIslandFrame` callbacks for Hot islands (paint-attributed — this\n * is why plain `useFrame` is not the contract);\n * 4. paint pass, Waking-first, staggered by `maxRepaintsPerFrame`, at\n * `min(pixelRatio, maxPaintDpr) × band`; band repaints suppressed while\n * gesturing (the composite's bilinear stretch is the accepted transient)\n * and picked up on the first idle pass;\n * 5. eviction to budget (kernel `selectEvictions`; Hot/Waking immune);\n * 6. quad reconcile: transform from Position/Size (kernel Y-flip), texture\n * from the pool, sibling-order renderOrder with grabbed widgets on top\n * (design-004 §1: renderOrder-top within P2 suffices), `pool.touch` on\n * every composited quad (still-Warm textures must not look LRU-stale);\n * 7. composite render to the backbuffer;\n * 8. self-sustain report (`anyHot`/`pendingPaints` → caller invalidates).\n *\n * The world is READ ONLY here (reads outside the tick are verified-\n * unrestricted); the caller arms the render write trap around the whole pass.\n */\nimport {\n computeIslandPhase,\n compositeCameraFrustum,\n cubicBezierEase,\n fboPixelSize,\n isOutOfBand,\n selectBand,\n selectEvictions,\n worldRectToComposite,\n type EvictionCandidate,\n} from \"@ice/kernel\";\nimport {\n Active,\n Camera,\n Grab,\n navFlightActive,\n Opacity,\n Position,\n PrefabId,\n Size,\n StackZ,\n StageMode,\n Viewport,\n Visible,\n widgets,\n type Entity,\n type World,\n} from \"@ice/core\";\nimport type { GLBridge } from \"./bridge\";\n\n/** Render order far above any sane sibling ordinal or legacy z — the grabbed quad draws last. */\nconst GRABBED_RENDER_ORDER = 1e9;\n\n/**\n * The lift's spring — the same curve the DOM card lift runs in CSS\n * (`cubic-bezier(0.2, 0.9, 0.3, 1.2)`: slight overshoot, quick settle).\n * GL widgets have no CSS transitions, so the pass owns the ease.\n */\nconst LIFT_EASE = cubicBezierEase(0.2, 0.9, 0.3, 1.2);\n\n/**\n * The fade's curve — CSS `ease`, NOT the lift spring: an overshoot past 1\n * would write alpha > 1 into the composite (and a dip below the target reads\n * as flicker, not bounce). Matches the DOM chrome's `opacity … ease`\n * transition so card body and GL content fade in lockstep.\n */\nconst OPACITY_EASE = cubicBezierEase(0.25, 0.1, 0.25, 1);\n\n// --- injected surfaces (GLViews binds three.js; traces bind fakes) ----------\n\nexport interface TargetLike {\n /** Opaque texture handle threaded to the quad (three: `.texture`). */\n readonly texture: unknown;\n}\n\nexport interface PoolLike {\n acquire(key: number, worldW: number, worldH: number, effectiveDpr: number): TargetLike;\n get(key: number): TargetLike | null;\n touch(key: number): void;\n release(key: number): void;\n bytesUsed(): number;\n entryInfos(): readonly { key: number; bytes: number; lastUsedMs: number }[];\n}\n\nexport interface QuadLike {\n setTransform(x: number, y: number, sx: number, sy: number): void;\n setTexture(t: unknown): void;\n setVisible(v: boolean): void;\n setRenderOrder(n: number): void;\n /**\n * Composite opacity, 0..1 (design-004 §3: the neutral composite's whole\n * per-widget fact) — the pass passes `Opacity` cell × eased fade channel.\n */\n setOpacity(o: number): void;\n /**\n * Drag clip (v1 RFC-003, composite-space): non-exempt quads discard\n * fragments inside the rect so a dragged card's P1 DOM chrome shows\n * through. (0,0,0,0, false) = inactive.\n */\n setDragClip(minX: number, minY: number, maxX: number, maxY: number, exempt: boolean): void;\n}\n\nexport interface QuadsLike {\n ensure(key: number): QuadLike;\n remove(key: number): void;\n keys(): readonly number[];\n}\n\nexport interface GlLike {\n setRenderTarget(t: TargetLike | null): void;\n /** Clear the CURRENT target to transparent black. */\n clear(): void;\n render(scene: object, camera: object): void;\n setPixelRatio(n: number): void;\n getPixelRatio(): number;\n}\n\nexport interface CompCameraLike {\n setFrustum(f: { left: number; right: number; top: number; bottom: number; x: number; y: number }): void;\n /**\n * The ACTUAL camera object handed to `gl.render` for the composite pass —\n * three's renderer instanceof-checks it, so this must be the real\n * `OrthographicCamera`, NOT this adapter. (Field bug 2026-07-10: the pass\n * rendered with the adapter itself; three threw \"camera is not an instance\n * of THREE.Camera\" every frame and P2 never composited. The headless fakes\n * couldn't catch it — both types erase to `object` and the fake render is\n * a no-op.)\n */\n readonly raw: object;\n}\n\nexport interface IslandCameraLike {\n setFrustum(halfW: number, halfH: number): void;\n}\n\nexport interface PassContext {\n readonly world: World;\n readonly bridge: GLBridge;\n readonly pool: PoolLike;\n readonly quads: QuadsLike;\n readonly gl: GlLike;\n readonly compCamera: CompCameraLike;\n /** Adapt an island's ortho camera (three or fake) for frustum writes. */\n readonly islandCamera: (entity: Entity) => IslandCameraLike | undefined;\n readonly compositeScene: object;\n readonly maxFboBytes: number;\n readonly maxRepaintsPerFrame: number;\n /**\n * Idle ceiling on island paint resolution (design-004 §3 amendment,\n * 2026-07-14): new paints allocate at `min(pixelRatio, maxPaintDpr) × band`.\n * On a dpr-2 display the composite's bilinear upscale from a 1.5× texture is\n * visually indistinguishable (A/B knot crops) while Hot repaint cost drops\n * ~22 %. Composes with the gesture drop (pixelRatio is already 1 while\n * gesturing) and with zoom bands. `Infinity` = uncapped.\n */\n readonly maxPaintDpr: number;\n readonly dtMs: number;\n}\n\nexport interface PassStats {\n repainted: number;\n /** Paint-needing islands deferred by the stagger cap — caller re-invalidates. */\n pendingPaints: number;\n evicted: number;\n fboBytes: number;\n anyHot: boolean;\n /** A composite ease (lift scale or fade) is mid-flight — caller re-invalidates (composite-only frames). */\n liftAnimating: boolean;\n}\n\nexport function runCompositorPass(ctx: PassContext): PassStats {\n const { world, bridge, pool, quads, gl } = ctx;\n const stats: PassStats = {\n repainted: 0,\n pendingPaints: 0,\n evicted: 0,\n fboBytes: 0,\n anyHot: false,\n liftAnimating: false,\n };\n\n const cam = world.getResource(Camera);\n const vp = world.getResource(Viewport);\n if (cam === undefined || vp === undefined || vp.w === 0) return stats;\n\n // 1. composite camera + dynamic DPR ---------------------------------------\n // \"Camera in transient motion\" = user gesture OR a design-006 nav flight\n // (§8.2, answered 2026-07-16): both sweep the camera per frame and get the\n // same duty treatment — DPR drop, band-repaint suppression. Flights go\n // further (islands turn COLD, below): the flight-end camera write re-fires\n // the reflector, so everything thaws in one pass with no extra machinery.\n const inFlight = navFlightActive(world);\n const inMotion = cam.gesturing || inFlight;\n // STAGE BACKGROUND (StageMode holds, 2026-07-19): app chrome covers the\n // canvas — same freeze posture as a nav flight (retained textures stretch,\n // Hot repaints and their paint-attributed `useIslandFrame` ticks pause,\n // never-painted islands still get their first paint) but WITHOUT the\n // motion-DPR drop: a resting frame stays full quality.\n const backgrounded = (world.getResource(StageMode)?.backgroundHolds ?? 0) > 0;\n const frozen = inFlight || backgrounded;\n ctx.compCamera.setFrustum(compositeCameraFrustum(cam, vp.w, vp.h));\n const idleDpr = vp.dpr > 0 ? vp.dpr : 1;\n const targetDpr = inMotion ? Math.min(idleDpr, 1) : idleDpr;\n if (gl.getPixelRatio() !== targetDpr) gl.setPixelRatio(targetDpr);\n\n // 2. phases (module-side state only) --------------------------------------\n // `active` = current-nav-frame membership (design-004 §7): the core\n // activeMembership system tags Active on the entities of the frame you are in\n // and clears it for other containers' content. A non-Active island keeps its\n // retained FBO but classifies Dormant (kernel truth table) — evicted only\n // under real pressure, re-Warms on re-entry.\n const phaseOf = (e: number): ReturnType<typeof computeIslandPhase> => {\n const alive = world.isAlive(e as Entity);\n const active = alive && world.hasTag(e as Entity, Active);\n const visible = alive && world.hasTag(e as Entity, Visible) && bridge.islandFor(e as Entity) !== undefined;\n const s = bridge.state.get(e);\n const hasFbo = s !== undefined && s.fboGeneration >= 0 && pool.get(e) !== null;\n return computeIslandPhase(active, visible, bridge.state.isAnimating(e), hasFbo);\n };\n for (const [e, s] of bridge.state.all()) {\n s.phase = phaseOf(e);\n if (s.phase === \"Hot\") stats.anyHot = true;\n }\n\n // 3+4. paint pass (Waking first, staggered) --------------------------------\n const band = selectBand(cam.zoom);\n const effectiveDpr = Math.min(gl.getPixelRatio(), ctx.maxPaintDpr) * band;\n const toPaint: Entity[] = [];\n for (const [e, s] of bridge.state.all()) {\n if (bridge.islandFor(e as Entity) === undefined) continue; // unmounted: retained texture only\n const wantsPhase = s.phase === \"Hot\" || s.phase === \"Waking\";\n const genDirty = s.paintGeneration > s.fboGeneration;\n const bandStale = !inMotion && s.fboGeneration >= 0 && isOutOfBand(cam.zoom, s.paintedAt.band);\n // FLIGHT FREEZE (design-006 §8.2): islands with a retained texture go\n // COLD for the flight — no Hot repaints (their `useIslandFrame` ticks are\n // paint-attributed, so animation pauses with them), no props repaints,\n // no band chasing; the composite stretches the stale FBO (the accepted\n // gesture transient). NEVER-PAINTED islands (fboGeneration < 0) still get\n // their first paint — an empty quad through a 400 ms enter reads as\n // missing content, not as motion.\n const paintable = frozen ? wantsPhase && s.fboGeneration < 0 : wantsPhase || genDirty || bandStale;\n if (paintable) {\n toPaint.push(e as Entity);\n // Animation time is owed to every paint-ELIGIBLE Hot island, painted\n // this pass or deferred by the stagger cap — the deferred paint delivers\n // the balance, so the cap changes cadence, never speed (design-004 §3;\n // the pre-accumulation behavior ran 5-Hot-vs-cap-4 boards at 4/5 speed).\n // Frozen islands never reach here — a stage hold PAUSES, not banks.\n if (s.phase === \"Hot\") s.pendingDtMs += ctx.dtMs;\n }\n }\n // Order: never-painted first (cold paints jump the queue), then LEAST\n // RECENTLY PAINTED — the fairness key. Insertion order starved the same\n // island every pass once Hot count exceeded the stagger cap (five Hot vs\n // cap four froze the shapes card at boot, 2026-07-12 field report).\n toPaint.sort((a, b) => {\n const sa = bridge.state.get(a);\n const sb = bridge.state.get(b);\n const coldA = sa !== undefined && sa.fboGeneration < 0 ? 0 : 1;\n const coldB = sb !== undefined && sb.fboGeneration < 0 ? 0 : 1;\n if (coldA !== coldB) return coldA - coldB;\n return (sa?.lastPaintSeq ?? 0) - (sb?.lastPaintSeq ?? 0);\n });\n\n const cap = Math.max(1, ctx.maxRepaintsPerFrame);\n for (const e of toPaint) {\n if (stats.repainted >= cap) {\n stats.pendingPaints = toPaint.length - stats.repainted;\n break;\n }\n const handle = bridge.islandFor(e);\n const s = bridge.state.get(e);\n const size = world.isAlive(e) ? world.get(e, Size) : undefined;\n if (handle === undefined || s === undefined || size === undefined || size.w <= 0 || size.h <= 0) continue;\n\n // Hot content ticks exactly when it paints — the attribution contract —\n // and receives the FULL time owed since its last tick (its own pass dt\n // plus any stagger-deferred passes' dt banked above).\n if (s.phase === \"Hot\") {\n const owedMs = s.pendingDtMs;\n s.pendingDtMs = 0;\n for (const cb of bridge.frameCallbacksFor(e)) cb(owedMs);\n }\n\n ctx.islandCamera(e)?.setFrustum(size.w / 2, size.h / 2);\n const fbo = pool.acquire(e, size.w, size.h, effectiveDpr);\n gl.setRenderTarget(fbo);\n try {\n // A throwing island must not leave its FBO bound — that would corrupt\n // the composite into the backbuffer (v1 lesson, kept).\n gl.clear();\n gl.render(handle.scene, handle.camera);\n } finally {\n gl.setRenderTarget(null);\n }\n const px = fboPixelSize(size.w, size.h, effectiveDpr, 1);\n bridge.state.markPainted(e, { w: px.width, h: px.height, dpr: effectiveDpr, band });\n stats.repainted += 1;\n }\n\n // 5. eviction to budget (Hot/Waking immune — kernel policy) ----------------\n if (pool.bytesUsed() > ctx.maxFboBytes) {\n const candidates: EvictionCandidate<number>[] = [];\n for (const info of pool.entryInfos()) {\n const s = bridge.state.get(info.key);\n // Phases RECOMPUTED post-paint: an island that woke and painted this\n // very pass is Warm now, not Waking — the stage-2 snapshot would grant\n // it spurious eviction immunity and let a first-paint storm blow the\n // budget (caught by the storm trace).\n const phase = s === undefined ? \"Dormant\" : phaseOf(info.key);\n if (s !== undefined) s.phase = phase;\n candidates.push({\n id: info.key,\n phase,\n bytes: info.bytes,\n lastUsedMs: info.lastUsedMs,\n });\n }\n for (const key of selectEvictions(candidates, pool.bytesUsed(), ctx.maxFboBytes)) {\n if (bridge.state.get(key)?.phase === \"Dormant\") {\n // Tunable-budget breadcrumb (v1 kept it; \"no silent caps\").\n console.debug(`[ice/r3f] evicting Dormant island ${key} — consider raising the FBO budget`);\n }\n pool.release(key);\n bridge.state.markEvicted(key);\n stats.evicted += 1;\n }\n }\n\n // 6. quad reconcile ---------------------------------------------------------\n // Membership = island-state entries (they outlive cull; bridge drops them on\n // death/reset). Pool entries with no state entry are stale (post-reset) —\n // release them; quads with no state entry are removed.\n const liveKeys = new Set<number>();\n for (const [e] of bridge.state.all()) liveKeys.add(e);\n for (const info of pool.entryInfos()) {\n if (!liveKeys.has(info.key)) pool.release(info.key);\n }\n for (const key of quads.keys()) {\n if (!liveKeys.has(key)) quads.remove(key);\n }\n // Drag clip collection (v1 RFC-003): the first grabbed CHROME-carrying\n // widget's lift-scaled composite rect; every other composited quad discards\n // inside it so the dragged card's P1 DOM chrome pairs with its content.\n const hasChrome = (e: number): boolean => {\n const type = world.get(e as Entity, PrefabId)?.id;\n return typeof type === \"string\" && widgets.get(type)?.chrome != null;\n };\n const composited: Array<{ key: number; quad: QuadLike }> = [];\n let clip: { key: number; minX: number; minY: number; maxX: number; maxY: number } | null = null;\n\n // Frame ordinals once per pass (petition 8): quad renderOrder IS sibling\n // position. Reading through the bridge's shared index also resets the\n // staleness its reorder wake filters on.\n const ordinals = bridge.order.ordinals();\n\n for (const [e, s] of bridge.state.all()) {\n const quad = quads.ensure(e);\n const alive = world.isAlive(e as Entity);\n const fbo = pool.get(e);\n const pos = alive ? world.get(e as Entity, Position) : undefined;\n const size = alive ? world.get(e as Entity, Size) : undefined;\n if (s.phase === \"Dormant\" || fbo === null || s.fboGeneration < 0 || pos === undefined || size === undefined) {\n // Not composited this pass — hidden, and its FBO ages toward eviction\n // (the `continue` skips the touch() below, so a hidden island never\n // stays artificially LRU-warm). Two ways in:\n // · Dormant: a retained texture from ANOTHER nav frame (design-004 §7).\n // Visibility is derived every pass, so re-entry (Active again → Warm)\n // shows the quad next pass — never latched.\n // · evicted-while-retained: hidden until first repaint (design-004 §3 —\n // instant reactivation holds only when the FBO survived).\n quad.setVisible(false);\n continue;\n }\n const q = worldRectToComposite({ x: pos.x, y: pos.y, width: size.w, height: size.h });\n // Lift-on-hold scales the QUAD (center-anchored — q.x/q.y is the rect\n // center): texture + rounded alpha corners scale together, and the card\n // overlaps its neighbors — scaling the SCENE instead crops the corners\n // at the card-sized frustum (2026-07-12 field report).\n //\n // The drawn scale EASES toward its target here, advanced by ctx.dtMs\n // (deterministic under the traces — no wall clock in the pass). Elapsed\n // time is the ONLY terminator: the overshoot spring crosses the target\n // value mid-flight, so a value comparison would freeze at the crossing.\n if (s.liftElapsedMs < s.liftMs) {\n s.liftElapsedMs += ctx.dtMs;\n const t = Math.min(1, s.liftElapsedMs / s.liftMs);\n s.compositeScale = t >= 1 ? s.liftTarget : s.liftFrom + (s.liftTarget - s.liftFrom) * LIFT_EASE(t);\n if (t < 1) stats.liftAnimating = true;\n }\n // The fade eases the same way (same terminator rationale), on its own\n // non-overshoot curve — see OPACITY_EASE.\n if (s.opacityElapsedMs < s.opacityMs) {\n s.opacityElapsedMs += ctx.dtMs;\n const t = Math.min(1, s.opacityElapsedMs / s.opacityMs);\n s.compositeOpacity =\n t >= 1 ? s.opacityTarget : s.opacityFrom + (s.opacityTarget - s.opacityFrom) * OPACITY_EASE(t);\n if (t < 1) stats.liftAnimating = true;\n }\n const lift = s.compositeScale;\n quad.setTransform(q.x, q.y, q.sx * lift, q.sy * lift);\n quad.setTexture(fbo.texture);\n // Drawn opacity = the widget's durable Opacity cell × the eased fade\n // channel (absent cell = 1). Clamped: CompositeMaterial passes through\n // unclamped, and userland cells are raw f32s.\n const baseOpacity = world.get(e as Entity, Opacity)?.a ?? 1;\n quad.setOpacity(Math.min(1, Math.max(0, baseOpacity * s.compositeOpacity)));\n const grabbed = world.get(e as Entity, Grab) !== undefined;\n // Sibling ordinal, else the legacy StackZ fallback (pre-schema-2 read-only\n // docs are ALL-fallback; mixed frames are nominally impossible, and the\n // two scales interleaving there is accepted — see core sibling-order.ts).\n quad.setRenderOrder(\n grabbed || lift !== 1\n ? GRABBED_RENDER_ORDER\n : (ordinals.get(e as Entity) ?? world.get(e as Entity, StackZ)?.z ?? 0),\n );\n quad.setVisible(true);\n pool.touch(e);\n composited.push({ key: e, quad });\n if (clip === null && grabbed && hasChrome(e)) {\n const hw = (q.sx * lift) / 2;\n const hh = (q.sy * lift) / 2;\n clip = { key: e, minX: q.x - hw, minY: q.y - hh, maxX: q.x + hw, maxY: q.y + hh };\n }\n }\n // Apply after the loop — the grabbed widget may reconcile after a neighbor.\n for (const { key, quad } of composited) {\n if (clip === null) quad.setDragClip(0, 0, 0, 0, false);\n else quad.setDragClip(clip.minX, clip.minY, clip.maxX, clip.maxY, key === clip.key);\n }\n\n // 7. composite to the backbuffer -------------------------------------------\n gl.setRenderTarget(null);\n gl.clear();\n gl.render(ctx.compositeScene, ctx.compCamera.raw);\n\n stats.fboBytes = pool.bytesUsed();\n // Backgrounded stages report NO Hot demand: with anyHot suppressed the\n // self-sustain loop stops requesting frames and the GPU goes fully idle —\n // the whole point of the hold. (A flight keeps anyHot semantics: its\n // camera writes drive the frames regardless.) The StageMode flip itself\n // re-fires this reflector on release — the bridge observes the resource —\n // so the first foreground pass repaints Hot islands with no extra wake.\n if (backgrounded) stats.anyHot = false;\n return stats;\n}\n","/**\n * GLViews — the P2 root (design-004 §1/§3). Mount ONE inside an R3F\n * `<Canvas frameloop=\"never\">` that the app positions as the GL-views plane\n * (absolute inset-0, `pointer-events: none` — the router owns GL hit\n * testing; the canvas element never sees pointers).\n *\n * `frameloop=\"never\"` is the contract (design-004 §3 amendment, 2026-07-20):\n * frames are driven by the ENGINE's reflect phase — the bridge's `r3fAdvance`\n * reflector calls R3F `advance()` synchronously in the same task the DOM\n * reflectors write their transforms, so card chrome and GL content present\n * the same camera every frame. A self-scheduling loop (\"demand\"/\"always\")\n * renders on its own rAF, out of phase with the DOM planes — field-measured\n * as a permanent one-frame smear under fast pans.\n *\n * Mount with `gl={{ alpha: true, antialias: false }}`: the composite pass\n * draws only textured quads whose corners are shader-rounded ALPHA, not\n * geometry, so backbuffer MSAA buys nothing — and at fullscreen dpr 2 it\n * costs ~21 % of the GPU frame (2026-07-14 A/B). Island edges keep their own\n * MSAA 4 inside the FBOs (pool.ts), which is where the 3D geometry lives.\n *\n * Owns everything whose lifetime IS the GL context's: the FBO pool, the\n * shared unit-quad geometry, the per-widget composite quads, the composite\n * camera, and the priority-1 `useFrame` that runs `runCompositorPass` (which\n * suppresses R3F's default render — the pass owns the whole frame). Island\n * membership mirrors `WidgetRoot`: the same widget mount store, filtered to\n * `surface: \"gl\"`, hidden (culled) entries unmounted — their FBOs stay\n * pooled, that's the retention decoupling.\n *\n * StrictMode/HMR: pool + quads are lazy-init'd and re-created if a previous\n * instance was disposed (v1 lesson — cleanup-then-remount reuses the\n * component instance, so refs may point at disposed objects).\n */\nimport { useFrame, useThree } from \"@react-three/fiber\";\nimport {\n createElement,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n type ReactElement,\n} from \"react\";\nimport { Mesh, OrthographicCamera, PlaneGeometry, type Texture, type WebGLRenderTarget } from \"three\";\nimport { selectBand } from \"@ice/kernel\";\nimport {\n Camera,\n Culled,\n PrefabId,\n RUNTIME_BUDGETS,\n Visible,\n defineQuery,\n widgets,\n type Engine,\n type Entity,\n type WidgetMountStore,\n} from \"@ice/core\";\nimport type { GLBridge } from \"./bridge\";\nimport { CompositeMaterial } from \"./composite-material\";\nimport {\n runCompositorPass,\n type GlLike,\n type QuadLike,\n type QuadsLike,\n type TargetLike,\n} from \"./compositor-pass\";\nimport { Island } from \"./island\";\nimport { RenderTargetPool } from \"./pool\";\nimport { selfSustainPlan } from \"./self-sustain\";\n\nexport interface GLViewsProps {\n readonly engine: Engine;\n readonly bridge: GLBridge;\n readonly store: WidgetMountStore;\n /** FBO byte budget (default `RUNTIME_BUDGETS.fboBytes`, 256 MB). */\n readonly maxFboBytes?: number;\n /** Repaint stagger per composited frame (v1 default 4). */\n readonly maxRepaintsPerFrame?: number;\n /**\n * Ambient-animation rate cap (default 60; `Infinity` = uncapped). Applies\n * ONLY to self-sustained frames — Hot islands and stagger backlogs park the\n * loop between paints instead of spinning at native refresh (5 Hot islands\n * at 120 Hz dpr-2 measured 96 % GPU duty at idle, 2026-07-14). Lift eases\n * and externally invalidated frames (camera, drags, props dirt) still run\n * at display rate. Approximate: frames land on the vsync grid.\n */\n readonly maxAnimationFps?: number;\n /**\n * Idle paint-DPR ceiling (default 1.5; `Infinity` = uncapped): island FBOs\n * allocate at `min(pixelRatio, maxPaintDpr) × band`. On dpr-2 displays the\n * composite's bilinear upscale from 1.5× is visually indistinguishable\n * (2026-07-14 A/B) and cuts Hot repaint cost ~22 %.\n */\n readonly maxPaintDpr?: number;\n /**\n * Shared IBL: stamped as `scene.environment` on EVERY island's private\n * scene (arrival/change repaints all islands). Load it app-side (e.g.\n * drei's useEnvironment in a Suspense boundary) — undefined until then is\n * fine; islands paint unlit-by-IBL and repaint when it lands.\n */\n readonly environment?: Texture | null;\n /**\n * GL frame profiling (2026-07-13): fires once per composited frame with the\n * pass's real costs. CPU/counts/pass-shape are engine-measured every\n * profiled frame; GPU ms rides stats-gl's headless `StatsProfiler`\n * (EXT_disjoint_timer_query / WebGPU timestamps — 0 where unsupported, e.g.\n * Safari without its flag), DYNAMICALLY imported on first use so the\n * dependency costs nothing when profiling is off. Feed the numbers to the\n * devtools profiler HUD as lanes (`devtools.lane(\"gpu\", s.gpuMs)`).\n */\n readonly onFrameStats?: (stats: GlFrameStats) => void;\n}\n\n/**\n * One profiled composite frame — see {@link GLViewsProps.onFrameStats}.\n * MIRRORED structurally as `GlPanelStats` in @ice/devtools (which cannot\n * import r3f under the walls) — keep the shapes aligned.\n */\nexport interface GlFrameStats {\n /** Whole-pass main-thread ms (reconcile + island paints + composite). */\n readonly cpuMs: number;\n /** GPU ms summed across the pass's render calls (0 until queries resolve / unsupported). */\n readonly gpuMs: number;\n /** stats-gl smoothed fps (0 until the profiler is live). */\n readonly fps: number;\n /** `renderer.info` aggregated across ALL of this pass's render calls. */\n readonly drawCalls: number;\n readonly triangles: number;\n readonly points: number;\n readonly lines: number;\n /** Live compiled shader programs (renderer-lifetime, not per-frame). */\n readonly programs: number;\n readonly geometries: number;\n readonly textures: number;\n /** Virtual texturing: live island render targets + their summed resolution. */\n readonly renderTargets: number;\n readonly renderMegaPixels: number;\n readonly fboBytes: number;\n readonly fboBudgetBytes: number;\n /** Island phase census (the demand/retention state machine, design-004 §3/§7). */\n readonly islands: {\n readonly total: number;\n readonly hot: number;\n readonly warm: number;\n readonly waking: number;\n readonly cold: number;\n readonly dormant: number;\n };\n /** Live targets per painted zoom band (\"×1\", \"×0.5\", …) — the LOD downgrade census. */\n readonly bandHistogram: Readonly<Record<string, number>>;\n /** This pass's shape (PassStats). */\n readonly repainted: number;\n readonly pendingPaints: number;\n readonly evicted: number;\n /** LOD context: camera zoom → hysteresis band → the DPR new paints get. */\n readonly zoom: number;\n readonly band: number;\n readonly effectiveDpr: number;\n /** Scene population: Visible vs Culled widgets (all surfaces). */\n readonly visibleWidgets: number;\n readonly culledWidgets: number;\n}\n\n/** The slice of stats-gl's StatsProfiler we drive (structural — the import is dynamic). */\ninterface GpuProfilerLike {\n update(): void;\n getData(): { fps: number; cpu: number; gpu: number };\n dispose(): void;\n}\n\n// Scene-population census (profiling only — never queried when the seam is off).\nconst visibleWidgetsQ = defineQuery([Visible]);\nconst culledWidgetsQ = defineQuery([Culled]);\n\nexport function GLViews({\n engine,\n bridge,\n store,\n maxFboBytes = RUNTIME_BUDGETS.fboBytes,\n maxRepaintsPerFrame = 4,\n maxAnimationFps = 60,\n maxPaintDpr = 1.5,\n environment,\n onFrameStats,\n}: GLViewsProps): ReactElement {\n const world = engine.world;\n const gl = useThree((s) => s.gl);\n const scene = useThree((s) => s.scene);\n const set = useThree((s) => s.set);\n const advance = useThree((s) => s.advance);\n const frameloop = useThree((s) => s.frameloop);\n const clock = useThree((s) => s.clock);\n\n // --- context-lifetime resources (lazy + disposed-aware, v1 pattern) ------\n const poolRef = useRef<RenderTargetPool | null>(null);\n if (poolRef.current === null || poolRef.current.isDisposed()) {\n poolRef.current = new RenderTargetPool();\n }\n const pool = poolRef.current;\n\n const quadGeometry = useMemo(() => new PlaneGeometry(1, 1), []);\n const compCamera = useMemo(() => new OrthographicCamera(0, 1, 0, -1, 0.1, 10000), []);\n\n // Make the composite camera the Canvas default so R3F utilities that read\n // `state.camera` (raycaster defaults etc.) have a sensible reference.\n useEffect(() => {\n set({ camera: compCamera as unknown as never });\n }, [set, compCamera]);\n\n // Composite quads: engine-neutral meshes in the default scene ({opacity}\n // is the whole per-widget composite fact; app looks are app hooks).\n const quadsRef = useRef(new Map<number, Mesh>());\n const quads: QuadsLike = useMemo(\n () => ({\n ensure(key: number): QuadLike {\n let mesh = quadsRef.current.get(key);\n if (mesh === undefined) {\n mesh = new Mesh(quadGeometry, new CompositeMaterial());\n mesh.frustumCulled = false;\n mesh.visible = false; // hidden until the island has painted once\n scene.add(mesh);\n quadsRef.current.set(key, mesh);\n }\n const m = mesh;\n return {\n setTransform: (x, y, sx, sy) => {\n m.position.set(x, y, 0);\n m.scale.set(sx, sy, 1);\n },\n setTexture: (t) => (m.material as CompositeMaterial).setMap(t as WebGLRenderTarget[\"texture\"]),\n setVisible: (v) => {\n m.visible = v;\n },\n setRenderOrder: (n) => {\n m.renderOrder = n;\n },\n setOpacity: (o) => (m.material as CompositeMaterial).setOpacity(o),\n setDragClip: (minX, minY, maxX, maxY, exempt) => {\n const mat = m.material as CompositeMaterial;\n mat.setDraggedRect(minX, minY, maxX, maxY);\n mat.setIsDragged(exempt);\n },\n };\n },\n remove(key: number) {\n const mesh = quadsRef.current.get(key);\n if (mesh !== undefined) {\n scene.remove(mesh);\n (mesh.material as CompositeMaterial).dispose();\n quadsRef.current.delete(key);\n }\n },\n keys: () => [...quadsRef.current.keys()],\n }),\n [scene, quadGeometry],\n );\n\n // Renderer adapter (explicit clear color: transparent black, v1 contract).\n const glLike: GlLike = useMemo(\n () => ({\n setRenderTarget: (t) => gl.setRenderTarget(t as WebGLRenderTarget | null),\n clear: () => {\n gl.setClearColor(0x000000, 0);\n gl.clear(true, true, false);\n },\n render: (s, c) => gl.render(s as never, c as never),\n setPixelRatio: (n) => gl.setPixelRatio(n),\n getPixelRatio: () => gl.getPixelRatio(),\n }),\n [gl],\n );\n\n // Wire the reflect-phase renderer for the life of this Canvas: the bridge's\n // r3fAdvance reflector calls this synchronously inside the engine flush.\n //\n // R3F's `frameloop=\"never\"` clock contract (their loop.ts): the advance\n // timestamp IS the clock, in SECONDS — `delta = timestamp − clock.elapsedTime`\n // feeds useFrame directly. Passing milliseconds ran every island animation\n // ~1000× fast (field report 2026-07-20, minutes after the advance seam\n // landed). And `setFrameloop('never')` zeroes elapsedTime with the clock\n // stopped, so the FIRST advance would deliver the page's whole uptime as\n // one delta — seed elapsedTime to \"now\" so the first frame steps from ≈0.\n useEffect(() => {\n clock.elapsedTime = performance.now() / 1000;\n bridge.setRenderNow((nowMs) => advance(nowMs / 1000, true));\n return () => bridge.setRenderNow(null);\n }, [bridge, advance, clock]);\n\n // The frameloop contract is a prop on the app's <Canvas> — unenforceable\n // from here, so misconfiguration gets a loud DEV hint instead of a silent\n // return of the one-frame pan smear this seam exists to prevent.\n useEffect(() => {\n if (frameloop !== \"never\") {\n console.warn(\n `[ice/r3f] GLViews: <Canvas frameloop=\"${frameloop}\"> — use frameloop=\"never\". The engine drives frames (reflect-phase advance); a self-scheduling loop renders out of phase with the DOM planes.`,\n );\n }\n }, [frameloop]);\n\n // --- GL profiling (opt-in via onFrameStats) --------------------------------\n // The callback rides a ref (no useFrame re-subscribe); the GPU profiler is\n // dynamic-imported on first profiled frame. stats-gl's three-renderer init\n // PATCHES gl.render to bracket every call, so the pass's N island paints +\n // composite sum into one per-frame gpu figure.\n const statsCbRef = useRef(onFrameStats);\n statsCbRef.current = onFrameStats;\n const gpuProfilerRef = useRef<GpuProfilerLike | null>(null);\n const gpuProfilerState = useRef<\"idle\" | \"loading\" | \"ready\" | \"failed\">(\"idle\");\n useEffect(\n () => () => {\n gpuProfilerRef.current?.dispose();\n gpuProfilerRef.current = null;\n gpuProfilerState.current = \"idle\";\n },\n [],\n );\n\n // Teardown: quads + pool die with the context (island state survives in\n // the bridge — a remounted Canvas re-wakes islands from Waking).\n useEffect(() => {\n const quadMap = quadsRef.current;\n return () => {\n for (const mesh of quadMap.values()) {\n scene.remove(mesh);\n (mesh.material as CompositeMaterial).dispose();\n }\n quadMap.clear();\n pool.dispose();\n for (const [key] of bridge.state.all()) bridge.state.markEvicted(key);\n };\n }, [scene, pool, bridge]);\n\n // The pass. Priority 1 suppresses R3F's default render — we own the frame.\n useFrame((_, delta) => {\n const profiling = statsCbRef.current !== undefined;\n if (profiling) {\n if (gpuProfilerState.current === \"idle\") {\n gpuProfilerState.current = \"loading\";\n void import(\"stats-gl\")\n .then(async ({ StatsProfiler }) => {\n const p = new StatsProfiler({ trackGPU: true }) as unknown as GpuProfilerLike & {\n init(renderer: unknown): Promise<void>;\n };\n await p.init(gl); // three-renderer init: patches gl.render to bracket every call\n gpuProfilerRef.current = p;\n gpuProfilerState.current = \"ready\";\n })\n .catch(() => {\n gpuProfilerState.current = \"failed\"; // headless / no WebGL2 — CPU + counts still report\n });\n }\n // Aggregate renderer.info across ALL of this pass's render calls (three's\n // default autoReset clears after EACH call — only the composite would count).\n gl.info.autoReset = false;\n gl.info.reset();\n } else if (!gl.info.autoReset) {\n gl.info.autoReset = true; // profiling stopped — restore vanilla three behavior\n }\n const passStart = performance.now(); // profiling cpuMs + the rate cap's schedule anchor\n bridge.renderAssert.begin();\n let stats: ReturnType<typeof runCompositorPass>;\n try {\n stats = runCompositorPass({\n world,\n bridge,\n pool,\n quads,\n gl: glLike,\n compCamera: {\n raw: compCamera, // the REAL camera — gl.render instanceof-checks it\n setFrustum: (f) => {\n compCamera.left = f.left;\n compCamera.right = f.right;\n compCamera.top = f.top;\n compCamera.bottom = f.bottom;\n compCamera.position.set(f.x, f.y, 1000);\n compCamera.updateProjectionMatrix();\n },\n },\n islandCamera: (entity) => {\n const handle = bridge.islandFor(entity);\n if (handle === undefined) return undefined;\n return {\n setFrustum: (halfW, halfH) => {\n handle.camera.left = -halfW;\n handle.camera.right = halfW;\n handle.camera.top = halfH;\n handle.camera.bottom = -halfH;\n handle.camera.updateProjectionMatrix();\n },\n };\n },\n compositeScene: scene,\n maxFboBytes,\n maxRepaintsPerFrame,\n maxPaintDpr,\n dtMs: delta * 1000,\n });\n } finally {\n bridge.renderAssert.end();\n }\n const cb = statsCbRef.current;\n if (cb !== undefined) {\n const gpu = gpuProfilerRef.current;\n gpu?.update();\n const d = gpu?.getData();\n const info = gl.info;\n\n // Island / virtual-texture census: phases + live-target resolutions come\n // straight from the bridge state the pass just stamped (paintedAt holds\n // each FBO's real pixel dims + the zoom band it was painted at).\n let total = 0;\n let hot = 0;\n let warm = 0;\n let waking = 0;\n let cold = 0;\n let dormant = 0;\n let pixels = 0;\n const bandHistogram: Record<string, number> = {};\n for (const [e, s] of bridge.state.all()) {\n total++;\n if (s.phase === \"Hot\") hot++;\n else if (s.phase === \"Warm\") warm++;\n else if (s.phase === \"Waking\") waking++;\n else if (s.phase === \"Dormant\") dormant++;\n else cold++;\n if (s.fboGeneration >= 0 && pool.get(e) !== null) {\n pixels += s.paintedAt.w * s.paintedAt.h;\n const key = `×${s.paintedAt.band}`;\n bandHistogram[key] = (bandHistogram[key] ?? 0) + 1;\n }\n }\n let visibleWidgets = 0;\n let culledWidgets = 0;\n world.query(visibleWidgetsQ).each((b) => {\n visibleWidgets += b.count;\n });\n world.query(culledWidgetsQ).each((b) => {\n culledWidgets += b.count;\n });\n const zoom = world.getResource(Camera)?.zoom ?? 1;\n const band = selectBand(zoom);\n\n cb({\n cpuMs: performance.now() - passStart,\n gpuMs: d?.gpu ?? 0,\n fps: d?.fps ?? 0,\n drawCalls: info.render.calls,\n triangles: info.render.triangles,\n points: info.render.points,\n lines: info.render.lines,\n programs: info.programs?.length ?? 0,\n geometries: info.memory.geometries,\n textures: info.memory.textures,\n renderTargets: pool.size(),\n renderMegaPixels: pixels / 1e6,\n fboBytes: pool.bytesUsed(),\n fboBudgetBytes: maxFboBytes,\n islands: { total, hot, warm, waking, cold, dormant },\n bandHistogram,\n repainted: stats.repainted,\n pendingPaints: stats.pendingPaints,\n evicted: stats.evicted,\n zoom,\n band,\n effectiveDpr: Math.min(gl.getPixelRatio(), maxPaintDpr) * band,\n visibleWidgets,\n culledWidgets,\n });\n }\n // Self-sustain: lift eases latch the immediate next engine frame (native\n // refresh); Hot islands and stagger backlogs arm the rate-capped due-time;\n // otherwise the seam parks until the next requestFrame latch. The bridge's\n // r3fAdvance reflector consumes this on the engine's own loop — no timer.\n bridge.schedulePass(selfSustainPlan(stats, performance.now() - passStart, maxAnimationFps));\n }, 1);\n\n // --- island membership (mount store → gl-surface islands) -----------------\n const entries = useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);\n const islands: ReactElement[] = [];\n for (const entry of entries) {\n if (entry.hidden) continue; // culled: island unmounts, FBO stays pooled\n if (!world.isAlive(entry.entity)) continue;\n const type = world.get(entry.entity, PrefabId)?.id;\n const widget = typeof type === \"string\" ? widgets.get(type) : undefined;\n if (widget === undefined || widget.surface !== \"gl\") continue;\n islands.push(\n createElement(Island, {\n key: String(entry.entity),\n bridge,\n world,\n entity: entry.entity as Entity,\n widget,\n ...(environment !== undefined ? { environment } : {}),\n }),\n );\n }\n return createElement(\"group\", null, islands);\n}\n","import { ShaderMaterial } from \"three\";\nimport type { Texture } from \"three\";\n\n/**\n * Neutral composite material for the island compositor (design-004 §3). One\n * instance per island quad: it samples the island's FBO texture and writes it to\n * the canvas backbuffer at `uOpacity`, with no look of its own.\n *\n * Ported from v1 `CompositionMaterial`\n * (../infinite-canvas .../r3f/compositor/CompositionMaterial.ts) STRIPPED to the\n * engine-neutral core per design-004 §3 rev 2: the v1 app-specific uniforms and\n * shader branches — the `uHotPoint`/`uHotStrength`/`uIsOverlapTarget` overlap\n * glow, the rim band, and the module-level `sharedGlowUniforms` — are DELETED.\n * Userland looks belong in userland materials (and, as of the chrome sandwich,\n * in DOM CSS).\n *\n * `uDraggedRect`/`uIsDragged` are RESTORED (2026-07-13 amendment): with\n * `defineWidget.chrome` an ENGINE feature, a dragged GL card's DOM chrome\n * lives in P1 under every other quad — neighbor fragments inside the dragged\n * card's rect must discard so the chrome+content pair floats whole (v1's\n * RFC-003 clip, re-cut from screen-space gl_FragCoord to composite-space\n * `vWorld`, so it is DPR/Y-flip-free by construction). This is compositing\n * CORRECTNESS for an engine feature, not an app look. Rect (0,0,0,0) = off.\n *\n * What is KEPT verbatim is the colour-management contract: the FBO already holds\n * sRGB-encoded, display-ready values (RenderTargetPool sets\n * `texture.colorSpace = SRGBColorSpace`), so this pass must sample-and-write\n * WITHOUT tone mapping. See the fragment-shader note below for the sRGB\n * double-encode trap and why the `<colorspace_fragment>` chunk is still required.\n */\n\nconst VERTEX_SHADER = /* glsl */ `\nvarying vec2 vUv;\nvarying vec2 vWorld;\nvoid main() {\n vUv = uv;\n vWorld = (modelMatrix * vec4(position, 1.0)).xy;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n}\n`;\n\n// Fragment shader. There is deliberately NO <tonemapping_fragment> chunk — the\n// FBO holds sRGB values already, so tone mapping would double-process them.\n//\n// The trailing <colorspace_fragment> chunk IS required, and this is the subtle\n// part (the sRGB double-encode trap): Three's texture sampler auto-DECODES the\n// sRGB FBO to linear during texture2D (because RenderTargetPool declares the\n// target's colorSpace = SRGBColorSpace). Without re-encoding to the renderer's\n// outputColorSpace (also sRGB) via <colorspace_fragment>, those linear values\n// would land in the backbuffer and read as washed-out / desaturated. So: no tone\n// map, but DO re-encode — a straight round-trip that leaves the island's pixels\n// exactly as painted.\nconst FRAGMENT_SHADER = /* glsl */ `\nuniform sampler2D map;\nuniform float uOpacity;\nuniform vec4 uDraggedRect;\nuniform float uIsDragged;\nvarying vec2 vUv;\nvarying vec2 vWorld;\n\nvoid main() {\n // Drag clip (v1 RFC-003, composite-space): while a chrome-carrying GL card\n // is dragged, every OTHER quad discards fragments inside its rect so the\n // card's P1 DOM chrome shows through. (0,0,0,0) rect ⇒ measure-zero, off.\n if (uIsDragged < 0.5 &&\n vWorld.x >= uDraggedRect.x && vWorld.x <= uDraggedRect.z &&\n vWorld.y >= uDraggedRect.y && vWorld.y <= uDraggedRect.w) {\n discard;\n }\n vec4 c = texture2D(map, vUv);\n if (c.a < 0.001) discard;\n c.a *= uOpacity;\n gl_FragColor = c;\n #include <colorspace_fragment>\n}\n`;\n\n/**\n * Per-island composite material. Each island quad gets its own instance so the\n * per-quad `map` uniform is independent; Three compiles the shader once and\n * reuses the program across instances since they share source (verify in dev via\n * `renderer.info.programs.length === 1` for the composite shader).\n */\nexport class CompositeMaterial extends ShaderMaterial {\n // Direct handles onto our two uniform cells. ShaderMaterial types `uniforms`\n // as an index signature, so `this.uniforms.map` reads as possibly-undefined\n // under strict indexing; holding the cells we created sidesteps that and keeps\n // the setters allocation-free.\n private readonly mapUniform: { value: Texture | null };\n private readonly opacityUniform: { value: number };\n private readonly draggedRectUniform: { value: [number, number, number, number] };\n private readonly isDraggedUniform: { value: number };\n\n constructor() {\n const uniforms = {\n map: { value: null as Texture | null },\n uOpacity: { value: 1 },\n // three uploads number[] as vec4 — no Vector4 allocation needed.\n uDraggedRect: { value: [0, 0, 0, 0] as [number, number, number, number] },\n uIsDragged: { value: 0 },\n };\n super({\n vertexShader: VERTEX_SHADER,\n fragmentShader: FRAGMENT_SHADER,\n uniforms,\n transparent: true,\n depthWrite: false,\n // Explicit: this pass must never tone-map (the FBO is already display-\n // ready). v1 left toneMapped at the ShaderMaterial default and relied on\n // the absent tonemapping chunk alone (CompositionMaterial.ts:140-142); we\n // set it false so the no-tone-map contract holds even if the shader ever\n // gains chunks. Behaviour is identical for the current shader.\n toneMapped: false,\n });\n // ShaderMaterial keeps the passed `uniforms` object by reference, so these\n // handles stay in sync with `this.uniforms`.\n this.mapUniform = uniforms.map;\n this.opacityUniform = uniforms.uOpacity;\n this.draggedRectUniform = uniforms.uDraggedRect;\n this.isDraggedUniform = uniforms.uIsDragged;\n }\n\n /** Bind the island's FBO texture (null clears). */\n setMap(map: Texture | null): void {\n this.mapUniform.value = map;\n }\n\n /** Composite opacity. Pass-through — no clamping; callers pass valid 0..1. */\n setOpacity(opacity: number): void {\n this.opacityUniform.value = opacity;\n }\n\n /**\n * Drag clip, composite-space min/max (v1's uDraggedRect re-cut from screen\n * space). (0,0,0,0) = inactive. Mutates the vec4 in place — no allocation.\n */\n setDraggedRect(minX: number, minY: number, maxX: number, maxY: number): void {\n const r = this.draggedRectUniform.value;\n r[0] = minX;\n r[1] = minY;\n r[2] = maxX;\n r[3] = maxY;\n }\n\n /** True on the dragged card's own quad — exempt from the clip. */\n setIsDragged(isDragged: boolean): void {\n this.isDraggedUniform.value = isDragged ? 1 : 0;\n }\n\n // dispose() is inherited from ShaderMaterial — it fires the dispose event that\n // frees the compiled program; no override needed.\n}\n","/**\n * One island = one GL widget's private Scene + center-origin Y-up ortho\n * camera, mounted via R3F `createPortal` so the content tree (hooks, state,\n * drei) lives OUTSIDE the composite scene and paints into a pooled FBO\n * (design-004 §3; the island-space convention is kernel's — Law 13).\n *\n * Deliberately thin: registration/unregistration is the ONLY effect. The\n * camera frustum is written by the frame pass at paint time from the live\n * `Size` (v1 set it from a React effect AND bumped an ECS component — both\n * moved out; islands never write ECS). Unmount (cull) drops scene + camera;\n * the FBO and island state survive in the pool/bridge — retention is\n * decoupled from culling by design.\n */\nimport { createPortal } from \"@react-three/fiber\";\nimport { createElement, useEffect, useMemo, type ComponentType, type ReactElement } from \"react\";\nimport { OrthographicCamera, Scene, type Texture } from \"three\";\nimport type { Entity, WidgetType, World } from \"@ice/core\";\nimport type { WidgetComponentProps } from \"@ice/react\";\nimport type { GLBridge } from \"./bridge\";\nimport { IslandContext } from \"./use-island-frame\";\n\nexport interface IslandProps {\n readonly bridge: GLBridge;\n readonly world: World;\n readonly entity: Entity;\n readonly widget: WidgetType;\n /** Shared IBL for this island's private scene (see GLViews.environment). */\n readonly environment?: Texture | null;\n}\n\nexport function Island({ bridge, world, entity, widget, environment }: IslandProps): ReactElement | null {\n const scene = useMemo(() => new Scene(), []);\n const camera = useMemo(() => {\n // Generous depth range (ortho — free): at z=100 a large card's rotating\n // geometry (e.g. a 329px torus knot's lobe swinging toward the camera)\n // crossed the near plane and clipped (field report 2026-07-12).\n const cam = new OrthographicCamera(-1, 1, 1, -1, 0.1, 2000);\n cam.position.set(0, 0, 500); // +Z looking at the XY content plane\n cam.lookAt(0, 0, 0);\n return cam;\n }, []);\n\n useEffect(\n () => bridge.registerIsland(entity, { scene, camera }),\n [bridge, entity, scene, camera],\n );\n\n // Shared environment (v1's Compositor propagated its env map to every widget\n // scene; v3 islands are private, so propagation is this explicit stamp). The\n // HDR usually arrives AFTER the first cold paint — bumpPaint repaints even\n // static (animated:false) islands with the new lighting.\n useEffect(() => {\n scene.environment = environment ?? null;\n bridge.bumpPaint(entity);\n }, [environment, scene, bridge, entity]);\n\n const View = widget.component as ComponentType<WidgetComponentProps>;\n if (View == null) return null;\n\n return createPortal(\n createElement(\n IslandContext.Provider,\n { value: { bridge, entity } },\n createElement(View, { entity, world }),\n ),\n scene,\n ) as unknown as ReactElement;\n}\n","/**\n * The island animation contract (design-004 §3, rev 2 corrected).\n *\n * Plain `useFrame` CANNOT drive island repaints: R3F portals share the\n * root's single commingled `internal.subscribers` array, so a subscription\n * cannot be attributed to an island without probing R3F internals (banned).\n * `useIslandFrame` is the engine's wrapper: it registers the callback WITH\n * the island (bridge-side), which (a) holds the island's animation signal\n * while subscribed — the island turns Hot and repaints every visible frame —\n * and (b) fires the callback exactly when its island paints, so content\n * mutation and texture refresh can never desynchronize.\n *\n * The callback runs INSIDE the render pass: it may mutate three objects in\n * the island scene freely, but any ECS write throws under the DEV render\n * write trap (M7 exit). Engine state changes belong in systems or ops.\n */\nimport { createContext, useCallback, useContext, useEffect, useRef } from \"react\";\nimport type { Entity } from \"@ice/core\";\nimport type { GLBridge, IslandFrameCallback } from \"./bridge\";\n\nexport interface IslandContextValue {\n readonly bridge: GLBridge;\n readonly entity: Entity;\n}\n\n/** Provided per-island by `<Island>`; null outside island content. */\nexport const IslandContext = createContext<IslandContextValue | null>(null);\n\nexport function useIslandContext(): IslandContextValue {\n const ctx = useContext(IslandContext);\n if (ctx === null) {\n throw new Error(\"ice: useIslandFrame/useIslandInvalidate must run inside a GL widget's island.\");\n }\n return ctx;\n}\n\n/** Per-frame tick while mounted (island goes Hot). `cb(dtMs)` on paint. */\nexport function useIslandFrame(cb: IslandFrameCallback): void {\n const { bridge, entity } = useIslandContext();\n const ref = useRef(cb);\n ref.current = cb; // latest closure runs without re-subscribing\n useEffect(() => bridge.addFrameCallback(entity, (dt) => ref.current(dt)), [bridge, entity]);\n}\n\n/**\n * One-shot repaint scheduler for content that changes outside React's render\n * cycle (imperative subscriptions, sockets). Bumps the island's paint\n * generation + wakes the demand loop.\n */\nexport function useIslandInvalidate(): () => void {\n const { bridge, entity } = useIslandContext();\n return useCallback(() => bridge.bumpPaint(entity), [bridge, entity]);\n}\n\n/**\n * Composite-quad lift: scales the CARD on the canvas (texture + rounded alpha\n * corners together) and pops it over neighbors while ≠1. Scaling scene content\n * instead crops the corners at the card-sized frustum — the 2026-07-12\n * hard-corner field report. Resets to 1 on unmount.\n *\n * The scale EASES to each new value (default 180ms, the DOM card-lift\n * spring — GL has no CSS transitions, so the compositor runs the curve;\n * 2026-07-13 field report: \"GL lift snaps while DOM lifts smooth\").\n * `durationMs: 0` snaps.\n */\nexport function useIslandLift(scale: number, durationMs?: number): void {\n const { bridge, entity } = useIslandContext();\n useEffect(() => {\n bridge.setCompositeScale(entity, scale, durationMs);\n }, [bridge, entity, scale, durationMs]);\n useEffect(() => () => bridge.setCompositeScale(entity, 1), [bridge, entity]);\n}\n\n/**\n * Composite-quad fade — the lift's opacity twin (e.g. the drag-lift 75 %\n * fade): eases the quad's drawn opacity to `opacity` (default 180ms; 0\n * snaps) and MULTIPLIES the widget's durable `Opacity` cell, so a transient\n * fade stacks over a doc-level opacity instead of fighting it. The DOM\n * chrome runs its own CSS `opacity … ease` transition — same duration/curve\n * family, so card body and GL content fade in lockstep. Resets to 1 on\n * unmount.\n */\nexport function useIslandOpacity(opacity: number, durationMs?: number): void {\n const { bridge, entity } = useIslandContext();\n useEffect(() => {\n bridge.setCompositeOpacity(entity, opacity, durationMs);\n }, [bridge, entity, opacity, durationMs]);\n useEffect(() => () => bridge.setCompositeOpacity(entity, 1), [bridge, entity]);\n}\n","import { SRGBColorSpace, WebGLRenderTarget } from \"three\";\n\n/**\n * Per-island FBO pool (design-004 §3). Each compositor island paints into its\n * own persistent `WebGLRenderTarget` instead of the shared canvas backbuffer,\n * so the compositor can sample islands as textures and stack them with correct\n * z / opacity.\n *\n * Ported from v1 `WidgetRenderTargetPool` (../infinite-canvas\n * .../r3f/compositor/WidgetRenderTargetPool.ts) with the design-004 §3 rev 2\n * deltas: the pool is keyed by a plain `number` (the caller's island/entity id)\n * and imports NOTHING from the ECS — it is a pure three resource, so it never\n * depends on the entity representation. Timestamps are injected (see `now`) so\n * the LRU is deterministic under test.\n *\n * Acquire returns an existing FBO when its pixel resolution matches the request;\n * otherwise the old FBO is disposed and a new one is created at the new\n * resolution. Eviction under memory pressure is a higher layer's concern — this\n * pool grows monotonically until islands are `release`d.\n */\n\n/**\n * Real GPU-allocation model for one target's bytes (2026-07-13 review finding).\n *\n * An MSAA `WebGLRenderTarget` (RGBA8, three's default `depthBuffer: true`,\n * `stencilBuffer: false`) is NOT one surface — three allocates three:\n * - the sampleable resolve texture: {@link COLOR_BYTES_PER_PIXEL} × 1;\n * - a multisample colour renderbuffer: {@link COLOR_BYTES_PER_PIXEL} × {@link SAMPLES};\n * - a multisample depth renderbuffer: {@link DEPTH_BYTES_PER_PIXEL} × {@link SAMPLES}.\n * At {@link SAMPLES} = 4 that is 4 + 16 + 16 = 36 bytes/pixel.\n *\n * v1 (and this file until now) charged a flat 8 bytes/pixel (`colour × 2`),\n * which under-counts the real allocation ~4.5×. The eviction pass in\n * compositor-pass.ts trusts `bytesUsed()` against RUNTIME_BUDGETS.fboBytes\n * (256 MB), so the undercount let real GPU use approach a gigabyte before\n * eviction fired. The model below charges the true figure so the budget bounds\n * reality.\n *\n * Single-sample ({@link SAMPLES} ≤ 1): the texture IS the colour buffer — no\n * separate resolve, no multisample multiplier — so it degrades to colour + depth.\n */\nconst COLOR_BYTES_PER_PIXEL = 4;\n\n/** Depth renderbuffer bytes per pixel (three's default depth24). */\nconst DEPTH_BYTES_PER_PIXEL = 4;\n\n/**\n * MSAA sample count. Matches the canvas's antialias setting so island edges look\n * the same as a direct-to-canvas pass (v1 WidgetRenderTargetPool.ts:73).\n */\nconst SAMPLES = 4;\n\n/** GPU bytes for one target at the given pixel size — see the allocation model above. */\nfunction targetBytes(pixelWidth: number, pixelHeight: number): number {\n const msaa = SAMPLES > 1;\n const colorBytes = COLOR_BYTES_PER_PIXEL * (msaa ? 1 + SAMPLES : 1);\n const depthBytes = DEPTH_BYTES_PER_PIXEL * (msaa ? SAMPLES : 1);\n return pixelWidth * pixelHeight * (colorBytes + depthBytes);\n}\n\ninterface PoolEntry {\n rt: WebGLRenderTarget;\n /** Pixel width = worldWidth × effectiveDpr, rounded, clamped ≥ 1. */\n pixelWidth: number;\n pixelHeight: number;\n effectiveDpr: number;\n bytes: number;\n /** Injected-clock timestamp of the most recent acquire/touch — drives LRU. */\n lastUsedMs: number;\n}\n\n/** Snapshot row returned by {@link RenderTargetPool.entryInfos}. */\nexport interface PoolEntryInfo {\n key: number;\n bytes: number;\n lastUsedMs: number;\n}\n\nexport class RenderTargetPool {\n private entries = new Map<number, PoolEntry>();\n private totalBytes = 0;\n private disposed = false;\n private readonly now: () => number;\n\n /**\n * @param now Injected monotonic clock for LRU timestamps. Defaults to\n * `performance.now()`; tests pass a deterministic stub so `lastUsedMs`\n * assertions do not depend on wall-clock timing.\n */\n constructor(now: () => number = () => performance.now()) {\n this.now = now;\n }\n\n /**\n * Get or create an FBO for `key` at the requested world size and effective\n * device-pixel-ratio. Returns the existing target unchanged when its pixel\n * dimensions already match; otherwise disposes the stale target and allocates\n * a new one sized to the new resolution.\n */\n acquire(key: number, worldW: number, worldH: number, effectiveDpr: number): WebGLRenderTarget {\n if (this.disposed) {\n throw new Error(\"RenderTargetPool: cannot acquire after dispose\");\n }\n const pixelWidth = Math.max(1, Math.round(worldW * effectiveDpr));\n const pixelHeight = Math.max(1, Math.round(worldH * effectiveDpr));\n const nowMs = this.now();\n\n const existing = this.entries.get(key);\n if (existing && existing.pixelWidth === pixelWidth && existing.pixelHeight === pixelHeight) {\n existing.lastUsedMs = nowMs;\n return existing.rt;\n }\n\n if (existing) {\n existing.rt.dispose();\n this.totalBytes -= existing.bytes;\n }\n\n const rt = new WebGLRenderTarget(pixelWidth, pixelHeight, { samples: SAMPLES });\n // sRGB colour space — without this, Three writes tone-mapped LINEAR values\n // to the FBO. The composite shader samples raw and outputs raw, and the\n // canvas backbuffer would then read the linear values as sRGB → washed-out /\n // dark. SRGBColorSpace tells Three's built-in materials to sRGB-encode when\n // writing here, so the FBO already holds display-ready values (design-004 §3;\n // the composite shader must NOT re-encode — see composite-material.ts).\n rt.texture.colorSpace = SRGBColorSpace;\n const bytes = targetBytes(pixelWidth, pixelHeight);\n this.entries.set(key, { rt, pixelWidth, pixelHeight, effectiveDpr, bytes, lastUsedMs: nowMs });\n this.totalBytes += bytes;\n return rt;\n }\n\n /** Look up an FBO without creating one. */\n get(key: number): WebGLRenderTarget | null {\n return this.entries.get(key)?.rt ?? null;\n }\n\n /**\n * Refresh `lastUsedMs` without re-acquiring. The compositor calls this for\n * every island it samples in the composition pass — without it, warm islands\n * that never repaint would freeze their timestamp at their last paint and the\n * LRU would treat still-visible islands as stale (design-004 §3).\n */\n touch(key: number): void {\n const entry = this.entries.get(key);\n if (!entry) return;\n entry.lastUsedMs = this.now();\n }\n\n /**\n * Release `key`'s FBO. Returns true if something was released. Safe after\n * dispose — returns false rather than corrupting the byte counter or\n * double-disposing the target.\n */\n release(key: number): boolean {\n if (this.disposed) return false;\n const entry = this.entries.get(key);\n if (!entry) return false;\n entry.rt.dispose();\n // Clamp at zero so out-of-order teardown never drives the counter negative.\n this.totalBytes = Math.max(0, this.totalBytes - entry.bytes);\n this.entries.delete(key);\n return true;\n }\n\n /** Total GPU bytes consumed by the pool. */\n bytesUsed(): number {\n return this.totalBytes;\n }\n\n /** Number of FBOs currently held. */\n size(): number {\n return this.entries.size;\n }\n\n /** True after `dispose()` — callers should re-create the pool instead of using it. */\n isDisposed(): boolean {\n return this.disposed;\n }\n\n /** Iterate live entries (key + target). */\n forEach(cb: (key: number, rt: WebGLRenderTarget) => void): void {\n for (const [key, entry] of this.entries) cb(key, entry.rt);\n }\n\n /**\n * Snapshot of every live entry's `bytes` + `lastUsedMs` — the input an\n * eviction pass ranks by LRU.\n */\n entryInfos(): PoolEntryInfo[] {\n const out: PoolEntryInfo[] = [];\n for (const [key, entry] of this.entries) {\n out.push({ key, bytes: entry.bytes, lastUsedMs: entry.lastUsedMs });\n }\n return out;\n }\n\n /** Dispose every FBO. After this, acquire throws and release returns false. */\n dispose(): void {\n if (this.disposed) return;\n for (const entry of this.entries.values()) entry.rt.dispose();\n this.entries.clear();\n this.totalBytes = 0;\n this.disposed = true;\n }\n}\n","/**\n * Self-sustain scheduling for the demand loop (design-004 §3 animation-rate\n * amendment, 2026-07-14).\n *\n * When the ONLY reason to run another frame is ambient animation (Hot islands\n * or a stagger backlog), the loop no longer re-invalidates at native refresh:\n * on a 120 Hz panel that was 5 always-Hot islands × 120 paints/sec ≈ 96 % GPU\n * duty at idle — the fan. Instead the next pass is scheduled `1000/maxFps` ms\n * after the last pass STARTED, so ambient animation runs at ~`maxFps` and the\n * GPU idles between frames.\n *\n * What stays at native refresh:\n * - lift eases (`liftAnimating`) — 180 ms of interaction feedback;\n * - every EXTERNALLY invalidated frame (camera, drag, props dirt): the\n * bridge's `requestFrame` path is untouched, so interaction still runs at\n * display rate and Hot islands ride along uncapped while it lasts.\n *\n * The cap is approximate: the wake-up is a timeout and the actual frame lands\n * on the next vsync after it. {@link RATE_CAP_SLACK_MS} pulls the timeout half\n * a 120 Hz vsync early so the following vsync is the intended one, not one\n * past it (naive `interval` scheduling on a 120 Hz grid yields 40 fps, not 60).\n */\n\n/** Timeout lead so the post-timeout vsync lands on the target boundary. */\nexport const RATE_CAP_SLACK_MS = 4;\n\nexport interface SelfSustainStats {\n readonly anyHot: boolean;\n readonly pendingPaints: number;\n readonly liftAnimating: boolean;\n}\n\n/**\n * Decide how the demand loop continues after a pass.\n *\n * @param stats The pass's self-sustain signals.\n * @param elapsedMs ms since the pass started (schedule anchor).\n * @param maxFps Animation rate cap; `Infinity` restores uncapped.\n * @returns `\"none\"` (park), `\"now\"` (invalidate immediately), or the timeout\n * delay in ms before invalidating.\n */\nexport function selfSustainPlan(\n stats: SelfSustainStats,\n elapsedMs: number,\n maxFps: number,\n): \"none\" | \"now\" | number {\n if (stats.liftAnimating) return \"now\";\n if (!stats.anyHot && stats.pendingPaints <= 0) return \"none\";\n const interval = 1000 / Math.max(1, maxFps);\n const delay = interval - elapsedMs - RATE_CAP_SLACK_MS;\n return delay <= 0 ? \"now\" : delay;\n}\n","import type { BufferGeometry, Material, Texture } from \"three\";\n\n/**\n * Ref-counted cache of shared GPU resources keyed by a caller-supplied\n * `cacheKey` (design-004 §3). Geometries, materials, and textures are pooled so\n * many islands of the same archetype share one instance instead of each\n * allocating its own copy.\n *\n * Ported ~verbatim from v1 `ResourceRegistry`\n * (../infinite-canvas .../r3f/compositor/ResourceRegistry.ts). Three's\n * geometries / materials / textures all expose `.dispose()` and are safe to\n * share across scenes; the registry disposes the underlying resource only after\n * every holder has called the matching `release*`.\n */\n\n/** Anything the registry can own — Three resources all satisfy this. */\ntype Disposable = { dispose: () => void };\n\ninterface Entry<T extends Disposable> {\n resource: T;\n refCount: number;\n}\n\nexport class ResourceRegistry {\n private geometries = new Map<string, Entry<BufferGeometry>>();\n private materials = new Map<string, Entry<Material>>();\n private textures = new Map<string, Entry<Texture>>();\n private disposed = false;\n\n acquireGeometry<T extends BufferGeometry>(key: string, factory: () => T): T {\n if (this.disposed) {\n throw new Error(\"ResourceRegistry: cannot acquire after dispose\");\n }\n const existing = this.geometries.get(key);\n if (existing) {\n existing.refCount++;\n return existing.resource as T;\n }\n const resource = factory();\n this.geometries.set(key, { resource, refCount: 1 });\n return resource;\n }\n releaseGeometry(key: string): void {\n this.releaseFrom(this.geometries, key);\n }\n\n acquireMaterial<T extends Material>(key: string, factory: () => T): T {\n if (this.disposed) {\n throw new Error(\"ResourceRegistry: cannot acquire after dispose\");\n }\n const existing = this.materials.get(key);\n if (existing) {\n existing.refCount++;\n return existing.resource as T;\n }\n const resource = factory();\n this.materials.set(key, { resource, refCount: 1 });\n return resource;\n }\n releaseMaterial(key: string): void {\n this.releaseFrom(this.materials, key);\n }\n\n acquireTexture<T extends Texture>(key: string, factory: () => T): T {\n if (this.disposed) {\n throw new Error(\"ResourceRegistry: cannot acquire after dispose\");\n }\n const existing = this.textures.get(key);\n if (existing) {\n existing.refCount++;\n return existing.resource as T;\n }\n const resource = factory();\n this.textures.set(key, { resource, refCount: 1 });\n return resource;\n }\n releaseTexture(key: string): void {\n this.releaseFrom(this.textures, key);\n }\n\n /** Number of distinct shared geometries currently held. */\n geometryCount(): number {\n return this.geometries.size;\n }\n\n /** Number of distinct shared materials currently held. */\n materialCount(): number {\n return this.materials.size;\n }\n\n /** Number of distinct shared textures currently held. */\n textureCount(): number {\n return this.textures.size;\n }\n\n /**\n * Estimated GPU bytes for shared geometry attribute buffers. Best-effort —\n * actual footprint depends on driver alignment, but a useful relative metric\n * for the profiler.\n */\n geometryBytes(): number {\n let total = 0;\n for (const { resource } of this.geometries.values()) {\n for (const attr of Object.values(resource.attributes)) {\n if (\"array\" in attr && (attr.array as ArrayBufferView).byteLength) {\n total += (attr.array as ArrayBufferView).byteLength;\n }\n }\n if (resource.index) {\n total += (resource.index.array as ArrayBufferView).byteLength;\n }\n }\n return total;\n }\n\n /** Dispose every resource and clear the registry. */\n dispose(): void {\n if (this.disposed) return;\n for (const { resource } of this.geometries.values()) resource.dispose();\n for (const { resource } of this.materials.values()) resource.dispose();\n for (const { resource } of this.textures.values()) resource.dispose();\n this.geometries.clear();\n this.materials.clear();\n this.textures.clear();\n this.disposed = true;\n }\n\n /** True after `dispose()` — callers should re-create the registry instead of using it. */\n isDisposed(): boolean {\n return this.disposed;\n }\n\n private releaseFrom<T extends Disposable>(map: Map<string, Entry<T>>, key: string): void {\n const entry = map.get(key);\n if (!entry) return;\n entry.refCount--;\n if (entry.refCount <= 0) {\n // Defer disposal by one microtask. Under React StrictMode the effect\n // cleanup fires immediately, followed by a remount + new acquire — without\n // the defer, the resource is disposed before the remount can re-acquire\n // it. The microtask gives the re-acquire a chance to bump refCount back\n // above 0; if it does not, we dispose for real.\n queueMicrotask(() => {\n const current = map.get(key);\n if (current && current.refCount <= 0) {\n current.resource.dispose();\n map.delete(key);\n }\n });\n }\n }\n}\n","/**\n * The pointer router's GL path (design-004 §4, rev 2 corrected).\n *\n * At EVENT time (outside the tick — world reads are verified-unrestricted)\n * the router runs its own synchronous point-pick against THE spatial index\n * via core's `pickTopAt` — the identical narrow-phase the in-tick `picking`\n * system runs, so the two can never disagree. It does NOT consult last-frame\n * `Targets`: that relation is absent for a touch's first event (the pointer\n * entity doesn't exist yet at down) and stale for fast mouse crossings —\n * rev 1 of the design ate the first tap on every interactive GL widget.\n * `Targets` remains the in-tick authority; this pick is a routing decision,\n * not a second truth.\n *\n * Hit a GL-view widget → island-local convert (kernel, THE Y-flip) → raycast\n * the island's scene through its ortho camera → dispatch synthetic events to\n * the intersected objects' R3F handlers. A handler calling\n * `stopPropagation()` claims the event: the adapter flags the fact\n * `surfaceHandled` and recognizers skip it (`HandledByWidget`, the M4 spine).\n *\n * Capture semantics (per island): a claimed down captures the pointer — its\n * moves/ups go to that island until up/cancel, mirroring how DOM widget\n * content holds `setPointerCapture` for sustained interactions. Hover\n * enter/leave are synthesized from pick transitions on buttonless moves.\n *\n * R3F-INTERNAL-ADJACENT (the one acknowledged spot, implementation-plan\n * risks): handlers are read from `object.__r3f.handlers` — the instance\n * state R3F v9 attaches to every declaratively-created three object. No\n * other R3F internal is touched; the dispatcher owns its own event shape.\n * Mid-event ordering note (design-004 §4): handlers may run engine ops —\n * legal; such mutations land immediately while the same event's position\n * facts land next tick via the queue.\n */\nimport { Raycaster, Vector2, type Intersection, type Object3D } from \"three\";\nimport { screenToWorld, worldToIsland } from \"@ice/kernel\";\nimport type { SpatialIndex } from \"@ice/kernel\";\nimport {\n Camera,\n GESTURE_DEFAULTS,\n GestureSettings,\n PrefabId,\n Position,\n Size,\n createSiblingOrderIndex,\n pickTopAt,\n widgets,\n type Entity,\n type World,\n} from \"@ice/core\";\nimport type { GLBridge } from \"./bridge\";\n\n/** The synthetic event island handlers receive (R3F-handler-compatible core). */\nexport interface IslandPointerEvent {\n readonly type: string;\n readonly nativeEvent: PointerEvent;\n /** Island-local intersection point (three world = island space). */\n readonly point: Intersection[\"point\"] | undefined;\n readonly distance: number;\n readonly object: Object3D;\n readonly eventObject: Object3D;\n readonly intersections: readonly Intersection[];\n readonly entity: Entity;\n stopPropagation(): void;\n readonly stopped: boolean;\n}\n\ntype HandlerName =\n | \"onPointerDown\"\n | \"onPointerMove\"\n | \"onPointerUp\"\n | \"onPointerCancel\"\n | \"onPointerOver\"\n | \"onPointerOut\"\n | \"onClick\";\n\n/** R3F v9 instance state — the single internal-adjacent touchpoint. */\ninterface R3FInstance {\n eventCount?: number;\n handlers?: Partial<Record<HandlerName, (ev: IslandPointerEvent) => void>>;\n}\n\nfunction handlersOf(obj: Object3D): R3FInstance[\"handlers\"] | undefined {\n const inst = (obj as unknown as { __r3f?: R3FInstance }).__r3f;\n if (inst === undefined || (inst.eventCount ?? 0) === 0) return undefined;\n return inst.handlers;\n}\n\nexport interface GLPointerRouterDeps {\n readonly world: World;\n readonly bridge: GLBridge;\n readonly index: SpatialIndex<Entity>;\n}\n\nexport interface GLPointerRouter {\n /** The adapter's `glRoute` seam. True = island content claimed the event. */\n route(kind: \"down\" | \"move\" | \"up\" | \"cancel\", screenX: number, screenY: number, native: PointerEvent): boolean;\n /**\n * Hover-time verdict as of the LAST routed `move` (design-002 §8 amendment,\n * 2026-07-18): the pick chain under the pointer holds claim-capable island\n * content — a mesh whose handlers include `onPointerDown`/`onClick` (the\n * claim/click paths; hover-only handlers like the shapes swarm's move reader\n * do NOT count — they never opt a down out). True for the whole life of an\n * island capture. Feed it into the adapter's `GLRouteVerdict.overInteractive`\n * on moves; presentation truth only, never a routing input.\n */\n overInteractive(): boolean;\n}\n\nexport function createGLPointerRouter({ world, bridge, index }: GLPointerRouterDeps): GLPointerRouter {\n const raycaster = new Raycaster();\n const ndc = new Vector2();\n // The router's OWN ordinal index (rev-ice-flip finding 1): event-time picks run on the\n // pointer task, BETWEEN engine ticks — reading the bridge's shared index here would consume\n // the staleness its reorder wake filters on, and a pure reorder's repaint would be silently\n // swallowed (pointermove at 125–1000 Hz vs the 60 Hz tick makes the window routine). A pick\n // read paints nothing, so it must never reset paint dirtiness; one extra rebuild per reorder\n // is the price. The compositor pass KEEPS sharing the bridge index — its read IS a paint.\n const routerOrder = createSiblingOrderIndex(world);\n\n // pointerId → captured island + the down's claiming object + screen coords\n // (click pairing: release must stay within tap slop of the down).\n const captures = new Map<\n number,\n { entity: Entity; downObject: Object3D | undefined; downX: number; downY: number }\n >();\n // entity → objects currently hovered (buttonless-move enter/leave synth).\n const hovered = new Map<Entity, Set<Object3D>>();\n // pointerId → unclaimed down's topmost object (click pairing without a claim).\n const unclaimedDowns = new Map<number, { entity: Entity; object: Object3D; downX: number; downY: number }>();\n\n // Last routed move's hover verdict (the overInteractive() accessor).\n let hoverInteractive = false;\n\n /** Any hit-chain object carrying a claim/click handler (down would be the island's). */\n const chainInteractive = (hits: readonly Intersection[]): boolean => {\n for (const h of hits) {\n for (let obj: Object3D | null = h.object; obj !== null; obj = obj.parent) {\n const handlers = handlersOf(obj);\n if (handlers !== undefined && (handlers.onPointerDown !== undefined || handlers.onClick !== undefined)) {\n return true;\n }\n }\n }\n return false;\n };\n\n // Click = press and release on the SAME object without travelling past tap\n // slop — the engine's own tap threshold, so GL clicks and engine taps agree.\n const withinTapSlop = (downX: number, downY: number, upX: number, upY: number): boolean => {\n const slop = world.getResource(GestureSettings)?.tapSlopPx ?? GESTURE_DEFAULTS.tapSlopPx;\n const dx = upX - downX;\n const dy = upY - downY;\n return dx * dx + dy * dy <= slop * slop;\n };\n\n /** True when `target` sits on any hit's ancestor chain (release is over it). */\n const chainHas = (hits: readonly Intersection[], target: Object3D): boolean => {\n for (const h of hits) {\n for (let obj: Object3D | null = h.object; obj !== null; obj = obj.parent) {\n if (obj === target) return true;\n }\n }\n return false;\n };\n\n /** The subset of `hits` on `target`'s chain — the capture restriction, so a\n * held pointer's moves/up/cancel never leak to a sibling mesh in the same\n * island. Non-empty result ⟺ `chainHas(result, target)`. */\n const filterToChain = (hits: readonly Intersection[], target: Object3D): Intersection[] => {\n const kept: Intersection[] = [];\n for (const h of hits) {\n for (let obj: Object3D | null = h.object; obj !== null; obj = obj.parent) {\n if (obj === target) {\n kept.push(h);\n break;\n }\n }\n }\n return kept;\n };\n\n /** Screen → (GL widget entity, island intersections); undefined off-GL. */\n const castAt = (\n screenX: number,\n screenY: number,\n ): { entity: Entity; hits: Intersection[] } | undefined => {\n const cam = world.getResource(Camera);\n if (cam === undefined) return undefined;\n const w = screenToWorld(screenX, screenY, cam);\n // The router's OWN ordinals (petition 8; rev-ice-flip finding 1) — same comparator and\n // stamp discipline as the tick pick, so \"topmost\" cannot diverge, but reading here never\n // consumes the bridge index's paint staleness.\n const hit = pickTopAt(world, index, w.x, w.y, 0, undefined, routerOrder.ordinals());\n if (hit === undefined) return undefined;\n const type = world.get(hit, PrefabId)?.id;\n const widget = typeof type === \"string\" ? widgets.get(type) : undefined;\n if (widget === undefined || widget.surface !== \"gl\") return undefined;\n const handle = bridge.islandFor(hit);\n const pos = world.get(hit, Position);\n const size = world.get(hit, Size);\n if (handle === undefined || pos === undefined || size === undefined || size.w <= 0 || size.h <= 0) {\n return undefined; // culled island (no scene) — the retained texture is not interactive\n }\n const local = worldToIsland(w.x, w.y, { x: pos.x, y: pos.y, width: size.w, height: size.h });\n ndc.set(local.x / (size.w / 2), local.y / (size.h / 2));\n // The event-time raycast must not depend on paint order (a tap can land\n // before the island's first paint sets the camera frustum): write the\n // frustum from the live Size and refresh matrices here. Event-rate, small\n // trees — cheap.\n const cam3 = handle.camera;\n cam3.left = -size.w / 2;\n cam3.right = size.w / 2;\n cam3.top = size.h / 2;\n cam3.bottom = -size.h / 2;\n cam3.updateProjectionMatrix();\n cam3.updateMatrixWorld(true);\n handle.scene.updateMatrixWorld(true);\n raycaster.setFromCamera(ndc, cam3);\n return { entity: hit, hits: raycaster.intersectObjects(handle.scene.children, true) };\n };\n\n /** Cast at screen restricted to a live capture: same island AND the\n * capturing object's chain. Empty (off-content or over a sibling) → the\n * dispatcher's `only` fallback still delivers to the capturer. */\n const captureHits = (\n x: number,\n y: number,\n capture: { entity: Entity; downObject: Object3D | undefined },\n ): readonly Intersection[] => {\n const cast = castAt(x, y);\n if (cast === undefined || cast.entity !== capture.entity) return [];\n return capture.downObject === undefined ? cast.hits : filterToChain(cast.hits, capture.downObject);\n };\n\n /** R3F bubbling: per intersection, walk up; dedupe eventObjects; stop on stopPropagation. */\n const dispatch = (\n type: HandlerName,\n eventType: string,\n entity: Entity,\n hits: readonly Intersection[],\n native: PointerEvent,\n only?: Object3D,\n ): { stopped: boolean; claimedBy: Object3D | undefined } => {\n const visited = new Set<Object3D>();\n let stopped = false;\n let claimedBy: Object3D | undefined;\n const targets: { obj: Object3D; hit: Intersection | undefined }[] = [];\n if (hits.length === 0 && only !== undefined) {\n targets.push({ obj: only, hit: undefined }); // captured island, ray off content\n }\n for (const hit of hits) {\n for (let obj: Object3D | null = hit.object; obj !== null; obj = obj.parent) {\n if (visited.has(obj)) continue;\n visited.add(obj);\n targets.push({ obj, hit });\n }\n }\n for (const { obj, hit } of targets) {\n const fn = handlersOf(obj)?.[type];\n if (fn === undefined) continue;\n let localStop = false;\n const ev: IslandPointerEvent = {\n type: eventType,\n nativeEvent: native,\n point: hit?.point,\n distance: hit?.distance ?? 0,\n object: hit?.object ?? obj,\n eventObject: obj,\n intersections: hits,\n entity,\n stopPropagation() {\n localStop = true;\n },\n get stopped() {\n return localStop;\n },\n };\n fn(ev);\n if (localStop) {\n stopped = true;\n claimedBy = obj;\n break;\n }\n }\n return { stopped, claimedBy };\n };\n\n /** Buttonless-move hover synth: over/out from pick transitions. */\n const syncHover = (\n now: { entity: Entity; hits: Intersection[] } | undefined,\n native: PointerEvent,\n ): void => {\n const nowEntity = now?.entity;\n const nowObjs = new Set<Object3D>();\n if (now !== undefined) {\n for (const hit of now.hits) {\n for (let obj: Object3D | null = hit.object; obj !== null; obj = obj.parent) nowObjs.add(obj);\n }\n }\n for (const [entity, prev] of hovered) {\n const gone: Object3D[] = [];\n for (const obj of prev) {\n if (entity !== nowEntity || !nowObjs.has(obj)) gone.push(obj);\n }\n for (const obj of gone) {\n prev.delete(obj);\n handlersOf(obj)?.onPointerOut?.({\n type: \"pointerout\",\n nativeEvent: native,\n point: undefined,\n distance: 0,\n object: obj,\n eventObject: obj,\n intersections: [],\n entity,\n stopPropagation() {},\n stopped: false,\n });\n }\n if (prev.size === 0) hovered.delete(entity);\n }\n if (now !== undefined && nowEntity !== undefined) {\n let set = hovered.get(nowEntity);\n if (set === undefined) {\n set = new Set();\n hovered.set(nowEntity, set);\n }\n for (const obj of nowObjs) {\n if (set.has(obj) || handlersOf(obj) === undefined) continue;\n set.add(obj);\n handlersOf(obj)?.onPointerOver?.({\n type: \"pointerover\",\n nativeEvent: native,\n point: undefined,\n distance: 0,\n object: obj,\n eventObject: obj,\n intersections: now.hits,\n entity: nowEntity,\n stopPropagation() {},\n stopped: false,\n });\n }\n }\n };\n\n return {\n route(kind, screenX, screenY, native) {\n if (kind === \"down\") {\n const cast = castAt(screenX, screenY);\n if (cast === undefined) {\n unclaimedDowns.delete(native.pointerId);\n return false;\n }\n const { stopped, claimedBy } = dispatch(\"onPointerDown\", \"pointerdown\", cast.entity, cast.hits, native);\n if (stopped) {\n unclaimedDowns.delete(native.pointerId);\n captures.set(native.pointerId, {\n entity: cast.entity,\n downObject: claimedBy,\n downX: screenX,\n downY: screenY,\n });\n return true;\n }\n // UNCLAIMED down over an island: remember the topmost object so a\n // clean up on the same object still yields a click (native-R3F\n // parity; v1 RFC-008 coexistence — the engine's tap runs too, so a\n // cube click can log AND select, 2026-07-12 field report).\n const top = cast.hits[0]?.object;\n if (top !== undefined) {\n unclaimedDowns.set(native.pointerId, {\n entity: cast.entity,\n object: top,\n downX: screenX,\n downY: screenY,\n });\n }\n return false;\n }\n\n const capture = captures.get(native.pointerId);\n\n if (kind === \"move\") {\n if (capture !== undefined) {\n // Captured island drag: the widget owns the pointer for its duration.\n hoverInteractive = true;\n const hits = captureHits(screenX, screenY, capture);\n dispatch(\"onPointerMove\", \"pointermove\", capture.entity, hits, native, capture.downObject);\n return true;\n }\n // Held-button uncaptured move (an ENGINE gesture is travelling over\n // the island) falls through with hoverInteractive false — correct.\n hoverInteractive = false;\n if (native.buttons === 0) {\n const cast = castAt(screenX, screenY);\n hoverInteractive = cast !== undefined && chainInteractive(cast.hits);\n syncHover(cast, native);\n // Native-R3F hover parity (2026-07-12 field report — v1's hover-driven\n // widgets, e.g. the shapes swarm, read point-carrying moves WITHOUT a\n // press): buttonless moves over an island dispatch onPointerMove with\n // the pick's island-local point. Never claims — the engine still sees\n // the move (no gesture is active buttonless, so nothing competes).\n if (cast !== undefined) {\n dispatch(\"onPointerMove\", \"pointermove\", cast.entity, cast.hits, native);\n }\n }\n return false;\n }\n\n // up | cancel\n if (capture === undefined) {\n // Unclaimed click pairing: down and up on the same topmost object.\n const pending = unclaimedDowns.get(native.pointerId);\n unclaimedDowns.delete(native.pointerId);\n if (kind === \"up\" && pending !== undefined && withinTapSlop(pending.downX, pending.downY, screenX, screenY)) {\n const cast = castAt(screenX, screenY);\n if (cast !== undefined && cast.entity === pending.entity && cast.hits[0]?.object === pending.object) {\n dispatch(\"onClick\", \"click\", cast.entity, cast.hits, native, pending.object);\n }\n }\n return false;\n }\n captures.delete(native.pointerId);\n const hits = captureHits(screenX, screenY, capture);\n if (kind === \"up\") {\n const { claimedBy } = dispatch(\"onPointerUp\", \"pointerup\", capture.entity, hits, native, capture.downObject);\n // Click pairs down+up on the same claiming object (R3F semantics) —\n // AND the release must land back on it within tap slop. Without both\n // gates a captured drag ended elsewhere still \"clicked\" the object it\n // grabbed (the old `claimedBy ?? downObject` fallback made the\n // same-object check tautological).\n if (\n capture.downObject !== undefined &&\n (claimedBy === undefined || claimedBy === capture.downObject) &&\n chainHas(hits, capture.downObject) &&\n withinTapSlop(capture.downX, capture.downY, screenX, screenY)\n ) {\n dispatch(\"onClick\", \"click\", capture.entity, hits, native, capture.downObject);\n }\n } else {\n dispatch(\"onPointerCancel\", \"pointercancel\", capture.entity, hits, native, capture.downObject);\n }\n return true;\n },\n overInteractive: () => hoverInteractive,\n };\n}\n","/**\n * The GL preview capture pipeline (design-005 §2 preview contract, P2 —\n * 2026-07-19). Renders each gl-surface widget's REAL island content once,\n * offscreen, and lands the capture in @ice/react's preview-snapshot store —\n * `<WidgetPreview>` re-renders any open palette the moment it arrives.\n *\n * The capture stage is a HEADLESS ISLAND: the exact contract island.tsx\n * gives live content — center-origin Y-up ortho at (0,0,500) with the\n * ±defaultSize/2 frustum, `scene.environment` stamped, and an IslandContext\n * whose bridge accepts the island hooks (frame callbacks fire per settle\n * frame; lift/opacity/paint-bumps are inert here). Widget components run\n * UNCHANGED — `useIslandFrame` animations tick, so the capture catches a\n * live pose, not frame zero.\n *\n * Deliberately LAZY: call this from idle time or first palette need — never\n * from the boot path (the design decision: \"cached after first capture\",\n * not \"ready at load\"). One R3F root + one canvas are reused across types\n * (WebGL contexts are a capped resource); already-captured types are\n * skipped, and concurrent calls coalesce onto one run.\n */\nimport {\n createCanvasEngine,\n widgets,\n type CanvasEngine,\n type Entity,\n type WidgetType,\n} from \"@ice/core\";\nimport {\n EngineProvider,\n hasPreviewSnapshot,\n setPreviewSnapshot,\n type WidgetComponentProps,\n} from \"@ice/react\";\nimport { advance, createRoot } from \"@react-three/fiber\";\nimport { createElement, type ComponentType } from \"react\";\nimport type { Texture, WebGLRenderer } from \"three\";\nimport type { GLBridge, IslandFrameCallback } from \"./bridge\";\nimport { IslandContext } from \"./use-island-frame\";\n\nexport interface CapturePreviewOpts {\n /** Types to capture (default: every registered gl-surface widget). */\n readonly types?: readonly string[];\n /**\n * Shared IBL. Prefer the FACTORY form: PMREM textures live on the GPU of\n * the renderer that generated them (no CPU image), so the app's main-canvas\n * env is EMPTY on the capture renderer (field bug 2026-07-19 — black\n * metals). The factory receives the capture renderer and builds the env\n * there (e.g. `(gl) => new PMREMGenerator(gl).fromScene(new RoomEnvironment(), 0.04).texture`).\n * A plain Texture is accepted for same-renderer/CPU-backed cases.\n */\n readonly environment?: Texture | ((gl: WebGLRenderer) => Texture | null) | null;\n /** Pixel density of the capture (default: fit 512px on the long side, ≤2). */\n readonly scale?: number;\n /** Frames advanced before the capture (animations reach a live pose). */\n readonly settleFrames?: number;\n}\n\n// --- the capture sandbox (r3f-local; mirrors @ice/react's — deliberately\n// separate: cross-package private state would couple the walls) -------------\nlet sandbox: { ce: CanvasEngine; entities: Map<string, Entity> } | null = null;\n\nfunction ensureEntity(def: WidgetType): Entity | undefined {\n if (sandbox === null) {\n const ce = createCanvasEngine();\n ce.docs.create();\n ce.world.sync();\n ce.step(16);\n sandbox = { ce, entities: new Map() };\n }\n const hit = sandbox.entities.get(def.type);\n if (hit !== undefined) return hit;\n try {\n const e = sandbox.ce.ops.spawnWidget(def.type, {\n x: 0,\n y: 0,\n undoable: false,\n ...(def.previewProps !== undefined ? { props: def.previewProps } : {}),\n });\n sandbox.ce.world.sync();\n sandbox.ce.step(32);\n sandbox.entities.set(def.type, e);\n return e;\n } catch (err) {\n console.warn(`ice: preview capture — sandbox spawn failed for \"${def.type}\".`, err);\n return undefined;\n }\n}\n\n/** The island hooks' surface, inert: frames collect, chrome signals no-op. */\nfunction stubBridge(callbacks: Set<IslandFrameCallback>): GLBridge {\n const stub = {\n addFrameCallback: (_e: Entity, cb: IslandFrameCallback) => {\n callbacks.add(cb);\n return () => callbacks.delete(cb);\n },\n bumpPaint: () => {},\n setCompositeScale: () => {},\n setCompositeOpacity: () => {},\n };\n return stub as unknown as GLBridge;\n}\n\nconst sleep = (ms: number): Promise<void> => new Promise((r) => setTimeout(r, ms));\n\nlet inFlight: Promise<string[]> | null = null;\n\nexport function captureWidgetPreviews(opts: CapturePreviewOpts = {}): Promise<string[]> {\n // Coalesce: a StrictMode double-fire or an eager second caller rides the\n // first run (skip-if-captured makes a follow-up run cheap anyway).\n if (inFlight !== null) return inFlight;\n const run = doCapture(opts).finally(() => {\n inFlight = null;\n });\n inFlight = run;\n return run;\n}\n\nasync function doCapture(opts: CapturePreviewOpts): Promise<string[]> {\n const wanted =\n opts.types ??\n widgets\n .all()\n .filter((d) => d.surface === \"gl\")\n .map((d) => d.type);\n const defs = wanted\n .map((t) => widgets.get(t))\n .filter((d): d is WidgetType => d !== undefined && d.surface === \"gl\" && d.component !== null && d.component !== undefined)\n .filter((d) => !hasPreviewSnapshot(d.type));\n if (defs.length === 0) return [];\n\n const canvas = document.createElement(\"canvas\");\n const root = createRoot(canvas);\n const captured: string[] = [];\n let resolvedEnv: Texture | null | undefined; // lazily built ON the capture renderer\n try {\n for (const def of defs) {\n // Per-type containment: one widget's render throw skips ITS capture —\n // the fallback silhouette covers it — never the whole run (field bug\n // 2026-07-19: one provider-hungry widget aborted every later type).\n try {\n const entity = ensureEntity(def);\n if (entity === undefined || sandbox === null) continue;\n const { w, h } = def.defaultSize;\n const scale = opts.scale ?? Math.min(2, 512 / Math.max(w, h));\n const callbacks = new Set<IslandFrameCallback>();\n\n root.configure({\n frameloop: \"never\",\n gl: { alpha: true, antialias: true, preserveDrawingBuffer: true },\n orthographic: true,\n // The island frustum verbatim (island.tsx / the paint pass): center\n // origin, Y-up, camera on +Z looking at the content plane; `manual`\n // pins it against R3F's resize auto-frustum.\n camera: {\n left: -w / 2,\n right: w / 2,\n top: h / 2,\n bottom: -h / 2,\n near: 0.1,\n far: 2000,\n position: [0, 0, 500],\n manual: true,\n },\n size: { width: w, height: h, top: 0, left: 0 },\n dpr: scale,\n });\n\n // EngineProvider wraps the tree: LIVE island content inherits it\n // through the app's portal chain, so widgets legitimately reach\n // useOps/useCommit — the capture stage must offer the same contract\n // (the sandbox engine), or provider-hungry widgets throw (field bug\n // 2026-07-19, shapes-card).\n const View = def.component as ComponentType<WidgetComponentProps>;\n const store = root.render(\n createElement(\n EngineProvider,\n { engine: sandbox.ce },\n createElement(\n IslandContext.Provider,\n { value: { bridge: stubBridge(callbacks), entity } },\n createElement(View, { entity, world: sandbox.ce.world }),\n ),\n ),\n );\n if (resolvedEnv === undefined) {\n resolvedEnv =\n typeof opts.environment === \"function\"\n ? opts.environment(store.getState().gl)\n : (opts.environment ?? null);\n }\n store.getState().scene.environment = resolvedEnv;\n // Commit the frustum IMPERATIVELY: `manual` pins R3F's auto-frustum,\n // but camera PROPS alone don't guarantee an updateProjectionMatrix —\n // the compositor pass learned this same lesson (\"write the frustum\n // from the live Size and refresh matrices here\"). Without it the\n // default ±1 window renders the hollow middle of a 60-unit knot.\n const cam = store.getState().camera as import(\"three\").OrthographicCamera;\n cam.left = -w / 2;\n cam.right = w / 2;\n cam.top = h / 2;\n cam.bottom = -h / 2;\n cam.near = 0.1;\n cam.far = 2000;\n cam.position.set(0, 0, 500);\n cam.lookAt(0, 0, 0);\n cam.updateProjectionMatrix();\n cam.updateMatrixWorld(true);\n\n // Settle: a beat for suspense/microtasks, then advance real frames so\n // useIslandFrame content reaches a live pose. runGlobalEffects FALSE:\n // the capture must never tick the app's own roots/effects (isolation\n // — the stage may be backgrounded while this runs).\n await sleep(30);\n const frames = opts.settleFrames ?? 12;\n // advance() timestamps are SECONDS in frameloop=\"never\" (R3F clock\n // contract — same unit trap as gl-root's reflect-phase advance): the\n // capture's frame callbacks get their dt via `cb(16.7)` ms directly,\n // but any plain-useFrame content reads the clock, so keep it honest.\n for (let i = 0; i < frames; i++) {\n for (const cb of callbacks) cb(16.7);\n advance((i * 16.7) / 1000, false, store.getState());\n await sleep(16);\n }\n // Final frame + readback in the SAME task, via 2D-canvas drawImage:\n // a WebGL drawing buffer is only guaranteed readable before the task\n // yields, and createImageBitmap can route through a (possibly\n // stalled) compositor — the synchronous copy depends on neither\n // (field bug 2026-07-19 — full-alpha-zero bitmaps).\n for (const cb of callbacks) cb(16.7);\n advance((frames * 16.7) / 1000, false, store.getState());\n const snap = document.createElement(\"canvas\");\n snap.width = canvas.width;\n snap.height = canvas.height;\n snap.getContext(\"2d\")?.drawImage(canvas, 0, 0);\n setPreviewSnapshot(def.type, snap);\n captured.push(def.type);\n } catch (err) {\n console.warn(`ice: preview capture failed for \"${def.type}\" — its tile keeps the fallback.`, err);\n }\n // Yield BETWEEN types: each capture is a ~250ms burst, and the app —\n // possibly mid-gesture — must breathe between them (lazy also means\n // polite; a starved main loop can cancel a live drag).\n await new Promise<void>((r) => {\n const w = window as Window & { requestIdleCallback?: (cb: () => void, o?: { timeout: number }) => number };\n if (w.requestIdleCallback !== undefined) w.requestIdleCallback(() => r(), { timeout: 500 });\n else setTimeout(r, 50);\n });\n }\n } finally {\n root.unmount();\n }\n return captured;\n}\n"],"mappings":"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","names":["inFlight","createElement","useEffect","useMemo","useRef","OrthographicCamera","useEffect","useEffect","advance","useRef","useMemo","OrthographicCamera","useEffect","createElement","hits","createElement","createElement"]}