@descix/frqtl-node 0.6.0-p0.1 → 0.6.0-p0.2

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 (130) hide show
  1. package/CLAUDE.md +1 -1
  2. package/LICENSE.md +664 -0
  3. package/README.md +1 -1
  4. package/dist/dist-manifest.json +125 -125
  5. package/dist/fat/pkg-node/egpt_wasm.js +7 -7
  6. package/dist/fat/pkg-node/egpt_wasm_bg.wasm +0 -0
  7. package/dist/fat/pkg-node/package.json +1 -1
  8. package/dist/frqtl/compat/providers/wasm-engine.js +29 -31
  9. package/dist/frqtl/compat/providers/wasm-load-browser.js +2 -2
  10. package/dist/frqtl/compat/renderer/RenderFamily.js +1 -2
  11. package/dist/frqtl/compat/renderer/RenderMesh.js +2 -3
  12. package/dist/frqtl/compat/renderer/RenderShape.js +1 -1
  13. package/dist/frqtl/compat/renderer/captureStill-common.js +1 -2
  14. package/dist/frqtl/compat/renderer/display-slot.js +1 -1
  15. package/dist/frqtl/compat/renderer/providers/p5-provider.js +5 -5
  16. package/dist/frqtl/compat/renderer/providers/three-camera-contract.js +1 -1
  17. package/dist/frqtl/compat/renderer/providers/three-camera-geometry.js +4 -4
  18. package/dist/frqtl/compat/renderer/providers/three-provider.js +23 -27
  19. package/dist/frqtl/compat/renderer/renderCapabilities-common.js +2 -2
  20. package/dist/frqtl/compat/renderer/renderer-provider-contract.js +1 -1
  21. package/dist/frqtl/compat/vendor.js +2 -2
  22. package/dist/frqtl/objects/FrqtlApp.js +22 -24
  23. package/dist/frqtl/objects/ObjectFactory.js +1 -2
  24. package/dist/frqtl/objects/constants/WallBehaviors.js +5 -5
  25. package/dist/frqtl/objects/geometry/SlabFace.js +6 -6
  26. package/dist/frqtl/objects/instruments/capture-host.js +2 -2
  27. package/dist/frqtl/objects/instruments/capture.js +4 -5
  28. package/dist/frqtl/objects/instruments/hosted-eyes.js +3 -4
  29. package/dist/frqtl/objects/objects/DirectedTunnel.js +10 -11
  30. package/dist/frqtl/objects/objects/LightSource.js +22 -25
  31. package/dist/frqtl/objects/objects/QuantumEmitter.js +14 -14
  32. package/dist/frqtl/objects/objects/Tube.js +14 -14
  33. package/dist/frqtl/objects/objects/absorbRadiation.js +12 -13
  34. package/dist/frqtl/objects/objects/actionCompiler.js +52 -52
  35. package/dist/frqtl/objects/objects/controlAction.js +2 -2
  36. package/dist/frqtl/objects/objects/controlBind.js +2 -2
  37. package/dist/frqtl/objects/objects/directedRedirectProgram.js +3 -3
  38. package/dist/frqtl/objects/objects/emitterProgram.js +9 -9
  39. package/dist/frqtl/objects/objects/frqtl-control-slider.js +3 -3
  40. package/dist/frqtl/objects/objects/frqtl-control-sync.js +9 -9
  41. package/dist/frqtl/objects/objects/frqtl-control-widgets.js +2 -2
  42. package/dist/frqtl/objects/objects/frqtl-control-write-queue.js +2 -2
  43. package/dist/frqtl/objects/objects/makeControlsForObject.js +25 -29
  44. package/dist/frqtl/objects/objects/makeControlsForRenderSurface.js +2 -2
  45. package/dist/frqtl/objects/objects/slitLinerScatter.js +8 -10
  46. package/dist/frqtl/objects/objects/sustainedSource.js +15 -16
  47. package/dist/frqtl/objects/objects/tagger.js +2 -2
  48. package/dist/frqtl/objects/schema/engine-scopes.js +11 -12
  49. package/dist/frqtl/objects/schema/index.js +6 -6
  50. package/dist/frqtl/objects/schema/scopes.js +10 -10
  51. package/dist/frqtl/objects/setup/_collisionMatrixLanes.js +1 -1
  52. package/dist/frqtl/objects/setup/setupBlackbodySubstrate.js +1 -1
  53. package/dist/frqtl/objects/setup/setupCollisionMatrix.js +3 -3
  54. package/dist/frqtl/objects/setup/setupConeEmitter3D.js +7 -8
  55. package/dist/frqtl/objects/setup/setupDoubleSlit.js +20 -21
  56. package/dist/frqtl/objects/setup/setupFxSmoke.js +1 -1
  57. package/dist/frqtl/objects/setup/setupLightSourceLab.js +23 -26
  58. package/dist/frqtl/objects/setup/setupSphereEmitter3D.js +39 -40
  59. package/dist/frqtl/objects/setup/setupTunnelLab.js +17 -19
  60. package/dist/frqtl/objects/setup/setupTunnelPointExit.js +1 -1
  61. package/dist/frqtl/objects/setup/setupWaveInterference.js +4 -5
  62. package/dist/frqtl/objects/v1-replacements.js +0 -1
  63. package/dist/frqtl/parts/CameraControls.js +5 -5
  64. package/dist/frqtl/parts/CameraPath.js +1 -1
  65. package/dist/frqtl/parts/CollisionActions.js +2 -3
  66. package/dist/frqtl/parts/CollisionTypes.js +1 -2
  67. package/dist/frqtl/parts/DetectorWall.js +10 -10
  68. package/dist/frqtl/parts/FrqtlControlsPanel.js +11 -11
  69. package/dist/frqtl/parts/FrqtlVision.js +1 -1
  70. package/dist/frqtl/parts/GraphingDetectorWall.js +3 -4
  71. package/dist/frqtl/parts/LargeObject.js +7 -8
  72. package/dist/frqtl/parts/LightColor.js +2 -2
  73. package/dist/frqtl/parts/LiveChart.js +1 -1
  74. package/dist/frqtl/parts/LogicGate.js +4 -7
  75. package/dist/frqtl/parts/OvenBox.js +1 -2
  76. package/dist/frqtl/parts/PointSource.js +10 -11
  77. package/dist/frqtl/parts/SlitLightSource.js +6 -6
  78. package/dist/frqtl/parts/SlitScreen.js +14 -14
  79. package/dist/frqtl/parts/SphereEmitter.js +24 -24
  80. package/dist/frqtl/parts/Tunnel.js +17 -17
  81. package/dist/frqtl/parts/Wall.js +17 -17
  82. package/dist/frqtl/scenes/dse-one-emitter.js +1 -1
  83. package/dist/frqtl/scenes/dse-one-slit.js +2 -2
  84. package/dist/frqtl/scenes/dse-photoelectric.js +3 -3
  85. package/dist/frqtl/scenes/dse-tunnel-rebuild.js +5 -6
  86. package/dist/frqtl/scenes/dse-two-emitters.js +1 -1
  87. package/dist/frqtl/scenes/dse-two-slits.js +2 -2
  88. package/dist/frqtl/scenes/laser-buildup.js +1 -1
  89. package/dist/frqtl/scenes/mirror-3d.js +4 -4
  90. package/dist/frqtl/scenes/mirror-route.js +9 -9
  91. package/dist/frqtl/scenes/mirror.js +1 -1
  92. package/dist/frqtl/scenes/self-interference.js +1 -1
  93. package/dist/frqtl/scenes/smoking-gun.js +1 -1
  94. package/dist/frqtl/scenes/sun.js +2 -2
  95. package/dist/shim/bundle/frqnb.js +3 -3
  96. package/dist/shim/bundle/index.js +1 -1
  97. package/dist/shim/bundle/manifest.js +2 -2
  98. package/dist/shim/bundle/zip.js +1 -1
  99. package/dist/shim/controls/index.js +14 -14
  100. package/dist/shim/controls/registry.js +3 -3
  101. package/dist/shim/engine/artifact-shell.js +1 -2
  102. package/dist/shim/engine/router.js +15 -17
  103. package/dist/shim/expr/ast-schema.js +5 -5
  104. package/dist/shim/field-descriptor/index.js +7 -8
  105. package/dist/shim/frame-data/index.js +3 -3
  106. package/dist/shim/index.js +4 -4
  107. package/dist/shim/notebook/canvas-guard.js +1 -1
  108. package/dist/shim/notebook/catalog.js +2 -2
  109. package/dist/shim/notebook/format.js +26 -26
  110. package/dist/shim/notebook/kernel.js +3 -4
  111. package/dist/shim/notebook/knob.js +0 -1
  112. package/dist/shim/notebook/module-resolver.js +6 -6
  113. package/dist/shim/notebook/produced-bindings.js +1 -1
  114. package/dist/shim/notebook/setup-builder.js +9 -12
  115. package/dist/shim/notebook/vendor-importmap.js +1 -1
  116. package/dist/shim/notebook/view-builder.js +1 -1
  117. package/dist/shim/notebook/view-ctx.js +1 -1
  118. package/dist/shim/notebook/warmup.js +2 -2
  119. package/dist/shim/page-params/index.js +8 -9
  120. package/dist/shim/registry/copy-gate.js +1 -1
  121. package/dist/shim/registry/exhibits.js +4 -4
  122. package/dist/shim/registry/experiments.js +3 -3
  123. package/dist/shim/registry/walkthrough.js +21 -24
  124. package/dist/shim/render/render-stages.js +2 -2
  125. package/dist/shim/render/sun-look.js +2 -2
  126. package/dist/shim/rpc/index.js +2 -2
  127. package/dist/shim/runtime/index.js +12 -12
  128. package/dist/shim/storage/modules.js +8 -8
  129. package/llms.txt +2 -2
  130. package/package.json +4 -3
