@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.
- package/CLAUDE.md +3 -3
- package/README.md +4 -3
- package/dist/dist-manifest.json +26 -56
- package/dist/frqtl/experiments/_shared/empty-sketch.js +17 -0
- package/dist/frqtl/objects/setup/setupBlackbodySubstrate.js +6 -6
- package/dist/frqtl/objects/setup/setupFxSmoke.js +2 -2
- package/dist/frqtl/objects/setup/setupG3Collide.js +1 -1
- package/dist/frqtl/objects/setup/setupSphereEmitter3D.js +2 -2
- package/dist/frqtl/objects/v1-replacements.js +1 -1
- package/dist/frqtl/parts/OvenBox.js +2 -2
- package/dist/frqtl/parts/SphereEmitter.js +1 -1
- package/dist/shim/engine/router.js +18 -6
- package/dist/shim/engine/site-assemble.mjs +268 -0
- package/dist/shim/engine/site-graph.js +42 -14
- package/dist/shim/host/device.js +1 -1
- package/dist/shim/index.js +3 -7
- package/dist/shim/notebook/catalog.js +2 -2
- package/dist/shim/notebook/format.js +1 -1
- package/dist/shim/notebook/knob.js +1 -1
- package/dist/shim/notebook/notebook-knobs.js +1 -1
- package/dist/shim/project/specifiers.js +8 -8
- package/dist/shim/registry/copy-gate.js +3 -3
- package/dist/shim/registry/index.js +9 -12
- package/dist/shim/registry/roster-link.js +142 -0
- package/dist/shim/registry/roster.js +595 -0
- package/dist/shim/registry/scene-source.js +80 -105
- package/dist/shim/registry/studio-landing.js +15 -7
- package/dist/shim/render/sun-look.js +1 -2
- package/llms.txt +4 -2
- package/package.json +1 -1
- package/dist/frqtl/scenes/absorbing-wall-3d.js +0 -37
- package/dist/frqtl/scenes/absorbing-wall.js +0 -36
- package/dist/frqtl/scenes/atomic-model.js +0 -91
- package/dist/frqtl/scenes/big-bang.js +0 -49
- package/dist/frqtl/scenes/blackbody.js +0 -84
- package/dist/frqtl/scenes/circuit-sat.js +0 -131
- package/dist/frqtl/scenes/collision-matrix-3d.js +0 -110
- package/dist/frqtl/scenes/counting-wall-3d.js +0 -40
- package/dist/frqtl/scenes/counting-wall.js +0 -42
- package/dist/frqtl/scenes/double-slit.js +0 -34
- package/dist/frqtl/scenes/dse-one-emitter.js +0 -200
- package/dist/frqtl/scenes/dse-one-slit.js +0 -118
- package/dist/frqtl/scenes/dse-photoelectric.js +0 -74
- package/dist/frqtl/scenes/dse-tunnel-rebuild.js +0 -279
- package/dist/frqtl/scenes/dse-two-emitters.js +0 -201
- package/dist/frqtl/scenes/dse-two-slits.js +0 -136
- package/dist/frqtl/scenes/empty.js +0 -17
- package/dist/frqtl/scenes/laser-buildup.js +0 -56
- package/dist/frqtl/scenes/mirror-3d.js +0 -60
- package/dist/frqtl/scenes/mirror-route.js +0 -164
- package/dist/frqtl/scenes/mirror.js +0 -42
- package/dist/frqtl/scenes/omni-3d.js +0 -30
- package/dist/frqtl/scenes/omni-source.js +0 -25
- package/dist/frqtl/scenes/self-interference.js +0 -42
- package/dist/frqtl/scenes/smoking-gun.js +0 -126
- package/dist/frqtl/scenes/straight-walk.js +0 -25
- package/dist/frqtl/scenes/sun.js +0 -42
- package/dist/frqtl/scenes/two-source.js +0 -42
- package/dist/frqtl/scenes/wave.js +0 -29
- package/dist/shim/engine/artifact-shell.js +0 -211
- package/dist/shim/registry/exhibits.js +0 -436
- package/dist/shim/registry/scene-roster.js +0 -35
- package/dist/shim/registry/showcase-link.js +0 -61
- 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
|
-
}
|
package/dist/frqtl/scenes/sun.js
DELETED
|
@@ -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
|
-
}
|