@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.
- package/CLAUDE.md +1 -1
- package/LICENSE.md +664 -0
- package/README.md +1 -1
- package/dist/dist-manifest.json +125 -125
- package/dist/fat/pkg-node/egpt_wasm.js +7 -7
- package/dist/fat/pkg-node/egpt_wasm_bg.wasm +0 -0
- package/dist/fat/pkg-node/package.json +1 -1
- package/dist/frqtl/compat/providers/wasm-engine.js +29 -31
- package/dist/frqtl/compat/providers/wasm-load-browser.js +2 -2
- package/dist/frqtl/compat/renderer/RenderFamily.js +1 -2
- package/dist/frqtl/compat/renderer/RenderMesh.js +2 -3
- package/dist/frqtl/compat/renderer/RenderShape.js +1 -1
- package/dist/frqtl/compat/renderer/captureStill-common.js +1 -2
- package/dist/frqtl/compat/renderer/display-slot.js +1 -1
- package/dist/frqtl/compat/renderer/providers/p5-provider.js +5 -5
- package/dist/frqtl/compat/renderer/providers/three-camera-contract.js +1 -1
- package/dist/frqtl/compat/renderer/providers/three-camera-geometry.js +4 -4
- package/dist/frqtl/compat/renderer/providers/three-provider.js +23 -27
- package/dist/frqtl/compat/renderer/renderCapabilities-common.js +2 -2
- package/dist/frqtl/compat/renderer/renderer-provider-contract.js +1 -1
- package/dist/frqtl/compat/vendor.js +2 -2
- package/dist/frqtl/objects/FrqtlApp.js +22 -24
- package/dist/frqtl/objects/ObjectFactory.js +1 -2
- package/dist/frqtl/objects/constants/WallBehaviors.js +5 -5
- package/dist/frqtl/objects/geometry/SlabFace.js +6 -6
- package/dist/frqtl/objects/instruments/capture-host.js +2 -2
- package/dist/frqtl/objects/instruments/capture.js +4 -5
- package/dist/frqtl/objects/instruments/hosted-eyes.js +3 -4
- package/dist/frqtl/objects/objects/DirectedTunnel.js +10 -11
- package/dist/frqtl/objects/objects/LightSource.js +22 -25
- package/dist/frqtl/objects/objects/QuantumEmitter.js +14 -14
- package/dist/frqtl/objects/objects/Tube.js +14 -14
- package/dist/frqtl/objects/objects/absorbRadiation.js +12 -13
- package/dist/frqtl/objects/objects/actionCompiler.js +52 -52
- package/dist/frqtl/objects/objects/controlAction.js +2 -2
- package/dist/frqtl/objects/objects/controlBind.js +2 -2
- package/dist/frqtl/objects/objects/directedRedirectProgram.js +3 -3
- package/dist/frqtl/objects/objects/emitterProgram.js +9 -9
- package/dist/frqtl/objects/objects/frqtl-control-slider.js +3 -3
- package/dist/frqtl/objects/objects/frqtl-control-sync.js +9 -9
- package/dist/frqtl/objects/objects/frqtl-control-widgets.js +2 -2
- package/dist/frqtl/objects/objects/frqtl-control-write-queue.js +2 -2
- package/dist/frqtl/objects/objects/makeControlsForObject.js +25 -29
- package/dist/frqtl/objects/objects/makeControlsForRenderSurface.js +2 -2
- package/dist/frqtl/objects/objects/slitLinerScatter.js +8 -10
- package/dist/frqtl/objects/objects/sustainedSource.js +15 -16
- package/dist/frqtl/objects/objects/tagger.js +2 -2
- package/dist/frqtl/objects/schema/engine-scopes.js +11 -12
- package/dist/frqtl/objects/schema/index.js +6 -6
- package/dist/frqtl/objects/schema/scopes.js +10 -10
- package/dist/frqtl/objects/setup/_collisionMatrixLanes.js +1 -1
- package/dist/frqtl/objects/setup/setupBlackbodySubstrate.js +1 -1
- package/dist/frqtl/objects/setup/setupCollisionMatrix.js +3 -3
- package/dist/frqtl/objects/setup/setupConeEmitter3D.js +7 -8
- package/dist/frqtl/objects/setup/setupDoubleSlit.js +20 -21
- package/dist/frqtl/objects/setup/setupFxSmoke.js +1 -1
- package/dist/frqtl/objects/setup/setupLightSourceLab.js +23 -26
- package/dist/frqtl/objects/setup/setupSphereEmitter3D.js +39 -40
- package/dist/frqtl/objects/setup/setupTunnelLab.js +17 -19
- package/dist/frqtl/objects/setup/setupTunnelPointExit.js +1 -1
- package/dist/frqtl/objects/setup/setupWaveInterference.js +4 -5
- package/dist/frqtl/objects/v1-replacements.js +0 -1
- package/dist/frqtl/parts/CameraControls.js +5 -5
- package/dist/frqtl/parts/CameraPath.js +1 -1
- package/dist/frqtl/parts/CollisionActions.js +2 -3
- package/dist/frqtl/parts/CollisionTypes.js +1 -2
- package/dist/frqtl/parts/DetectorWall.js +10 -10
- package/dist/frqtl/parts/FrqtlControlsPanel.js +11 -11
- package/dist/frqtl/parts/FrqtlVision.js +1 -1
- package/dist/frqtl/parts/GraphingDetectorWall.js +3 -4
- package/dist/frqtl/parts/LargeObject.js +7 -8
- package/dist/frqtl/parts/LightColor.js +2 -2
- package/dist/frqtl/parts/LiveChart.js +1 -1
- package/dist/frqtl/parts/LogicGate.js +4 -7
- package/dist/frqtl/parts/OvenBox.js +1 -2
- package/dist/frqtl/parts/PointSource.js +10 -11
- package/dist/frqtl/parts/SlitLightSource.js +6 -6
- package/dist/frqtl/parts/SlitScreen.js +14 -14
- package/dist/frqtl/parts/SphereEmitter.js +24 -24
- package/dist/frqtl/parts/Tunnel.js +17 -17
- package/dist/frqtl/parts/Wall.js +17 -17
- package/dist/frqtl/scenes/dse-one-emitter.js +1 -1
- package/dist/frqtl/scenes/dse-one-slit.js +2 -2
- package/dist/frqtl/scenes/dse-photoelectric.js +3 -3
- package/dist/frqtl/scenes/dse-tunnel-rebuild.js +5 -6
- package/dist/frqtl/scenes/dse-two-emitters.js +1 -1
- package/dist/frqtl/scenes/dse-two-slits.js +2 -2
- package/dist/frqtl/scenes/laser-buildup.js +1 -1
- package/dist/frqtl/scenes/mirror-3d.js +4 -4
- package/dist/frqtl/scenes/mirror-route.js +9 -9
- package/dist/frqtl/scenes/mirror.js +1 -1
- package/dist/frqtl/scenes/self-interference.js +1 -1
- package/dist/frqtl/scenes/smoking-gun.js +1 -1
- package/dist/frqtl/scenes/sun.js +2 -2
- package/dist/shim/bundle/frqnb.js +3 -3
- package/dist/shim/bundle/index.js +1 -1
- package/dist/shim/bundle/manifest.js +2 -2
- package/dist/shim/bundle/zip.js +1 -1
- package/dist/shim/controls/index.js +14 -14
- package/dist/shim/controls/registry.js +3 -3
- package/dist/shim/engine/artifact-shell.js +1 -2
- package/dist/shim/engine/router.js +15 -17
- package/dist/shim/expr/ast-schema.js +5 -5
- package/dist/shim/field-descriptor/index.js +7 -8
- package/dist/shim/frame-data/index.js +3 -3
- package/dist/shim/index.js +4 -4
- package/dist/shim/notebook/canvas-guard.js +1 -1
- package/dist/shim/notebook/catalog.js +2 -2
- package/dist/shim/notebook/format.js +26 -26
- package/dist/shim/notebook/kernel.js +3 -4
- package/dist/shim/notebook/knob.js +0 -1
- package/dist/shim/notebook/module-resolver.js +6 -6
- package/dist/shim/notebook/produced-bindings.js +1 -1
- package/dist/shim/notebook/setup-builder.js +9 -12
- package/dist/shim/notebook/vendor-importmap.js +1 -1
- package/dist/shim/notebook/view-builder.js +1 -1
- package/dist/shim/notebook/view-ctx.js +1 -1
- package/dist/shim/notebook/warmup.js +2 -2
- package/dist/shim/page-params/index.js +8 -9
- package/dist/shim/registry/copy-gate.js +1 -1
- package/dist/shim/registry/exhibits.js +4 -4
- package/dist/shim/registry/experiments.js +3 -3
- package/dist/shim/registry/walkthrough.js +21 -24
- package/dist/shim/render/render-stages.js +2 -2
- package/dist/shim/render/sun-look.js +2 -2
- package/dist/shim/rpc/index.js +2 -2
- package/dist/shim/runtime/index.js +12 -12
- package/dist/shim/storage/modules.js +8 -8
- package/llms.txt +2 -2
- package/package.json +4 -3
|
@@ -56,7 +56,7 @@ export const PROSE_CELL_TYPES = Object.freeze(['markdown']);
|
|
|
56
56
|
* Cell type. `markdown` renders prose. `js` executes via the Runtime lane
|
|
57
57
|
* (`math` or `frqtl`). `module` is user-code reachable by import (not runnable).
|
|
58
58
|
* `canvas` mounts a live physics realm. `chart` renders a data view. `view` runs
|
|
59
|
-
* ARBITRARY user code in the realm
|
|
59
|
+
* ARBITRARY user code in the realm — the
|
|
60
60
|
* user module (`module="<name>#<export>"`) imports vendored libs via the 2a
|
|
61
61
|
* import-map and renders into a DOM `mount`. `liveChart=` is a blessed PRESET
|
|
62
62
|
* over this same `view` substrate.
|
|
@@ -73,7 +73,7 @@ export const PROSE_CELL_TYPES = Object.freeze(['markdown']);
|
|
|
73
73
|
* @property {string[]} out
|
|
74
74
|
* Binding names this cell PRODUCES (committed to the kernel's binding store on success).
|
|
75
75
|
* @property {string} bind
|
|
76
|
-
* For `canvas` cells: RETIRED runner binding name
|
|
76
|
+
* For `canvas` cells: RETIRED runner binding name.
|
|
77
77
|
* A canvas that carries BOTH `setup` and a legacy `bind`/`out` runner ref is an
|
|
78
78
|
* unconverted cell and FAILS LOUD at both hosts (C7 migration guard). The runner is
|
|
79
79
|
* now realm-internal, never a kernel binding.
|
|
@@ -82,7 +82,7 @@ export const PROSE_CELL_TYPES = Object.freeze(['markdown']);
|
|
|
82
82
|
* For `canvas` cells: RETIRED (the opaque setup-factory name) — a `spec` on a canvas
|
|
83
83
|
* FAILS LOUD at both hosts (factory-retire C3).
|
|
84
84
|
* @property {string} setup
|
|
85
|
-
* For `canvas` cells: the setup declaration
|
|
85
|
+
* For `canvas` cells: the setup declaration.
|
|
86
86
|
* `<module-name>` is a `type="module"` cell's `name`. Its grammar depends on `shape`
|
|
87
87
|
* and is owned by lib/shim/notebook/setup-builder.js parseSetupDeclaration: a factory
|
|
88
88
|
* canvas is `'<module-name>#<factoryName>'` (the name REQUIRED), a recipe canvas is
|
|
@@ -92,7 +92,7 @@ export const PROSE_CELL_TYPES = Object.freeze(['markdown']);
|
|
|
92
92
|
* Empty for all other cell types.
|
|
93
93
|
* @property {string} shape
|
|
94
94
|
* For `canvas` cells: OPTIONAL setup-form discriminator naming which SHAPE the
|
|
95
|
-
* declared `setup` module takes (
|
|
95
|
+
* declared `setup` module takes (the frqtl-notebook recipe fix). Two forms:
|
|
96
96
|
* - `'factory'` (DEFAULT when omitted): the module export is a setup FACTORY
|
|
97
97
|
* `fn(frqtl, universe, options)` — the shim synthesizes
|
|
98
98
|
* `runner.setup((u,o) => fn(frqtl, u, o), opts)` (the pre-existing gallery form,
|
|
@@ -119,7 +119,7 @@ export const PROSE_CELL_TYPES = Object.freeze(['markdown']);
|
|
|
119
119
|
* all other cell types.
|
|
120
120
|
* @property {boolean} render3d
|
|
121
121
|
* For `canvas` cells: OPTIONAL — request the three.js 3D renderer + perspective
|
|
122
|
-
* camera for this canvas
|
|
122
|
+
* camera for this canvas.
|
|
123
123
|
* Selected through the ONE renderer-selection mechanism (the boot module's
|
|
124
124
|
* bootRealm, lib/frqtl/experiments/_shared/boot.js) — NOT a new renderer
|
|
125
125
|
* mechanism. The host (notebook-pane) threads this into `realm-frqtl.js`'s
|
|
@@ -131,20 +131,20 @@ export const PROSE_CELL_TYPES = Object.freeze(['markdown']);
|
|
|
131
131
|
* `false` for all other cell types.
|
|
132
132
|
* @property {Object<string,number|string>} renderOptions
|
|
133
133
|
* For `canvas` cells: OPTIONAL render-INTENT knob assignments parsed from
|
|
134
|
-
* `"key=value,…"` (
|
|
134
|
+
* `"key=value,…"` (gym-controls-as-sugar fix-loop #6 Finding B, 2026-07-04) —
|
|
135
135
|
* the notebook-cell channel for the SAME render-intent writes a scene file states
|
|
136
136
|
* itself (e.g. lib/frqtl/scenes/collision-matrix-3d.js's
|
|
137
137
|
* `exp.render({ shape: 'sphere', colorScheme: 'roygbiv' })`, a ferry to
|
|
138
138
|
* `runner.setRenderOptions`). PURE PARSE — reuses the identical `_parseOpts`/
|
|
139
139
|
* `_joinOpts` machinery as `opts` (same `kind:'opts'`), but is a DISTINCT,
|
|
140
140
|
* SEPARATE key — never folded into `opts`. This is deliberate channel
|
|
141
|
-
* separation
|
|
141
|
+
* separation: `opts` feeds the setup
|
|
142
142
|
* FACTORY as physics-knob arguments (`frqtl.knob` → `options` param);
|
|
143
143
|
* `renderOptions` feeds `runner.setRenderOption()` calls AFTER `runner.setup()`
|
|
144
144
|
* returns — a render-knob write must never be mixed into the physics-knob bag.
|
|
145
145
|
* Empty → `{}`; omitted on serialize when empty. Empty for all other cell types.
|
|
146
146
|
* @property {string} cameraPreset
|
|
147
|
-
* For `canvas` cells: OPTIONAL named camera-orbit preset (
|
|
147
|
+
* For `canvas` cells: OPTIONAL named camera-orbit preset (gym-controls-as-sugar
|
|
148
148
|
* fix-loop #6 Finding B) — the notebook-cell channel for a standalone page's
|
|
149
149
|
* `runner.cameraControl.setPreset('<name>')` call (e.g. a 3D page's
|
|
150
150
|
* `window._egptFx.cameraPreset = 'down-barrel'`, applied by `fx-experiment.js`
|
|
@@ -163,7 +163,7 @@ export const PROSE_CELL_TYPES = Object.freeze(['markdown']);
|
|
|
163
163
|
* cell types.
|
|
164
164
|
* @property {string[]} produces
|
|
165
165
|
* For `canvas` cells: the serializable binding name(s) the canvas COMMITS to the
|
|
166
|
-
* kernel after the realm-internal runner mounts
|
|
166
|
+
* kernel after the realm-internal runner mounts.
|
|
167
167
|
* The realm DERIVES each value at runtime via the frozen handle (`produceVia`) and
|
|
168
168
|
* the host commits it via `kernel.commitViewOutputs`. Parsed with `_splitNames`
|
|
169
169
|
* (→ `string[]`); empty → `[]`; omitted on serialize when empty. On parse a canvas's
|
|
@@ -178,7 +178,7 @@ export const PROSE_CELL_TYPES = Object.freeze(['markdown']);
|
|
|
178
178
|
* @property {string} produceAfter
|
|
179
179
|
* For `canvas` cells: OPTIONAL integer-string tick count to WARM UP the realm
|
|
180
180
|
* (deterministic `handle.step()` loop) BEFORE deriving the produced binding
|
|
181
|
-
*
|
|
181
|
+
* The runner mounts at tick ~0 where no particle has
|
|
182
182
|
* reached the detector yet — deriving immediately commits an EMPTY histogram. Warming
|
|
183
183
|
* up `produceAfter` ticks lets particles cross the stage and accumulate at the detector
|
|
184
184
|
* so the committed binding (and the downstream chart) shows REAL data. ONE config
|
|
@@ -186,7 +186,7 @@ export const PROSE_CELL_TYPES = Object.freeze(['markdown']);
|
|
|
186
186
|
* the host default warmup. Empty for all other cell types.
|
|
187
187
|
* @property {string} liveChart
|
|
188
188
|
* For `canvas` cells: OPTIONAL frozen-handle `call()` projector name the live
|
|
189
|
-
* SAME-CELL accumulation chart polls each throttle tick
|
|
189
|
+
* SAME-CELL accumulation chart polls each throttle tick.
|
|
190
190
|
* The blessed value is `'detectorHistogram'` (the one frqtl producer) — it reuses the
|
|
191
191
|
* SAME projector vocabulary as `produceVia`. UNLIKE `produces`, `liveChart` commits
|
|
192
192
|
* NOTHING to the kernel: it draws CONTINUOUSLY inside the canvas's OWN realm off the
|
|
@@ -205,7 +205,7 @@ export const PROSE_CELL_TYPES = Object.freeze(['markdown']);
|
|
|
205
205
|
* boot (`frqtl` | `chart` | a BYO name). `_realmNameForCell` ALREADY honors this:
|
|
206
206
|
* an explicit `cell.realm` wins, else the cell TYPE selects the blessed pre-load.
|
|
207
207
|
* PURE PARSE — empty → `''` (omitted on serialize; the host falls back to the
|
|
208
|
-
* type-default `frqtl`).
|
|
208
|
+
* type-default `frqtl`).
|
|
209
209
|
* @property {string} module
|
|
210
210
|
* For `view` cells: the user render module declaration `'<module-name>#<exportName>'`,
|
|
211
211
|
* mirroring the canvas `setup` shape. `<module-name>` is a `type="module"` cell's
|
|
@@ -213,13 +213,13 @@ export const PROSE_CELL_TYPES = Object.freeze(['markdown']);
|
|
|
213
213
|
* export (zero/multiple → FAIL-LOUD at the view-builder synthesis helper, never
|
|
214
214
|
* guess; C5 mirror). The shim runs the named export IN THE REALM with the view
|
|
215
215
|
* `ctx`. PURE PARSE — empty → `''` (omitted on serialize). Empty for non-`view`
|
|
216
|
-
* cell types.
|
|
216
|
+
* cell types.
|
|
217
217
|
* @property {string} subscribe
|
|
218
218
|
* For `view` cells: OPTIONAL cross-cell — the cellId of ANOTHER canvas whose tick
|
|
219
219
|
* stream this view observes. PARSED + round-tripped now for format stability, but
|
|
220
220
|
* the cross-cell WIRING is DEFERRED (§3.4 of the design): the same-cell path is the
|
|
221
|
-
* primary 2b
|
|
222
|
-
* for non-`view` cell types.
|
|
221
|
+
* primary 2b path. PURE PARSE — empty → `''` (omitted on serialize). Empty
|
|
222
|
+
* for non-`view` cell types.
|
|
223
223
|
* @property {Object<string,number|string>} opts
|
|
224
224
|
* For `canvas` cells: driving-knob assignments parsed from `"key=value,…"`.
|
|
225
225
|
* PURE PARSE only — validation is `lib/shim/notebook/knob.js`'s authority. Empty → `{}`.
|
|
@@ -521,7 +521,7 @@ export function parse(html) {
|
|
|
521
521
|
' — legal types (CELL_TYPES): ' + CELL_TYPES.join(', ') + ' (FAIL-LOUD).'
|
|
522
522
|
);
|
|
523
523
|
}
|
|
524
|
-
//
|
|
524
|
+
// A canvas's `produces` names are the
|
|
525
525
|
// serializable bindings it COMMITS to the kernel after the realm-internal
|
|
526
526
|
// runner mounts. They are FOLDED INTO `out` here (a produced binding IS an
|
|
527
527
|
// output binding the cell commits) so producer-discovery + the topo run-order
|
|
@@ -548,51 +548,51 @@ export function parse(html) {
|
|
|
548
548
|
out: foldedOut,
|
|
549
549
|
bind: a.bind || '',
|
|
550
550
|
spec: a.spec || '',
|
|
551
|
-
//
|
|
551
|
+
// View-cell declaration (realm/module/subscribe).
|
|
552
552
|
// PURE PARSE — kept verbatim; the host validates (FAIL-LOUD). View-only in
|
|
553
553
|
// practice; empty for every other cell type so the attrs are omitted on
|
|
554
554
|
// serialize (round-trip idempotent).
|
|
555
555
|
realm: a.realm || '',
|
|
556
556
|
module: a.module || '',
|
|
557
557
|
subscribe: a.subscribe || '',
|
|
558
|
-
//
|
|
558
|
+
// The canvas DECLARES its setup +
|
|
559
559
|
// runner config; the shim synthesizes the builder from these. Only
|
|
560
560
|
// meaningful for type="canvas"; empty for every other type so the
|
|
561
561
|
// attribute is omitted on serialize (round-trip idempotent).
|
|
562
562
|
setup: a.setup || '',
|
|
563
|
-
//
|
|
563
|
+
// The setup-form discriminator ('factory' | 'recipe'). PURE PARSE
|
|
564
564
|
// — kept verbatim; the setup-builder synthesis helper validates it (empty →
|
|
565
565
|
// 'factory'; unknown → FAIL-LOUD). Canvas-only in practice; empty for every
|
|
566
566
|
// other cell type so the attribute is omitted on serialize (idempotent).
|
|
567
567
|
shape: a.shape || '',
|
|
568
568
|
stage: a.stage || '',
|
|
569
569
|
seed: a.seed || '',
|
|
570
|
-
//
|
|
570
|
+
// Request the three.js 3D
|
|
571
571
|
// renderer for this canvas (mirrors `collapsed`'s bool-attr parse —
|
|
572
572
|
// only the literal "true" sets it; absent/anything else → false,
|
|
573
573
|
// omitted on serialize, idempotent round-trip). Canvas-only in
|
|
574
574
|
// practice.
|
|
575
575
|
render3d: a.render3d === 'true',
|
|
576
|
-
//
|
|
576
|
+
// gym-controls-as-sugar fix-loop #6 Finding B: render-INTENT knobs
|
|
577
577
|
// (`runner.setRenderOption` key/value pairs) — reuses `_parseOpts`
|
|
578
578
|
// (SAME kind:'opts' parser as `opts`, but a channel-separate key; see
|
|
579
579
|
// the @property doc above). Canvas-only in practice.
|
|
580
580
|
renderOptions: _parseOpts(a.renderOptions),
|
|
581
|
-
//
|
|
581
|
+
// gym-controls-as-sugar fix-loop #6 Finding B: named camera-orbit
|
|
582
582
|
// preset (`runner.cameraControl.setPreset` call) — PURE PARSE, kept
|
|
583
583
|
// verbatim as a string (mirrors `seed`). Canvas-only in practice.
|
|
584
584
|
cameraPreset: a.cameraPreset || '',
|
|
585
|
-
//
|
|
585
|
+
// The serializable binding(s) this canvas
|
|
586
586
|
// commits + the frozen-handle call that derives each. Canvas-only; empty for
|
|
587
587
|
// every other cell type so the attrs are omitted on serialize (idempotent).
|
|
588
588
|
produces: declaredProduces,
|
|
589
589
|
produceVia: a.produceVia || '',
|
|
590
|
-
//
|
|
590
|
+
// Integer-string warmup tick count. PURE PARSE —
|
|
591
591
|
// kept verbatim as a string (mirrors `seed`); the host parses + clamps it
|
|
592
592
|
// (numeric validation is the host's authority, not this pure parser). Empty
|
|
593
593
|
// for every other cell type so the attr is omitted on serialize (idempotent).
|
|
594
594
|
produceAfter: a.produceAfter || '',
|
|
595
|
-
//
|
|
595
|
+
// The SAME-CELL live accumulation chart's
|
|
596
596
|
// projector name + kind. PURE PARSE — kept verbatim as strings (mirrors
|
|
597
597
|
// `produceVia`/`seed`); the host validates the projector against the blessed set
|
|
598
598
|
// and the kind against `bar|line` (FAIL-LOUD). They commit NOTHING to the kernel
|
|
@@ -652,7 +652,7 @@ function _cellOpenTag(cell) {
|
|
|
652
652
|
if (kind === 'names') {
|
|
653
653
|
str = _joinNames(key === 'out' ? outOnly : key === 'produces' ? producesArr : cell[key]);
|
|
654
654
|
} else if (kind === 'opts') {
|
|
655
|
-
// Generalized to `cell[key]` (
|
|
655
|
+
// Generalized to `cell[key]` (gym-controls-as-sugar fix-loop #6 Finding B):
|
|
656
656
|
// a hardcoded `cell.opts` here was harmless while `opts` was the ONLY
|
|
657
657
|
// kind:'opts' key, but would have silently serialized `opts`'s content
|
|
658
658
|
// under a SECOND opts-kind key's tag (`renderOptions`) once one was added —
|
|
@@ -378,10 +378,9 @@ export class NotebookKernel {
|
|
|
378
378
|
* keep document order. A dependency cycle → FAIL-LOUD throw (no safe order).
|
|
379
379
|
* NEVER auto-runs; NEVER mutates bindings.
|
|
380
380
|
*
|
|
381
|
-
* FRQTL-MAINT(runall-excludes-chart-cells) — FIXED
|
|
382
|
-
* A2, FRAQTL issue #61). The RUNNABLE map used to be `{js, canvas}` only —
|
|
381
|
+
* FRQTL-MAINT(runall-excludes-chart-cells) — FIXED. The RUNNABLE map used to be `{js, canvas}` only —
|
|
383
382
|
* `runAll()` reported `total:N ran:N` while silently never running `chart`/
|
|
384
|
-
* `view` cells (
|
|
383
|
+
* `view` cells (`double-slit-rosetta-qft.html`),
|
|
385
384
|
* even though a manual per-cell Run on the same cell works (it routes through
|
|
386
385
|
* the pane's realm-cell runner, `opts.runner`, not `runCell`). `chart`/`view`
|
|
387
386
|
* cells DO declare `in`/`out` bindings today (`_resolveChartRecipe` FAIL-LOUD
|
|
@@ -391,7 +390,7 @@ export class NotebookKernel {
|
|
|
391
390
|
* whichever cell produces the binding it reads, exactly like a `js` consumer.
|
|
392
391
|
* The pane's `opts.runner` (lib/components/notebook-pane/index.js `runAll()`)
|
|
393
392
|
* already special-cased `chart` alongside `canvas` — it was only ever missing
|
|
394
|
-
* `view`, fixed in the same
|
|
393
|
+
* `view`, fixed in the same change.
|
|
395
394
|
*
|
|
396
395
|
* @returns {Array<object>} ordered cell objects (each has `{ id, type, lane, body, in, out }`).
|
|
397
396
|
* @throws {Error} if a cycle is detected in the declared `in`/`out` graph.
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Notebook knob — the SINGLE authority for the canvas-cell driving knob
|
|
5
|
-
* (WS-NOTEBOOK-D GAP2).
|
|
6
5
|
*
|
|
7
6
|
* A canvas cell may carry an `opts="<key>=<value>,…"` attribute (parsed to a
|
|
8
7
|
* `{key: Number}` map by lib/shim/notebook/format.js — a pure module that does
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/* Copyright 2023-2026 by Essam Abadir */
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Notebook cell-as-module resolver — the IN-MEMORY blob closure (
|
|
5
|
-
*
|
|
4
|
+
* Notebook cell-as-module resolver — the IN-MEMORY blob closure (B2;
|
|
5
|
+
* build-gate C + VETO-CLASS constraint #1).
|
|
6
6
|
*
|
|
7
7
|
* Named ESM export. PURE module — NO Runtime/Bus/DOM/engine imports. It is
|
|
8
8
|
* host-neutral (it must NOT assume CodeEditorPane or any pane exists — model-gate
|
|
9
|
-
*
|
|
9
|
+
* rule 6): the blob-minting + dynamic-import are injected by the caller
|
|
10
10
|
* (Runtime.runCell in the browser; a test stub in node).
|
|
11
11
|
*
|
|
12
12
|
* ── What it does ─────────────────────────────────────────────────────────────
|
|
@@ -118,8 +118,8 @@ export function splitImportsAndBody(code) {
|
|
|
118
118
|
|
|
119
119
|
// Rewrite every relative specifier in `source` to the blob URL of the resolved
|
|
120
120
|
// sibling (looked up in blobUrlByKey) — BOTH static `from '…'` clauses (import/
|
|
121
|
-
// export) AND dynamic `import('…')` call expressions (
|
|
122
|
-
//
|
|
121
|
+
// export) AND dynamic `import('…')` call expressions (gym-controls-as-sugar
|
|
122
|
+
// REMEDIATION, Finding 2: the synthesized builder now DEFERS its
|
|
123
123
|
// module-cell import to a dynamic `await import(...)` placed AFTER
|
|
124
124
|
// `frqtl.ensureEngine()` — see setup-builder.js — so the relative specifier
|
|
125
125
|
// this rewrite must resolve can appear inside the function BODY, not only the
|
|
@@ -242,7 +242,7 @@ export function buildModuleClosure(modules, mintBlobUrl) {
|
|
|
242
242
|
* invokes `mod.default(caps, inputs)`.
|
|
243
243
|
*
|
|
244
244
|
* The rewrite runs on the FULL `code` (imports AND body) BEFORE splitting —
|
|
245
|
-
*
|
|
245
|
+
* REMEDIATION, Finding 2: the synthesized
|
|
246
246
|
* builder's module-cell reference is now a DYNAMIC `await import('<module>')`
|
|
247
247
|
* placed inside the body (after `frqtl.ensureEngine()`, deliberately deferring
|
|
248
248
|
* evaluation — see setup-builder.js), so a relative specifier needing
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* produced-bindings — the PURE derive-the-serializable-binding helper for the
|
|
5
|
-
* realm→kernel binding seam
|
|
5
|
+
* realm→kernel binding seam. NO DOM / engine /
|
|
6
6
|
* Runtime / Bus import, so a test exercises it with a fake handle WITHOUT a browser.
|
|
7
7
|
*
|
|
8
8
|
* A DECLARED canvas commits its `produces` binding(s) by DERIVING each value from the
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* setup-builder — the SOLE authority that synthesizes the canonical experiment
|
|
5
5
|
* BUILDER source from a `canvas` cell's declarative configuration
|
|
6
|
-
* (WS-NOTEBOOK-SHIM-MANAGED-BUILDER).
|
|
7
6
|
*
|
|
8
7
|
* Named ESM export. PURE module — NO DOM / engine / Runtime / Bus import (C8). It
|
|
9
8
|
* is host-neutral and node-testable: hosts (the notebook-pane in-app) import this
|
|
@@ -52,7 +51,7 @@
|
|
|
52
51
|
* caller never ships a builder that 404s the relative import downstream.
|
|
53
52
|
*
|
|
54
53
|
* ── C14: the module import is DYNAMIC and runs AFTER ensureEngine (ordering
|
|
55
|
-
* guarantee,
|
|
54
|
+
* guarantee, REMEDIATION, Finding 2) ───────────────────────────────────────────
|
|
56
55
|
*
|
|
57
56
|
* A canonical setup factory's browser-classic export branch captures window.*
|
|
58
57
|
* game-layer globals (LargeObject, SlitScreen, PointSource, …) into closure vars
|
|
@@ -250,7 +249,7 @@ export function parseSeed(seed) {
|
|
|
250
249
|
* @param {boolean} [decl.render3d] — the cell's display declaration: a factory canvas's runner is
|
|
251
250
|
* built 3D (`is3D: true`); a recipe canvas states 3D itself (`exp.createScene`).
|
|
252
251
|
* @param {string|number} [decl.seed] — runner RNG seed (C4); empty → FrqtlApp default.
|
|
253
|
-
* @param {Object<string,number|string>} [decl.renderOptions] —
|
|
252
|
+
* @param {Object<string,number|string>} [decl.renderOptions] — gym-controls-as-sugar
|
|
254
253
|
* fix-loop #6 Finding B: render-INTENT key/value pairs applied via
|
|
255
254
|
* `runner.setRenderOption(key, value)` calls, ONE per key, emitted AFTER
|
|
256
255
|
* `runner.setup(...)` — mirroring the proven page-side order
|
|
@@ -258,12 +257,12 @@ export function parseSeed(seed) {
|
|
|
258
257
|
* A SEPARATE channel from `decl.opts` (never merged — `opts` are physics-factory
|
|
259
258
|
* arguments; `renderOptions` are renderer-property-bag writes). `{}` → no calls
|
|
260
259
|
* emitted (byte-identical to a canvas with no `renderOptions` attr).
|
|
261
|
-
* @param {string} [decl.cameraPreset] —
|
|
260
|
+
* @param {string} [decl.cameraPreset] — gym-controls-as-sugar fix-loop #6 Finding B:
|
|
262
261
|
* a named camera-orbit preset applied via the CAPABILITY-CHECKED
|
|
263
262
|
* `runner.cameraControl && runner.cameraControl.setPreset(name)` (skipped when the active
|
|
264
263
|
* renderer has no camera control — the page-side `if (cam) { cam.setPreset(...) }` idiom;
|
|
265
264
|
* a camera that does not offer the preset THROWS). Empty/absent → no call emitted.
|
|
266
|
-
* @param {string} [decl.shape] — the setup-form discriminator
|
|
265
|
+
* @param {string} [decl.shape] — the setup-form discriminator: `'factory'`
|
|
267
266
|
* (DEFAULT when empty/absent) or `'recipe'`. Any OTHER value → FAIL-LOUD (never a
|
|
268
267
|
* silent fallback). See the two-form note below.
|
|
269
268
|
* @param {string} [decl.outName] — realm-internal output name; default `'_run'`.
|
|
@@ -273,7 +272,7 @@ export function parseSeed(seed) {
|
|
|
273
272
|
* @throws {Error} FAIL-LOUD on a missing module / unknown export / zero-or-multiple
|
|
274
273
|
* exports with no `#export` / malformed stage|seed / an unknown `shape`.
|
|
275
274
|
*
|
|
276
|
-
* ── Two setup forms — the `shape` discriminator
|
|
275
|
+
* ── Two setup forms — the `shape` discriminator ───────────────────────────────
|
|
277
276
|
*
|
|
278
277
|
* A declared canvas's `setup` module takes ONE of two shapes; the CELL_ATTR `shape`
|
|
279
278
|
* (owner: lib/shim/notebook/format.js) declares which, and this authority synthesizes
|
|
@@ -309,9 +308,7 @@ export function parseSeed(seed) {
|
|
|
309
308
|
* the owner anyway. `RecipeContext` used to return null instead — that null reached
|
|
310
309
|
* `exp.build` as an opaque property-access TypeError, which is what #73 reported.
|
|
311
310
|
*
|
|
312
|
-
* ── C15: the caller MUST force the runtime's cell-as-module path
|
|
313
|
-
* gym-controls-as-sugar Bite 0a fix-loop #3 — tester regression finding
|
|
314
|
-
* 2026-07-03) ──────────────────────────────────────────────────────────────
|
|
311
|
+
* ── C15: the caller MUST force the runtime's cell-as-module path ────────────
|
|
315
312
|
*
|
|
316
313
|
* `Runtime.runCell` decides JS-vs-module-blob routing by SNIFFING the cell body
|
|
317
314
|
* for a STATIC top-level `import` (`lib/shim/notebook/module-resolver.js`
|
|
@@ -345,7 +342,7 @@ export function parseSeed(seed) {
|
|
|
345
342
|
*/
|
|
346
343
|
export function synthesizeBuilderSource(decl) {
|
|
347
344
|
decl = decl || {};
|
|
348
|
-
//
|
|
345
|
+
// The setup-form discriminator. Empty/absent → 'factory' (the pre-existing
|
|
349
346
|
// gallery form, byte-identical). 'recipe' → RecipeContext/buildExperiment. Any other
|
|
350
347
|
// value FAILS LOUD — never a silent guess.
|
|
351
348
|
var shape = (decl.shape == null || decl.shape === '') ? 'factory' : String(decl.shape).trim();
|
|
@@ -389,7 +386,7 @@ export function synthesizeBuilderSource(decl) {
|
|
|
389
386
|
var factoryCfgParts = decl.render3d ? cfgParts.concat(['is3D: true']) : cfgParts;
|
|
390
387
|
var cfgLiteral = '{ ' + factoryCfgParts.join(', ') + ' }';
|
|
391
388
|
|
|
392
|
-
//
|
|
389
|
+
// gym-controls-as-sugar fix-loop #6 Finding B: render-INTENT lines, emitted
|
|
393
390
|
// AFTER runner.setup() (mirrors the proven page-side order in fx-experiment.js:
|
|
394
391
|
// setup() → setRenderOption(renderDefaults) → cameraControl.setPreset()). Each
|
|
395
392
|
// `renderOptions` key becomes its OWN `runner.setRenderOption('<k>', <v>);` call
|
|
@@ -419,7 +416,7 @@ export function synthesizeBuilderSource(decl) {
|
|
|
419
416
|
// The canonical template (the §0 builder shape). Both shapes:
|
|
420
417
|
// - boot the engine FIRST (ensureEngine),
|
|
421
418
|
// - THEN dynamically import the editable in-notebook module by name (C1) — WS
|
|
422
|
-
//
|
|
419
|
+
// REMEDIATION, Finding 2: a canonical setup
|
|
423
420
|
// factory's browser-classic branch captures window.* game-layer globals
|
|
424
421
|
// (LargeObject, SlitScreen, …) into closure vars AT MODULE-EVALUATION TIME. A
|
|
425
422
|
// STATIC top-level `import` of the module cell is resolved+evaluated as part
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Copyright 2023-2026 by Essam Abadir
|
|
2
2
|
// lib/shim/notebook/vendor-importmap.js — the ONE pure import-map generator.
|
|
3
3
|
//
|
|
4
|
-
//
|
|
4
|
+
// Phase 2a (§2a.3). Maps the committed vendor manifest
|
|
5
5
|
// (lib/frqtl/assets/vendor/manifest.json) → a browser `<script type="importmap">`
|
|
6
6
|
// payload `{ imports: { <spec>: <url> } }`, so a realm cell's builder/view module
|
|
7
7
|
// can `import * as d3 from 'd3'` and the realm's native module loader resolves the
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* view-builder — the SOLE authority that synthesizes the canonical VIEW-ENTRY source
|
|
5
|
-
* from a `view` cell's declarative configuration
|
|
5
|
+
* from a `view` cell's declarative configuration.
|
|
6
6
|
*
|
|
7
7
|
* Named ESM export. PURE module — NO DOM / engine / Runtime / Bus import. It is
|
|
8
8
|
* host-neutral and node-testable: hosts (the notebook-pane in-app) import this one
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* view-ctx — the SOLE authority that assembles the `view` cell CONTEXT object handed
|
|
5
|
-
* to a user render module's export
|
|
5
|
+
* to a user render module's export.
|
|
6
6
|
*
|
|
7
7
|
* Named ESM export. PURE module — NO DOM / engine / Runtime / Bus import. It is a
|
|
8
8
|
* THIN convenience WRAPPER over the EXISTING frozen ViewHandle + the realm→kernel
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* warmup — the PURE warm-up-before-derive helper for the realm→kernel binding seam
|
|
5
|
-
*
|
|
5
|
+
* NO DOM / engine / Runtime / Bus import, so a test
|
|
6
6
|
* exercises it with a fake handle WITHOUT a browser.
|
|
7
7
|
*
|
|
8
8
|
* THE PROBLEM IT SOLVES: a DECLARED canvas that `produces` a binding mounts its
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* `produceAfter` (a malformed authored attr) FAILS LOUD here — never silently
|
|
25
25
|
* clamped-to-zero, which would re-introduce the empty-histogram bug under a typo.
|
|
26
26
|
*
|
|
27
|
-
* FOLLOW-UP (
|
|
27
|
+
* FOLLOW-UP (interactive review): the live `on('tick')` same-cell chart and
|
|
28
28
|
* arbitrary-import path supersede this static one-shot warmup. This module is the
|
|
29
29
|
* baseline only.
|
|
30
30
|
*/
|
|
@@ -2,9 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* lib/shim/page-params — the URL-param routing-table contract for canonical
|
|
5
|
-
* experiment pages (
|
|
6
|
-
*
|
|
7
|
-
* design circulated + converged).
|
|
5
|
+
* experiment pages (gym-controls-as-sugar item 0 — the param contract designed
|
|
6
|
+
* properly and built with the controls).
|
|
8
7
|
*
|
|
9
8
|
* Peer of `lib/shim/frame-data`, `lib/shim/expr/ast-schema`, `lib/shim/controls` —
|
|
10
9
|
* same layout convention: a closed vocabulary exported as named ES-module exports,
|
|
@@ -18,8 +17,8 @@
|
|
|
18
17
|
* - `lib/frqtl/experiments/_shared/boot.js` reads `renderer`, `engine` and the
|
|
19
18
|
* HOST-COMPOSITION token `chrome`.
|
|
20
19
|
*
|
|
21
|
-
* A `reader` need not be a `_shared` boot file: `stepping`
|
|
22
|
-
*
|
|
20
|
+
* A `reader` need not be a `_shared` boot file: `stepping`
|
|
21
|
+
* is read by ONE experiment page's own inline sketch, because it is a
|
|
23
22
|
* per-universe PHYSICS option that page ferries into its own `universe.init()`
|
|
24
23
|
* — the registry's job is that the KEY NAME has exactly one owner, wherever the
|
|
25
24
|
* single reader lives (see that entry's own note for the hoist rule when a
|
|
@@ -43,7 +42,7 @@
|
|
|
43
42
|
* read exactly once, at page boot, from the URL. There is deliberately NO
|
|
44
43
|
* `normalize()` here — the tables are frozen static data, not runtime input to
|
|
45
44
|
* validate. The two contracts are ADJACENT (both are consumed by the same
|
|
46
|
-
* experiment pages, and
|
|
45
|
+
* experiment pages, and the controls-panel work touches both) but are
|
|
47
46
|
* NEVER unified into one schema/kind-union.
|
|
48
47
|
*
|
|
49
48
|
* Usage:
|
|
@@ -98,7 +97,7 @@ var PAGE_PARAMS = Object.freeze([
|
|
|
98
97
|
key: KEYS.STEPPING,
|
|
99
98
|
reader: 'lib/frqtl/experiments/single-source-interference/index.html',
|
|
100
99
|
forward: true
|
|
101
|
-
//
|
|
100
|
+
// Circulation §2: `stepping`
|
|
102
101
|
// selects the WAVE-WALK STEPPING SAMPLER for one universe —
|
|
103
102
|
// 'fixed' (deterministic error-accumulator walk, the engine's serde default)
|
|
104
103
|
// vs 'average' (the historic per-axis Bernoulli walk). It is a PER-UNIVERSE
|
|
@@ -155,14 +154,14 @@ var PAGE_PARAMS = Object.freeze([
|
|
|
155
154
|
* rule (read them side by side — this is not "some hosts hide chrome,
|
|
156
155
|
* others don't" as a per-host preference; it is one test with two different
|
|
157
156
|
* answers):
|
|
158
|
-
* - The GYM (`CompareView.jsx
|
|
157
|
+
* - The GYM (`CompareView.jsx`):
|
|
159
158
|
* OMITS `chrome=` entirely (full chrome renders in-iframe). The GYM's own
|
|
160
159
|
* host chrome is deliberately minimal (Run/Pause/camera/rates only) — it
|
|
161
160
|
* does NOT replicate the physics-parametric controls (temperature,
|
|
162
161
|
* wavelength, density sweeps, …) every experiment declares, so hiding the
|
|
163
162
|
* experiment's own chrome would strictly REMOVE capability from the GYM
|
|
164
163
|
* user with no host-side equivalent to fall back on.
|
|
165
|
-
* - Studio (`AuthorView.jsx`,
|
|
164
|
+
* - Studio (`AuthorView.jsx`, "Studio adoption"): SETS
|
|
166
165
|
* `chrome=canvas`. Studio's own chrome already replicates-or-supersets
|
|
167
166
|
* the experiment's control surface for its purposes: a Design/Run/Pause
|
|
168
167
|
* topbar, an Effects palette (backdrop/water toggles), and a fully
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* re-enumerate its keys — it walks every string leaf for placeholder text. With `{ table: false }`
|
|
17
17
|
* a table paragraph is refused outright.
|
|
18
18
|
*
|
|
19
|
-
* What a caption SAYS is
|
|
19
|
+
* What a caption SAYS is an editorial pass, never a gate here: this module checks shape only.
|
|
20
20
|
*
|
|
21
21
|
* @module copy-gate
|
|
22
22
|
*/
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* roster scene the GYM plays, and the showcase copy around them (the intro card, the through-line
|
|
6
6
|
* and the one invitation). It is the ONE owner of every word of that copy.
|
|
7
7
|
*
|
|
8
|
-
* EXHIBITS is the ONE source for the front-page tiles, their GYM deep links and the scene card
|
|
9
|
-
*
|
|
8
|
+
* EXHIBITS is the ONE source for the front-page tiles, their GYM deep links and the scene card:
|
|
9
|
+
* nine rows in front-page order, each
|
|
10
10
|
* `{ kind, id, mode, title, tile, what, why, how, controls, still }`.
|
|
11
11
|
* - `kind` is 'rung' (a walk-through rung, lib/shim/registry/walkthrough.js) or 'experiment'
|
|
12
12
|
* (a canonical experiment page, lib/shim/registry/experiments.js); `id` resolves there.
|
|
@@ -160,8 +160,8 @@ export const SHOWCASE_INTRO = Object.freeze({
|
|
|
160
160
|
assertShowcaseIntro(SHOWCASE_INTRO);
|
|
161
161
|
|
|
162
162
|
// The authored roster, front-page order. `title` and `tile` are the published front-page tile copy
|
|
163
|
-
// (egpt-frqtl
|
|
164
|
-
// `what`, `why`, `how`, `controls` and each `still.alt` are the
|
|
163
|
+
// (the egpt-frqtl front page's #proof tiles: each tile's <b> and its sentence), verbatim;
|
|
164
|
+
// `what`, `why`, `how`, `controls` and each `still.alt` are the authored captions.
|
|
165
165
|
const ROSTER = [
|
|
166
166
|
{
|
|
167
167
|
kind: 'rung', id: "dse-tunnel-rebuild", mode: "3d",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* cat : category label
|
|
12
12
|
* jsOnly : true if the experiment requires JS-engine-only APIs
|
|
13
13
|
*
|
|
14
|
-
* Ordering (G1
|
|
14
|
+
* Ordering (G1):
|
|
15
15
|
* Experiments listed in the exhibit manifest appear FIRST, in manifest order.
|
|
16
16
|
* Remaining experiments follow in their original declaration order.
|
|
17
17
|
* This ordering is consumed by SimPane's dropdown via the existing prop path
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
* the named infra ids: a dev-tier page is absent from the npm/CDN package, but
|
|
42
42
|
* present in the GYM (both the dev IDE and the shipped static deploy).
|
|
43
43
|
*
|
|
44
|
-
* ── The public set is the NEW-SUGAR content ONLY
|
|
44
|
+
* ── The public set is the NEW-SUGAR content ONLY ─────────────────────────────
|
|
45
45
|
* EVERY row below is `tier:'dev'`: none of these pages has been rebuilt on the
|
|
46
46
|
* current sugar objects (SphereEmitter / v2 `Wall` / `Tunnel` / LiveChart /
|
|
47
47
|
* GraphingDetectorWall), so none is public and none ships. The PUBLIC gallery
|
|
@@ -71,7 +71,7 @@ export const EXPERIMENT_TIERS = Object.freeze({
|
|
|
71
71
|
* labs is for. Omit `tier` for a public experiment.
|
|
72
72
|
* wasmOnly: 3D experiment; the JS reference is a frozen 2D fixture, so Compare runs
|
|
73
73
|
* WASM-only (JS-reference pane disabled). See CompareView filter.
|
|
74
|
-
* is3D : the ONE mount-time 3D-render authority (E-W0a
|
|
74
|
+
* is3D : the ONE mount-time 3D-render authority (E-W0a). TRUE iff
|
|
75
75
|
* the experiment page unconditionally boots a 3D display — its runner is
|
|
76
76
|
* `new FrqtlApp({ is3D: true, … })` on the three display — the ground-truth
|
|
77
77
|
* signal, NOT wasmOnly (orthogonal: collision-matrix is wasmOnly+2D). STUDIO
|