@@ -2,8 +2,8 @@
2
2
 
3
3
  /**
4
4
  * setupSphereEmitter3D — a spherical "sun" emitter: uniform-DIRECTION emission
5
- * via ball-rejected integer velocity sampling (CEO-ratified model, 2026-07-17,
6
- * corrected same day: speed is ALWAYS 1px/tick (bench M1) — (vx,vy,vz) is
5
+ * via ball-rejected integer velocity sampling (the model: speed is
6
+ * ALWAYS 1px/tick (bench M1) — (vx,vy,vz) is
7
7
  * DIRECTION ONLY, never a speed knob; only the ratio vx:vy:vz matters,
8
8
  * (3,4,0)≡(6,8,0)). Models on `setupConeEmitter3D.js` (same live-knob,
9
9
  * host-tick-fn, thin-sugar pattern).
@@ -71,7 +71,7 @@
71
71
  * enough that a SINGLE BURST (before engine-tick temporal averaging kicks
72
72
  * in) doesn't itself read lumpy: a static (no-tick) per-burst octant CV is
73
73
  * ~0.16 at R=9, ~0.09 at R=20, ~0.07 at R=24-25, flattening to ~0.05-0.06 by
74
- * R=30-40 (CEO-directed re-check, 2026-07-18, host-RNG measurement) — R=24
74
+ * R=30-40 (host-RNG measurement) — R=24
75
75
  * is the new DEFAULT, comfortably past the R=20 knee with headroom below the
76
76
  * R=40 slider ceiling (so the R=9-ish "lumpy" end of the range stays
77
77
  * explorable too).
@@ -90,8 +90,8 @@
90
90
  * ball's 0.082 at R=20,N=4000) because it drops the coarse near-origin
91
91
  * lattice points; optional refinement, not the default.
92
92
  * @param {'spherical'|'hemisphere'|'laser'|'drum'|'particle-walk'} [options.preset='spherical'] - Sets the
93
- * per-axis velocity RANGES the sampler draws from — the unification the CEO
94
- * asked for: sun/laser/drum are the SAME sampler with different ranges.
93
+ * per-axis velocity RANGES the sampler draws from — the unification:
94
+ * sun/laser/drum are the SAME sampler with different ranges.
95
95
  * 'spherical' (DEFAULT, the sun): vx,vy,vz each in [-R,R] -> full ball ->
96
96
  * uniform spherical direction distribution.
97
97
  * 'hemisphere' (FORWARD 180° emission — the directed sun): the SAME ball-
@@ -99,7 +99,7 @@
99
99
  * vy,vz in [-R,R]. Conditioning a uniform ball on vx>=0 leaves a uniform
100
100
  * HALF-ball, whose direction marginal is EXACTLY the restriction of
101
101
  * 'spherical''s to the forward hemisphere: same physics, pointed one way
102
- * (theorist advisory 2026-07-28, measured over 2x10^6 MC samples). BALL
102
+ * (measured over 2x10^6 MC samples, 2026-07-28). BALL
103
103
  * REJECTION IS RETAINED and that is load-bearing — a raw box draw
104
104
  * (vx in [0,R], vy in [-R,R], no magnitude clip) measures 1.83:1
105
105
  * anisotropy with 1.45x peaks at +/-45deg, which is exactly the diagonal
@@ -130,7 +130,7 @@
130
130
  * component (this is the historical concentric-ring-emitter-vs-cone
131
131
  * construction's "collimated cylinder" case generalized: here the
132
132
  * DISK is of DIRECTIONS at the source, not ring positions).
133
- * 'particle-walk' (CEO Phase 1 iteration, 2026-07-18, two rounds — a
133
+ * 'particle-walk' (a
134
134
  * FAITHFUL reproduction, not just the primitive, GROUND-TRUTHED against
135
135
  * the actual `setupParticleWalk.js`/`setupParticleWalk3D.js` source):
136
136
  * vx PINNED to `[R,R]` (deterministic +X drift, ALWAYS the forward
@@ -162,7 +162,7 @@
162
162
  * `control.setAxisRange('vx', lo, hi)` etc. for custom directional shapes.
163
163
  * @param {{x:number,y:number,z:number}} [options.emissionBox] - OPT-IN per-axis
164
164
  * emission-position box (extends the scalar `emissionBoxSide` cube into an
165
- * independent size per axis — CEO Phase 1 iteration). Omitted (default) ->
165
+ * independent size per axis). Omitted (default) ->
166
166
  * `emissionBox` is DERIVED from `emissionBoxSide` + the current preset
167
167
  * (uniform cube for spherical/laser/drum — BYTE-IDENTICAL to every
168
168
  * pre-existing caller; the flat line shape above for 'particle-walk',
@@ -243,7 +243,7 @@
243
243
  * SOURCE POSITION in ABSOLUTE canvas px — WHERE this emitter seeds its leaves
244
244
  * (the center `cx0/cy0/cz0` that BOTH the volume box AND the surface ring
245
245
  * launch are measured relative to). Wins over `options.offset` when both are
246
- * present. z (3rd element) defaults to 0. Pure sugar (Bite 3, 2026-07-20): it
246
+ * present. z (3rd element) defaults to 0. Pure sugar: it
247
247
  * ONLY moves the `makeLeafFrame` seed pixel — the velocity-aligned ring launch
248
248
  * (`start = center + innerR×unit(v)`) stays relative to THIS center; zero
249
249
  * engine, no golden moves (SU1). Needed for TWO-SOURCE interference (two
@@ -299,8 +299,7 @@
299
299
  * fewer axis; `is2D` simply narrows `activeAxes` at init and drops vz
300
300
  * from the sampler.
301
301
  *
302
- * MEASURED engine-realized finding (canonical-bench S4/S5,
303
- * `docs/internal/physics-lab/canonical-bench/bench.cjs`, pkg-node WASM, R=20 N=2000 T=30
302
+ * MEASURED engine-realized finding (canonical-bench S4/S5, pkg-node WASM, R=20 N=2000 T=30
304
303
  * seed=42, bit-reproducible across runs): angular uniformity (equal-solid-
305
304
  * angle octant CV + cos(polar) marginal-flatness CV) is NOT distorted toward
306
305
  * axes or diagonals by the ±1px/tick per-axis speed cap — S4 measures
@@ -330,10 +329,10 @@
330
329
  * is a property of the ALREADY-GOLDENED move-gate rule, not new sugar logic —
331
330
  * composing it here (dial mass via the `wavelength` arg, read the resulting
332
331
  * oscillation) is exactly the r0/r1 "unique rational wavelength, unchanged
333
- * speed" demo the intuition guide (`docs/internal/physics-lab/intuition/README.md`) names.
332
+ * speed" demo the intuition guide names.
334
333
  *
335
334
  * Sustained emission is a HOST TICK-FN pushed to
336
- * `universe.experimentTickFunctions` (architect guardrail: no new engine
335
+ * `universe.experimentTickFunctions` (guardrail: no new engine
337
336
  * hook, no native emit-spec). Fast-path regime: no
338
337
  * `withInterQuantumCollisions`, no `brownianMotion`, no top-down frame-gen
339
338
  * auto-spawn ladder. No sink — leaves drift forever (M5) until they exit
@@ -376,9 +375,9 @@ import { FrqtlWorldInit } from './_worldInit.js';
376
375
  * Three names for three layers of one quantity — author knob, universe field,
377
376
  * emergent wavelength — so a reader who sees only one of them can find the others.
378
377
  * Confirmed by measurement at both sweep points: fWL 64 -> 256, fWL 32 -> 128
379
- * (docs/internal/physics-lab/intuition/starter.jsonl, r3-radius-stall-shells).
378
+ * (the intuition record r3-radius-stall-shells).
380
379
  *
381
- * ── `stepping` (ws-walk-unification Bite 1) — a WORLD field, PASSED THROUGH ──
380
+ * ── `stepping` — a WORLD field, PASSED THROUGH ───────────────────────────────
382
381
  * The wave-walk STEPPING SAMPLER ('fixed' | 'average') is a per-universe init
383
382
  * option, reinit-class exactly like `is2D`/`fundamentalDimension`, so it belongs
384
383
  * to the world step rather than to the part. This factory NEITHER validates NOR
@@ -554,7 +553,7 @@ import { FrqtlWorldInit } from './_worldInit.js';
554
553
  : (declaresDimension ? 0 : _worldFundamentalDimension(universe));
555
554
 
556
555
  // `leafDimension` = the dimension THIS emitter births its leaves at (per-emitter
557
- // — the CEO's corrected 2026-07-19 model: dimension is an ADDABLE scale layer, and
556
+ // — the corrected model: dimension is an ADDABLE scale layer, and
558
557
  // an emitter creates leaves AT a chosen dimension via makeLeafFrame's explicit
559
558
  // `level` + `addDimension` (the SAME pattern scenes/blackbody.js uses: init at a base
560
559
  // fundamental, then addDimension for the higher scale layer). Default =
@@ -593,7 +592,7 @@ import { FrqtlWorldInit } from './_worldInit.js';
593
592
  universe.addDimension(leafDimension);
594
593
  }
595
594
 
596
- // ── Emission SOURCE POSITION (per-emitter — Bite 3, 2026-07-20) ──────────
595
+ // ── Emission SOURCE POSITION (per-emitter) ───────────────────────────────
597
596
  // cx0/cy0/cz0 = the center this emitter seeds its leaves around (BOTH the
598
597
  // volume box AND the surface ring launch are relative to it). Resolved from
599
598
  // options.center (ABSOLUTE canvas px, wins) / options.offset (RELATIVE to
@@ -642,7 +641,7 @@ import { FrqtlWorldInit } from './_worldInit.js';
642
641
  // = per-leaf ±, exactly reproducing PointSource/emitterProgram.js's
643
642
  // `chargeInt = universe.random() < 0.5 ? 0 : 1` (the ONE opt-in extra
644
643
  // draw). Required to reproduce the Wave-Interference look from a single
645
- // omni source (CEO 2026-07-18).
644
+ // omni source.
646
645
  chargeMode: (options.chargeMode === 'random' || options.chargeMode === 'negative'
647
646
  || options.chargeMode === 'positive') ? options.chargeMode : 'positive',
648
647
  // Emission START-POSITION topology (WHERE a leaf is seeded, independent
@@ -652,14 +651,14 @@ import { FrqtlWorldInit } from './_worldInit.js';
652
651
  // CIRCLE in 2D / a SPHERE SHELL in 3D). Surface mode reproduces the old
653
652
  // PointSource "ring launch": single-occupancy forbids many quanta from
654
653
  // starting on the EXACT same pixel, so PointSource seeds them around a
655
- // ring — the correct single-source start topology (CEO 2026-07-18).
654
+ // ring — the correct single-source start topology.
656
655
  emissionShell: (options.emissionShell === 'surface') ? 'surface' : 'volume',
657
656
  // Shell radius (px) for emissionShell:'surface'. Non-negative integer;
658
657
  // 0 collapses the shell back to the center point (so 'surface' with
659
658
  // innerR 0 == 'volume' with box 0 — a single pixel). Ignored entirely
660
659
  // in 'volume' mode (no draw).
661
660
  innerR: (options.innerR !== undefined) ? Math.max(0, Math.round(options.innerR)) : 0,
662
- // Per-leaf RENDER COLOR OVERRIDE (render-intent DATA, NOT physics — CEO 2026-07-19).
661
+ // Per-leaf RENDER COLOR OVERRIDE (render-intent DATA, NOT physics).
663
662
  // null (DEFAULT) → leaves are emitted COLORLESS (byte-identical to every pre-existing
664
663
  // caller) so the renderer's colorScheme derives color from fullness (LightColor). An
665
664
  // [r,g,b] / [r,g,b,a] array → FORCES that color: it is passed to makeLeafFrame's `color`
@@ -670,7 +669,7 @@ import { FrqtlWorldInit } from './_worldInit.js';
670
669
  // wavelength→LightColor mapping with ZERO engine field touched. LIVE via
671
670
  // control.setRenderColor (affects the NEXT emitted leaf, M5).
672
671
  renderColor: Array.isArray(options.renderColor) ? options.renderColor.slice() : null,
673
- // Per-leaf RENDER SHAPE OVERRIDE (render-intent DATA, NOT physics — Bite 5b A3).
672
+ // Per-leaf RENDER SHAPE OVERRIDE (render-intent DATA, NOT physics).
674
673
  // null (DEFAULT) → leaves emit with NO render.shape key (byte-identical to every
675
674
  // pre-existing caller); the renderer falls back to the render-level "Default Shape"
676
675
  // (setRenderOption) then 'ball'. A ball|box|circle|cube|sphere string is stamped as
@@ -693,7 +692,7 @@ import { FrqtlWorldInit } from './_worldInit.js';
693
692
  active: true
694
693
  };
695
694
  // GROUND-TRUTHED against setupParticleWalk.js / setupParticleWalk3D.js
696
- // (CEO fullness-tuning pass, 2026-07-18 — read the actual source, not a
695
+ // (read the actual source, not a
697
696
  // paraphrase): both historical experiments use IDENTICAL construction —
698
697
  // `sourceRect=[cx,cy,1,10]` (a height-10 vertical LINE, x-width=1, in
699
698
  // BOTH 2D and 3D — there is no disk anywhere in the historical code;
@@ -705,7 +704,7 @@ import { FrqtlWorldInit } from './_worldInit.js';
705
704
  // canvas, wrap=false so quanta die at the far wall): alive count
706
705
  // climbs 1000/2000/4000 at ticks 50/100/200 then PLATEAUS at exactly
707
706
  // 5960 by tick~300 (little's-law steady state: 20/tick x ~298-tick
708
- // transit time from x~302 to the x=599 wall) — this IS the CEO's
707
+ // transit time from x~302 to the x=599 wall) — this IS the
709
708
  // "~5960 alive, the fuller sheet/beam" density target, reproduced
710
709
  // here by matching the SAME three numbers, not by tuning against the
711
710
  // number directly.
@@ -719,7 +718,7 @@ import { FrqtlWorldInit } from './_worldInit.js';
719
718
  state.burstSize = options.burstSize !== undefined ? options.burstSize
720
719
  : (state.preset === 'particle-walk' ? PARTICLE_WALK_DEFAULT_BURST_SIZE : 40);
721
720
 
722
- // ── Per-axis emission SOURCE SHAPE (CEO Phase 1 iteration, 2026-07-18
721
+ // ── Per-axis emission SOURCE SHAPE
723
722
  // — the "drum emitter" shape: a flat line source, extending the
724
723
  // scalar emissionBoxSide cube into an opt-in per-axis box).
725
724
  // `explicitEmissionBox`/`explicitSourceShape` (options, FROZEN at
@@ -788,7 +787,7 @@ import { FrqtlWorldInit } from './_worldInit.js';
788
787
  ranges.vz = fwd;
789
788
  }
790
789
  } else if (name === 'hemisphere') {
791
- // FORWARD 180° emission (D1, CEO 2026-07-28) — the ONE line that
790
+ // FORWARD 180° emission (D1) — the ONE line that
792
791
  // differs from 'spherical': the forward axis' range is HALVED to
793
792
  // [0,R]. Everything else (the ball rejection below, the isotropy
794
793
  // correction) is shared, which is the whole point: a uniform ball
@@ -805,7 +804,7 @@ import { FrqtlWorldInit } from './_worldInit.js';
805
804
  ranges.vy = [-R, R];
806
805
  ranges.vz = [0, 0];
807
806
  } else if (name === 'particle-walk') {
808
- // Faithful reproduction (CEO Phase 1 iteration): PURE-FORWARD
807
+ // Faithful reproduction: PURE-FORWARD
809
808
  // +X momentum, ALWAYS (not is2D-branched like 'laser' — both
810
809
  // historical experiments, 2D and 3D, used vx=1,vy=0 literally).
811
810
  // vy=vz PINNED to 0 — the waviness comes entirely from the
@@ -829,7 +828,7 @@ import { FrqtlWorldInit } from './_worldInit.js';
829
828
  // Mulberry32 stream (G-EMIT primitive) — same stream physics draws from, so a
830
829
  // fixed seed is fully reproducible.
831
830
  //
832
- // REJECTION IS PRESET-AWARE (CEO fix, 2026-07-18) — the rejection criterion
831
+ // REJECTION IS PRESET-AWARE — the rejection criterion
833
832
  // must match each preset's INTENDED SHAPE, not a single one-size ball:
834
833
  // 'spherical': reject to the BALL |v|<=R (rounds the sampled cube into a
835
834
  // sphere of directions — the mandatory isotropy correction, S4/S5).
@@ -916,8 +915,8 @@ import { FrqtlWorldInit } from './_worldInit.js';
916
915
  }
917
916
 
918
917
  // Circular rejection in the Y-Z plane (the transverse cross-section
919
- // perpendicular to 'particle-walk''s +X forward axis — the CEO's
920
- // "circular disk source (3D)"). Mirrors sampleVelocity's own
918
+ // perpendicular to 'particle-walk''s +X forward axis — the
919
+ // circular disk source (3D)). Mirrors sampleVelocity's own
921
920
  // ball-rejection idiom, applied to POSITION instead of direction.
922
921
  // Only ever called when state.sourceShape==='disk' (opt-in — never
923
922
  // the default path for spherical/laser/drum).
@@ -933,11 +932,11 @@ import { FrqtlWorldInit } from './_worldInit.js';
933
932
  return [0, 0]; // safety net (misconfigured box)
934
933
  }
935
934
 
936
- // Emission SHELL SURFACE start-position — VELOCITY-ALIGNED (CEO 2026-07-18).
935
+ // Emission SHELL SURFACE start-position — VELOCITY-ALIGNED.
937
936
  // The old-PointSource "ring launch" seeds each particle ON the ring AT THE
938
937
  // ANGLE OF ITS OWN VELOCITY, so its start pixel is COLLINEAR with its outward
939
- // trajectory (the CEO's "pixel position is the integer-scaled momentum
940
- // vector"). This is what gives a single source an EMPTY CENTER and razor-
938
+ // trajectory (the pixel position is the integer-scaled momentum
939
+ // vector). This is what gives a single source an EMPTY CENTER and razor-
941
940
  // sharp bands: every particle projects radially outward and NONE cuts across
942
941
  // the inner disk. Draws NOTHING itself — it is a deterministic function of
943
942
  // the ALREADY-SAMPLED velocity `v` (which is why emitOneLeaf samples velocity
@@ -999,7 +998,7 @@ import { FrqtlWorldInit } from './_worldInit.js';
999
998
  // wavelength=state.wavelength -- null by default (mass=capacity, byte-identical);
1000
999
  // a number sets mass=max(1,capacity/wavelength) for the NEXT emitted leaf (M5:
1001
1000
  // already-emitted leaves keep whatever mass they were stamped with).
1002
- // 10th arg (Bite 5b A3) = per-leaf render.shape override (null default → no key →
1001
+ // 10th arg = per-leaf render.shape override (null default → no key →
1003
1002
  // byte-identical). Rides the SAME provider render-intent MERGE seam as color.
1004
1003
  var h = universe.makeLeafFrame(lx, ly, leafDimension, state.wavelength, v[0], v[1], false, chg, state.renderColor, state.renderShape);
1005
1004
  if (h === null) { return; } // liveQuantaCap refused the add: no leaf, nothing to stamp
@@ -1031,7 +1030,7 @@ import { FrqtlWorldInit } from './_worldInit.js';
1031
1030
  marker.setRect([cx0 - D / 2, cy0 - D / 2, cz0 - D / 2, D, D, D]);
1032
1031
  }
1033
1032
  var control = {
1034
- // INVARIANT (CEO fix, 2026-07-18 — "the clamp bug"): emissionBoxSide is
1033
+ // INVARIANT ("the clamp bug"): emissionBoxSide is
1035
1034
  // NEVER larger than the CURRENT R. Construction clamps it once; setR()
1036
1035
  // is the ONLY runtime path that can widen the gap (R shrinking below an
1037
1036
  // already-set box), so it MUST re-clamp every time — this is the single
@@ -1067,7 +1066,7 @@ import { FrqtlWorldInit } from './_worldInit.js';
1067
1066
  getEmitEveryTicks: function () { return emitEveryTicks; },
1068
1067
  setActive: function (v) { state.active = !!v; },
1069
1068
  getIs2D: function () { return is2D; },
1070
- // Emission SOURCE POSITION (Bite 3, 2026-07-20) — reposition this emitter's
1069
+ // Emission SOURCE POSITION — reposition this emitter's
1071
1070
  // center LIVE (affects the NEXT emitted leaf, M5). Absolute canvas px. z
1072
1071
  // optional (retains the current z when omitted). Pure sugar — only the
1073
1072
  // makeLeafFrame seed pixel moves; the ring launch stays relative to it.
@@ -1113,11 +1112,11 @@ import { FrqtlWorldInit } from './_worldInit.js';
1113
1112
  getWavelength: function () { return state.wavelength !== null ? state.wavelength : 1; },
1114
1113
  getMaxWavelength: function () { return maxWavelength; },
1115
1114
  getFundamentalDimension: function () { return fundamentalDimension; },
1116
- // The dimension THIS emitter births leaves at (per-emitter — CEO 2026-07-19).
1115
+ // The dimension THIS emitter births leaves at (per-emitter).
1117
1116
  getLeafDimension: function () { return leafDimension; },
1118
- // LIVE "Emit Dimension" (Bite 5b A2). Host-side addDimension (idempotent) +
1117
+ // LIVE "Emit Dimension". Host-side addDimension (idempotent) +
1119
1118
  // closure-var flip: the NEXT emitted leaf is born at the new dimension (M5, exactly
1120
- // like wavelength/charge). Theorist CLEARED mid-run addDimension as SAFE (2026-07-22):
1119
+ // like wavelength/charge). Mid-run addDimension is SAFE (cleared 2026-07-22):
1121
1120
  // do_tick snapshots the dim key set fresh each tick, so a between-ticks add is atomic;
1122
1121
  // promotion routes live. SIDE EFFECT (S1): a value BELOW the current fundamental
1123
1122
  // self-lowers the floor UNIVERSE-GLOBALLY and is a ONE-WAY RATCHET (no removeDimension)
@@ -1164,7 +1163,7 @@ import { FrqtlWorldInit } from './_worldInit.js';
1164
1163
 
1165
1164
  // Standardized live knobs (runner.experimentControls-compatible — the SAME
1166
1165
  // shape coneEmitterControl.controls uses). Every
1167
- // descriptor carries a `get()` accessor (CEO fix, 2026-07-18) so a page can
1166
+ // descriptor carries a `get()` accessor so a page can
1168
1167
  // generically RE-SYNC every slider's displayed value/label from authoritative
1169
1168
  // state after ANY control fires — not just the one the user dragged. This is
1170
1169
  // what makes the emissionBoxSide<=R clamp VISIBLE live: `emissionBoxSide`
@@ -1225,7 +1224,7 @@ import { FrqtlWorldInit } from './_worldInit.js';
1225
1224
  return {
1226
1225
  sphereEmitterControl: control,
1227
1226
  largeObjects: [],
1228
- // TOP-LEVEL dispose (STACKING-BUG FIX, CEO 2026-07-19): FrqtlApp.setup()
1227
+ // TOP-LEVEL dispose (STACKING-BUG FIX): FrqtlApp.setup()
1229
1228
  // tears down the PREVIOUS setupResult by calling `setupResult.dispose()` IF it
1230
1229
  // exists (canonical teardown, FrqtlApp.js) — but this factory previously
1231
1230
  // exposed dispose ONLY on `sphereEmitterControl`, so the runner's teardown check
@@ -3,8 +3,8 @@
3
3
  /**
4
4
  * setupTunnelLab — DirectedTunnel ISOLATION (I1, the directed-tunnel composition model
5
5
  * §3): ONE `DirectedTunnel`, gun-chamber mechanics (fill / escape / dispersion) at a
6
- * live-tunable scale — the visual half of the scale-sweep measurement
7
- * (`docs/internal/physics-lab/directed-tunnel-scale-sweep/`), same methodology, same source shape.
6
+ * live-tunable scale — the visual half of the scale-sweep measurement, same methodology,
7
+ * same source shape.
8
8
  *
9
9
  * ── Layer 1: API contract ────────────────────────────────────────────────────
10
10
  *
@@ -22,7 +22,7 @@
22
22
  * `QuantumEmitter` has no wavelength field, which is exactly why this factory hand-
23
23
  * places quanta via a local host tick-fn instead of `DirectedTunnel`'s `options.emitter`
24
24
  * — see the Layer 2 note below). LIVE (`setupResult.sourceState.wavelength`).
25
- * **CEILING (CEO drive #2, 2026-07-14 — "the wavelength slider has no effect"
25
+ * **CEILING ("the wavelength slider has no effect"
26
26
  * root cause):** Engine Invariant #6 is `mass = max(1, capacity/wavelength)` —
27
27
  * at this factory's `FUNDAMENTAL_DIMENSION=2`, `capacity = (2^2)^2 = 16`
28
28
  * (`setupTunnelLab.CAPACITY`, exported below), so ANY `wavelength >= capacity`
@@ -43,7 +43,7 @@
43
43
  * @param {number} [opts.sourceDensity=5] - Quanta hand-placed per burst. LIVE
44
44
  * (`setupResult.sourceState.density`). NOTE: this is the FACTORY's own
45
45
  * omitted-opt default (unchanged, for any headless caller) — `tunnel-lab
46
- * /index.html`'s own UI default is 10 (CEO drive #2, 2026-07-14
46
+ * /index.html`'s own UI default is 10 (the
47
47
  * population-density fix: the page ALWAYS passes an explicit value read
48
48
  * from its own `<input>` default, so this factory default is never
49
49
  * actually reached by the page — see that file's own docstring for the
@@ -56,15 +56,14 @@
56
56
  * for the same reason.
57
57
  * @param {boolean} [opts.sourceActive=true] - Master on/off for the burst source. LIVE
58
58
  * (`setupResult.sourceState.active`).
59
- * @param {number} [opts.depth] - CEO drive #2 (2026-07-14) 3D toggle. OMITTED
59
+ * @param {number} [opts.depth] - 3D toggle. OMITTED
60
60
  * (default) -> 2D (byte-identical to every pre-existing caller). A positive
61
61
  * value -> real z-containment (`activeAxes:{x,y,z}` on `universe.init()`,
62
62
  * `DirectedTunnel`'s own `depth`/`z=-depth/2`, hand-placed quanta z-centred)
63
63
  * — the standard `options.depth` recipe. REINIT-CLASS
64
64
  * (only meaningful at construction, like bore/length).
65
- * @param {'spray'|'beam'} [opts.velocityProfile='spray'] - ws-dse-3d AC3 (CEO
66
- * drive #2 round-2 ruling, "tunnel-lab gains the source-profile selection off
67
- * the shared surface"): the SAME `SustainedSource.SOURCE_SPEC_FIELDS.
65
+ * @param {'spray'|'beam'} [opts.velocityProfile='spray'] - tunnel-lab has the
66
+ * source-profile selection off the shared surface: the SAME `SustainedSource.SOURCE_SPEC_FIELDS.
68
67
  * velocityProfile` axis `LightSource`'s own `particleWalk` burst always uses
69
68
  * (`'beam'`, hardcoded there) — exposed here so tunnel-lab can be set to
70
69
  * `'beam'` and produce a directly comparable collimated source to
@@ -98,12 +97,11 @@
98
97
  *
99
98
  * **Gun-chamber convention**: `capNegX:true, capPosX:false` — a CLOSED breech (source
100
99
  * fires INTO the bore, quanta bounce/fill) and an OPEN muzzle (quanta escape, then
101
- * disperse freely with no walls) — the CEO's own Gun-Chamber model ("particles ping-pong
102
- * in a tube, escape the open end, spread comes from dispersion AFTER escape").
100
+ * disperse freely with no walls) — the Gun-Chamber model (particles ping-pong
101
+ * in a tube, escape the open end, spread comes from dispersion AFTER escape).
103
102
  *
104
103
  * **Fundamental dimension = 2** (matches `setupDoubleSlit.js`'s default AND the scale-
105
- * sweep's own convention — see `docs/internal/physics-lab/directed-tunnel-scale-sweep/README.md`'s
106
- * "level 0 pins wavelength to a no-op" note): a level-0 leaf has `capacity=1`, so
104
+ * sweep's own convention — level 0 pins wavelength to a no-op): a level-0 leaf has `capacity=1`, so
107
105
  * `mass=max(1,capacity/wavelength)` is PINNED at 1 for any `wavelength>=2` — the
108
106
  * wavelength slider would be a silent no-op at level 0.
109
107
  *
@@ -126,14 +124,14 @@ import * as SustainedSource from '../objects/sustainedSource.js';
126
124
 
127
125
  var FUNDAMENTAL_DIMENSION = 2; // matches setupDoubleSlit.js + the scale-sweep script
128
126
 
129
- // CEO drive #2 (2026-07-14) — the ONE authority for "what's the largest
127
+ // The ONE authority for "what's the largest
130
128
  // wavelength value that still produces a DISTINCT mass from any larger one"
131
129
  // at this factory's FUNDAMENTAL_DIMENSION. Engine Invariant #6:
132
130
  // `mass = max(1, capacity/wavelength)` — the floor (mass=1) is reached
133
131
  // exactly at `wavelength === capacity`; every wavelength beyond that is
134
132
  // indistinguishable. `tunnel-lab/index.html` reads this (never a hand-typed
135
133
  // "16" literal) to clamp its wavelength slider's max to the achievable range.
136
- // ws-dse-3d: derived from `SustainedSource.capacityAtDimension` — the SAME
134
+ // Derived from `SustainedSource.capacityAtDimension` — the SAME
137
135
  // authority `setupLightSourceLab.js` now also derives its own
138
136
  // MAX_USEFUL_WAVELENGTH from (AC4: "same MAX_USEFUL_WAVELENGTH clamp
139
137
  // authority" for both labs).
@@ -164,7 +162,7 @@ import * as SustainedSource from '../objects/sustainedSource.js';
164
162
  var sourceDensity = opts.sourceDensity !== undefined ? opts.sourceDensity : 5;
165
163
  var sourceRate = opts.sourceRate !== undefined ? opts.sourceRate : 10;
166
164
  var sourceActive = opts.sourceActive !== undefined ? !!opts.sourceActive : true;
167
- // CEO drive #2 item 1 (2026-07-14) — OPT-IN 3D, OMISSION-preserves-2D
165
+ // OPT-IN 3D, OMISSION-preserves-2D
168
166
  // (the "before adding a creation-method parameter" discipline): mirrors
169
167
  // the standard `options.depth` recipe — omitted/null ->
170
168
  // 2D (zContain:false, byte-identical to every existing caller); a
@@ -172,7 +170,7 @@ import * as SustainedSource from '../objects/sustainedSource.js';
172
170
  // `options.depth` already existed on DirectedTunnel, T1; this factory
173
171
  // simply now forwards it + arms activeAxes).
174
172
  var depth = (opts.depth !== undefined && opts.depth !== null) ? opts.depth : null;
175
- // ws-dse-3d AC3 — default 'spray' is byte-identical to every pre-existing
173
+ // Default 'spray' is byte-identical to every pre-existing
176
174
  // caller (this factory's own original hardcoded value below).
177
175
  var velocityProfile = opts.velocityProfile !== undefined ? opts.velocityProfile : 'spray';
178
176
 
@@ -191,7 +189,7 @@ import * as SustainedSource from '../objects/sustainedSource.js';
191
189
  if (depth !== null) { tunnelOpts.depth = depth; tunnelOpts.z = -depth / 2; }
192
190
  var tunnel = new DirectedTunnel(universe, tunnelOpts);
193
191
 
194
- // ws-dse-3d (CEO ruling 2026-07-14, "one source surface"): the recurring
192
+ // One source surface: the recurring
195
193
  // burst injector now routes through `sustainedSource.js`'s ONE
196
194
  // `buildSustainedSource` authority — the SAME surface
197
195
  // `setupLightSourceLab.js` (via `LightSource`'s own opt-in
@@ -199,7 +197,7 @@ import * as SustainedSource from '../objects/sustainedSource.js';
199
197
  // `entranceBias:'top'` reproduce this factory's PRE-EXISTING biased-
200
198
  // random-fan shape EXACTLY (the "uniformization visible" demo shape —
201
199
  // see the module docstring's "Biased entrance" note); `zIsotropy:true`
202
- // (the default) is the 3D-SYMMETRIC EMISSION fix (ws-dse-3d, theorist §4
200
+ // (the default) is the 3D-SYMMETRIC EMISSION fix (§4
203
201
  // option (a)) — when `depth` is armed, every burst now ALSO draws a `vz`
204
202
  // symmetric to the `vy` spread, instead of pinning z-momentum at zero
205
203
  // forever (the tester-measured z/y=0.23 flatness root cause).
@@ -220,7 +218,7 @@ import * as SustainedSource from '../objects/sustainedSource.js';
220
218
  // FrqtlApp.setup() (FrqtlApp.js:528) auto-wires
221
219
  // the render list; today the world's own census carries them by construction.
222
220
  largeObjects: tunnel.largeObjects,
223
- // CANONICAL TEARDOWN (CEO drive #2, 2026-07-14 — the reinit-
221
+ // CANONICAL TEARDOWN (the reinit-
224
222
  // compounding fix): `FrqtlApp.prototype.setup()` calls THIS
225
223
  // automatically before installing the NEXT setupResult. Delegates to
226
224
  // `src.dispose()` (the ONE `sustainedSource.js` teardown mechanism)
@@ -1,7 +1,7 @@
1
1
  /* Copyright 2023-2026 by Essam Abadir */
