@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
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* Tagger — the MARK part: put a user string on a frame, consistently.
|
|
5
5
|
*
|
|
6
|
-
* ── A Tagger IS … (the datasheet line;
|
|
6
|
+
* ── A Tagger IS … (the datasheet line; the minimal sim §3) ───────────────────────
|
|
7
7
|
*
|
|
8
8
|
* A Tagger is the op-program op `{ set: '0.data.<key>', to: StrLit(<value>) }` — ONE
|
|
9
9
|
* write of a user string into a frame's engine-opaque `string_map` — offered on the
|
|
@@ -156,7 +156,7 @@ import * as FrameDataSchema from '../../../shim/frame-data/index.js';
|
|
|
156
156
|
* no collision, no LargeObject and no op-program: read the frame's current data bag,
|
|
157
157
|
* merge the tags into its `string_map`, write the whole bag back.
|
|
158
158
|
*
|
|
159
|
-
* get→merge→set is deliberate (the
|
|
159
|
+
* get→merge→set is deliberate (the render-intent stamp rule): the write
|
|
160
160
|
* must PRESERVE the frame's `detection` section and any pre-existing string_map keys,
|
|
161
161
|
* rather than relying on the engine's `set('data')` happening to merge.
|
|
162
162
|
*
|
|
@@ -44,12 +44,12 @@ import * as FrameDataSchema from '../../../shim/frame-data/index.js';
|
|
|
44
44
|
* Keep them DISTINCT — do NOT merge them. `particle` drives the inspector palette;
|
|
45
45
|
* `Frame` drives the uniform accessor (getFrameProperty/setFrameProperty).
|
|
46
46
|
*
|
|
47
|
-
* Property access rules
|
|
47
|
+
* Property access rules:
|
|
48
48
|
* type:'writable' → user-writable; reaches the engine.
|
|
49
49
|
* type:'readonly' → derived/computed; inspectable, write THROWS.
|
|
50
50
|
* type:'forbidden' → engine-owned topology; any write FAIL-LOUDs (TypeError).
|
|
51
51
|
*
|
|
52
|
-
* FAIL-LOUD discipline (Gate-2
|
|
52
|
+
* FAIL-LOUD discipline (Gate-2 binding):
|
|
53
53
|
* The Frame accessor is THROW-OR-APPLY, never silent-skip.
|
|
54
54
|
* Frames have NO JS-wrapper upstream (engine owns them).
|
|
55
55
|
* Every writable prop reaches the engine or throws.
|
|
@@ -58,7 +58,7 @@ import * as FrameDataSchema from '../../../shim/frame-data/index.js';
|
|
|
58
58
|
* data bubble sub-shape:
|
|
59
59
|
* NOT re-listed here. The canonical authority is lib/shim/frame-data (SECTION_KEYS,
|
|
60
60
|
* normalizeDataBubble). Reference it via FrameDataSchema — never re-enumerate
|
|
61
|
-
* 'detection'/'render'/'ext' keys (schema-mirror trap
|
|
61
|
+
* 'detection'/'render'/'ext' keys (schema-mirror trap).
|
|
62
62
|
*/
|
|
63
63
|
var FrameDescriptor = {
|
|
64
64
|
kind: 'Frame',
|
|
@@ -150,7 +150,7 @@ import * as FrameDataSchema from '../../../shim/frame-data/index.js';
|
|
|
150
150
|
type: 'writable',
|
|
151
151
|
engineVisible: true,
|
|
152
152
|
description: 'Pixel occupancy count. Feeds setWavelength() on the next tick ' +
|
|
153
|
-
'(
|
|
153
|
+
'(FrameStore.set_wavelength). Higher mass → shorter ' +
|
|
154
154
|
'wavelength → higher frequency (E=mc² analog, invariant 6).'
|
|
155
155
|
},
|
|
156
156
|
// ── Writable: charge ───────────────────────────────────────────────
|
|
@@ -178,7 +178,7 @@ import * as FrameDataSchema from '../../../shim/frame-data/index.js';
|
|
|
178
178
|
type: 'writable',
|
|
179
179
|
engineVisible: true,
|
|
180
180
|
description: 'Pins the frame in place: move() is skipped when true. ' +
|
|
181
|
-
'Existing per-frame flag (
|
|
181
|
+
'Existing per-frame flag (FrameStore.is_stationary). ' +
|
|
182
182
|
'Used in bespoke experiments to freeze specific frames while others evolve.'
|
|
183
183
|
},
|
|
184
184
|
{
|
|
@@ -206,7 +206,7 @@ import * as FrameDataSchema from '../../../shim/frame-data/index.js';
|
|
|
206
206
|
type: 'writable',
|
|
207
207
|
constraint: { integer: true },
|
|
208
208
|
engineVisible: true,
|
|
209
|
-
description: 'Per-frame wave-phase counter (integer ticks;
|
|
209
|
+
description: 'Per-frame wave-phase counter (integer ticks; ' +
|
|
210
210
|
'frame.rs local_time). Drives the spin/coin-flip via local_time % wavelength. ' +
|
|
211
211
|
'Incremented each tick; reset to 0 on collision/reset. Op-programs that ' +
|
|
212
212
|
'reproduce the native reset() (e.g. compiled RANDOM_* collision behavior) ' +
|
|
@@ -298,7 +298,7 @@ import * as FrameDataSchema from '../../../shim/frame-data/index.js';
|
|
|
298
298
|
// restore the pre-move position via `set 0.x = Ref(0,'prev_x')`. Promoted to
|
|
299
299
|
// canonical FrameDescriptor fields (PF1) so the one owner is mirrored by both
|
|
300
300
|
// interpreters + conformance — closes the scope-read schema-mirror gap
|
|
301
|
-
// (
|
|
301
|
+
// (ENGINE_LANGUAGE_SPEC §5-F3). Read-only — engine-owned per-tick snapshot.
|
|
302
302
|
{
|
|
303
303
|
name: 'prev_x',
|
|
304
304
|
type: 'readonly',
|
|
@@ -350,12 +350,12 @@ import * as FrameDataSchema from '../../../shim/frame-data/index.js';
|
|
|
350
350
|
/**
|
|
351
351
|
* Universe — property table for the top-level simulation container.
|
|
352
352
|
*
|
|
353
|
-
* Gate-2
|
|
353
|
+
* Gate-2 binding (§10.8 B4):
|
|
354
354
|
* Same home/pattern as FrameDescriptor. Reads = readonly (activeQuanta, tick).
|
|
355
355
|
* Scratch slots = writable (no scratch slots defined in that slice).
|
|
356
356
|
* THROW-OR-APPLY FAIL-LOUD on writes to readonly fields (no silent-skip).
|
|
357
357
|
*
|
|
358
|
-
*
|
|
358
|
+
* Studio Controls Realignment S1 (design §2.3.2 / gap-census #10, 2026-07-05):
|
|
359
359
|
* Added the FIRST writable field, `wavelengthScale` — Wave Interference's
|
|
360
360
|
* primary physics knob was previously unbindable (no writable Universe field
|
|
361
361
|
* existed to validate a bind against; the page wrote `universe.wavelengthScale`
|
|
@@ -415,8 +415,7 @@ import * as FrameDataSchema from '../../../shim/frame-data/index.js';
|
|
|
415
415
|
'Layer 2 — physics behavior: this is Wave Interference\'s and Double-Slit\'s ' +
|
|
416
416
|
'primary knob — raising it stretches every Frame\'s transverse oscillation ' +
|
|
417
417
|
'period, widening fringe/interference spacing without changing any Frame\'s ' +
|
|
418
|
-
'mass or capacity
|
|
419
|
-
'docs/internal/physics-lab/double-slit-wavelength.md for the observed sweep figures).'
|
|
418
|
+
'mass or capacity.'
|
|
420
419
|
}
|
|
421
420
|
]
|
|
422
421
|
};
|
|
@@ -424,7 +423,7 @@ import * as FrameDataSchema from '../../../shim/frame-data/index.js';
|
|
|
424
423
|
/**
|
|
425
424
|
* Dimension — read-only property table for a scale layer in the simulation.
|
|
426
425
|
*
|
|
427
|
-
* Gate-2
|
|
426
|
+
* Gate-2 binding (§10.8 B4):
|
|
428
427
|
* Same home/pattern as FrameDescriptor and UniverseDescriptor.
|
|
429
428
|
* layer = readonly (engine-managed).
|
|
430
429
|
* THROW-OR-APPLY FAIL-LOUD on writes.
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* engineVisible:false → edit is render-layer-only (Phase 4a).
|
|
17
17
|
* 4. The schema set stays 1:1 with the object set and the frozen enum set.
|
|
18
18
|
* Adding a new editable enum value still requires the JS-reference-first
|
|
19
|
-
* → conformance flow (
|
|
19
|
+
* → conformance flow (the engine contract's discipline).
|
|
20
20
|
* 5. Every descriptor has an object-level `description` (what the object does)
|
|
21
21
|
* and every field has a `description` (what the property does / its effect).
|
|
22
22
|
* 6. A composing part stamps `_owner` on what it composed (and nothing else); the declared
|
|
@@ -55,8 +55,8 @@ import { kindOf, registeredKinds, placeableKinds } from '../kinds.js';
|
|
|
55
55
|
// This mirrors the schema-mirror discipline: one owner per key list (§Engineering Culture).
|
|
56
56
|
|
|
57
57
|
// FieldDescriptorSchema (FIELD_TYPES — the shared field-SHAPE vocabulary) is imported
|
|
58
|
-
// BY REFERENCE from lib/shim/field-descriptor —
|
|
59
|
-
//
|
|
58
|
+
// BY REFERENCE from lib/shim/field-descriptor — Studio Controls Realignment §7 r2
|
|
59
|
+
// C1: ONE owner for the field-type vocabulary this file's
|
|
60
60
|
// ~200 field declarations and makeControlsForObject.js's TYPE_DISPATCH both consume.
|
|
61
61
|
// This file's own per-kind field ARRAYS stay UNCHANGED (byte-identical) — only the type
|
|
62
62
|
// vocabulary itself is now shared, asserted below (never a hand-copied comment list).
|
|
@@ -76,7 +76,7 @@ import { kindOf, registeredKinds, placeableKinds } from '../kinds.js';
|
|
|
76
76
|
// type:'rect-array' → array of rect tuples (source_rects for emitters)
|
|
77
77
|
// type:'readonly' → derived/computed: inspectable but not editable
|
|
78
78
|
//
|
|
79
|
-
// Optional per-field key `unit` (
|
|
79
|
+
// Optional per-field key `unit` (Studio Controls Realignment S2, design §2.2):
|
|
80
80
|
// a machine-readable string ('px', 'px/tick', 'ticks', 'px²', …) for fields whose
|
|
81
81
|
// `description` prose already states a unit. NOT populated en masse — only where
|
|
82
82
|
// the description text already says so (mechanical, not invented). Consumed by
|
|
@@ -84,7 +84,7 @@ import { kindOf, registeredKinds, placeableKinds } from '../kinds.js';
|
|
|
84
84
|
// append "(unit)" to a generated control's label. Absence means "no declared unit,"
|
|
85
85
|
// never "unitless" — most number fields simply haven't been swept yet.
|
|
86
86
|
|
|
87
|
-
// ── Shape-vocab ferry (
|
|
87
|
+
// ── Shape-vocab ferry (R2-3) ─────────────────────────────────────────────
|
|
88
88
|
// The shell SHAPE selector (LargeObject.shellShape) ferries the canonical shape
|
|
89
89
|
// value set from its ONE owner, lib/shim/frame-data (RENDER_INTENT_VALUES
|
|
90
90
|
// ['render.shape']) — the SAME set the render-level "Default Shape" uses — never a
|
|
@@ -151,7 +151,7 @@ import { kindOf, registeredKinds, placeableKinds } from '../kinds.js';
|
|
|
151
151
|
},
|
|
152
152
|
/**
|
|
153
153
|
* ux(kind) → the normalized STUDIO UX presentation contract for a kind
|
|
154
|
-
*
|
|
154
|
+
* Runs the descriptor's declared `ux:{}` block (or absence)
|
|
155
155
|
* through lib/shim/field-descriptor's normalizeUx, so a caller ALWAYS gets
|
|
156
156
|
* the full bag { resizable, draggable, handles, shellRender }
|
|
157
157
|
* with legacy defaults filled (R6 — no block ⇒ today's behavior). Consumers
|
|
@@ -146,7 +146,7 @@ export function shapeValuesMap() {
|
|
|
146
146
|
'pre-fix hardcoded behavior — see #61).'
|
|
147
147
|
},
|
|
148
148
|
{
|
|
149
|
-
// ── SWEPT-OBB NARROW-PHASE region (circulation §2
|
|
149
|
+
// ── SWEPT-OBB NARROW-PHASE region (circulation §2) ──────────────────────────
|
|
150
150
|
// The RESOLVED, convention-FREE collision region produced by the ONE
|
|
151
151
|
// SlabFace authority (lib/frqtl/objects/geometry/SlabFace.js) for a NON-
|
|
152
152
|
// cardinal (rotated) wall: { kind:'obb', theta, hw, hh, hz } — theta in
|
|
@@ -163,7 +163,7 @@ export function shapeValuesMap() {
|
|
|
163
163
|
// reserved-but-rejected in v1. Written via updateObjectProperty(handle,
|
|
164
164
|
// 'LargeObject', 'region', regionOrNull) — the SAME live-push path `program`
|
|
165
165
|
// uses (register-time or on a live orientation edit). WASM-only surface
|
|
166
|
-
// (the frozen 2D JS fixture FAILS LOUD on a non-null region
|
|
166
|
+
// (the frozen 2D JS fixture FAILS LOUD on a non-null region).
|
|
167
167
|
name: 'region',
|
|
168
168
|
type: 'object',
|
|
169
169
|
engineVisible: true,
|
|
@@ -183,7 +183,7 @@ export function shapeValuesMap() {
|
|
|
183
183
|
// SUGAR-INPUT (G2/G4b): the engine has NO collision_type dispatch (G2 deleted it).
|
|
184
184
|
// collision_type is a declarative sugar field that actionCompiler.js lowers to an
|
|
185
185
|
// op-program at REGISTRATION. engineVisible:false — the engine never reads it directly.
|
|
186
|
-
//
|
|
186
|
+
// Studio Controls Realignment S4 (design §2.3.5):
|
|
187
187
|
// FrqtlApp.updateObjectProperty routes a runtime edit of THIS field through
|
|
188
188
|
// LargeObject.recompileActions() (re-runs actionCompiler.js + pushes the new
|
|
189
189
|
// op-program), so a live edit DOES retarget the running behavior (e.g. WALL → NONE
|
|
@@ -201,7 +201,7 @@ export function shapeValuesMap() {
|
|
|
201
201
|
// SUGAR-INPUT (G3/G4b): the CollisionAction engine enum + actions field were DELETED
|
|
202
202
|
// (G3). actions is a declarative sugar field that actionCompiler.js lowers to an
|
|
203
203
|
// op-program at REGISTRATION. engineVisible:false — the engine never reads it
|
|
204
|
-
// directly.
|
|
204
|
+
// directly. Studio Controls Realignment S4: a runtime edit of THIS field is ALSO
|
|
205
205
|
// routed through LargeObject.recompileActions() (see the collision_type field's
|
|
206
206
|
// doc, above) — live, not mirror-only.
|
|
207
207
|
engineVisible: false,
|
|
@@ -232,7 +232,7 @@ export function shapeValuesMap() {
|
|
|
232
232
|
constraint: { min: 0, integer: true },
|
|
233
233
|
engineVisible: false,
|
|
234
234
|
description: 'DEPRECATED / IGNORED. The engine no longer reads this; the collision ' +
|
|
235
|
-
'search rect now expands by the dimension\'s mb_w
|
|
235
|
+
'search rect now expands by the dimension\'s mb_w. Retained ' +
|
|
236
236
|
'only as a reserved positional constructor placeholder.'
|
|
237
237
|
},
|
|
238
238
|
{
|
|
@@ -260,12 +260,12 @@ export function shapeValuesMap() {
|
|
|
260
260
|
type: 'enum',
|
|
261
261
|
constraint: { values: { design: 'design', run: 'run', never: 'never' } },
|
|
262
262
|
engineVisible: false,
|
|
263
|
-
//
|
|
264
|
-
// the
|
|
265
|
-
// design — only while authoring (Design mode). The
|
|
263
|
+
// WHEN this object's visual shell paints (render-only, generalizes
|
|
264
|
+
// the `_designMarker` boolean at the ONE _visibleLargeObjects authority):
|
|
265
|
+
// design — only while authoring (Design mode). The manipulable-marker
|
|
266
266
|
// default (a SphereEmitter marker is invisible during Run — you see the
|
|
267
267
|
// emission, not the source).
|
|
268
|
-
// run — ALWAYS visible (the
|
|
268
|
+
// run — ALWAYS visible (the "red light bulb" opt-in: a run-visible shell;
|
|
269
269
|
// pair with visible:true + color:[255,0,0] + a low alpha for the orb).
|
|
270
270
|
// never — never drawn.
|
|
271
271
|
// Absent → the effective default is derived at the filter (a _designMarker LO
|
|
@@ -287,7 +287,7 @@ export function shapeValuesMap() {
|
|
|
287
287
|
name: 'shellShape',
|
|
288
288
|
type: 'enum',
|
|
289
289
|
// Vocab FERRIED from the ONE owner (lib/shim/frame-data render.shape set) —
|
|
290
|
-
// the same set "Default Shape" uses; never a hand-listed enum (
|
|
290
|
+
// the same set "Default Shape" uses; never a hand-listed enum (R2-3).
|
|
291
291
|
constraint: { values: shapeValuesMap() },
|
|
292
292
|
engineVisible: false,
|
|
293
293
|
description: 'Render shape of this object\'s visual shell (render-only): ball|box|circle|' +
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* the 3D scene with no dense lanes at all.
|
|
18
18
|
*
|
|
19
19
|
* The powers-of-two ladder is deliberate: collision probability goes as density², so a
|
|
20
|
-
* LOG scale is what reads cleanly across the transition
|
|
20
|
+
* LOG scale is what reads cleanly across the transition.
|
|
21
21
|
*
|
|
22
22
|
* @module _collisionMatrixLanes
|
|
23
23
|
*/
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* setupBlackbodySubstrate — Blackbody experiment reconstructed under the
|
|
5
|
-
* as-intended control loop
|
|
5
|
+
* as-intended control loop.
|
|
6
6
|
*
|
|
7
7
|
* ## One-line OvenBox difference from `lib/frqtl/scenes/blackbody.js` (config a vs config b)
|
|
8
8
|
*
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
* runs ≈0.0002 … 1.0 DOWN the lanes: SPARSE at the TOP, FULL at the BOTTOM. Bodies are
|
|
25
25
|
* COLORLESS; the ROYGBIV render scheme colours each by its fullness.
|
|
26
26
|
*
|
|
27
|
-
* withInterQuantumCollisions=true runs voxel_collision_pass — the TWO-BUCKET momentum exchange
|
|
28
|
-
*
|
|
27
|
+
* withInterQuantumCollisions=true runs voxel_collision_pass — the TWO-BUCKET momentum exchange:
|
|
28
|
+
* colliding boxes EXCHANGE momentum and
|
|
29
29
|
* CONSERVE it; the per-tick exchange ceiling carries occupancy (ρ_A·ρ_B), so the bounce TIMING
|
|
30
30
|
* emerges from density — rigid (full) lanes bounce fast and clean, soft (sparse) lanes bounce
|
|
31
31
|
* slowly. The sweep reads this spectrum at a glance. Cross-lane coupling is impossible: lanes are
|
|
@@ -49,7 +49,7 @@ import { collisionMatrixLanes as _lanes } from './_collisionMatrixLanes.js';
|
|
|
49
49
|
* DENSITY is swept on a strict LOGARITHMIC (powers-of-2) scale from ρ≈0 (one Dim-0 child →
|
|
50
50
|
* near-total pass-through) to ρ=1 (full box → hard abut) — non-linear probabilistic
|
|
51
51
|
* effects (collision prob ~ density² with density=mass/capacity) read cleanly on a log scale
|
|
52
|
-
*
|
|
52
|
+
* speed_prob=1 on every body so ALL lanes approach at the same 1px/tick,
|
|
53
53
|
* isolating density→collision from the fullness-gate movement-speed effect (that is G1's job).
|
|
54
54
|
* For a 2D Dim-6 box capacity = 64×64 = 4096 = 2^12, so the ladder is 2^0…2^12. The table is
|
|
55
55
|
* `_collisionMatrixLanes.js` — shared with the 3D matrix, whose capacity is 64³ and whose
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/* Copyright 2023-2026 by Essam Abadir */
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* setupConeEmitter3D — the smallest GYM-visible 3D surface for the
|
|
5
|
-
* concentric-ring cone-vs-cylinder construction (canonical-bench S2/S3,
|
|
6
|
-
*
|
|
4
|
+
* setupConeEmitter3D — the smallest GYM-visible 3D surface for the
|
|
5
|
+
* concentric-ring cone-vs-cylinder construction (canonical-bench S2/S3),
|
|
6
|
+
* driven by ONE live SPREAD knob.
|
|
7
7
|
*
|
|
8
8
|
* ── Layer 1: API contract ────────────────────────────────────────────────────
|
|
9
9
|
*
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* (bench S3 law, measured within ~0.3° across 5 vz values).
|
|
25
25
|
* @param {number} [options.vz=1] - Constant forward velocity (px/tick) every
|
|
26
26
|
* ring leaf is stamped with, along the engine's z axis (bench's S2/S3 axis
|
|
27
|
-
* convention —
|
|
27
|
+
* convention — z towards the viewer).
|
|
28
28
|
* @param {number} [options.ringCount=4] - Concentric rings per emission burst,
|
|
29
29
|
* radii evenly spaced from `ringRadius/ringCount` to `ringRadius`.
|
|
30
30
|
* @param {number} [options.ringRadius=40] - Outer ring radius (px).
|
|
@@ -74,13 +74,12 @@
|
|
|
74
74
|
* extent now grows in lockstep with z-travel, and the half-angle converges to
|
|
75
75
|
* `atan(spread/vz)` — a genuine diverging CONE (flashlight). No engine change
|
|
76
76
|
* is implicated anywhere in this file — it is purely which velocity a
|
|
77
|
-
* scene-builder hands each leaf
|
|
78
|
-
* `.claude/agent-memory/frqtl-experiment-coder/reference_concentric_ring_cone_vs_cylinder_law.md`).
|
|
77
|
+
* scene-builder hands each leaf.
|
|
79
78
|
*
|
|
80
79
|
* Sustained emission is a HOST TICK-FN pushed to
|
|
81
80
|
* `universe.experimentTickFunctions` — the SAME framework hook
|
|
82
81
|
* Blackbody's thermostat already uses
|
|
83
|
-
* (
|
|
82
|
+
* (guardrail R1: no new engine hook, no native emit-spec). Because
|
|
84
83
|
* each successive ring burst is younger (has traveled less z), a running scene
|
|
85
84
|
* shows a series of receding ring-shells at increasing z-depth — a solid-
|
|
86
85
|
* looking collimated tube (spread=0) or an opening flashlight cone (spread>0).
|
|
@@ -163,7 +162,7 @@ import { assertSetupOptions as _assertSetupOptions, requireWorldRect as _require
|
|
|
163
162
|
// move_frame classifies the propagation axis by a BIT-EXACT vx!=0.0 /
|
|
164
163
|
// vy!=0.0 test, so those degenerate leaves get NO transverse wave on the
|
|
165
164
|
// (bit-)zero axis and stay plane-confined, projecting as sharp bright
|
|
166
|
-
// axis-aligned LINES
|
|
165
|
+
// axis-aligned LINES. The +0.5 offset gives
|
|
167
166
|
// every leaf a meaningfully-nonzero (vx,vy) pair so it fans into the cone
|
|
168
167
|
// VOLUME instead of a plane. |v_radial|=spread is unchanged by a pure
|
|
169
168
|
// angular rotation, so the S3 half-angle law atan(spread/vz) is preserved.
|
|
@@ -65,8 +65,7 @@ import { CollisionTypes } from '../../parts/CollisionTypes.js';
|
|
|
65
65
|
* | **64** (default) | **4** | ~3601 | **0.98** | full canvas, clear interference bands |
|
|
66
66
|
* | 128 | 8 | ~6029 | — | geometry exceeds canvas; detector not reached at tick 400 |
|
|
67
67
|
*
|
|
68
|
-
|
|
69
|
-
*
|
|
68
|
+
|
|
70
69
|
* **Disambiguate from wave-interference `wavelengthScale`:** the DSE
|
|
71
70
|
* `wavelength` scales PHYSICAL GEOMETRY (moves walls). The wave-interference
|
|
72
71
|
* `wavelengthScale` in `setupWaveInterference` only scales the per-Frame
|
|
@@ -97,23 +96,23 @@ import { CollisionTypes } from '../../parts/CollisionTypes.js';
|
|
|
97
96
|
* @param {number} [options.angleIncrement=10] - Degrees between emission angles
|
|
98
97
|
* from the light source. Smaller = more rays = smoother illumination cone;
|
|
99
98
|
* larger = coarser, more visible discrete rays.
|
|
100
|
-
* @param {number} [options.depth] -
|
|
99
|
+
* @param {number} [options.depth] - total z-extent for a 3D run.
|
|
101
100
|
* OMITTED (default) → today's 2D behavior, byte-identical — no `activeAxes`
|
|
102
101
|
* key touched, every wall/screen/detector rect stays the legacy 4-element form,
|
|
103
102
|
* the light source's inner PointSource gets no z-draw at all. When provided:
|
|
104
103
|
* `universe.init()` gains `activeAxes:{x:true,y:true,z:true}` (mirrors
|
|
105
|
-
* `setupWaveInterference`'s `options.depth
|
|
106
|
-
* becomes a FLOOR-TO-CEILING 3D wall (
|
|
104
|
+
* `setupWaveInterference`'s `options.depth`); `SlitScreen`
|
|
105
|
+
* becomes a FLOOR-TO-CEILING 3D wall (the geometry amendment):
|
|
107
106
|
* `wall1`/`wall2`/`wall3` span the full z-depth `[-depth/2,+depth/2]`, and
|
|
108
107
|
* each slit becomes a CUBIC HOLE (bounded in BOTH y and z, see
|
|
109
108
|
* `options.holeDepth`) tiled from a solid near/far z-side pair around the
|
|
110
|
-
* aperture — NOT a full-depth-in-z slot (supersedes the earlier
|
|
109
|
+
* aperture — NOT a full-depth-in-z slot (supersedes the earlier
|
|
111
110
|
* construction). The start-wall and detector wall get the SAME full-z-depth
|
|
112
111
|
* treatment (else z-spread quanta fly around/past them); `SlitLightSource`
|
|
113
112
|
* threads `zMin=-depth/2, zDepth=depth` into its inner PointSource — the
|
|
114
|
-
* IDENTICAL shared z-spread mechanism
|
|
113
|
+
* IDENTICAL shared z-spread mechanism built for
|
|
115
114
|
* `setupWaveInterference` (`emitterProgram.js`'s opt-in `em.zMin`/`em.zDepth`),
|
|
116
|
-
* reused not forked. PHYSICS EXPECTATION (restated
|
|
115
|
+
* reused not forked. PHYSICS EXPECTATION (restated): the
|
|
117
116
|
* detector pattern is genuinely 2D — y-interference fringes × a z
|
|
118
117
|
* aperture-diffraction envelope (concentrated near the hole's z-band, NOT
|
|
119
118
|
* uniform across all z-bands — the old "every z-band identical" self-check
|
|
@@ -123,10 +122,10 @@ import { CollisionTypes } from '../../parts/CollisionTypes.js';
|
|
|
123
122
|
* at the default wavelength — see `SlitScreen`'s docstring for the exact
|
|
124
123
|
* value). Ignored when `options.depth` is omitted.
|
|
125
124
|
* @param {'current'|'noreset'|'symmetric'|'combined'|'bounce'|'ejectY'|'ejectYReflect'} [options.slitScatter='current']
|
|
126
|
-
* EXPERIMENT LOOP
|
|
125
|
+
* EXPERIMENT LOOP: selects the slit
|
|
127
126
|
* liner's edge-diffraction scatter behavior. `'current'` (default, OMIT to
|
|
128
127
|
* keep it) is today's exact compiled `RANDOM_XY` — byte-identical, the
|
|
129
|
-
*
|
|
128
|
+
* ratified 2D golden (seed42/wl64/detect1/t400 -> 103/63/40) depends on
|
|
130
129
|
* it. See `SlitScreen`'s `_buildLinerVelocityOps` docstring for
|
|
131
130
|
* `noreset`/`symmetric`/`combined`/`bounce`, and `_buildEjectYOps`'s
|
|
132
131
|
* docstring for `ejectY`/`ejectYReflect` (MATRIX EXTENSION, 2026-07-12 — the
|
|
@@ -179,14 +178,14 @@ import { CollisionTypes } from '../../parts/CollisionTypes.js';
|
|
|
179
178
|
// non-positive dimension — a zero-high screen would count nothing, silently).
|
|
180
179
|
var canvasH = _requireWorldRect('setupDoubleSlit universe.universe_rect', canvasRect).h;
|
|
181
180
|
var angleIncrement = options.angleIncrement !== undefined ? options.angleIncrement : 10;
|
|
182
|
-
//
|
|
181
|
+
// Opt-in 3D depth. undefined/null → 2D, byte-identical.
|
|
183
182
|
var depth = (options.depth !== undefined && options.depth !== null) ? options.depth : null;
|
|
184
|
-
//
|
|
183
|
+
// The geometry amendment: cubic-hole z-extent. undefined -> SlitScreen
|
|
185
184
|
// applies its own default (the effective slit_height). 2D-inert.
|
|
186
185
|
var holeDepth = (options.holeDepth !== undefined && options.holeDepth !== null) ? options.holeDepth : undefined;
|
|
187
186
|
// EXPERIMENT LOOP (2026-07-12): liner edge-diffraction scatter variant.
|
|
188
187
|
// 'current' (default/omitted) -> today's exact RANDOM_XY, byte-identical —
|
|
189
|
-
// the
|
|
188
|
+
// the ratified 2D golden depends on this. Works identically in 2D and 3D.
|
|
190
189
|
var slitScatter = options.slitScatter !== undefined ? options.slitScatter : 'current';
|
|
191
190
|
// DSE LAB (2026-07-13): inter-slit gap override ("slit gap" / "slit-tunnel
|
|
192
191
|
// width" — the interference formula's `d`). undefined (default) -> SlitScreen's
|
|
@@ -227,13 +226,13 @@ import { CollisionTypes } from '../../parts/CollisionTypes.js';
|
|
|
227
226
|
detectAtSlits,
|
|
228
227
|
undefined, // slitHeight override (none)
|
|
229
228
|
gapHeight, // DSE LAB: inter-slit gap override (undefined -> SlitScreen default)
|
|
230
|
-
depth, //
|
|
231
|
-
holeDepth, //
|
|
229
|
+
depth, // null (default) -> legacy 4-elem rects
|
|
230
|
+
holeDepth, // the geometry amendment: cubic-hole z-extent (2D-inert)
|
|
232
231
|
slitScatter // EXPERIMENT LOOP: 'current' (default) -> byte-identical liner behavior
|
|
233
232
|
);
|
|
234
233
|
|
|
235
234
|
// ── Start Wall (absorb wall at left edge) ───────────────────────
|
|
236
|
-
//
|
|
235
|
+
// Full-z-depth 6-elem rect when depth is set (Tube.js
|
|
237
236
|
// precedent) — without it, z-spread quanta fly around a paper-thin (z=0,d=w)
|
|
238
237
|
// start wall. depth===null (default) -> legacy 4-elem rect, byte-identical.
|
|
239
238
|
var startWallRect = (depth !== null)
|
|
@@ -252,7 +251,7 @@ import { CollisionTypes } from '../../parts/CollisionTypes.js';
|
|
|
252
251
|
1,
|
|
253
252
|
[120, 120, 120]
|
|
254
253
|
);
|
|
255
|
-
//
|
|
254
|
+
// Render: the Tube.js precedent — a 6-element
|
|
256
255
|
// rect gives the ENGINE a real z-slab, but _buildLoMesh (three-provider.js)
|
|
257
256
|
// only builds a 3D BoxGeometry when the LO ALSO carries the render-only
|
|
258
257
|
// `shape='box'` + `depth` hint (see SlitScreen.js for the identical fix).
|
|
@@ -268,7 +267,7 @@ import { CollisionTypes } from '../../parts/CollisionTypes.js';
|
|
|
268
267
|
angleIncrement,
|
|
269
268
|
undefined, // quantum_limit (default)
|
|
270
269
|
undefined, // delay (default)
|
|
271
|
-
{ depth: depth } //
|
|
270
|
+
{ depth: depth } // null (default) -> no z-draw at all
|
|
272
271
|
);
|
|
273
272
|
|
|
274
273
|
// ── Detector Wall ────────────────────────────────────────────────
|
|
@@ -278,7 +277,7 @@ import { CollisionTypes } from '../../parts/CollisionTypes.js';
|
|
|
278
277
|
canvasRect,
|
|
279
278
|
detectorWallX,
|
|
280
279
|
undefined, undefined, undefined, undefined, undefined, undefined,
|
|
281
|
-
{ depth: depth } //
|
|
280
|
+
{ depth: depth } // null (default) -> legacy 4-elem rect
|
|
282
281
|
);
|
|
283
282
|
|
|
284
283
|
// ── Tick function ────────────────────────────────────────────────
|
|
@@ -298,8 +297,8 @@ import { CollisionTypes } from '../../parts/CollisionTypes.js';
|
|
|
298
297
|
largeObjects.push(startWall);
|
|
299
298
|
largeObjects.push(detectorWall.detector_wall);
|
|
300
299
|
|
|
301
|
-
//
|
|
302
|
-
// a 2D interferenceParams object has the EXACT SAME key set as
|
|
300
|
+
// §2.1: depth key present ONLY on a 3D run —
|
|
301
|
+
// a 2D interferenceParams object has the EXACT SAME key set as a 2D-only build.
|
|
303
302
|
var interferenceParams = {
|
|
304
303
|
d: d_distance_between_slits,
|
|
305
304
|
L: L_distance_slits_to_screen,
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
* rect.w drives the renderer's `aSize` attribute (three-provider.js) → larger,
|
|
67
67
|
* softer puff sprites. Faster bullet = denser wake = bigger emergent frames.
|
|
68
68
|
*
|
|
69
|
-
* OBSERVED effect (design intent —
|
|
69
|
+
* OBSERVED effect (design intent — verified in the realm):
|
|
70
70
|
* fx-smoke: at tick ~200 puffs range from 1 px (single leaf) to 8–16 px
|
|
71
71
|
* (aggregated compound frames). The bullet wake region shows higher density
|
|
72
72
|
* and larger puff sizes than the undisturbed beam. Adjusting the `puff` slider
|
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* setupLightSourceLab — LightSource ISOLATION (I2, directed-tunnel composition model
|
|
5
5
|
* §3 row 2): ONE `LightSource`, gun-chamber mechanics (fill / escape / dispersion) at a
|
|
6
|
-
* live-tunable scale — the visual half of the I2 source-invariance measurement
|
|
7
|
-
* (`docs/internal/physics-lab/directed-tunnel-scale-sweep/source-invariance.cjs`), same object,
|
|
6
|
+
* live-tunable scale — the visual half of the I2 source-invariance measurement, same object,
|
|
8
7
|
* same DSE-scale defaults.
|
|
9
8
|
*
|
|
10
9
|
* ── Layer 1: API contract ────────────────────────────────────────────────────
|
|
@@ -18,7 +17,7 @@
|
|
|
18
17
|
* @param {number} [opts.length=16] - Tunnel length (`LightSource`'s own DSE-scale
|
|
19
18
|
* default). REINIT-CLASS.
|
|
20
19
|
* @param {'particleWalk'|'emitter'} [opts.source='particleWalk'] - `LightSource`'s
|
|
21
|
-
* own I2 default (the
|
|
20
|
+
* own I2 default (the PRIMARY reference source). REINIT-CLASS (the two
|
|
22
21
|
* source mechanisms are fundamentally different constructions — see
|
|
23
22
|
* `LightSource.js`'s own docstring).
|
|
24
23
|
* @param {'random'|'positive'|'negative'} [opts.polarization='random'] - passed
|
|
@@ -26,9 +25,9 @@
|
|
|
26
25
|
* @param {number} [opts.particleCount=20] - The INITIAL one-shot burst size
|
|
27
26
|
* hand-placed at construction (unchanged meaning/default — `LightSource`'s
|
|
28
27
|
* own construction-time placement, T2/I2 semantics untouched).
|
|
29
|
-
* @param {number} [opts.sourceDensity] -
|
|
30
|
-
*
|
|
31
|
-
*
|
|
28
|
+
* @param {number} [opts.sourceDensity] - the SUSTAIN fix (without it the
|
|
29
|
+
* LightSource Lab decays to 0 by tick ~2000: particleWalk is a one-shot
|
|
30
|
+
* snapshot that never replenishes).
|
|
32
31
|
* Quanta per RECURRING emission event, for BOTH source modes — mirrors
|
|
33
32
|
* `setupTunnelLab.js`'s own `sourceDensity` exactly ("same treatment,
|
|
34
33
|
* layered"). Defaults to `particleCount` (the recurring bursts match the
|
|
@@ -64,7 +63,7 @@
|
|
|
64
63
|
* updateBehavior(newBehavior)` — the same stock `DirectedTunnel` accessor
|
|
65
64
|
* `tunnel-lab` uses; REPLICA DISCIPLINE means nothing LightSource-specific is
|
|
66
65
|
* needed here).
|
|
67
|
-
* @param {number} [opts.depth] -
|
|
66
|
+
* @param {number} [opts.depth] - 3D toggle. OMITTED
|
|
68
67
|
* (default) -> 2D (byte-identical to every pre-existing caller). A positive
|
|
69
68
|
* value -> real z-containment (`activeAxes:{x,y,z}` on `universe.init()`,
|
|
70
69
|
* `LightSource.tunnel`'s own `depth`/`z=-depth/2` — `LightSource.js` ALREADY
|
|
@@ -102,7 +101,7 @@ import * as SustainedSource from '../objects/sustainedSource.js';
|
|
|
102
101
|
|
|
103
102
|
var FUNDAMENTAL_DIMENSION = 2; // matches setupTunnelLab.js / setupDoubleSlit.js / LightSource.js's own construction path
|
|
104
103
|
|
|
105
|
-
//
|
|
104
|
+
// MATCHED CONTROLS -> MATCHED PHYSICS: the
|
|
106
105
|
// SAME MAX_USEFUL_WAVELENGTH clamp authority setupTunnelLab.js derives its
|
|
107
106
|
// own ceiling from (SustainedSource.capacityAtDimension) — at identical
|
|
108
107
|
// FUNDAMENTAL_DIMENSION=2, this is byte-identical to setupTunnelLab.
|
|
@@ -136,23 +135,22 @@ import * as SustainedSource from '../objects/sustainedSource.js';
|
|
|
136
135
|
var particleCount = opts.particleCount !== undefined ? opts.particleCount : 20;
|
|
137
136
|
var wallBehavior = opts.wallBehavior !== undefined ? opts.wallBehavior : 'option2';
|
|
138
137
|
var depth = (opts.depth !== undefined && opts.depth !== null) ? opts.depth : null;
|
|
139
|
-
//
|
|
140
|
-
//
|
|
141
|
-
//
|
|
138
|
+
// lightsource-lab has the SAME wavelength control tunnel-lab has, same
|
|
139
|
+
// default 8, same MAX_USEFUL_WAVELENGTH clamp authority: threaded into the
|
|
140
|
+
// INITIAL one-shot burst
|
|
142
141
|
// (`lsOpts.particle.wavelength`, `source:'particleWalk'`, matching
|
|
143
142
|
// `LightSource.js`'s own `options.particle.wavelength` field) AND into
|
|
144
143
|
// the recurring sustain spec below — this is THE field whose omission
|
|
145
|
-
// on this factory's OLD injector produced
|
|
146
|
-
// colors"
|
|
144
|
+
// on this factory's OLD injector produced "different particle
|
|
145
|
+
// colors" (tunnel-lab's mass=2/fullness=0.125/red vs this page's
|
|
147
146
|
// mass=16/fullness=1.0/violet at otherwise-identical settings).
|
|
148
|
-
//
|
|
149
|
-
//
|
|
150
|
-
// 'emitter'` now ALSO stamps `wavelength` (via `lsOpts.emitterSpec.
|
|
147
|
+
// lightsource-lab's λ slider governs emitter mode too — `source:
|
|
148
|
+
// 'emitter'` ALSO stamps `wavelength` (via `lsOpts.emitterSpec.
|
|
151
149
|
// wavelength` below, QuantumEmitter's new `opts.wavelength`), and is LIVE
|
|
152
150
|
// via the `sourceState.wavelength` accessor built further down.
|
|
153
151
|
var wavelength = opts.wavelength !== undefined ? opts.wavelength : 8;
|
|
154
152
|
|
|
155
|
-
//
|
|
153
|
+
// SUSTAIN fix:
|
|
156
154
|
// recurring emission params, ONE authority for BOTH source modes —
|
|
157
155
|
// mirrors setupTunnelLab.js's own sourceDensity/sourceRate/sourceActive
|
|
158
156
|
// exactly ("same treatment, layered"). Defaults to particleCount so the
|
|
@@ -183,8 +181,8 @@ import * as SustainedSource from '../objects/sustainedSource.js';
|
|
|
183
181
|
if (source === 'particleWalk') {
|
|
184
182
|
lsOpts.particleCount = particleCount;
|
|
185
183
|
lsOpts.particle = { wavelength: wavelength };
|
|
186
|
-
//
|
|
187
|
-
//
|
|
184
|
+
// LightSource itself has the sustain capability through the SAME
|
|
185
|
+
// single authority: delegates
|
|
188
186
|
// the recurring re-placement to `LightSource`'s own opt-in
|
|
189
187
|
// `options.sustain` (-> `sustainedSource.js`'s ONE authority) —
|
|
190
188
|
// REPLACES this factory's own previously hand-rolled injector
|
|
@@ -208,8 +206,7 @@ import * as SustainedSource from '../objects/sustainedSource.js';
|
|
|
208
206
|
quantumLimit: Infinity,
|
|
209
207
|
randomDirection: false,
|
|
210
208
|
delay: Math.max(0, sourceRate - 1),
|
|
211
|
-
//
|
|
212
|
-
// slider must govern emitter mode too"): threads through
|
|
209
|
+
// lightsource-lab's λ slider governs emitter mode too: threads through
|
|
213
210
|
// LightSource.js's generic `options.emitterSpec` passthrough ->
|
|
214
211
|
// DirectedTunnel's generic `options.emitter` copy -> Tube.js's new
|
|
215
212
|
// `espec.wavelength` read -> QuantumEmitter's new `opts.wavelength`.
|
|
@@ -226,13 +223,13 @@ import * as SustainedSource from '../objects/sustainedSource.js';
|
|
|
226
223
|
// .js` returns — a UI slider mutating `sourceState.wavelength`/`density`
|
|
227
224
|
// /`rate`/`active` takes effect on the NEXT recurring burst, no
|
|
228
225
|
// reinit). For 'emitter', a plain info object PLUS a `wavelength`
|
|
229
|
-
// ACCESSOR
|
|
226
|
+
// ACCESSOR that delegates to `QuantumEmitter.prototype.
|
|
230
227
|
// setWavelength` — so the page's wavelength slider
|
|
231
228
|
// (`runner.setupResult.sourceState.wavelength = v`, the SAME bare-
|
|
232
229
|
// assignment idiom used for BOTH modes) works identically whether the
|
|
233
230
|
// live source is a sustainedSource or this emitter, with zero page-level
|
|
234
231
|
// branching on source mode. burstSize/delay stay NOT live-wired
|
|
235
|
-
// (unchanged
|
|
232
|
+
// (unchanged).
|
|
236
233
|
var sourceState;
|
|
237
234
|
if (source === 'particleWalk' && lightSource.sustainedSource) {
|
|
238
235
|
sourceState = lightSource.sustainedSource.sourceState;
|
|
@@ -255,9 +252,9 @@ import * as SustainedSource from '../objects/sustainedSource.js';
|
|
|
255
252
|
// FrqtlApp.setup() (FrqtlApp.js:528) auto-wires
|
|
256
253
|
// the render list; today the world's own census carries them by construction.
|
|
257
254
|
largeObjects: lightSource.largeObjects,
|
|
258
|
-
// CANONICAL TEARDOWN (
|
|
255
|
+
// CANONICAL TEARDOWN (the reinit-
|
|
259
256
|
// compounding fix): delegates to `LightSource.prototype.dispose`
|
|
260
|
-
//
|
|
257
|
+
// — that ONE method already tears down BOTH
|
|
261
258
|
// `this.sustainedSource` (particleWalk+sustain) and `this.emitter`
|
|
262
259
|
// (emitter mode's own QuantumEmitter.dispose) — no bespoke
|
|
263
260
|
// teardownFns array needed here anymore.
|
|
@@ -266,7 +263,7 @@ import * as SustainedSource from '../objects/sustainedSource.js';
|
|
|
266
263
|
}
|
|
267
264
|
|
|
268
265
|
// ONE authority for the achievable wavelength ceiling at this factory's
|
|
269
|
-
// FUNDAMENTAL_DIMENSION —
|
|
266
|
+
// FUNDAMENTAL_DIMENSION — byte-identical formula/value to
|
|
270
267
|
// `setupTunnelLab.MAX_USEFUL_WAVELENGTH` (both derive from
|
|
271
268
|
// `SustainedSource.capacityAtDimension`), so `lightsource-lab/index.html`
|
|
272
269
|
// reads THIS instead of hand-typing "16" — matched controls on both pages.
|