@descix/frqtl-node 0.6.1-p3.4 → 0.7.0-p0

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 (64) hide show
  1. package/CLAUDE.md +3 -3
  2. package/README.md +4 -3
  3. package/dist/dist-manifest.json +26 -56
  4. package/dist/frqtl/experiments/_shared/empty-sketch.js +17 -0
  5. package/dist/frqtl/objects/setup/setupBlackbodySubstrate.js +6 -6
  6. package/dist/frqtl/objects/setup/setupFxSmoke.js +2 -2
  7. package/dist/frqtl/objects/setup/setupG3Collide.js +1 -1
  8. package/dist/frqtl/objects/setup/setupSphereEmitter3D.js +2 -2
  9. package/dist/frqtl/objects/v1-replacements.js +1 -1
  10. package/dist/frqtl/parts/OvenBox.js +2 -2
  11. package/dist/frqtl/parts/SphereEmitter.js +1 -1
  12. package/dist/shim/engine/router.js +18 -6
  13. package/dist/shim/engine/site-assemble.mjs +268 -0
  14. package/dist/shim/engine/site-graph.js +42 -14
  15. package/dist/shim/host/device.js +1 -1
  16. package/dist/shim/index.js +3 -7
  17. package/dist/shim/notebook/catalog.js +2 -2
  18. package/dist/shim/notebook/format.js +1 -1
  19. package/dist/shim/notebook/knob.js +1 -1
  20. package/dist/shim/notebook/notebook-knobs.js +1 -1
  21. package/dist/shim/project/specifiers.js +8 -8
  22. package/dist/shim/registry/copy-gate.js +3 -3
  23. package/dist/shim/registry/index.js +9 -12
  24. package/dist/shim/registry/roster-link.js +142 -0
  25. package/dist/shim/registry/roster.js +595 -0
  26. package/dist/shim/registry/scene-source.js +80 -105
  27. package/dist/shim/registry/studio-landing.js +15 -7
  28. package/dist/shim/render/sun-look.js +1 -2
  29. package/llms.txt +4 -2
  30. package/package.json +1 -1
  31. package/dist/frqtl/scenes/absorbing-wall-3d.js +0 -37
  32. package/dist/frqtl/scenes/absorbing-wall.js +0 -36
  33. package/dist/frqtl/scenes/atomic-model.js +0 -91
  34. package/dist/frqtl/scenes/big-bang.js +0 -49
  35. package/dist/frqtl/scenes/blackbody.js +0 -84
  36. package/dist/frqtl/scenes/circuit-sat.js +0 -131
  37. package/dist/frqtl/scenes/collision-matrix-3d.js +0 -110
  38. package/dist/frqtl/scenes/counting-wall-3d.js +0 -40
  39. package/dist/frqtl/scenes/counting-wall.js +0 -42
  40. package/dist/frqtl/scenes/double-slit.js +0 -34
  41. package/dist/frqtl/scenes/dse-one-emitter.js +0 -200
  42. package/dist/frqtl/scenes/dse-one-slit.js +0 -118
  43. package/dist/frqtl/scenes/dse-photoelectric.js +0 -74
  44. package/dist/frqtl/scenes/dse-tunnel-rebuild.js +0 -279
  45. package/dist/frqtl/scenes/dse-two-emitters.js +0 -201
  46. package/dist/frqtl/scenes/dse-two-slits.js +0 -136
  47. package/dist/frqtl/scenes/empty.js +0 -17
  48. package/dist/frqtl/scenes/laser-buildup.js +0 -56
  49. package/dist/frqtl/scenes/mirror-3d.js +0 -60
  50. package/dist/frqtl/scenes/mirror-route.js +0 -164
  51. package/dist/frqtl/scenes/mirror.js +0 -42
  52. package/dist/frqtl/scenes/omni-3d.js +0 -30
  53. package/dist/frqtl/scenes/omni-source.js +0 -25
  54. package/dist/frqtl/scenes/self-interference.js +0 -42
  55. package/dist/frqtl/scenes/smoking-gun.js +0 -126
  56. package/dist/frqtl/scenes/straight-walk.js +0 -25
  57. package/dist/frqtl/scenes/sun.js +0 -42
  58. package/dist/frqtl/scenes/two-source.js +0 -42
  59. package/dist/frqtl/scenes/wave.js +0 -29
  60. package/dist/shim/engine/artifact-shell.js +0 -211
  61. package/dist/shim/registry/exhibits.js +0 -436
  62. package/dist/shim/registry/scene-roster.js +0 -35
  63. package/dist/shim/registry/showcase-link.js +0 -61
  64. package/dist/shim/registry/walkthrough.js +0 -752