2
2
 
3
3
  /**
4
- * setupTunnelPointExit — the TUNNEL POINT-EXIT LAB (D3, CEO 2026-07-29).
4
+ * setupTunnelPointExit — the TUNNEL POINT-EXIT LAB (D3).
5
5
  *
6
6
  * ── Layer 1: API contract ────────────────────────────────────────────────────
7
7
  *
@@ -26,8 +26,7 @@ import { CollisionTypes } from '../../parts/CollisionTypes.js';
26
26
  * Builds two {@link PointSource} emitters separated by `sourceSeparation`, each
27
27
  * firing 1px/tick leaf Frames radially, plus two visual-only source circles.
28
28
  * The fringe pattern is EMERGENT — no wave equation; it appears where the two
29
- * particle streams overlap. (Figure + the knob sweep:
30
- * `docs/internal/records/physics-lab/2026-06-16-wave-interference-wavelengthScale.md`.)
29
+ * particle streams overlap.
31
30
  *
32
31
  * Two independent "wavelength" knobs — keep them distinct:
33
32
  * - `options.fundamentalWaveLength` → each emitter's `opts.wavelength` → particle
@@ -51,14 +50,14 @@ import { CollisionTypes } from '../../parts/CollisionTypes.js';
51
50
  * @param {number} [options.sourceDiameter] - Source circle diameter (default = wavelength).
52
51
  * @param {number} [options.quantumLimit] - Max quanta emitted per angle (default: velocity);
53
52
  * the steady-state density ceiling.
54
- * @param {number} [options.depth] - WS-DSE-3D Bite B0: total z-extent for a 3D run. OMITTED
53
+ * @param {number} [options.depth] - total z-extent for a 3D run. OMITTED
55
54
  * (default) → today's 2D behavior, byte-identical (no `activeAxes`/z key touched at all).
56
55
  * When provided: `universe.init()` gains `activeAxes:{x:true,y:true,z:true}` (mirrors
57
56
  * `setupParticleWalk3D`) and BOTH PointSources emit with a uniform z-spread centered on
58
57
  * z=0 (`zMin=-depth/2, zDepth=depth`) — every z-slice sees the same radial illumination,
59
58
  * so the emergent fringe pattern is genuinely 3D rather than a dark volume around one
60
59
  * lit plane (design §2.3/§4.4). This is the SAME emitter option `SlitLightSource`
61
- * consumes (WS-DSE-3D Bite B1) — the z-spread lives in `PointSource`/
60
+ * consumes — the z-spread lives in `PointSource`/
62
61
  * `emitterProgram.js`, not here, precisely so both experiments share it.
63
62
  * @returns {Object} `{ sources:{source1,source2}, source1Circle, source2Circle,
64
63
  * fundamentalDimension, desiredWaveLength, largeObjects }`.
@@ -84,7 +83,7 @@ import { CollisionTypes } from '../../parts/CollisionTypes.js';
84
83
  var fundamentalDimension = options.fundamentalDimension !== undefined ? options.fundamentalDimension : 2;
85
84
  var desiredWaveLength = options.fundamentalWaveLength !== undefined ? options.fundamentalWaveLength : 32;
86
85
  var wavelengthScale = options.wavelengthScale !== undefined ? options.wavelengthScale : 8;
87
- // WS-DSE-3D Bite B0: opt-in 3D depth. undefined/null → 2D, byte-identical.
86
+ // Opt-in 3D depth. undefined/null → 2D, byte-identical.
88
87
  var depth = (options.depth !== undefined && options.depth !== null) ? options.depth : null;
89
88
 
90
89
  // Init universe: ground-up, brownianMotion:false (the wave-walk). activeAxes is ONLY
@@ -5,7 +5,6 @@
5
5
  * unknown-kind throw TELLS the author what to build instead of leaving them to guess. A LEAF (no
6
6
  * imports): ObjectFactory reads it for its unknown-kind refusals, SlitLightSource for its own, and
7
7
  * the sketch rule (lib/frqtl/scenes/test/_sketch-rule.mjs) reads the names from here.
8
- * Rulings: docs/internal/engine/V2_PARTS_CLASSIFICATION.md §4.3/§4.4.
9
8
  */
