@jamesyong42/infinite-canvas 1.2.0 → 1.4.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 (56) hide show
  1. package/README.md +65 -0
  2. package/dist/advanced.cjs +61 -24
  3. package/dist/advanced.cjs.map +1 -1
  4. package/dist/advanced.d.cts +180 -64
  5. package/dist/advanced.d.cts.map +1 -1
  6. package/dist/advanced.d.mts +180 -64
  7. package/dist/advanced.d.mts.map +1 -1
  8. package/dist/advanced.mjs +29 -12
  9. package/dist/advanced.mjs.map +1 -1
  10. package/dist/devtools.cjs +22 -22
  11. package/dist/devtools.cjs.map +1 -1
  12. package/dist/devtools.d.cts +2 -2
  13. package/dist/devtools.d.cts.map +1 -1
  14. package/dist/devtools.d.mts +2 -2
  15. package/dist/devtools.d.mts.map +1 -1
  16. package/dist/devtools.mjs +2 -2
  17. package/dist/devtools.mjs.map +1 -1
  18. package/dist/{hooks-BwY7rRHg.mjs → ecs-3kimUV5Z.mjs} +238 -74
  19. package/dist/ecs-3kimUV5Z.mjs.map +1 -0
  20. package/dist/{hooks-DHShH86C.cjs → ecs-B4QrqfvQ.cjs} +320 -108
  21. package/dist/ecs-B4QrqfvQ.cjs.map +1 -0
  22. package/dist/hooks-CtP02JNt.cjs +3762 -0
  23. package/dist/hooks-CtP02JNt.cjs.map +1 -0
  24. package/dist/hooks-gsQDDE56.mjs +3494 -0
  25. package/dist/hooks-gsQDDE56.mjs.map +1 -0
  26. package/dist/index-3GY7T8JM.d.mts +480 -0
  27. package/dist/index-3GY7T8JM.d.mts.map +1 -0
  28. package/dist/index-B7B1tRPl.d.cts +480 -0
  29. package/dist/index-B7B1tRPl.d.cts.map +1 -0
  30. package/dist/index-DSdbSQ_t.d.cts +1451 -0
  31. package/dist/index-DSdbSQ_t.d.cts.map +1 -0
  32. package/dist/index-Dj9odADH.d.mts +1451 -0
  33. package/dist/index-Dj9odADH.d.mts.map +1 -0
  34. package/dist/index.cjs +3901 -643
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +315 -138
  37. package/dist/index.d.cts.map +1 -1
  38. package/dist/index.d.mts +315 -138
  39. package/dist/index.d.mts.map +1 -1
  40. package/dist/index.mjs +3803 -571
  41. package/dist/index.mjs.map +1 -1
  42. package/package.json +2 -2
  43. package/dist/SelectionRenderer-CR2PBQwx.d.cts +0 -105
  44. package/dist/SelectionRenderer-CR2PBQwx.d.cts.map +0 -1
  45. package/dist/SelectionRenderer-DlsBstAq.d.mts +0 -105
  46. package/dist/SelectionRenderer-DlsBstAq.d.mts.map +0 -1
  47. package/dist/WebGLWidgetLayer-BBMuwzHq.cjs +0 -3560
  48. package/dist/WebGLWidgetLayer-BBMuwzHq.cjs.map +0 -1
  49. package/dist/WebGLWidgetLayer-C3p1tnpm.mjs +0 -3375
  50. package/dist/WebGLWidgetLayer-C3p1tnpm.mjs.map +0 -1
  51. package/dist/engine-BfbvWXSk.d.mts +0 -982
  52. package/dist/engine-BfbvWXSk.d.mts.map +0 -1
  53. package/dist/engine-CCjuFMC-.d.cts +0 -982
  54. package/dist/engine-CCjuFMC-.d.cts.map +0 -1
  55. package/dist/hooks-BwY7rRHg.mjs.map +0 -1
  56. package/dist/hooks-DHShH86C.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["useComponent","WidgetData","WidgetBreakpoint","Children","useTag","Selected","useLayoutEngine","DEFAULT_CARD_PRESET_SIZES","useTag","Dragging","Card","Shape","ExtrudeGeometry","useTag","Dragging","Card","WidgetResolverProvider","isR3FWidget","React","GridRenderer","SelectionRenderer","Vector2","CursorResource","SelectionFrame","WorldBounds","NavigationStackResource","Widget","EngineProvider","ContainerRefProvider","WidgetSlot","SelectionOverlaySlot","useWidgetResolver","WebGLWidgetLayer"],"sources":["../src/react/widget-hooks.ts","../src/react/card.tsx","../src/react/geometry-card.tsx","../src/react/WidgetProvider.tsx","../src/react/InfiniteCanvas.tsx"],"sourcesContent":["import type { EntityId } from '@jamesyong42/reactive-ecs';\nimport { useCallback } from 'react';\nimport { Children, Selected, WidgetBreakpoint, WidgetData } from '../components.js';\nimport type { Breakpoint } from '../resources.js';\nimport { useLayoutEngine } from './context.js';\nimport { useComponent, useTag } from './hooks.js';\n\n/**\n * Returns the custom data attached to a widget entity.\n * Use the generic parameter for type safety: `useWidgetData<MyData>(entityId)`. Re-renders when data changes.\n */\nexport function useWidgetData<T = Record<string, unknown>>(entityId: EntityId): T {\n\tconst comp = useComponent(entityId, WidgetData);\n\treturn (comp?.data ?? {}) as T;\n}\n\n/**\n * Returns the current responsive breakpoint for a widget based on its screen-space size.\n * Re-renders when the breakpoint changes.\n */\nexport function useBreakpoint(entityId: EntityId): Breakpoint {\n\tconst comp = useComponent(entityId, WidgetBreakpoint);\n\treturn comp?.current ?? 'normal';\n}\n\n/**\n * Returns child entity IDs of a container entity.\n * Re-renders when children are added or removed.\n */\nexport function useChildren(entityId: EntityId): EntityId[] {\n\tconst comp = useComponent(entityId, Children);\n\treturn comp?.ids ?? [];\n}\n\n/**\n * Returns whether the entity is currently selected.\n * Re-renders when the entity's selection state changes.\n */\nexport function useIsSelected(entityId: EntityId): boolean {\n\treturn useTag(entityId, Selected);\n}\n\n/**\n * Returns a function to update the widget's custom data.\n * Merges the patch into existing data via shallow spread.\n */\nexport function useUpdateWidget(entityId: EntityId): (patch: Record<string, unknown>) => void {\n\tconst engine = useLayoutEngine();\n\treturn useCallback(\n\t\t(patch: Record<string, unknown>) => {\n\t\t\tconst existing = engine.get(entityId, WidgetData);\n\t\t\tif (existing) {\n\t\t\t\tengine.set(entityId, WidgetData, {\n\t\t\t\t\tdata: { ...existing.data, ...patch },\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t\t[engine, entityId],\n\t);\n}\n","import type { EntityId } from '@jamesyong42/reactive-ecs';\nimport type * as React from 'react';\nimport type { Archetype } from '../archetype.js';\nimport type { CardPreset } from '../components.js';\nimport { Card, Dragging } from '../components.js';\nimport type { StandardSchemaV1 } from '../schema.js';\nimport { useTag } from './hooks.js';\nimport type { DomWidget, DomWidgetProps } from './registry.js';\nimport { useWidgetData } from './widget-hooks.js';\n\n/**\n * Built-in preset sizes, matching `CardPresetsResource` defaults.\n * Used by `createCardWidget` to set `defaultSize` at widget-registration\n * time (before the engine is constructed).\n */\nconst DEFAULT_CARD_PRESET_SIZES: Record<CardPreset, { width: number; height: number }> = {\n\tsmall: { width: 155, height: 155 },\n\tmedium: { width: 329, height: 155 },\n\tlarge: { width: 329, height: 345 },\n\txl: { width: 329, height: 535 },\n};\n\n/** Props accepted by `<CardFrame>`. */\nexport interface CardFrameProps {\n\tentityId: EntityId;\n\tchildren?: React.ReactNode;\n\tclassName?: string;\n\t/** Merged into the frame div's style (wins over defaults). */\n\tstyle?: React.CSSProperties;\n}\n\n/**\n * Visual chrome for an iOS-style card: rounded corners, hairline ring,\n * soft drop shadow, and a subtle lift (scale + stronger shadow) while\n * the entity carries the `Dragging` tag.\n *\n * Uses CSS transitions — no animation library dependency.\n */\nexport function CardFrame({ entityId, children, className, style }: CardFrameProps) {\n\tconst dragging = useTag(entityId, Dragging);\n\n\tconst baseStyle: React.CSSProperties = {\n\t\twidth: '100%',\n\t\theight: '100%',\n\t\tborderRadius: '21.67px',\n\t\toverflow: 'hidden',\n\t\tboxShadow: dragging\n\t\t\t? '0 30px 60px rgba(0,0,0,0.22), 0 0 0 1px rgba(0,0,0,0.06)'\n\t\t\t: '0 20px 40px rgba(0,0,0,0.15), 0 0 0 1px rgba(0,0,0,0.05)',\n\t\ttransform: dragging ? 'scale(1.05)' : 'scale(1)',\n\t\ttransformOrigin: 'center center',\n\t\ttransition:\n\t\t\t'transform 180ms cubic-bezier(0.2, 0.9, 0.3, 1.2), box-shadow 180ms cubic-bezier(0.2, 0.9, 0.3, 1.2)',\n\t\twillChange: dragging ? 'transform, box-shadow' : undefined,\n\t\t...style,\n\t};\n\n\treturn (\n\t\t<div className={className} style={baseStyle}>\n\t\t\t{children}\n\t\t</div>\n\t);\n}\n\n/** Options passed to `createCardWidget`. */\nexport interface CreateCardWidgetOptions<T> {\n\t/** Unique widget type id. Doubles as the archetype id. */\n\ttype: string;\n\t/** Which iOS preset the card sits at. Fixed for the widget's lifetime (change via `engine.set(id, Card, { preset })`). */\n\tsize: CardPreset;\n\t/** Standard Schema v1-compatible validator for the widget's data. */\n\t// biome-ignore lint/suspicious/noExplicitAny: schema Input is intentionally permissive\n\tschema: StandardSchemaV1<any, T>;\n\t/** Default data for new instances; merged with user-supplied data at spawn. */\n\tdefaultData: T;\n\t/** The card's rendered content. Receives entityId + typed data. */\n\trender: React.ComponentType<{ entityId: EntityId; data: T }>;\n}\n\n/**\n * Returns a paired widget + archetype for an iOS-style card. Register both\n * with `createLayoutEngine({ widgets: [card.widget], archetypes: [card.archetype] })`\n * (or via `engine.registerWidget` / `engine.registerArchetype`) and spawn with\n * `engine.spawn('your-card-type', { at, data })`.\n *\n * The produced widget is non-resizable (Selectable + Draggable only), wrapped\n * in `<CardFrame>`, and spawns with a `Card` component so `cardSystem` enforces\n * the preset size each tick.\n */\nexport function createCardWidget<T>(opts: CreateCardWidgetOptions<T>): {\n\twidget: DomWidget<T>;\n\tarchetype: Archetype;\n} {\n\tconst defaultSize = DEFAULT_CARD_PRESET_SIZES[opts.size];\n\tconst Render = opts.render;\n\n\tconst Component: React.ComponentType<DomWidgetProps> = ({ entityId }) => {\n\t\tconst data = useWidgetData<T>(entityId);\n\t\treturn (\n\t\t\t<CardFrame entityId={entityId}>\n\t\t\t\t<Render entityId={entityId} data={data} />\n\t\t\t</CardFrame>\n\t\t);\n\t};\n\n\tconst widget: DomWidget<T> = {\n\t\ttype: opts.type,\n\t\tschema: opts.schema,\n\t\tdefaultData: opts.defaultData,\n\t\tdefaultSize,\n\t\tcomponent: Component,\n\t};\n\n\tconst archetype: Archetype = {\n\t\tid: opts.type,\n\t\twidget: opts.type,\n\t\tcomponents: [[Card, { preset: opts.size }]],\n\t\tinteractive: {\n\t\t\tselectable: true,\n\t\t\tdraggable: true,\n\t\t\tresizable: false,\n\t\t\t// Cards render their own chrome via CardFrame — opt out of the\n\t\t\t// engine-drawn selection/hover outline.\n\t\t\tselectionFrame: false,\n\t\t},\n\t\tdefaultSize,\n\t};\n\n\treturn { widget, archetype };\n}\n","import type { EntityId } from '@jamesyong42/reactive-ecs';\nimport { useFrame } from '@react-three/fiber';\nimport type * as React from 'react';\nimport { useMemo, useRef } from 'react';\nimport type { Group } from 'three';\nimport { ExtrudeGeometry, Shape } from 'three';\nimport type { Archetype } from '../archetype.js';\nimport type { CardPreset } from '../components.js';\nimport { Card, Dragging } from '../components.js';\nimport type { StandardSchemaV1 } from '../schema.js';\nimport { useTag } from './hooks.js';\nimport type { R3FWidget, R3FWidgetProps } from './registry.js';\nimport { useWidgetData } from './widget-hooks.js';\n\n/** Must match {@link CardPresetsResource} defaults. */\nconst DEFAULT_CARD_PRESET_SIZES: Record<CardPreset, { width: number; height: number }> = {\n\tsmall: { width: 155, height: 155 },\n\tmedium: { width: 329, height: 155 },\n\tlarge: { width: 329, height: 345 },\n\txl: { width: 329, height: 535 },\n};\n\n/**\n * Pure-three rounded-rect extrude geometry — avoids a drei dependency.\n * Rounded corners match the DOM CardFrame radius (21.67 px).\n */\nfunction makeRoundedCardGeometry(\n\twidth: number,\n\theight: number,\n\tradius: number,\n\tdepth: number,\n): ExtrudeGeometry {\n\tconst shape = new Shape();\n\tconst r = Math.min(radius, Math.min(width, height) / 2);\n\tconst x = -width / 2;\n\tconst y = -height / 2;\n\tshape.moveTo(x, y + r);\n\tshape.lineTo(x, y + height - r);\n\tshape.quadraticCurveTo(x, y + height, x + r, y + height);\n\tshape.lineTo(x + width - r, y + height);\n\tshape.quadraticCurveTo(x + width, y + height, x + width, y + height - r);\n\tshape.lineTo(x + width, y + r);\n\tshape.quadraticCurveTo(x + width, y, x + width - r, y);\n\tshape.lineTo(x + r, y);\n\tshape.quadraticCurveTo(x, y, x, y + r);\n\n\treturn new ExtrudeGeometry(shape, {\n\t\tdepth,\n\t\tbevelEnabled: true,\n\t\tbevelSegments: 3,\n\t\tbevelSize: 0.6,\n\t\tbevelThickness: 0.6,\n\t});\n}\n\ninterface CardBackProps {\n\twidth: number;\n\theight: number;\n\tcolor: string;\n\troughness: number;\n\tmetalness: number;\n}\n\nfunction CardBack({ width, height, color, roughness, metalness }: CardBackProps) {\n\tconst geometry = useMemo(() => makeRoundedCardGeometry(width, height, 21.67, 3), [width, height]);\n\treturn (\n\t\t<mesh geometry={geometry} position={[0, 0, -6]} receiveShadow>\n\t\t\t<meshStandardMaterial color={color} roughness={roughness} metalness={metalness} />\n\t\t</mesh>\n\t);\n}\n\n/** Background options for a geometry card widget. */\nexport type GeometryCardBackground =\n\t| 'card'\n\t| 'transparent'\n\t| {\n\t\t\t/** Hex color for the card back (e.g. '#1C1C1E' dark, '#F2F2F7' light). */\n\t\t\tcolor: string;\n\t\t\t/** PBR roughness. Default 0.55. */\n\t\t\troughness?: number;\n\t\t\t/** PBR metalness. Default 0. */\n\t\t\tmetalness?: number;\n\t };\n\n/** Props passed to the user's geometry component. */\nexport interface GeometryCardRenderProps<T> {\n\tentityId: EntityId;\n\tdata: T;\n\t/** Widget width in world units. */\n\twidth: number;\n\t/** Widget height in world units. */\n\theight: number;\n}\n\n/** Options for `createGeometryCardWidget`. */\nexport interface CreateGeometryCardWidgetOptions<T> {\n\t/** Unique widget type id. Doubles as the archetype id. */\n\ttype: string;\n\t/** iOS card preset size. */\n\tsize: CardPreset;\n\t/** Standard Schema v1-compatible validator for the widget's data. */\n\t// biome-ignore lint/suspicious/noExplicitAny: schema Input is intentionally permissive\n\tschema: StandardSchemaV1<any, T>;\n\t/** Default data for new instances. */\n\tdefaultData: T;\n\t/**\n\t * `'card'` (default) renders a dark iOS-style card back behind the geometry.\n\t * `'transparent'` skips the card so the geometry floats over the canvas.\n\t * Object form customises the back's color and PBR parameters.\n\t */\n\tbackground?: GeometryCardBackground;\n\t/** The 3D content rendered in local space (origin at centre). */\n\tgeometry: React.ComponentType<GeometryCardRenderProps<T>>;\n}\n\n/**\n * Returns a paired R3F widget + archetype for a card-shaped 3D widget.\n * Behaves like {@link createCardWidget} — fixed preset size, non-resizable,\n * no engine-drawn selection frame, and lifts on drag (scale + z) — but\n * renders a three.js scene instead of DOM content.\n *\n * Lighting: this helper adds no lights. Declare your own in the `geometry`\n * component (typically a local `pointLight` scoped with `distance`).\n */\nexport function createGeometryCardWidget<T>(opts: CreateGeometryCardWidgetOptions<T>): {\n\twidget: R3FWidget<T>;\n\tarchetype: Archetype;\n} {\n\tconst defaultSize = DEFAULT_CARD_PRESET_SIZES[opts.size];\n\tconst Render = opts.geometry;\n\tconst backgroundConfig = opts.background ?? 'card';\n\n\tconst resolvedBack =\n\t\tbackgroundConfig === 'transparent'\n\t\t\t? null\n\t\t\t: backgroundConfig === 'card'\n\t\t\t\t? { color: '#1C1C1E', roughness: 0.55, metalness: 0 }\n\t\t\t\t: {\n\t\t\t\t\t\tcolor: backgroundConfig.color,\n\t\t\t\t\t\troughness: backgroundConfig.roughness ?? 0.55,\n\t\t\t\t\t\tmetalness: backgroundConfig.metalness ?? 0,\n\t\t\t\t\t};\n\n\tconst Component: React.ComponentType<R3FWidgetProps> = ({ entityId, width, height }) => {\n\t\tconst data = useWidgetData<T>(entityId);\n\t\tconst dragging = useTag(entityId, Dragging);\n\t\tconst groupRef = useRef<Group>(null);\n\n\t\t// Spring-lerp the group scale + z on drag for the iOS lift feel.\n\t\tuseFrame(() => {\n\t\t\tconst g = groupRef.current;\n\t\t\tif (!g) return;\n\t\t\tconst targetScale = dragging ? 1.05 : 1;\n\t\t\tconst targetZ = dragging ? 8 : 0;\n\t\t\tconst s = g.scale.x;\n\t\t\tg.scale.setScalar(s + (targetScale - s) * 0.2);\n\t\t\tg.position.z += (targetZ - g.position.z) * 0.2;\n\t\t});\n\n\t\treturn (\n\t\t\t<group ref={groupRef}>\n\t\t\t\t{resolvedBack && (\n\t\t\t\t\t<CardBack\n\t\t\t\t\t\twidth={width}\n\t\t\t\t\t\theight={height}\n\t\t\t\t\t\tcolor={resolvedBack.color}\n\t\t\t\t\t\troughness={resolvedBack.roughness}\n\t\t\t\t\t\tmetalness={resolvedBack.metalness}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t\t<Render entityId={entityId} data={data} width={width} height={height} />\n\t\t\t</group>\n\t\t);\n\t};\n\n\tconst widget: R3FWidget<T> = {\n\t\ttype: opts.type,\n\t\tsurface: 'webgl',\n\t\tschema: opts.schema,\n\t\tdefaultData: opts.defaultData,\n\t\tdefaultSize,\n\t\tcomponent: Component,\n\t};\n\n\tconst archetype: Archetype = {\n\t\tid: opts.type,\n\t\twidget: opts.type,\n\t\tcomponents: [[Card, { preset: opts.size }]],\n\t\tinteractive: {\n\t\t\tselectable: true,\n\t\t\tdraggable: true,\n\t\t\tresizable: false,\n\t\t\tselectionFrame: false,\n\t\t},\n\t\tdefaultSize,\n\t};\n\n\treturn { widget, archetype };\n}\n","import type { ReactNode } from 'react';\nimport { useCallback } from 'react';\nimport type { LayoutEngine } from '../engine.js';\nimport type { ResolvedWidget } from './context.js';\nimport { WidgetResolverProvider } from './context.js';\nimport { isR3FWidget } from './registry.js';\n\ninterface WidgetProviderProps {\n\tengine: LayoutEngine;\n\tchildren?: ReactNode;\n}\n\n/**\n * Bridges the engine's widget registry to React context so WidgetSlot /\n * WebGLWidgetLayer can resolve components by type.\n */\nexport function WidgetProvider({ engine, children }: WidgetProviderProps) {\n\tconst resolver = useCallback(\n\t\t(_entityId: number, widgetType: string): ResolvedWidget | null => {\n\t\t\tconst def = engine.getWidget(widgetType);\n\t\t\tif (!def) return null;\n\t\t\tif (isR3FWidget(def)) {\n\t\t\t\treturn { surface: 'webgl', component: def.component };\n\t\t\t}\n\t\t\treturn { surface: 'dom', component: def.component };\n\t\t},\n\t\t[engine],\n\t);\n\n\treturn <WidgetResolverProvider value={resolver}>{children}</WidgetResolverProvider>;\n}\n","import type { EntityId } from '@jamesyong42/reactive-ecs';\nimport React, {\n\tuseCallback,\n\tuseEffect,\n\tuseImperativeHandle,\n\tuseLayoutEffect,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n} from 'react';\nimport { Vector2 } from 'three';\nimport { SelectionFrame, Widget, WorldBounds } from '../components.js';\nimport type { LayoutEngine } from '../engine.js';\nimport { DEAD_ZONE_TOUCH_PX } from '../interaction-constants.js';\nimport { CursorResource, NavigationStackResource } from '../resources.js';\nimport { ContainerRefProvider, EngineProvider, useWidgetResolver } from './context.js';\nimport { SelectionOverlaySlot } from './SelectionOverlaySlot.js';\nimport { WidgetProvider } from './WidgetProvider.js';\nimport { WidgetSlot } from './WidgetSlot.js';\nimport type { GridConfig } from './webgl/GridRenderer.js';\nimport { GridRenderer } from './webgl/GridRenderer.js';\nimport type { SelectionBounds, SelectionConfig } from './webgl/SelectionRenderer.js';\nimport { SelectionRenderer } from './webgl/SelectionRenderer.js';\nimport { WebGLWidgetLayer } from './webgl/WebGLWidgetLayer.js';\n\n/** Imperative handle exposed via `ref` on InfiniteCanvas for programmatic control. */\nexport interface InfiniteCanvasHandle {\n\t/** Moves the camera to the specified world coordinates. */\n\tpanTo(worldX: number, worldY: number): void;\n\t/** Sets the zoom level directly. */\n\tzoomTo(zoom: number): void;\n\t/** Adjusts camera to fit all entities in the viewport. */\n\tzoomToFit(padding?: number): void;\n\t/** Undoes the last command or command group. */\n\tundo(): void;\n\t/** Redoes the last undone command. */\n\tredo(): void;\n\t/** Returns the underlying LayoutEngine instance. */\n\tgetEngine(): LayoutEngine;\n}\n\n/** Props for the InfiniteCanvas component. */\ninterface InfiniteCanvasProps {\n\t/**\n\t * The LayoutEngine instance powering this canvas. Create with `createLayoutEngine()`.\n\t * Widgets and archetypes must be registered on the engine — via config or\n\t * `engine.registerWidget` / `engine.registerArchetype`.\n\t */\n\tengine: LayoutEngine;\n\t/** Grid configuration. Pass `false` to disable the grid entirely. */\n\tgrid?: Partial<GridConfig> | false;\n\t/** Selection highlight style configuration. */\n\tselection?: Partial<SelectionConfig>;\n\t/** Called when the set of selected entities changes. */\n\tonSelectionChange?: (entityIds: EntityId[]) => void;\n\t/** Called when the camera (pan/zoom) changes. */\n\tonCameraChange?: (camera: { x: number; y: number; zoom: number }) => void;\n\t/** Called when navigation depth changes (entering/exiting containers). */\n\tonNavigationChange?: (depth: number, containerId: EntityId | null) => void;\n\t/** CSS class name applied to the root container div. */\n\tclassName?: string;\n\t/** Inline styles applied to the root container div. */\n\tstyle?: React.CSSProperties;\n\t/** Overlay children (toolbars, panels) rendered on top of the canvas. */\n\tchildren?: React.ReactNode;\n}\n\nexport const InfiniteCanvas = React.forwardRef<InfiniteCanvasHandle, InfiniteCanvasProps>(\n\tfunction InfiniteCanvas(\n\t\t{\n\t\t\tengine,\n\t\t\tgrid,\n\t\t\tselection,\n\t\t\tonSelectionChange,\n\t\t\tonCameraChange,\n\t\t\tonNavigationChange,\n\t\t\tclassName,\n\t\t\tstyle,\n\t\t\tchildren,\n\t\t},\n\t\tref,\n\t) {\n\t\tconst containerRef = useRef<HTMLDivElement>(null);\n\n\t\t// Keep latest callback refs to avoid stale closures in the rAF loop\n\t\tconst onSelectionChangeRef = useRef(onSelectionChange);\n\t\tconst onCameraChangeRef = useRef(onCameraChange);\n\t\tconst onNavigationChangeRef = useRef(onNavigationChange);\n\t\tuseEffect(() => {\n\t\t\tonSelectionChangeRef.current = onSelectionChange;\n\t\t}, [onSelectionChange]);\n\t\tuseEffect(() => {\n\t\t\tonCameraChangeRef.current = onCameraChange;\n\t\t}, [onCameraChange]);\n\t\tuseEffect(() => {\n\t\t\tonNavigationChangeRef.current = onNavigationChange;\n\t\t}, [onNavigationChange]);\n\n\t\t// Imperative handle\n\t\tuseImperativeHandle(\n\t\t\tref,\n\t\t\t() => ({\n\t\t\t\tpanTo: (x, y) => {\n\t\t\t\t\tengine.panTo(x, y);\n\t\t\t\t\tengine.markDirty();\n\t\t\t\t},\n\t\t\t\tzoomTo: (zoom) => {\n\t\t\t\t\tengine.zoomTo(zoom);\n\t\t\t\t\tengine.markDirty();\n\t\t\t\t},\n\t\t\t\tzoomToFit: (padding) => {\n\t\t\t\t\tengine.zoomToFit(undefined, padding);\n\t\t\t\t\tengine.markDirty();\n\t\t\t\t},\n\t\t\t\tundo: () => {\n\t\t\t\t\tengine.undo();\n\t\t\t\t\tengine.markDirty();\n\t\t\t\t},\n\t\t\t\tredo: () => {\n\t\t\t\t\tengine.redo();\n\t\t\t\t\tengine.markDirty();\n\t\t\t\t},\n\t\t\t\tgetEngine: () => engine,\n\t\t\t}),\n\t\t\t[engine],\n\t\t);\n\n\t\tconst webglCanvasRef = useRef<HTMLCanvasElement>(null);\n\t\tconst gridRendererRef = useRef<GridRenderer | null>(null);\n\t\tconst selectionRendererRef = useRef<SelectionRenderer | null>(null);\n\t\tconst cameraLayerRef = useRef<HTMLDivElement>(null);\n\t\tconst slotRefs = useRef(new Map<EntityId, HTMLDivElement>());\n\t\tconst [visibleEntities, setVisibleEntities] = useState<EntityId[]>([]);\n\n\t\t// Register slot ref for batch updater\n\t\tconst registerSlotRef = useCallback((entityId: EntityId, el: HTMLDivElement | null) => {\n\t\t\tif (el) {\n\t\t\t\tslotRefs.current.set(entityId, el);\n\t\t\t} else {\n\t\t\t\tslotRefs.current.delete(entityId);\n\t\t\t}\n\t\t}, []);\n\n\t\t// Initialize GridRenderer + set viewport size on mount/resize\n\t\tuseLayoutEffect(() => {\n\t\t\tconst container = containerRef.current;\n\t\t\tconst canvas = webglCanvasRef.current;\n\t\t\tif (!container || !canvas) return;\n\n\t\t\tconst gridEnabled = grid !== false;\n\t\t\tlet gridInst: GridRenderer | null = null;\n\t\t\tif (gridEnabled) {\n\t\t\t\tgridInst = new GridRenderer(canvas);\n\t\t\t\tgridRendererRef.current = gridInst;\n\t\t\t}\n\n\t\t\t// SelectionRenderer shares the WebGLRenderer from GridRenderer\n\t\t\tconst selInst = new SelectionRenderer();\n\t\t\tselectionRendererRef.current = selInst;\n\n\t\t\tconst updateSize = () => {\n\t\t\t\tconst rect = container.getBoundingClientRect();\n\t\t\t\tconst dpr = window.devicePixelRatio;\n\t\t\t\tengine.setViewport(rect.width, rect.height, dpr);\n\t\t\t\tcanvas.style.width = `${rect.width}px`;\n\t\t\t\tcanvas.style.height = `${rect.height}px`;\n\t\t\t\tif (gridInst) {\n\t\t\t\t\tgridInst.setSize(rect.width, rect.height, dpr);\n\t\t\t\t}\n\t\t\t\tselInst.setSize(new Vector2(rect.width * dpr, rect.height * dpr), dpr);\n\t\t\t};\n\n\t\t\tupdateSize();\n\t\t\tconst observer = new ResizeObserver(updateSize);\n\t\t\tobserver.observe(container);\n\t\t\treturn () => {\n\t\t\t\tobserver.disconnect();\n\t\t\t\tif (gridInst) {\n\t\t\t\t\tgridInst.dispose();\n\t\t\t\t\tgridRendererRef.current = null;\n\t\t\t\t}\n\t\t\t\tselInst.dispose();\n\t\t\t\tselectionRendererRef.current = null;\n\t\t\t};\n\t\t}, [engine, grid]);\n\n\t\t// Apply grid + selection config on every render\n\t\tuseEffect(() => {\n\t\t\tconst gridR = gridRendererRef.current;\n\t\t\tif (gridR && grid !== false) {\n\t\t\t\tconst isDark = document.documentElement.classList.contains('dark');\n\t\t\t\tgridR.setConfig({\n\t\t\t\t\tdotColor: isDark ? [1, 1, 1] : [0, 0, 0],\n\t\t\t\t\tdotAlpha: isDark ? 0.12 : 0.18,\n\t\t\t\t\t...grid,\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst selR = selectionRendererRef.current;\n\t\t\tif (selR && selection) {\n\t\t\t\tselR.setConfig(selection);\n\t\t\t}\n\t\t\tengine.markDirty();\n\t\t}, [engine, grid, selection]);\n\n\t\t// Wheel handler — pan/zoom (gesture channel, always active)\n\t\tuseEffect(() => {\n\t\t\tconst container = containerRef.current;\n\t\t\tif (!container) return;\n\n\t\t\tconst onWheel = (e: WheelEvent) => {\n\t\t\t\te.preventDefault();\n\t\t\t\tif (e.ctrlKey || e.metaKey) {\n\t\t\t\t\t// Pinch zoom or ctrl+scroll\n\t\t\t\t\tconst rect = container.getBoundingClientRect();\n\t\t\t\t\tengine.zoomAtPoint(e.clientX - rect.left, e.clientY - rect.top, -e.deltaY * 0.01);\n\t\t\t\t} else {\n\t\t\t\t\t// Two-finger scroll pan\n\t\t\t\t\tengine.panBy(-e.deltaX, -e.deltaY);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tcontainer.addEventListener('wheel', onWheel, { passive: false });\n\t\t\treturn () => container.removeEventListener('wheel', onWheel);\n\t\t}, [engine]);\n\n\t\t// Touch gesture handler — iOS Freeform-style interactions\n\t\t// 1 finger on background → pan; 1 finger on entity → select/drag;\n\t\t// 2 fingers → pinch-to-zoom + pan; double-tap → zoom step / enter container\n\t\tuseEffect(() => {\n\t\t\tconst container = containerRef.current;\n\t\t\tif (!container) return;\n\n\t\t\ttype TouchGesture =\n\t\t\t\t| { type: 'idle' }\n\t\t\t\t| { type: 'pending-pan'; x: number; y: number; time: number }\n\t\t\t\t| { type: 'panning'; lastX: number; lastY: number }\n\t\t\t\t| { type: 'pending-entity'; x: number; y: number; time: number }\n\t\t\t\t| { type: 'entity-dragging' }\n\t\t\t\t| { type: 'pinching'; lastDist: number; lastCx: number; lastCy: number };\n\n\t\t\tlet gesture: TouchGesture = { type: 'idle' };\n\t\t\tlet lastTapTime = 0;\n\t\t\tlet lastTapX = 0;\n\t\t\tlet lastTapY = 0;\n\t\t\tconst DOUBLE_TAP_MS = 300;\n\t\t\tconst DOUBLE_TAP_DIST = 30;\n\n\t\t\tfunction isOnWidget(target: EventTarget | null): boolean {\n\t\t\t\tlet el = target as HTMLElement | null;\n\t\t\t\twhile (el && el !== container) {\n\t\t\t\t\tif (el.hasAttribute('data-widget-slot')) return true;\n\t\t\t\t\tel = el.parentElement;\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tfunction isInteractive(target: EventTarget | null): boolean {\n\t\t\t\tconst el = target as HTMLElement | null;\n\t\t\t\tif (!el) return false;\n\t\t\t\tconst tag = el.tagName;\n\t\t\t\treturn (\n\t\t\t\t\ttag === 'INPUT' ||\n\t\t\t\t\ttag === 'TEXTAREA' ||\n\t\t\t\t\ttag === 'BUTTON' ||\n\t\t\t\t\ttag === 'SELECT' ||\n\t\t\t\t\tel.isContentEditable ||\n\t\t\t\t\tel.closest('button') !== null\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tfunction getRect() {\n\t\t\t\treturn container?.getBoundingClientRect() ?? new DOMRect();\n\t\t\t}\n\n\t\t\tfunction touchDist(t1: Touch, t2: Touch) {\n\t\t\t\tconst dx = t1.clientX - t2.clientX;\n\t\t\t\tconst dy = t1.clientY - t2.clientY;\n\t\t\t\treturn Math.sqrt(dx * dx + dy * dy);\n\t\t\t}\n\n\t\t\tfunction touchCenter(t1: Touch, t2: Touch, rect: DOMRect) {\n\t\t\t\treturn {\n\t\t\t\t\tx: (t1.clientX + t2.clientX) / 2 - rect.left,\n\t\t\t\t\ty: (t1.clientY + t2.clientY) / 2 - rect.top,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tfunction cancelEngineGesture() {\n\t\t\t\tif (gesture.type === 'pending-entity' || gesture.type === 'entity-dragging') {\n\t\t\t\t\tengine.handlePointerUp();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst noMods = { shift: false, ctrl: false, alt: false, meta: false };\n\n\t\t\tfunction onTouchStart(e: TouchEvent) {\n\t\t\t\tconst rect = getRect();\n\t\t\t\tconst touches = e.touches;\n\n\t\t\t\t// --- 2+ fingers → pinch (override everything) ---\n\t\t\t\tif (touches.length >= 2) {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\tcancelEngineGesture();\n\t\t\t\t\tconst dist = touchDist(touches[0], touches[1]);\n\t\t\t\t\tconst center = touchCenter(touches[0], touches[1], rect);\n\t\t\t\t\tgesture = { type: 'pinching', lastDist: dist, lastCx: center.x, lastCy: center.y };\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// --- 1 finger ---\n\t\t\t\tconst touch = touches[0];\n\t\t\t\tconst x = touch.clientX - rect.left;\n\t\t\t\tconst y = touch.clientY - rect.top;\n\n\t\t\t\t// Let interactive elements (buttons, inputs) handle their own touch\n\t\t\t\tif (isInteractive(e.target)) return;\n\n\t\t\t\te.preventDefault();\n\n\t\t\t\t// Double-tap detection\n\t\t\t\tconst now = Date.now();\n\t\t\t\tif (\n\t\t\t\t\tnow - lastTapTime < DOUBLE_TAP_MS &&\n\t\t\t\t\tMath.abs(x - lastTapX) < DOUBLE_TAP_DIST &&\n\t\t\t\t\tMath.abs(y - lastTapY) < DOUBLE_TAP_DIST\n\t\t\t\t) {\n\t\t\t\t\tlastTapTime = 0;\n\t\t\t\t\t// Hit test to check for entity\n\t\t\t\t\tconst directive = engine.handlePointerDown(x, y, 0, noMods);\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (directive.action === 'passthrough-track-drag') {\n\t\t\t\t\t\t\t// Double-tap on entity → enter container\n\t\t\t\t\t\t\tconst selected = engine.getSelectedEntities();\n\t\t\t\t\t\t\tif (selected.length === 1) {\n\t\t\t\t\t\t\t\tengine.enterContainer(selected[0]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Double-tap on empty → zoom step\n\t\t\t\t\t\t\tconst camera = engine.getCamera();\n\t\t\t\t\t\t\tconst target = camera.zoom < 0.9 ? 1 : camera.zoom < 1.8 ? 2 : 1;\n\t\t\t\t\t\t\tengine.zoomAtPoint(x, y, (target - camera.zoom) / camera.zoom);\n\t\t\t\t\t\t}\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tengine.handlePointerUp();\n\t\t\t\t\t\tengine.markDirty();\n\t\t\t\t\t}\n\t\t\t\t\tgesture = { type: 'idle' };\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (isOnWidget(e.target)) {\n\t\t\t\t\t// Touch on entity → delegate to engine\n\t\t\t\t\tengine.handlePointerDown(x, y, 0, noMods);\n\t\t\t\t\tgesture = { type: 'pending-entity', x, y, time: now };\n\t\t\t\t} else {\n\t\t\t\t\t// Touch on empty space → prepare to pan (don't tell engine yet)\n\t\t\t\t\tgesture = { type: 'pending-pan', x, y, time: now };\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction onTouchMove(e: TouchEvent) {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst rect = getRect();\n\t\t\t\tconst touches = e.touches;\n\n\t\t\t\t// --- Pinch ---\n\t\t\t\tif (gesture.type === 'pinching' && touches.length >= 2) {\n\t\t\t\t\tconst dist = touchDist(touches[0], touches[1]);\n\t\t\t\t\tconst center = touchCenter(touches[0], touches[1], rect);\n\t\t\t\t\tconst scale = dist / gesture.lastDist;\n\t\t\t\t\tengine.zoomAtPoint(center.x, center.y, scale - 1);\n\t\t\t\t\tengine.panBy(center.x - gesture.lastCx, center.y - gesture.lastCy);\n\t\t\t\t\tgesture.lastDist = dist;\n\t\t\t\t\tgesture.lastCx = center.x;\n\t\t\t\t\tgesture.lastCy = center.y;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Transition to pinch if second finger added\n\t\t\t\tif (touches.length >= 2) {\n\t\t\t\t\tcancelEngineGesture();\n\t\t\t\t\tconst dist = touchDist(touches[0], touches[1]);\n\t\t\t\t\tconst center = touchCenter(touches[0], touches[1], rect);\n\t\t\t\t\tgesture = { type: 'pinching', lastDist: dist, lastCx: center.x, lastCy: center.y };\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (touches.length < 1) return;\n\t\t\t\tconst touch = touches[0];\n\t\t\t\tconst x = touch.clientX - rect.left;\n\t\t\t\tconst y = touch.clientY - rect.top;\n\n\t\t\t\t// Pending pan → check dead zone\n\t\t\t\tif (gesture.type === 'pending-pan') {\n\t\t\t\t\tif (\n\t\t\t\t\t\tMath.abs(x - gesture.x) > DEAD_ZONE_TOUCH_PX ||\n\t\t\t\t\t\tMath.abs(y - gesture.y) > DEAD_ZONE_TOUCH_PX\n\t\t\t\t\t) {\n\t\t\t\t\t\tgesture = { type: 'panning', lastX: x, lastY: y };\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Active panning\n\t\t\t\tif (gesture.type === 'panning') {\n\t\t\t\t\tengine.panBy(x - gesture.lastX, y - gesture.lastY);\n\t\t\t\t\tgesture.lastX = x;\n\t\t\t\t\tgesture.lastY = y;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Entity drag → delegate to engine\n\t\t\t\tif (gesture.type === 'pending-entity' || gesture.type === 'entity-dragging') {\n\t\t\t\t\tengine.handlePointerMove(x, y, noMods);\n\t\t\t\t\tif (gesture.type === 'pending-entity') {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tMath.abs(x - gesture.x) > DEAD_ZONE_TOUCH_PX ||\n\t\t\t\t\t\t\tMath.abs(y - gesture.y) > DEAD_ZONE_TOUCH_PX\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tgesture = { type: 'entity-dragging' };\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction onTouchEnd(e: TouchEvent) {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst remaining = e.touches.length;\n\t\t\t\tconst rect = getRect();\n\n\t\t\t\t// Pinch → transition based on remaining fingers\n\t\t\t\tif (gesture.type === 'pinching') {\n\t\t\t\t\tif (remaining === 1) {\n\t\t\t\t\t\tconst t = e.touches[0];\n\t\t\t\t\t\tgesture = {\n\t\t\t\t\t\t\ttype: 'panning',\n\t\t\t\t\t\t\tlastX: t.clientX - rect.left,\n\t\t\t\t\t\t\tlastY: t.clientY - rect.top,\n\t\t\t\t\t\t};\n\t\t\t\t\t} else if (remaining === 0) {\n\t\t\t\t\t\tgesture = { type: 'idle' };\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (remaining > 0) return;\n\n\t\t\t\t// Tap on empty space → deselect\n\t\t\t\tif (gesture.type === 'pending-pan') {\n\t\t\t\t\tengine.handlePointerDown(gesture.x, gesture.y, 0, noMods);\n\t\t\t\t\tengine.handlePointerUp();\n\t\t\t\t\tengine.markDirty();\n\t\t\t\t\tlastTapTime = Date.now();\n\t\t\t\t\tlastTapX = gesture.x;\n\t\t\t\t\tlastTapY = gesture.y;\n\t\t\t\t}\n\n\t\t\t\t// Tap on entity (no drag) → selection already happened\n\t\t\t\tif (gesture.type === 'pending-entity') {\n\t\t\t\t\tengine.handlePointerUp();\n\t\t\t\t\tengine.markDirty();\n\t\t\t\t\tlastTapTime = Date.now();\n\t\t\t\t\tlastTapX = gesture.x;\n\t\t\t\t\tlastTapY = gesture.y;\n\t\t\t\t}\n\n\t\t\t\t// Entity drag end\n\t\t\t\tif (gesture.type === 'entity-dragging') {\n\t\t\t\t\tengine.handlePointerUp();\n\t\t\t\t\tengine.markDirty();\n\t\t\t\t}\n\n\t\t\t\tgesture = { type: 'idle' };\n\t\t\t}\n\n\t\t\tfunction onTouchCancel(_e: TouchEvent) {\n\t\t\t\t// Reset gesture state unconditionally — the browser cancelled the touch.\n\t\t\t\t// Unlike onTouchEnd we don't inspect e.touches (which may be empty).\n\t\t\t\tgesture = { type: 'idle' };\n\t\t\t\tengine.handlePointerCancel();\n\t\t\t}\n\n\t\t\tcontainer.addEventListener('touchstart', onTouchStart, { passive: false });\n\t\t\tcontainer.addEventListener('touchmove', onTouchMove, { passive: false });\n\t\t\tcontainer.addEventListener('touchend', onTouchEnd, { passive: false });\n\t\t\tcontainer.addEventListener('touchcancel', onTouchCancel, { passive: true });\n\n\t\t\treturn () => {\n\t\t\t\tcontainer.removeEventListener('touchstart', onTouchStart);\n\t\t\t\tcontainer.removeEventListener('touchmove', onTouchMove);\n\t\t\t\tcontainer.removeEventListener('touchend', onTouchEnd);\n\t\t\t\tcontainer.removeEventListener('touchcancel', onTouchCancel);\n\t\t\t};\n\t\t}, [engine]);\n\n\t\t// Canvas-level pointer handlers — attached to the root container div so\n\t\t// pointer events in the \"outside handle strip\" (handle hit zone that\n\t\t// extends beyond a widget slot's DOM bounds) reach the engine. Widget\n\t\t// slots still have their own handlers and stopPropagation, so events\n\t\t// inside widgets never reach these fallbacks.\n\t\tconst onCanvasPointerDown = useCallback(\n\t\t\t(e: React.PointerEvent) => {\n\t\t\t\tconst target = e.target as HTMLElement | null;\n\t\t\t\t// Respect interactive form elements inside widget children.\n\t\t\t\tif (target?.closest('button, input, textarea, select, [contenteditable]')) return;\n\t\t\t\tconst rect = containerRef.current?.getBoundingClientRect();\n\t\t\t\tif (!rect) return;\n\t\t\t\tconst directive = engine.handlePointerDown(\n\t\t\t\t\te.clientX - rect.left,\n\t\t\t\t\te.clientY - rect.top,\n\t\t\t\t\te.button,\n\t\t\t\t\t{\n\t\t\t\t\t\tshift: e.shiftKey,\n\t\t\t\t\t\tctrl: e.ctrlKey,\n\t\t\t\t\t\talt: e.altKey,\n\t\t\t\t\t\tmeta: e.metaKey,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\t// Capture on the container so subsequent moves route here even when\n\t\t\t\t// the pointer leaves the viewport. Widget slot already captures for\n\t\t\t\t// events that reach it first; this is for empty-space / outside-strip\n\t\t\t\t// events that bypass widget slots.\n\t\t\t\tif (\n\t\t\t\t\tdirective.action === 'capture-resize' ||\n\t\t\t\t\tdirective.action === 'passthrough-track-drag'\n\t\t\t\t) {\n\t\t\t\t\tcontainerRef.current?.setPointerCapture(e.pointerId);\n\t\t\t\t}\n\t\t\t\tif (directive.action === 'capture-resize') e.preventDefault();\n\t\t\t},\n\t\t\t[engine],\n\t\t);\n\n\t\tconst onCanvasPointerMove = useCallback(\n\t\t\t(e: React.PointerEvent) => {\n\t\t\t\t// Skip if a widget slot is handling this pointer — avoids double\n\t\t\t\t// handlePointerMove when the event bubbles from a captured widget.\n\t\t\t\tconst target = e.target as HTMLElement;\n\t\t\t\tif (target.closest?.('[data-widget-slot]') && target !== containerRef.current) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst rect = containerRef.current?.getBoundingClientRect();\n\t\t\t\tif (!rect) return;\n\t\t\t\tengine.handlePointerMove(e.clientX - rect.left, e.clientY - rect.top, {\n\t\t\t\t\tshift: e.shiftKey,\n\t\t\t\t\tctrl: e.ctrlKey,\n\t\t\t\t\talt: e.altKey,\n\t\t\t\t\tmeta: e.metaKey,\n\t\t\t\t});\n\t\t\t},\n\t\t\t[engine],\n\t\t);\n\n\t\tconst onCanvasPointerUp = useCallback(\n\t\t\t(e: React.PointerEvent) => {\n\t\t\t\tif (containerRef.current?.hasPointerCapture(e.pointerId)) {\n\t\t\t\t\tcontainerRef.current.releasePointerCapture(e.pointerId);\n\t\t\t\t}\n\t\t\t\tengine.handlePointerUp();\n\t\t\t},\n\t\t\t[engine],\n\t\t);\n\n\t\t// rAF tick loop — flushes the engine when dirty, then applies updates.\n\t\t// This is THE render loop. Input handlers set engine dirty; this loop ticks.\n\t\tuseEffect(() => {\n\t\t\tlet rafId: number;\n\t\t\tlet running = true;\n\n\t\t\tfunction loop() {\n\t\t\t\tif (!running) return;\n\n\t\t\t\tconst didTick = engine.flushIfDirty();\n\t\t\t\tif (didTick) {\n\t\t\t\t\tconst camera = engine.getCamera();\n\t\t\t\t\tconst changes = engine.getFrameChanges();\n\n\t\t\t\t\t// 1. Update camera layer CSS transform (O(1) for pan/zoom)\n\t\t\t\t\tif (cameraLayerRef.current) {\n\t\t\t\t\t\tcameraLayerRef.current.style.transform = `scale(${camera.zoom}) translate(${-camera.x}px, ${-camera.y}px)`;\n\t\t\t\t\t}\n\n\t\t\t\t\t// RFC-001 Phase 7: apply derived cursor to root container.\n\t\t\t\t\t// Equality guard avoids redundant DOM writes in devtools diffs.\n\t\t\t\t\tconst cursor = engine.world.getResource(CursorResource).cursor;\n\t\t\t\t\tif (containerRef.current && containerRef.current.style.cursor !== cursor) {\n\t\t\t\t\t\tcontainerRef.current.style.cursor = cursor;\n\t\t\t\t\t}\n\n\t\t\t\t\t// 1b. Render WebGL dot grid + selection, with profiler probes.\n\t\t\t\t\tconst profiler = engine.profiler;\n\t\t\t\t\tconst profilerOn = profiler.isEnabled();\n\t\t\t\t\tlet selectionFramesDrawn = 0;\n\t\t\t\t\tlet snapGuidesDrawn = 0;\n\t\t\t\t\tlet spacingIndicatorsDrawn = 0;\n\n\t\t\t\t\t// Zero the engine renderer.info counters at the top of the\n\t\t\t\t\t// tick. `autoReset` is set to false in GridRenderer so that\n\t\t\t\t\t// grid + selection calls accumulate into one tick total.\n\t\t\t\t\tif (gridRendererRef.current) {\n\t\t\t\t\t\tgridRendererRef.current.getWebGLRenderer().info.reset();\n\t\t\t\t\t}\n\n\t\t\t\t\tif (gridRendererRef.current) {\n\t\t\t\t\t\tprofiler.beginWebGL('grid');\n\t\t\t\t\t\tgridRendererRef.current.render(camera.x, camera.y, camera.zoom);\n\t\t\t\t\t\tprofiler.endWebGL('grid');\n\t\t\t\t\t}\n\t\t\t\t\tif (selectionRendererRef.current && gridRendererRef.current) {\n\t\t\t\t\t\tconst selected = engine.getSelectedEntities();\n\t\t\t\t\t\tconst selBounds: SelectionBounds[] = [];\n\t\t\t\t\t\tfor (const id of selected) {\n\t\t\t\t\t\t\t// Widgets that render their own chrome (e.g. cards) opt out\n\t\t\t\t\t\t\t// of the engine-drawn frame by lacking the SelectionFrame tag.\n\t\t\t\t\t\t\tif (!engine.has(id, SelectionFrame)) continue;\n\t\t\t\t\t\t\tconst wb = engine.get(id, WorldBounds);\n\t\t\t\t\t\t\tif (wb)\n\t\t\t\t\t\t\t\tselBounds.push({\n\t\t\t\t\t\t\t\t\tx: wb.worldX,\n\t\t\t\t\t\t\t\t\ty: wb.worldY,\n\t\t\t\t\t\t\t\t\twidth: wb.worldWidth,\n\t\t\t\t\t\t\t\t\theight: wb.worldHeight,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst hovId = engine.getHoveredEntity();\n\t\t\t\t\t\tlet hovBounds: SelectionBounds | null = null;\n\t\t\t\t\t\tif (hovId !== null && engine.has(hovId, SelectionFrame)) {\n\t\t\t\t\t\t\tconst wb = engine.get(hovId, WorldBounds);\n\t\t\t\t\t\t\tif (wb)\n\t\t\t\t\t\t\t\thovBounds = {\n\t\t\t\t\t\t\t\t\tx: wb.worldX,\n\t\t\t\t\t\t\t\t\ty: wb.worldY,\n\t\t\t\t\t\t\t\t\twidth: wb.worldWidth,\n\t\t\t\t\t\t\t\t\theight: wb.worldHeight,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst snapGuides = engine.getSnapGuides();\n\t\t\t\t\t\tconst equalSpacing = engine.getEqualSpacing();\n\t\t\t\t\t\tselectionFramesDrawn = selBounds.length + (hovBounds ? 1 : 0);\n\t\t\t\t\t\tsnapGuidesDrawn = snapGuides.length;\n\t\t\t\t\t\tspacingIndicatorsDrawn = equalSpacing.length;\n\n\t\t\t\t\t\tprofiler.beginWebGL('selection');\n\t\t\t\t\t\tselectionRendererRef.current.render(\n\t\t\t\t\t\t\tgridRendererRef.current.getWebGLRenderer(),\n\t\t\t\t\t\t\tcamera.x,\n\t\t\t\t\t\t\tcamera.y,\n\t\t\t\t\t\t\tcamera.zoom,\n\t\t\t\t\t\t\tselBounds,\n\t\t\t\t\t\t\thovBounds,\n\t\t\t\t\t\t\tsnapGuides,\n\t\t\t\t\t\t\tequalSpacing,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tprofiler.endWebGL('selection');\n\t\t\t\t\t}\n\n\t\t\t\t\t// 1c. Capture renderer.info + counts from the engine WebGL\n\t\t\t\t\t// renderer. Because GridRenderer sets autoReset=false and we\n\t\t\t\t\t// reset at the top of this block, info.render now holds the\n\t\t\t\t\t// accumulated total across grid + selection passes.\n\t\t\t\t\tif (profilerOn && gridRendererRef.current) {\n\t\t\t\t\t\tconst info = gridRendererRef.current.getWebGLRenderer().info;\n\t\t\t\t\t\tprofiler.recordWebGLStats({\n\t\t\t\t\t\t\tdrawCalls: info.render.calls,\n\t\t\t\t\t\t\ttriangles: info.render.triangles,\n\t\t\t\t\t\t\tselectionFrames: selectionFramesDrawn,\n\t\t\t\t\t\t\tsnapGuides: snapGuidesDrawn,\n\t\t\t\t\t\t\tspacingIndicators: spacingIndicatorsDrawn,\n\t\t\t\t\t\t\tdomPositionsUpdated: changes.positionsChanged.length,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\t// 2. Fix #1: Use WorldBounds (world-space) not Transform2D (local/parent-relative)\n\t\t\t\t\tfor (const entityId of changes.positionsChanged) {\n\t\t\t\t\t\tconst el = slotRefs.current.get(entityId);\n\t\t\t\t\t\tif (!el) continue;\n\t\t\t\t\t\tconst wb = engine.get(entityId, WorldBounds);\n\t\t\t\t\t\tif (!wb) continue;\n\t\t\t\t\t\tel.style.transform = `translate(${wb.worldX}px, ${wb.worldY}px)`;\n\t\t\t\t\t\tel.style.width = `${wb.worldWidth}px`;\n\t\t\t\t\t\tel.style.height = `${wb.worldHeight}px`;\n\t\t\t\t\t}\n\n\t\t\t\t\t// 3. Update visible entity list if entities entered/exited\n\t\t\t\t\tif (changes.entered.length > 0 || changes.exited.length > 0) {\n\t\t\t\t\t\tconst visible = engine.getVisibleEntities();\n\t\t\t\t\t\tsetVisibleEntities(visible.map((v) => v.entityId));\n\t\t\t\t\t}\n\n\t\t\t\t\t// 4. Fire event callbacks\n\t\t\t\t\tif (changes.selectionChanged && onSelectionChangeRef.current) {\n\t\t\t\t\t\tonSelectionChangeRef.current(engine.getSelectedEntities());\n\t\t\t\t\t}\n\t\t\t\t\tif (changes.cameraChanged && onCameraChangeRef.current) {\n\t\t\t\t\t\tonCameraChangeRef.current({ x: camera.x, y: camera.y, zoom: camera.zoom });\n\t\t\t\t\t}\n\t\t\t\t\tif (changes.navigationChanged && onNavigationChangeRef.current) {\n\t\t\t\t\t\tconst navStack = engine.world.getResource(NavigationStackResource);\n\t\t\t\t\t\tconst depth = navStack.frames.length - 1;\n\t\t\t\t\t\tconst containerId = navStack.frames[navStack.frames.length - 1].containerId;\n\t\t\t\t\t\tonNavigationChangeRef.current(depth, containerId);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\trafId = requestAnimationFrame(loop);\n\t\t\t}\n\n\t\t\t// Initial tick on mount\n\t\t\tengine.tick();\n\t\t\tconst visible = engine.getVisibleEntities();\n\t\t\tsetVisibleEntities(visible.map((v) => v.entityId));\n\n\t\t\t// Set initial camera transform + grid\n\t\t\tconst camera = engine.getCamera();\n\t\t\tif (cameraLayerRef.current) {\n\t\t\t\tcameraLayerRef.current.style.transform = `scale(${camera.zoom}) translate(${-camera.x}px, ${-camera.y}px)`;\n\t\t\t}\n\t\t\t// Initial WebGL grid render\n\t\t\tif (gridRendererRef.current) {\n\t\t\t\tgridRendererRef.current.render(camera.x, camera.y, camera.zoom);\n\t\t\t}\n\n\t\t\t// Set initial slot positions\n\t\t\tfor (const v of visible) {\n\t\t\t\tconst el = slotRefs.current.get(v.entityId);\n\t\t\t\tif (!el) continue;\n\t\t\t\tel.style.transform = `translate(${v.worldX}px, ${v.worldY}px)`;\n\t\t\t\tel.style.width = `${v.worldWidth}px`;\n\t\t\t\tel.style.height = `${v.worldHeight}px`;\n\t\t\t}\n\n\t\t\t// Start the loop\n\t\t\trafId = requestAnimationFrame(loop);\n\n\t\t\treturn () => {\n\t\t\t\trunning = false;\n\t\t\t\tcancelAnimationFrame(rafId);\n\t\t\t};\n\t\t}, [engine]);\n\n\t\t// Fix #4: useLayoutEffect to set initial positions BEFORE browser paint\n\t\t// Prevents one-frame flash at (0,0) when new widgets enter the viewport\n\t\tuseLayoutEffect(() => {\n\t\t\tfor (const entityId of visibleEntities) {\n\t\t\t\tconst el = slotRefs.current.get(entityId);\n\t\t\t\tif (!el) continue;\n\t\t\t\tconst wb = engine.get(entityId, WorldBounds);\n\t\t\t\tif (!wb) continue;\n\t\t\t\tel.style.transform = `translate(${wb.worldX}px, ${wb.worldY}px)`;\n\t\t\t\tel.style.width = `${wb.worldWidth}px`;\n\t\t\t\tel.style.height = `${wb.worldHeight}px`;\n\t\t\t}\n\t\t}, [visibleEntities, engine]);\n\n\t\t// Split visible entities by surface\n\t\tconst { domEntities, webglEntities } = useMemo(() => {\n\t\t\tconst dom: EntityId[] = [];\n\t\t\tconst webgl: EntityId[] = [];\n\t\t\tfor (const id of visibleEntities) {\n\t\t\t\tconst w = engine.get(id, Widget);\n\t\t\t\tif (w?.surface === 'webgl') {\n\t\t\t\t\twebgl.push(id);\n\t\t\t\t} else {\n\t\t\t\t\tdom.push(id);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { domEntities: dom, webglEntities: webgl };\n\t\t}, [visibleEntities, engine]);\n\n\t\tconst canvasContent = (\n\t\t\t<div\n\t\t\t\tref={containerRef}\n\t\t\t\tclassName={`relative overflow-hidden ${className ?? ''}`}\n\t\t\t\tstyle={{\n\t\t\t\t\t...style,\n\t\t\t\t\ttouchAction: 'none',\n\t\t\t\t\tbackgroundColor: 'var(--canvas-bg, #fafafa)',\n\t\t\t\t}}\n\t\t\t\tonPointerDown={onCanvasPointerDown}\n\t\t\t\tonPointerMove={onCanvasPointerMove}\n\t\t\t\tonPointerUp={onCanvasPointerUp}\n\t\t\t>\n\t\t\t\t{/* WebGL layer — dot grid, selection overlays, connections */}\n\t\t\t\t<canvas ref={webglCanvasRef} className=\"absolute inset-0 pointer-events-none\" />\n\n\t\t\t\t{/* R3F layer — WebGL widgets (lazy, only when webgl entities exist) */}\n\t\t\t\t{webglEntities.length > 0 && <WebGLWidgetBridge engine={engine} entities={webglEntities} />}\n\n\t\t\t\t{/* Background — purely visual; pointer handlers live on the container.\n\t\t\t Kept as a div so the paint order (canvas, background, camera layer)\n\t\t\t is stable and future background visuals have a dedicated layer. */}\n\t\t\t\t<div className=\"absolute inset-0 pointer-events-none\" />\n\n\t\t\t\t{/* Camera transform layer — DOM widgets + selection overlays for WebGL widgets */}\n\t\t\t\t<div\n\t\t\t\t\tref={cameraLayerRef}\n\t\t\t\t\tclassName=\"absolute left-0 top-0 origin-top-left will-change-transform\"\n\t\t\t\t>\n\t\t\t\t\t{domEntities.map((entityId) => (\n\t\t\t\t\t\t<WidgetSlot key={entityId} entityId={entityId} slotRef={registerSlotRef} />\n\t\t\t\t\t))}\n\t\t\t\t\t{webglEntities.map((entityId) => (\n\t\t\t\t\t\t<SelectionOverlaySlot key={entityId} entityId={entityId} slotRef={registerSlotRef} />\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\n\t\t\t\t{/* Children: toolbars, panels, etc. */}\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t);\n\n\t\treturn (\n\t\t\t<EngineProvider value={engine}>\n\t\t\t\t<ContainerRefProvider value={containerRef}>\n\t\t\t\t\t<WidgetProvider engine={engine}>{canvasContent}</WidgetProvider>\n\t\t\t\t</ContainerRefProvider>\n\t\t\t</EngineProvider>\n\t\t);\n\t},\n);\n\n/** Bridge component — reads widget resolver from context and passes to WebGLWidgetLayer */\nfunction WebGLWidgetBridge({ engine, entities }: { engine: LayoutEngine; entities: EntityId[] }) {\n\tconst resolver = useWidgetResolver();\n\tconst resolve = useCallback(\n\t\t(entityId: EntityId) => {\n\t\t\tif (!resolver) return null;\n\t\t\tconst w = engine.get(entityId, Widget);\n\t\t\treturn resolver(entityId, w?.type ?? '');\n\t\t},\n\t\t[resolver, engine],\n\t);\n\n\tif (!resolver) return null;\n\n\treturn <WebGLWidgetLayer engine={engine} entities={entities} resolve={resolve} />;\n}\n"],"mappings":";;;;;;;;;;;;;AAWA,SAAgB,cAA2C,UAAuB;AAEjF,QADaA,cAAAA,aAAa,UAAUC,cAAAA,WACxB,EAAE,QAAQ,EAAE;;;;;;AAOzB,SAAgB,cAAc,UAAgC;AAE7D,QADaD,cAAAA,aAAa,UAAUE,cAAAA,iBACzB,EAAE,WAAW;;;;;;AAOzB,SAAgB,YAAY,UAAgC;AAE3D,QADaF,cAAAA,aAAa,UAAUG,cAAAA,SACzB,EAAE,OAAO,EAAE;;;;;;AAOvB,SAAgB,cAAc,UAA6B;AAC1D,QAAOC,cAAAA,OAAO,UAAUC,cAAAA,SAAS;;;;;;AAOlC,SAAgB,gBAAgB,UAA8D;CAC7F,MAAM,SAASC,cAAAA,iBAAiB;AAChC,SAAA,GAAA,MAAA,cACE,UAAmC;EACnC,MAAM,WAAW,OAAO,IAAI,UAAUL,cAAAA,WAAW;AACjD,MAAI,SACH,QAAO,IAAI,UAAUA,cAAAA,YAAY,EAChC,MAAM;GAAE,GAAG,SAAS;GAAM,GAAG;GAAO,EACpC,CAAC;IAGJ,CAAC,QAAQ,SAAS,CAClB;;;;;;;;;AC3CF,MAAMM,8BAAmF;CACxF,OAAO;EAAE,OAAO;EAAK,QAAQ;EAAK;CAClC,QAAQ;EAAE,OAAO;EAAK,QAAQ;EAAK;CACnC,OAAO;EAAE,OAAO;EAAK,QAAQ;EAAK;CAClC,IAAI;EAAE,OAAO;EAAK,QAAQ;EAAK;CAC/B;;;;;;;;AAkBD,SAAgB,UAAU,EAAE,UAAU,UAAU,WAAW,SAAyB;CACnF,MAAM,WAAWC,cAAAA,OAAO,UAAUC,cAAAA,SAAS;AAkB3C,QACC,iBAAA,GAAA,kBAAA,KAAC,OAAD;EAAgB;EAAW,OAAO;GAhBlC,OAAO;GACP,QAAQ;GACR,cAAc;GACd,UAAU;GACV,WAAW,WACR,6DACA;GACH,WAAW,WAAW,gBAAgB;GACtC,iBAAiB;GACjB,YACC;GACD,YAAY,WAAW,0BAA0B,KAAA;GACjD,GAAG;GAIwC;EACzC;EACI,CAAA;;;;;;;;;;;;AA6BR,SAAgB,iBAAoB,MAGlC;CACD,MAAM,cAAcF,4BAA0B,KAAK;CACnD,MAAM,SAAS,KAAK;CAEpB,MAAM,aAAkD,EAAE,eAAe;AAExE,SACC,iBAAA,GAAA,kBAAA,KAAC,WAAD;GAAqB;aACpB,iBAAA,GAAA,kBAAA,KAAC,QAAD;IAAkB;IAAU,MAHjB,cAAiB,SAGU;IAAI,CAAA;GAC/B,CAAA;;AA2Bd,QAAO;EAAE,QAAA;GAtBR,MAAM,KAAK;GACX,QAAQ,KAAK;GACb,aAAa,KAAK;GAClB;GACA,WAAW;GAkBG;EAAE,WAAA;GAdhB,IAAI,KAAK;GACT,QAAQ,KAAK;GACb,YAAY,CAAC,CAACG,cAAAA,MAAM,EAAE,QAAQ,KAAK,MAAM,CAAC,CAAC;GAC3C,aAAa;IACZ,YAAY;IACZ,WAAW;IACX,WAAW;IAGX,gBAAgB;IAChB;GACD;GAGyB;EAAE;;;;;ACjH7B,MAAM,4BAAmF;CACxF,OAAO;EAAE,OAAO;EAAK,QAAQ;EAAK;CAClC,QAAQ;EAAE,OAAO;EAAK,QAAQ;EAAK;CACnC,OAAO;EAAE,OAAO;EAAK,QAAQ;EAAK;CAClC,IAAI;EAAE,OAAO;EAAK,QAAQ;EAAK;CAC/B;;;;;AAMD,SAAS,wBACR,OACA,QACA,QACA,OACkB;CAClB,MAAM,QAAQ,IAAIC,MAAAA,OAAO;CACzB,MAAM,IAAI,KAAK,IAAI,QAAQ,KAAK,IAAI,OAAO,OAAO,GAAG,EAAE;CACvD,MAAM,IAAI,CAAC,QAAQ;CACnB,MAAM,IAAI,CAAC,SAAS;AACpB,OAAM,OAAO,GAAG,IAAI,EAAE;AACtB,OAAM,OAAO,GAAG,IAAI,SAAS,EAAE;AAC/B,OAAM,iBAAiB,GAAG,IAAI,QAAQ,IAAI,GAAG,IAAI,OAAO;AACxD,OAAM,OAAO,IAAI,QAAQ,GAAG,IAAI,OAAO;AACvC,OAAM,iBAAiB,IAAI,OAAO,IAAI,QAAQ,IAAI,OAAO,IAAI,SAAS,EAAE;AACxE,OAAM,OAAO,IAAI,OAAO,IAAI,EAAE;AAC9B,OAAM,iBAAiB,IAAI,OAAO,GAAG,IAAI,QAAQ,GAAG,EAAE;AACtD,OAAM,OAAO,IAAI,GAAG,EAAE;AACtB,OAAM,iBAAiB,GAAG,GAAG,GAAG,IAAI,EAAE;AAEtC,QAAO,IAAIC,MAAAA,gBAAgB,OAAO;EACjC;EACA,cAAc;EACd,eAAe;EACf,WAAW;EACX,gBAAgB;EAChB,CAAC;;AAWH,SAAS,SAAS,EAAE,OAAO,QAAQ,OAAO,WAAW,aAA4B;AAEhF,QACC,iBAAA,GAAA,kBAAA,KAAC,QAAD;EAAM,WAAA,GAAA,MAAA,eAFwB,wBAAwB,OAAO,QAAQ,OAAO,EAAE,EAAE,CAAC,OAAO,OAAO,CAEvE;EAAE,UAAU;GAAC;GAAG;GAAG;GAAG;EAAE,eAAA;YAC/C,iBAAA,GAAA,kBAAA,KAAC,wBAAD;GAA6B;GAAkB;GAAsB;GAAa,CAAA;EAC5E,CAAA;;;;;;;;;;;AAyDT,SAAgB,yBAA4B,MAG1C;CACD,MAAM,cAAc,0BAA0B,KAAK;CACnD,MAAM,SAAS,KAAK;CACpB,MAAM,mBAAmB,KAAK,cAAc;CAE5C,MAAM,eACL,qBAAqB,gBAClB,OACA,qBAAqB,SACpB;EAAE,OAAO;EAAW,WAAW;EAAM,WAAW;EAAG,GACnD;EACA,OAAO,iBAAiB;EACxB,WAAW,iBAAiB,aAAa;EACzC,WAAW,iBAAiB,aAAa;EACzC;CAEL,MAAM,aAAkD,EAAE,UAAU,OAAO,aAAa;EACvF,MAAM,OAAO,cAAiB,SAAS;EACvC,MAAM,WAAWC,cAAAA,OAAO,UAAUC,cAAAA,SAAS;EAC3C,MAAM,YAAA,GAAA,MAAA,QAAyB,KAAK;AAGpC,GAAA,GAAA,mBAAA,gBAAe;GACd,MAAM,IAAI,SAAS;AACnB,OAAI,CAAC,EAAG;GACR,MAAM,cAAc,WAAW,OAAO;GACtC,MAAM,UAAU,WAAW,IAAI;GAC/B,MAAM,IAAI,EAAE,MAAM;AAClB,KAAE,MAAM,UAAU,KAAK,cAAc,KAAK,GAAI;AAC9C,KAAE,SAAS,MAAM,UAAU,EAAE,SAAS,KAAK;IAC1C;AAEF,SACC,iBAAA,GAAA,kBAAA,MAAC,SAAD;GAAO,KAAK;aAAZ,CACE,gBACA,iBAAA,GAAA,kBAAA,KAAC,UAAD;IACQ;IACC;IACR,OAAO,aAAa;IACpB,WAAW,aAAa;IACxB,WAAW,aAAa;IACvB,CAAA,EAEH,iBAAA,GAAA,kBAAA,KAAC,QAAD;IAAkB;IAAgB;IAAa;IAAe;IAAU,CAAA,CACjE;;;AA0BV,QAAO;EAAE,QAAA;GArBR,MAAM,KAAK;GACX,SAAS;GACT,QAAQ,KAAK;GACb,aAAa,KAAK;GAClB;GACA,WAAW;GAgBG;EAAE,WAAA;GAZhB,IAAI,KAAK;GACT,QAAQ,KAAK;GACb,YAAY,CAAC,CAACC,cAAAA,MAAM,EAAE,QAAQ,KAAK,MAAM,CAAC,CAAC;GAC3C,aAAa;IACZ,YAAY;IACZ,WAAW;IACX,WAAW;IACX,gBAAgB;IAChB;GACD;GAGyB;EAAE;;;;;;;;ACtL7B,SAAgB,eAAe,EAAE,QAAQ,YAAiC;AAazE,QAAO,iBAAA,GAAA,kBAAA,KAACC,cAAAA,wBAAD;EAAwB,QAAA,GAAA,MAAA,cAX7B,WAAmB,eAA8C;GACjE,MAAM,MAAM,OAAO,UAAU,WAAW;AACxC,OAAI,CAAC,IAAK,QAAO;AACjB,OAAIC,yBAAAA,YAAY,IAAI,CACnB,QAAO;IAAE,SAAS;IAAS,WAAW,IAAI;IAAW;AAEtD,UAAO;IAAE,SAAS;IAAO,WAAW,IAAI;IAAW;KAEpD,CAAC,OAAO,CAGqC;EAAG;EAAkC,CAAA;;;;ACsCpF,MAAa,iBAAiBC,MAAAA,QAAM,WACnC,SAAS,eACR,EACC,QACA,MACA,WACA,mBACA,gBACA,oBACA,WACA,OACA,YAED,KACC;CACD,MAAM,gBAAA,GAAA,MAAA,QAAsC,KAAK;CAGjD,MAAM,wBAAA,GAAA,MAAA,QAA8B,kBAAkB;CACtD,MAAM,qBAAA,GAAA,MAAA,QAA2B,eAAe;CAChD,MAAM,yBAAA,GAAA,MAAA,QAA+B,mBAAmB;AACxD,EAAA,GAAA,MAAA,iBAAgB;AACf,uBAAqB,UAAU;IAC7B,CAAC,kBAAkB,CAAC;AACvB,EAAA,GAAA,MAAA,iBAAgB;AACf,oBAAkB,UAAU;IAC1B,CAAC,eAAe,CAAC;AACpB,EAAA,GAAA,MAAA,iBAAgB;AACf,wBAAsB,UAAU;IAC9B,CAAC,mBAAmB,CAAC;AAGxB,EAAA,GAAA,MAAA,qBACC,YACO;EACN,QAAQ,GAAG,MAAM;AAChB,UAAO,MAAM,GAAG,EAAE;AAClB,UAAO,WAAW;;EAEnB,SAAS,SAAS;AACjB,UAAO,OAAO,KAAK;AACnB,UAAO,WAAW;;EAEnB,YAAY,YAAY;AACvB,UAAO,UAAU,KAAA,GAAW,QAAQ;AACpC,UAAO,WAAW;;EAEnB,YAAY;AACX,UAAO,MAAM;AACb,UAAO,WAAW;;EAEnB,YAAY;AACX,UAAO,MAAM;AACb,UAAO,WAAW;;EAEnB,iBAAiB;EACjB,GACD,CAAC,OAAO,CACR;CAED,MAAM,kBAAA,GAAA,MAAA,QAA2C,KAAK;CACtD,MAAM,mBAAA,GAAA,MAAA,QAA8C,KAAK;CACzD,MAAM,wBAAA,GAAA,MAAA,QAAwD,KAAK;CACnE,MAAM,kBAAA,GAAA,MAAA,QAAwC,KAAK;CACnD,MAAM,YAAA,GAAA,MAAA,wBAAkB,IAAI,KAA+B,CAAC;CAC5D,MAAM,CAAC,iBAAiB,uBAAA,GAAA,MAAA,UAA2C,EAAE,CAAC;CAGtE,MAAM,mBAAA,GAAA,MAAA,cAA+B,UAAoB,OAA8B;AACtF,MAAI,GACH,UAAS,QAAQ,IAAI,UAAU,GAAG;MAElC,UAAS,QAAQ,OAAO,SAAS;IAEhC,EAAE,CAAC;AAGN,EAAA,GAAA,MAAA,uBAAsB;EACrB,MAAM,YAAY,aAAa;EAC/B,MAAM,SAAS,eAAe;AAC9B,MAAI,CAAC,aAAa,CAAC,OAAQ;EAE3B,MAAM,cAAc,SAAS;EAC7B,IAAI,WAAgC;AACpC,MAAI,aAAa;AAChB,cAAW,IAAIC,yBAAAA,aAAa,OAAO;AACnC,mBAAgB,UAAU;;EAI3B,MAAM,UAAU,IAAIC,yBAAAA,mBAAmB;AACvC,uBAAqB,UAAU;EAE/B,MAAM,mBAAmB;GACxB,MAAM,OAAO,UAAU,uBAAuB;GAC9C,MAAM,MAAM,OAAO;AACnB,UAAO,YAAY,KAAK,OAAO,KAAK,QAAQ,IAAI;AAChD,UAAO,MAAM,QAAQ,GAAG,KAAK,MAAM;AACnC,UAAO,MAAM,SAAS,GAAG,KAAK,OAAO;AACrC,OAAI,SACH,UAAS,QAAQ,KAAK,OAAO,KAAK,QAAQ,IAAI;AAE/C,WAAQ,QAAQ,IAAIC,MAAAA,QAAQ,KAAK,QAAQ,KAAK,KAAK,SAAS,IAAI,EAAE,IAAI;;AAGvE,cAAY;EACZ,MAAM,WAAW,IAAI,eAAe,WAAW;AAC/C,WAAS,QAAQ,UAAU;AAC3B,eAAa;AACZ,YAAS,YAAY;AACrB,OAAI,UAAU;AACb,aAAS,SAAS;AAClB,oBAAgB,UAAU;;AAE3B,WAAQ,SAAS;AACjB,wBAAqB,UAAU;;IAE9B,CAAC,QAAQ,KAAK,CAAC;AAGlB,EAAA,GAAA,MAAA,iBAAgB;EACf,MAAM,QAAQ,gBAAgB;AAC9B,MAAI,SAAS,SAAS,OAAO;GAC5B,MAAM,SAAS,SAAS,gBAAgB,UAAU,SAAS,OAAO;AAClE,SAAM,UAAU;IACf,UAAU,SAAS;KAAC;KAAG;KAAG;KAAE,GAAG;KAAC;KAAG;KAAG;KAAE;IACxC,UAAU,SAAS,MAAO;IAC1B,GAAG;IACH,CAAC;;EAEH,MAAM,OAAO,qBAAqB;AAClC,MAAI,QAAQ,UACX,MAAK,UAAU,UAAU;AAE1B,SAAO,WAAW;IAChB;EAAC;EAAQ;EAAM;EAAU,CAAC;AAG7B,EAAA,GAAA,MAAA,iBAAgB;EACf,MAAM,YAAY,aAAa;AAC/B,MAAI,CAAC,UAAW;EAEhB,MAAM,WAAW,MAAkB;AAClC,KAAE,gBAAgB;AAClB,OAAI,EAAE,WAAW,EAAE,SAAS;IAE3B,MAAM,OAAO,UAAU,uBAAuB;AAC9C,WAAO,YAAY,EAAE,UAAU,KAAK,MAAM,EAAE,UAAU,KAAK,KAAK,CAAC,EAAE,SAAS,IAAK;SAGjF,QAAO,MAAM,CAAC,EAAE,QAAQ,CAAC,EAAE,OAAO;;AAIpC,YAAU,iBAAiB,SAAS,SAAS,EAAE,SAAS,OAAO,CAAC;AAChE,eAAa,UAAU,oBAAoB,SAAS,QAAQ;IAC1D,CAAC,OAAO,CAAC;AAKZ,EAAA,GAAA,MAAA,iBAAgB;EACf,MAAM,YAAY,aAAa;AAC/B,MAAI,CAAC,UAAW;EAUhB,IAAI,UAAwB,EAAE,MAAM,QAAQ;EAC5C,IAAI,cAAc;EAClB,IAAI,WAAW;EACf,IAAI,WAAW;EACf,MAAM,gBAAgB;EACtB,MAAM,kBAAkB;EAExB,SAAS,WAAW,QAAqC;GACxD,IAAI,KAAK;AACT,UAAO,MAAM,OAAO,WAAW;AAC9B,QAAI,GAAG,aAAa,mBAAmB,CAAE,QAAO;AAChD,SAAK,GAAG;;AAET,UAAO;;EAGR,SAAS,cAAc,QAAqC;GAC3D,MAAM,KAAK;AACX,OAAI,CAAC,GAAI,QAAO;GAChB,MAAM,MAAM,GAAG;AACf,UACC,QAAQ,WACR,QAAQ,cACR,QAAQ,YACR,QAAQ,YACR,GAAG,qBACH,GAAG,QAAQ,SAAS,KAAK;;EAI3B,SAAS,UAAU;AAClB,UAAO,WAAW,uBAAuB,IAAI,IAAI,SAAS;;EAG3D,SAAS,UAAU,IAAW,IAAW;GACxC,MAAM,KAAK,GAAG,UAAU,GAAG;GAC3B,MAAM,KAAK,GAAG,UAAU,GAAG;AAC3B,UAAO,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG;;EAGpC,SAAS,YAAY,IAAW,IAAW,MAAe;AACzD,UAAO;IACN,IAAI,GAAG,UAAU,GAAG,WAAW,IAAI,KAAK;IACxC,IAAI,GAAG,UAAU,GAAG,WAAW,IAAI,KAAK;IACxC;;EAGF,SAAS,sBAAsB;AAC9B,OAAI,QAAQ,SAAS,oBAAoB,QAAQ,SAAS,kBACzD,QAAO,iBAAiB;;EAI1B,MAAM,SAAS;GAAE,OAAO;GAAO,MAAM;GAAO,KAAK;GAAO,MAAM;GAAO;EAErE,SAAS,aAAa,GAAe;GACpC,MAAM,OAAO,SAAS;GACtB,MAAM,UAAU,EAAE;AAGlB,OAAI,QAAQ,UAAU,GAAG;AACxB,MAAE,gBAAgB;AAClB,yBAAqB;IACrB,MAAM,OAAO,UAAU,QAAQ,IAAI,QAAQ,GAAG;IAC9C,MAAM,SAAS,YAAY,QAAQ,IAAI,QAAQ,IAAI,KAAK;AACxD,cAAU;KAAE,MAAM;KAAY,UAAU;KAAM,QAAQ,OAAO;KAAG,QAAQ,OAAO;KAAG;AAClF;;GAID,MAAM,QAAQ,QAAQ;GACtB,MAAM,IAAI,MAAM,UAAU,KAAK;GAC/B,MAAM,IAAI,MAAM,UAAU,KAAK;AAG/B,OAAI,cAAc,EAAE,OAAO,CAAE;AAE7B,KAAE,gBAAgB;GAGlB,MAAM,MAAM,KAAK,KAAK;AACtB,OACC,MAAM,cAAc,iBACpB,KAAK,IAAI,IAAI,SAAS,GAAG,mBACzB,KAAK,IAAI,IAAI,SAAS,GAAG,iBACxB;AACD,kBAAc;IAEd,MAAM,YAAY,OAAO,kBAAkB,GAAG,GAAG,GAAG,OAAO;AAC3D,QAAI;AACH,SAAI,UAAU,WAAW,0BAA0B;MAElD,MAAM,WAAW,OAAO,qBAAqB;AAC7C,UAAI,SAAS,WAAW,EACvB,QAAO,eAAe,SAAS,GAAG;YAE7B;MAEN,MAAM,SAAS,OAAO,WAAW;MACjC,MAAM,SAAS,OAAO,OAAO,KAAM,IAAI,OAAO,OAAO,MAAM,IAAI;AAC/D,aAAO,YAAY,GAAG,IAAI,SAAS,OAAO,QAAQ,OAAO,KAAK;;cAEtD;AACT,YAAO,iBAAiB;AACxB,YAAO,WAAW;;AAEnB,cAAU,EAAE,MAAM,QAAQ;AAC1B;;AAGD,OAAI,WAAW,EAAE,OAAO,EAAE;AAEzB,WAAO,kBAAkB,GAAG,GAAG,GAAG,OAAO;AACzC,cAAU;KAAE,MAAM;KAAkB;KAAG;KAAG,MAAM;KAAK;SAGrD,WAAU;IAAE,MAAM;IAAe;IAAG;IAAG,MAAM;IAAK;;EAIpD,SAAS,YAAY,GAAe;AACnC,KAAE,gBAAgB;GAClB,MAAM,OAAO,SAAS;GACtB,MAAM,UAAU,EAAE;AAGlB,OAAI,QAAQ,SAAS,cAAc,QAAQ,UAAU,GAAG;IACvD,MAAM,OAAO,UAAU,QAAQ,IAAI,QAAQ,GAAG;IAC9C,MAAM,SAAS,YAAY,QAAQ,IAAI,QAAQ,IAAI,KAAK;IACxD,MAAM,QAAQ,OAAO,QAAQ;AAC7B,WAAO,YAAY,OAAO,GAAG,OAAO,GAAG,QAAQ,EAAE;AACjD,WAAO,MAAM,OAAO,IAAI,QAAQ,QAAQ,OAAO,IAAI,QAAQ,OAAO;AAClE,YAAQ,WAAW;AACnB,YAAQ,SAAS,OAAO;AACxB,YAAQ,SAAS,OAAO;AACxB;;AAID,OAAI,QAAQ,UAAU,GAAG;AACxB,yBAAqB;IACrB,MAAM,OAAO,UAAU,QAAQ,IAAI,QAAQ,GAAG;IAC9C,MAAM,SAAS,YAAY,QAAQ,IAAI,QAAQ,IAAI,KAAK;AACxD,cAAU;KAAE,MAAM;KAAY,UAAU;KAAM,QAAQ,OAAO;KAAG,QAAQ,OAAO;KAAG;AAClF;;AAGD,OAAI,QAAQ,SAAS,EAAG;GACxB,MAAM,QAAQ,QAAQ;GACtB,MAAM,IAAI,MAAM,UAAU,KAAK;GAC/B,MAAM,IAAI,MAAM,UAAU,KAAK;AAG/B,OAAI,QAAQ,SAAS,eAAe;AACnC,QACC,KAAK,IAAI,IAAI,QAAQ,EAAE,GAAA,KACvB,KAAK,IAAI,IAAI,QAAQ,EAAE,GAAA,EAEvB,WAAU;KAAE,MAAM;KAAW,OAAO;KAAG,OAAO;KAAG;AAElD;;AAID,OAAI,QAAQ,SAAS,WAAW;AAC/B,WAAO,MAAM,IAAI,QAAQ,OAAO,IAAI,QAAQ,MAAM;AAClD,YAAQ,QAAQ;AAChB,YAAQ,QAAQ;AAChB;;AAID,OAAI,QAAQ,SAAS,oBAAoB,QAAQ,SAAS,mBAAmB;AAC5E,WAAO,kBAAkB,GAAG,GAAG,OAAO;AACtC,QAAI,QAAQ,SAAS;SAEnB,KAAK,IAAI,IAAI,QAAQ,EAAE,GAAA,KACvB,KAAK,IAAI,IAAI,QAAQ,EAAE,GAAA,EAEvB,WAAU,EAAE,MAAM,mBAAmB;;;;EAMzC,SAAS,WAAW,GAAe;AAClC,KAAE,gBAAgB;GAClB,MAAM,YAAY,EAAE,QAAQ;GAC5B,MAAM,OAAO,SAAS;AAGtB,OAAI,QAAQ,SAAS,YAAY;AAChC,QAAI,cAAc,GAAG;KACpB,MAAM,IAAI,EAAE,QAAQ;AACpB,eAAU;MACT,MAAM;MACN,OAAO,EAAE,UAAU,KAAK;MACxB,OAAO,EAAE,UAAU,KAAK;MACxB;eACS,cAAc,EACxB,WAAU,EAAE,MAAM,QAAQ;AAE3B;;AAGD,OAAI,YAAY,EAAG;AAGnB,OAAI,QAAQ,SAAS,eAAe;AACnC,WAAO,kBAAkB,QAAQ,GAAG,QAAQ,GAAG,GAAG,OAAO;AACzD,WAAO,iBAAiB;AACxB,WAAO,WAAW;AAClB,kBAAc,KAAK,KAAK;AACxB,eAAW,QAAQ;AACnB,eAAW,QAAQ;;AAIpB,OAAI,QAAQ,SAAS,kBAAkB;AACtC,WAAO,iBAAiB;AACxB,WAAO,WAAW;AAClB,kBAAc,KAAK,KAAK;AACxB,eAAW,QAAQ;AACnB,eAAW,QAAQ;;AAIpB,OAAI,QAAQ,SAAS,mBAAmB;AACvC,WAAO,iBAAiB;AACxB,WAAO,WAAW;;AAGnB,aAAU,EAAE,MAAM,QAAQ;;EAG3B,SAAS,cAAc,IAAgB;AAGtC,aAAU,EAAE,MAAM,QAAQ;AAC1B,UAAO,qBAAqB;;AAG7B,YAAU,iBAAiB,cAAc,cAAc,EAAE,SAAS,OAAO,CAAC;AAC1E,YAAU,iBAAiB,aAAa,aAAa,EAAE,SAAS,OAAO,CAAC;AACxE,YAAU,iBAAiB,YAAY,YAAY,EAAE,SAAS,OAAO,CAAC;AACtE,YAAU,iBAAiB,eAAe,eAAe,EAAE,SAAS,MAAM,CAAC;AAE3E,eAAa;AACZ,aAAU,oBAAoB,cAAc,aAAa;AACzD,aAAU,oBAAoB,aAAa,YAAY;AACvD,aAAU,oBAAoB,YAAY,WAAW;AACrD,aAAU,oBAAoB,eAAe,cAAc;;IAE1D,CAAC,OAAO,CAAC;CAOZ,MAAM,uBAAA,GAAA,MAAA,cACJ,MAA0B;AAG1B,MAFe,EAAE,QAEL,QAAQ,qDAAqD,CAAE;EAC3E,MAAM,OAAO,aAAa,SAAS,uBAAuB;AAC1D,MAAI,CAAC,KAAM;EACX,MAAM,YAAY,OAAO,kBACxB,EAAE,UAAU,KAAK,MACjB,EAAE,UAAU,KAAK,KACjB,EAAE,QACF;GACC,OAAO,EAAE;GACT,MAAM,EAAE;GACR,KAAK,EAAE;GACP,MAAM,EAAE;GACR,CACD;AAKD,MACC,UAAU,WAAW,oBACrB,UAAU,WAAW,yBAErB,cAAa,SAAS,kBAAkB,EAAE,UAAU;AAErD,MAAI,UAAU,WAAW,iBAAkB,GAAE,gBAAgB;IAE9D,CAAC,OAAO,CACR;CAED,MAAM,uBAAA,GAAA,MAAA,cACJ,MAA0B;EAG1B,MAAM,SAAS,EAAE;AACjB,MAAI,OAAO,UAAU,qBAAqB,IAAI,WAAW,aAAa,QACrE;EAED,MAAM,OAAO,aAAa,SAAS,uBAAuB;AAC1D,MAAI,CAAC,KAAM;AACX,SAAO,kBAAkB,EAAE,UAAU,KAAK,MAAM,EAAE,UAAU,KAAK,KAAK;GACrE,OAAO,EAAE;GACT,MAAM,EAAE;GACR,KAAK,EAAE;GACP,MAAM,EAAE;GACR,CAAC;IAEH,CAAC,OAAO,CACR;CAED,MAAM,qBAAA,GAAA,MAAA,cACJ,MAA0B;AAC1B,MAAI,aAAa,SAAS,kBAAkB,EAAE,UAAU,CACvD,cAAa,QAAQ,sBAAsB,EAAE,UAAU;AAExD,SAAO,iBAAiB;IAEzB,CAAC,OAAO,CACR;AAID,EAAA,GAAA,MAAA,iBAAgB;EACf,IAAI;EACJ,IAAI,UAAU;EAEd,SAAS,OAAO;AACf,OAAI,CAAC,QAAS;AAGd,OADgB,OAAO,cACZ,EAAE;IACZ,MAAM,SAAS,OAAO,WAAW;IACjC,MAAM,UAAU,OAAO,iBAAiB;AAGxC,QAAI,eAAe,QAClB,gBAAe,QAAQ,MAAM,YAAY,SAAS,OAAO,KAAK,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE;IAKvG,MAAM,SAAS,OAAO,MAAM,YAAYC,cAAAA,eAAe,CAAC;AACxD,QAAI,aAAa,WAAW,aAAa,QAAQ,MAAM,WAAW,OACjE,cAAa,QAAQ,MAAM,SAAS;IAIrC,MAAM,WAAW,OAAO;IACxB,MAAM,aAAa,SAAS,WAAW;IACvC,IAAI,uBAAuB;IAC3B,IAAI,kBAAkB;IACtB,IAAI,yBAAyB;AAK7B,QAAI,gBAAgB,QACnB,iBAAgB,QAAQ,kBAAkB,CAAC,KAAK,OAAO;AAGxD,QAAI,gBAAgB,SAAS;AAC5B,cAAS,WAAW,OAAO;AAC3B,qBAAgB,QAAQ,OAAO,OAAO,GAAG,OAAO,GAAG,OAAO,KAAK;AAC/D,cAAS,SAAS,OAAO;;AAE1B,QAAI,qBAAqB,WAAW,gBAAgB,SAAS;KAC5D,MAAM,WAAW,OAAO,qBAAqB;KAC7C,MAAM,YAA+B,EAAE;AACvC,UAAK,MAAM,MAAM,UAAU;AAG1B,UAAI,CAAC,OAAO,IAAI,IAAIC,cAAAA,eAAe,CAAE;MACrC,MAAM,KAAK,OAAO,IAAI,IAAIC,cAAAA,YAAY;AACtC,UAAI,GACH,WAAU,KAAK;OACd,GAAG,GAAG;OACN,GAAG,GAAG;OACN,OAAO,GAAG;OACV,QAAQ,GAAG;OACX,CAAC;;KAEJ,MAAM,QAAQ,OAAO,kBAAkB;KACvC,IAAI,YAAoC;AACxC,SAAI,UAAU,QAAQ,OAAO,IAAI,OAAOD,cAAAA,eAAe,EAAE;MACxD,MAAM,KAAK,OAAO,IAAI,OAAOC,cAAAA,YAAY;AACzC,UAAI,GACH,aAAY;OACX,GAAG,GAAG;OACN,GAAG,GAAG;OACN,OAAO,GAAG;OACV,QAAQ,GAAG;OACX;;KAEH,MAAM,aAAa,OAAO,eAAe;KACzC,MAAM,eAAe,OAAO,iBAAiB;AAC7C,4BAAuB,UAAU,UAAU,YAAY,IAAI;AAC3D,uBAAkB,WAAW;AAC7B,8BAAyB,aAAa;AAEtC,cAAS,WAAW,YAAY;AAChC,0BAAqB,QAAQ,OAC5B,gBAAgB,QAAQ,kBAAkB,EAC1C,OAAO,GACP,OAAO,GACP,OAAO,MACP,WACA,WACA,YACA,aACA;AACD,cAAS,SAAS,YAAY;;AAO/B,QAAI,cAAc,gBAAgB,SAAS;KAC1C,MAAM,OAAO,gBAAgB,QAAQ,kBAAkB,CAAC;AACxD,cAAS,iBAAiB;MACzB,WAAW,KAAK,OAAO;MACvB,WAAW,KAAK,OAAO;MACvB,iBAAiB;MACjB,YAAY;MACZ,mBAAmB;MACnB,qBAAqB,QAAQ,iBAAiB;MAC9C,CAAC;;AAIH,SAAK,MAAM,YAAY,QAAQ,kBAAkB;KAChD,MAAM,KAAK,SAAS,QAAQ,IAAI,SAAS;AACzC,SAAI,CAAC,GAAI;KACT,MAAM,KAAK,OAAO,IAAI,UAAUA,cAAAA,YAAY;AAC5C,SAAI,CAAC,GAAI;AACT,QAAG,MAAM,YAAY,aAAa,GAAG,OAAO,MAAM,GAAG,OAAO;AAC5D,QAAG,MAAM,QAAQ,GAAG,GAAG,WAAW;AAClC,QAAG,MAAM,SAAS,GAAG,GAAG,YAAY;;AAIrC,QAAI,QAAQ,QAAQ,SAAS,KAAK,QAAQ,OAAO,SAAS,EAEzD,oBADgB,OAAO,oBACG,CAAC,KAAK,MAAM,EAAE,SAAS,CAAC;AAInD,QAAI,QAAQ,oBAAoB,qBAAqB,QACpD,sBAAqB,QAAQ,OAAO,qBAAqB,CAAC;AAE3D,QAAI,QAAQ,iBAAiB,kBAAkB,QAC9C,mBAAkB,QAAQ;KAAE,GAAG,OAAO;KAAG,GAAG,OAAO;KAAG,MAAM,OAAO;KAAM,CAAC;AAE3E,QAAI,QAAQ,qBAAqB,sBAAsB,SAAS;KAC/D,MAAM,WAAW,OAAO,MAAM,YAAYC,cAAAA,wBAAwB;KAClE,MAAM,QAAQ,SAAS,OAAO,SAAS;KACvC,MAAM,cAAc,SAAS,OAAO,SAAS,OAAO,SAAS,GAAG;AAChE,2BAAsB,QAAQ,OAAO,YAAY;;;AAInD,WAAQ,sBAAsB,KAAK;;AAIpC,SAAO,MAAM;EACb,MAAM,UAAU,OAAO,oBAAoB;AAC3C,qBAAmB,QAAQ,KAAK,MAAM,EAAE,SAAS,CAAC;EAGlD,MAAM,SAAS,OAAO,WAAW;AACjC,MAAI,eAAe,QAClB,gBAAe,QAAQ,MAAM,YAAY,SAAS,OAAO,KAAK,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE;AAGvG,MAAI,gBAAgB,QACnB,iBAAgB,QAAQ,OAAO,OAAO,GAAG,OAAO,GAAG,OAAO,KAAK;AAIhE,OAAK,MAAM,KAAK,SAAS;GACxB,MAAM,KAAK,SAAS,QAAQ,IAAI,EAAE,SAAS;AAC3C,OAAI,CAAC,GAAI;AACT,MAAG,MAAM,YAAY,aAAa,EAAE,OAAO,MAAM,EAAE,OAAO;AAC1D,MAAG,MAAM,QAAQ,GAAG,EAAE,WAAW;AACjC,MAAG,MAAM,SAAS,GAAG,EAAE,YAAY;;AAIpC,UAAQ,sBAAsB,KAAK;AAEnC,eAAa;AACZ,aAAU;AACV,wBAAqB,MAAM;;IAE1B,CAAC,OAAO,CAAC;AAIZ,EAAA,GAAA,MAAA,uBAAsB;AACrB,OAAK,MAAM,YAAY,iBAAiB;GACvC,MAAM,KAAK,SAAS,QAAQ,IAAI,SAAS;AACzC,OAAI,CAAC,GAAI;GACT,MAAM,KAAK,OAAO,IAAI,UAAUD,cAAAA,YAAY;AAC5C,OAAI,CAAC,GAAI;AACT,MAAG,MAAM,YAAY,aAAa,GAAG,OAAO,MAAM,GAAG,OAAO;AAC5D,MAAG,MAAM,QAAQ,GAAG,GAAG,WAAW;AAClC,MAAG,MAAM,SAAS,GAAG,GAAG,YAAY;;IAEnC,CAAC,iBAAiB,OAAO,CAAC;CAG7B,MAAM,EAAE,aAAa,mBAAA,GAAA,MAAA,eAAgC;EACpD,MAAM,MAAkB,EAAE;EAC1B,MAAM,QAAoB,EAAE;AAC5B,OAAK,MAAM,MAAM,gBAEhB,KADU,OAAO,IAAI,IAAIE,cAAAA,OACpB,EAAE,YAAY,QAClB,OAAM,KAAK,GAAG;MAEd,KAAI,KAAK,GAAG;AAGd,SAAO;GAAE,aAAa;GAAK,eAAe;GAAO;IAC/C,CAAC,iBAAiB,OAAO,CAAC;AA4C7B,QACC,iBAAA,GAAA,kBAAA,KAACC,cAAAA,gBAAD;EAAgB,OAAO;YACtB,iBAAA,GAAA,kBAAA,KAACC,cAAAA,sBAAD;GAAsB,OAAO;aAC5B,iBAAA,GAAA,kBAAA,KAAC,gBAAD;IAAwB;cAAS,iBAAA,GAAA,kBAAA,MA5ClC,OAAD;KACC,KAAK;KACL,WAAW,4BAA4B,aAAa;KACpD,OAAO;MACN,GAAG;MACH,aAAa;MACb,iBAAiB;MACjB;KACD,eAAe;KACf,eAAe;KACf,aAAa;eAVd;MAaC,iBAAA,GAAA,kBAAA,KAAC,UAAD;OAAQ,KAAK;OAAgB,WAAU;OAAyC,CAAA;MAG/E,cAAc,SAAS,KAAK,iBAAA,GAAA,kBAAA,KAAC,mBAAD;OAA2B;OAAQ,UAAU;OAAiB,CAAA;MAK3F,iBAAA,GAAA,kBAAA,KAAC,OAAD,EAAK,WAAU,wCAAyC,CAAA;MAGxD,iBAAA,GAAA,kBAAA,MAAC,OAAD;OACC,KAAK;OACL,WAAU;iBAFX,CAIE,YAAY,KAAK,aACjB,iBAAA,GAAA,kBAAA,KAACC,yBAAAA,YAAD;QAAqC;QAAU,SAAS;QAAmB,EAA1D,SAA0D,CAC1E,EACD,cAAc,KAAK,aACnB,iBAAA,GAAA,kBAAA,KAACC,yBAAAA,sBAAD;QAA+C;QAAU,SAAS;QAAmB,EAA1D,SAA0D,CACpF,CACG;;MAGL;MACI;MAM0C;IAAkB,CAAA;GAC1C,CAAA;EACP,CAAA;EAGnB;;AAGD,SAAS,kBAAkB,EAAE,QAAQ,YAA4D;CAChG,MAAM,WAAWC,cAAAA,mBAAmB;CACpC,MAAM,WAAA,GAAA,MAAA,cACJ,aAAuB;AACvB,MAAI,CAAC,SAAU,QAAO;AAEtB,SAAO,SAAS,UADN,OAAO,IAAI,UAAUL,cAAAA,OACJ,EAAE,QAAQ,GAAG;IAEzC,CAAC,UAAU,OAAO,CAClB;AAED,KAAI,CAAC,SAAU,QAAO;AAEtB,QAAO,iBAAA,GAAA,kBAAA,KAACM,yBAAAA,kBAAD;EAA0B;EAAkB;EAAmB;EAAW,CAAA"}
1
+ {"version":3,"file":"index.cjs","names":["CameraResource","BreakpointConfigResource","Widget","Visible","Transform2D","WidgetBreakpoint","CardPresetsResource","Card","Transform2D","CameraResource","ViewportResource","SpatialIndexResource","Visible","Culled","Active","Transform2D","Dragging","PreDragLayer","Card","Widget","Layer","NavigationStackResource","ParentFrame","Active","Transform2D","TransformTween","Transform2D","Resizable","Selected","Transform2D","CameraResource","Active","InteractionRole","ZIndex","Selectable","Card","Widget","OverlapCandidate","CardOverlapHotPoint","OverlapTarget","TransformTween","Dragging","CursorHint","CursorResource","SnapSource","SnapTarget","computeSnapGuides","Draggable","PhasedScheduler","SpatialIndex","Profiler","SpatialIndexResource","ZoomConfigResource","BreakpointConfigResource","CardPresetsResource","Transform2D","Container","ContainerCamera","ParentFrame","InteractionRole","Draggable","Selectable","CursorHint","NavigationStackResource","WidgetComp","WidgetData","ZIndex","Resizable","SelectionFrame","SnapSource","SnapTarget","ContainerChildren","CameraResource","ViewportResource","Active","Selected","RootCameraResource","Visible","WidgetBreakpoint","Layer","TransformTween","ParentFrame","useComponent","WidgetData","WidgetBreakpoint","Children","useTag","Selected","useLayoutEngine","pe","inputGroupStart","Widget","WidgetResolverProvider","React","WebGLManager","CursorResource","SelectionFrame","Transform2D","ZIndex","NavigationStackResource","Widget","Layer","EngineProvider","ContainerRefProvider","useWidgetResolver","R3FManager","SelectionOverlaySlot","WidgetSlot","useTag","Dragging","OverlapCandidate","OverlapTarget","useComponent","CardOverlapHotPoint","CardChrome","DEFAULT_CARD_PRESET_SIZES","Card","DEFAULT_CARD_PRESET_SIZES","Card"],"sources":["../src/ecs/archetype.ts","../src/ecs/commands.ts","../src/ecs/math.ts","../src/ecs/systems/breakpoint.ts","../src/ecs/systems/card.ts","../src/ecs/systems/cull.ts","../src/ecs/systems/drag-promote.ts","../src/ecs/systems/navigation-filter.ts","../src/ecs/systems/sort.ts","../src/ecs/systems/transform-tween.ts","../src/ecs/engine/interaction.ts","../src/ecs/engine/phases.ts","../src/ecs/engine/widget-binding.ts","../src/ecs/engine/LayoutEngine.ts","../src/ecs/hierarchy.ts","../src/react/hooks/widget.ts","../src/react/input/adapters/native-interactive.ts","../src/react/input/adapters/ClickAdapter.ts","../src/react/input/adapters/PointerAdapter.ts","../src/react/input/adapters/WheelAdapter.ts","../src/react/input/constants.ts","../src/react/input/InputManager.ts","../src/react/input/installEngineHandlers.ts","../src/react/input/synthetic.ts","../src/react/input/recognizers/DoubleTapRecognizer.ts","../src/react/input/recognizers/DragRecognizer.ts","../src/react/input/recognizers/HoverRecognizer.ts","../src/react/input/recognizers/PanRecognizer.ts","../src/react/input/recognizers/PinchRecognizer.ts","../src/react/input/recognizers/TapRecognizer.ts","../src/react/input/routers/R3FRouter.ts","../src/react/widgets/overlap-glow.ts","../src/react/widgets/registry.ts","../src/react/widgets/WidgetProvider.tsx","../src/react/InfiniteCanvas.tsx","../src/react/widgets/card.tsx","../src/r3f/widgets/geometry-card.tsx"],"sourcesContent":["import type { ComponentInit, EntityId, TagType } from '@jamesyong42/reactive-ecs';\n\n/**\n * An archetype is a recipe for creating an entity: it declares which components\n * and tags the entity should have on spawn. Archetypes may reference a widget\n * type (for visible entities) or stand alone (for logic-only entities).\n *\n * The engine auto-generates a default archetype for every registered widget\n * that does not have an explicit one — so simple widgets don't need to ship\n * an archetype at all. Write an archetype only when you need to bundle extra\n * behaviour (Container, Locked, custom components) with a widget.\n */\nexport interface Archetype {\n\t/** Unique archetype id. Pass this to `engine.spawn(id, ...)`. */\n\tid: string;\n\t/**\n\t * The widget type this archetype renders as. Required for visible entities;\n\t * omit for logic-only entities that have no view.\n\t */\n\twidget?: string;\n\t/** Extra components added on spawn, beyond Transform2D / Widget / WidgetData / ZIndex. */\n\tcomponents?: ComponentInit[];\n\t/** Extra tags added on spawn, beyond the interactive defaults. */\n\ttags?: TagType[];\n\t/**\n\t * Which interaction capabilities to grant on spawn.\n\t *\n\t * - `true` (default) / `undefined`: add Selectable, Draggable, Resizable,\n\t * SelectionFrame, SnapSource, and SnapTarget — the full bundle.\n\t * - `false`: add none (backdrops, decorations, locked entities).\n\t * - object form: pick and choose — e.g. iOS-style cards use\n\t * `{ selectable: true, draggable: true, resizable: false,\n\t * selectionFrame: false, snapSource: false, snapTarget: true }`\n\t * so they can be moved and selected but never resized, render their\n\t * own chrome instead of the engine-drawn frame, don't snap to\n\t * neighbours when dragged, but do serve as references that other\n\t * widgets snap to.\n\t *\n\t * Omitted interaction keys default to `false`. `selectionFrame` is an\n\t * exception: if omitted, it follows `selectable` (an entity you can\n\t * select gets a frame unless you explicitly opt out).\n\t *\n\t * NOTE for upgraders from earlier versions: `interactive: true` now\n\t * additionally grants `SnapSource` and `SnapTarget`, so widgets using\n\t * the default bundle will start participating in alignment-snap math\n\t * during drag. If you previously relied on snap being a no-op for\n\t * these widgets, switch to the object form and set both to `false`.\n\t */\n\tinteractive?:\n\t\t| boolean\n\t\t| {\n\t\t\t\tselectable?: boolean;\n\t\t\t\tdraggable?: boolean;\n\t\t\t\tresizable?: boolean;\n\t\t\t\tselectionFrame?: boolean;\n\t\t\t\t/** Dragging this entity invokes alignment-snap math. Default false in the object form. */\n\t\t\t\tsnapSource?: boolean;\n\t\t\t\t/** Bounds participate as references for other entities' snap math. Default false in the object form. */\n\t\t\t\tsnapTarget?: boolean;\n\t\t };\n\t/** Overrides the widget's defaultSize. */\n\tdefaultSize?: { width: number; height: number };\n}\n\n/**\n * Options for `engine.spawn(archetypeId, opts)`.\n * All fields are optional — defaults come from the archetype + widget.\n */\nexport interface SpawnOptions {\n\t/** World-space position. Defaults to { x: 0, y: 0 }. */\n\tat?: { x: number; y: number };\n\t/** World-space size. Falls back to archetype.defaultSize → widget.defaultSize. */\n\tsize?: { width: number; height: number };\n\t/** Initial rotation in radians. Default 0. */\n\trotation?: number;\n\t/** Data patch merged into the widget's defaultData. */\n\tdata?: Record<string, unknown>;\n\t/** Z-order. Default 0. */\n\tzIndex?: number;\n\t/** Parent container entity — writes `ParentFrame` on spawn so the child\n\t * lives in the container's sub-canvas frame. */\n\tparent?: EntityId;\n}\n\n/** Simple in-memory archetype registry. */\nexport interface ArchetypeRegistry {\n\tregister(archetype: Archetype): void;\n\tget(id: string): Archetype | null;\n\tgetAll(): Archetype[];\n}\n\nexport function createArchetypeRegistry(archetypes: Archetype[] = []): ArchetypeRegistry {\n\tconst map = new Map<string, Archetype>();\n\tfor (const a of archetypes) map.set(a.id, a);\n\treturn {\n\t\tregister(a) {\n\t\t\tmap.set(a.id, a);\n\t\t},\n\t\tget(id) {\n\t\t\treturn map.get(id) ?? null;\n\t\t},\n\t\tgetAll() {\n\t\t\treturn [...map.values()];\n\t\t},\n\t};\n}\n","import type { ComponentType, EntityId, TagType, World } from '@jamesyong42/reactive-ecs';\nimport { MIN_WIDGET_SIZE } from './interaction-constants.js';\n\n// === Command Interface ===\n\nexport interface Command {\n\texecute(world: World): void;\n\tundo(world: World): void;\n}\n\n// === Command Buffer with Undo/Redo ===\n\nexport class CommandBuffer {\n\tprivate undoStack: Command[][] = [];\n\tprivate redoStack: Command[][] = [];\n\tprivate currentGroup: Command[] | null = null;\n\n\t/** Start grouping commands (e.g., on pointerdown). All commands until endGroup() are one undo step. */\n\tbeginGroup() {\n\t\tif (this.currentGroup !== null) {\n\t\t\tthis.endGroup(); // auto-close previous group\n\t\t}\n\t\tthis.currentGroup = [];\n\t}\n\n\t/** Execute a command and record it for undo. */\n\texecute(command: Command, world: World) {\n\t\tcommand.execute(world);\n\n\t\tif (this.currentGroup) {\n\t\t\tthis.currentGroup.push(command);\n\t\t} else {\n\t\t\t// Single command = its own undo group\n\t\t\tthis.undoStack.push([command]);\n\t\t\tthis.redoStack.length = 0;\n\t\t}\n\t}\n\n\t/** Close the current group — all commands since beginGroup() become one undo step. */\n\tendGroup() {\n\t\tif (this.currentGroup && this.currentGroup.length > 0) {\n\t\t\tthis.undoStack.push(this.currentGroup);\n\t\t\tthis.redoStack.length = 0;\n\t\t}\n\t\tthis.currentGroup = null;\n\t}\n\n\t/** Undo the last command group. */\n\tundo(world: World): boolean {\n\t\t// Close any open group first\n\t\tif (this.currentGroup) {\n\t\t\tthis.endGroup();\n\t\t}\n\n\t\tconst group = this.undoStack.pop();\n\t\tif (!group) return false;\n\n\t\t// Undo in reverse order\n\t\tfor (let i = group.length - 1; i >= 0; i--) {\n\t\t\tgroup[i].undo(world);\n\t\t}\n\t\tthis.redoStack.push(group);\n\t\treturn true;\n\t}\n\n\t/** Redo the last undone command group. */\n\tredo(world: World): boolean {\n\t\tconst group = this.redoStack.pop();\n\t\tif (!group) return false;\n\n\t\tfor (const cmd of group) {\n\t\t\tcmd.execute(world);\n\t\t}\n\t\tthis.undoStack.push(group);\n\t\treturn true;\n\t}\n\n\tcanUndo(): boolean {\n\t\treturn (\n\t\t\tthis.undoStack.length > 0 || (this.currentGroup !== null && this.currentGroup.length > 0)\n\t\t);\n\t}\n\n\tcanRedo(): boolean {\n\t\treturn this.redoStack.length > 0;\n\t}\n\n\tclear() {\n\t\tthis.undoStack.length = 0;\n\t\tthis.redoStack.length = 0;\n\t\tthis.currentGroup = null;\n\t}\n\n\tget undoSize(): number {\n\t\treturn this.undoStack.length;\n\t}\n\tget redoSize(): number {\n\t\treturn this.redoStack.length;\n\t}\n}\n\n// === Built-in Commands ===\n\nexport class MoveCommand implements Command {\n\tprivate beforePositions: Map<EntityId, { x: number; y: number }> = new Map();\n\tprivate afterPositions: Map<EntityId, { x: number; y: number }> = new Map();\n\tprivate captured = false;\n\n\tconstructor(\n\t\tprivate entityIds: EntityId[],\n\t\tprivate dx: number,\n\t\tprivate dy: number,\n\t\tprivate transformType: ComponentType<{ x: number; y: number }>,\n\t) {}\n\n\texecute(world: World) {\n\t\tif (!this.captured) {\n\t\t\t// First execute: snapshot before positions, compute after positions\n\t\t\tfor (const id of this.entityIds) {\n\t\t\t\tconst t = world.getComponent(id, this.transformType);\n\t\t\t\tif (t) {\n\t\t\t\t\tthis.beforePositions.set(id, { x: t.x, y: t.y });\n\t\t\t\t\tthis.afterPositions.set(id, { x: t.x + this.dx, y: t.y + this.dy });\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.captured = true;\n\t\t}\n\n\t\tfor (const [id, pos] of this.afterPositions) {\n\t\t\tworld.setComponent(id, this.transformType, { x: pos.x, y: pos.y });\n\t\t}\n\t}\n\n\tundo(world: World) {\n\t\tfor (const [id, pos] of this.beforePositions) {\n\t\t\tworld.setComponent(id, this.transformType, { x: pos.x, y: pos.y });\n\t\t}\n\t}\n}\n\nexport class ResizeCommand implements Command {\n\tconstructor(\n\t\tprivate entityId: EntityId,\n\t\tprivate before: { x: number; y: number; width: number; height: number },\n\t\tprivate after: { x: number; y: number; width: number; height: number },\n\t\tprivate transformType: ComponentType<{ x: number; y: number; width: number; height: number }>,\n\t) {\n\t\t// Enforce min-size so redo always produces valid bounds\n\t\tthis.after = {\n\t\t\t...after,\n\t\t\twidth: Math.max(MIN_WIDGET_SIZE, after.width),\n\t\t\theight: Math.max(MIN_WIDGET_SIZE, after.height),\n\t\t};\n\t}\n\n\texecute(world: World) {\n\t\tworld.setComponent(this.entityId, this.transformType, this.after);\n\t}\n\n\tundo(world: World) {\n\t\tworld.setComponent(this.entityId, this.transformType, this.before);\n\t}\n}\n\n/**\n * Snapshot of an entity's full component + tag state, suitable for\n * reconstruction via {@link rehydrateEntity} on undo.\n */\nexport interface EntitySnapshot {\n\tentityId: EntityId;\n\tcomponents: Array<{ type: ComponentType<unknown>; data: unknown }>;\n\ttags: TagType[];\n}\n\n/**\n * Capture an entity's complete current state. Used by `ConsumeCommand`\n * so `undo` can fully reconstitute a destroyed child. Relies on\n * `world.getComponentsOf(entity)` / `world.getTagsOf(entity)` so no\n * external type registries need to be threaded through.\n */\nexport function snapshotEntity(world: World, entity: EntityId): EntitySnapshot {\n\tconst components: EntitySnapshot['components'] = [];\n\tfor (const type of world.getComponentsOf(entity)) {\n\t\tconst data = world.getComponent(entity, type);\n\t\tif (data !== undefined) {\n\t\t\tcomponents.push({ type: type as ComponentType<unknown>, data: structuredClone(data) });\n\t\t}\n\t}\n\tconst tags = [...world.getTagsOf(entity)];\n\treturn { entityId: entity, components, tags };\n}\n\n/**\n * Recreate an entity's state from a snapshot. Uses the same\n * `EntityId` captured in the snapshot if the world allows\n * reassignment; otherwise creates a fresh id and returns it.\n */\nexport function rehydrateEntity(world: World, snapshot: EntitySnapshot): EntityId {\n\tconst id = world.createEntity();\n\tfor (const entry of snapshot.components) {\n\t\tworld.addComponent(id, entry.type, entry.data);\n\t}\n\tfor (const tag of snapshot.tags) {\n\t\tworld.addTag(id, tag);\n\t}\n\treturn id;\n}\n\n/**\n * Drop-to-consume command (RFC-004 § Phase 4). Undo / redo are\n * fully supported by:\n * - capturing a full entity snapshot of the child at construction time,\n * - delegating the forward mutation to the parent widget's\n * `applyMutation` handler,\n * - delegating the reverse mutation to `revertMutation`.\n *\n * Handlers are supplied at construction time (captured from the widget\n * registry in the interaction runtime's pointerup path), so the\n * command doesn't need to know about the registry shape itself.\n */\nexport class ConsumeCommand implements Command {\n\t/**\n\t * The entity id we currently target for destroy. Starts as the\n\t * initial `childId` captured at construction; updated to the fresh\n\t * id returned by `rehydrateEntity` on undo so that a subsequent\n\t * `redo()` destroys the rehydrated entity (not a stale id from a\n\t * previous execute cycle).\n\t */\n\tprivate currentChildId: EntityId;\n\n\tconstructor(\n\t\tpublic readonly parentId: EntityId,\n\t\tpublic readonly childId: EntityId,\n\t\tpublic readonly childSnapshot: EntitySnapshot,\n\t\tpublic readonly mutation: unknown,\n\t\tprivate readonly applyMutation: ((world: World, mutation: unknown) => void) | undefined,\n\t\tprivate readonly revertMutation: ((world: World, mutation: unknown) => void) | undefined,\n\t) {\n\t\tthis.currentChildId = childId;\n\t}\n\n\texecute(world: World) {\n\t\tthis.applyMutation?.(world, this.mutation);\n\t\t// No author-supplied mutation → default behaviour: destroy the\n\t\t// child. Simple \"trash bin\" widgets can rely on this without\n\t\t// writing a custom handler. Widgets that re-parent instead\n\t\t// (containers) implement `applyMutation` and must NOT destroy\n\t\t// the child inside it.\n\t\tif (this.applyMutation === undefined && world.entityExists(this.currentChildId)) {\n\t\t\tworld.destroyEntity(this.currentChildId);\n\t\t}\n\t}\n\n\tundo(world: World) {\n\t\tthis.revertMutation?.(world, this.mutation);\n\t\tif (!world.entityExists(this.currentChildId)) {\n\t\t\tthis.currentChildId = rehydrateEntity(world, this.childSnapshot);\n\t\t}\n\t}\n}\n\nexport class SetComponentCommand<T> implements Command {\n\tconstructor(\n\t\tprivate entityId: EntityId,\n\t\tprivate type: ComponentType<T>,\n\t\tprivate before: Partial<T>,\n\t\tprivate after: Partial<T>,\n\t) {}\n\n\texecute(world: World) {\n\t\tworld.setComponent(this.entityId, this.type, this.after);\n\t}\n\n\tundo(world: World) {\n\t\tworld.setComponent(this.entityId, this.type, this.before);\n\t}\n}\n","export interface Vec2 {\n\tx: number;\n\ty: number;\n}\n\nexport interface Rect {\n\tx: number;\n\ty: number;\n\twidth: number;\n\theight: number;\n}\n\nexport interface AABB {\n\tminX: number;\n\tminY: number;\n\tmaxX: number;\n\tmaxY: number;\n}\n\n/** Convert a Rect to AABB */\nexport function rectToAABB(r: Rect): AABB {\n\treturn {\n\t\tminX: r.x,\n\t\tminY: r.y,\n\t\tmaxX: r.x + r.width,\n\t\tmaxY: r.y + r.height,\n\t};\n}\n\n/** Convert AABB to Rect */\nexport function aabbToRect(a: AABB): Rect {\n\treturn {\n\t\tx: a.minX,\n\t\ty: a.minY,\n\t\twidth: a.maxX - a.minX,\n\t\theight: a.maxY - a.minY,\n\t};\n}\n\n/** Test if two AABBs overlap */\nexport function intersectsAABB(a: AABB, b: AABB): boolean {\n\treturn a.maxX >= b.minX && a.minX <= b.maxX && a.maxY >= b.minY && a.minY <= b.maxY;\n}\n\n/** Test if a point is inside an AABB */\nexport function pointInAABB(px: number, py: number, a: AABB): boolean {\n\treturn px >= a.minX && px <= a.maxX && py >= a.minY && py <= a.maxY;\n}\n\n/** Convert screen coordinates to world coordinates */\nexport function screenToWorld(\n\tscreenX: number,\n\tscreenY: number,\n\tcamera: { x: number; y: number; zoom: number },\n): Vec2 {\n\treturn {\n\t\tx: screenX / camera.zoom + camera.x,\n\t\ty: screenY / camera.zoom + camera.y,\n\t};\n}\n\n/** Convert world coordinates to screen coordinates */\nexport function worldToScreen(\n\tworldX: number,\n\tworldY: number,\n\tcamera: { x: number; y: number; zoom: number },\n): Vec2 {\n\treturn {\n\t\tx: (worldX - camera.x) * camera.zoom,\n\t\ty: (worldY - camera.y) * camera.zoom,\n\t};\n}\n\n/** Clamp a value between min and max */\nexport function clamp(value: number, min: number, max: number): number {\n\treturn Math.max(min, Math.min(max, value));\n}\n","import type { World } from '@jamesyong42/reactive-ecs';\nimport { defineSystem } from '@jamesyong42/reactive-ecs';\nimport { Transform2D, Visible, Widget, WidgetBreakpoint } from '../components.js';\nimport type { Breakpoint } from '../resources.js';\nimport { BreakpointConfigResource, CameraResource } from '../resources.js';\n\n/**\n * Compute breakpoints for visible widgets based on screen size.\n * Fix #10: Always update screenWidth/screenHeight even if breakpoint tier doesn't change.\n */\nexport const breakpointSystem = defineSystem({\n\tname: 'breakpoint',\n\tphase: 'derive',\n\tafter: 'cull',\n\texecute: (world: World) => {\n\t\tconst camera = world.getResource(CameraResource);\n\t\tconst config = world.getResource(BreakpointConfigResource);\n\n\t\tfor (const entity of world.query(Widget, Visible)) {\n\t\t\tconst transform = world.getComponent(entity, Transform2D);\n\t\t\tif (!transform) continue;\n\n\t\t\tconst screenWidth = transform.width * camera.zoom;\n\t\t\tconst screenHeight = transform.height * camera.zoom;\n\n\t\t\tlet bp: Breakpoint;\n\t\t\tif (screenWidth < config.micro) bp = 'micro';\n\t\t\telse if (screenWidth < config.compact) bp = 'compact';\n\t\t\telse if (screenWidth < config.normal) bp = 'normal';\n\t\t\telse if (screenWidth < config.expanded) bp = 'expanded';\n\t\t\telse bp = 'detailed';\n\n\t\t\tconst existing = world.getComponent(entity, WidgetBreakpoint);\n\t\t\tif (!existing) {\n\t\t\t\tworld.addComponent(entity, WidgetBreakpoint, {\n\t\t\t\t\tcurrent: bp,\n\t\t\t\t\tscreenWidth,\n\t\t\t\t\tscreenHeight,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t// Fix #10: Update if breakpoint tier changed OR screen dimensions changed significantly.\n\t\t\t\t// Compare rounded values to avoid floating-point instability at fractional zoom levels.\n\t\t\t\tconst bpChanged = existing.current !== bp;\n\t\t\t\tconst sizeChanged =\n\t\t\t\t\tMath.round(existing.screenWidth) !== Math.round(screenWidth) ||\n\t\t\t\t\tMath.round(existing.screenHeight) !== Math.round(screenHeight);\n\n\t\t\t\tif (bpChanged || sizeChanged) {\n\t\t\t\t\tworld.setComponent(entity, WidgetBreakpoint, {\n\t\t\t\t\t\tcurrent: bp,\n\t\t\t\t\t\tscreenWidth,\n\t\t\t\t\t\tscreenHeight,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n});\n","import type { World } from '@jamesyong42/reactive-ecs';\nimport { defineSystem } from '@jamesyong42/reactive-ecs';\nimport { Card, Transform2D } from '../components.js';\nimport { CardPresetsResource } from '../resources.js';\n\n/**\n * Stamp Transform2D width/height from Card.preset every tick. Manual\n * writes to Transform2D.width/height on a card entity get overwritten\n * — to change card size, update `Card.preset`. The spatial-index\n * observer fires reactively on the Transform2D write, so no ordering\n * constraint against other systems is needed.\n */\nexport const cardSystem = defineSystem({\n\tname: 'card',\n\tphase: 'derive',\n\texecute: (world: World) => {\n\t\tconst resource = world.getResource(CardPresetsResource);\n\t\tif (!resource) return;\n\t\tconst { presets } = resource;\n\n\t\tfor (const entity of world.query(Card, Transform2D)) {\n\t\t\tconst card = world.getComponent(entity, Card);\n\t\t\tconst transform = world.getComponent(entity, Transform2D);\n\t\t\tif (!card || !transform) continue;\n\t\t\tconst size = presets[card.preset];\n\t\t\tif (!size) continue;\n\t\t\tif (transform.width !== size.width || transform.height !== size.height) {\n\t\t\t\tworld.setComponent(entity, Transform2D, {\n\t\t\t\t\twidth: size.width,\n\t\t\t\t\theight: size.height,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t},\n});\n","import type { EntityId, World } from '@jamesyong42/reactive-ecs';\nimport { defineSystem } from '@jamesyong42/reactive-ecs';\nimport { Active, Culled, Transform2D, Visible } from '../components.js';\nimport { intersectsAABB, rectToAABB } from '../math.js';\nimport { CameraResource, SpatialIndexResource, ViewportResource } from '../resources.js';\n\n/**\n * Viewport culling — for every `Active` entity, sets exactly one of `Visible`\n * (intersects viewport+overscan) or `Culled` (outside it). Non-Active entities\n * carry neither tag.\n *\n * The `Culled` tag is consumed by render layers that want to keep cached state\n * without rendering — the R3F compositor (RFC-002) holds Culled widgets in its\n * Cold pool and skips ticks/paints for them.\n */\nexport const cullSystem = defineSystem({\n\tname: 'cull',\n\tphase: 'derive',\n\texecute: (world: World) => {\n\t\tconst camera = world.getResource(CameraResource);\n\t\tconst viewport = world.getResource(ViewportResource);\n\t\tif (viewport.width === 0 || viewport.height === 0) return;\n\n\t\tconst res = world.getResource(SpatialIndexResource);\n\t\tconst spatialIndex = res.instance;\n\n\t\tconst overscan = 200 / camera.zoom;\n\t\tconst vpWorldAABB = {\n\t\t\tminX: camera.x - overscan,\n\t\t\tminY: camera.y - overscan,\n\t\t\tmaxX: camera.x + viewport.width / camera.zoom + overscan,\n\t\t\tmaxY: camera.y + viewport.height / camera.zoom + overscan,\n\t\t};\n\n\t\t// Clear previous frame's tags before recomputing.\n\t\tfor (const entity of world.queryTagged(Visible)) world.removeTag(entity, Visible);\n\t\tfor (const entity of world.queryTagged(Culled)) world.removeTag(entity, Culled);\n\n\t\tconst visibleIds = new Set<EntityId>();\n\n\t\tif (spatialIndex && spatialIndex.size > 0) {\n\t\t\tconst candidates = spatialIndex.search(vpWorldAABB);\n\t\t\tfor (const entry of candidates) {\n\t\t\t\tif (world.hasTag(entry.entityId, Active)) {\n\t\t\t\t\tworld.addTag(entry.entityId, Visible);\n\t\t\t\t\tvisibleIds.add(entry.entityId);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tfor (const entity of world.queryTagged(Active)) {\n\t\t\t\tconst t = world.getComponent(entity, Transform2D);\n\t\t\t\tif (t && intersectsAABB(rectToAABB(t), vpWorldAABB)) {\n\t\t\t\t\tworld.addTag(entity, Visible);\n\t\t\t\t\tvisibleIds.add(entity);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Tag remaining Active entities as Culled to maintain the invariant.\n\t\tfor (const entity of world.queryTagged(Active)) {\n\t\t\tif (!visibleIds.has(entity)) world.addTag(entity, Culled);\n\t\t}\n\t},\n});\n","import type { World } from '@jamesyong42/reactive-ecs';\nimport { defineSystem } from '@jamesyong42/reactive-ecs';\nimport { Card, Dragging, Layer, PreDragLayer, Widget } from '../components.js';\n\n/**\n * Promotes a dragged DOM card to the 'overlay' layer so it visually pops above\n * its siblings; reverses on drag end. R3F cards opt out — the compositor\n * handles their stacking via `uDraggedRect` clip + renderOrder bump\n * (RFC-002), and a bare DOM widget without `Card` is a debug-style surface\n * that shouldn't acquire card-shaped affordances.\n *\n * Diff signal: presence of `PreDragLayer` is the \"currently promoted\" flag.\n * Dragging present, no PreDragLayer → promote (stash old layer, set overlay)\n * PreDragLayer present, no Dragging → restore (write back stashed layer)\n *\n * RFC-010 — runs in the `react` phase so the promote/restore is settled\n * before `derive`-phase systems (`cull`, `breakpoint`, `sort`) and the\n * `present`-phase visibility / frame-changes assembly run.\n */\nexport const dragPromoteSystem = defineSystem({\n\tname: 'dragPromote',\n\tphase: 'react',\n\texecute: (world: World) => {\n\t\tfor (const entity of world.queryTagged(Dragging)) {\n\t\t\tif (world.hasComponent(entity, PreDragLayer)) continue;\n\t\t\tif (!world.hasComponent(entity, Card)) continue;\n\t\t\tif (world.getComponent(entity, Widget)?.surface === 'webgl') continue;\n\t\t\tconst prev = world.getComponent(entity, Layer)?.name ?? 'base';\n\t\t\tworld.addComponent(entity, PreDragLayer, { name: prev });\n\t\t\tif (world.hasComponent(entity, Layer)) {\n\t\t\t\tworld.setComponent(entity, Layer, { name: 'overlay' });\n\t\t\t} else {\n\t\t\t\tworld.addComponent(entity, Layer, { name: 'overlay' });\n\t\t\t}\n\t\t}\n\n\t\tfor (const entity of world.query(PreDragLayer)) {\n\t\t\tif (world.hasTag(entity, Dragging)) continue;\n\t\t\tconst stash = world.getComponent(entity, PreDragLayer);\n\t\t\tif (!stash) continue;\n\t\t\tworld.setComponent(entity, Layer, { name: stash.name });\n\t\t\tworld.removeComponent(entity, PreDragLayer);\n\t\t}\n\t},\n});\n","import type { World } from '@jamesyong42/reactive-ecs';\nimport { defineSystem } from '@jamesyong42/reactive-ecs';\nimport { Active, ParentFrame, Transform2D } from '../components.js';\nimport { NavigationStackResource } from '../resources.js';\n\n/**\n * Reconcile `Active` for a single entity against the given nav frame.\n * Exported so the engine can wire a reactive `ParentFrame` observer\n * that keeps the consume / re-parent / undo paths in sync without\n * waiting for a nav-stack change (RFC-004 § Phase 5).\n */\nexport function reconcileEntityActive(world: World, entity: number): void {\n\tconst navStack = world.getResource(NavigationStackResource);\n\tconst activeContainer = navStack.frames[navStack.frames.length - 1].containerId;\n\tconst pf = world.getComponent(entity, ParentFrame);\n\tconst belongs = activeContainer === null ? pf === undefined : pf?.id === activeContainer;\n\tconst isActive = world.hasTag(entity, Active);\n\tif (belongs && !isActive) world.addTag(entity, Active);\n\telse if (!belongs && isActive) world.removeTag(entity, Active);\n}\n\n/**\n * Filter entities to the active navigation layer.\n * Runs on nav-stack changes (full refilter) and incrementally whenever new\n * Transform2D entities are added (so runtime spawns land in the active layer).\n *\n * Mid-session `ParentFrame` mutations (consume / undo) are handled out of\n * band by a reactive observer in the engine — see\n * {@link reconcileEntityActive}.\n */\nexport const navigationFilterSystem = defineSystem({\n\tname: 'navigationFilter',\n\tphase: 'control',\n\texecute: (world: World) => {\n\t\tconst navStack = world.getResource(NavigationStackResource);\n\t\tconst stackChanged = navStack.changed;\n\t\tconst newEntities = world.queryAdded(Transform2D);\n\t\tif (!stackChanged && newEntities.length === 0) return;\n\n\t\tconst currentFrame = navStack.frames[navStack.frames.length - 1];\n\t\tconst activeContainer = currentFrame.containerId;\n\n\t\tconst belongsToCurrentFrame = (entity: number): boolean => {\n\t\t\tif (activeContainer === null) return !world.hasComponent(entity, ParentFrame);\n\t\t\treturn world.getComponent(entity, ParentFrame)?.id === activeContainer;\n\t\t};\n\n\t\tif (stackChanged) {\n\t\t\tfor (const entity of world.queryTagged(Active)) {\n\t\t\t\tworld.removeTag(entity, Active);\n\t\t\t}\n\t\t\tfor (const entity of world.query(Transform2D)) {\n\t\t\t\tif (belongsToCurrentFrame(entity)) world.addTag(entity, Active);\n\t\t\t}\n\t\t\t// Direct mutation is intentional: `navStack.changed` is a side-\n\t\t\t// channel flag. `engine.tick()` captures its value into a local\n\t\t\t// `const` BEFORE `scheduler.execute()` runs (see the INVARIANT\n\t\t\t// comment there) — this reset clears the flag for the NEXT tick\n\t\t\t// without affecting this tick's `FrameChanges.navigationChanged`\n\t\t\t// signal. Do not switch to `setResource` here; it would trigger\n\t\t\t// unnecessary change bookkeeping on a hot path.\n\t\t\tnavStack.changed = false;\n\t\t} else {\n\t\t\tfor (const entity of newEntities) {\n\t\t\t\tif (belongsToCurrentFrame(entity) && !world.hasTag(entity, Active)) {\n\t\t\t\t\tworld.addTag(entity, Active);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n});\n","import type { World } from '@jamesyong42/reactive-ecs';\nimport { defineSystem } from '@jamesyong42/reactive-ecs';\n\n/**\n * Sort visible entities by z-index (handled in engine.tick()).\n */\nexport const sortSystem = defineSystem({\n\tname: 'sort',\n\tphase: 'derive',\n\tafter: 'breakpoint',\n\texecute: (_world: World) => {\n\t\t// Sorting is done in engine.tick() after systems run\n\t},\n});\n","import type { World } from '@jamesyong42/reactive-ecs';\nimport { defineSystem } from '@jamesyong42/reactive-ecs';\nimport { Transform2D, TransformTween, type TweenEasing } from '../components.js';\n\n/**\n * Apply an easing curve to a linear progress value in `[0, 1]`.\n *\n * - `linear` — no curve (`p`).\n * - `ease-out` — cubic ease-out (`1 - (1-p)^3`), default for fly-back.\n * - `ease-in-out` — cubic ease-in-out; symmetric accelerate/decelerate.\n * - `spring` — not yet implemented; falls back to `ease-out` for now.\n *\n * Input is clamped to `[0, 1]`; callers are expected to pass the tween's\n * `elapsed / durationMs` before clamping themselves.\n */\nexport function applyEasing(p: number, easing: TweenEasing): number {\n\tconst t = p < 0 ? 0 : p > 1 ? 1 : p;\n\tswitch (easing) {\n\t\tcase 'linear':\n\t\t\treturn t;\n\t\tcase 'ease-in-out':\n\t\t\treturn t < 0.5 ? 4 * t * t * t : 1 - (-2 * t + 2) ** 3 / 2;\n\t\tcase 'ease-out':\n\t\tcase 'spring':\n\t\t\t// spring stub — honest ease-out until we actually spec spring's\n\t\t\t// stiffness/damping defaults (RFC-004 § Phase 2 open question).\n\t\t\treturn 1 - (1 - t) ** 3;\n\t}\n}\n\n/**\n * Advance every active `TransformTween`, write the interpolated\n * position back to the entity's `Transform2D`, and remove the tween\n * component on completion (RFC-004 § Phase 2).\n *\n * No scheduler ordering constraint — the spatial-index observer fires\n * reactively on every `Transform2D` change, so downstream consumers\n * see the animated values within the same tick regardless of system\n * order.\n */\nexport const transformTweenSystem = defineSystem({\n\tname: 'transformTween',\n\tphase: 'simulate',\n\texecute: (world: World) => {\n\t\tconst nowMs = typeof performance !== 'undefined' ? performance.now() : Date.now();\n\t\tfor (const entity of world.query(TransformTween)) {\n\t\t\tconst t = world.getComponent(entity, TransformTween);\n\t\t\tconst x2d = world.getComponent(entity, Transform2D);\n\t\t\tif (!t) continue;\n\t\t\tif (!x2d) {\n\t\t\t\t// Nothing to animate into — tween is orphaned.\n\t\t\t\tworld.removeComponent(entity, TransformTween);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst elapsed = nowMs - t.startMs;\n\t\t\t// `durationMs === 0` snaps immediately on the first tick because\n\t\t\t// `elapsed >= 0` always holds. No NaN from the divide-below path\n\t\t\t// can slip through.\n\t\t\tif (elapsed >= t.durationMs) {\n\t\t\t\t// Snap to destination and remove the component. Merging via\n\t\t\t\t// partial setComponent preserves width / height / rotation.\n\t\t\t\tworld.setComponent(entity, Transform2D, { x: t.toX, y: t.toY });\n\t\t\t\tworld.removeComponent(entity, TransformTween);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst p = applyEasing(elapsed / t.durationMs, t.easing);\n\t\t\tworld.setComponent(entity, Transform2D, {\n\t\t\t\tx: t.fromX + (t.toX - t.fromX) * p,\n\t\t\t\ty: t.fromY + (t.toY - t.fromY) * p,\n\t\t\t});\n\t\t}\n\t},\n});\n","import type { EntityId, World } from '@jamesyong42/reactive-ecs';\nimport type { CommandBuffer, EntitySnapshot } from '../commands.js';\nimport { ConsumeCommand, MoveCommand, ResizeCommand, snapshotEntity } from '../commands.js';\nimport type { CSSCursor, InteractionRoleData, ResizeHandlePos } from '../components.js';\nimport {\n\tActive,\n\tCard,\n\tCardOverlapHotPoint,\n\tCursorHint,\n\tDraggable,\n\tDragging,\n\tInteractionRole,\n\tOverlapCandidate,\n\tOverlapTarget,\n\tResizable,\n\tSelectable,\n\tSelected,\n\tSnapSource,\n\tSnapTarget,\n\tTransform2D,\n\tTransformTween,\n\tWidget,\n\tZIndex,\n} from '../components.js';\nimport { DEAD_ZONE_MOUSE_PX, MIN_WIDGET_SIZE } from '../interaction-constants.js';\nimport { screenToWorld } from '../math.js';\nimport { CameraResource, CursorResource } from '../resources.js';\nimport type { SpatialIndex } from '../spatial/SpatialIndex.js';\nimport type { SnapResult } from '../spatial/snap.js';\nimport { computeSnapGuides } from '../spatial/snap.js';\nimport type { Modifiers, PointerDirective } from './types.js';\n\n/**\n * Hit-zone size for resize hotspots (full width, screen px). Deliberately\n * larger than the visual handle size to give a generous clickable area.\n * Do not reduce without a UX test.\n *\n * Private to `interaction.ts` post-RFC-005 — handle hotspots are not\n * separate ECS entities, so this constant has no other consumer.\n */\nconst HANDLE_HIT_SIZE_PX = 16;\n\ntype RectLike = {\n\tx: number;\n\ty: number;\n\twidth: number;\n\theight: number;\n};\n\n/**\n * Return the resize-handle hotspot a world-space point falls inside,\n * if any. Corners are tested before edges so they win when hit zones\n * overlap — this replicates today's `layer: 15` (corner) vs\n * `layer: 10` (edge) priority encoded on handle entities.\n *\n * `zoom` converts the screen-pixel hit size to world units so the\n * hotspot stays visually constant across zoom levels.\n */\nexport function detectResizeHandle(\n\tworldX: number,\n\tworldY: number,\n\trect: RectLike,\n\tzoom: number,\n): ResizeHandlePos | null {\n\tconst S = HANDLE_HIT_SIZE_PX / zoom;\n\tconst half = S / 2;\n\tconst xL = rect.x;\n\tconst xR = rect.x + rect.width;\n\tconst yT = rect.y;\n\tconst yB = rect.y + rect.height;\n\n\tconst corners: Array<{ pos: ResizeHandlePos; cx: number; cy: number }> = [\n\t\t{ pos: 'nw', cx: xL, cy: yT },\n\t\t{ pos: 'ne', cx: xR, cy: yT },\n\t\t{ pos: 'sw', cx: xL, cy: yB },\n\t\t{ pos: 'se', cx: xR, cy: yB },\n\t];\n\tfor (const c of corners) {\n\t\tif (\n\t\t\tworldX >= c.cx - half &&\n\t\t\tworldX <= c.cx + half &&\n\t\t\tworldY >= c.cy - half &&\n\t\t\tworldY <= c.cy + half\n\t\t) {\n\t\t\treturn c.pos;\n\t\t}\n\t}\n\n\tconst edges: Array<{ pos: ResizeHandlePos; cx: number; cy: number }> = [\n\t\t{ pos: 'n', cx: (xL + xR) / 2, cy: yT },\n\t\t{ pos: 's', cx: (xL + xR) / 2, cy: yB },\n\t\t{ pos: 'w', cx: xL, cy: (yT + yB) / 2 },\n\t\t{ pos: 'e', cx: xR, cy: (yT + yB) / 2 },\n\t];\n\tfor (const e of edges) {\n\t\tif (\n\t\t\tworldX >= e.cx - half &&\n\t\t\tworldX <= e.cx + half &&\n\t\t\tworldY >= e.cy - half &&\n\t\t\tworldY <= e.cy + half\n\t\t) {\n\t\t\treturn e.pos;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * Inline resize-handle hit test (RFC-005).\n *\n * Returns a `{ entityId: widgetId, role: resize-with-handle-pos }`\n * result when the pointer falls inside one of the 8 hotspots around\n * the single selected `Resizable` widget. Gated on exactly-one\n * selected Resizable so that multi-select drag doesn't accidentally\n * latch onto a resize hotspot — matches the historical\n * handle-spawning rule.\n */\nfunction findInlineResizeHit(\n\tworld: World,\n\tworldX: number,\n\tworldY: number,\n\tzoom: number,\n): { entityId: EntityId; role: InteractionRoleData } | null {\n\tlet selected: EntityId | null = null;\n\tlet count = 0;\n\tfor (const e of world.queryTagged(Resizable)) {\n\t\tif (world.hasTag(e, Selected)) {\n\t\t\tselected = e;\n\t\t\tif (++count > 1) return null;\n\t\t}\n\t}\n\tif (!selected) return null;\n\n\tconst t = world.getComponent(selected, Transform2D);\n\tif (!t) return null;\n\n\tconst handle = detectResizeHandle(worldX, worldY, t, zoom);\n\tif (!handle) return null;\n\n\treturn {\n\t\tentityId: selected,\n\t\trole: { layer: 15, role: { type: 'resize', handle } },\n\t};\n}\n\n/**\n * Map a resize-handle position to the CSS cursor value. Used by the\n * cursor system in place of the per-handle-entity `CursorHint` reads\n * the old model used.\n */\nfunction cursorForHandle(handle: ResizeHandlePos): CSSCursor {\n\treturn `${handle}-resize` as CSSCursor;\n}\n\ntype InputState =\n\t| { mode: 'idle' }\n\t| { mode: 'tracking'; entityId: EntityId; startScreenX: number; startScreenY: number }\n\t| {\n\t\t\tmode: 'dragging';\n\t\t\tentityId: EntityId;\n\t\t\tstartWorldX: number;\n\t\t\tstartWorldY: number;\n\t\t\tstartPositions: Map<EntityId, { x: number; y: number }>;\n\t\t\toriginalZIndices: Map<EntityId, number>;\n\t }\n\t| {\n\t\t\tmode: 'resizing';\n\t\t\tentityId: EntityId;\n\t\t\thandle: ResizeHandlePos;\n\t\t\tstartWorldX: number;\n\t\t\tstartWorldY: number;\n\t\t\tstartBounds: { x: number; y: number; width: number; height: number };\n\t }\n\t| {\n\t\t\t/**\n\t\t\t * RFC-004 § Phase 4 — the card is animating back to its\n\t\t\t * pre-drag position after a mismatched drop. `Dragging` stays\n\t\t\t * set for the duration so layer / ZIndex / compositor\n\t\t\t * drag-promote state is preserved. Completion poll in\n\t\t\t * `tickFrame()` watches for `TransformTween` removal to\n\t\t\t * transition to idle.\n\t\t\t */\n\t\t\tmode: 'flyingBack';\n\t\t\tentityId: EntityId;\n\t\t\tstartPositions: Map<EntityId, { x: number; y: number }>;\n\t\t\toriginalZIndices: Map<EntityId, number>;\n\t }\n\t| { mode: 'marquee'; startWorldX: number; startWorldY: number };\n\nexport interface InteractionContext {\n\tworld: World;\n\tspatialIndex: SpatialIndex;\n\tcommandBuffer: CommandBuffer;\n\t/** Called whenever something that requires a re-tick mutates. */\n\tmarkDirty: () => void;\n\t/** Called whenever the selection set changes so the frame runner can flag it. */\n\tnotifySelectionChanged: () => void;\n\t/** Snap configuration accessors — held by the engine so toggles at runtime take effect. */\n\tgetSnapEnabled: () => boolean;\n\tgetSnapThreshold: () => number;\n\t/**\n\t * Resolve a widget type's registered interaction handlers (RFC-004\n\t * § Phase 1). Used by the overlap pass to call the optional\n\t * `canAccept` gate before flagging a card as `OverlapTarget`.\n\t * Returns `undefined` when the widget type has no handlers.\n\t */\n\tgetWidgetInteraction?: (\n\t\ttype: string,\n\t) => import('./widget-binding.js').WidgetInteractionHandlers | undefined;\n}\n\n/**\n * The pointer state machine, hit testing, selection logic, and the\n * root-container cursor resolution.\n *\n * Kept as one cohesive unit because every branch of the state machine needs\n * access to the same closed-over state (inputState, hoveredEntity, snap\n * result). Splitting further would require threading state refs through\n * every callee, which hurts readability more than it helps.\n */\nexport function createInteractionRuntime(ctx: InteractionContext) {\n\tconst { world, spatialIndex, commandBuffer, markDirty, notifySelectionChanged } = ctx;\n\n\tlet inputState: InputState = { mode: 'idle' };\n\tlet hoveredEntity: EntityId | null = null;\n\t/**\n\t * Cached handle position the pointer is currently over, iff the\n\t * hovered entity is the selected `Resizable` widget. Updated by the\n\t * idle-branch hover path in `handlePointerMove`; read by\n\t * `runCursorSystem` to pick the right directional cursor without\n\t * consulting a handle entity's `CursorHint` (RFC-005).\n\t */\n\tlet hoveredHandle: ResizeHandlePos | null = null;\n\tlet currentSnap: SnapResult = { snapDx: 0, snapDy: 0, guides: [], spacings: [] };\n\n\t// RFC-004 § Phase 3 — card overlap state. Populated while a Card-tagged\n\t// entity is being dragged; cleared on drag end (commit, fly-back, or\n\t// cancel). All three collections are mirrored into ECS tags/components\n\t// for rendering layers to read; these locals let us diff cheaply.\n\tlet overlapCandidates = new Set<EntityId>();\n\tlet overlapTarget: EntityId | null = null;\n\n\tfunction hitTest(\n\t\tscreenX: number,\n\t\tscreenY: number,\n\t): { entityId: EntityId; role: InteractionRoleData } | null {\n\t\tconst camera = world.getResource(CameraResource);\n\t\tconst worldPos = screenToWorld(screenX, screenY, camera);\n\n\t\t// Resize hotspots take priority — corner/edge hits live on the\n\t\t// selected Resizable widget directly (no sub-entity handles).\n\t\tconst inlineHit = findInlineResizeHit(world, worldPos.x, worldPos.y, camera.zoom);\n\t\tif (inlineHit) return inlineHit;\n\n\t\t// Zero-tolerance point query: RBush returns only entries whose AABB\n\t\t// strictly contains the point, so no secondary pointInAABB check is\n\t\t// needed. Resize hit slop is handled by `detectResizeHandle` above;\n\t\t// widget-body hits use the widget's own AABB directly.\n\t\tconst candidates = spatialIndex.searchPoint(worldPos.x, worldPos.y, 0);\n\n\t\ttype Candidate = { entityId: EntityId; role: InteractionRoleData };\n\t\tconst interactable: Candidate[] = [];\n\t\tfor (const c of candidates) {\n\t\t\tif (!world.hasTag(c.entityId, Active)) continue;\n\t\t\tconst role = world.getComponent(c.entityId, InteractionRole);\n\t\t\tif (!role) continue;\n\t\t\tinteractable.push({ entityId: c.entityId, role });\n\t\t}\n\t\tif (interactable.length === 0) return null;\n\n\t\tinteractable.sort((a, b) => {\n\t\t\tif (b.role.layer !== a.role.layer) return b.role.layer - a.role.layer;\n\t\t\tconst zA = world.getComponent(a.entityId, ZIndex)?.value ?? 0;\n\t\t\tconst zB = world.getComponent(b.entityId, ZIndex)?.value ?? 0;\n\t\t\treturn zB - zA;\n\t\t});\n\n\t\treturn interactable[0];\n\t}\n\n\tfunction selectEntity(entity: EntityId, additive: boolean) {\n\t\tif (!world.hasTag(entity, Selectable)) return;\n\n\t\tif (additive) {\n\t\t\tif (world.hasTag(entity, Selected)) {\n\t\t\t\tworld.removeTag(entity, Selected);\n\t\t\t} else {\n\t\t\t\tworld.addTag(entity, Selected);\n\t\t\t}\n\t\t} else {\n\t\t\tfor (const e of world.queryTagged(Selected)) {\n\t\t\t\tif (e !== entity) world.removeTag(e, Selected);\n\t\t\t}\n\t\t\tworld.addTag(entity, Selected);\n\t\t}\n\t\tnotifySelectionChanged();\n\t}\n\n\tfunction clearSelection() {\n\t\tconst selected = world.queryTagged(Selected);\n\t\tif (selected.length > 0) {\n\t\t\tfor (const e of selected) {\n\t\t\t\tworld.removeTag(e, Selected);\n\t\t\t}\n\t\t\tnotifySelectionChanged();\n\t\t}\n\t}\n\n\t/**\n\t * RFC-004 § Phase 3 — contract match between a dragged card (child)\n\t * and a candidate parent. Returns true iff their `provides` /\n\t * `accepts` arrays intersect AND the optional `canAccept` gate on\n\t * the parent's widget type returns truthy.\n\t */\n\tfunction contractsMatch(childId: EntityId, parentId: EntityId): boolean {\n\t\tconst childCard = world.getComponent(childId, Card);\n\t\tconst parentCard = world.getComponent(parentId, Card);\n\t\tif (!childCard || !parentCard) return false;\n\t\tif (childCard.provides.length === 0 || parentCard.accepts.length === 0) return false;\n\t\tlet intersects = false;\n\t\tfor (const p of childCard.provides) {\n\t\t\tif (parentCard.accepts.includes(p)) {\n\t\t\t\tintersects = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!intersects) return false;\n\t\tconst gate = ctx.getWidgetInteraction?.(\n\t\t\tworld.getComponent(parentId, Widget)?.type ?? '',\n\t\t)?.canAccept;\n\t\tif (!gate) return true;\n\t\treturn gate({ parent: parentId, child: childId, world });\n\t}\n\n\t/**\n\t * RFC-004 § Phase 3 — the overlap detection pass.\n\t *\n\t * Called from `handlePointerMove` whenever a Card-tagged entity is\n\t * being dragged. Produces three pieces of visible state:\n\t *\n\t * - `OverlapCandidate` tag + `CardOverlapHotPoint` component on every\n\t * other card whose AABB intersects the dragged card's AABB.\n\t * `CardOverlapHotPoint.{x,y}` are the intersection centroid in the\n\t * overlapped card's local (0..1) frame. Layer 1 of the visual state.\n\t *\n\t * - `OverlapTarget` tag on at most one card — the closest by centre\n\t * distance — iff contracts match and any `canAccept` gate passes.\n\t * Layer 2.\n\t *\n\t * `strength` is set to 1 on entry and 0 on exit; CSS / shader\n\t * consumers own the actual fade transition (opacity transition at\n\t * the rendering layer). Keeps the ECS pass cheap and stateless.\n\t */\n\tfunction updateCardOverlap(draggedId: EntityId): void {\n\t\tif (!world.hasComponent(draggedId, Card)) {\n\t\t\tclearOverlapState();\n\t\t\treturn;\n\t\t}\n\t\tconst draggedT = world.getComponent(draggedId, Transform2D);\n\t\tif (!draggedT) {\n\t\t\tclearOverlapState();\n\t\t\treturn;\n\t\t}\n\t\tconst dxMin = draggedT.x;\n\t\tconst dyMin = draggedT.y;\n\t\tconst dxMax = draggedT.x + draggedT.width;\n\t\tconst dyMax = draggedT.y + draggedT.height;\n\t\tconst dCenterX = draggedT.x + draggedT.width / 2;\n\t\tconst dCenterY = draggedT.y + draggedT.height / 2;\n\n\t\t// Gather Card entities whose AABB intersects the dragged rect.\n\t\t// Filter to `Active` so consumed children (which still occupy a\n\t\t// spatial-index slot at their drop-world coords) don't register as\n\t\t// overlap candidates at their parent's frame (RFC-004 § Phase 5).\n\t\tconst next = new Set<EntityId>();\n\t\tconst hits = spatialIndex.search({\n\t\t\tminX: dxMin,\n\t\t\tminY: dyMin,\n\t\t\tmaxX: dxMax,\n\t\t\tmaxY: dyMax,\n\t\t});\n\t\tfor (const entry of hits) {\n\t\t\tif (entry.entityId === draggedId) continue;\n\t\t\tif (!world.hasComponent(entry.entityId, Card)) continue;\n\t\t\tif (!world.hasTag(entry.entityId, Active)) continue;\n\t\t\tnext.add(entry.entityId);\n\t\t}\n\n\t\t// Exit: tags + hot-point component come off cards no longer overlapping.\n\t\tfor (const prev of overlapCandidates) {\n\t\t\tif (!next.has(prev)) {\n\t\t\t\tworld.removeTag(prev, OverlapCandidate);\n\t\t\t\tworld.removeComponent(prev, CardOverlapHotPoint);\n\t\t\t}\n\t\t}\n\t\t// Enter: add tag + default hot-point on new candidates. Use\n\t\t// addComponent so reactive-ecs registers the component up front;\n\t\t// the hot-point write loop below then freely `setComponent` to\n\t\t// update it every move.\n\t\tfor (const c of next) {\n\t\t\tif (!overlapCandidates.has(c)) {\n\t\t\t\tworld.addTag(c, OverlapCandidate);\n\t\t\t\tworld.addComponent(c, CardOverlapHotPoint, { x: 0.5, y: 0.5, strength: 0 });\n\t\t\t}\n\t\t}\n\n\t\t// Hot-point write + primary selection.\n\t\tlet primary: EntityId | null = null;\n\t\tlet bestDist = Number.POSITIVE_INFINITY;\n\t\tlet bestZ = Number.NEGATIVE_INFINITY;\n\t\tlet bestId = Number.POSITIVE_INFINITY;\n\t\tfor (const c of next) {\n\t\t\tconst ct = world.getComponent(c, Transform2D);\n\t\t\tif (!ct) continue;\n\t\t\tconst cxMin = ct.x;\n\t\t\tconst cyMin = ct.y;\n\t\t\tconst cxMax = ct.x + ct.width;\n\t\t\tconst cyMax = ct.y + ct.height;\n\n\t\t\t// Intersection centroid → normalized local coords within `c`.\n\t\t\tconst ix = (Math.max(dxMin, cxMin) + Math.min(dxMax, cxMax)) / 2;\n\t\t\tconst iy = (Math.max(dyMin, cyMin) + Math.min(dyMax, cyMax)) / 2;\n\t\t\tconst hotX = ct.width > 0 ? (ix - ct.x) / ct.width : 0.5;\n\t\t\tconst hotY = ct.height > 0 ? (iy - ct.y) / ct.height : 0.5;\n\t\t\tworld.setComponent(c, CardOverlapHotPoint, {\n\t\t\t\tx: hotX < 0 ? 0 : hotX > 1 ? 1 : hotX,\n\t\t\t\ty: hotY < 0 ? 0 : hotY > 1 ? 1 : hotY,\n\t\t\t\tstrength: 1,\n\t\t\t});\n\n\t\t\t// Closest centre distance (RFC-004 § primary selection). Tie-break:\n\t\t\t// ZIndex desc, then entity id asc for determinism.\n\t\t\tconst ccx = ct.x + ct.width / 2;\n\t\t\tconst ccy = ct.y + ct.height / 2;\n\t\t\tconst d = Math.hypot(ccx - dCenterX, ccy - dCenterY);\n\t\t\tconst z = world.getComponent(c, ZIndex)?.value ?? 0;\n\t\t\tif (\n\t\t\t\td < bestDist ||\n\t\t\t\t(d === bestDist && z > bestZ) ||\n\t\t\t\t(d === bestDist && z === bestZ && c < bestId)\n\t\t\t) {\n\t\t\t\tbestDist = d;\n\t\t\t\tbestZ = z;\n\t\t\t\tbestId = c;\n\t\t\t\tprimary = c;\n\t\t\t}\n\t\t}\n\n\t\toverlapCandidates = next;\n\n\t\t// Reconcile OverlapTarget based on primary + contract match.\n\t\tconst match = primary !== null && contractsMatch(draggedId, primary);\n\t\tconst nextTarget = match ? primary : null;\n\t\tif (nextTarget !== overlapTarget) {\n\t\t\tif (overlapTarget !== null) world.removeTag(overlapTarget, OverlapTarget);\n\t\t\tif (nextTarget !== null) world.addTag(nextTarget, OverlapTarget);\n\t\t\toverlapTarget = nextTarget;\n\t\t}\n\t}\n\n\t/**\n\t * RFC-004 § Phase 3 — tear down all overlap state. Called on drag\n\t * end (commit / cancel) and when the dragged entity stops being a\n\t * Card (e.g. a non-card entity enters the drag state machine).\n\t */\n\tfunction clearOverlapState(): void {\n\t\tfor (const c of overlapCandidates) {\n\t\t\tworld.removeTag(c, OverlapCandidate);\n\t\t\tworld.removeComponent(c, CardOverlapHotPoint);\n\t\t}\n\t\tif (overlapTarget !== null) {\n\t\t\tworld.removeTag(overlapTarget, OverlapTarget);\n\t\t}\n\t\toverlapCandidates = new Set();\n\t\toverlapTarget = null;\n\t}\n\n\t/**\n\t * RFC-004 § Phase 4 — fly-back completion poll. Called by the engine's\n\t * frame runner after `scheduler.execute(world)` each tick. The tween\n\t * system runs first, interpolates `Transform2D` toward the starting\n\t * position, and auto-removes its `TransformTween` component on\n\t * completion. When we see the tween component gone from the primary\n\t * flying-back entity, the animation is done: remove `Dragging`,\n\t * restore `ZIndex`, transition to idle.\n\t */\n\tfunction runFlyBackSystem(): void {\n\t\tif (inputState.mode !== 'flyingBack') return;\n\n\t\t// If the primary entity was destroyed mid-animation (external\n\t\t// destroyEntity call), we can't query its tween component — bail\n\t\t// to idle with best-effort cleanup of whatever siblings survive.\n\t\tconst primaryAlive = world.entityExists(inputState.entityId);\n\n\t\t// Still animating — the primary's tween is live.\n\t\tif (primaryAlive && world.hasComponent(inputState.entityId, TransformTween)) return;\n\n\t\tfor (const e of inputState.startPositions.keys()) {\n\t\t\tif (!world.entityExists(e)) continue;\n\t\t\tif (world.hasTag(e, Dragging)) world.removeTag(e, Dragging);\n\t\t}\n\t\tfor (const [entity, originalZ] of inputState.originalZIndices) {\n\t\t\tif (!world.entityExists(entity)) continue;\n\t\t\tworld.setComponent(entity, ZIndex, { value: originalZ });\n\t\t}\n\t\tinputState = { mode: 'idle' };\n\t\tmarkDirty();\n\t}\n\n\t/**\n\t * Derive the root-container cursor from input state + hover.\n\t * Writes to CursorResource. Called from the frame runner after systems.\n\t */\n\tfunction runCursorSystem(): void {\n\t\tlet cursor: CSSCursor = 'default';\n\n\t\tswitch (inputState.mode) {\n\t\t\tcase 'idle':\n\t\t\tcase 'marquee': {\n\t\t\t\t// RFC-005: resize hover wins over widget-body hover so the\n\t\t\t\t// directional cursor is visible at the handle hotspots.\n\t\t\t\tif (hoveredHandle !== null) {\n\t\t\t\t\tcursor = cursorForHandle(hoveredHandle);\n\t\t\t\t} else if (hoveredEntity !== null) {\n\t\t\t\t\tcursor = world.getComponent(hoveredEntity, CursorHint)?.hover ?? 'default';\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'tracking': {\n\t\t\t\tcursor = world.getComponent(inputState.entityId, CursorHint)?.hover ?? 'default';\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'dragging': {\n\t\t\t\tcursor = world.getComponent(inputState.entityId, CursorHint)?.active ?? 'grabbing';\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'resizing': {\n\t\t\t\tcursor = cursorForHandle(inputState.handle);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tworld.setResource(CursorResource, { cursor });\n\t}\n\n\t// ------------------------------------------------------------------\n\t// RFC-008 Phase 3b — internal helpers operating in world coordinates.\n\t// Both legacy `handlePointer*` entry points and the new public\n\t// `beginDrag` / `beginResize` / `beginMarquee` API funnel through these\n\t// so the state machine has one implementation per branch.\n\t// ------------------------------------------------------------------\n\n\t/**\n\t * Transition to `dragging` mode. Snapshots ZIndex + Transform2D for every\n\t * `Selected` entity, elevates them to `maxZ + 1`, tags `Dragging`, opens a\n\t * command group. Caller is responsible for `Selected` set being correct.\n\t */\n\tfunction _beginDrag(entity: EntityId, startWorldX: number, startWorldY: number): void {\n\t\tconst originalZIndices = new Map<EntityId, number>();\n\t\tlet maxZ = 0;\n\t\tfor (const e of world.queryTagged(Active)) {\n\t\t\tconst z = world.getComponent(e, ZIndex);\n\t\t\tif (z && z.value > maxZ) maxZ = z.value;\n\t\t}\n\t\tfor (const e of world.queryTagged(Selected)) {\n\t\t\tconst z = world.getComponent(e, ZIndex);\n\t\t\toriginalZIndices.set(e, z?.value ?? 0);\n\t\t\tworld.setComponent(e, ZIndex, { value: maxZ + 1 });\n\t\t}\n\n\t\tconst startPositions = new Map<EntityId, { x: number; y: number }>();\n\t\tfor (const e of world.queryTagged(Selected)) {\n\t\t\tconst t = world.getComponent(e, Transform2D);\n\t\t\tif (t) startPositions.set(e, { x: t.x, y: t.y });\n\t\t}\n\t\tfor (const e of startPositions.keys()) {\n\t\t\tworld.addTag(e, Dragging);\n\t\t}\n\n\t\tcommandBuffer.beginGroup();\n\t\tinputState = {\n\t\t\tmode: 'dragging',\n\t\t\tentityId: entity,\n\t\t\tstartWorldX,\n\t\t\tstartWorldY,\n\t\t\tstartPositions,\n\t\t\toriginalZIndices,\n\t\t};\n\t\tmarkDirty();\n\t}\n\n\t/** Apply drag math + snap + overlap update for the current cursor world position. */\n\tfunction _updateDrag(worldX: number, worldY: number): void {\n\t\tif (inputState.mode !== 'dragging') return;\n\t\tconst camera = world.getResource(CameraResource);\n\t\tconst totalDx = worldX - inputState.startWorldX;\n\t\tconst totalDy = worldY - inputState.startWorldY;\n\n\t\t// Snap math runs only when:\n\t\t// - the engine has snap globally enabled, AND\n\t\t// - the primary dragged entity carries `SnapSource` (the\n\t\t// leader's geometry drives the calculation; followers in a\n\t\t// multi-select drag inherit the same correction).\n\t\t// References are restricted to `SnapTarget` entities, so a\n\t\t// widget can serve as a snap reference without ever snapping\n\t\t// itself (the asymmetry cards rely on).\n\t\tconst firstId = inputState.startPositions.keys().next().value as EntityId | undefined;\n\t\tif (ctx.getSnapEnabled() && firstId !== undefined && world.hasTag(firstId, SnapSource)) {\n\t\t\tconst draggedIds = new Set(inputState.startPositions.keys());\n\t\t\tconst firstStart = inputState.startPositions.get(firstId);\n\t\t\tconst firstT = world.getComponent(firstId, Transform2D);\n\t\t\tif (firstT && firstStart) {\n\t\t\t\tconst draggedBounds = {\n\t\t\t\t\tx: firstStart.x + totalDx,\n\t\t\t\t\ty: firstStart.y + totalDy,\n\t\t\t\t\twidth: firstT.width,\n\t\t\t\t\theight: firstT.height,\n\t\t\t\t};\n\n\t\t\t\tconst refs = [];\n\t\t\t\tfor (const entity of world.queryTagged(SnapTarget)) {\n\t\t\t\t\tif (draggedIds.has(entity)) continue;\n\t\t\t\t\tif (!world.hasTag(entity, Active)) continue;\n\t\t\t\t\tconst rt = world.getComponent(entity, Transform2D);\n\t\t\t\t\tif (rt) {\n\t\t\t\t\t\trefs.push({\n\t\t\t\t\t\t\tx: rt.x,\n\t\t\t\t\t\t\ty: rt.y,\n\t\t\t\t\t\t\twidth: rt.width,\n\t\t\t\t\t\t\theight: rt.height,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcurrentSnap = computeSnapGuides(draggedBounds, refs, ctx.getSnapThreshold() / camera.zoom);\n\t\t\t}\n\t\t} else {\n\t\t\tcurrentSnap = { snapDx: 0, snapDy: 0, guides: [], spacings: [] };\n\t\t}\n\n\t\tconst finalDx = totalDx + currentSnap.snapDx;\n\t\tconst finalDy = totalDy + currentSnap.snapDy;\n\t\tfor (const [e, start] of inputState.startPositions) {\n\t\t\tworld.setComponent(e, Transform2D, {\n\t\t\t\tx: start.x + finalDx,\n\t\t\t\ty: start.y + finalDy,\n\t\t\t});\n\t\t}\n\n\t\tupdateCardOverlap(inputState.entityId);\n\t\tmarkDirty();\n\t}\n\n\t/**\n\t * End an active drag. `cancelled: false` runs the commit/fly-back/consume\n\t * decision tree (RFC-004 § Phase 4); `cancelled: true` rolls back state\n\t * and discards the open command group.\n\t */\n\tfunction _endDrag(cancelled: boolean): void {\n\t\tconst prevState = inputState;\n\t\tif (prevState.mode !== 'dragging') return;\n\n\t\tif (cancelled) {\n\t\t\t// Roll Transform2D back to the pre-drag positions so a cancelled\n\t\t\t// drag leaves no visible trace. Mirrors `_endResize(true)`.\n\t\t\tfor (const [e, start] of prevState.startPositions) {\n\t\t\t\tif (world.entityExists(e)) {\n\t\t\t\t\tworld.setComponent(e, Transform2D, { x: start.x, y: start.y });\n\t\t\t\t}\n\t\t\t}\n\t\t\tcommandBuffer.endGroup();\n\t\t\tfor (const e of prevState.startPositions.keys()) {\n\t\t\t\tif (world.hasTag(e, Dragging)) world.removeTag(e, Dragging);\n\t\t\t}\n\t\t\tfor (const [entity, originalZ] of prevState.originalZIndices) {\n\t\t\t\tif (world.entityExists(entity)) {\n\t\t\t\t\tworld.setComponent(entity, ZIndex, { value: originalZ });\n\t\t\t\t}\n\t\t\t}\n\t\t\tclearOverlapState();\n\t\t\tcurrentSnap = { snapDx: 0, snapDy: 0, guides: [], spacings: [] };\n\t\t\tinputState = { mode: 'idle' };\n\t\t\tmarkDirty();\n\t\t\treturn;\n\t\t}\n\n\t\t// RFC-004 § Phase 4 decision tree:\n\t\t// has Card + OverlapTarget → consume\n\t\t// has Card + overlap but no target → fly-back\n\t\t// otherwise → normal move\n\t\tconst draggedId = prevState.entityId;\n\t\tconst draggedHasCard = world.hasComponent(draggedId, Card);\n\t\tconst hadOverlap = overlapCandidates.size > 0;\n\t\tconst target = overlapTarget;\n\t\tconst shouldConsume = draggedHasCard && target !== null;\n\t\tconst shouldFlyBack = draggedHasCard && hadOverlap && target === null;\n\n\t\tif (shouldFlyBack) {\n\t\t\tconst nowMs = typeof performance !== 'undefined' ? performance.now() : Date.now();\n\t\t\tfor (const [e, start] of prevState.startPositions) {\n\t\t\t\tconst cur = world.getComponent(e, Transform2D);\n\t\t\t\tif (!cur) continue;\n\t\t\t\tworld.addComponent(e, TransformTween, {\n\t\t\t\t\tfromX: cur.x,\n\t\t\t\t\tfromY: cur.y,\n\t\t\t\t\ttoX: start.x,\n\t\t\t\t\ttoY: start.y,\n\t\t\t\t\tstartMs: nowMs,\n\t\t\t\t\tdurationMs: 250,\n\t\t\t\t\teasing: 'ease-out',\n\t\t\t\t\tkind: 'flyback',\n\t\t\t\t});\n\t\t\t}\n\t\t\tcommandBuffer.endGroup();\n\t\t\tcurrentSnap = { snapDx: 0, snapDy: 0, guides: [], spacings: [] };\n\t\t\tclearOverlapState();\n\t\t\tinputState = {\n\t\t\t\tmode: 'flyingBack',\n\t\t\t\tentityId: draggedId,\n\t\t\t\tstartPositions: prevState.startPositions,\n\t\t\t\toriginalZIndices: prevState.originalZIndices,\n\t\t\t};\n\t\t\tmarkDirty();\n\t\t\treturn;\n\t\t}\n\n\t\t// Commit / consume path.\n\t\tfor (const e of prevState.startPositions.keys()) {\n\t\t\tif (world.hasTag(e, Dragging)) world.removeTag(e, Dragging);\n\t\t}\n\t\tfor (const [entity, originalZ] of prevState.originalZIndices) {\n\t\t\tworld.setComponent(entity, ZIndex, { value: originalZ });\n\t\t}\n\n\t\tconst entityIds = [...prevState.startPositions.keys()];\n\t\tlet totalDx = 0;\n\t\tlet totalDy = 0;\n\t\tlet movedSomething = false;\n\t\tif (entityIds.length > 0) {\n\t\t\tconst firstId = entityIds[0];\n\t\t\tconst start = prevState.startPositions.get(firstId);\n\t\t\tconst current = world.getComponent(firstId, Transform2D);\n\t\t\tif (current && start) {\n\t\t\t\ttotalDx = current.x - start.x;\n\t\t\t\ttotalDy = current.y - start.y;\n\t\t\t\tif (totalDx !== 0 || totalDy !== 0) {\n\t\t\t\t\t// Rewind Transform2Ds so MoveCommand's first-execute\n\t\t\t\t\t// `beforePositions` snapshot captures the pre-drag state.\n\t\t\t\t\tfor (const [e, s] of prevState.startPositions) {\n\t\t\t\t\t\tworld.setComponent(e, Transform2D, { x: s.x, y: s.y });\n\t\t\t\t\t}\n\t\t\t\t\tmovedSomething = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlet consumeSnapshot: EntitySnapshot | undefined;\n\t\tlet consumeHandlers: ReturnType<NonNullable<typeof ctx.getWidgetInteraction>> | undefined;\n\t\tlet consumeMutation: unknown;\n\t\tlet shouldEmitConsume = false;\n\t\tif (shouldConsume && target !== null) {\n\t\t\tconst parentType = world.getComponent(target, Widget)?.type ?? '';\n\t\t\tconsumeHandlers = ctx.getWidgetInteraction?.(parentType);\n\t\t\tconst result = consumeHandlers?.onReceiveChild?.({\n\t\t\t\tparent: target,\n\t\t\t\tchild: draggedId,\n\t\t\t\tworld,\n\t\t\t}) ?? { consume: true };\n\t\t\tif (result.consume) {\n\t\t\t\tconsumeSnapshot = snapshotEntity(world, draggedId);\n\t\t\t\tconsumeMutation = result.mutation;\n\t\t\t\tshouldEmitConsume = true;\n\t\t\t}\n\t\t}\n\n\t\tif (movedSomething) {\n\t\t\tcommandBuffer.execute(new MoveCommand(entityIds, totalDx, totalDy, Transform2D), world);\n\t\t}\n\n\t\tif (shouldEmitConsume && target !== null && consumeSnapshot) {\n\t\t\tcommandBuffer.execute(\n\t\t\t\tnew ConsumeCommand(\n\t\t\t\t\ttarget,\n\t\t\t\t\tdraggedId,\n\t\t\t\t\tconsumeSnapshot,\n\t\t\t\t\tconsumeMutation,\n\t\t\t\t\tconsumeHandlers?.applyMutation,\n\t\t\t\t\tconsumeHandlers?.revertMutation,\n\t\t\t\t),\n\t\t\t\tworld,\n\t\t\t);\n\t\t\tif (world.hasTag(draggedId, Selected)) {\n\t\t\t\tworld.removeTag(draggedId, Selected);\n\t\t\t\tnotifySelectionChanged();\n\t\t\t}\n\t\t}\n\n\t\tcommandBuffer.endGroup();\n\t\tcurrentSnap = { snapDx: 0, snapDy: 0, guides: [], spacings: [] };\n\t\tclearOverlapState();\n\t\tinputState = { mode: 'idle' };\n\t\tmarkDirty();\n\t}\n\n\tfunction _beginResize(\n\t\tentity: EntityId,\n\t\thandle: ResizeHandlePos,\n\t\tstartWorldX: number,\n\t\tstartWorldY: number,\n\t): boolean {\n\t\tconst t = world.getComponent(entity, Transform2D);\n\t\tif (!t) return false;\n\t\tcommandBuffer.beginGroup();\n\t\tinputState = {\n\t\t\tmode: 'resizing',\n\t\t\tentityId: entity,\n\t\t\thandle,\n\t\t\tstartWorldX,\n\t\t\tstartWorldY,\n\t\t\tstartBounds: { x: t.x, y: t.y, width: t.width, height: t.height },\n\t\t};\n\t\tmarkDirty();\n\t\treturn true;\n\t}\n\n\tfunction _updateResize(worldX: number, worldY: number): void {\n\t\tif (inputState.mode !== 'resizing') return;\n\t\tconst dx = worldX - inputState.startWorldX;\n\t\tconst dy = worldY - inputState.startWorldY;\n\t\tconst { x, y, width: w, height: h } = inputState.startBounds;\n\t\tconst handle = inputState.handle;\n\n\t\tlet newX = x;\n\t\tlet newY = y;\n\t\tlet newW = w;\n\t\tlet newH = h;\n\n\t\tif (handle.includes('e')) {\n\t\t\tnewW = Math.max(MIN_WIDGET_SIZE, w + dx);\n\t\t}\n\t\tif (handle.includes('w')) {\n\t\t\tconst clampedW = Math.max(MIN_WIDGET_SIZE, w - dx);\n\t\t\tnewX = x + w - clampedW;\n\t\t\tnewW = clampedW;\n\t\t}\n\t\tif (handle.includes('s')) {\n\t\t\tnewH = Math.max(MIN_WIDGET_SIZE, h + dy);\n\t\t}\n\t\tif (handle.includes('n')) {\n\t\t\tconst clampedH = Math.max(MIN_WIDGET_SIZE, h - dy);\n\t\t\tnewY = y + h - clampedH;\n\t\t\tnewH = clampedH;\n\t\t}\n\n\t\tworld.setComponent(inputState.entityId, Transform2D, {\n\t\t\tx: newX,\n\t\t\ty: newY,\n\t\t\twidth: newW,\n\t\t\theight: newH,\n\t\t});\n\t\tmarkDirty();\n\t}\n\n\tfunction _endResize(cancelled: boolean): void {\n\t\tconst prevState = inputState;\n\t\tif (prevState.mode !== 'resizing') return;\n\n\t\tif (cancelled) {\n\t\t\t// Roll the widget back to its starting bounds and discard the\n\t\t\t// open command group. Mirrors `_endDrag` cancel symmetry.\n\t\t\tworld.setComponent(prevState.entityId, Transform2D, prevState.startBounds);\n\t\t\tcommandBuffer.endGroup();\n\t\t\tinputState = { mode: 'idle' };\n\t\t\tmarkDirty();\n\t\t\treturn;\n\t\t}\n\n\t\tconst t = world.getComponent(prevState.entityId, Transform2D);\n\t\tif (t) {\n\t\t\tconst finalBounds = { x: t.x, y: t.y, width: t.width, height: t.height };\n\t\t\tconst sb = prevState.startBounds;\n\t\t\tworld.setComponent(prevState.entityId, Transform2D, sb);\n\t\t\tcommandBuffer.execute(\n\t\t\t\tnew ResizeCommand(prevState.entityId, sb, finalBounds, Transform2D),\n\t\t\t\tworld,\n\t\t\t);\n\t\t}\n\t\tcommandBuffer.endGroup();\n\t\tinputState = { mode: 'idle' };\n\t\tmarkDirty();\n\t}\n\n\tfunction _beginMarquee(startWorldX: number, startWorldY: number): void {\n\t\tinputState = { mode: 'marquee', startWorldX, startWorldY };\n\t\tmarkDirty();\n\t}\n\n\tfunction _updateMarquee(_worldX: number, _worldY: number): void {\n\t\t// Marquee box visuals are not yet implemented — placeholder for the\n\t\t// new public API to drive when the marquee rect lands.\n\t}\n\n\tfunction _endMarquee(): void {\n\t\tif (inputState.mode !== 'marquee') return;\n\t\tinputState = { mode: 'idle' };\n\t\tmarkDirty();\n\t}\n\n\t/**\n\t * Cancel any active drag/resize/flyingBack state. Used by both the\n\t * legacy `handlePointerCancel` and as the implementation of the\n\t * new public `endDrag(_, { cancelled: true })` / `endResize(_, …)`.\n\t */\n\tfunction _cancelAll(): void {\n\t\tif (inputState.mode === 'dragging') {\n\t\t\t_endDrag(true);\n\t\t} else if (inputState.mode === 'resizing') {\n\t\t\t_endResize(true);\n\t\t} else if (inputState.mode === 'flyingBack') {\n\t\t\t// RFC-004 § Phase 4 — cancel during fly-back animation: kill\n\t\t\t// the tween, remove Dragging, restore original ZIndex, and\n\t\t\t// snap Transform2D to the fly-back destination (which is the\n\t\t\t// pre-drag position the tween was already animating toward).\n\t\t\t// Without the position snap the entity would freeze mid-flight,\n\t\t\t// orphaned in space — fly-back leaves no command-buffer entry\n\t\t\t// to undo, so there's no other recovery path.\n\t\t\tfor (const [e, start] of inputState.startPositions) {\n\t\t\t\tif (!world.entityExists(e)) continue;\n\t\t\t\tif (world.hasComponent(e, TransformTween)) world.removeComponent(e, TransformTween);\n\t\t\t\tif (world.hasTag(e, Dragging)) world.removeTag(e, Dragging);\n\t\t\t\tworld.setComponent(e, Transform2D, { x: start.x, y: start.y });\n\t\t\t}\n\t\t\tfor (const [entity, originalZ] of inputState.originalZIndices) {\n\t\t\t\tif (!world.entityExists(entity)) continue;\n\t\t\t\tworld.setComponent(entity, ZIndex, { value: originalZ });\n\t\t\t}\n\t\t\tcurrentSnap = { snapDx: 0, snapDy: 0, guides: [], spacings: [] };\n\t\t\tinputState = { mode: 'idle' };\n\t\t\tmarkDirty();\n\t\t} else if (inputState.mode === 'marquee') {\n\t\t\t_endMarquee();\n\t\t} else if (inputState.mode === 'tracking') {\n\t\t\tinputState = { mode: 'idle' };\n\t\t\tmarkDirty();\n\t\t}\n\t}\n\n\t// ------------------------------------------------------------------\n\t// Legacy entry points (RFC-008 Phase 3d will retire these).\n\t// ------------------------------------------------------------------\n\n\tfunction handlePointerDown(\n\t\tscreenX: number,\n\t\tscreenY: number,\n\t\t_button: number,\n\t\tmodifiers: Modifiers,\n\t): PointerDirective {\n\t\tconst camera = world.getResource(CameraResource);\n\t\tconst startWorld = screenToWorld(screenX, screenY, camera);\n\n\t\t// RFC-004 § Phase 4 — fly-back interruption. If a pointerdown\n\t\t// lands on (or near) the flying entity, cancel the tween and\n\t\t// resume dragging from the CURRENT animated position. Keep\n\t\t// Dragging / ZIndex / layer in place to avoid visual flicker.\n\t\tif (inputState.mode === 'flyingBack') {\n\t\t\tconst hit = hitTest(screenX, screenY);\n\t\t\tconst target = hit?.entityId === inputState.entityId ? hit.entityId : null;\n\t\t\tif (target !== null) {\n\t\t\t\tworld.removeComponent(target, TransformTween);\n\t\t\t\tconst newStartPositions = new Map<EntityId, { x: number; y: number }>();\n\t\t\t\tfor (const e of inputState.startPositions.keys()) {\n\t\t\t\t\tconst cur = world.getComponent(e, Transform2D);\n\t\t\t\t\tif (cur) newStartPositions.set(e, { x: cur.x, y: cur.y });\n\t\t\t\t\tif (world.hasComponent(e, TransformTween)) world.removeComponent(e, TransformTween);\n\t\t\t\t}\n\t\t\t\tcommandBuffer.beginGroup();\n\t\t\t\tinputState = {\n\t\t\t\t\tmode: 'dragging',\n\t\t\t\t\tentityId: target,\n\t\t\t\t\tstartWorldX: startWorld.x,\n\t\t\t\t\tstartWorldY: startWorld.y,\n\t\t\t\t\tstartPositions: newStartPositions,\n\t\t\t\t\toriginalZIndices: inputState.originalZIndices,\n\t\t\t\t};\n\t\t\t\tmarkDirty();\n\t\t\t\treturn { action: 'capture-drag' };\n\t\t\t}\n\t\t}\n\n\t\tconst hit = hitTest(screenX, screenY);\n\n\t\tif (!hit) {\n\t\t\tclearSelection();\n\t\t\t_beginMarquee(startWorld.x, startWorld.y);\n\t\t\treturn { action: 'capture-marquee' };\n\t\t}\n\n\t\tswitch (hit.role.role.type) {\n\t\t\tcase 'resize': {\n\t\t\t\tconst ok = _beginResize(hit.entityId, hit.role.role.handle, startWorld.x, startWorld.y);\n\t\t\t\tif (!ok) return { action: 'passthrough' };\n\t\t\t\treturn { action: 'capture-resize', handle: hit.role.role.handle };\n\t\t\t}\n\n\t\t\tcase 'drag': {\n\t\t\t\tselectEntity(hit.entityId, modifiers.shift);\n\t\t\t\tif (world.hasTag(hit.entityId, Draggable)) {\n\t\t\t\t\tinputState = {\n\t\t\t\t\t\tmode: 'tracking',\n\t\t\t\t\t\tentityId: hit.entityId,\n\t\t\t\t\t\tstartScreenX: screenX,\n\t\t\t\t\t\tstartScreenY: screenY,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tmarkDirty();\n\t\t\t\treturn { action: 'passthrough-track-drag' };\n\t\t\t}\n\n\t\t\tcase 'select': {\n\t\t\t\tselectEntity(hit.entityId, modifiers.shift);\n\t\t\t\tmarkDirty();\n\t\t\t\treturn { action: 'passthrough' };\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\treturn { action: 'passthrough' };\n\t\t}\n\t}\n\n\tfunction handlePointerMove(\n\t\tscreenX: number,\n\t\tscreenY: number,\n\t\t_modifiers: Modifiers,\n\t): PointerDirective {\n\t\tconst camera = world.getResource(CameraResource);\n\t\tconst w = screenToWorld(screenX, screenY, camera);\n\n\t\tif (inputState.mode === 'tracking') {\n\t\t\tconst dx = screenX - inputState.startScreenX;\n\t\t\tconst dy = screenY - inputState.startScreenY;\n\t\t\tif (Math.abs(dx) > DEAD_ZONE_MOUSE_PX || Math.abs(dy) > DEAD_ZONE_MOUSE_PX) {\n\t\t\t\t// Drag origin is the dead-zone-crossing pointer position, not\n\t\t\t\t// the original pointer-down position. Matches the v1 behaviour\n\t\t\t\t// snap tests assert against (delta is measured from dead-zone\n\t\t\t\t// exit, not from down). No Transform2D mutation on this frame.\n\t\t\t\t_beginDrag(inputState.entityId, w.x, w.y);\n\t\t\t\treturn { action: 'capture-drag' };\n\t\t\t}\n\t\t\treturn { action: 'passthrough' };\n\t\t}\n\n\t\tif (inputState.mode === 'dragging') {\n\t\t\t_updateDrag(w.x, w.y);\n\t\t\treturn { action: 'capture-drag' };\n\t\t}\n\n\t\tif (inputState.mode === 'resizing') {\n\t\t\tconst handle = inputState.handle;\n\t\t\t_updateResize(w.x, w.y);\n\t\t\treturn { action: 'capture-resize', handle };\n\t\t}\n\n\t\tif (inputState.mode === 'marquee') {\n\t\t\t_updateMarquee(w.x, w.y);\n\t\t\treturn { action: 'capture-marquee' };\n\t\t}\n\n\t\tif (inputState.mode === 'idle') {\n\t\t\tconst hit = hitTest(screenX, screenY);\n\t\t\tconst hoverTarget: EntityId | null = hit ? hit.entityId : null;\n\t\t\tconst hoverHandle: ResizeHandlePos | null =\n\t\t\t\thit?.role.role.type === 'resize' ? hit.role.role.handle : null;\n\t\t\tif (hoverTarget !== hoveredEntity || hoverHandle !== hoveredHandle) {\n\t\t\t\thoveredEntity = hoverTarget;\n\t\t\t\thoveredHandle = hoverHandle;\n\t\t\t\tmarkDirty();\n\t\t\t}\n\t\t}\n\n\t\treturn { action: 'passthrough' };\n\t}\n\n\tfunction handlePointerUp(): PointerDirective {\n\t\tconst mode = inputState.mode;\n\t\tif (mode === 'dragging') {\n\t\t\t_endDrag(false);\n\t\t} else if (mode === 'resizing') {\n\t\t\t_endResize(false);\n\t\t} else if (mode === 'marquee') {\n\t\t\t_endMarquee();\n\t\t} else if (mode === 'tracking') {\n\t\t\tinputState = { mode: 'idle' };\n\t\t}\n\t\treturn { action: 'passthrough' };\n\t}\n\n\tfunction handlePointerCancel(): void {\n\t\t_cancelAll();\n\t}\n\n\t// ------------------------------------------------------------------\n\t// RFC-008 Phase 3b — public input API. Wraps the world-coord helpers\n\t// above so callers can drive the state machine without going through\n\t// the legacy screen-coord `handlePointer*` entry points.\n\t// ------------------------------------------------------------------\n\n\tfunction beginDrag(_entity: EntityId, worldX: number, worldY: number): void {\n\t\t// `_entity` documents intent; the state machine drags whatever's\n\t\t// `Selected` (multi-select preserved). Caller manages selection.\n\t\t_beginDrag(_entity, worldX, worldY);\n\t}\n\n\tfunction updateDrag(_entity: EntityId, worldX: number, worldY: number): void {\n\t\t_updateDrag(worldX, worldY);\n\t}\n\n\tfunction endDrag(_entity: EntityId, opts: { cancelled: boolean }): void {\n\t\t_endDrag(opts.cancelled);\n\t}\n\n\tfunction beginResize(\n\t\tentity: EntityId,\n\t\thandle: ResizeHandlePos,\n\t\tworldX: number,\n\t\tworldY: number,\n\t): boolean {\n\t\treturn _beginResize(entity, handle, worldX, worldY);\n\t}\n\n\tfunction updateResize(_entity: EntityId, worldX: number, worldY: number): void {\n\t\t_updateResize(worldX, worldY);\n\t}\n\n\tfunction endResize(_entity: EntityId, opts: { cancelled: boolean }): void {\n\t\t_endResize(opts.cancelled);\n\t}\n\n\tfunction beginMarquee(worldX: number, worldY: number): void {\n\t\t_beginMarquee(worldX, worldY);\n\t}\n\n\tfunction updateMarquee(worldX: number, worldY: number): void {\n\t\t_updateMarquee(worldX, worldY);\n\t}\n\n\tfunction endMarquee(): void {\n\t\t_endMarquee();\n\t}\n\n\tfunction isMarqueeActive(): boolean {\n\t\treturn inputState.mode === 'marquee';\n\t}\n\n\tfunction getDraggingEntity(): EntityId | null {\n\t\treturn inputState.mode === 'dragging' ? inputState.entityId : null;\n\t}\n\n\tfunction isResizing(): boolean {\n\t\treturn inputState.mode === 'resizing';\n\t}\n\n\tfunction getResizingEntity(): EntityId | null {\n\t\treturn inputState.mode === 'resizing' ? inputState.entityId : null;\n\t}\n\n\tfunction setHoveredEntity(entity: EntityId | null): void {\n\t\tif (entity === hoveredEntity) return;\n\t\thoveredEntity = entity;\n\t\t// Hover-handle cache is only valid when hover came via `hitTest`;\n\t\t// an external setHoveredEntity path doesn't know about handles.\n\t\thoveredHandle = null;\n\t\tmarkDirty();\n\t}\n\n\t/**\n\t * Update hover state from a screen-space pointer position. Runs the\n\t * full hit-test so both `hoveredEntity` and `hoveredHandle` (RFC-005\n\t * resize hotspot under the cursor, if any) reflect the current pixel.\n\t *\n\t * Gated on `idle` mode — hover doesn't refresh during drag / resize /\n\t * marquee / fly-back (matches the v1 `handlePointerMove` idle branch).\n\t *\n\t * Called from the InputManager pipeline's `move` engine handler on\n\t * every pointermove: HoverRecognizer's `hover-enter` / `hover-leave`\n\t * events only fire on entity transitions, but the cursor needs to\n\t * change between resize handles within the same entity, so this path\n\t * runs the hit-test per move.\n\t */\n\tfunction updateHover(screenX: number, screenY: number): void {\n\t\tif (inputState.mode !== 'idle') return;\n\t\tconst hit = hitTest(screenX, screenY);\n\t\tconst target: EntityId | null = hit ? hit.entityId : null;\n\t\tconst handle: ResizeHandlePos | null =\n\t\t\thit?.role.role.type === 'resize' ? hit.role.role.handle : null;\n\t\tif (target === hoveredEntity && handle === hoveredHandle) return;\n\t\thoveredEntity = target;\n\t\thoveredHandle = handle;\n\t\tmarkDirty();\n\t}\n\n\t/**\n\t * Cancel any active interaction state (drag / resize / marquee /\n\t * fly-back / tracking). Public surface for the InputManager pipeline's\n\t * `cancel` engine handler — `endDrag(.., {cancelled:true})` only handles\n\t * `dragging`, but a native `pointercancel` can land in any of the other\n\t * mid-gesture modes. `_cancelAll` covers them all.\n\t */\n\tfunction cancelInteraction(): void {\n\t\t_cancelAll();\n\t}\n\n\treturn {\n\t\thandlePointerDown,\n\t\thandlePointerMove,\n\t\thandlePointerUp,\n\t\thandlePointerCancel,\n\t\trunCursorSystem,\n\t\trunFlyBackSystem,\n\t\tselectEntity,\n\t\tclearSelection,\n\t\tgetHoveredEntity: () => hoveredEntity,\n\t\tsetHoveredEntity,\n\t\tupdateHover,\n\t\tgetSnapGuides: () => currentSnap.guides,\n\t\tgetEqualSpacing: () => currentSnap.spacings,\n\t\t/**\n\t\t * Topmost interactable entity under a screen-space point, or null\n\t\t * if nothing's there. Same hit-test the pointer state machine\n\t\t * uses, exposed for callers that need to resolve coords to an\n\t\t * entity without entering the state machine — used by\n\t\t * `installEngineHandlers` (tap, drag-start, double-tap routing) and\n\t\t * the InputManager dispatch loop (surface routing for R3F widgets).\n\t\t */\n\t\tpickAt: (screenX: number, screenY: number): EntityId | null =>\n\t\t\thitTest(screenX, screenY)?.entityId ?? null,\n\t\t// RFC-008 Phase 3b — new public API.\n\t\tbeginDrag,\n\t\tupdateDrag,\n\t\tendDrag,\n\t\tcancelInteraction,\n\t\tbeginResize,\n\t\tupdateResize,\n\t\tendResize,\n\t\tisResizing,\n\t\tgetResizingEntity,\n\t\t/**\n\t\t * Rich variant of `pickAt` — returns the entity AND its\n\t\t * `InteractionRoleData` (role + layer) at a screen-space point.\n\t\t * Used by `installEngineHandlers` to role-branch on `drag-start`\n\t\t * (resize → `beginResize`, drag → `beginDrag`, etc.). External\n\t\t * callers that only need the entity id should use `pickAt`.\n\t\t */\n\t\thitTest,\n\t\tbeginMarquee,\n\t\tupdateMarquee,\n\t\tendMarquee,\n\t\tisMarqueeActive,\n\t\tgetDraggingEntity,\n\t};\n}\n","/**\n * Pipeline phases for the infinite-canvas `LayoutEngine`.\n *\n * `reactive-ecs` ships zero phase vocabulary — phase names and order are the\n * consumer's responsibility. These names are infinite-canvas's choice; a UI\n * tool, a game engine, and an agent simulator would each pick differently.\n *\n * Phase intent:\n * - `input` — drain external intent (gestures, raw flag captures) into the world\n * - `react` — maintain invariants in response to mutations from prior writes\n * - `control` — state machines, intent resolution, navigation\n * - `simulate` — time-driven mutations (tweens, animation)\n * - `derive` — compute frame-local derived state (visibility, sort, layout)\n * - `present` — build outputs for renderers (frame-changes, visible lists)\n * - `cleanup` — end-of-frame bookkeeping (clearDirty, incrementTick, emitFrame)\n *\n * See RFC-010 for the full architectural rationale.\n */\nexport const ENGINE_PHASES = [\n\t'input',\n\t'react',\n\t'control',\n\t'simulate',\n\t'derive',\n\t'present',\n\t'cleanup',\n] as const;\n\nexport type EnginePhase = (typeof ENGINE_PHASES)[number];\n","import type { EntityId, World } from '@jamesyong42/reactive-ecs';\nimport type { StandardSchemaV1 } from '../schema.js';\n\n/** Rendering surface for a widget. */\nexport type WidgetSurface = 'dom' | 'webgl';\n\n/**\n * Drop-to-consume interaction handlers for a widget type (RFC-004 § Phase 1).\n *\n * All fields are optional. A widget that sets `accepts` on its `Card`\n * component should typically also supply `onReceiveChild` so it can\n * actually do something on consume; a widget that sets `provides`\n * rarely needs `onDroppedOnParent` unless it wants to veto or run\n * side effects.\n *\n * Handlers live on the widget *type* (not the entity) so `Card` data\n * stays serializable and one handler triple drives every instance of\n * the widget type.\n */\nexport interface WidgetInteractionHandlers {\n\t/**\n\t * Parent-side: called on drop when a child lands on this widget.\n\t * Return `{ consume: true }` to accept the drop; the optional\n\t * `mutation` payload is passed to `applyMutation` / `revertMutation`\n\t * so undo can be symmetric.\n\t */\n\tonReceiveChild?(ctx: { parent: EntityId; child: EntityId; world: World }): {\n\t\tconsume: boolean;\n\t\tmutation?: unknown;\n\t};\n\n\t/**\n\t * Child-side: called on drop when this widget is being dropped\n\t * onto a parent. Optional side effects and optional veto.\n\t */\n\tonDroppedOnParent?(ctx: {\n\t\tchild: EntityId;\n\t\tparent: EntityId;\n\t\tworld: World;\n\t}): { veto: boolean } | undefined;\n\n\t/**\n\t * Parent-side runtime gate on top of the static `accepts` /\n\t * `provides` intersection — e.g. \"container is full, refuse further\n\t * children.\" Returning `false` blocks the consume before\n\t * `onReceiveChild` is called.\n\t */\n\tcanAccept?(ctx: { parent: EntityId; child: EntityId; world: World }): boolean;\n\n\t/**\n\t * Apply the mutation returned by `onReceiveChild` (forward path).\n\t * Called by `ConsumeCommand.execute`.\n\t */\n\tapplyMutation?(world: World, mutation: unknown): void;\n\n\t/**\n\t * Reverse the mutation (undo path). Called by `ConsumeCommand.undo`.\n\t */\n\trevertMutation?(world: World, mutation: unknown): void;\n}\n\n/**\n * Framework-free widget contract used by the engine.\n *\n * The React layer (see `react/widgets/registry.ts`) extends this with a\n * `component` field to carry the rendered React component. The engine never\n * reads that field — it only needs the metadata here — which keeps the\n * `ecs/` layer free of React imports.\n */\nexport interface WidgetBinding<T = Record<string, unknown>> {\n\t/** Unique widget type id. Matches `Widget { type }` on spawned entities. */\n\ttype: string;\n\t/** Rendering surface; defaults to `'dom'`. */\n\tsurface?: WidgetSurface;\n\t/**\n\t * Standard Schema v1-compatible schema for the widget's data.\n\t * Use Zod 3.24+, Valibot, ArkType, or any other conforming validator.\n\t * The schema's output type drives the widget's data type.\n\t */\n\t// biome-ignore lint/suspicious/noExplicitAny: schema Input is intentionally permissive\n\tschema: StandardSchemaV1<any, T>;\n\t/** Default data shape for new instances. Merged with user-supplied data at spawn. */\n\tdefaultData: T;\n\t/** Default world-space size at spawn. */\n\tdefaultSize: { width: number; height: number };\n\t/** Minimum world-space size when resizing. */\n\tminSize?: { width: number; height: number };\n\t/**\n\t * Optional drop-to-consume handlers. Only meaningful for `Card`-tagged\n\t * widgets; non-card widgets don't participate in the consume mechanic\n\t * so any handlers here are dead code for them.\n\t */\n\tinteraction?: WidgetInteractionHandlers;\n}\n\n/** Simple in-memory registry of widget bindings. */\nexport interface WidgetRegistry<W extends WidgetBinding = WidgetBinding> {\n\tregister(def: W): void;\n\tget(type: string): W | null;\n\tgetAll(): W[];\n}\n\nexport function createWidgetRegistry<W extends WidgetBinding = WidgetBinding>(\n\tdefs: W[] = [],\n): WidgetRegistry<W> {\n\tconst map = new Map<string, W>();\n\tfor (const def of defs) map.set(def.type, def);\n\treturn {\n\t\tregister(def) {\n\t\t\tmap.set(def.type, def);\n\t\t},\n\t\tget(type) {\n\t\t\treturn map.get(type) ?? null;\n\t\t},\n\t\tgetAll() {\n\t\t\treturn [...map.values()];\n\t\t},\n\t};\n}\n","import type {\n\tComponentInit,\n\tComponentType,\n\tEntityId,\n\tSystemDef,\n\tTagType,\n\tUnsubscribe,\n} from '@jamesyong42/reactive-ecs';\nimport { createWorld, PhasedScheduler } from '@jamesyong42/reactive-ecs';\nimport { Profiler } from '../../profiler/Profiler.js';\nimport type { Archetype, ArchetypeRegistry, SpawnOptions } from '../archetype.js';\nimport { createArchetypeRegistry } from '../archetype.js';\nimport type { Command } from '../commands.js';\nimport { CommandBuffer } from '../commands.js';\nimport type { InteractionRoleType } from '../components.js';\nimport {\n\tActive,\n\tContainer,\n\tContainerCamera,\n\tContainerChildren,\n\tCursorHint,\n\tDraggable,\n\tInteractionRole,\n\tLayer,\n\tParentFrame,\n\tResizable,\n\tSelectable,\n\tSelected,\n\tSelectionFrame,\n\tSnapSource,\n\tSnapTarget,\n\tTransform2D,\n\tTransformTween,\n\tVisible,\n\tWidgetBreakpoint,\n\tWidget as WidgetComp,\n\tWidgetData,\n\tZIndex,\n} from '../components.js';\nimport { clamp, rectToAABB, screenToWorld } from '../math.js';\nimport {\n\tBreakpointConfigResource,\n\tCameraResource,\n\tCardPresetsResource,\n\tNavigationStackResource,\n\tRootCameraResource,\n\tSpatialIndexResource,\n\tViewportResource,\n\tZoomConfigResource,\n} from '../resources.js';\nimport type { StandardSchemaV1 } from '../schema.js';\nimport { SpatialIndex } from '../spatial/SpatialIndex.js';\nimport {\n\tbreakpointSystem,\n\tcardSystem,\n\tcullSystem,\n\tdragPromoteSystem,\n\tnavigationFilterSystem,\n\treconcileEntityActive,\n\tsortSystem,\n\ttransformTweenSystem,\n} from '../systems/index.js';\nimport { createInteractionRuntime } from './interaction.js';\nimport { ENGINE_PHASES } from './phases.js';\nimport type {\n\tFrameChanges,\n\tLayoutEngine,\n\tLayoutEngineConfig,\n\tModifiers,\n\tPointerDirective,\n\tVisibleEntity,\n} from './types.js';\nimport type { WidgetBinding, WidgetRegistry } from './widget-binding.js';\nimport { createWidgetRegistry } from './widget-binding.js';\n\n/**\n * Creates a new LayoutEngine instance with the given configuration.\n * This is the main entry point for the infinite canvas library.\n */\nexport function createLayoutEngine<W extends WidgetBinding = WidgetBinding>(\n\tconfig?: LayoutEngineConfig<W>,\n): LayoutEngine<W> {\n\tconst world = createWorld();\n\tconst scheduler = new PhasedScheduler({\n\t\tphases: ENGINE_PHASES,\n\t\tdefaultPhase: 'derive',\n\t});\n\tconst spatialIndex = new SpatialIndex();\n\tconst profiler = new Profiler();\n\tscheduler.profiler = profiler;\n\n\t// Store spatial index as a proper resource\n\tworld.setResource(SpatialIndexResource, { instance: spatialIndex });\n\n\tconst commandBuffer = new CommandBuffer();\n\n\tconst widgetRegistry: WidgetRegistry<W> = createWidgetRegistry<W>();\n\tconst archetypeRegistry: ArchetypeRegistry = createArchetypeRegistry();\n\n\t// Apply config\n\tif (config?.zoom) {\n\t\tworld.setResource(ZoomConfigResource, config.zoom);\n\t}\n\tif (config?.breakpoints) {\n\t\tworld.setResource(BreakpointConfigResource, config.breakpoints);\n\t}\n\tif (config?.cardPresets) {\n\t\tconst current = world.getResource(CardPresetsResource);\n\t\tworld.setResource(CardPresetsResource, {\n\t\t\tpresets: { ...current.presets, ...config.cardPresets.presets },\n\t\t\tgap: config.cardPresets.gap ?? current.gap,\n\t\t});\n\t}\n\n\tlet snapEnabled = config?.snap?.enabled ?? true;\n\tlet snapThreshold = config?.snap?.threshold ?? 5;\n\tlet snapGuidesVisible = config?.snap?.guidesVisible ?? true;\n\n\t// Register built-in systems.\n\tscheduler.register(cardSystem);\n\tscheduler.register(transformTweenSystem);\n\tscheduler.register(navigationFilterSystem);\n\tscheduler.register(cullSystem);\n\tscheduler.register(breakpointSystem);\n\tscheduler.register(sortSystem);\n\tscheduler.register(dragPromoteSystem);\n\n\tconst unsubscribers: Unsubscribe[] = [];\n\n\t// Wire spatial index reactively via observer instead of per-frame scan.\n\t// Post-RFC-004 Phase 0b: Transform2D is the single source of truth for\n\t// entity bounds — no more WorldBounds shadow.\n\tunsubscribers.push(\n\t\tworld.onComponentChanged(Transform2D, (entityId, _prev, t) => {\n\t\t\tif (t) {\n\t\t\t\tspatialIndex.upsert(entityId, rectToAABB(t));\n\t\t\t}\n\t\t}),\n\t);\n\n\tunsubscribers.push(\n\t\tworld.onEntityDestroyed((entity) => {\n\t\t\tspatialIndex.remove(entity);\n\t\t}),\n\t);\n\n\t// Auto-attach ContainerCamera on Container-tag add, so every container\n\t// entity has a usable camera component from birth (serialization round-\n\t// trips cleanly; enterContainer can read without falling back). The\n\t// prev === undefined guard scopes this to component *adds* only —\n\t// updates of an existing Container value do not re-stamp a fresh camera.\n\tunsubscribers.push(\n\t\tworld.onComponentChanged(Container, (entityId, prev, next) => {\n\t\t\tif (prev === undefined && next !== undefined) {\n\t\t\t\tif (!world.hasComponent(entityId, ContainerCamera)) {\n\t\t\t\t\tworld.addComponent(entityId, ContainerCamera, { x: 0, y: 0, zoom: 1 });\n\t\t\t\t}\n\t\t\t}\n\t\t}),\n\t);\n\n\t// RFC-004 § Phase 5 — keep `Active` in sync with mid-session\n\t// ParentFrame mutations. Covers the consume path (child gets\n\t// `ParentFrame`, should leave the current frame), re-parent (id\n\t// changes), and undo (ParentFrame removed, child returns to root).\n\t// Without this, a consumed card retains `Active` at root until the\n\t// next nav-stack change and renders visibly on top of its own\n\t// container. The nav-stack-change branch of `navigationFilterSystem`\n\t// still handles the full refilter when the user navigates.\n\tunsubscribers.push(\n\t\tworld.onComponentChanged(ParentFrame, (entityId) => {\n\t\t\treconcileEntityActive(world, entityId);\n\t\t\tmarkDirtyInternal();\n\t\t}),\n\t);\n\n\t// Auto-attach InteractionRole and CursorHint based on Draggable/Selectable\n\t// tag presence. Entities with an explicit non-drag/non-select role\n\t// (rotate/connect/etc.) are left alone.\n\tfunction refreshInteractionRole(entity: EntityId): void {\n\t\tconst current = world.getComponent(entity, InteractionRole);\n\t\tif (\n\t\t\tcurrent &&\n\t\t\tcurrent.role.type !== 'drag' &&\n\t\t\tcurrent.role.type !== 'select' &&\n\t\t\tcurrent.role.type !== 'canvas'\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst hasDraggable = world.hasTag(entity, Draggable);\n\t\tconst hasSelectable = world.hasTag(entity, Selectable);\n\t\tconst desiredRole: InteractionRoleType | null = hasDraggable\n\t\t\t? { type: 'drag' }\n\t\t\t: hasSelectable\n\t\t\t\t? { type: 'select' }\n\t\t\t\t: null;\n\n\t\tif (desiredRole === null) {\n\t\t\tif (current) world.removeComponent(entity, InteractionRole);\n\t\t\tif (world.hasComponent(entity, CursorHint)) world.removeComponent(entity, CursorHint);\n\t\t\treturn;\n\t\t}\n\n\t\tif (!current) {\n\t\t\tworld.addComponent(entity, InteractionRole, { layer: 5, role: desiredRole });\n\t\t} else if (current.role.type !== desiredRole.type) {\n\t\t\tworld.setComponent(entity, InteractionRole, { role: desiredRole });\n\t\t}\n\n\t\tif (desiredRole.type === 'drag' && !world.hasComponent(entity, CursorHint)) {\n\t\t\tworld.addComponent(entity, CursorHint, { hover: 'grab', active: 'grabbing' });\n\t\t}\n\t}\n\tunsubscribers.push(world.onTagAdded(Draggable, refreshInteractionRole));\n\tunsubscribers.push(world.onTagRemoved(Draggable, refreshInteractionRole));\n\tunsubscribers.push(world.onTagAdded(Selectable, refreshInteractionRole));\n\tunsubscribers.push(world.onTagRemoved(Selectable, refreshInteractionRole));\n\n\t// Drag-promote is implemented as `dragPromoteSystem` (RFC-010 Phase 1),\n\t// registered above. It runs `before: 'cull'` and uses the presence of\n\t// `PreDragLayer` as a diff signal — no observers required.\n\n\t// Pre-register widgets and archetypes from config\n\tif (config?.widgets) {\n\t\tfor (const w of config.widgets) widgetRegistry.register(w);\n\t}\n\tif (config?.archetypes) {\n\t\tfor (const a of config.archetypes) archetypeRegistry.register(a);\n\t}\n\n\t// Initialize navigation — mark root entities as Active on first tick\n\tworld.setResource(NavigationStackResource, { changed: true });\n\n\t// Frame-level state\n\tlet dirty = false;\n\tlet cameraChangedThisTick = false;\n\tlet selectionChangedThisTick = false;\n\tlet prevVisible = new Set<EntityId>();\n\tlet currentVisible: VisibleEntity[] = [];\n\tlet frameChanges: FrameChanges = {\n\t\tpositionsChanged: [],\n\t\tbreakpointsChanged: [],\n\t\tzIndicesChanged: [],\n\t\tentered: [],\n\t\texited: [],\n\t\tcameraChanged: false,\n\t\tnavigationChanged: false,\n\t\tselectionChanged: false,\n\t\tlayersChanged: false,\n\t};\n\n\tfunction markDirtyInternal() {\n\t\tdirty = true;\n\t}\n\n\t// Compose the pointer / selection state machine.\n\tconst interaction = createInteractionRuntime({\n\t\tworld,\n\t\tspatialIndex,\n\t\tcommandBuffer,\n\t\tmarkDirty: markDirtyInternal,\n\t\tnotifySelectionChanged: () => {\n\t\t\tselectionChangedThisTick = true;\n\t\t},\n\t\tgetSnapEnabled: () => snapEnabled,\n\t\tgetSnapThreshold: () => snapThreshold,\n\t\t// RFC-004 § Phase 3 — the overlap pass consults the parent widget\n\t\t// type's `canAccept` gate (when present) before flagging\n\t\t// `OverlapTarget`. Non-card / unregistered widgets fall through\n\t\t// to \"no gate, static contract check only.\"\n\t\tgetWidgetInteraction: (type: string) => widgetRegistry.get(type)?.interaction,\n\t});\n\n\tconst engine: LayoutEngine<W> = {\n\t\tworld,\n\n\t\t// === Entity CRUD ===\n\n\t\tcreateEntity(inits?: ComponentInit[]): EntityId {\n\t\t\tconst entity = world.createEntity();\n\t\t\tif (inits) {\n\t\t\t\tfor (const init of inits) {\n\t\t\t\t\tconst type = init[0];\n\t\t\t\t\tif (type.__kind === 'tag') {\n\t\t\t\t\t\tworld.addTag(entity, type as TagType);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tworld.addComponent(entity, type as ComponentType, init[1] ?? {});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tmarkDirtyInternal();\n\t\t\treturn entity;\n\t\t},\n\n\t\tspawn(id: string, opts: SpawnOptions = {}): EntityId {\n\t\t\t// Resolve archetype: explicit → widget-derived default → bare default.\n\t\t\tconst archetype = archetypeRegistry.get(id);\n\t\t\tconst widgetTypeId = archetype?.widget ?? id;\n\t\t\tconst widget = widgetRegistry.get(widgetTypeId);\n\n\t\t\tconst surface = widget?.surface ?? 'dom';\n\t\t\tconst defaultData = (widget?.defaultData as Record<string, unknown> | undefined) ?? {};\n\t\t\tconst defaultSize = archetype?.defaultSize ??\n\t\t\t\twidget?.defaultSize ?? { width: 100, height: 100 };\n\n\t\t\tconst position = opts.at ?? { x: 0, y: 0 };\n\t\t\tconst size = opts.size ?? defaultSize;\n\t\t\tconst data = { ...defaultData, ...opts.data };\n\n\t\t\tconst inits: ComponentInit[] = [\n\t\t\t\t[\n\t\t\t\t\tTransform2D,\n\t\t\t\t\t{\n\t\t\t\t\t\tx: position.x,\n\t\t\t\t\t\ty: position.y,\n\t\t\t\t\t\twidth: size.width,\n\t\t\t\t\t\theight: size.height,\n\t\t\t\t\t\trotation: opts.rotation ?? 0,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\t[WidgetComp, { surface, type: widgetTypeId }],\n\t\t\t\t[WidgetData, { data }],\n\t\t\t\t[ZIndex, { value: opts.zIndex ?? 0 }],\n\t\t\t];\n\n\t\t\tif (archetype?.components) {\n\t\t\t\tfor (const init of archetype.components) inits.push(init);\n\t\t\t}\n\n\t\t\tif (opts.parent !== undefined) {\n\t\t\t\tinits.push([ParentFrame, { id: opts.parent }]);\n\t\t\t}\n\n\t\t\t// Interactive defaults — boolean or per-cap object.\n\t\t\tconst interactiveConfig = archetype?.interactive;\n\t\t\tconst caps =\n\t\t\t\tinteractiveConfig === false\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tselectable: false,\n\t\t\t\t\t\t\tdraggable: false,\n\t\t\t\t\t\t\tresizable: false,\n\t\t\t\t\t\t\tselectionFrame: false,\n\t\t\t\t\t\t\tsnapSource: false,\n\t\t\t\t\t\t\tsnapTarget: false,\n\t\t\t\t\t\t}\n\t\t\t\t\t: interactiveConfig === undefined || interactiveConfig === true\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tselectable: true,\n\t\t\t\t\t\t\t\tdraggable: true,\n\t\t\t\t\t\t\t\tresizable: true,\n\t\t\t\t\t\t\t\tselectionFrame: true,\n\t\t\t\t\t\t\t\tsnapSource: true,\n\t\t\t\t\t\t\t\tsnapTarget: true,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: (() => {\n\t\t\t\t\t\t\t\tconst selectable = interactiveConfig.selectable ?? false;\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\tselectable,\n\t\t\t\t\t\t\t\t\tdraggable: interactiveConfig.draggable ?? false,\n\t\t\t\t\t\t\t\t\tresizable: interactiveConfig.resizable ?? false,\n\t\t\t\t\t\t\t\t\tselectionFrame: interactiveConfig.selectionFrame ?? selectable,\n\t\t\t\t\t\t\t\t\tsnapSource: interactiveConfig.snapSource ?? false,\n\t\t\t\t\t\t\t\t\tsnapTarget: interactiveConfig.snapTarget ?? false,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t})();\n\t\t\tif (caps.selectable) inits.push([Selectable]);\n\t\t\tif (caps.draggable) inits.push([Draggable]);\n\t\t\tif (caps.resizable) inits.push([Resizable]);\n\t\t\tif (caps.selectionFrame) inits.push([SelectionFrame]);\n\t\t\tif (caps.snapSource) inits.push([SnapSource]);\n\t\t\tif (caps.snapTarget) inits.push([SnapTarget]);\n\n\t\t\tif (archetype?.tags) {\n\t\t\t\tfor (const tag of archetype.tags) inits.push([tag]);\n\t\t\t}\n\n\t\t\tconst entity = engine.createEntity(inits);\n\n\t\t\t// RFC-004 § Phase 5 open question 7 — a runtime spawn inside a\n\t\t\t// container must push onto the parent's `ContainerChildren.ids`\n\t\t\t// so the two-way ParentFrame ↔ ContainerChildren invariant is\n\t\t\t// upheld on the spawn path (consume already does this via\n\t\t\t// `applyMutation`). Only touches a container that actually has\n\t\t\t// the component attached — widgets outside the Phase 5 pattern\n\t\t\t// use `ParentFrame` without `ContainerChildren` and are left\n\t\t\t// alone.\n\t\t\tif (opts.parent !== undefined && world.hasComponent(opts.parent, ContainerChildren)) {\n\t\t\t\tconst current = world.getComponent(opts.parent, ContainerChildren);\n\t\t\t\tif (current && !current.ids.includes(entity)) {\n\t\t\t\t\tworld.setComponent(opts.parent, ContainerChildren, {\n\t\t\t\t\t\tids: [...current.ids, entity],\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn entity;\n\t\t},\n\n\t\tspawnAtCameraCenter(id: string, opts: Omit<SpawnOptions, 'at'> = {}): EntityId {\n\t\t\tconst camera = world.getResource(CameraResource);\n\t\t\tconst viewport = world.getResource(ViewportResource);\n\t\t\tconst centerX = camera.x + viewport.width / (2 * camera.zoom);\n\t\t\tconst centerY = camera.y + viewport.height / (2 * camera.zoom);\n\t\t\tconst archetype = archetypeRegistry.get(id);\n\t\t\tconst widget = widgetRegistry.get(archetype?.widget ?? id);\n\t\t\tconst size = opts.size ??\n\t\t\t\tarchetype?.defaultSize ??\n\t\t\t\twidget?.defaultSize ?? { width: 100, height: 100 };\n\t\t\treturn engine.spawn(id, {\n\t\t\t\t...opts,\n\t\t\t\tat: { x: centerX - size.width / 2, y: centerY - size.height / 2 },\n\t\t\t});\n\t\t},\n\n\t\tregisterWidget(widget: W) {\n\t\t\twidgetRegistry.register(widget);\n\t\t},\n\n\t\tgetWidget(type: string) {\n\t\t\treturn widgetRegistry.get(type);\n\t\t},\n\n\t\tgetWidgets() {\n\t\t\treturn widgetRegistry.getAll();\n\t\t},\n\n\t\tregisterArchetype(archetype: Archetype) {\n\t\t\tarchetypeRegistry.register(archetype);\n\t\t},\n\n\t\tgetArchetype(id: string) {\n\t\t\treturn archetypeRegistry.get(id);\n\t\t},\n\n\t\tdestroyEntity(id: EntityId) {\n\t\t\tspatialIndex.remove(id);\n\t\t\tworld.destroyEntity(id);\n\t\t\tmarkDirtyInternal();\n\t\t},\n\n\t\tget<T>(entity: EntityId, type: ComponentType<T>): T | undefined {\n\t\t\treturn world.getComponent(entity, type);\n\t\t},\n\n\t\tset<T>(entity: EntityId, type: ComponentType<T>, data: Partial<T>) {\n\t\t\tworld.setComponent(entity, type, data);\n\t\t\tmarkDirtyInternal();\n\t\t},\n\n\t\thas(entity: EntityId, type: ComponentType | TagType): boolean {\n\t\t\tif (type.__kind === 'tag') return world.hasTag(entity, type as TagType);\n\t\t\treturn world.hasComponent(entity, type as ComponentType);\n\t\t},\n\n\t\taddComponent<T>(entity: EntityId, type: ComponentType<T>, data?: T) {\n\t\t\tworld.addComponent(entity, type, data ?? type.defaults);\n\t\t\tmarkDirtyInternal();\n\t\t},\n\n\t\tremoveComponent(entity: EntityId, type: ComponentType) {\n\t\t\tworld.removeComponent(entity, type);\n\t\t\tmarkDirtyInternal();\n\t\t},\n\n\t\taddTag(entity: EntityId, type: TagType) {\n\t\t\tworld.addTag(entity, type);\n\t\t\tmarkDirtyInternal();\n\t\t},\n\n\t\tremoveTag(entity: EntityId, type: TagType) {\n\t\t\tworld.removeTag(entity, type);\n\t\t\tmarkDirtyInternal();\n\t\t},\n\n\t\tgetSchemaFor(entity: EntityId): StandardSchemaV1 | undefined {\n\t\t\tconst w = world.getComponent(entity, WidgetComp);\n\t\t\tif (!w) return undefined;\n\t\t\treturn widgetRegistry.get(w.type)?.schema;\n\t\t},\n\n\t\t// === Extensions ===\n\n\t\tregisterSystem(system: SystemDef) {\n\t\t\tscheduler.register(system);\n\t\t},\n\n\t\tremoveSystem(name: string) {\n\t\t\tscheduler.remove(name);\n\t\t},\n\n\t\t// === Camera ===\n\n\t\tgetCamera() {\n\t\t\treturn world.getResource(CameraResource);\n\t\t},\n\n\t\tpanBy(dx: number, dy: number) {\n\t\t\tconst camera = world.getResource(CameraResource);\n\t\t\tcamera.x -= dx / camera.zoom;\n\t\t\tcamera.y -= dy / camera.zoom;\n\t\t\tcameraChangedThisTick = true;\n\t\t\tmarkDirtyInternal();\n\t\t},\n\n\t\tpanTo(worldX: number, worldY: number) {\n\t\t\tconst camera = world.getResource(CameraResource);\n\t\t\tconst viewport = world.getResource(ViewportResource);\n\t\t\tcamera.x = worldX - viewport.width / (2 * camera.zoom);\n\t\t\tcamera.y = worldY - viewport.height / (2 * camera.zoom);\n\t\t\tcameraChangedThisTick = true;\n\t\t\tmarkDirtyInternal();\n\t\t},\n\n\t\tzoomAtPoint(screenX: number, screenY: number, delta: number) {\n\t\t\tconst camera = world.getResource(CameraResource);\n\t\t\tconst zoomConfig = world.getResource(ZoomConfigResource);\n\n\t\t\tconst worldBefore = screenToWorld(screenX, screenY, camera);\n\t\t\tconst newZoom = clamp(camera.zoom * (1 + delta), zoomConfig.min, zoomConfig.max);\n\t\t\tcamera.zoom = newZoom;\n\t\t\tcamera.x = worldBefore.x - screenX / newZoom;\n\t\t\tcamera.y = worldBefore.y - screenY / newZoom;\n\t\t\tcameraChangedThisTick = true;\n\t\t\tmarkDirtyInternal();\n\t\t},\n\n\t\tzoomTo(zoom: number) {\n\t\t\tconst camera = world.getResource(CameraResource);\n\t\t\tconst zoomConfig = world.getResource(ZoomConfigResource);\n\t\t\tconst viewport = world.getResource(ViewportResource);\n\t\t\tconst centerWorldX = camera.x + viewport.width / (2 * camera.zoom);\n\t\t\tconst centerWorldY = camera.y + viewport.height / (2 * camera.zoom);\n\t\t\tcamera.zoom = clamp(zoom, zoomConfig.min, zoomConfig.max);\n\t\t\tcamera.x = centerWorldX - viewport.width / (2 * camera.zoom);\n\t\t\tcamera.y = centerWorldY - viewport.height / (2 * camera.zoom);\n\t\t\tcameraChangedThisTick = true;\n\t\t\tmarkDirtyInternal();\n\t\t},\n\n\t\t/**\n\t\t * Toggle the camera's `gesturing` flag. Called by gesture handlers\n\t\t * (wheel debounced, touch pinch / pan start+end) so render layers\n\t\t * can defer expensive work — e.g. the R3F compositor skips zoom-band\n\t\t * repaints while gesturing is true so a continuous pinch doesn't\n\t\t * trigger a repaint storm across every visible widget.\n\t\t */\n\t\tsetGesturing(active: boolean) {\n\t\t\tconst camera = world.getResource(CameraResource);\n\t\t\tif (camera.gesturing === active) return;\n\t\t\tcamera.gesturing = active;\n\t\t\tcameraChangedThisTick = true;\n\t\t\tmarkDirtyInternal();\n\t\t},\n\n\t\tzoomToFit(entityIds?: EntityId[], padding = 50) {\n\t\t\tconst viewport = world.getResource(ViewportResource);\n\t\t\tif (viewport.width === 0) return;\n\n\t\t\tconst entities = entityIds ?? world.queryTagged(Active);\n\t\t\tif (entities.length === 0) return;\n\n\t\t\tlet minX = Number.POSITIVE_INFINITY;\n\t\t\tlet minY = Number.POSITIVE_INFINITY;\n\t\t\tlet maxX = Number.NEGATIVE_INFINITY;\n\t\t\tlet maxY = Number.NEGATIVE_INFINITY;\n\t\t\tfor (const e of entities) {\n\t\t\t\tconst t = world.getComponent(e, Transform2D);\n\t\t\t\tif (!t) continue;\n\t\t\t\tminX = Math.min(minX, t.x);\n\t\t\t\tminY = Math.min(minY, t.y);\n\t\t\t\tmaxX = Math.max(maxX, t.x + t.width);\n\t\t\t\tmaxY = Math.max(maxY, t.y + t.height);\n\t\t\t}\n\t\t\tif (!Number.isFinite(minX)) return;\n\n\t\t\tconst contentWidth = maxX - minX + padding * 2;\n\t\t\tconst contentHeight = maxY - minY + padding * 2;\n\t\t\tconst zoomConfig = world.getResource(ZoomConfigResource);\n\t\t\tconst zoom = clamp(\n\t\t\t\tMath.min(viewport.width / contentWidth, viewport.height / contentHeight),\n\t\t\t\tzoomConfig.min,\n\t\t\t\tzoomConfig.max,\n\t\t\t);\n\n\t\t\tconst camera = world.getResource(CameraResource);\n\t\t\tcamera.zoom = zoom;\n\t\t\tcamera.x = minX - padding - (viewport.width / zoom - contentWidth) / 2;\n\t\t\tcamera.y = minY - padding - (viewport.height / zoom - contentHeight) / 2;\n\t\t\tcameraChangedThisTick = true;\n\t\t\tmarkDirtyInternal();\n\t\t},\n\n\t\t// === Viewport ===\n\n\t\tsetViewport(width: number, height: number, dpr?: number) {\n\t\t\tworld.setResource(ViewportResource, { width, height, dpr: dpr ?? 1 });\n\t\t\tmarkDirtyInternal();\n\t\t},\n\n\t\t// === Commands + Undo/Redo ===\n\n\t\texecute(command: Command) {\n\t\t\tcommandBuffer.execute(command, world);\n\t\t\tmarkDirtyInternal();\n\t\t},\n\n\t\tbeginCommandGroup() {\n\t\t\tcommandBuffer.beginGroup();\n\t\t},\n\n\t\tendCommandGroup() {\n\t\t\tcommandBuffer.endGroup();\n\t\t},\n\n\t\tundo(): boolean {\n\t\t\tconst did = commandBuffer.undo(world);\n\t\t\tif (did) markDirtyInternal();\n\t\t\treturn did;\n\t\t},\n\n\t\tredo(): boolean {\n\t\t\tconst did = commandBuffer.redo(world);\n\t\t\tif (did) markDirtyInternal();\n\t\t\treturn did;\n\t\t},\n\n\t\tcanUndo(): boolean {\n\t\t\treturn commandBuffer.canUndo();\n\t\t},\n\n\t\tcanRedo(): boolean {\n\t\t\treturn commandBuffer.canRedo();\n\t\t},\n\n\t\t// === Pointer input — delegated to interaction runtime ===\n\n\t\thandlePointerDown(\n\t\t\tscreenX: number,\n\t\t\tscreenY: number,\n\t\t\tbutton: number,\n\t\t\tmodifiers: Modifiers,\n\t\t): PointerDirective {\n\t\t\treturn interaction.handlePointerDown(screenX, screenY, button, modifiers);\n\t\t},\n\n\t\thandlePointerMove(screenX: number, screenY: number, modifiers: Modifiers): PointerDirective {\n\t\t\treturn interaction.handlePointerMove(screenX, screenY, modifiers);\n\t\t},\n\n\t\thandlePointerUp(): PointerDirective {\n\t\t\treturn interaction.handlePointerUp();\n\t\t},\n\n\t\thandlePointerCancel(): void {\n\t\t\tinteraction.handlePointerCancel();\n\t\t},\n\n\t\tpickAt(screenX: number, screenY: number): EntityId | null {\n\t\t\treturn interaction.pickAt(screenX, screenY);\n\t\t},\n\n\t\thitTest(screenX, screenY) {\n\t\t\treturn interaction.hitTest(screenX, screenY);\n\t\t},\n\n\t\t// === RFC-008 Phase 3b — engine input API ===\n\n\t\tbeginDrag(entity, worldX, worldY) {\n\t\t\tinteraction.beginDrag(entity, worldX, worldY);\n\t\t},\n\t\tupdateDrag(entity, worldX, worldY) {\n\t\t\tinteraction.updateDrag(entity, worldX, worldY);\n\t\t},\n\t\tendDrag(entity, opts) {\n\t\t\tinteraction.endDrag(entity, opts);\n\t\t},\n\t\tgetDraggingEntity() {\n\t\t\treturn interaction.getDraggingEntity();\n\t\t},\n\n\t\tcancelInteraction() {\n\t\t\tinteraction.cancelInteraction();\n\t\t},\n\n\t\tbeginResize(entity, handle, worldX, worldY) {\n\t\t\treturn interaction.beginResize(entity, handle, worldX, worldY);\n\t\t},\n\t\tupdateResize(entity, worldX, worldY) {\n\t\t\tinteraction.updateResize(entity, worldX, worldY);\n\t\t},\n\t\tendResize(entity, opts) {\n\t\t\tinteraction.endResize(entity, opts);\n\t\t},\n\t\tisResizing() {\n\t\t\treturn interaction.isResizing();\n\t\t},\n\t\tgetResizingEntity() {\n\t\t\treturn interaction.getResizingEntity();\n\t\t},\n\n\t\tbeginMarquee(worldX, worldY) {\n\t\t\tinteraction.beginMarquee(worldX, worldY);\n\t\t},\n\t\tupdateMarquee(worldX, worldY) {\n\t\t\tinteraction.updateMarquee(worldX, worldY);\n\t\t},\n\t\tendMarquee() {\n\t\t\tinteraction.endMarquee();\n\t\t},\n\t\tisMarqueeActive() {\n\t\t\treturn interaction.isMarqueeActive();\n\t\t},\n\n\t\t// === Selection ===\n\n\t\tgetSelectedEntities(): EntityId[] {\n\t\t\treturn world.queryTagged(Selected);\n\t\t},\n\n\t\tselectEntity(entity: EntityId, additive: boolean): void {\n\t\t\tinteraction.selectEntity(entity, additive);\n\t\t},\n\n\t\tclearSelection(): void {\n\t\t\tinteraction.clearSelection();\n\t\t},\n\n\t\tgetHoveredEntity(): EntityId | null {\n\t\t\treturn interaction.getHoveredEntity();\n\t\t},\n\n\t\tsetHoveredEntity(entity: EntityId | null): void {\n\t\t\tinteraction.setHoveredEntity(entity);\n\t\t},\n\n\t\tupdateHover(screenX: number, screenY: number): void {\n\t\t\tinteraction.updateHover(screenX, screenY);\n\t\t},\n\n\t\t// === Snap Guides ===\n\n\t\tgetSnapGuides() {\n\t\t\treturn interaction.getSnapGuides();\n\t\t},\n\n\t\tgetEqualSpacing() {\n\t\t\treturn interaction.getEqualSpacing();\n\t\t},\n\n\t\tsetSnapEnabled(on: boolean) {\n\t\t\tsnapEnabled = on;\n\t\t\tmarkDirtyInternal();\n\t\t},\n\n\t\tsetSnapThreshold(worldPx: number) {\n\t\t\tsnapThreshold = worldPx;\n\t\t\tmarkDirtyInternal();\n\t\t},\n\n\t\tgetSnapGuidesVisible() {\n\t\t\treturn snapGuidesVisible;\n\t\t},\n\n\t\tsetSnapGuidesVisible(on: boolean) {\n\t\t\tsnapGuidesVisible = on;\n\t\t\tmarkDirtyInternal();\n\t\t},\n\n\t\t// === Navigation ===\n\n\t\tenterContainer(entity: EntityId) {\n\t\t\t// Only Container-tagged entities are enterable. An empty container\n\t\t\t// (no Children component yet) is still allowed — you enter it and\n\t\t\t// see an empty sub-canvas, which is consistent with a just-created\n\t\t\t// container that will be populated later.\n\t\t\tif (!world.hasComponent(entity, Container)) return;\n\n\t\t\tconst navStack = world.getResource(NavigationStackResource);\n\t\t\tconst camera = world.getResource(CameraResource);\n\n\t\t\t// Snapshot the outgoing frame's camera to its home so navigating\n\t\t\t// back restores the same view.\n\t\t\tconst outgoing = navStack.frames[navStack.frames.length - 1].containerId;\n\t\t\tif (outgoing === null) {\n\t\t\t\tworld.setResource(RootCameraResource, {\n\t\t\t\t\tx: camera.x,\n\t\t\t\t\ty: camera.y,\n\t\t\t\t\tzoom: camera.zoom,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tworld.setComponent(outgoing, ContainerCamera, {\n\t\t\t\t\tx: camera.x,\n\t\t\t\t\ty: camera.y,\n\t\t\t\t\tzoom: camera.zoom,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tnavStack.frames.push({ containerId: entity });\n\t\t\tnavStack.changed = true;\n\n\t\t\t// Restore the incoming container's camera (default to origin +\n\t\t\t// 1× if the container has never been entered before).\n\t\t\tconst incoming = world.getComponent(entity, ContainerCamera) ?? {\n\t\t\t\tx: 0,\n\t\t\t\ty: 0,\n\t\t\t\tzoom: 1,\n\t\t\t};\n\t\t\tcamera.x = incoming.x;\n\t\t\tcamera.y = incoming.y;\n\t\t\tcamera.zoom = incoming.zoom;\n\n\t\t\tinteraction.clearSelection();\n\t\t\tcameraChangedThisTick = true;\n\t\t\tmarkDirtyInternal();\n\t\t},\n\n\t\texitContainer() {\n\t\t\tconst navStack = world.getResource(NavigationStackResource);\n\t\t\tif (navStack.frames.length <= 1) return;\n\n\t\t\tconst camera = world.getResource(CameraResource);\n\n\t\t\t// Snapshot the outgoing container's camera so re-entering later\n\t\t\t// restores the view.\n\t\t\tconst outgoing = navStack.frames[navStack.frames.length - 1].containerId;\n\t\t\tif (outgoing !== null) {\n\t\t\t\tworld.setComponent(outgoing, ContainerCamera, {\n\t\t\t\t\tx: camera.x,\n\t\t\t\t\ty: camera.y,\n\t\t\t\t\tzoom: camera.zoom,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tnavStack.frames.pop();\n\t\t\tnavStack.changed = true;\n\n\t\t\t// Load the newly-current frame's camera (parent container or root).\n\t\t\tconst parent = navStack.frames[navStack.frames.length - 1].containerId;\n\t\t\tconst incoming =\n\t\t\t\tparent === null\n\t\t\t\t\t? world.getResource(RootCameraResource)\n\t\t\t\t\t: (world.getComponent(parent, ContainerCamera) ?? { x: 0, y: 0, zoom: 1 });\n\t\t\tcamera.x = incoming.x;\n\t\t\tcamera.y = incoming.y;\n\t\t\tcamera.zoom = incoming.zoom;\n\n\t\t\tinteraction.clearSelection();\n\t\t\tcameraChangedThisTick = true;\n\t\t\tmarkDirtyInternal();\n\t\t},\n\n\t\tgetActiveContainer(): EntityId | null {\n\t\t\tconst navStack = world.getResource(NavigationStackResource);\n\t\t\treturn navStack.frames[navStack.frames.length - 1].containerId;\n\t\t},\n\n\t\tgetNavigationDepth(): number {\n\t\t\treturn world.getResource(NavigationStackResource).frames.length - 1;\n\t\t},\n\n\t\t// === Frame ===\n\n\t\tmarkDirty() {\n\t\t\tmarkDirtyInternal();\n\t\t},\n\n\t\tprofiler,\n\n\t\ttick() {\n\t\t\tprofiler.beginFrame(world.currentTick);\n\n\t\t\t// INVARIANT (RFC-004 Phase 0c): capture `navStack.changed` into a\n\t\t\t// local `const` BEFORE `scheduler.execute` runs. `navigationFilter`\n\t\t\t// mutates `navStack.changed = false` mid-tick as its reset signal;\n\t\t\t// reading the flag after systems execute would always see false\n\t\t\t// and this-tick navigation pushes/pops would silently miss their\n\t\t\t// FrameChanges.navigationChanged notification. Do not reorder.\n\t\t\tconst navStackPreTick = world.getResource(NavigationStackResource);\n\t\t\tconst navigationChangedThisTick = navStackPreTick?.changed ?? false;\n\n\t\t\t// Run all systems\n\t\t\tscheduler.execute(world);\n\n\t\t\t// RFC-004 § Phase 4 — fly-back completion poll. Runs after the\n\t\t\t// tween system so an in-flight tween has had a chance to\n\t\t\t// remove itself this tick; if it's gone and we're still in\n\t\t\t// `flyingBack` mode, finalize (remove Dragging, restore ZIndex).\n\t\t\tinteraction.runFlyBackSystem();\n\n\t\t\t// Derive cursor from interaction state + hover.\n\t\t\tinteraction.runCursorSystem();\n\n\t\t\t// Compute visible entities for renderers\n\t\t\tprofiler.beginVisibility();\n\t\t\tconst newVisible: VisibleEntity[] = [];\n\t\t\tconst newVisibleSet = new Set<EntityId>();\n\n\t\t\tfor (const entity of world.query(WidgetComp, Visible)) {\n\t\t\t\tconst t = world.getComponent(entity, Transform2D);\n\t\t\t\tconst widget = world.getComponent(entity, WidgetComp);\n\t\t\t\tconst bp = world.getComponent(entity, WidgetBreakpoint);\n\t\t\t\tconst zIdx = world.getComponent(entity, ZIndex);\n\t\t\t\tif (!t || !widget) continue;\n\n\t\t\t\tnewVisibleSet.add(entity);\n\t\t\t\tnewVisible.push({\n\t\t\t\t\tentityId: entity,\n\t\t\t\t\tx: t.x,\n\t\t\t\t\ty: t.y,\n\t\t\t\t\twidth: t.width,\n\t\t\t\t\theight: t.height,\n\t\t\t\t\tbreakpoint: bp?.current ?? 'normal',\n\t\t\t\t\tzIndex: zIdx?.value ?? 0,\n\t\t\t\t\tsurface: widget.surface,\n\t\t\t\t\twidgetType: widget.type,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tnewVisible.sort((a, b) => a.zIndex - b.zIndex);\n\t\t\tprofiler.endVisibility();\n\n\t\t\tconst entered: EntityId[] = [];\n\t\t\tconst exited: EntityId[] = [];\n\t\t\tfor (const entity of newVisibleSet) {\n\t\t\t\tif (!prevVisible.has(entity)) entered.push(entity);\n\t\t\t}\n\t\t\tfor (const entity of prevVisible) {\n\t\t\t\tif (!newVisibleSet.has(entity)) exited.push(entity);\n\t\t\t}\n\n\t\t\tframeChanges = {\n\t\t\t\tpositionsChanged: world.queryChanged(Transform2D),\n\t\t\t\tbreakpointsChanged: world.queryChanged(WidgetBreakpoint),\n\t\t\t\tzIndicesChanged: world.queryChanged(ZIndex),\n\t\t\t\tentered,\n\t\t\t\texited,\n\t\t\t\tcameraChanged: cameraChangedThisTick,\n\t\t\t\tnavigationChanged: navigationChangedThisTick,\n\t\t\t\tselectionChanged: selectionChangedThisTick,\n\t\t\t\tlayersChanged: world.queryChanged(Layer).length > 0,\n\t\t\t};\n\n\t\t\tcurrentVisible = newVisible;\n\t\t\tprevVisible = newVisibleSet;\n\t\t\tcameraChangedThisTick = false;\n\t\t\tselectionChangedThisTick = false;\n\n\t\t\tprofiler.endFrame(world.entityCount, newVisible.length);\n\n\t\t\tworld.clearDirty();\n\t\t\tworld.incrementTick();\n\t\t\tworld.emitFrame();\n\n\t\t\tdirty = false;\n\n\t\t\t// RFC-004 § Phase 2/4 — keep the rAF loop alive while any\n\t\t\t// `TransformTween` is still running. The `Transform2D` reactive\n\t\t\t// observer deliberately skips `markDirty` (it only refreshes the\n\t\t\t// spatial index), so a tween's own Transform2D writes don't\n\t\t\t// re-dirty the engine. Without this post-reset re-dirty, the\n\t\t\t// engine would tick once into the animation and then freeze the\n\t\t\t// card mid-fly-back. Cheap: bails after one iteration.\n\t\t\tfor (const _ of world.query(TransformTween)) {\n\t\t\t\tdirty = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t},\n\n\t\tflushIfDirty(): boolean {\n\t\t\tif (!dirty) return false;\n\t\t\tengine.tick();\n\t\t\treturn true;\n\t\t},\n\n\t\t// === Output ===\n\n\t\tgetVisibleEntities(): VisibleEntity[] {\n\t\t\treturn currentVisible;\n\t\t},\n\n\t\tgetFrameChanges(): FrameChanges {\n\t\t\treturn frameChanges;\n\t\t},\n\n\t\tgetSpatialIndex(): SpatialIndex {\n\t\t\treturn spatialIndex;\n\t\t},\n\n\t\t// === Events ===\n\n\t\tonFrame(handler: () => void): Unsubscribe {\n\t\t\treturn world.onFrame(handler);\n\t\t},\n\n\t\t// === Lifecycle ===\n\n\t\tdestroy() {\n\t\t\tfor (const unsub of unsubscribers) {\n\t\t\t\tunsub();\n\t\t\t}\n\t\t\tunsubscribers.length = 0;\n\n\t\t\tcommandBuffer.clear();\n\n\t\t\tprofiler.setEnabled(false);\n\t\t\tprofiler.clear();\n\n\t\t\tspatialIndex.clear();\n\t\t},\n\t};\n\n\treturn engine;\n}\n","import type { EntityId, World } from '@jamesyong42/reactive-ecs';\nimport { ParentFrame } from './components.js';\n\n/**\n * Walks the `ParentFrame` chain from `descendant` upward and returns\n * true iff `candidate` appears on that chain (inclusive check excluded:\n * an entity is not considered its own ancestor).\n *\n * Used by `CardContainer`'s default `canAccept` as a cycle-guard so\n * dragging a container onto one of its own descendants is rejected\n * before any mutation fires (RFC-004 § Phase 5). Cheap — the chain is\n * typically 0–3 deep. Capped at a sane depth to defend against\n * pathological / malformed worlds.\n */\nexport function isFrameAncestorOf(\n\tworld: World,\n\tcandidate: EntityId,\n\tdescendant: EntityId,\n): boolean {\n\tif (candidate === descendant) return false;\n\tlet current: EntityId = descendant;\n\tfor (let i = 0; i < 64; i++) {\n\t\tconst pf: { id: EntityId } | undefined = world.getComponent(current, ParentFrame);\n\t\tif (!pf) return false;\n\t\tif (pf.id === candidate) return true;\n\t\tcurrent = pf.id;\n\t}\n\treturn false;\n}\n","import type { EntityId } from '@jamesyong42/reactive-ecs';\nimport { useCallback } from 'react';\nimport { Children, Selected, WidgetBreakpoint, WidgetData } from '../../ecs/components.js';\nimport type { Breakpoint } from '../../ecs/resources.js';\nimport { useLayoutEngine } from '../context/engine-context.js';\nimport { useComponent, useTag } from './ecs.js';\n\n/**\n * Returns the custom data attached to a widget entity.\n * Use the generic parameter for type safety: `useWidgetData<MyData>(entityId)`. Re-renders when data changes.\n */\nexport function useWidgetData<T = Record<string, unknown>>(entityId: EntityId): T {\n\tconst comp = useComponent(entityId, WidgetData);\n\treturn (comp?.data ?? {}) as T;\n}\n\n/**\n * Returns the current responsive breakpoint for a widget based on its screen-space size.\n * Re-renders when the breakpoint changes.\n */\nexport function useBreakpoint(entityId: EntityId): Breakpoint {\n\tconst comp = useComponent(entityId, WidgetBreakpoint);\n\treturn comp?.current ?? 'normal';\n}\n\n/**\n * Returns child entity IDs of a container entity.\n * Re-renders when children are added or removed.\n */\nexport function useChildren(entityId: EntityId): EntityId[] {\n\tconst comp = useComponent(entityId, Children);\n\treturn comp?.ids ?? [];\n}\n\n/**\n * Returns whether the entity is currently selected.\n * Re-renders when the entity's selection state changes.\n */\nexport function useIsSelected(entityId: EntityId): boolean {\n\treturn useTag(entityId, Selected);\n}\n\n/**\n * Returns a function to update the widget's custom data.\n * Merges the patch into existing data via shallow spread.\n */\nexport function useUpdateWidget(entityId: EntityId): (patch: Record<string, unknown>) => void {\n\tconst engine = useLayoutEngine();\n\treturn useCallback(\n\t\t(patch: Record<string, unknown>) => {\n\t\t\tconst existing = engine.get(entityId, WidgetData);\n\t\t\tif (existing) {\n\t\t\t\tengine.set(entityId, WidgetData, {\n\t\t\t\t\tdata: { ...existing.data, ...patch },\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t\t[engine, entityId],\n\t);\n}\n","/**\n * Native HTML elements whose pointer / click events should never start a\n * canvas-level drag, marquee, selection, or navigation. The browser's\n * natural focus / activation / click synthesis runs unimpeded; the canvas\n * just stays out. Authors who want additional opt-out elements call\n * `e.stopPropagation()` from their own handler — it halts the bubble\n * before the native event reaches the canvas container, so neither\n * adapter sees it.\n *\n * Shared between PointerAdapter (skips `pointerdown`) and ClickAdapter\n * (skips `click` / `dblclick` / `contextmenu`) so the two adapters apply\n * consistent rules.\n */\nexport const NATIVE_INTERACTIVE_SELECTOR = 'button, input, textarea, select, [contenteditable]';\n","import { screenToWorld } from '../../../ecs/math.js';\nimport { inputLog } from '../debug.js';\nimport type { Adapter, Button, InputEvent, InputManager, InputSource } from '../types.js';\nimport { NATIVE_INTERACTIVE_SELECTOR } from './native-interactive.js';\n\n/**\n * Click / dblclick / contextmenu adapter (RFC-008 v6).\n *\n * The browser fires click / dblclick / contextmenu through a native event\n * channel that's distinct from `pointerdown` / `pointerup` — they're\n * synthesised after the pointer cycle completes (down → up with little\n * movement, double-click within a short window, right-click). Pre-v6 the\n * canvas had no adapter for these: R3F registered its own listeners on\n * the container via `EventManager.connect`, and the InputManager pipeline\n * never saw them. Two side effects:\n *\n * 1. A click on a mesh that called `setPointerCapture` skipped the\n * `tap` recognizer (capture-claim) so the engine's selection logic\n * didn't run — the widget didn't select.\n * 2. Clicks couldn't be observed by recognizers / handlers / external\n * listeners through the manager, only via direct R3F mesh handlers.\n *\n * v6 makes click / dblclick / contextmenu first-class `InputEvent`s. The\n * adapter dispatches them through `InputManager.dispatch`, which routes\n * to the surface router (R3FRouter for webgl widgets — invokes the\n * mesh's `onClick` etc.) and fires engine handlers (which run\n * `selectEntity` for click, `enterContainer` for dblclick).\n *\n * `preventDefault` discipline:\n * - `click` / `dblclick`: never. Browser focus / activation must run.\n * - `contextmenu`: always. Canvas isn't a place for the browser context\n * menu.\n *\n * Native-interactive skip mirrors `PointerAdapter`: a click landing on a\n * `<button>` / `<input>` / etc. inside a DOM widget is suppressed at the\n * adapter so the widget body doesn't get re-selected over the user's\n * intent (typing, button activation, etc.). Authors who want canvas-level\n * coexistence with their own native interactive call\n * `e.stopPropagation()` so the click never reaches the container.\n */\nexport class ClickAdapter implements Adapter {\n\tattach(container: HTMLElement, manager: InputManager): () => void {\n\t\tconst make = (type: 'click' | 'dblclick' | 'contextmenu', e: MouseEvent): InputEvent => {\n\t\t\tconst rect = container.getBoundingClientRect();\n\t\t\tconst screen = { x: e.clientX - rect.left, y: e.clientY - rect.top };\n\t\t\tconst camera = manager.engine.getCamera();\n\t\t\tconst world = screenToWorld(screen.x, screen.y, camera);\n\t\t\tconst button: Button = (e.button as 0 | 1 | 2) ?? null;\n\n\t\t\treturn {\n\t\t\t\ttype,\n\t\t\t\tsource: clickSource(e),\n\t\t\t\t// Modern browsers fire `PointerEvent` for click / dblclick /\n\t\t\t\t// contextmenu (it extends MouseEvent), so `pointerId` is often\n\t\t\t\t// available; older paths fall back to 0. Recognizers don't\n\t\t\t\t// observe click events, so this only matters for routers and\n\t\t\t\t// downstream handlers that want to correlate with the\n\t\t\t\t// preceding pointerdown.\n\t\t\t\tpointerId: pointerIdOf(e),\n\t\t\t\tprimary: true,\n\t\t\t\tscreen,\n\t\t\t\tworld,\n\t\t\t\tbutton,\n\t\t\t\tmodifiers: {\n\t\t\t\t\tshift: e.shiftKey,\n\t\t\t\t\tctrl: e.ctrlKey,\n\t\t\t\t\talt: e.altKey,\n\t\t\t\t\tmeta: e.metaKey,\n\t\t\t\t},\n\t\t\t\ttimestamp: e.timeStamp,\n\t\t\t\tnative: e,\n\t\t\t};\n\t\t};\n\n\t\tconst onClick = (e: MouseEvent) => {\n\t\t\tconst target = e.target as HTMLElement | null;\n\t\t\tconst targetTag = target ? `${target.tagName}${target.id ? `#${target.id}` : ''}` : 'null';\n\t\t\tif (target?.closest(NATIVE_INTERACTIVE_SELECTOR)) {\n\t\t\t\tinputLog('Adapter', `click → SKIPPED (native interactive)`, {\n\t\t\t\t\ttarget: targetTag,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tinputLog('Adapter', `click → InputManager`, {\n\t\t\t\tscreen: {\n\t\t\t\t\tx: e.clientX - container.getBoundingClientRect().left,\n\t\t\t\t\ty: e.clientY - container.getBoundingClientRect().top,\n\t\t\t\t},\n\t\t\t\ttarget: targetTag,\n\t\t\t});\n\t\t\tmanager.dispatch(make('click', e));\n\t\t};\n\n\t\tconst onDblClick = (e: MouseEvent) => {\n\t\t\tconst target = e.target as HTMLElement | null;\n\t\t\tif (target?.closest(NATIVE_INTERACTIVE_SELECTOR)) return;\n\t\t\tinputLog('Adapter', `dblclick → InputManager`);\n\t\t\tmanager.dispatch(make('dblclick', e));\n\t\t};\n\n\t\tconst onContextMenu = (e: MouseEvent) => {\n\t\t\te.preventDefault();\n\t\t\tconst target = e.target as HTMLElement | null;\n\t\t\tif (target?.closest(NATIVE_INTERACTIVE_SELECTOR)) return;\n\t\t\tinputLog('Adapter', `contextmenu → InputManager`);\n\t\t\tmanager.dispatch(make('contextmenu', e));\n\t\t};\n\n\t\tcontainer.addEventListener('click', onClick);\n\t\tcontainer.addEventListener('dblclick', onDblClick);\n\t\tcontainer.addEventListener('contextmenu', onContextMenu);\n\n\t\treturn () => {\n\t\t\tcontainer.removeEventListener('click', onClick);\n\t\t\tcontainer.removeEventListener('dblclick', onDblClick);\n\t\t\tcontainer.removeEventListener('contextmenu', onContextMenu);\n\t\t};\n\t}\n}\n\nfunction pointerIdOf(e: MouseEvent): number {\n\tconst pe = e as Partial<PointerEvent>;\n\treturn typeof pe.pointerId === 'number' ? pe.pointerId : 0;\n}\n\nfunction clickSource(e: MouseEvent): InputSource {\n\tconst pe = e as Partial<PointerEvent>;\n\tswitch (pe.pointerType) {\n\t\tcase 'mouse':\n\t\t\treturn 'mouse';\n\t\tcase 'pen':\n\t\t\treturn 'pen';\n\t\tcase 'touch':\n\t\t\treturn 'touch';\n\t\tdefault:\n\t\t\treturn 'mouse';\n\t}\n}\n","import { screenToWorld } from '../../../ecs/math.js';\nimport { inputLog } from '../debug.js';\nimport type { Adapter, Button, InputEvent, InputManager, InputSource } from '../types.js';\nimport { NATIVE_INTERACTIVE_SELECTOR } from './native-interactive.js';\n\n/**\n * Native pointer-event adapter (RFC-008). Listens for pointerdown / move /\n * up / cancel / pointerleave on the canvas container, normalises into\n * `InputEvent`s, and dispatches via `manager.dispatch(...)`.\n *\n * Single-finger and multi-finger touch flow through this adapter via the\n * browser's touch-to-pointer synthesis (`touch-action: none` on the\n * container is what makes synthesis reliable). PinchRecognizer counts\n * simultaneous active touch-source pointer IDs from these events.\n *\n * `preventDefault` discipline:\n * - Pointer events: never. Bubble must continue so widget React handlers\n * fire and so widgets can call `setPointerCapture` to claim drags.\n * - `contextmenu`: handled by `ClickAdapter`, not here.\n *\n * `pointerdown` on a native interactive target (button, input, etc.) is\n * suppressed at the adapter so a button click inside a DOM widget can't\n * spawn a marquee or drag. Move / up / cancel still flow so hover chrome\n * stays accurate.\n *\n * `pointerleave` is dispatched as its own InputEvent type so engine hover\n * chrome can clear when the cursor exits the canvas — without an inline\n * listener outside the InputManager pipeline (RFC-008 v6 unification).\n */\nexport class PointerAdapter implements Adapter {\n\tattach(container: HTMLElement, manager: InputManager): () => void {\n\t\tconst lastByPointerId = new Map<number, { x: number; y: number }>();\n\n\t\tconst make = (\n\t\t\ttype: 'down' | 'move' | 'up' | 'cancel' | 'pointerleave',\n\t\t\te: PointerEvent,\n\t\t): InputEvent => {\n\t\t\tconst rect = container.getBoundingClientRect();\n\t\t\tconst screen = { x: e.clientX - rect.left, y: e.clientY - rect.top };\n\t\t\tconst camera = manager.engine.getCamera();\n\t\t\tconst world = screenToWorld(screen.x, screen.y, camera);\n\t\t\tconst last = lastByPointerId.get(e.pointerId);\n\t\t\tconst delta = last ? { x: screen.x - last.x, y: screen.y - last.y } : undefined;\n\n\t\t\tconst button: Button =\n\t\t\t\ttype === 'down' || type === 'up' ? ((e.button as 0 | 1 | 2) ?? null) : null;\n\n\t\t\treturn {\n\t\t\t\ttype,\n\t\t\t\tsource: pointerSource(e),\n\t\t\t\tpointerId: e.pointerId,\n\t\t\t\tprimary: e.isPrimary,\n\t\t\t\tscreen,\n\t\t\t\tworld,\n\t\t\t\tdelta,\n\t\t\t\tbutton,\n\t\t\t\tmodifiers: {\n\t\t\t\t\tshift: e.shiftKey,\n\t\t\t\t\tctrl: e.ctrlKey,\n\t\t\t\t\talt: e.altKey,\n\t\t\t\t\tmeta: e.metaKey,\n\t\t\t\t},\n\t\t\t\ttimestamp: e.timeStamp,\n\t\t\t\tnative: e,\n\t\t\t};\n\t\t};\n\n\t\tconst onDown = (e: PointerEvent) => {\n\t\t\tconst rect = container.getBoundingClientRect();\n\t\t\tconst screen = { x: e.clientX - rect.left, y: e.clientY - rect.top };\n\t\t\tlastByPointerId.set(e.pointerId, screen);\n\n\t\t\tconst target = e.target as HTMLElement | null;\n\t\t\tconst targetTag = target ? `${target.tagName}${target.id ? `#${target.id}` : ''}` : 'null';\n\t\t\tif (target?.closest(NATIVE_INTERACTIVE_SELECTOR)) {\n\t\t\t\tinputLog('Adapter', `pointerdown → SKIPPED (native interactive)`, {\n\t\t\t\t\tpointerId: e.pointerId,\n\t\t\t\t\ttarget: targetTag,\n\t\t\t\t\tsource: e.pointerType,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tinputLog('Adapter', `pointerdown id=${e.pointerId} → InputManager`, {\n\t\t\t\tpointerId: e.pointerId,\n\t\t\t\tscreen,\n\t\t\t\tbutton: e.button,\n\t\t\t\tsource: e.pointerType,\n\t\t\t\ttarget: targetTag,\n\t\t\t});\n\n\t\t\tconst event = make('down', e);\n\t\t\tmanager.dispatch({ ...event, delta: undefined });\n\t\t};\n\n\t\tconst onMove = (e: PointerEvent) => {\n\t\t\tconst event = make('move', e);\n\t\t\tlastByPointerId.set(e.pointerId, { x: event.screen.x, y: event.screen.y });\n\t\t\tinputLog('Adapter', `pointermove id=${e.pointerId} → InputManager`, {\n\t\t\t\ttype: 'move',\n\t\t\t\tpointerId: e.pointerId,\n\t\t\t\tscreen: event.screen,\n\t\t\t});\n\t\t\tmanager.dispatch(event);\n\t\t};\n\n\t\tconst onUp = (e: PointerEvent) => {\n\t\t\tinputLog('Adapter', `pointerup id=${e.pointerId} → InputManager`, {\n\t\t\t\tpointerId: e.pointerId,\n\t\t\t\tsource: e.pointerType,\n\t\t\t});\n\t\t\tmanager.dispatch(make('up', e));\n\t\t\tlastByPointerId.delete(e.pointerId);\n\t\t};\n\n\t\tconst onCancel = (e: PointerEvent) => {\n\t\t\tinputLog('Adapter', `pointercancel id=${e.pointerId} → InputManager`, {\n\t\t\t\tpointerId: e.pointerId,\n\t\t\t});\n\t\t\tmanager.dispatch(make('cancel', e));\n\t\t\tlastByPointerId.delete(e.pointerId);\n\t\t};\n\n\t\tconst onLeave = (e: PointerEvent) => {\n\t\t\tinputLog('Adapter', `pointerleave id=${e.pointerId} → InputManager`, {\n\t\t\t\tpointerId: e.pointerId,\n\t\t\t\tsource: e.pointerType,\n\t\t\t});\n\t\t\tmanager.dispatch(make('pointerleave', e));\n\t\t\tlastByPointerId.delete(e.pointerId);\n\t\t};\n\n\t\tcontainer.addEventListener('pointerdown', onDown);\n\t\tcontainer.addEventListener('pointermove', onMove);\n\t\tcontainer.addEventListener('pointerup', onUp);\n\t\tcontainer.addEventListener('pointercancel', onCancel);\n\t\tcontainer.addEventListener('pointerleave', onLeave);\n\n\t\treturn () => {\n\t\t\tcontainer.removeEventListener('pointerdown', onDown);\n\t\t\tcontainer.removeEventListener('pointermove', onMove);\n\t\t\tcontainer.removeEventListener('pointerup', onUp);\n\t\t\tcontainer.removeEventListener('pointercancel', onCancel);\n\t\t\tcontainer.removeEventListener('pointerleave', onLeave);\n\t\t\tlastByPointerId.clear();\n\t\t};\n\t}\n}\n\nfunction pointerSource(e: PointerEvent): InputSource {\n\tswitch (e.pointerType) {\n\t\tcase 'mouse':\n\t\t\treturn 'mouse';\n\t\tcase 'pen':\n\t\t\treturn 'pen';\n\t\tcase 'touch':\n\t\t\treturn 'touch';\n\t\tdefault:\n\t\t\treturn 'mouse';\n\t}\n}\n","import { screenToWorld } from '../../../ecs/math.js';\nimport { inputLog } from '../debug.js';\nimport type { Adapter, InputEvent, InputManager } from '../types.js';\n\n/**\n * Wheel adapter (RFC-008). Listens for native wheel events on the canvas\n * container, normalises into `InputEvent`s with a `wheelDelta` payload,\n * and dispatches via `manager.dispatch(...)`.\n *\n * Always calls `preventDefault()` — we always own canvas pan/zoom from\n * wheel input. Widgets that want internal scroll content call\n * `e.stopPropagation()` on `wheel` from inside their React tree, which\n * halts the bubble before it reaches this listener.\n *\n * `wheelDelta.pinch` is true when ctrl or meta is held — browsers\n * translate trackpad pinch into ctrl+wheel events; the engine wheel\n * handler interprets pinch as zoom and plain wheel as pan.\n */\nexport class WheelAdapter implements Adapter {\n\tattach(container: HTMLElement, manager: InputManager): () => void {\n\t\tconst onWheel = (e: WheelEvent) => {\n\t\t\te.preventDefault();\n\t\t\tconst rect = container.getBoundingClientRect();\n\t\t\tconst screen = { x: e.clientX - rect.left, y: e.clientY - rect.top };\n\t\t\tconst camera = manager.engine.getCamera();\n\t\t\tconst world = screenToWorld(screen.x, screen.y, camera);\n\n\t\t\tconst event: InputEvent = {\n\t\t\t\ttype: 'wheel',\n\t\t\t\tsource: 'wheel',\n\t\t\t\tpointerId: 0,\n\t\t\t\tprimary: true,\n\t\t\t\tscreen,\n\t\t\t\tworld,\n\t\t\t\twheelDelta: {\n\t\t\t\t\tdx: e.deltaX,\n\t\t\t\t\tdy: e.deltaY,\n\t\t\t\t\tpinch: e.ctrlKey || e.metaKey,\n\t\t\t\t},\n\t\t\t\tmodifiers: {\n\t\t\t\t\tshift: e.shiftKey,\n\t\t\t\t\tctrl: e.ctrlKey,\n\t\t\t\t\talt: e.altKey,\n\t\t\t\t\tmeta: e.metaKey,\n\t\t\t\t},\n\t\t\t\ttimestamp: e.timeStamp,\n\t\t\t\tnative: e,\n\t\t\t};\n\t\t\tinputLog('Adapter', `wheel → InputManager`, {\n\t\t\t\ttype: 'wheel',\n\t\t\t\tscreen,\n\t\t\t\tdx: e.deltaX,\n\t\t\t\tdy: e.deltaY,\n\t\t\t\tpinch: e.ctrlKey || e.metaKey,\n\t\t\t});\n\t\t\tmanager.dispatch(event);\n\t\t};\n\n\t\tcontainer.addEventListener('wheel', onWheel, { passive: false });\n\t\treturn () => {\n\t\t\tcontainer.removeEventListener('wheel', onWheel);\n\t\t};\n\t}\n}\n","/**\n * Centralised input timing windows, dead zones, and debounce intervals\n * (RFC-008). Single source of truth — recognizers and engine handlers\n * import from here. Replaces today's per-file constant duplication\n * (`PointerEventBus`, `TouchEventBus`, the wheel `useEffect`).\n */\n\n/** Mouse / pen drag dead zone in screen pixels. Matches today's `interaction-constants.ts`. */\nexport const DEAD_ZONE_MOUSE_PX = 4;\n\n/** Touch drag dead zone in screen pixels. Matches today's `interaction-constants.ts`. */\nexport const DEAD_ZONE_TOUCH_PX = 8;\n\n/** Quick-up window after pointerdown to count as a tap (no significant movement). */\nexport const TAP_WINDOW_MS = 250;\n\n/** Window between two taps to register as a double-tap. */\nexport const DOUBLE_TAP_WINDOW_MS = 300;\n\n/** Spatial threshold between two taps (centroid) to register as a double-tap. */\nexport const DOUBLE_TAP_DIST_PX = 30;\n\n/** Idle window after a viewport gesture before clearing `engine.setGesturing(false)`. */\nexport const GESTURING_IDLE_MS = 200;\n\n/** Double-tap zoom level cycle. */\nexport const ZOOM_TARGETS = [1, 2] as const;\n\n/** If camera zoom is below this, double-tap zoom targets ZOOM_TARGETS[0]. */\nexport const ZOOM_LOW_THRESHOLD = 0.9;\n\n/** If camera zoom is below this (and above LOW), double-tap zoom targets ZOOM_TARGETS[1]. */\nexport const ZOOM_HIGH_THRESHOLD = 1.8;\n\n/** Wheel deltaY → zoom delta multiplier. Matches today's wheel `useEffect`. */\nexport const WHEEL_ZOOM_FACTOR = 0.01;\n","import type { EntityId } from '@jamesyong42/reactive-ecs';\nimport { Widget } from '../../ecs/components.js';\nimport type { LayoutEngine } from '../../ecs/engine/index.js';\nimport { GESTURING_IDLE_MS } from './constants.js';\nimport { inputGroupStart, inputLog } from './debug.js';\nimport type {\n\tAdapter,\n\tHandler,\n\tInputManager as IInputManager,\n\tInputEvent,\n\tInputEventType,\n\tPoint,\n\tRecognizer,\n\tSurface,\n\tWidgetSurfaceRouter,\n} from './types.js';\n\n/**\n * RFC-008 input pipeline core. Adapters dispatch normalised InputEvents;\n * routers deliver to widget surfaces; engine handlers and recognizers\n * react.\n *\n * Lifecycle:\n * 1. Construct: `new InputManager(engine, container, [adapter, ...])`.\n * 2. Register handlers / recognizers / routers as needed.\n * 3. `attach()` — mounts adapters; returns detacher.\n * 4. Dispatch flows through automatically as native events arrive.\n * 5. Detacher tears down adapters and clears the gesturing debounce.\n */\nexport class InputManager implements IInputManager {\n\tprivate readonly handlers: Map<InputEventType, Set<Handler>> = new Map();\n\tprivate readonly recognizers: Recognizer[] = [];\n\tprivate readonly routers: Map<Surface, WidgetSurfaceRouter> = new Map();\n\n\tprivate gesturingClearTimer: ReturnType<typeof setTimeout> | null = null;\n\n\tconstructor(\n\t\treadonly engine: LayoutEngine,\n\t\tprivate readonly container: HTMLElement,\n\t\tprivate readonly adapters: Adapter[],\n\t) {}\n\n\tattach(): () => void {\n\t\tconst detachers = this.adapters.map((a) => a.attach(this.container, this));\n\t\treturn () => {\n\t\t\tfor (const d of detachers) {\n\t\t\t\ttry {\n\t\t\t\t\td();\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconsole.error('[InputManager] adapter detach threw', err);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this.gesturingClearTimer !== null) {\n\t\t\t\tclearTimeout(this.gesturingClearTimer);\n\t\t\t\tthis.gesturingClearTimer = null;\n\t\t\t}\n\t\t\tfor (const r of this.recognizers) {\n\t\t\t\ttry {\n\t\t\t\t\tr.reset?.();\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconsole.error('[InputManager] recognizer reset threw', err);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\ton(type: InputEventType, handler: Handler): () => void {\n\t\tlet set = this.handlers.get(type);\n\t\tif (!set) {\n\t\t\tset = new Set();\n\t\t\tthis.handlers.set(type, set);\n\t\t}\n\t\tset.add(handler);\n\t\treturn () => {\n\t\t\tconst s = this.handlers.get(type);\n\t\t\tif (s) {\n\t\t\t\ts.delete(handler);\n\t\t\t\tif (s.size === 0) this.handlers.delete(type);\n\t\t\t}\n\t\t};\n\t}\n\n\taddRecognizer(r: Recognizer): () => void {\n\t\tthis.recognizers.push(r);\n\t\treturn () => {\n\t\t\tconst i = this.recognizers.indexOf(r);\n\t\t\tif (i !== -1) this.recognizers.splice(i, 1);\n\t\t};\n\t}\n\n\tsetRouter(router: WidgetSurfaceRouter): () => void {\n\t\tthis.routers.set(router.surface, router);\n\t\treturn () => {\n\t\t\tif (this.routers.get(router.surface) === router) {\n\t\t\t\tthis.routers.delete(router.surface);\n\t\t\t}\n\t\t};\n\t}\n\n\tdispatch(event: InputEvent): void {\n\t\tconst closeGroup = inputGroupStart(`dispatch ${event.type} id=${event.pointerId}`);\n\t\tinputLog('InputManager', `dispatch ${event.type}`, {\n\t\t\ttype: event.type,\n\t\t\tsource: event.source,\n\t\t\tpointerId: event.pointerId,\n\t\t\tscreen: event.screen,\n\t\t\tworld: event.world,\n\t\t});\n\n\t\t// 1. Surface routing for raw pointer events + browser-derived click\n\t\t// family. Synthetic events (recognizer-emitted) bypass routing —\n\t\t// they're already at the intent layer (drag, pinch, etc.) and\n\t\t// don't need re-delivery to widget surfaces. `pointerleave` and\n\t\t// `wheel` also bypass routing — the cursor is exiting (no entity\n\t\t// to deliver to) or the event is whole-canvas (camera ops).\n\t\tif (\n\t\t\t(event.type === 'down' ||\n\t\t\t\tevent.type === 'move' ||\n\t\t\t\tevent.type === 'up' ||\n\t\t\t\tevent.type === 'cancel' ||\n\t\t\t\tevent.type === 'click' ||\n\t\t\t\tevent.type === 'dblclick' ||\n\t\t\t\tevent.type === 'contextmenu') &&\n\t\t\tevent.source !== 'synthetic' &&\n\t\t\tthis.routers.size > 0\n\t\t) {\n\t\t\tconst entityId = this.engine.pickAt(event.screen.x, event.screen.y);\n\t\t\tif (entityId !== null) {\n\t\t\t\tconst surface = this.surfaceOf(entityId);\n\t\t\t\tconst router = surface !== null ? this.routers.get(surface) : undefined;\n\t\t\t\tinputLog('InputManager', `routing → ${surface ?? 'none'} entity=${entityId}`, {\n\t\t\t\t\ttype: event.type,\n\t\t\t\t\tentityId,\n\t\t\t\t\tsurface,\n\t\t\t\t\thasRouter: !!router,\n\t\t\t\t});\n\t\t\t\tif (router) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\trouter.route(event, entityId);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tconsole.error('[InputManager] router threw', err);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tinputLog('InputManager', `routing → empty space (pickAt null)`, {\n\t\t\t\t\ttype: event.type,\n\t\t\t\t\tscreen: event.screen,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// 1b. Claim check — after routers ran, ask each router whether\n\t\t// this pointer is now exclusively held by a widget mesh\n\t\t// (e.g. R3F's `setPointerCapture` populated capturedMap).\n\t\t// Claimed pointers skip recognizer observation so the engine's\n\t\t// drag / tap / pan recognizers don't react to a gesture the\n\t\t// widget is handling itself.\n\t\tlet claimed = false;\n\t\tif (event.source !== 'synthetic') {\n\t\t\tfor (const router of this.routers.values()) {\n\t\t\t\tif (router.isPointerClaimed?.(event.pointerId)) {\n\t\t\t\t\tclaimed = true;\n\t\t\t\t\tinputLog(\n\t\t\t\t\t\t'InputManager',\n\t\t\t\t\t\t`claim check → CLAIMED by ${router.surface} router (recognizers will skip)`,\n\t\t\t\t\t\t{ type: event.type, pointerId: event.pointerId },\n\t\t\t\t\t);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// 2. Engine and recognizer-subscribed handlers — always run. The\n\t\t// `move` engine handler updates hover; other handlers respond to\n\t\t// synthetic events (drag-start, tap, etc.) which are gated by\n\t\t// recognizers, so claimed pointers naturally never produce\n\t\t// synthetic events.\n\t\tconst handlers = this.handlers.get(event.type);\n\t\tif (handlers && handlers.size > 0) {\n\t\t\tinputLog('InputManager', `handlers for ${event.type}: ${handlers.size} → firing`, {\n\t\t\t\ttype: event.type,\n\t\t\t\tcount: handlers.size,\n\t\t\t});\n\t\t\tfor (const h of handlers) {\n\t\t\t\ttry {\n\t\t\t\t\th(event);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconsole.error('[InputManager] handler threw', err);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// 3. Recognizers observe (after handlers, so a handler that captured\n\t\t// can affect what recognizers see — e.g. `engine.beginDrag` ran\n\t\t// before DragRecognizer sees the next 'move'). Skipped entirely\n\t\t// when a router claims the pointer.\n\t\tif (!claimed) {\n\t\t\tfor (const r of this.recognizers) {\n\t\t\t\ttry {\n\t\t\t\t\tr.observe(event, this);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconsole.error('[InputManager] recognizer threw', err);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tinputLog('InputManager', `recognizers skipped (pointer claimed)`, {\n\t\t\t\ttype: event.type,\n\t\t\t\tpointerId: event.pointerId,\n\t\t\t});\n\t\t}\n\n\t\tcloseGroup();\n\t}\n\n\tpickAt(screen: Point): EntityId | null {\n\t\treturn this.engine.pickAt(screen.x, screen.y);\n\t}\n\n\tnotifyGesturing(): void {\n\t\tthis.engine.setGesturing(true);\n\t\tif (this.gesturingClearTimer !== null) clearTimeout(this.gesturingClearTimer);\n\t\tthis.gesturingClearTimer = setTimeout(() => {\n\t\t\tthis.engine.setGesturing(false);\n\t\t\tthis.gesturingClearTimer = null;\n\t\t}, GESTURING_IDLE_MS);\n\t}\n\n\t/** Resolve an entity's rendering surface via the `Widget` component. */\n\tprivate surfaceOf(entityId: EntityId): Surface | null {\n\t\tconst w = this.engine.get(entityId, Widget);\n\t\tif (!w) return null;\n\t\t// Widget.surface is typed as a string in the ECS layer; narrow here.\n\t\tif (w.surface === 'dom' || w.surface === 'webgl' || w.surface === 'webview') {\n\t\t\treturn w.surface;\n\t\t}\n\t\treturn null;\n\t}\n}\n","import type { LayoutEngine } from '../../ecs/engine/index.js';\nimport {\n\tWHEEL_ZOOM_FACTOR,\n\tZOOM_HIGH_THRESHOLD,\n\tZOOM_LOW_THRESHOLD,\n\tZOOM_TARGETS,\n} from './constants.js';\nimport { inputLog } from './debug.js';\nimport type { GestureDetail, InputManager, Point } from './types.js';\n\n/**\n * RFC-008 § Engine handler registration. Wires the engine's input\n * primitives (`beginDrag`, `selectEntity`, camera ops, hover state, etc.)\n * to the synthetic events emitted by recognizers and the raw events\n * emitted by adapters. Returns a teardown that removes every handler.\n *\n * The `container` is the canvas-container DOM element. Pointer-capture\n * for drags is anchored on it so the gesture survives the cursor leaving\n * the container's bounds.\n */\nexport function installEngineHandlers(\n\tmanager: InputManager,\n\tengine: LayoutEngine,\n\tcontainer: HTMLElement,\n): () => void {\n\t// PinchRecognizer emits `center` per update but no center delta — the\n\t// engine handler accumulates so pinch + two-finger pan act as a\n\t// compound gesture (matches iOS Maps and the legacy TouchEventBus).\n\tlet lastPinchCenter: Point | null = null;\n\n\tconst offs: Array<() => void> = [];\n\n\t// --- Camera --------------------------------------------------------\n\n\toffs.push(\n\t\tmanager.on('wheel', (e) => {\n\t\t\tconst w = e.wheelDelta;\n\t\t\tif (!w) return;\n\t\t\tif (w.pinch) {\n\t\t\t\tengine.zoomAtPoint(e.screen.x, e.screen.y, -w.dy * WHEEL_ZOOM_FACTOR);\n\t\t\t} else {\n\t\t\t\tengine.panBy(-w.dx, -w.dy);\n\t\t\t}\n\t\t\tmanager.notifyGesturing();\n\t\t}),\n\t);\n\n\toffs.push(\n\t\tmanager.on('pinch-start', (e) => {\n\t\t\tconst g = e.gesture as Extract<GestureDetail, { kind: 'pinch' }>;\n\t\t\tlastPinchCenter = { x: g.center.x, y: g.center.y };\n\t\t\tmanager.notifyGesturing();\n\t\t}),\n\t);\n\n\toffs.push(\n\t\tmanager.on('pinch-update', (e) => {\n\t\t\tconst g = e.gesture as Extract<GestureDetail, { kind: 'pinch' }>;\n\t\t\tengine.zoomAtPoint(g.center.x, g.center.y, g.scale - 1);\n\t\t\tif (lastPinchCenter) {\n\t\t\t\tengine.panBy(g.center.x - lastPinchCenter.x, g.center.y - lastPinchCenter.y);\n\t\t\t}\n\t\t\tlastPinchCenter = { x: g.center.x, y: g.center.y };\n\t\t\tmanager.notifyGesturing();\n\t\t}),\n\t);\n\n\toffs.push(\n\t\tmanager.on('pinch-end', () => {\n\t\t\tlastPinchCenter = null;\n\t\t}),\n\t);\n\n\toffs.push(\n\t\tmanager.on('pan-update', (e) => {\n\t\t\tconst g = e.gesture as Extract<GestureDetail, { kind: 'pan' }>;\n\t\t\tengine.panBy(g.delta.x, g.delta.y);\n\t\t\tmanager.notifyGesturing();\n\t\t}),\n\t);\n\n\t// --- Click / double-click ------------------------------------------\n\t//\n\t// v6: drives selection / navigation off browser-native click events\n\t// instead of TapRecognizer / DoubleTapRecognizer synthetics. The\n\t// browser fires `click` / `dblclick` after the pointer cycle\n\t// completes — including when a mesh held setPointerCapture during\n\t// the down → up sequence (the previous tap-based path was skipped in\n\t// that case, so capturing meshes never got selected). Recognizers\n\t// still emit `tap` / `double-tap` for any external listener that\n\t// wants gesture-style events; the engine just no longer consumes\n\t// them.\n\n\toffs.push(\n\t\tmanager.on('click', (e) => {\n\t\t\t// Left button only. Browsers vary on whether middle / right\n\t\t\t// dispatch `click` — we ignore those; right-click is\n\t\t\t// `contextmenu`, middle-click has no canvas semantics yet.\n\t\t\tif (e.button !== 0 && e.button !== null) return;\n\t\t\tconst entity = engine.pickAt(e.screen.x, e.screen.y);\n\t\t\tif (entity !== null) {\n\t\t\t\tinputLog('Engine', `click on entity ${entity} → selectEntity (shift=${e.modifiers.shift})`);\n\t\t\t\tengine.selectEntity(entity, e.modifiers.shift);\n\t\t\t} else {\n\t\t\t\tinputLog('Engine', `click on empty space → clearSelection`);\n\t\t\t\tengine.clearSelection();\n\t\t\t}\n\t\t}),\n\t);\n\n\toffs.push(\n\t\tmanager.on('dblclick', (e) => {\n\t\t\tconst entity = engine.pickAt(e.screen.x, e.screen.y);\n\t\t\tif (entity !== null) {\n\t\t\t\tinputLog('Engine', `dblclick on entity ${entity} → enterContainer`);\n\t\t\t\tengine.enterContainer(entity);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst camera = engine.getCamera();\n\t\t\tconst target =\n\t\t\t\tcamera.zoom < ZOOM_LOW_THRESHOLD\n\t\t\t\t\t? ZOOM_TARGETS[0]\n\t\t\t\t\t: camera.zoom < ZOOM_HIGH_THRESHOLD\n\t\t\t\t\t\t? ZOOM_TARGETS[1]\n\t\t\t\t\t\t: ZOOM_TARGETS[0];\n\t\t\tinputLog('Engine', `dblclick on empty → zoomAtPoint target=${target}x`);\n\t\t\tengine.zoomAtPoint(e.screen.x, e.screen.y, (target - camera.zoom) / camera.zoom);\n\t\t}),\n\t);\n\n\t// --- Drag / marquee ------------------------------------------------\n\n\toffs.push(\n\t\tmanager.on('drag-start', (e) => {\n\t\t\tconst hit = engine.hitTest(e.screen.x, e.screen.y);\n\t\t\tcontainer.setPointerCapture(e.pointerId);\n\n\t\t\tif (!hit) {\n\t\t\t\tif (e.source === 'touch') {\n\t\t\t\t\tinputLog('Engine', `drag-start on empty (touch) → defer to PanRecognizer`, {\n\t\t\t\t\t\tpointerId: e.pointerId,\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tinputLog('Engine', `drag-start on empty (mouse/pen) → beginMarquee`, {\n\t\t\t\t\tpointerId: e.pointerId,\n\t\t\t\t});\n\t\t\t\tengine.clearSelection();\n\t\t\t\tengine.beginMarquee(e.world.x, e.world.y);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (hit.role.role.type === 'resize') {\n\t\t\t\tinputLog('Engine', `drag-start on resize handle → beginResize ${hit.role.role.handle}`, {\n\t\t\t\t\tentityId: hit.entityId,\n\t\t\t\t\thandle: hit.role.role.handle,\n\t\t\t\t});\n\t\t\t\tengine.beginResize(hit.entityId, hit.role.role.handle, e.world.x, e.world.y);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst selected = engine.getSelectedEntities();\n\t\t\tif (!selected.includes(hit.entityId)) {\n\t\t\t\tengine.selectEntity(hit.entityId, e.modifiers.shift);\n\t\t\t}\n\t\t\tinputLog('Engine', `drag-start on entity → beginDrag ${hit.entityId}`, {\n\t\t\t\tentityId: hit.entityId,\n\t\t\t\trole: hit.role.role.type,\n\t\t\t\tshift: e.modifiers.shift,\n\t\t\t});\n\t\t\tengine.beginDrag(hit.entityId, e.world.x, e.world.y);\n\t\t}),\n\t);\n\n\toffs.push(\n\t\tmanager.on('drag-update', (e) => {\n\t\t\tif (engine.isMarqueeActive()) {\n\t\t\t\tengine.updateMarquee(e.world.x, e.world.y);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst resizing = engine.getResizingEntity();\n\t\t\tif (resizing !== null) {\n\t\t\t\tengine.updateResize(resizing, e.world.x, e.world.y);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst dragging = engine.getDraggingEntity();\n\t\t\tif (dragging !== null) {\n\t\t\t\tengine.updateDrag(dragging, e.world.x, e.world.y);\n\t\t\t}\n\t\t}),\n\t);\n\n\toffs.push(\n\t\tmanager.on('drag-end', (e) => {\n\t\t\tif (engine.isMarqueeActive()) {\n\t\t\t\tinputLog('Engine', `drag-end → endMarquee`);\n\t\t\t\tengine.endMarquee();\n\t\t\t} else {\n\t\t\t\tconst resizing = engine.getResizingEntity();\n\t\t\t\tif (resizing !== null) {\n\t\t\t\t\tinputLog('Engine', `drag-end → endResize ${resizing} (commit)`);\n\t\t\t\t\tengine.endResize(resizing, { cancelled: false });\n\t\t\t\t} else {\n\t\t\t\t\tconst dragging = engine.getDraggingEntity();\n\t\t\t\t\tif (dragging !== null) {\n\t\t\t\t\t\tinputLog('Engine', `drag-end → endDrag ${dragging} (commit)`);\n\t\t\t\t\t\tengine.endDrag(dragging, { cancelled: false });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (container.hasPointerCapture(e.pointerId)) {\n\t\t\t\tcontainer.releasePointerCapture(e.pointerId);\n\t\t\t}\n\t\t}),\n\t);\n\n\toffs.push(\n\t\tmanager.on('cancel', (e) => {\n\t\t\tinputLog('Engine', `cancel → cancelInteraction (covers all mid-gesture modes)`, {\n\t\t\t\tpointerId: e.pointerId,\n\t\t\t});\n\t\t\tengine.cancelInteraction();\n\t\t\tif (container.hasPointerCapture(e.pointerId)) {\n\t\t\t\tcontainer.releasePointerCapture(e.pointerId);\n\t\t\t}\n\t\t}),\n\t);\n\n\t// --- Hover chrome --------------------------------------------------\n\t//\n\t// `updateHover` runs the engine's full hit-test so the cursor can\n\t// switch between RFC-005 resize hotspots within a single widget —\n\t// HoverRecognizer's `hover-enter` / `hover-leave` events only fire on\n\t// entity transitions, which is too coarse for handle cursor changes.\n\t// Internally gated on `idle` mode so drag / resize / marquee freeze\n\t// hover (matches the v1 `handlePointerMove` idle-branch behaviour).\n\n\toffs.push(\n\t\tmanager.on('move', (e) => {\n\t\t\tengine.updateHover(e.screen.x, e.screen.y);\n\t\t}),\n\t);\n\n\t// Cursor exited the canvas container — clear hover chrome. v6: the\n\t// pre-existing inline `pointerleave` listener in `InfiniteCanvas.tsx`\n\t// is gone; PointerAdapter dispatches the event instead, so this\n\t// handler runs through the same pipeline as every other input.\n\toffs.push(\n\t\tmanager.on('pointerleave', () => {\n\t\t\tinputLog('Engine', `pointerleave → setHoveredEntity(null)`);\n\t\t\tengine.setHoveredEntity(null);\n\t\t}),\n\t);\n\n\treturn () => {\n\t\tfor (const off of offs) off();\n\t\tlastPinchCenter = null;\n\t};\n}\n","import type { GestureDetail, InputEvent, InputEventType, Point } from './types.js';\n\n/**\n * Helper for constructing recognizer-emitted synthetic events. The\n * recognizer copies pointerId / modifiers / coords from the base raw\n * event, sets `source: 'synthetic'`, and attaches a `gesture` payload.\n */\nexport function makeSynthetic(\n\ttype: InputEventType,\n\tbase: InputEvent,\n\tgesture: GestureDetail,\n\toverrides?: Partial<{ screen: Point; world: Point; delta: Point }>,\n): InputEvent {\n\treturn {\n\t\ttype,\n\t\tsource: 'synthetic',\n\t\tpointerId: base.pointerId,\n\t\tprimary: base.primary,\n\t\tscreen: overrides?.screen ?? base.screen,\n\t\tworld: overrides?.world ?? base.world,\n\t\tdelta: overrides?.delta,\n\t\tmodifiers: base.modifiers,\n\t\ttimestamp: base.timestamp,\n\t\tgesture,\n\t};\n}\n\n/** Squared distance — avoids a sqrt for threshold comparisons. */\nexport function distSq(a: Point, b: Point): number {\n\tconst dx = a.x - b.x;\n\tconst dy = a.y - b.y;\n\treturn dx * dx + dy * dy;\n}\n\n/** Returns true if the linear distance between two points exceeds `threshold` px. */\nexport function exceedsThreshold(a: Point, b: Point, threshold: number): boolean {\n\treturn distSq(a, b) > threshold * threshold;\n}\n","import { DOUBLE_TAP_DIST_PX, DOUBLE_TAP_WINDOW_MS } from '../constants.js';\nimport { inputLog } from '../debug.js';\nimport { exceedsThreshold, makeSynthetic } from '../synthetic.js';\nimport type { InputEvent, InputManager, Point, Recognizer } from '../types.js';\n\n/**\n * Double-tap recognizer (RFC-008). Observes the `tap` events emitted by\n * `TapRecognizer`. When two consecutive taps land within\n * `DOUBLE_TAP_WINDOW_MS` and `DOUBLE_TAP_DIST_PX`, emits a synthetic\n * `'double-tap'`.\n *\n * The first tap continues to fire normally — handlers that listen to\n * `'tap'` (e.g., engine selection) react to it. The second tap fires\n * both a `'tap'` AND a `'double-tap'`. Engine handlers can decide which\n * to respond to based on what they care about.\n */\nexport class DoubleTapRecognizer implements Recognizer {\n\tprivate last: { at: Point; time: number } | null = null;\n\n\tobserve(event: InputEvent, manager: InputManager): void {\n\t\tif (event.type !== 'tap' || event.gesture?.kind !== 'tap' || event.gesture.count !== 1) {\n\t\t\treturn;\n\t\t}\n\t\tconst now = event.timestamp;\n\t\tconst here = event.screen;\n\t\tif (\n\t\t\tthis.last !== null &&\n\t\t\tnow - this.last.time <= DOUBLE_TAP_WINDOW_MS &&\n\t\t\t!exceedsThreshold(here, this.last.at, DOUBLE_TAP_DIST_PX)\n\t\t) {\n\t\t\tinputLog('Recognizer', `DoubleTapRecognizer: 2nd tap within window → double-tap`, {\n\t\t\t\tpointerId: event.pointerId,\n\t\t\t\tdtMs: now - this.last.time,\n\t\t\t});\n\t\t\tmanager.dispatch(makeSynthetic('double-tap', event, { kind: 'tap', count: 2 }));\n\t\t\tthis.last = null;\n\t\t\treturn;\n\t\t}\n\t\tthis.last = { at: here, time: now };\n\t}\n\n\treset(): void {\n\t\tthis.last = null;\n\t}\n}\n","import { DEAD_ZONE_MOUSE_PX, DEAD_ZONE_TOUCH_PX } from '../constants.js';\nimport { inputLog } from '../debug.js';\nimport { exceedsThreshold, makeSynthetic } from '../synthetic.js';\nimport type { InputEvent, InputManager, Point, Recognizer } from '../types.js';\n\ninterface TrackingState {\n\tdownAt: { screen: Point; world: Point };\n\tlast: { screen: Point; world: Point };\n\tstatus: 'tracking' | 'dragging';\n}\n\n/**\n * Drag recognizer (RFC-008). Per-pointerId state on `down`. On `move`\n * past the source-appropriate dead zone, emits a synthetic `drag-start`\n * and transitions to `dragging`. Subsequent moves emit `drag-update`s\n * with screen + world deltas. `up` or `cancel` after dragging emits\n * `drag-end`.\n *\n * Single-finger only: PinchRecognizer dispatches a synthetic `cancel`\n * when a 2nd touch lands, which DragRecognizer observes and uses to\n * abort tracking for the first finger.\n *\n * Note: synthetic `drag-update` events carry the SCREEN delta in\n * `gesture.delta` (not world delta) — the engine handler needs world\n * coords to update entity positions, but it gets those from the raw\n * `move` event's `world`. The gesture's `delta` is informational, not\n * used by the engine drag handler.\n */\nexport class DragRecognizer implements Recognizer {\n\tprivate readonly tracking = new Map<number, TrackingState>();\n\n\tobserve(event: InputEvent, manager: InputManager): void {\n\t\tswitch (event.type) {\n\t\t\tcase 'down': {\n\t\t\t\tif (event.button !== 0 && event.button !== null) return;\n\t\t\t\t// Single-finger only (RFC-008 § Recognizers table). A 2nd\n\t\t\t\t// concurrent `down` while a prior pointer is still tracked\n\t\t\t\t// would otherwise produce parallel drag states and the\n\t\t\t\t// engine's `beginDrag` doesn't model concurrent drags.\n\t\t\t\t// PinchRecognizer's synthetic `cancel` will retire the\n\t\t\t\t// first pointer cleanly before its `pinch-start` fires.\n\t\t\t\tif (this.tracking.size > 0) return;\n\t\t\t\tthis.tracking.set(event.pointerId, {\n\t\t\t\t\tdownAt: { screen: event.screen, world: event.world },\n\t\t\t\t\tlast: { screen: event.screen, world: event.world },\n\t\t\t\t\tstatus: 'tracking',\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'move': {\n\t\t\t\tconst t = this.tracking.get(event.pointerId);\n\t\t\t\tif (!t) return;\n\t\t\t\tif (t.status === 'tracking') {\n\t\t\t\t\tconst dz = event.source === 'touch' ? DEAD_ZONE_TOUCH_PX : DEAD_ZONE_MOUSE_PX;\n\t\t\t\t\tif (!exceedsThreshold(event.screen, t.downAt.screen, dz)) return;\n\t\t\t\t\tt.status = 'dragging';\n\t\t\t\t\tinputLog('Recognizer', `DragRecognizer: dead-zone crossed → drag-start`, {\n\t\t\t\t\t\tpointerId: event.pointerId,\n\t\t\t\t\t\tsource: event.source,\n\t\t\t\t\t\tdeadZone: dz,\n\t\t\t\t\t});\n\t\t\t\t\tmanager.dispatch(\n\t\t\t\t\t\tmakeSynthetic('drag-start', event, {\n\t\t\t\t\t\t\tkind: 'drag',\n\t\t\t\t\t\t\tphase: 'start',\n\t\t\t\t\t\t\ttotal: {\n\t\t\t\t\t\t\t\tx: event.screen.x - t.downAt.screen.x,\n\t\t\t\t\t\t\t\ty: event.screen.y - t.downAt.screen.y,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tdelta: { x: event.screen.x - t.last.screen.x, y: event.screen.y - t.last.screen.y },\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t\tt.last = { screen: event.screen, world: event.world };\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// status === 'dragging'\n\t\t\t\tmanager.dispatch(\n\t\t\t\t\tmakeSynthetic('drag-update', event, {\n\t\t\t\t\t\tkind: 'drag',\n\t\t\t\t\t\tphase: 'update',\n\t\t\t\t\t\ttotal: { x: event.screen.x - t.downAt.screen.x, y: event.screen.y - t.downAt.screen.y },\n\t\t\t\t\t\tdelta: { x: event.screen.x - t.last.screen.x, y: event.screen.y - t.last.screen.y },\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tt.last = { screen: event.screen, world: event.world };\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'up': {\n\t\t\t\tconst t = this.tracking.get(event.pointerId);\n\t\t\t\tif (!t) return;\n\t\t\t\tthis.tracking.delete(event.pointerId);\n\t\t\t\tif (t.status !== 'dragging') return;\n\t\t\t\tinputLog('Recognizer', `DragRecognizer: up after dragging → drag-end`, {\n\t\t\t\t\tpointerId: event.pointerId,\n\t\t\t\t});\n\t\t\t\tmanager.dispatch(\n\t\t\t\t\tmakeSynthetic('drag-end', event, {\n\t\t\t\t\t\tkind: 'drag',\n\t\t\t\t\t\tphase: 'end',\n\t\t\t\t\t\ttotal: { x: event.screen.x - t.downAt.screen.x, y: event.screen.y - t.downAt.screen.y },\n\t\t\t\t\t\tdelta: { x: event.screen.x - t.last.screen.x, y: event.screen.y - t.last.screen.y },\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'cancel': {\n\t\t\t\t// Only clear tracking state. The native `cancel` propagates\n\t\t\t\t// to engine handlers BEFORE recognizers observe (per\n\t\t\t\t// InputManager.dispatch ordering), so the engine `cancel`\n\t\t\t\t// handler has already rolled back the drag with\n\t\t\t\t// `cancelled: true`. Re-emitting a synthetic `drag-end`\n\t\t\t\t// here would be carry the wrong intent (`drag-end` →\n\t\t\t\t// `cancelled: false` → commit) and is only harmless today\n\t\t\t\t// because state is already idle by the time it dispatches.\n\t\t\t\t// Keep the recognizer contract clean: `cancel` is `cancel`,\n\t\t\t\t// not `drag-end`.\n\t\t\t\tthis.tracking.delete(event.pointerId);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\treset(): void {\n\t\tthis.tracking.clear();\n\t}\n}\n","import type { EntityId } from '@jamesyong42/reactive-ecs';\nimport { inputLog } from '../debug.js';\nimport { makeSynthetic } from '../synthetic.js';\nimport type { InputEvent, InputManager, Recognizer } from '../types.js';\n\n/**\n * Hover recognizer (RFC-008). Observes `move` events; tracks the last\n * leaf entity under each pointer via `manager.pickAt`. On change, emits\n * `hover-leave` (with the previous entity in `gesture.entityId`) and\n * `hover-enter` (with the new entity).\n *\n * Hover is informational — recognizers and handlers downstream cannot\n * \"consume\" it. Engine hover chrome (selection ring, cursor hint) is\n * driven entirely by these events.\n *\n * Pen + mouse hover normally; touch fires hover only while a finger is\n * pressed, so touch-source hover events fire as a side-effect of drag\n * tracking. Authors who want touch hover-on-hover should listen for\n * `move` events themselves.\n */\nexport class HoverRecognizer implements Recognizer {\n\tprivate readonly lastByPointer = new Map<number, EntityId | null>();\n\n\tobserve(event: InputEvent, manager: InputManager): void {\n\t\tswitch (event.type) {\n\t\t\tcase 'move': {\n\t\t\t\tconst current = manager.pickAt(event.screen);\n\t\t\t\tconst prev = this.lastByPointer.get(event.pointerId) ?? null;\n\t\t\t\tif (current === prev) return;\n\t\t\t\tinputLog('Recognizer', `HoverRecognizer: entity changed ${prev} → ${current}`, {\n\t\t\t\t\tpointerId: event.pointerId,\n\t\t\t\t\tprev,\n\t\t\t\t\tcurrent,\n\t\t\t\t});\n\t\t\t\tif (prev !== null) {\n\t\t\t\t\tmanager.dispatch(makeSynthetic('hover-leave', event, { kind: 'hover', entityId: prev }));\n\t\t\t\t}\n\t\t\t\tthis.lastByPointer.set(event.pointerId, current);\n\t\t\t\tif (current !== null) {\n\t\t\t\t\tmanager.dispatch(\n\t\t\t\t\t\tmakeSynthetic('hover-enter', event, { kind: 'hover', entityId: current }),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'up':\n\t\t\tcase 'cancel': {\n\t\t\t\tconst prev = this.lastByPointer.get(event.pointerId);\n\t\t\t\tthis.lastByPointer.delete(event.pointerId);\n\t\t\t\tif (prev != null) {\n\t\t\t\t\tmanager.dispatch(makeSynthetic('hover-leave', event, { kind: 'hover', entityId: prev }));\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\treset(): void {\n\t\tthis.lastByPointer.clear();\n\t}\n}\n","import { DEAD_ZONE_TOUCH_PX } from '../constants.js';\nimport { inputLog } from '../debug.js';\nimport { exceedsThreshold, makeSynthetic } from '../synthetic.js';\nimport type { InputEvent, InputManager, Point, Recognizer } from '../types.js';\n\ninterface TrackingState {\n\tdownAt: Point;\n\tlast: Point;\n\tstatus: 'tracking' | 'panning';\n}\n\n/**\n * Pan recognizer (RFC-008). Single-finger touch on empty space only —\n * `engine.pickAt(world) === null` at down-time. Emits `pan-update` with\n * screen deltas. The engine pan handler translates them into camera\n * `panBy` calls.\n *\n * Pinch + pan run simultaneously when two fingers are down on empty\n * space (matches iOS Maps): PinchRecognizer cancels this recognizer's\n * tracking via synthetic `cancel`, then a fresh PanRecognizer state\n * doesn't restart until both fingers release and a new single-finger\n * touch begins on empty space.\n *\n * Mouse / pen drags on empty space are NOT pans here — they're marquee\n * selection, handled by the engine drag handler responding to\n * DragRecognizer's `drag-start` for empty-space hits.\n */\nexport class PanRecognizer implements Recognizer {\n\tprivate readonly tracking = new Map<number, TrackingState>();\n\n\tobserve(event: InputEvent, manager: InputManager): void {\n\t\tswitch (event.type) {\n\t\t\tcase 'down': {\n\t\t\t\tif (event.source !== 'touch') return;\n\t\t\t\tif (event.button !== 0 && event.button !== null) return;\n\t\t\t\tconst hit = manager.pickAt(event.screen);\n\t\t\t\tif (hit !== null) return; // entity hit — drag/select, not pan\n\t\t\t\tthis.tracking.set(event.pointerId, {\n\t\t\t\t\tdownAt: event.screen,\n\t\t\t\t\tlast: event.screen,\n\t\t\t\t\tstatus: 'tracking',\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'move': {\n\t\t\t\tconst t = this.tracking.get(event.pointerId);\n\t\t\t\tif (!t) return;\n\t\t\t\tif (t.status === 'tracking') {\n\t\t\t\t\tif (!exceedsThreshold(event.screen, t.downAt, DEAD_ZONE_TOUCH_PX)) return;\n\t\t\t\t\tt.status = 'panning';\n\t\t\t\t\tt.last = event.screen;\n\t\t\t\t\tinputLog('Recognizer', `PanRecognizer: dead-zone crossed → panning (touch empty-space)`, {\n\t\t\t\t\t\tpointerId: event.pointerId,\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst delta = { x: event.screen.x - t.last.x, y: event.screen.y - t.last.y };\n\t\t\t\tt.last = event.screen;\n\t\t\t\tmanager.dispatch(makeSynthetic('pan-update', event, { kind: 'pan', delta }));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'up':\n\t\t\tcase 'cancel': {\n\t\t\t\tthis.tracking.delete(event.pointerId);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\treset(): void {\n\t\tthis.tracking.clear();\n\t}\n}\n","import { screenToWorld } from '../../../ecs/math.js';\nimport { inputLog } from '../debug.js';\nimport { makeSynthetic } from '../synthetic.js';\nimport type { InputEvent, InputManager, Point, Recognizer } from '../types.js';\n\ninterface PinchState {\n\tpointerIds: [number, number];\n\tlast: { dist: number; center: Point };\n}\n\n/**\n * Pinch recognizer (RFC-008). Counts simultaneous active touch-source\n * pointers; emits `pinch-start` when count reaches 2, `pinch-update` on\n * either finger move, `pinch-end` when count drops below 2.\n *\n * On `pinch-start`, dispatches a synthetic `cancel` for any tracked\n * single-finger gesture so DragRecognizer / TapRecognizer / PanRecognizer\n * can abort cleanly. This is the cancel-then-pinch ordering — engine\n * drag (if active) runs `endDrag(entity, { cancelled: true })` before\n * pinch math takes over.\n *\n * Coexists with PanRecognizer: empty-space pan (single finger that\n * already crossed dead zone before the 2nd finger arrives) gets\n * cancelled by the synthetic `cancel`. After `pinch-end`, the user must\n * lift and re-place to start a new gesture (matches iOS).\n */\nexport class PinchRecognizer implements Recognizer {\n\t/** Active touch-source pointers and their latest positions (screen). */\n\tprivate readonly active = new Map<number, Point>();\n\tprivate state: PinchState | null = null;\n\n\tobserve(event: InputEvent, manager: InputManager): void {\n\t\tif (event.source !== 'touch') return;\n\t\tswitch (event.type) {\n\t\t\tcase 'down': {\n\t\t\t\tthis.active.set(event.pointerId, event.screen);\n\t\t\t\tif (this.state === null && this.active.size === 2) {\n\t\t\t\t\tconst ids = [...this.active.keys()] as [number, number];\n\t\t\t\t\tconst camera = manager.engine.getCamera();\n\t\t\t\t\t// Cancel any single-finger gesture in progress on either pointer.\n\t\t\t\t\t// World coords are derived from the per-pointer screen position\n\t\t\t\t\t// so HoverRecognizer's `cancel` → `hover-leave` re-dispatch\n\t\t\t\t\t// carries a self-consistent (screen, world) pair.\n\t\t\t\t\tfor (const id of ids) {\n\t\t\t\t\t\tconst screen = this.active.get(id)!;\n\t\t\t\t\t\tmanager.dispatch({\n\t\t\t\t\t\t\ttype: 'cancel',\n\t\t\t\t\t\t\tsource: 'synthetic',\n\t\t\t\t\t\t\tpointerId: id,\n\t\t\t\t\t\t\tprimary: false,\n\t\t\t\t\t\t\tscreen,\n\t\t\t\t\t\t\tworld: screenToWorld(screen.x, screen.y, camera),\n\t\t\t\t\t\t\tmodifiers: event.modifiers,\n\t\t\t\t\t\t\ttimestamp: event.timestamp,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tconst positions = [...this.active.values()];\n\t\t\t\t\tconst dist = pointDistance(positions[0], positions[1]);\n\t\t\t\t\tconst center = midpoint(positions[0], positions[1]);\n\t\t\t\t\tthis.state = {\n\t\t\t\t\t\tpointerIds: ids,\n\t\t\t\t\t\tlast: { dist, center },\n\t\t\t\t\t};\n\t\t\t\t\tinputLog(\n\t\t\t\t\t\t'Recognizer',\n\t\t\t\t\t\t`PinchRecognizer: 2nd touch → pinch-start (cancel sent for both)`,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpointerIds: ids,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t\tmanager.dispatch(\n\t\t\t\t\t\tmakeSynthetic('pinch-start', event, {\n\t\t\t\t\t\t\tkind: 'pinch',\n\t\t\t\t\t\t\tphase: 'start',\n\t\t\t\t\t\t\tscale: 1,\n\t\t\t\t\t\t\tcenter,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'move': {\n\t\t\t\tif (this.state === null || !this.active.has(event.pointerId)) return;\n\t\t\t\tthis.active.set(event.pointerId, event.screen);\n\t\t\t\tconst a = this.active.get(this.state.pointerIds[0]);\n\t\t\t\tconst b = this.active.get(this.state.pointerIds[1]);\n\t\t\t\tif (!a || !b) return;\n\t\t\t\tconst dist = pointDistance(a, b);\n\t\t\t\tconst center = midpoint(a, b);\n\t\t\t\tconst scale = this.state.last.dist > 0 ? dist / this.state.last.dist : 1;\n\t\t\t\tthis.state.last = { dist, center };\n\t\t\t\tmanager.dispatch(\n\t\t\t\t\tmakeSynthetic(\n\t\t\t\t\t\t'pinch-update',\n\t\t\t\t\t\tevent,\n\t\t\t\t\t\t{ kind: 'pinch', phase: 'update', scale, center },\n\t\t\t\t\t\t{ screen: center },\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'up':\n\t\t\tcase 'cancel': {\n\t\t\t\tthis.active.delete(event.pointerId);\n\t\t\t\tif (this.state !== null && this.active.size < 2) {\n\t\t\t\t\tinputLog('Recognizer', `PinchRecognizer: finger lifted → pinch-end`, {\n\t\t\t\t\t\tremainingActive: this.active.size,\n\t\t\t\t\t});\n\t\t\t\t\tmanager.dispatch(\n\t\t\t\t\t\tmakeSynthetic('pinch-end', event, {\n\t\t\t\t\t\t\tkind: 'pinch',\n\t\t\t\t\t\t\tphase: 'end',\n\t\t\t\t\t\t\tscale: 1,\n\t\t\t\t\t\t\tcenter: this.state.last.center,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t\tthis.state = null;\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\treset(): void {\n\t\tthis.active.clear();\n\t\tthis.state = null;\n\t}\n}\n\nfunction pointDistance(a: Point, b: Point): number {\n\tconst dx = a.x - b.x;\n\tconst dy = a.y - b.y;\n\treturn Math.sqrt(dx * dx + dy * dy);\n}\n\nfunction midpoint(a: Point, b: Point): Point {\n\treturn { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };\n}\n","import { DEAD_ZONE_MOUSE_PX, DEAD_ZONE_TOUCH_PX, TAP_WINDOW_MS } from '../constants.js';\nimport { inputLog } from '../debug.js';\nimport { exceedsThreshold, makeSynthetic } from '../synthetic.js';\nimport type { InputEvent, InputManager, Point, Recognizer } from '../types.js';\n\n/**\n * Tap recognizer (RFC-008). Per-pointerId state on `down`; emits a\n * synthetic `'tap'` (count 1) on `up` within `TAP_WINDOW_MS` and the\n * source-appropriate dead zone.\n *\n * Pairwise relationships:\n * - Cancels its pending tap on observed `drag-start` or `pinch-start`\n * for the same pointerId.\n * - Cancels its pending tap on observed `cancel`.\n */\nexport class TapRecognizer implements Recognizer {\n\tprivate readonly pending = new Map<number, { downAt: Point; time: number }>();\n\n\tobserve(event: InputEvent, manager: InputManager): void {\n\t\tswitch (event.type) {\n\t\t\tcase 'down': {\n\t\t\t\tif (event.button !== 0 && event.button !== null) return;\n\t\t\t\tthis.pending.set(event.pointerId, { downAt: event.screen, time: event.timestamp });\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'up': {\n\t\t\t\tconst p = this.pending.get(event.pointerId);\n\t\t\t\tif (!p) return;\n\t\t\t\tthis.pending.delete(event.pointerId);\n\t\t\t\tconst elapsed = event.timestamp - p.time;\n\t\t\t\tconst dz = event.source === 'touch' ? DEAD_ZONE_TOUCH_PX : DEAD_ZONE_MOUSE_PX;\n\t\t\t\tif (elapsed <= TAP_WINDOW_MS && !exceedsThreshold(event.screen, p.downAt, dz)) {\n\t\t\t\t\tinputLog('Recognizer', `TapRecognizer: up within tap window → tap`, {\n\t\t\t\t\t\tpointerId: event.pointerId,\n\t\t\t\t\t\telapsedMs: elapsed,\n\t\t\t\t\t});\n\t\t\t\t\tmanager.dispatch(makeSynthetic('tap', event, { kind: 'tap', count: 1 }));\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'cancel':\n\t\t\tcase 'drag-start':\n\t\t\tcase 'pinch-start': {\n\t\t\t\tthis.pending.delete(event.pointerId);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\treset(): void {\n\t\tthis.pending.clear();\n\t}\n}\n","import type { EntityId } from '@jamesyong42/reactive-ecs';\nimport { inputLog } from '../debug.js';\nimport type { InputEvent, InputEventType, Surface, WidgetSurfaceRouter } from '../types.js';\n\n/**\n * R3F event manager — the runtime shape we depend on. We avoid importing\n * `EventManager` from `@react-three/fiber` directly to keep this module\n * tree-shakeable for non-R3F consumers; the contract is the seven dispatch\n * methods we actually invoke. R3F's default factory (and\n * `createR3FEventManager`) exposes more (`onWheel`, etc.) but RFC-008 v6\n * routes pointer + click families only. Click family was previously\n * registered by R3F's own `connect` listener; v6 promotes them to first-\n * class InputEvents and routes them through the same path as pointer\n * events for consistent coexistence semantics.\n */\ninterface R3FHandlerMap {\n\treadonly onPointerDown?: (event: PointerEvent) => void;\n\treadonly onPointerMove?: (event: PointerEvent) => void;\n\treadonly onPointerUp?: (event: PointerEvent) => void;\n\treadonly onPointerCancel?: (event: PointerEvent) => void;\n\treadonly onClick?: (event: MouseEvent) => void;\n\treadonly onDoubleClick?: (event: MouseEvent) => void;\n\treadonly onContextMenu?: (event: MouseEvent) => void;\n}\n\ninterface R3FEventManagerLike {\n\treadonly handlers?: R3FHandlerMap;\n\t/**\n\t * Custom probe added by `createR3FEventManager` — returns `true` while\n\t * a mesh inside an R3F widget holds DOM `setPointerCapture` for the\n\t * given pointer ID. Used by the InputManager to skip recognizer\n\t * observation for claimed pointers (so the engine drag doesn't fire\n\t * alongside a widget orbit / pinch / etc.).\n\t */\n\treadonly isPointerCaptured?: (pointerId: number) => boolean;\n}\n\n/**\n * Map `InputEventType`s to the R3F handler name that drives R3F's\n * mesh-dispatch machinery. Pointer types feed R3F's hover-diff + capture\n * pipeline; click family feeds R3F's click synthesis (`onClick`,\n * `onDoubleClick`, `onContextMenu`). v6 routes clicks through this table\n * so the InputManager pipeline is the single source for both engine and\n * widget — no parallel `connect` listener registration on the container.\n */\nconst HANDLER_BY_TYPE: Partial<Record<InputEventType, keyof R3FHandlerMap>> = {\n\tdown: 'onPointerDown',\n\tmove: 'onPointerMove',\n\tup: 'onPointerUp',\n\tcancel: 'onPointerCancel',\n\tclick: 'onClick',\n\tdblclick: 'onDoubleClick',\n\tcontextmenu: 'onContextMenu',\n};\n\n/**\n * RFC-008 v5 — `WidgetSurfaceRouter` for the WebGL surface.\n *\n * Invoked by `InputManager.dispatch` whenever a raw pointer event falls\n * over an entity whose `Widget.surface === 'webgl'`. Looks up the matching\n * R3F mesh-dispatch handler and invokes it with the underlying native\n * event, letting R3F run its raycast → bubble → handler pipeline (with\n * `compute` + `filter` from `createR3FEventManager` targeting the right\n * per-widget scene).\n *\n * The InputManager dispatches the router BEFORE engine handlers, so widget\n * mesh handlers that call `setPointerCapture` (claiming exclusive ownership\n * of the gesture) take effect before the engine's drag/marquee logic could\n * react. Mesh handlers that call `e.stopPropagation()` halt R3F's bubble\n * but NOT the engine's handlers — those listen on the InputManager, not on\n * R3F's bubble. This is the coexistence model: R3F handles widget-internal\n * logic, engine handles canvas-level logic, both react to the same event\n * unless a widget explicitly claims it (RFC-008 § Default coexistence).\n */\nexport class R3FRouter implements WidgetSurfaceRouter {\n\treadonly surface: Surface = 'webgl';\n\n\t/**\n\t * @param getEventManager Returns the R3F event manager whose `handlers`\n\t * we invoke. Wrapped in a getter because R3F creates the manager\n\t * inside the React component tree, so the router (typically constructed\n\t * alongside the InputManager) needs late-bound access.\n\t */\n\tconstructor(private readonly getEventManager: () => R3FEventManagerLike | null | undefined) {}\n\n\troute(event: InputEvent, entityId: EntityId): void {\n\t\tif (!event.native) return;\n\t\tconst handlerName = HANDLER_BY_TYPE[event.type];\n\t\tif (!handlerName) return;\n\n\t\tconst manager = this.getEventManager();\n\t\tconst handler = manager?.handlers?.[handlerName];\n\t\tif (!handler) {\n\t\t\tinputLog('Router', `R3FRouter: no R3F manager / handler for ${handlerName}`, {\n\t\t\t\ttype: event.type,\n\t\t\t\tentityId,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tinputLog('Router', `R3FRouter → R3F.${handlerName} for entity ${entityId}`, {\n\t\t\ttype: event.type,\n\t\t\tentityId,\n\t\t\thandlerName,\n\t\t});\n\t\t// R3F handlers all expect a DOM Event subtype (PointerEvent for\n\t\t// pointer types, MouseEvent for click family). The handler-name\n\t\t// → InputEventType mapping above is the runtime type guard; the\n\t\t// native event was constructed by the matching adapter so the\n\t\t// shape lines up. One cast covers both families.\n\t\t(handler as (event: Event) => void)(event.native);\n\t}\n\n\tisPointerClaimed(pointerId: number): boolean {\n\t\tconst claimed = this.getEventManager()?.isPointerCaptured?.(pointerId) ?? false;\n\t\tif (claimed) {\n\t\t\tinputLog('Router', `R3FRouter: pointer ${pointerId} CLAIMED via setPointerCapture`, {\n\t\t\t\tpointerId,\n\t\t\t});\n\t\t}\n\t\treturn claimed;\n\t}\n}\n","/**\n * Overlap glow — visual config for the drag-over highlight applied to\n * cards (DOM `CardChrome` + R3F `CompositionMaterial`).\n *\n * Single-layer design: a soft radial gradient at the hot point in a\n * neutral color, blended normally over the card content. Deliberately\n * simple — no backdrop-filter, no saturation/contrast tricks, no rim,\n * no bloom. Three tunables: color, alpha (per state), falloff radius.\n *\n * Flows two ways from `<InfiniteCanvas overlapGlow={...} />`:\n * 1. CSS custom properties on the canvas container — read by\n * `CardChrome` via `var(--ic-glow-…, fallback)` for DOM widgets.\n * 2. Shared shader uniforms — every `CompositionMaterial` instance\n * references the same uniform objects, so mutating\n * {@link sharedGlowUniforms} updates all R3F cards at once.\n *\n * Each `[candidate, target]` pair holds the value used while the card\n * is just an overlap candidate vs. when the drop will actually consume.\n */\n\nimport { sharedGlowUniforms } from '../../r3f/compositor/CompositionMaterial.js';\n\nexport interface OverlapGlowConfig {\n\t/** Inner glow RGB color in 0-1 range. */\n\tglowColor: [number, number, number];\n\t/** Inner-glow alpha, [candidate, target]. */\n\tglowAlpha: [number, number];\n\t/**\n\t * Inner-glow blur radius in CSS px — the blur arg of the inset\n\t * box-shadow that paints the glow. Matches `--glow-size` in the\n\t * reference (card-light.html). [candidate, target].\n\t */\n\tglowSize: [number, number];\n\t/** Rim RGB color in 0-1 range (independent of glowColor). */\n\trimColor: [number, number, number];\n\t/** Rim width in CSS px (DOM only — shader rim thickness is fixed). */\n\trimWidth: number;\n\t/** Rim alpha at the bright (hot-point-side) end, [candidate, target]. */\n\trimAlpha: [number, number];\n\t/**\n\t * Rim radial-gradient circle radius in CSS px. Matches `600px circle`\n\t * in the reference. Larger = more uniform rim (less pooling toward\n\t * hot point); smaller = tighter pooling.\n\t */\n\trimRadius: number;\n}\n\nexport const DEFAULT_OVERLAP_GLOW_CONFIG: OverlapGlowConfig = {\n\tglowColor: [0.5, 0.5, 0.5],\n\tglowAlpha: [0.25, 0.45],\n\tglowSize: [60, 80],\n\trimColor: [0.5, 0.5, 0.5],\n\trimWidth: 1.5,\n\trimAlpha: [0.55, 0.85],\n\trimRadius: 600,\n};\n\nfunction rgbTriplet(color: [number, number, number]): string {\n\tconst [r, g, b] = color;\n\treturn `${Math.round(r * 255)}, ${Math.round(g * 255)}, ${Math.round(b * 255)}`;\n}\n\n/** Write the config as CSS custom properties on `target`. CardChrome reads them. */\nexport function applyOverlapGlowVars(target: HTMLElement, c: OverlapGlowConfig): void {\n\tconst s = target.style;\n\ts.setProperty('--ic-glow-color', rgbTriplet(c.glowColor));\n\ts.setProperty('--ic-glow-alpha-c', String(c.glowAlpha[0]));\n\ts.setProperty('--ic-glow-alpha-t', String(c.glowAlpha[1]));\n\ts.setProperty('--ic-glow-size-c', `${c.glowSize[0]}px`);\n\ts.setProperty('--ic-glow-size-t', `${c.glowSize[1]}px`);\n\ts.setProperty('--ic-rim-color', rgbTriplet(c.rimColor));\n\ts.setProperty('--ic-rim-width', `${c.rimWidth}px`);\n\ts.setProperty('--ic-rim-alpha-c', String(c.rimAlpha[0]));\n\ts.setProperty('--ic-rim-alpha-t', String(c.rimAlpha[1]));\n\ts.setProperty('--ic-rim-radius', `${c.rimRadius}px`);\n}\n\n/** Push the same config into the shared shader uniforms (mutates in place). */\nexport function applyOverlapGlowShaderUniforms(c: OverlapGlowConfig): void {\n\tsharedGlowUniforms.uGlowColor.value.set(c.glowColor[0], c.glowColor[1], c.glowColor[2]);\n\tsharedGlowUniforms.uGlowAlpha.value.set(c.glowAlpha[0], c.glowAlpha[1]);\n\t// Shader operates in UV (0..1). Convert px → UV using a fixed\n\t// reference card width of 200px — close enough for visual parity\n\t// across the typical iOS-widget size range.\n\tsharedGlowUniforms.uGlowFalloff.value.set(c.glowSize[0] / 200, c.glowSize[1] / 200);\n\tsharedGlowUniforms.uRimColor.value.set(c.rimColor[0], c.rimColor[1], c.rimColor[2]);\n\tsharedGlowUniforms.uRimAlpha.value.set(c.rimAlpha[0], c.rimAlpha[1]);\n\tsharedGlowUniforms.uRimRadius.value = c.rimRadius / 200;\n}\n\nexport function mergeOverlapGlow(override?: Partial<OverlapGlowConfig>): OverlapGlowConfig {\n\treturn { ...DEFAULT_OVERLAP_GLOW_CONFIG, ...override };\n}\n","import type { EntityId } from '@jamesyong42/reactive-ecs';\nimport type {\n\tWidgetBinding,\n\tWidgetInteractionHandlers,\n\tWidgetRegistry,\n\tWidgetSurface,\n} from '../../ecs/engine/widget-binding.js';\nimport { createWidgetRegistry } from '../../ecs/engine/widget-binding.js';\n\nexport type { WidgetInteractionHandlers, WidgetRegistry, WidgetSurface };\nexport { createWidgetRegistry };\n\n// === Widget Prop Contracts ===\n\n/**\n * Props passed to every DOM widget component. The component is mounted\n * inside a sized `WidgetSlot` div — size via CSS or layout — and renders\n * normal React/HTML.\n *\n * Pointer events work natively (RFC-006): `onClick`, `onPointerOver`,\n * focus, native form inputs, contenteditable, drag-and-drop API — all\n * dispatched by the browser's event path and reach widget children\n * before they bubble to the canvas-level `PointerEventBus`.\n *\n * To opt out of engine routing (drag / select / resize) for an event,\n * call `e.stopPropagation()` from inside the widget. `<button>`,\n * `<input>`, `<textarea>`, `<select>`, and `[contenteditable]` opt out\n * automatically — the bus skips engine routing when the event target\n * matches one of those native interactive selectors.\n */\nexport interface DomWidgetProps {\n\tentityId: EntityId;\n}\n\n/**\n * Props passed to every R3F widget component. Rendered in widget-local\n * coords — the origin is the widget centre, X right, Y up — and the\n * component declares its own Three.js scene through R3F primitives.\n *\n * Pointer events on `<mesh>` / `<group>` work natively (RFC-006):\n * `onClick`, `onPointerOver`, `onPointerOut`, `onPointerEnter`,\n * `onPointerLeave`, `onPointerMove`, `onPointerDown`, `onPointerUp`,\n * `onPointerMissed`, `event.point` / `event.uv` / `event.intersections`,\n * R3F's `event.stopPropagation()` and `setPointerCapture` — all\n * dispatched by a custom EventManager that raycasts the widget's\n * own scene with widget-local coords.\n *\n * To opt out of engine routing (drag / select / resize) for an event,\n * additionally call `event.nativeEvent.stopPropagation()` to prevent\n * the canvas-container `PointerEventBus` from receiving it.\n */\nexport interface R3FWidgetProps {\n\tentityId: EntityId;\n\t/** Widget width in world units. */\n\twidth: number;\n\t/** Widget height in world units. */\n\theight: number;\n}\n\n// === Widget Definitions ===\n\n/** A DOM-rendered widget. The component is wrapped in a sized div — size via CSS. */\nexport interface DomWidget<T = Record<string, unknown>> extends WidgetBinding<T> {\n\tsurface?: 'dom';\n\tcomponent: React.ComponentType<DomWidgetProps>;\n}\n\n/**\n * An R3F (React Three Fiber) widget. The component receives local-space\n * width/height. Card-shaped chrome / lift / drag-promote / compositor\n * discard are all opted in via the `Card` ECS component on the spawned\n * entity (typically declared in the widget's archetype) — see\n * `createGeometryCardWidget` for the convenience wrapper.\n */\nexport interface R3FWidget<T = Record<string, unknown>> extends WidgetBinding<T> {\n\tsurface: 'webgl';\n\tcomponent: React.ComponentType<R3FWidgetProps>;\n}\n\n/** Either kind of widget. */\nexport type Widget<T = Record<string, unknown>> = DomWidget<T> | R3FWidget<T>;\n\n/** Narrows to the R3F variant. */\nexport function isR3FWidget<T>(widget: Widget<T>): widget is R3FWidget<T> {\n\treturn widget.surface === 'webgl';\n}\n","import type { ReactNode } from 'react';\nimport { useCallback } from 'react';\nimport type { LayoutEngine } from '../../ecs/engine/index.js';\nimport type { ResolvedWidget } from '../context/widget-resolver-context.js';\nimport { WidgetResolverProvider } from '../context/widget-resolver-context.js';\nimport { isR3FWidget } from './registry.js';\n\ninterface WidgetProviderProps {\n\tengine: LayoutEngine;\n\tchildren?: ReactNode;\n}\n\n/**\n * Bridges the engine's widget registry to React context so WidgetSlot /\n * R3FManager can resolve components by type.\n */\nexport function WidgetProvider({ engine, children }: WidgetProviderProps) {\n\tconst resolver = useCallback(\n\t\t(_entityId: number, widgetType: string): ResolvedWidget | null => {\n\t\t\tconst def = engine.getWidget(widgetType);\n\t\t\tif (!def) return null;\n\t\t\tif (isR3FWidget(def)) {\n\t\t\t\treturn { surface: 'webgl', component: def.component };\n\t\t\t}\n\t\t\treturn { surface: 'dom', component: def.component };\n\t\t},\n\t\t[engine],\n\t);\n\n\treturn <WidgetResolverProvider value={resolver}>{children}</WidgetResolverProvider>;\n}\n","import type { EntityId } from '@jamesyong42/reactive-ecs';\nimport React, {\n\tuseCallback,\n\tuseEffect,\n\tuseImperativeHandle,\n\tuseLayoutEffect,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n} from 'react';\nimport { Layer, SelectionFrame, Transform2D, Widget, ZIndex } from '../ecs/components.js';\nimport type { LayoutEngine } from '../ecs/engine/index.js';\nimport { CursorResource, NavigationStackResource } from '../ecs/resources.js';\nimport { R3FManager } from '../r3f/R3FManager.js';\nimport type { GridConfig } from '../webgl/renderers/GridRenderer.js';\nimport type { SelectionBounds, SelectionConfig } from '../webgl/renderers/SelectionRenderer.js';\nimport type { SnapGuideConfig } from '../webgl/renderers/SnapGuideRenderer.js';\nimport { WebGLManager } from '../webgl/WebGLManager.js';\nimport { ContainerRefProvider } from './context/container-ref-context.js';\nimport { EngineProvider } from './context/engine-context.js';\nimport { useWidgetResolver } from './context/widget-resolver-context.js';\nimport { ClickAdapter } from './input/adapters/ClickAdapter.js';\nimport { PointerAdapter } from './input/adapters/PointerAdapter.js';\nimport { WheelAdapter } from './input/adapters/WheelAdapter.js';\nimport { InputManager } from './input/InputManager.js';\nimport { installEngineHandlers } from './input/installEngineHandlers.js';\nimport { DoubleTapRecognizer } from './input/recognizers/DoubleTapRecognizer.js';\nimport { DragRecognizer } from './input/recognizers/DragRecognizer.js';\nimport { HoverRecognizer } from './input/recognizers/HoverRecognizer.js';\nimport { PanRecognizer } from './input/recognizers/PanRecognizer.js';\nimport { PinchRecognizer } from './input/recognizers/PinchRecognizer.js';\nimport { TapRecognizer } from './input/recognizers/TapRecognizer.js';\nimport { R3FRouter } from './input/routers/R3FRouter.js';\nimport { SelectionOverlaySlot } from './overlays/SelectionOverlaySlot.js';\nimport {\n\tapplyOverlapGlowShaderUniforms,\n\tapplyOverlapGlowVars,\n\tmergeOverlapGlow,\n\ttype OverlapGlowConfig,\n} from './widgets/overlap-glow.js';\nimport { WidgetProvider } from './widgets/WidgetProvider.js';\nimport { WidgetSlot } from './widgets/WidgetSlot.js';\n\n/** Imperative handle exposed via `ref` on InfiniteCanvas for programmatic control. */\nexport interface InfiniteCanvasHandle {\n\tpanTo(worldX: number, worldY: number): void;\n\tzoomTo(zoom: number): void;\n\tzoomToFit(padding?: number): void;\n\tundo(): void;\n\tredo(): void;\n\tgetEngine(): LayoutEngine;\n}\n\ninterface InfiniteCanvasProps {\n\t/**\n\t * The LayoutEngine instance powering this canvas. Create with `createLayoutEngine()`.\n\t */\n\tengine: LayoutEngine;\n\t/** Grid configuration. Pass `false` to disable the grid entirely. */\n\tgrid?: Partial<GridConfig> | false;\n\t/**\n\t * Drag-over glow configuration — controls every visual parameter of\n\t * the highlight applied to a card while another card is being dragged\n\t * over it. Drives both the DOM `CardChrome` (via CSS custom\n\t * properties on the canvas container) and the R3F compositor shader\n\t * (via shared uniforms) so the look stays in sync across widget\n\t * surfaces.\n\t */\n\toverlapGlow?: Partial<OverlapGlowConfig>;\n\t/** Selection highlight style configuration. */\n\tselection?: Partial<SelectionConfig>;\n\t/** Snap guide overlay style (color, line width, alpha). */\n\tsnapGuides?: Partial<SnapGuideConfig>;\n\tonSelectionChange?: (entityIds: EntityId[]) => void;\n\tonCameraChange?: (camera: { x: number; y: number; zoom: number }) => void;\n\tonNavigationChange?: (depth: number, containerId: EntityId | null) => void;\n\tclassName?: string;\n\tstyle?: React.CSSProperties;\n\tchildren?: React.ReactNode;\n\t/**\n\t * R3F nodes mounted at the root of the internal `<Canvas>`, as siblings\n\t * of the widget compositor. Use this for canvas-level Three.js state\n\t * that must survive widget lifecycle — drei's `<Environment>` is the\n\t * canonical case: mounting it in a widget ties global IBL to that\n\t * widget's `Active` state, so consuming it into a folder or\n\t * navigating away kills lighting for every other widget. A root-level\n\t * `<Environment>` stays mounted as long as the canvas itself is, and\n\t * the compositor propagates its texture to every per-widget scene.\n\t */\n\tr3fRoot?: React.ReactNode;\n}\n\nexport const InfiniteCanvas = React.forwardRef<InfiniteCanvasHandle, InfiniteCanvasProps>(\n\tfunction InfiniteCanvas(\n\t\t{\n\t\t\tengine,\n\t\t\tgrid,\n\t\t\toverlapGlow,\n\t\t\tselection,\n\t\t\tsnapGuides,\n\t\t\tonSelectionChange,\n\t\t\tonCameraChange,\n\t\t\tonNavigationChange,\n\t\t\tclassName,\n\t\t\tstyle,\n\t\t\tchildren,\n\t\t\tr3fRoot,\n\t\t},\n\t\tref,\n\t) {\n\t\tconst containerRef = useRef<HTMLDivElement>(null);\n\t\t// R3F's `<Canvas eventSource={ref}>` resolves `ref.current` once at\n\t\t// canvas-init time. Mounting R3FBridge before the container ref is\n\t\t// populated would leave R3F unable to attach its native pointer\n\t\t// listeners. This flag flips true after the first commit, when the\n\t\t// container's ref is guaranteed to be assigned.\n\t\tconst [containerMounted, setContainerMounted] = useState(false);\n\t\tuseLayoutEffect(() => {\n\t\t\tsetContainerMounted(true);\n\t\t}, []);\n\n\t\t// Keep latest callback refs to avoid stale closures in the rAF loop\n\t\tconst onSelectionChangeRef = useRef(onSelectionChange);\n\t\tconst onCameraChangeRef = useRef(onCameraChange);\n\t\tconst onNavigationChangeRef = useRef(onNavigationChange);\n\t\tuseEffect(() => {\n\t\t\tonSelectionChangeRef.current = onSelectionChange;\n\t\t}, [onSelectionChange]);\n\t\tuseEffect(() => {\n\t\t\tonCameraChangeRef.current = onCameraChange;\n\t\t}, [onCameraChange]);\n\t\tuseEffect(() => {\n\t\t\tonNavigationChangeRef.current = onNavigationChange;\n\t\t}, [onNavigationChange]);\n\n\t\t// Latest renderer-style refs so the WebGLManager can be constructed\n\t\t// with the user's initial config on first mount, without taking\n\t\t// `selection` / `snapGuides` as deps of the mount effect (which\n\t\t// would tear down + rebuild the GL context on every prop change).\n\t\t// Runtime updates still flow through the dedicated useEffect below.\n\t\tconst selectionRef = useRef(selection);\n\t\tconst snapGuidesRef = useRef(snapGuides);\n\t\tuseEffect(() => {\n\t\t\tselectionRef.current = selection;\n\t\t}, [selection]);\n\t\tuseEffect(() => {\n\t\t\tsnapGuidesRef.current = snapGuides;\n\t\t}, [snapGuides]);\n\n\t\tuseImperativeHandle(\n\t\t\tref,\n\t\t\t() => ({\n\t\t\t\tpanTo: (x, y) => {\n\t\t\t\t\tengine.panTo(x, y);\n\t\t\t\t\tengine.markDirty();\n\t\t\t\t},\n\t\t\t\tzoomTo: (zoom) => {\n\t\t\t\t\tengine.zoomTo(zoom);\n\t\t\t\t\tengine.markDirty();\n\t\t\t\t},\n\t\t\t\tzoomToFit: (padding) => {\n\t\t\t\t\tengine.zoomToFit(undefined, padding);\n\t\t\t\t\tengine.markDirty();\n\t\t\t\t},\n\t\t\t\tundo: () => {\n\t\t\t\t\tengine.undo();\n\t\t\t\t\tengine.markDirty();\n\t\t\t\t},\n\t\t\t\tredo: () => {\n\t\t\t\t\tengine.redo();\n\t\t\t\t\tengine.markDirty();\n\t\t\t\t},\n\t\t\t\tgetEngine: () => engine,\n\t\t\t}),\n\t\t\t[engine],\n\t\t);\n\n\t\tconst webglCanvasRef = useRef<HTMLCanvasElement>(null);\n\t\tconst webglManagerRef = useRef<WebGLManager | null>(null);\n\t\t// One transform ref per layer container — all driven by the same\n\t\t// camera transform so they pan / zoom in lockstep. RFC-003.\n\t\tconst backgroundLayerRef = useRef<HTMLDivElement>(null);\n\t\tconst baseLayerRef = useRef<HTMLDivElement>(null);\n\t\tconst overlayLayerRef = useRef<HTMLDivElement>(null);\n\t\tconst slotRefs = useRef(new Map<EntityId, HTMLDivElement>());\n\t\tconst [visibleEntities, setVisibleEntities] = useState<EntityId[]>([]);\n\n\t\t// Register slot ref for batch updater\n\t\tconst registerSlotRef = useCallback((entityId: EntityId, el: HTMLDivElement | null) => {\n\t\t\tif (el) {\n\t\t\t\tslotRefs.current.set(entityId, el);\n\t\t\t} else {\n\t\t\t\tslotRefs.current.delete(entityId);\n\t\t\t}\n\t\t}, []);\n\n\t\t// Initialise WebGLManager + viewport on mount/resize.\n\t\tuseLayoutEffect(() => {\n\t\t\tconst container = containerRef.current;\n\t\t\tconst canvas = webglCanvasRef.current;\n\t\t\tif (!container || !canvas) return;\n\n\t\t\tconst manager = new WebGLManager(canvas, {\n\t\t\t\tgrid,\n\t\t\t\tselection: selectionRef.current,\n\t\t\t\tsnapGuides: snapGuidesRef.current,\n\t\t\t});\n\t\t\twebglManagerRef.current = manager;\n\n\t\t\tconst updateSize = () => {\n\t\t\t\tconst rect = container.getBoundingClientRect();\n\t\t\t\tconst dpr = window.devicePixelRatio;\n\t\t\t\tengine.setViewport(rect.width, rect.height, dpr);\n\t\t\t\tcanvas.style.width = `${rect.width}px`;\n\t\t\t\tcanvas.style.height = `${rect.height}px`;\n\t\t\t\tmanager.setSize(rect.width, rect.height, dpr);\n\t\t\t};\n\n\t\t\tupdateSize();\n\t\t\tconst observer = new ResizeObserver(updateSize);\n\t\t\tobserver.observe(container);\n\t\t\treturn () => {\n\t\t\t\tobserver.disconnect();\n\t\t\t\tmanager.dispose();\n\t\t\t\twebglManagerRef.current = null;\n\t\t\t};\n\t\t}, [engine, grid]);\n\n\t\t// Apply grid + selection config on every render\n\t\tuseEffect(() => {\n\t\t\tconst manager = webglManagerRef.current;\n\t\t\tif (!manager) return;\n\t\t\tif (grid !== false) {\n\t\t\t\tconst isDark = document.documentElement.classList.contains('dark');\n\t\t\t\tmanager.setGridConfig({\n\t\t\t\t\t// Soft neutral gray — matches Apple Freeform / FigJam look.\n\t\t\t\t\t// Dark-mode value is slightly desaturated to read well on\n\t\t\t\t\t// near-black backgrounds without blooming.\n\t\t\t\t\tdotColor: isDark ? [0.35, 0.37, 0.4] : [0.75, 0.77, 0.8],\n\t\t\t\t\tdotAlpha: 1.0,\n\t\t\t\t\t...grid,\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (selection) {\n\t\t\t\tmanager.setSelectionConfig(selection);\n\t\t\t}\n\t\t\tif (snapGuides) {\n\t\t\t\tmanager.setSnapGuideConfig(snapGuides);\n\t\t\t}\n\t\t\tengine.markDirty();\n\t\t}, [engine, grid, selection, snapGuides]);\n\n\t\t// Apply overlap-glow config: write CSS vars on the canvas container\n\t\t// (DOM `CardChrome` reads them), and push the same values into the\n\t\t// shared shader uniforms (R3F `CompositionMaterial` reads them).\n\t\t// Both paths see the change without re-mounting anything.\n\t\tuseEffect(() => {\n\t\t\tconst merged = mergeOverlapGlow(overlapGlow);\n\t\t\tconst container = containerRef.current;\n\t\t\tif (container) applyOverlapGlowVars(container, merged);\n\t\t\tapplyOverlapGlowShaderUniforms(merged);\n\t\t\tengine.markDirty();\n\t\t}, [engine, overlapGlow]);\n\n\t\t// RFC-008 — late-bound R3F event manager. R3F's `<Canvas events={...}>`\n\t\t// invokes the factory once at canvas mount; the factory writes the\n\t\t// produced manager into this ref so `R3FRouter` can dispatch into\n\t\t// R3F's mesh handlers from the InputManager pipeline.\n\t\t// biome-ignore lint/suspicious/noExplicitAny: R3F's EventManager\n\t\t// type isn't surfaced cleanly through our types; the router only\n\t\t// needs `.handlers.onPointerXxx` and reads it dynamically.\n\t\tconst r3fEventManagerRef = useRef<any>(null);\n\n\t\t// RFC-008 Phase 3d — single InputManager owns all pointer + wheel\n\t\t// listeners on the canvas container. Recognizers turn raw events\n\t\t// into synthetic gestures; `installEngineHandlers` wires the engine\n\t\t// to those gestures; `R3FRouter` delivers raw pointer events over\n\t\t// R3F widgets to R3F's mesh-dispatch machinery (replacing\n\t\t// PointerEventBus, TouchEventBus, the inline wheel useEffect, and\n\t\t// the parallel R3F EventRouter listener architecture).\n\t\tuseEffect(() => {\n\t\t\tconst container = containerRef.current;\n\t\t\tif (!container) return;\n\n\t\t\tconst manager = new InputManager(engine, container, [\n\t\t\t\tnew PointerAdapter(),\n\t\t\t\tnew WheelAdapter(),\n\t\t\t\tnew ClickAdapter(),\n\t\t\t]);\n\n\t\t\t// Recognizer registration order is observation-only — pairwise\n\t\t\t// cancellations run via synthetic `cancel` dispatch, not by\n\t\t\t// observation order. Listed source-of-input first, then derived.\n\t\t\tmanager.addRecognizer(new HoverRecognizer());\n\t\t\tmanager.addRecognizer(new TapRecognizer());\n\t\t\tmanager.addRecognizer(new DoubleTapRecognizer());\n\t\t\tmanager.addRecognizer(new DragRecognizer());\n\t\t\tmanager.addRecognizer(new PinchRecognizer());\n\t\t\tmanager.addRecognizer(new PanRecognizer());\n\n\t\t\tmanager.setRouter(new R3FRouter(() => r3fEventManagerRef.current));\n\n\t\t\tconst offHandlers = installEngineHandlers(manager, engine, container);\n\n\t\t\tconst detach = manager.attach();\n\t\t\treturn () => {\n\t\t\t\toffHandlers();\n\t\t\t\tdetach();\n\t\t\t\t// Clear the late-bound R3F manager ref. Without this, an\n\t\t\t\t// `<R3FBridge>` unmount (last webgl entity removed) would\n\t\t\t\t// leave a stale manager pointer in the ref; a subsequent\n\t\t\t\t// pointer event picked up before remount would route into\n\t\t\t\t// a dead manager.\n\t\t\t\tr3fEventManagerRef.current = null;\n\t\t\t};\n\t\t}, [engine]);\n\n\t\t// rAF tick loop — flushes the engine when dirty, then applies updates.\n\t\tuseEffect(() => {\n\t\t\tlet rafId: number;\n\t\t\tlet running = true;\n\n\t\t\tfunction loop() {\n\t\t\t\tif (!running) return;\n\n\t\t\t\tconst didTick = engine.flushIfDirty();\n\t\t\t\tif (didTick) {\n\t\t\t\t\tconst camera = engine.getCamera();\n\t\t\t\t\tconst changes = engine.getFrameChanges();\n\n\t\t\t\t\t// 1. Update camera layer CSS transform (O(1) for pan/zoom)\n\t\t\t\t\tconst transform = `scale(${camera.zoom}) translate(${-camera.x}px, ${-camera.y}px)`;\n\t\t\t\t\tif (backgroundLayerRef.current) backgroundLayerRef.current.style.transform = transform;\n\t\t\t\t\tif (baseLayerRef.current) baseLayerRef.current.style.transform = transform;\n\t\t\t\t\tif (overlayLayerRef.current) overlayLayerRef.current.style.transform = transform;\n\n\t\t\t\t\t// RFC-001 Phase 7: apply derived cursor to root container.\n\t\t\t\t\tconst cursor = engine.world.getResource(CursorResource).cursor;\n\t\t\t\t\tif (containerRef.current && containerRef.current.style.cursor !== cursor) {\n\t\t\t\t\t\tcontainerRef.current.style.cursor = cursor;\n\t\t\t\t\t}\n\n\t\t\t\t\t// 1b. Drive WebGL layer via the manager — grid + selection + profiler.\n\t\t\t\t\tconst manager = webglManagerRef.current;\n\t\t\t\t\tif (manager) {\n\t\t\t\t\t\tconst selectedIds = engine.getSelectedEntities();\n\t\t\t\t\t\tconst selBounds: SelectionBounds[] = [];\n\t\t\t\t\t\tfor (const id of selectedIds) {\n\t\t\t\t\t\t\t// Widgets that render their own chrome (e.g. cards) opt out\n\t\t\t\t\t\t\t// of the engine-drawn frame by lacking the SelectionFrame tag.\n\t\t\t\t\t\t\tif (!engine.has(id, SelectionFrame)) continue;\n\t\t\t\t\t\t\tconst t = engine.get(id, Transform2D);\n\t\t\t\t\t\t\tif (t)\n\t\t\t\t\t\t\t\tselBounds.push({\n\t\t\t\t\t\t\t\t\tx: t.x,\n\t\t\t\t\t\t\t\t\ty: t.y,\n\t\t\t\t\t\t\t\t\twidth: t.width,\n\t\t\t\t\t\t\t\t\theight: t.height,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst hovId = engine.getHoveredEntity();\n\t\t\t\t\t\tlet hovBounds: SelectionBounds | null = null;\n\t\t\t\t\t\tif (hovId !== null && engine.has(hovId, SelectionFrame)) {\n\t\t\t\t\t\t\tconst t = engine.get(hovId, Transform2D);\n\t\t\t\t\t\t\tif (t)\n\t\t\t\t\t\t\t\thovBounds = {\n\t\t\t\t\t\t\t\t\tx: t.x,\n\t\t\t\t\t\t\t\t\ty: t.y,\n\t\t\t\t\t\t\t\t\twidth: t.width,\n\t\t\t\t\t\t\t\t\theight: t.height,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tmanager.render({\n\t\t\t\t\t\t\tcamera: { x: camera.x, y: camera.y, zoom: camera.zoom },\n\t\t\t\t\t\t\tselection: {\n\t\t\t\t\t\t\t\tbounds: selBounds,\n\t\t\t\t\t\t\t\thovered: hovBounds,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tsnap: {\n\t\t\t\t\t\t\t\tguides: engine.getSnapGuides(),\n\t\t\t\t\t\t\t\tspacings: engine.getEqualSpacing(),\n\t\t\t\t\t\t\t\tvisible: engine.getSnapGuidesVisible(),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tprofiler: engine.profiler,\n\t\t\t\t\t\t\tdomPositionsUpdated: changes.positionsChanged.length,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\t// 2. Push frame-local Transform2D changes into each slot's style.\n\t\t\t\t\t// (Post-RFC-004 Phase 0b there's no `WorldBounds` shadow —\n\t\t\t\t\t// Transform2D is already in the current frame's coord system.)\n\t\t\t\t\tfor (const entityId of changes.positionsChanged) {\n\t\t\t\t\t\tconst el = slotRefs.current.get(entityId);\n\t\t\t\t\t\tif (!el) continue;\n\t\t\t\t\t\tconst t = engine.get(entityId, Transform2D);\n\t\t\t\t\t\tif (!t) continue;\n\t\t\t\t\t\tel.style.transform = `translate(${t.x}px, ${t.y}px)`;\n\t\t\t\t\t\tel.style.width = `${t.width}px`;\n\t\t\t\t\t\tel.style.height = `${t.height}px`;\n\t\t\t\t\t}\n\n\t\t\t\t\t// 2b. Push ZIndex changes to CSS z-index so drag-bumped R3F\n\t\t\t\t\t// cards lift above their siblings. DOM cards also pick\n\t\t\t\t\t// this up — the Layer re-bucket alone isn't enough when\n\t\t\t\t\t// two cards share a layer; ZIndex is the tiebreak. R3F\n\t\t\t\t\t// cards skip the Layer-promote path (RFC-003) so ZIndex\n\t\t\t\t\t// is their only lift signal on the CSS chrome.\n\t\t\t\t\tfor (const entityId of changes.zIndicesChanged) {\n\t\t\t\t\t\tconst el = slotRefs.current.get(entityId);\n\t\t\t\t\t\tif (!el) continue;\n\t\t\t\t\t\tconst z = engine.get(entityId, ZIndex);\n\t\t\t\t\t\tel.style.zIndex = z ? String(z.value) : '';\n\t\t\t\t\t}\n\n\t\t\t\t\t// 3. Update visible entity list if entities entered/exited,\n\t\t\t\t\t// or any visible entity's Layer component changed (re-bucket\n\t\t\t\t\t// trigger for RFC-003 dragPromoteSystem).\n\t\t\t\t\tif (changes.entered.length > 0 || changes.exited.length > 0 || changes.layersChanged) {\n\t\t\t\t\t\tconst visible = engine.getVisibleEntities();\n\t\t\t\t\t\tsetVisibleEntities(visible.map((v) => v.entityId));\n\t\t\t\t\t}\n\n\t\t\t\t\t// 4. Fire event callbacks\n\t\t\t\t\tif (changes.selectionChanged && onSelectionChangeRef.current) {\n\t\t\t\t\t\tonSelectionChangeRef.current(engine.getSelectedEntities());\n\t\t\t\t\t}\n\t\t\t\t\tif (changes.cameraChanged && onCameraChangeRef.current) {\n\t\t\t\t\t\tonCameraChangeRef.current({ x: camera.x, y: camera.y, zoom: camera.zoom });\n\t\t\t\t\t}\n\t\t\t\t\tif (changes.navigationChanged && onNavigationChangeRef.current) {\n\t\t\t\t\t\tconst navStack = engine.world.getResource(NavigationStackResource);\n\t\t\t\t\t\tconst depth = navStack.frames.length - 1;\n\t\t\t\t\t\tconst containerId = navStack.frames[navStack.frames.length - 1].containerId;\n\t\t\t\t\t\tonNavigationChangeRef.current(depth, containerId);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\trafId = requestAnimationFrame(loop);\n\t\t\t}\n\n\t\t\t// Initial tick on mount\n\t\t\tengine.tick();\n\t\t\tconst visible = engine.getVisibleEntities();\n\t\t\tsetVisibleEntities(visible.map((v) => v.entityId));\n\n\t\t\t// Set initial camera transform\n\t\t\tconst camera = engine.getCamera();\n\t\t\tconst initTransform = `scale(${camera.zoom}) translate(${-camera.x}px, ${-camera.y}px)`;\n\t\t\tif (backgroundLayerRef.current) backgroundLayerRef.current.style.transform = initTransform;\n\t\t\tif (baseLayerRef.current) baseLayerRef.current.style.transform = initTransform;\n\t\t\tif (overlayLayerRef.current) overlayLayerRef.current.style.transform = initTransform;\n\n\t\t\t// Initial WebGL render\n\t\t\tconst manager = webglManagerRef.current;\n\t\t\tif (manager) {\n\t\t\t\tmanager.render({\n\t\t\t\t\tcamera: { x: camera.x, y: camera.y, zoom: camera.zoom },\n\t\t\t\t\tselection: { bounds: [], hovered: null },\n\t\t\t\t\tsnap: { guides: [], spacings: [], visible: false },\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Set initial slot positions\n\t\t\tfor (const v of visible) {\n\t\t\t\tconst el = slotRefs.current.get(v.entityId);\n\t\t\t\tif (!el) continue;\n\t\t\t\tel.style.transform = `translate(${v.x}px, ${v.y}px)`;\n\t\t\t\tel.style.width = `${v.width}px`;\n\t\t\t\tel.style.height = `${v.height}px`;\n\t\t\t\tel.style.zIndex = String(v.zIndex);\n\t\t\t}\n\n\t\t\trafId = requestAnimationFrame(loop);\n\n\t\t\treturn () => {\n\t\t\t\trunning = false;\n\t\t\t\tcancelAnimationFrame(rafId);\n\t\t\t};\n\t\t}, [engine]);\n\n\t\t// Fix #4: useLayoutEffect to set initial positions BEFORE browser paint\n\t\tuseLayoutEffect(() => {\n\t\t\tfor (const entityId of visibleEntities) {\n\t\t\t\tconst el = slotRefs.current.get(entityId);\n\t\t\t\tif (!el) continue;\n\t\t\t\tconst t = engine.get(entityId, Transform2D);\n\t\t\t\tif (!t) continue;\n\t\t\t\tel.style.transform = `translate(${t.x}px, ${t.y}px)`;\n\t\t\t\tel.style.width = `${t.width}px`;\n\t\t\t\tel.style.height = `${t.height}px`;\n\t\t\t\tconst z = engine.get(entityId, ZIndex);\n\t\t\t\tif (z) el.style.zIndex = String(z.value);\n\t\t\t}\n\t\t}, [visibleEntities, engine]);\n\n\t\t// Split visible entities by surface AND by layer (RFC-003).\n\t\t// DOM widgets bucket directly into their target layer container.\n\t\t// R3F widgets always render through the R3F canvas; their\n\t\t// SelectionOverlaySlot (chrome + interaction surface) buckets into\n\t\t// the layer container matching their Layer.name.\n\t\t//\n\t\t// Re-bucket runs when visibleEntities ref changes — driven by the\n\t\t// rAF loop, which now calls setVisibleEntities on entered/exited\n\t\t// OR FrameChanges.layersChanged. The latter fires whenever any\n\t\t// entity's Layer component value changed during the tick (RFC-003\n\t\t// dragPromoteSystem flip / restore).\n\t\tconst { backgroundDom, baseDom, overlayDom, webglEntities } = useMemo(() => {\n\t\t\tconst background: EntityId[] = [];\n\t\t\tconst base: EntityId[] = [];\n\t\t\tconst overlay: EntityId[] = [];\n\t\t\tconst webgl: EntityId[] = [];\n\t\t\tfor (const id of visibleEntities) {\n\t\t\t\tconst w = engine.get(id, Widget);\n\t\t\t\tif (w?.surface === 'webgl') webgl.push(id);\n\t\t\t\tconst layerName = engine.get(id, Layer)?.name ?? 'base';\n\t\t\t\tconst bucket =\n\t\t\t\t\tlayerName === 'background' ? background : layerName === 'overlay' ? overlay : base;\n\t\t\t\tbucket.push(id);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tbackgroundDom: background,\n\t\t\t\tbaseDom: base,\n\t\t\t\toverlayDom: overlay,\n\t\t\t\twebglEntities: webgl,\n\t\t\t};\n\t\t}, [visibleEntities, engine]);\n\n\t\tconst canvasContent = (\n\t\t\t<div\n\t\t\t\tref={containerRef}\n\t\t\t\tclassName={`relative overflow-hidden ${className ?? ''}`}\n\t\t\t\tstyle={{\n\t\t\t\t\t...style,\n\t\t\t\t\ttouchAction: 'none',\n\t\t\t\t\tbackgroundColor: 'var(--canvas-bg, #fafafa)',\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{/* Vanilla WebGL layer — dot grid + selection overlays (driven by WebGLManager) */}\n\t\t\t\t<canvas ref={webglCanvasRef} className=\"absolute inset-0 pointer-events-none\" />\n\n\t\t\t\t{/* Background — purely visual; pointer handlers live on the container. */}\n\t\t\t\t<div className=\"absolute inset-0 pointer-events-none\" />\n\n\t\t\t\t{/* RFC-003 layer stack:\n\t\t\t\t 'background' + 'base' beneath the R3F canvas (zIndex < 1)\n\t\t\t\t R3F canvas at zIndex 1\n\t\t\t\t 'overlay' above the R3F canvas (zIndex 2)\n\t\t\t\t All three DOM containers share the same camera transform\n\t\t\t\t so they pan / zoom in lockstep. */}\n\t\t\t\t<LayerContainer layerRef={backgroundLayerRef}>\n\t\t\t\t\t{bucketSlots(backgroundDom, engine, registerSlotRef)}\n\t\t\t\t</LayerContainer>\n\t\t\t\t<LayerContainer layerRef={baseLayerRef}>\n\t\t\t\t\t{bucketSlots(baseDom, engine, registerSlotRef)}\n\t\t\t\t</LayerContainer>\n\n\t\t\t\t{/* R3F layer — 3D widgets (lazy, only when webgl entities exist).\n\t\t\t\t Gated on `containerMounted` so R3F's `eventSource` ref is\n\t\t\t\t populated by the time `<Canvas>` resolves it. */}\n\t\t\t\t{containerMounted && webglEntities.length > 0 && (\n\t\t\t\t\t<R3FBridge\n\t\t\t\t\t\tengine={engine}\n\t\t\t\t\t\tentities={webglEntities}\n\t\t\t\t\t\tr3fRoot={r3fRoot}\n\t\t\t\t\t\teventManagerRef={r3fEventManagerRef}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\n\t\t\t\t<LayerContainer layerRef={overlayLayerRef} zIndex={2}>\n\t\t\t\t\t{bucketSlots(overlayDom, engine, registerSlotRef)}\n\t\t\t\t</LayerContainer>\n\n\t\t\t\t{/* Children: toolbars, panels, etc. */}\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t);\n\n\t\treturn (\n\t\t\t<EngineProvider value={engine}>\n\t\t\t\t<ContainerRefProvider value={containerRef}>\n\t\t\t\t\t<WidgetProvider engine={engine}>{canvasContent}</WidgetProvider>\n\t\t\t\t</ContainerRefProvider>\n\t\t\t</EngineProvider>\n\t\t);\n\t},\n);\n\n/** Bridge component — reads widget resolver from context and passes to R3FManager. */\nfunction R3FBridge({\n\tengine,\n\tentities,\n\tr3fRoot,\n\teventManagerRef,\n}: {\n\tengine: LayoutEngine;\n\tentities: EntityId[];\n\tr3fRoot?: React.ReactNode;\n\t// biome-ignore lint/suspicious/noExplicitAny: late-bound R3F manager ref.\n\teventManagerRef: React.MutableRefObject<any>;\n}) {\n\tconst resolver = useWidgetResolver();\n\tconst resolve = useCallback(\n\t\t(entityId: EntityId) => {\n\t\t\tif (!resolver) return null;\n\t\t\tconst w = engine.get(entityId, Widget);\n\t\t\treturn resolver(entityId, w?.type ?? '');\n\t\t},\n\t\t[resolver, engine],\n\t);\n\n\tif (!resolver) return null;\n\n\treturn (\n\t\t<R3FManager\n\t\t\tengine={engine}\n\t\t\tentities={entities}\n\t\t\tresolve={resolve}\n\t\t\tr3fRoot={r3fRoot}\n\t\t\teventManagerRef={eventManagerRef}\n\t\t/>\n\t);\n}\n\n/**\n * One DOM container for a render layer (RFC-003). Each container holds\n * the WidgetSlot / SelectionOverlaySlot elements for the entities\n * bucketed into its layer; the container's CSS transform is driven by\n * the rAF loop so all layers pan / zoom in lockstep.\n *\n * `zIndex` is applied via a one-shot effect (not via React's `style`\n * prop) so it doesn't fight the rAF loop's direct `style.transform`\n * writes — and so it doesn't depend on Tailwind's content scanner\n * picking up the class from inside the library bundle (which it\n * doesn't, since the library lives in node_modules of the consumer).\n */\nfunction LayerContainer({\n\tlayerRef,\n\tzIndex,\n\tchildren,\n}: {\n\tlayerRef: React.RefObject<HTMLDivElement | null>;\n\tzIndex?: number;\n\tchildren: React.ReactNode;\n}) {\n\tuseEffect(() => {\n\t\tif (zIndex !== undefined && layerRef.current) {\n\t\t\tlayerRef.current.style.zIndex = String(zIndex);\n\t\t}\n\t}, [layerRef, zIndex]);\n\treturn (\n\t\t<div ref={layerRef} className=\"absolute left-0 top-0 origin-top-left will-change-transform\">\n\t\t\t{children}\n\t\t</div>\n\t);\n}\n\n/**\n * Renders the right slot per entity in a layer container — DOM widgets\n * get a `WidgetSlot`, R3F widgets get a `SelectionOverlaySlot` (chrome\n * + interaction surface; the actual 3D content renders through the R3F\n * canvas). Pure helper so the JSX in the main component stays compact.\n */\nfunction bucketSlots(\n\tentities: EntityId[],\n\tengine: LayoutEngine,\n\tregisterSlotRef: (entityId: EntityId, el: HTMLDivElement | null) => void,\n): React.ReactNode[] {\n\treturn entities.map((entityId) => {\n\t\tconst w = engine.get(entityId, Widget);\n\t\treturn w?.surface === 'webgl' ? (\n\t\t\t<SelectionOverlaySlot key={entityId} entityId={entityId} slotRef={registerSlotRef} />\n\t\t) : (\n\t\t\t<WidgetSlot key={entityId} entityId={entityId} slotRef={registerSlotRef} />\n\t\t);\n\t});\n}\n","import type { EntityId } from '@jamesyong42/reactive-ecs';\nimport type * as React from 'react';\nimport type { Archetype } from '../../ecs/archetype.js';\nimport type { CardPreset } from '../../ecs/components.js';\nimport {\n\tCard,\n\tCardOverlapHotPoint,\n\tDragging,\n\tOverlapCandidate,\n\tOverlapTarget,\n} from '../../ecs/components.js';\nimport type { WidgetInteractionHandlers } from '../../ecs/engine/widget-binding.js';\nimport { DEFAULT_CARD_PRESET_SIZES } from '../../ecs/resources.js';\nimport type { StandardSchemaV1 } from '../../ecs/schema.js';\nimport { useComponent, useTag } from '../hooks/ecs.js';\nimport { useWidgetData } from '../hooks/widget.js';\nimport { CardChrome } from './CardChrome.js';\nimport type { DomWidget, DomWidgetProps } from './registry.js';\n\n/** Props accepted by `<CardFrame>`. */\nexport interface CardFrameProps {\n\tentityId: EntityId;\n\tchildren?: React.ReactNode;\n\tclassName?: string;\n\t/** Merged into the frame div's style (wins over defaults). */\n\tstyle?: React.CSSProperties;\n}\n\n/**\n * Visual chrome for an iOS-style card. Reads the entity's `Dragging` tag\n * and forwards `lifted` to {@link CardChrome}, which owns the actual\n * appearance (rounded corners, hairline ring, soft drop shadow, lift\n * transition). Same chrome is used by R3F geometry cards via a DOM slot\n * beneath the WebGL canvas, so DOM and 3D cards stay visually identical.\n */\nexport function CardFrame({ entityId, children, className, style }: CardFrameProps) {\n\tconst dragging = useTag(entityId, Dragging);\n\tconst overlapCandidate = useTag(entityId, OverlapCandidate);\n\tconst overlapTarget = useTag(entityId, OverlapTarget);\n\tconst hot = useComponent(entityId, CardOverlapHotPoint);\n\treturn (\n\t\t<CardChrome\n\t\t\tlifted={dragging}\n\t\t\tclassName={className}\n\t\t\tstyle={style}\n\t\t\toverlapCandidate={overlapCandidate}\n\t\t\toverlapTarget={overlapTarget}\n\t\t\thotX={hot?.x}\n\t\t\thotY={hot?.y}\n\t\t\thotStrength={hot?.strength}\n\t\t>\n\t\t\t{children}\n\t\t</CardChrome>\n\t);\n}\n\n/** Options passed to `createCardWidget`. */\nexport interface CreateCardWidgetOptions<T> {\n\t/** Unique widget type id. Doubles as the archetype id. */\n\ttype: string;\n\t/** Which iOS preset the card sits at. Fixed for the widget's lifetime (change via `engine.set(id, Card, { preset })`). */\n\tsize: CardPreset;\n\t/** Standard Schema v1-compatible validator for the widget's data. */\n\t// biome-ignore lint/suspicious/noExplicitAny: schema Input is intentionally permissive\n\tschema: StandardSchemaV1<any, T>;\n\t/** Default data for new instances; merged with user-supplied data at spawn. */\n\tdefaultData: T;\n\t/** The card's rendered content. Receives entityId + typed data. */\n\trender: React.ComponentType<{ entityId: EntityId; data: T }>;\n\t/**\n\t * Drop-to-consume contract — what this card accepts as a parent\n\t * (RFC-004 § Phase 1). Stamped onto the archetype's `Card`\n\t * component so every spawned instance carries it. Defaults to `[]`.\n\t */\n\taccepts?: readonly string[];\n\t/**\n\t * Drop-to-consume contract — what this card provides when dropped\n\t * as a child. Stamped onto the archetype's `Card` component.\n\t * Defaults to `[]`.\n\t */\n\tprovides?: readonly string[];\n\t/**\n\t * Optional widget-type interaction handlers — `onReceiveChild` /\n\t * `canAccept` / `applyMutation` / `revertMutation` (RFC-004 § Phase 1).\n\t * Handlers live on the widget binding so every instance of this\n\t * type shares them.\n\t */\n\tinteraction?: WidgetInteractionHandlers;\n}\n\n/**\n * Returns a paired widget + archetype for an iOS-style card. Register both\n * with `createLayoutEngine({ widgets: [card.widget], archetypes: [card.archetype] })`\n * (or via `engine.registerWidget` / `engine.registerArchetype`) and spawn with\n * `engine.spawn('your-card-type', { at, data })`.\n *\n * The produced widget is non-resizable (Selectable + Draggable only), wrapped\n * in `<CardFrame>`, and spawns with a `Card` component so `cardSystem` enforces\n * the preset size each tick.\n */\nexport function createCardWidget<T>(opts: CreateCardWidgetOptions<T>): {\n\twidget: DomWidget<T>;\n\tarchetype: Archetype;\n} {\n\tconst defaultSize = DEFAULT_CARD_PRESET_SIZES[opts.size];\n\tconst Render = opts.render;\n\n\tconst Component: React.ComponentType<DomWidgetProps> = ({ entityId }) => {\n\t\tconst data = useWidgetData<T>(entityId);\n\t\treturn (\n\t\t\t<CardFrame entityId={entityId}>\n\t\t\t\t<Render entityId={entityId} data={data} />\n\t\t\t</CardFrame>\n\t\t);\n\t};\n\n\tconst widget: DomWidget<T> = {\n\t\ttype: opts.type,\n\t\tschema: opts.schema,\n\t\tdefaultData: opts.defaultData,\n\t\tdefaultSize,\n\t\tcomponent: Component,\n\t\tinteraction: opts.interaction,\n\t};\n\n\tconst archetype: Archetype = {\n\t\tid: opts.type,\n\t\twidget: opts.type,\n\t\tcomponents: [\n\t\t\t[\n\t\t\t\tCard,\n\t\t\t\t{\n\t\t\t\t\tpreset: opts.size,\n\t\t\t\t\taccepts: opts.accepts ?? [],\n\t\t\t\t\tprovides: opts.provides ?? [],\n\t\t\t\t},\n\t\t\t],\n\t\t],\n\t\tinteractive: {\n\t\t\tselectable: true,\n\t\t\tdraggable: true,\n\t\t\tresizable: false,\n\t\t\t// Cards render their own chrome via CardFrame — opt out of the\n\t\t\t// engine-drawn selection/hover outline.\n\t\t\tselectionFrame: false,\n\t\t\t// Cards never snap themselves when dragged, but they ARE references\n\t\t\t// other widgets snap to. Asymmetric on purpose.\n\t\t\tsnapSource: false,\n\t\t\tsnapTarget: true,\n\t\t},\n\t\tdefaultSize,\n\t};\n\n\treturn { widget, archetype };\n}\n","import type { EntityId } from '@jamesyong42/reactive-ecs';\nimport type * as React from 'react';\nimport type { Archetype } from '../../ecs/archetype.js';\nimport type { CardPreset } from '../../ecs/components.js';\nimport { Card } from '../../ecs/components.js';\nimport type { WidgetInteractionHandlers } from '../../ecs/engine/widget-binding.js';\nimport { DEFAULT_CARD_PRESET_SIZES } from '../../ecs/resources.js';\nimport type { StandardSchemaV1 } from '../../ecs/schema.js';\nimport { useWidgetData } from '../../react/hooks/widget.js';\nimport type { R3FWidget, R3FWidgetProps } from '../../react/widgets/registry.js';\n\n/** Props passed to the user's geometry component. */\nexport interface GeometryCardRenderProps<T> {\n\tentityId: EntityId;\n\tdata: T;\n\t/** Widget width in world units. */\n\twidth: number;\n\t/** Widget height in world units. */\n\theight: number;\n}\n\n/** Options for `createGeometryCardWidget`. */\nexport interface CreateGeometryCardWidgetOptions<T> {\n\t/** Unique widget type id. Doubles as the archetype id. */\n\ttype: string;\n\t/** iOS card preset size. */\n\tsize: CardPreset;\n\t/** Standard Schema v1-compatible validator for the widget's data. */\n\t// biome-ignore lint/suspicious/noExplicitAny: schema Input is intentionally permissive\n\tschema: StandardSchemaV1<any, T>;\n\t/** Default data for new instances. */\n\tdefaultData: T;\n\t/**\n\t * If false, the widget skips the `Card` component entirely — no DOM\n\t * `<CardChrome>` (no rounded background, no drop shadow), no\n\t * lift-on-drag CSS transition, no compositor discard rect for\n\t * neighbours. The widget's 3D content floats over the canvas\n\t * background and just stacks on top of overlapping R3F content\n\t * during drag (via the compositor's renderOrder bump).\n\t *\n\t * Default true.\n\t */\n\twithCard?: boolean;\n\t/**\n\t * CSS background for the chrome's surface — only meaningful when\n\t * `withCard` is true. Stored on the `Card` component so the chrome\n\t * + any future tooling can read it. Defaults to the dark iOS card.\n\t */\n\tbackground?: string;\n\t/** The 3D content rendered in local space (origin at centre). */\n\tgeometry: React.ComponentType<GeometryCardRenderProps<T>>;\n\t/**\n\t * Drop-to-consume contract — what this card accepts as a parent\n\t * (RFC-004 § Phase 1). Only meaningful when `withCard` is true,\n\t * since non-card widgets don't participate in the consume mechanic.\n\t */\n\taccepts?: readonly string[];\n\t/**\n\t * Drop-to-consume contract — what this card provides as a child.\n\t * Only meaningful when `withCard` is true.\n\t */\n\tprovides?: readonly string[];\n\t/**\n\t * Optional widget-type interaction handlers. Only meaningful when\n\t * `withCard` is true; dispatch logic skips non-card widgets.\n\t */\n\tinteraction?: WidgetInteractionHandlers;\n}\n\n/**\n * Returns a paired R3F widget + archetype for a card-shaped 3D widget.\n * Behaves like {@link createCardWidget} — fixed preset size, non-resizable,\n * no engine-drawn selection frame, and lifts on drag (scale + z) — but\n * renders a three.js scene instead of DOM content.\n *\n * The card body and drop shadow are rendered as DOM `<CardChrome>`\n * beneath the WebGL canvas, not inside the FBO. The user's `geometry`\n * component renders ONLY the 3D content; chrome is provided by the\n * `Card` ECS component (the source of truth for all card-shaped\n * behavior — chrome, lift, drag-promote, compositor discard).\n *\n * Pass `withCard: false` to skip card behavior entirely (bare 3D\n * widget — no chrome, no lift, no discard).\n *\n * Lighting: this helper adds no lights. Declare your own in the `geometry`\n * component (typically a local `pointLight` scoped with `distance`).\n */\nexport function createGeometryCardWidget<T>(opts: CreateGeometryCardWidgetOptions<T>): {\n\twidget: R3FWidget<T>;\n\tarchetype: Archetype;\n} {\n\tconst defaultSize = DEFAULT_CARD_PRESET_SIZES[opts.size];\n\tconst Render = opts.geometry;\n\tconst withCard = opts.withCard ?? true;\n\n\tconst Component: React.ComponentType<R3FWidgetProps> = ({ entityId, width, height }) => {\n\t\tconst data = useWidgetData<T>(entityId);\n\t\t// Drag-lift (scale + z) is applied at the composition layer, not\n\t\t// inside this widget's FBO — keeps rounded corners from clipping\n\t\t// against the FBO rectangle when the lift expands the content.\n\t\treturn <Render entityId={entityId} data={data} width={width} height={height} />;\n\t};\n\n\tconst widget: R3FWidget<T> = {\n\t\ttype: opts.type,\n\t\tsurface: 'webgl',\n\t\tschema: opts.schema,\n\t\tdefaultData: opts.defaultData,\n\t\tdefaultSize,\n\t\tcomponent: Component,\n\t\tinteraction: opts.interaction,\n\t};\n\n\tconst archetype: Archetype = {\n\t\tid: opts.type,\n\t\twidget: opts.type,\n\t\tcomponents: withCard\n\t\t\t? [\n\t\t\t\t\t[\n\t\t\t\t\t\tCard,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpreset: opts.size,\n\t\t\t\t\t\t\tbackground: opts.background ?? '#1C1C1E',\n\t\t\t\t\t\t\taccepts: opts.accepts ?? [],\n\t\t\t\t\t\t\tprovides: opts.provides ?? [],\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t]\n\t\t\t: [],\n\t\tinteractive: {\n\t\t\tselectable: true,\n\t\t\tdraggable: true,\n\t\t\tresizable: false,\n\t\t\tselectionFrame: false,\n\t\t\t// Cards never snap themselves when dragged, but they ARE references\n\t\t\t// other widgets snap to. Asymmetric on purpose.\n\t\t\tsnapSource: false,\n\t\t\tsnapTarget: true,\n\t\t},\n\t\tdefaultSize,\n\t};\n\n\treturn { widget, archetype };\n}\n"],"mappings":"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"}