@@ -1,164 +0,0 @@
1
- /* Copyright 2023-2026 by Essam Abadir */
2
-
3
- /**
4
- * SCENE — 1D · Mirror Loop (10-mirror {10/3} star)
5
- *
6
- * A sketch file: the WHOLE scene as one ES module, `export default function buildExperiment(exp)`. The world
7
- * (its co-init call, `exp.createCanvas` / `exp.createScene` — the one place its size is written),
8
- * the parts (`export const parts` + `exp.declare`, or `exp.addObject`) and the render intent are all here; the sugar
9
- * objects, renderer and engine are imports. Registered by lib/shim/registry/walkthrough.js
10
- * (rung cl1d-mirror-route).
11
- */
12
-
13
- // A CLOSED {10/3} STAR BILLIARD: a 2-particle-wide laser loops
14
- // m1→m2→…→m10→m1 FOREVER. Ten mirrors at the vertices of a regular decagon; each tilt solved
15
- // from its in/out chords so the reflected centre-line hits the next mirror, and the star's
16
- // symmetry closes the tenth leg back into the first. Each mirror tags the beam with its own
17
- // colour (recolor hook) → the beam re-colours every bounce. No detector: the loop has no exit.
18
- // The emitter's DECLARED emission gate (emissionCap/gateCounter — the blackbody pattern as
19
- // captured descriptor DATA) keeps the population bounded so FPS stays healthy, Restart-safe.
20
- //
21
- // ONE MODE-AWARE SOURCE. The mode strip selects the RENDERER the host boots
22
- // (renderState.renderer), and this scene reads it ONCE, inside buildExperiment: `three` ⇒
23
- // exp.createScene (a 600x400x600 world), else exp.createCanvas (600x400). The ring geometry,
24
- // tilts, colours, laser and gate are the SAME in both modes (2D≡3D). `parts` is written in the
25
- // 3D default mode, and flat2D (below) derives the 2D block from it — the scene's own statement of
26
- // two of its deltas:
27
- // (a) every mirror is a 3D SLAB — a z-slab centred on the beam plane z=0, rendered as a plate;
28
- // (b) the laser is VOLUMETRIC (is2D:false — it braids in y AND z; the slab depth catches the
29
- // z-braid; its tilted xy faces reflect by the 2θ law, its near/far z-faces bounce vz).
30
- // `IS3D` guards the rest, in code after exp.declare:
31
- // (c) two invisible destroy z-collimators flush with the slab z-band;
32
- // (d) the population counter carries a z-slab covering the WHOLE universe z-band (the emitter's
33
- // gateCounter names it, so it stays a code declaration);
34
- // (e) MOVE/LOOK camera joysticks (the OMNI_3D pattern).
35
- // The 3D mode's render intent — the particles hidden so the light field alone shows, strong
36
- // 'field' god-rays computed from the light particles only (godraySource 'leaf'), a soft glow, and
37
- // a face-on camera close enough that the ring spans the canvas height — rides the registry mode's
38
- // renderState (lib/shim/registry/walkthrough.js), its one home.
39
-
40
- import { CameraControls, SphereEmitter, Wall } from '@descix/frqtl-web/parts';
41
- import * as FrqtlDisplay from '@descix/frqtl-web/compat/renderer/display-slot.js';
42
-
43
- const W = 600, H = 400, WORLD_D = 600; // THE WORLD this scene states (its co-init call below)
44
- const f = Math.min(W, H) / 600;
45
- // R 225·f: adjacent decagon vertices sit 2R·sin18° ≈ 0.618R apart vs slab
46
- // height ~110·f, so the mirrors separate with clear gaps. Fit: R + rotated-slab half-diagonal
47
- // (≈55·f) stays inside min(W,H)/2 with margin.
48
- const CX = Math.round(W / 2), CY = Math.round(H / 2), R = Math.round(225 * f), HOP = 3, ROT = 12;
49
- // CAP 6400 / burst 8 (brightness retune): a VERY BRIGHT braid. The cap is
50
- // LIVE-controllable off the population counter (select 'population' in Layers → Inspector
51
- // 'Population Gate').
52
- const SW = Math.max(10, Math.round(14 * f)), SH = Math.max(70, Math.round(110 * f)), CAP = 6400;
53
- // SD — the 3D slab z-depth: a 2:1 tile (twice the slab height, z-centred on the beam plane).
54
- // The scene z-collimator clamps ALL quanta to this band, so every mirror provably faces every
55
- // alive quantum.
56
- const SD = 2 * SH;
57
- // Each mirror a DIFFERENT colour = its identity (a red→magenta rainbow); the recolor hook
58
- // stamps that colour onto every particle it reflects (string_map['render.color']).
59
- const PAL = [[255,60,60],[255,140,0],[255,220,0],[150,230,40],[40,210,90],[0,210,190],[0,170,255],[70,90,255],[150,70,235],[235,50,190]];
60
- // Hit-order vertices of the {10/3} star (m1..m10 named IN the order the beam visits them).
61
- const order = []; for (var k = 0; k < 10; k++) { order.push((k * HOP) % 10); }
62
- const D2R = Math.PI / 180;
63
- const vpos = function (v) { var a = (v * 36 + ROT) * D2R; return [CX + R * Math.cos(a), CY + R * Math.sin(a)]; };
64
- const pos = order.map(vpos);
65
- const deg = function (a) { return ((a * 180 / Math.PI) % 360 + 360) % 360; };
66
- const angOf = function (p, q) { return deg(Math.atan2(q[1] - p[1], q[0] - p[0])); };
67
- // Where each mirror belongs: m1..m10 by name, at its star vertex (the centre of the slot in the ring). m4 and m6
68
- // are declared off theirs below; STUDIO's "try it" reads this to know when a dragged mirror is home.
69
- export const starPoints = Object.freeze(Object.fromEntries(pos.map(function (p, i) { return ['m' + (i + 1), Object.freeze(p.slice())]; })));
70
- // Per-mirror IN-PLANE orientation from the in/out chords: ori = (in+out−180)/2, branch chosen
71
- // so the engine reflect law out = 180 + 2·ori − in reproduces the outgoing chord exactly.
72
- // Orientation is z-axis rotation, so the 3D slab depth adds NO new angle.
73
- const ORI = [];
74
- for (var j = 0; j < 10; j++) {
75
- var pr = pos[(j + 9) % 10], cu = pos[j], nx = pos[(j + 1) % 10];
76
- var inA = angOf(pr, cu), outA = angOf(cu, nx);
77
- var o = (((inA + outA - 180) / 2) % 360 + 360) % 360;
78
- var op = ((180 + 2 * o - inA) % 360 + 360) % 360;
79
- if (Math.abs(((op - outA + 540) % 360) - 180) > 0.5) { o = (o + 90) % 360; }
80
- ORI.push(o);
81
- }
82
- // The NARROW STRAIGHT-WALK laser (the exemplar): the SAME emitter as Rung 1
83
- // (Straight Walk) — preset 'particle-walk', every walk-character field INHERITED from the same
84
- // factory defaults (chargeMode 'positive', dim 0 = 'light' P=1, fundamentalWaveLength 64 → the
85
- // λ16 braided transverse ripple) — with ONLY the deliberate loop deltas: (a) a 2px source line
86
- // (emissionBoxSide 2 vs r1's default 10), (b) seated on the m10→m1 leg JUST CLEAR of m10 (70·f
87
- // past its vertex > the rotated-slab half-diagonal ≈55·f) and aimed along the leg (the longest
88
- // clear throw: leg 1.618R ≈ 364·f), (c) a burst of 8/tick, and (d) the DECLARED emission gate.
89
- const pS = pos[9], p0 = pos[0];
90
- const dx = p0[0] - pS[0], dy = p0[1] - pS[1], L = Math.hypot(dx, dy), ux = dx / L, uy = dy / L;
91
- const emit = [Math.round(pS[0] + 70 * f * ux), Math.round(pS[1] + 70 * f * uy)];
92
- // EMISSION-CAP GATE as DECLARED DATA (the blackbody-thermostat pattern):
93
- // emissionCap + gateCounter compile at CONSTRUCTION into a host tick-fn reading
94
- // Wall.getLiveCount on the background counter named 'population' (placed below — the by-name
95
- // reference resolves lazily on the first tick). The closed loop has NO sink, so the gate pauses
96
- // emission at the cap and resumes below it: the population plateaus. Restart-safe: the parts
97
- // writer keeps the two fields in the entry and the rebuilt emitter recompiles the gate (no free recipe tick-fn).
98
- // is2D: false (the 3D default) opens activeAxes.z — the volumetric laser; flat2D writes it true.
99
- // The parts, written in the 3D default mode (the mode strip's default): the laser, then the ten mirrors at the
100
- // star vertices — each its own colour + the recolor tag, each a 3D SLAB (z-slab -SD/2..SD/2). 2D is derived from
101
- // this block by flat2D below.
102
- export const parts = {
103
- source: [SphereEmitter, { preset: 'particle-walk', is2D: false, center: emit, orientationDeg: angOf(pS, p0), emissionBoxSide: 2, burstSize: 8, emissionCap: CAP, gateCounter: 'population' }],
104
- m1: [Wall, { rect: [Math.round(pos[0][0] - SW / 2), Math.round(pos[0][1] - SH / 2), SW, SH], z: -Math.round(SD / 2), depth: SD, collisionBehavior: 'bounce', bounceDirection: 'reflect', orientationDeg: ORI[0], color: PAL[0], hooks: ['recolor'] }],
105
- m2: [Wall, { rect: [Math.round(pos[1][0] - SW / 2), Math.round(pos[1][1] - SH / 2), SW, SH], z: -Math.round(SD / 2), depth: SD, collisionBehavior: 'bounce', bounceDirection: 'reflect', orientationDeg: ORI[1], color: PAL[1], hooks: ['recolor'] }],
106
- m3: [Wall, { rect: [Math.round(pos[2][0] - SW / 2), Math.round(pos[2][1] - SH / 2), SW, SH], z: -Math.round(SD / 2), depth: SD, collisionBehavior: 'bounce', bounceDirection: 'reflect', orientationDeg: ORI[2], color: PAL[2], hooks: ['recolor'] }],
107
- // m4 and m6 stand OFF their star vertices (m4 5 px right, m6 67 px toward the centre): the ring opens broken, so dragging one home is the thing to try.
108
- m4: [Wall, { rect: [437, 103, SW, SH], z: -Math.round(SD / 2), depth: SD, collisionBehavior: 'bounce', bounceDirection: 'reflect', orientationDeg: ORI[3], color: PAL[3], hooks: ['recolor'] }],
109
- m5: [Wall, { rect: [Math.round(pos[4][0] - SW / 2), Math.round(pos[4][1] - SH / 2), SW, SH], z: -Math.round(SD / 2), depth: SD, collisionBehavior: 'bounce', bounceDirection: 'reflect', orientationDeg: ORI[4], color: PAL[4], hooks: ['recolor'] }],
110
- m6: [Wall, { rect: [215, 142, SW, SH], z: -Math.round(SD / 2), depth: SD, collisionBehavior: 'bounce', bounceDirection: 'reflect', orientationDeg: ORI[5], color: PAL[5], hooks: ['recolor'] }],
111
- m7: [Wall, { rect: [Math.round(pos[6][0] - SW / 2), Math.round(pos[6][1] - SH / 2), SW, SH], z: -Math.round(SD / 2), depth: SD, collisionBehavior: 'bounce', bounceDirection: 'reflect', orientationDeg: ORI[6], color: PAL[6], hooks: ['recolor'] }],
112
- m8: [Wall, { rect: [Math.round(pos[7][0] - SW / 2), Math.round(pos[7][1] - SH / 2), SW, SH], z: -Math.round(SD / 2), depth: SD, collisionBehavior: 'bounce', bounceDirection: 'reflect', orientationDeg: ORI[7], color: PAL[7], hooks: ['recolor'] }],
113
- m9: [Wall, { rect: [Math.round(pos[8][0] - SW / 2), Math.round(pos[8][1] - SH / 2), SW, SH], z: -Math.round(SD / 2), depth: SD, collisionBehavior: 'bounce', bounceDirection: 'reflect', orientationDeg: ORI[8], color: PAL[8], hooks: ['recolor'] }],
114
- m10: [Wall, { rect: [Math.round(pos[9][0] - SW / 2), Math.round(pos[9][1] - SH / 2), SW, SH], z: -Math.round(SD / 2), depth: SD, collisionBehavior: 'bounce', bounceDirection: 'reflect', orientationDeg: ORI[9], color: PAL[9], hooks: ['recolor'] }],
115
- };
116
-
117
- /** This scene's 2D delta, stated once: the same keys in the same order, each props copied with its z-slab
118
- * (z, depth) dropped and is2D written true where it is spelled. Pure; adds no key. */
119
- function flat2D(parts) {
120
- const out = {};
121
- for (const key of Object.keys(parts)) {
122
- const props = Object.assign({}, parts[key][1]);
123
- delete props.z;
124
- delete props.depth;
125
- if ('is2D' in props) { props.is2D = true; }
126
- out[key] = [parts[key][0], props];
127
- }
128
- return out;
129
- }
130
-
131
- export default function buildExperiment(exp) {
132
- // The booted display (the host's renderState.renderer) decides which world this mode makes.
133
- var IS3D = FrqtlDisplay.name() === 'three';
134
- var P = IS3D ? parts : flat2D(parts);
135
- // THE WORLD — first, then parts: a 3D scene + universe (600x400x600) or a 2D canvas + universe.
136
- if (IS3D) { exp.createScene(W, H, WORLD_D, SphereEmitter.worldCfg(P.source[1])); }
137
- else { exp.createCanvas(W, H, SphereEmitter.worldCfg(P.source[1])); }
138
- exp.declare(P);
139
- if (IS3D) {
140
- // SCENE Z-COLLIMATOR (without it the z lets things pass through instead of
141
- // reflecting): the legs' z-braid diffuses lap over lap; any quantum beyond the mirrors'
142
- // z-band would sail BESIDE a plate on the leg line — reading as a beam passing THROUGH the
143
- // mirror. Two INVISIBLE full-canvas destroy boundaries flush with the slab z-band clamp the
144
- // scene to the mirror faces (the universe z-edge moved inward — the sanctioned
145
- // experiment-boundary sink). 40px deep: un-jumpable (max z step ±2/tick).
146
- exp.addObject('Wall', { rect: [0, 0, W, H], z: Math.round(SD / 2), depth: 40,
147
- collisionBehavior: 'destroy', name: 'zClipFar', visible: false });
148
- exp.addObject('Wall', { rect: [0, 0, W, H], z: -Math.round(SD / 2) - 40, depth: 40,
149
- collisionBehavior: 'destroy', name: 'zClipNear', visible: false });
150
- }
151
- // BACKGROUND POPULATION COUNTER (the canonical objects approach): an INVISIBLE
152
- // full-canvas Wall with collisionBehavior 'nothing' + the count hook. Every live leaf inside its
153
- // rect collides every tick, so its per-tick collided-frame count (Wall.getLiveCount, bench LO7
154
- // mechanics) IS the live population — the ONE 'how many live' authority. In 3D it must contain
155
- // EVERY live leaf: the universe z-band is ±half-width (z-strays DIE at it), so its z-slab is ±W
156
- // (a strict superset). Counting never moves/kills/recolors a frame: zero physics (SU1).
157
- exp.addObject('Wall', Object.assign(
158
- { rect: [0, 0, W, H] }, IS3D ? { z: -W, depth: 2 * W } : {},
159
- { collisionBehavior: 'nothing', hooks: ['count'], name: 'population', visible: false }));
160
- // MOVE/LOOK camera joysticks — the OMNI_3D pattern (3D only).
161
- if (IS3D && typeof document !== 'undefined' && exp.runner) {
162
- if (exp.runner.controlHost) { CameraControls.attach(exp.runner, exp.runner.controlHost); }
163
- }
164
- }
@@ -1,42 +0,0 @@
1
- /* Copyright 2023-2026 by Essam Abadir */
2
-
3
- /**
4
- * SCENE — 1A · Mirror
5
- *
6
- * A sketch file: the WHOLE scene as one ES module, `export default function buildExperiment(exp)`. The world
7
- * (its co-init call, `exp.createCanvas` / `exp.createScene` — the one place its size is written),
8
- * the parts (`export const parts` + `exp.declare`, or `exp.addObject`) and the render intent are all here; the sugar
9
- * objects, renderer and engine are imports. Registered by lib/shim/registry/walkthrough.js
10
- * (rung cl1a-mirror).
11
- */
12
-
13
- import { SphereEmitter, Wall } from '@descix/frqtl-web/parts';
14
-
15
- // Collision Lab 1A (Mirror) — a collimated LASER aimed at a rotatable Bounce/Reflect
16
- // Wall. LASER TUNING: particle-walk pins PURE +x momentum (the
17
- // tightest constrained-angle the emitter supports — zero angular spread); a SINGLE
18
- // (positive) charge removes the random transverse braiding; wavelength 1 → the
19
- // minimal transverse wiggle; fundamentalWaveLength 4 → wavelengthScale 1 (the
20
- // 256px scale-spread REMOVED — that spray was the 'visually non-sensical' look);
21
- // a TINY burst (2/tick) keeps it a thin beam (frame-rate protection). Rotate the
22
- // mirror to steer the reflected beam: 45 -> straight-up exit, 30 -> R(120) exit.
23
- const W = 600, H = 400; // THE WORLD this scene states (its co-init call below)
24
- const cy = Math.round(H / 2);
25
-
26
- export const parts = {
27
- source: [SphereEmitter, {
28
- preset: 'particle-walk', is2D: true, center: [Math.round(W * 0.12), cy],
29
- orientationDeg: 0, chargeMode: 'positive', fundamentalDimension: 2, wavelength: 1,
30
- fundamentalWaveLength: 4, burstSize: 2, emitEveryTicks: 1
31
- }],
32
- mirror: [Wall, {
33
- rect: [Math.round(W * 0.6), Math.round(H * 0.2), 20, Math.round(H * 0.6)],
34
- collisionBehavior: 'bounce', bounceDirection: 'reflect',
35
- orientationDeg: 45, color: [255, 120, 0], hooks: ['recolor']
36
- }],
37
- };
38
-
39
- export default function buildExperiment(exp) {
40
- exp.createCanvas(W, H, SphereEmitter.worldCfg(parts.source[1])); // THE WORLD: a 2D canvas + universe — first, then parts
41
- exp.declare(parts);
42
- }
@@ -1,30 +0,0 @@
1
- /* Copyright 2023-2026 by Essam Abadir */
2
-
3
- /**
4
- * SCENE — 7 · 3D
5
- *
6
- * A sketch file: the WHOLE scene as one ES module, `export default function buildExperiment(exp)`. The world
7
- * (its co-init call, `exp.createCanvas` / `exp.createScene` — the one place its size is written),
8
- * the parts (`export const parts` + `exp.declare`, or `exp.addObject`) and the render intent are all here; the sugar
9
- * objects, renderer and engine are imports. Registered by lib/shim/registry/walkthrough.js
10
- * (rung r7-3d).
11
- */
12
-
13
- // The omni source released into 3D (is2D:false) + the reusable camera joysticks.
14
-
15
- import { CameraControls, SphereEmitter } from '@descix/frqtl-web/parts';
16
-
17
- export const parts = {
18
- source: [SphereEmitter, { preset: 'spherical', is2D: false }],
19
- };
20
-
21
- export default function buildExperiment(exp) {
22
- // is2D:false opens the z-axis: the ball-rejected sampler draws a 3D BALL of
23
- // directions (bench S1). three renderer + perspective camera come from renderState.
24
- // CameraControls.attach = reusable FAIL-SOFT joystick sugar (no-op in 2D).
25
- exp.createScene(600, 400, 600, SphereEmitter.worldCfg(parts.source[1])); // THE WORLD: a 3D scene + universe, 600x400x600 — first, then parts
26
- exp.declare(parts);
27
- if (typeof document !== 'undefined' && exp.runner) {
28
- if (exp.runner.controlHost) { CameraControls.attach(exp.runner, exp.runner.controlHost); }
29
- }
30
- }
@@ -1,25 +0,0 @@
1
- /* Copyright 2023-2026 by Essam Abadir */
2
-
3
- /**
4
- * SCENE — 3 · Omni Source
5
- *
6
- * A sketch file: the WHOLE scene as one ES module, `export default function buildExperiment(exp)`. The world
7
- * (its co-init call, `exp.createCanvas` / `exp.createScene` — the one place its size is written),
8
- * the parts (`export const parts` + `exp.declare`, or `exp.addObject`) and the render intent are all here; the sugar
9
- * objects, renderer and engine are imports. Registered by lib/shim/registry/walkthrough.js
10
- * (rung r3-omni-source).
11
- */
12
-
13
- import { SphereEmitter } from '@descix/frqtl-web/parts';
14
-
15
- export const parts = {
16
- source: [SphereEmitter, { preset: 'spherical', is2D: true }],
17
- };
18
-
19
- export default function buildExperiment(exp) {
20
- // Rung 3 — full dispersion: the spherical preset draws (vx,vy) across the whole
21
- // ball; in 2D the ball-rejected sampler collapses to an even DISK of directions
22
- // (bench S5). One omni point source = the sun disk.
23
- exp.createCanvas(600, 400, SphereEmitter.worldCfg(parts.source[1])); // THE WORLD: a 2D canvas + universe — first, then parts
24
- exp.declare(parts);
25
- }
@@ -1,42 +0,0 @@
1
- /* Copyright 2023-2026 by Essam Abadir */
2
-
3
- /**
4
- * SCENE — 4 · Self-Interference / 5 · Fountain Pool
5
- *
6
- * A sketch file: the WHOLE scene as one ES module, `export default function buildExperiment(exp)`. The world
7
- * (its co-init call, `exp.createCanvas` / `exp.createScene` — the one place its size is written),
8
- * the parts (`export const parts` + `exp.declare`, or `exp.addObject`) and the render intent are all here; the sugar
9
- * objects, renderer and engine are imports. Registered by lib/shim/registry/walkthrough.js
10
- * (rungs r4-self-interference, r5-fountain-pool).
11
- */
12
-
13
- // ── Shared physics recipe SOURCES (ONE authority per physics setup) ──────────
14
- // The render-variant rungs REFERENCE these consts (never copy-paste) and express
15
- // ONLY a renderState delta — so a future change to a base tuple flows to its
16
- // variants automatically (no config mirror).
17
- // The classic self-interference field (Rung 4). Reused VERBATIM by Rung 5
18
- // (Fountain Pool) with only a water renderState delta.
19
-
20
- import { SphereEmitter } from '@descix/frqtl-web/parts';
21
-
22
- export const parts = {
23
- source: [SphereEmitter, {
24
- is2D: true, preset: 'spherical',
25
- emissionShell: 'surface', innerR: 16,
26
- fundamentalDimension: 2, wavelength: 32,
27
- chargeMode: 'random', fundamentalWaveLength: 64,
28
- burstSize: 72, emitEveryTicks: 1
29
- }],
30
- };
31
-
32
- export default function buildExperiment(exp) {
33
- // The classic self-interference tuple (matches self-interference-preset.png):
34
- // dim 2 (capacity 16) + wavelength 32 -> clamped to 16 -> mass 1 (fullness 1/16);
35
- // fundamentalWaveLength 64 -> wavelengthScale floor(64/4)=16 -> effective lambda 256px;
36
- // chargeMode 'random' -> per-leaf +/- braiding (THE interference);
37
- // emissionShell 'surface' + innerR 16 -> RING launch (empty center, sharp bands);
38
- // burst 72/tick. Red is DERIVED from fullness 1/16 (ROYGBIV low end), not forced.
39
- // Pattern = radial BRAIDED BANDS (not concentric rings).
40
- exp.createCanvas(600, 400, SphereEmitter.worldCfg(parts.source[1])); // THE WORLD: a 2D canvas + universe — first, then parts
41
- exp.declare(parts);
42
- }
@@ -1,126 +0,0 @@
1
- /* Copyright 2023-2026 by Essam Abadir */
2
-
3
- /**
4
- * SCENE — Smoking Gun
5
- *
6
- * A sketch file: the WHOLE scene as one ES module, `export default function buildExperiment(exp)`. The 3D world, the
7
- * muzzle, its wind-down, the bullet and its flight, and the painted gun body are all here; the
8
- * sugar objects (SphereEmitter, Wall, LargeObject), the renderer and the engine are imports.
9
- * Registered by lib/shim/registry/walkthrough.js (rung smoking-gun); the look and the camera ride
10
- * that row's renderState.
11
- *
12
- * Composition (zero new physics): a 1×10 slit at the muzzle emits at-fundamental leaves with the
13
- * particle-walk preset (+X momentum); brownian motion and inter-quantum collisions are on; the
14
- * declared dimensions are 4, 8 and 12. The bullet is a Wall{bounce, reflect} cube that a tick-fn
15
- * steps +1 px every second tick through Wall.setRect. A second tick-fn ramps the burst from 20 at
16
- * tick 180 toward 0 at tick 600 and cuts the muzzle once when it rounds to 0.
17
- *
18
- * Order (it seeds the run): world → brownian/collision flags → the smoke ladder → the muzzle →
19
- * the wind-down tick-fn → the bullet → its flight tick-fn → the gun body.
20
- *
21
- * Card text (this scene's what / why / how, verbatim; the scene is not on the
22
- * showcase roster, lib/shim/registry/exhibits.js, so no front-page tile or GYM card shows it):
23
- * What you are seeing:
24
- * Explore how you can create CGI-like effects out of emergent physics - if you are a ThreeJS
25
- * developer, this is your opportunity to shine! Presently, a gun fires, seen from the side. A
26
- * slit at the muzzle, one pixel wide and ten tall, releases twenty quanta per tick heading down
27
- * the barrel. The bullet is currently a ten-pixel reflecting cube (quanta bounce off it).
28
- * Why it is impossible the usual way:
29
- * Look into how you can use the collisions from the 3D Collisions Lab and the collision
30
- * experiments to make the bullet self-propelled. You'll need an intuitive understanding of what
31
- * the standard collisions in the model end up doing and possibly how Large Objects allow you to
32
- * define your own custom hooks and collision behaviors. The goal is that the collisions of the
33
- * smaller light quanta accumulate into bullet momentum instead of the currently scripted one
34
- * pixel every second tick.
35
- * How FRQTL gets it:
36
- * Currently, the quanta jostle and collide with one another, and they promote into ever larger
37
- * frames, from the fundamental layer through dimensions 4, 8 and 12. That climb is the smoke.
38
- * After three seconds the muzzle winds down, and by ten seconds it is cut, leaving the plume to
39
- * drift and spread on its own. No fluid dynamics, no gas law, no particle system scripted to
40
- * look like smoke.
41
- *
42
- * Facts to help you out:
43
- * - Muzzle: a 1×10 px slit, particle-walk preset (pure +X), 20 quanta per tick, at-fundamental leaves.
44
- * - Brownian motion and inter-quantum collisions are on. Declared dimensions are 4, 8 and 12 (the
45
- * scene's "smoke ladder": leaves promote 0 → 4 → 8 → 12).
46
- * - The bullet's motion is scripted: a tick function steps it +1 px every second tick. The quanta
47
- * do NOT push it.
48
- * - Bullet: a 10 px cube Wall, collisionBehavior bounce/reflect, so quanta reflect off it.
49
- * - Wind-down: full burst until tick 180, linear fall to zero at tick 600, then the muzzle is cut.
50
- * The rate is capped at 60 ticks per second, so that is 3 s and 10 s.
51
- * - The gun body is a painted shape with no collision, so it has no physical role.
52
- * - Look: side profile (barrel reads left to right), glow 0.6, god rays 0.5 from the fundamental
53
- * layer, heat 0.2, smoke render effect 0. The visible "smoke" is therefore the frames themselves,
54
- * not a render effect.
55
- */
56
-
57
- import { CameraControls, CollisionTypes, LargeObject, SphereEmitter } from '@descix/frqtl-web/parts';
58
-
59
- const W = 600, H = 600, D = 600; // THE WORLD this scene states (its co-init call below)
60
- const BURST = 20; // quanta per tick at the muzzle, before the wind-down
61
- const BULLET_SIDE = 10; // the bullet cube's edge = the muzzle slit's height (px)
62
- const MUZZLE_X = Math.floor(W / 2), MUZZLE_Y = Math.floor(H / 2);
63
-
64
- export const parts = {
65
- muzzle: [SphereEmitter, {
66
- preset: 'particle-walk', is2D: false, // pure +X momentum in 2D and 3D
67
- center: [MUZZLE_X, MUZZLE_Y, 0],
68
- emissionBox: { x: 0, y: BULLET_SIDE, z: 0 }, // the 1×10 slit
69
- chargeMode: 'negative', burstSize: BURST, emitEveryTicks: 1,
70
- fundamentalDimension: 0, fundamentalWaveLength: 64 // λ scale floor(64/4) = 16
71
- }],
72
- };
73
-
74
- export default function buildExperiment(exp) {
75
- var RAMP_START = 180, RAMP_END = 600; // the wind-down: full burst until RAMP_START, zero at RAMP_END
76
- var GUN_W = 150, GUN_H = 84; // the painted gun body (px); its right edge is the muzzle
77
-
78
- // ── WORLD — a 3D scene + universe W×H×D, fundamental layer 0, λ multiplier 16 ──
79
- exp.createScene(W, H, D, SphereEmitter.worldCfg(parts.muzzle[1]));
80
- var u = exp.universe;
81
- u.brownianMotion = true;
82
- u.withInterQuantumCollisions = true;
83
- u.addDimension(4); // the smoke ladder: leaves promote 0 → 4 → 8 → 12
84
- u.addDimension(8);
85
- u.addDimension(12);
86
- exp.runner.setRateLimits({ tpsLimit: 60 }); // pacing only: 60 ticks = 1 s of wall-clock
87
-
88
- // ── THE MUZZLE ──
89
- const p = exp.declare(parts);
90
- var muzzle = p.muzzle;
91
-
92
- // ── THE WIND-DOWN — the burst falls linearly from BURST at RAMP_START to zero at RAMP_END ──
93
- // The burst setter's floor is one quantum per tick, so zero is the muzzle's cut, issued once.
94
- var rampTick = 0, muzzleCut = false;
95
- exp.addTickFunction(function () {
96
- rampTick++;
97
- if (muzzleCut || rampTick < RAMP_START) { return; }
98
- var n = Math.round(BURST * Math.max(0, 1 - (rampTick - RAMP_START) / (RAMP_END - RAMP_START)));
99
- if (n >= 1) { muzzle.setBurstSize(n); } else { muzzle.setActive(false); muzzleCut = true; }
100
- });
101
-
102
- // ── THE BULLET — a reflecting wall cube at the muzzle, stepped +1 px every second tick ──
103
- var bulletLeft = MUZZLE_X, bulletTop = MUZZLE_Y - BULLET_SIDE / 2;
104
- var bullet = exp.addObject('Wall', {
105
- rect: [bulletLeft, bulletTop, -BULLET_SIDE / 2, BULLET_SIDE, BULLET_SIDE, BULLET_SIDE],
106
- collisionBehavior: 'bounce', bounceDirection: 'reflect', shellShape: 'box',
107
- color: [235, 205, 150], name: 'bullet'
108
- });
109
- var flightTick = 0;
110
- exp.addTickFunction(function () {
111
- flightTick++;
112
- if (flightTick % 2 !== 0 || bulletLeft + BULLET_SIDE >= W) { return; } // stops at the far wall
113
- bulletLeft += 1;
114
- bullet.setRect([bulletLeft, bulletTop, BULLET_SIDE, BULLET_SIDE]); // planar: z and depth kept
115
- });
116
-
117
- // ── THE GUN BODY — a painted occluder (no collision); the renderer paints the 'gun' hint ──
118
- var gun = new LargeObject(u, [MUZZLE_X - GUN_W + 12, MUZZLE_Y - GUN_H / 2, GUN_W, GUN_H],
119
- CollisionTypes.NONE, [], 'gun', 'closest', null, 1, [46, 46, 52]);
120
- gun.renderHint = 'gun';
121
-
122
- // ── MOVE/LOOK pads ──
123
- if (typeof document !== 'undefined' && exp.runner.controlHost) {
124
- CameraControls.attach(exp.runner, exp.runner.controlHost);
125
- }
126
- }
@@ -1,25 +0,0 @@
1
- /* Copyright 2023-2026 by Essam Abadir */
2
-
3
- /**
4
- * SCENE — 1 · Straight Walk
5
- *
6
- * A sketch file: the WHOLE scene as one ES module, `export default function buildExperiment(exp)`. The world
7
- * (its co-init call, `exp.createCanvas` / `exp.createScene` — the one place its size is written),
8
- * the parts (`export const parts` + `exp.declare`, or `exp.addObject`) and the render intent are all here; the sugar
9
- * objects, renderer and engine are imports. Registered by lib/shim/registry/walkthrough.js
10
- * (rung r1-straight-walk).
11
- */
12
-
13
- import { SphereEmitter } from '@descix/frqtl-web/parts';
14
-
15
- export const parts = {
16
- source: [SphereEmitter, { preset: 'particle-walk', is2D: true }],
17
- };
18
-
19
- export default function buildExperiment(exp) {
20
- // Rung 1 — deterministic +X drift (particle-walk preset pins vx=[R,R], vy=vz=0)
21
- // with the tiny always-armed transverse coin. Born AT the fundamental (dim 0)
22
- // so it is 'light' — steps every tick (fast straight drift).
23
- exp.createCanvas(600, 400, SphereEmitter.worldCfg(parts.source[1])); // THE WORLD: a 2D canvas + universe — first, then parts
24
- exp.declare(parts);
25
- }
@@ -1,42 +0,0 @@
1
- /* Copyright 2023-2026 by Essam Abadir */
2
-
3
- /**
4
- * SCENE — 8 · Sun
5
- *
6
- * A sketch file: the WHOLE scene as one ES module, `export default function buildExperiment(exp)`. The world
7
- * (its co-init call, `exp.createCanvas` / `exp.createScene` — the one place its size is written),
8
- * the parts (`export const parts` + `exp.declare`, or `exp.addObject`) and the render intent are all here; the sugar
9
- * objects, renderer and engine are imports. Registered by lib/shim/registry/walkthrough.js
10
- * (rung r8-sun).
11
- */
12
-
13
- // The sun — the 3D omni POINT source at the sun.png panel-visible regime
14
- // (supersedes the bare r-code-a-sun reuse for THIS rung). Panel knobs:
15
- // dim 2, virtual mass 16 (mass/cap 16/16, fullness 1 — the density driver, ~25012
16
- // activeQuanta) via wavelength arg 1 (mass = max(1, capacity 16 / 1) = 16, verified
17
- // vs the factory clamp); λ scale (wavelengthScale) 16 via fundamentalWaveLength 64
18
- // (waveLengthMultiplier = max(1, floor(64/4)) = 16 → eff λ (16/16)×16 = 16px); emit
19
- // every 1. force-red OFF (no color), water OFF, source-mesh OFF. FX ride the renderState
20
- // (values: lib/shim/render/sun-look.js).
21
-
22
- import { CameraControls, SphereEmitter } from '@descix/frqtl-web/parts';
23
-
24
- export const parts = {
25
- source: [SphereEmitter, {
26
- preset: 'spherical', emissionBoxSide: 0, is2D: false,
27
- chargeMode: 'random', fundamentalDimension: 2,
28
- wavelength: 1, fundamentalWaveLength: 64, emitEveryTicks: 1
29
- }],
30
- };
31
-
32
- export default function buildExperiment(exp) {
33
- // Rung 8 (Sun) — the sun.png panel regime: a 3D omni POINT source, virtual mass 16
34
- // (fullness 1) via wavelength:1, λ scale 16 via fundamentalWaveLength:64, emit every 1.
35
- // The sphere shape + god-rays + glow FX ride the renderState (three-only capabilities).
36
- // The sun's yellow is the NATURAL fullness->color (mass=capacity, fullness 1); no forced color.
37
- exp.createScene(600, 400, 600, SphereEmitter.worldCfg(parts.source[1])); // THE WORLD: a 3D scene + universe, 600x400x600 — first, then parts
38
- exp.declare(parts);
39
- if (typeof document !== 'undefined' && exp.runner) {
40
- if (exp.runner.controlHost) { CameraControls.attach(exp.runner, exp.runner.controlHost); }
41
- }
42
- }
@@ -1,42 +0,0 @@
1
- /* Copyright 2023-2026 by Essam Abadir */
2
-
3
- /**
4
- * SCENE — 6A · Two Sources / 6B · Two Fountains / 6C · Plasma Fusion
5
- *
6
- * A sketch file: the WHOLE scene as one ES module, `export default function buildExperiment(exp)`. The world
7
- * (its co-init call, `exp.createCanvas` / `exp.createScene` — the one place its size is written),
8
- * the parts (`export const parts` + `exp.declare`, or `exp.addObject`) and the render intent are all here; the sugar
9
- * objects, renderer and engine are imports. Registered by lib/shim/registry/walkthrough.js
10
- * (rungs r6a-two-source, r6b-two-fountains, r6c-plasma-fusion).
11
- */
12
-
13
- // Two self-interference sources ±32px apart (the classic config called TWICE — one
14
- // world, two parts). Reused VERBATIM by Rung 6B (Two Fountains) + 6C (Plasma Fusion)
15
- // — render deltas only.
16
-
17
- import { SphereEmitter } from '@descix/frqtl-web/parts';
18
-
19
- // The classic self-interference config called TWICE, centered ±32px from canvas
20
- // center (64px apart = 1×fundamentalWaveLength, i.e. λ_eff/4 since λ_eff = 4×fWL).
21
- // The world is init'd ONCE, then TWO parts are constructed on it — no flag, no
22
- // re-init, no stacking. The
23
- // lattice BETWEEN the two visible sources is EMERGENT density superposition (SU1).
24
- const W = 600, H = 400; // THE WORLD this scene states (its co-init call below)
25
- const cx = Math.floor(W / 2), cy = Math.floor(H / 2);
26
- const CFG = {
27
- is2D: true, preset: 'spherical',
28
- emissionShell: 'surface', innerR: 16,
29
- fundamentalDimension: 2, wavelength: 32,
30
- chargeMode: 'random', fundamentalWaveLength: 64,
31
- burstSize: 72, emitEveryTicks: 1
32
- };
33
-
34
- export const parts = {
35
- left: [SphereEmitter, { ...CFG, center: [cx - 32, cy] }],
36
- right: [SphereEmitter, { ...CFG, center: [cx + 32, cy] }],
37
- };
38
-
39
- export default function buildExperiment(exp) {
40
- exp.createCanvas(W, H, SphereEmitter.worldCfg(CFG)); // THE WORLD: a 2D canvas + universe — first, then parts
41
- exp.declare(parts);
42
- }
@@ -1,29 +0,0 @@
1
- /* Copyright 2023-2026 by Essam Abadir */
2
-
3
- /**
4
- * SCENE — 2 · Wave
5
- *
6
- * A sketch file: the WHOLE scene as one ES module, `export default function buildExperiment(exp)`. The world
7
- * (its co-init call, `exp.createCanvas` / `exp.createScene` — the one place its size is written),
8
- * the parts (`export const parts` + `exp.declare`, or `exp.addObject`) and the render intent are all here; the sugar
9
- * objects, renderer and engine are imports. Registered by lib/shim/registry/walkthrough.js
10
- * (rung r2-wave).
11
- */
12
-
13
- import { SphereEmitter } from '@descix/frqtl-web/parts';
14
-
15
- export const parts = {
16
- source: [SphereEmitter, {
17
- preset: 'particle-walk', is2D: true,
18
- fundamentalDimension: 2, wavelength: 8
19
- }],
20
- };
21
-
22
- export default function buildExperiment(exp) {
23
- // Rung 2 — Rung 1 + raise the leaf dimension to 2 (WAVELENGTH_DEMO_DIMENSION):
24
- // wavelength is a NO-OP at dim 0 (capacity=1 saturates mass), so raising the
25
- // fundamental gives the wavelength arg leverage. wavelength:8 -> mass 2 ->
26
- // transverse period grows from ~16px (Rung 1) to a visible ~128px snake.
27
- exp.createCanvas(600, 400, SphereEmitter.worldCfg(parts.source[1])); // THE WORLD: a 2D canvas + universe — first, then parts
28
- exp.declare(parts);
29
- }