10
9
 
11
10
  export const V1_REPLACEMENTS = Object.freeze({
@@ -2,7 +2,7 @@
2
2
 
3
3
  /**
4
4
  * CameraControls.js — a REUSABLE first-person-game-style camera-controls sugar
5
- * object (ws-emitter-wave Bite 3B, CEO 2026-07-20). ANY 3D experiment page drops
5
+ * object. ANY 3D experiment page drops
6
6
  * it in with ONE call; it drives the existing `runner.cameraControl` capability
7
7
  * (the camera-as-sugar / BYO-renderer pattern — `getCameraControl()` →
8
8
  * `look({spin,pitch})` ROTATES, `move({forward,strafe})` TRANSLATES) with two
@@ -82,7 +82,7 @@
82
82
  * all methods safe) is returned — every caller, including an unconditional
83
83
  * walkthrough-rung attach, is right in 2D by construction.
84
84
  *
85
- * ── Input mapping — the STANDARD FPS SPLIT (CEO-ruled 2026-07-26/07-28) ──────
85
+ * ── Input mapping — the STANDARD FPS SPLIT ───────────────────────────────────
86
86
  * The two pads are the two halves of a first-person camera and they do NOT
87
87
  * overlap: LOOK rotates, MOVE translates. MOVE never rotates.
88
88
  * LOOK pad (bottom-RIGHT) — ROTATION ONLY, and it is SCREEN-RELATIVE.
@@ -106,7 +106,7 @@
106
106
  * grabbed object follows the camera because the runner carries it on the camera's
107
107
  * own pose notice (`addPoseListener`), not because a stick is routed to it.
108
108
  * Space → `runner.grabToggle()` — the aim's grab/place key (STUDIO's
109
- * stationary reticle; docs/internal/engine/AIM_GRAB_FEEDBACK_CONTRACT.md).
109
+ * stationary reticle).
110
110
  * Ignored while typing (INPUT/TEXTAREA/SELECT/contenteditable) and
111
111
  * on key auto-repeat; a no-op while the runner's aim is off.
112
112
  * A state label above the pads (`data-role="aim-state"`) reads the runner's aim
@@ -166,7 +166,7 @@ import * as OrbitBag from '../compat/renderer/orbit-bag.js';
166
166
  '(RENDERER_CONTRACT §1a.2). (FAIL-LOUD.)');
167
167
  }
168
168
 
169
- // ── IDEMPOTENT per mountEl (F4, CEO 2026-07-23) ──────────────────────
169
+ // ── IDEMPOTENT per mountEl (F4) ──────────────────────────────────────
170
170
  // A second attach() on the SAME container returns the LIVE instance instead of
171
171
  // stacking a second pad set + a second window keydown listener. This kills the
172
172
  // double-mount race for EVERY caller — a page that wires its own joysticks
@@ -286,7 +286,7 @@ import * as OrbitBag from '../compat/renderer/orbit-bag.js';
286
286
  var moveY = clamp(jMove.y + km.y, -1, 1); // walk (translation, into the picture)
287
287
 
288
288
  var o = cam.getOrbit();
289
- // ── THE FPS SPLIT (CEO 2026-07-26, screen-relative 2026-07-28) ───
289
+ // ── THE FPS SPLIT (screen-relative) ──────────────────────────────
290
290
  // LOOK = rotation ONLY, and the widget COMPOSES NOTHING: it hands the
291
291
  // provider a screen-relative DELTA (spin about the view axis,
292
292
  // pitch about screen-right) and the ONE camera authority does
@@ -1,7 +1,7 @@
1
1
  /* Copyright 2023-2026 by Essam Abadir */
2
2
 
3
3
  /**
4
- * CameraPath.js — a declarative, REPRODUCIBLE camera path (CEO-ratified 2026-07-30).
4
+ * CameraPath.js — a declarative, REPRODUCIBLE camera path.
5
5
  *
6
6
  * ONE object for both modes. It drives `runner.cameraControl` — the single camera write path —
7
7
  * with ABSOLUTE poses derived from waypoints, so the same waypoints and the same tick always
@@ -4,9 +4,8 @@
4
4
  * CollisionActions — Canonical collision action enum for EGPT FRQTL VM.
5
5
  * Values are SCREAMING_SNAKE (the JS engine's native vocabulary).
6
6
  *
7
- * Canonical set — exactly what EGPTfrqtl.js lo.collide() action dispatch has.
8
- * Reference:docs/internal/engine/ENGINE_CONTRACT.md §2.3.
9
- * ACTIVE_ACTIONS = [ABSORB, COUNT, MARK, DETECT, LOG] (EGPTfrqtl.js line 987).
7
+ * Canonical set — exactly what the JS reference engine's lo.collide() action dispatch has.
8
+ * ACTIVE_ACTIONS = [ABSORB, COUNT, MARK, DETECT, LOG].
10
9
  * DO NOT add actions not present in the JS reference collide() without first
11
10
  * adding them there and updating the conformance suite (§11.3).
12
11
  *
@@ -4,8 +4,7 @@
4
4
  * CollisionTypes — Canonical collision type enum for EGPT FRQTL VM.
5
5
  * Values are SCREAMING_SNAKE (the JS engine's native vocabulary).
6
6
  *
7
- * Canonical set — exactly what EGPTfrqtl.js lo.collide() type switch has.
8
- * Reference:docs/internal/engine/ENGINE_CONTRACT.md §2.2.
7
+ * Canonical set — exactly what the JS reference engine's lo.collide() type switch has.
9
8
  * DO NOT add types not present in the JS reference collide() without first
10
9
  * adding them there and updating the conformance suite (§11.3).
11
10
  *