@descix/egpt-math-sdk 0.1.0

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 (114) hide show
  1. package/README.md +224 -0
  2. package/dist/egpt-math-sdk.browser.js +5 -0
  3. package/dist/index.d.ts +100 -0
  4. package/dist/index.js +985 -0
  5. package/dist/notebooks/arithmetic-basics.html +166 -0
  6. package/dist/notebooks/complex-twiddle.html +148 -0
  7. package/dist/notebooks/double-slit-rosetta-qft.html +154 -0
  8. package/dist/notebooks/egpt-fft-test.html +202 -0
  9. package/dist/notebooks/egpt-matrix-test.html +241 -0
  10. package/dist/notebooks/egpt-polynomial-test.html +703 -0
  11. package/dist/notebooks/egpt-prime-composite-test.html +561 -0
  12. package/dist/notebooks/egpt-test-suite.html +1387 -0
  13. package/dist/notebooks/egpt-topology-test.html +410 -0
  14. package/dist/notebooks/factorization-basics.html +131 -0
  15. package/dist/notebooks/fft.html +155 -0
  16. package/dist/notebooks/frqtl-qft-benchmark.html +207 -0
  17. package/dist/notebooks/gallery-atomic-model.html +51 -0
  18. package/dist/notebooks/gallery-big-bang.html +62 -0
  19. package/dist/notebooks/gallery-blackbody.html +52 -0
  20. package/dist/notebooks/gallery-circuit-sat.html +104 -0
  21. package/dist/notebooks/gallery-collision-matrix-3d.html +51 -0
  22. package/dist/notebooks/gallery-double-slit.html +53 -0
  23. package/dist/notebooks/gallery-gun-chamber.html +62 -0
  24. package/dist/notebooks/gallery-particle-walk-3d.html +53 -0
  25. package/dist/notebooks/gallery-wave-interference.html +52 -0
  26. package/dist/notebooks/getting-started-hello-frqtl.html +53 -0
  27. package/dist/notebooks/iso-canonical-chain.html +203 -0
  28. package/dist/notebooks/iso-entropy-log.html +127 -0
  29. package/dist/notebooks/iso-fft-polynomial.html +136 -0
  30. package/dist/notebooks/iso-matrix-four-views.html +131 -0
  31. package/dist/notebooks/iso-number-theory-four-views.html +99 -0
  32. package/dist/notebooks/iso-pi-log-fraction-loop.html +140 -0
  33. package/dist/notebooks/matrix.html +202 -0
  34. package/dist/notebooks/notebooks.json +240 -0
  35. package/dist/notebooks/polynomials.html +201 -0
  36. package/dist/notebooks/prime-composite.html +268 -0
  37. package/dist/notebooks/rational-core.html +179 -0
  38. package/dist/notebooks/reference-egpt-fft-test.html +187 -0
  39. package/dist/notebooks/reference-order-finder-test.html +196 -0
  40. package/dist/notebooks/reference-prime-atom-polynomial-test.html +542 -0
  41. package/dist/notebooks/reference-solve-polynomial-system-test.html +471 -0
  42. package/dist/notebooks/scaled-vectors.html +112 -0
  43. package/dist/notebooks/stats.html +206 -0
  44. package/dist/notebooks/transcendentals.html +195 -0
  45. package/dist/notebooks/view-vendored-d3.html +78 -0
  46. package/dist/vendor/d3-array/src/array.js +4 -0
  47. package/dist/vendor/d3-array/src/ascending.js +3 -0
  48. package/dist/vendor/d3-array/src/bin.js +125 -0
  49. package/dist/vendor/d3-array/src/bisect.js +9 -0
  50. package/dist/vendor/d3-array/src/bisector.js +56 -0
  51. package/dist/vendor/d3-array/src/blur.js +115 -0
  52. package/dist/vendor/d3-array/src/constant.js +3 -0
  53. package/dist/vendor/d3-array/src/count.js +18 -0
  54. package/dist/vendor/d3-array/src/cross.js +33 -0
  55. package/dist/vendor/d3-array/src/cumsum.js +6 -0
  56. package/dist/vendor/d3-array/src/descending.js +7 -0
  57. package/dist/vendor/d3-array/src/deviation.js +6 -0
  58. package/dist/vendor/d3-array/src/difference.js +11 -0
  59. package/dist/vendor/d3-array/src/disjoint.js +15 -0
  60. package/dist/vendor/d3-array/src/every.js +10 -0
  61. package/dist/vendor/d3-array/src/extent.js +29 -0
  62. package/dist/vendor/d3-array/src/filter.js +11 -0
  63. package/dist/vendor/d3-array/src/fsum.js +69 -0
  64. package/dist/vendor/d3-array/src/greatest.js +29 -0
  65. package/dist/vendor/d3-array/src/greatestIndex.js +19 -0
  66. package/dist/vendor/d3-array/src/group.js +65 -0
  67. package/dist/vendor/d3-array/src/groupSort.js +10 -0
  68. package/dist/vendor/d3-array/src/identity.js +3 -0
  69. package/dist/vendor/d3-array/src/index.js +57 -0
  70. package/dist/vendor/d3-array/src/intersection.js +19 -0
  71. package/dist/vendor/d3-array/src/least.js +29 -0
  72. package/dist/vendor/d3-array/src/leastIndex.js +19 -0
  73. package/dist/vendor/d3-array/src/map.js +5 -0
  74. package/dist/vendor/d3-array/src/max.js +20 -0
  75. package/dist/vendor/d3-array/src/maxIndex.js +22 -0
  76. package/dist/vendor/d3-array/src/mean.js +19 -0
  77. package/dist/vendor/d3-array/src/median.js +9 -0
  78. package/dist/vendor/d3-array/src/merge.js +9 -0
  79. package/dist/vendor/d3-array/src/min.js +20 -0
  80. package/dist/vendor/d3-array/src/minIndex.js +22 -0
  81. package/dist/vendor/d3-array/src/mode.js +28 -0
  82. package/dist/vendor/d3-array/src/nice.js +18 -0
  83. package/dist/vendor/d3-array/src/number.js +20 -0
  84. package/dist/vendor/d3-array/src/pairs.js +15 -0
  85. package/dist/vendor/d3-array/src/permute.js +3 -0
  86. package/dist/vendor/d3-array/src/quantile.js +47 -0
  87. package/dist/vendor/d3-array/src/quickselect.js +53 -0
  88. package/dist/vendor/d3-array/src/range.js +13 -0
  89. package/dist/vendor/d3-array/src/rank.js +24 -0
  90. package/dist/vendor/d3-array/src/reduce.js +14 -0
  91. package/dist/vendor/d3-array/src/reverse.js +4 -0
  92. package/dist/vendor/d3-array/src/scan.js +6 -0
  93. package/dist/vendor/d3-array/src/shuffle.js +13 -0
  94. package/dist/vendor/d3-array/src/some.js +10 -0
  95. package/dist/vendor/d3-array/src/sort.js +39 -0
  96. package/dist/vendor/d3-array/src/subset.js +5 -0
  97. package/dist/vendor/d3-array/src/sum.js +18 -0
  98. package/dist/vendor/d3-array/src/superset.js +19 -0
  99. package/dist/vendor/d3-array/src/threshold/freedmanDiaconis.js +7 -0
  100. package/dist/vendor/d3-array/src/threshold/scott.js +7 -0
  101. package/dist/vendor/d3-array/src/threshold/sturges.js +5 -0
  102. package/dist/vendor/d3-array/src/ticks.js +55 -0
  103. package/dist/vendor/d3-array/src/transpose.js +15 -0
  104. package/dist/vendor/d3-array/src/union.js +11 -0
  105. package/dist/vendor/d3-array/src/variance.js +25 -0
  106. package/dist/vendor/d3-array/src/zip.js +5 -0
  107. package/dist/vendor/internmap/src/index.js +61 -0
  108. package/dist/vendor/manifest.json +11 -0
  109. package/dist/wasm/egpt_math_sdk_wasm.d.ts +214 -0
  110. package/dist/wasm/egpt_math_sdk_wasm.js +1120 -0
  111. package/dist/wasm/egpt_math_sdk_wasm_bg.wasm +0 -0
  112. package/dist/wasm/egpt_math_sdk_wasm_bg.wasm.d.ts +66 -0
  113. package/dist/wasm/manifest.json +5 -0
  114. package/package.json +53 -0
@@ -0,0 +1,51 @@
1
+ <frqtl-notebook version="1" title="Collision Matrix 3D — the same density gradient, read in perspective">
2
+
3
+ <cell type="markdown">
4
+ # Collision Matrix 3D
5
+
6
+ **Seven lanes of head-on collisions, distributed in a 3×3 grid of depth — the SAME density-vs-bounce-timing law as the 2D matrix, now visibly receding into the z axis.**
7
+
8
+ Seven pairs of Dim-6 cube bodies (same voxel size, same capacity) launch head-on along X. Mass is swept on a log (powers-of-2) scale from 1 to capacity, giving density ρ ≈ 0.0002 … 1.0. The 2D collision-matrix arranges these lanes in a single column; this version distributes them in rows (Y) and columns (Z) so the perspective orbit camera reveals TRUE DEPTH — cubes at different Z recede convincingly, not just stack vertically. Engine bench C5 (z-axis bounce ≡ x-axis bounce) means this 3D distribution is architecturally free — no new engine behavior, only a different placement of the SAME physics.
9
+
10
+ *New to FRQTL? Start with **Hello, FRQTL** (`getting-started-hello-frqtl`) for the `caps.frqtl` setup-module + declarative-canvas basics this notebook assumes.*
11
+ </cell>
12
+
13
+ <cell type="markdown">
14
+ The experiment assembly — seven mass-swept lanes distributed in Y and Z — as a thin adapter over the canonical factory (see below):
15
+ </cell>
16
+
17
+ <cell type="module" name="./setups/collision-matrix-3d.js">
18
+ /* setupCollisionMatrix3D — THIN ADAPTER over the canonical setup factory
19
+ * (WS gym-controls-as-sugar Bite 0 ADDENDUM, CEO 2026-07-03). Same Bite-0
20
+ * mechanism as every other de-forked notebook: the canonical factory is
21
+ * imported by BARE SPECIFIER (a relative path here would 404 — see
22
+ * lib/shim/notebook/frqtl-setups-importmap.js); this cell only bridges the
23
+ * notebook builder's `(frqtl, universe, options)` call shape to the factory's
24
+ * `(universe, options)` shape — ZERO physics here. The SAME canonical
25
+ * `lib/frqtl/objects/setup/setupCollisionMatrix3D.js` also drives the
26
+ * standalone `lib/frqtl/experiments/collision-matrix-3d/` page.
27
+ */
28
+ import { setupCollisionMatrix3D as _setupCollisionMatrix3D } from '@frqtl/setups/collision-matrix-3d';
29
+
30
+ export function setupCollisionMatrix3D(frqtl, universe, options) {
31
+ return _setupCollisionMatrix3D(universe, options);
32
+ }
33
+ </cell>
34
+
35
+ <cell type="markdown">
36
+ Declare a canvas that runs it. `render3d="true"` requests the three.js 3D renderer + perspective camera for this canvas (the notebook-realm mirror of an experiment page's `window._egpt3D = true;` opt-in). `renderOptions="shape=cube,colorScheme=roygbiv"` is the notebook-cell channel for the SAME `runner.setRenderOption('shape','cube')` / `('colorScheme','roygbiv')` calls the standalone page makes page-side beside `setup()` (WS gym-controls-as-sugar fix-loop #6 Finding B, 2026-07-04) — without it this canvas rendered soft default-shaded blobs instead of the shaded cube meshes the GYM/standalone page show; the render intent did not travel with the physics-only adapter. Click **Run** (or **Run All**):
37
+ </cell>
38
+
39
+ <cell type="canvas" id="c-cm3d-canvas" setup="./setups/collision-matrix-3d.js#setupCollisionMatrix3D" stage="480x480" seed="42" render3d="true" renderOptions="shape=cube,colorScheme=roygbiv"></cell>
40
+
41
+ <cell type="markdown">
42
+ ## What you are seeing
43
+
44
+ Seven pairs of cubes, arranged in a 3×3 grid facing the camera, collide head-on. Sparse (low-mass) lanes bounce almost instantly; dense (high-mass, near-capacity) lanes linger before separating — the SAME per-tick occupancy-ceiling law the 2D collision-matrix demonstrates, now visible with true perspective depth: cubes further back in Z genuinely recede, rather than merely stacking on a flat plane.
45
+
46
+ **Compare to the 2D version** (`collision-matrix`): identical physics, identical lane masses — the ONLY difference is the render intent (`render3d`) and the lane distribution (Y×Z grid instead of a single Y column), both of which the canonical `setupCollisionMatrix3D.js` factory already encodes; nothing in this notebook cell reimplements it.
47
+
48
+ The simulation runs live in your browser on the compiled FRQTL (WASM) engine.
49
+ </cell>
50
+
51
+ </frqtl-notebook>
@@ -0,0 +1,53 @@
1
+ <frqtl-notebook version="1" title="Double Slit — the fringe pattern builds itself">
2
+
3
+ <cell type="markdown">
4
+ # Double Slit
5
+
6
+ **One particle at a time — the fringe pattern builds itself. Classically this is supposed to be impossible.**
7
+
8
+ Particles pass through two slits one by one. There is no wave function evaluated anywhere in the engine — each particle is a leaf Frame taking a single 1-pixel step per tick. The banded arrival distribution at the detector wall is **emergent** from single-occupancy collisions and the per-Frame oscillation alone.
9
+
10
+ *New to FRQTL? Start with **Hello, FRQTL** (`getting-started-hello-frqtl`) for the `caps.frqtl` setup-module + declarative-canvas basics this notebook assumes.*
11
+ </cell>
12
+
13
+ <cell type="markdown">
14
+ The experiment assembly — slit screen, light source, detector wall — as editable user code:
15
+ </cell>
16
+
17
+ <cell type="module" name="./setups/double-slit.js">
18
+ /* setupDoubleSlit — THIN ADAPTER over the canonical setup factory
19
+ * (WS gym-controls-as-sugar Bite 0: this cell used to hand-copy the physics —
20
+ * a divergent fork of lib/frqtl/objects/setup/setupDoubleSlit.js that had
21
+ * already drifted onto a stale `universe.init(...)` positional-argument call the
22
+ * engine now FAIL-LOUDs on, plus a dead `CollisionActions.RECOLOR` reference the
23
+ * canonical source removed. The canonical factory is imported by BARE SPECIFIER
24
+ * (a relative path here would 404 — see lib/shim/notebook/frqtl-setups-importmap.js);
25
+ * this cell only bridges the notebook builder's `(frqtl, universe, options)` call
26
+ * shape to the factory's `(universe, options)` shape — ZERO physics here.)
27
+ */
28
+ import { setupDoubleSlit as _setupDoubleSlit } from '@frqtl/setups/double-slit';
29
+
30
+ export function setupDoubleSlit(frqtl, universe, options) {
31
+ return _setupDoubleSlit(universe, options);
32
+ }
33
+ </cell>
34
+
35
+ <cell type="markdown">
36
+ Declare a canvas that runs it. `setup="<module>#<export>"` + `stage`/`seed`; the shim synthesizes and runs the builder boilerplate in the realm. Click **Run** (or **Run All**):
37
+ </cell>
38
+
39
+ <cell type="canvas" id="c-ds-canvas" setup="./setups/double-slit.js#setupDoubleSlit" stage="480x480" seed="42"></cell>
40
+
41
+ <cell type="markdown">
42
+ ## What you are seeing
43
+
44
+ Particles emit from the light source on the left, most are blocked by the slit screen, and the few that pass through the two openings travel to the detector wall on the right. Over many ticks the arrival positions cluster into fringes — the classical "impossible" result, built from individually launched particles with no wave equation.
45
+
46
+ **The geometry is a knob.** `wavelength` (default 64) is the single master parameter: it scales slit height, inter-slit gap, wall positions, and detector distance all at once. At `wavelength = 64` on a 480×480 canvas both slits receive balanced illumination (slit1/slit2 ratio ≈ 1.0) and a clear multi-band pattern emerges. The captured sweep across `wavelength` 16 → 128 is in [`docs/physics/double-slit-wavelength.md`](../../docs/physics/double-slit-wavelength.md).
47
+
48
+ **`detectAtSlits` — the "which-slit" knob.** The default (`1`) applies `RANDOM_XY` at each slit opening: detection disturbs the particle's trajectory. Set it to `0` (transparent slits, no detection) or `2` (color-only, no disturbance) to compare the unobserved and color-only cases.
49
+
50
+ **Edit the physics:** open the `./setups/double-slit.js` tab and pass an option override to the canonical factory — e.g. change the adapter's `_setupDoubleSlit(universe, options)` call to `_setupDoubleSlit(universe, Object.assign({ wavelength: 32 }, options))` (also try `angleIncrement` or `detectAtSlits`) — then re-Run. The fringe pattern changes because you edited the construction. (The physics body itself lives in the canonical `lib/frqtl/objects/setup/setupDoubleSlit.js` — this cell is a thin, engine-agnostic adapter over it, the SAME construction the `double-slit-rosetta-qft` notebook and the `lib/frqtl/experiments/double-slit/` page drive.) The simulation runs live in your browser on the compiled FRQTL (WASM) engine.
51
+ </cell>
52
+
53
+ </frqtl-notebook>
@@ -0,0 +1,62 @@
1
+ <frqtl-notebook version="1" title="Gun Chamber — L2 effects cascade in a tube">
2
+
3
+ <cell type="markdown">
4
+ # Gun Chamber
5
+
6
+ **A breech emitter ignites inside a barrel-scale tube — Dim-0 collisions cascade UP through six declared dimension rungs (light → plasma → air → fire → smoke → haze), with no per-dimension force law anywhere.**
7
+
8
+ A `Tube` (translucent barrel walls, L1) contains ONE breech `ChamberEmitter` firing rightward down the bore. `universe.addDimension` declares the full sequential Dim 1-6 cascade, so `Universe::handle_promotion` routes each collision's parent to the NEXT declared dimension above it — Dim-0 collisions promote to Dim-1, Dim-1 to Dim-2, and so on, a genuine sequential cascade rather than a skip-ahead. Two hand-placed seeds (Dim-2 "air", Dim-3 "fire") fill tiers the cascade does not reach naturally within the observed window — a reported, measured finding, not a hedge. A muzzle absorber-sink bounds the alive population.
9
+
10
+ *New to FRQTL? Start with **Hello, FRQTL** (`getting-started-hello-frqtl`) for the `caps.frqtl` setup-module + declarative-canvas basics this notebook assumes.*
11
+ </cell>
12
+
13
+ <cell type="markdown">
14
+ The experiment assembly — Tube + ChamberEmitter + the declared dimension cascade + two hand-placed seeds — as a thin adapter over the canonical factory (see below):
15
+ </cell>
16
+
17
+ <cell type="module" name="./setups/gun-chamber.js">
18
+ /* setupGunChamber — THIN ADAPTER over the canonical setup factory
19
+ * (WS gym-controls-as-sugar Bite 0 ADDENDUM, CEO 2026-07-03). Same Bite-0
20
+ * mechanism as every other de-forked notebook: the canonical factory is
21
+ * imported by BARE SPECIFIER (a relative path here would 404 — see
22
+ * lib/shim/notebook/frqtl-setups-importmap.js); this cell only bridges the
23
+ * notebook builder's `(frqtl, universe, options)` call shape to the factory's
24
+ * `(universe, options)` shape — ZERO physics here. The SAME canonical
25
+ * `lib/frqtl/objects/setup/setupGunChamber.js` also drives the standalone
26
+ * `lib/frqtl/experiments/gun-chamber/` page.
27
+ *
28
+ * NOTE (ground-truthed, not hand-copied): setupGunChamber.js's browser-classic
29
+ * branch reads window.Tube / window.ChamberEmitter / window.LeafField directly
30
+ * (the SAME window.* sugar pattern every canonical factory uses) — these three
31
+ * "Layer class" sugar objects were previously ONLY loaded as per-page
32
+ * data-page-scripts extras (3 experiment pages: tube-l1, gun, gun-chamber),
33
+ * NOT part of the shared game layer the notebook realm boots. This bite
34
+ * promotes them into GAME_LAYER_SCRIPTS (lib/shim/engine/game-layer-manifest.js)
35
+ * — the canonical move, since they are already reusable across 3 independent
36
+ * experiments, not gun-chamber-specific — rather than inventing a new
37
+ * per-notebook "extra scripts" mechanism.
38
+ */
39
+ import { setupGunChamber as _setupGunChamber } from '@frqtl/setups/gun-chamber';
40
+
41
+ export function setupGunChamber(frqtl, universe, options) {
42
+ return _setupGunChamber(universe, options);
43
+ }
44
+ </cell>
45
+
46
+ <cell type="markdown">
47
+ Declare a canvas that runs it. `render3d="true"` requests the three.js 3D renderer + perspective camera for this canvas (the notebook-realm mirror of an experiment page's `window._egpt3D = true;` opt-in). `cameraPreset="down-barrel"` and `renderOptions="glowIntensity=1.3,godrays=0.8,smoke=4"` carry the standalone page's OWN defaults (WS gym-controls-as-sugar fix-loop #6 Finding B, 2026-07-04 — the tester's fresh-nav side-by-side had flagged these as differing from the GYM/standalone default view). Click **Run** (or **Run All**):
48
+ </cell>
49
+
50
+ <cell type="canvas" id="c-gunchamber-canvas" setup="./setups/gun-chamber.js#setupGunChamber" stage="480x480" seed="42" render3d="true" cameraPreset="down-barrel" renderOptions="glowIntensity=1.3,godrays=0.8,smoke=4"></cell>
51
+
52
+ <cell type="markdown">
53
+ ## What you are seeing
54
+
55
+ A bright flash of Dim-0 quanta ignites at the breech and streams down the bore; as collisions cascade upward through the declared dimension ladder, denser compound frames appear further down the tube — light, then plasma, then (from the hand-placed seeds) air and fire tiers — all inside the translucent barrel walls, viewed with true perspective depth, opening on the same down-barrel view (bullet stares at you) as the standalone page and the GYM, with the glow/god-ray/smoke post-process layers on at their page defaults.
56
+
57
+ **Scope note (this notebook, not the standalone page — fix-loop #6, 2026-07-04):** the camera's default preset and the 3 numeric effect-intensity defaults (glow/god-rays/smoke) now travel identically to the standalone page (via the new `cameraPreset`/`renderOptions` cell attributes — the SAME `runner.cameraControl.setPreset()` / `runner.setRenderOption()` calls the page itself makes). What does NOT travel: the standalone page's PER-DIMENSION `renderTiers` table (flash/plasma/air/fire/smoke/haze/vapor — a structured array-of-objects, not a flat `key=value` pair) and its interactive tier-matrix/preset-button/effect-slider UI, all wired by `fx-experiment.js` reading `window._egptFx` — a substantially larger, separate control system this notebook does not build out. The underlying physics and dimension cascade are byte-identical either way, driven by the identical canonical factory; only the per-dimension VISUAL TREATMENT and the extra UI differ from the standalone page.
58
+
59
+ The simulation runs live in your browser on the compiled FRQTL (WASM) engine.
60
+ </cell>
61
+
62
+ </frqtl-notebook>
@@ -0,0 +1,53 @@
1
+ <frqtl-notebook version="1" title="Particle Walk 3D — the beam fans out in three axes">
2
+
3
+ <cell type="markdown">
4
+ # Particle Walk 3D
5
+
6
+ **A radial beam fans out in TWO transverse axes at once — proof the engine's per-axis speed limit is genuinely 3D, not a 2D model with a cosmetic z column bolted on.**
7
+
8
+ A single `QuantumEmitter` fires quanta rightward (`vx=1`). With `activeAxes:{x,y,z}` all live, the wave-walk coin-flip fires its transverse yo-yo kick on BOTH y AND z independently, every tick — two independent transverse coins, not one. The beam spreads in both directions as it propagates; with only two axes the z column would stay zero throughout. This is the realm-observable proof of Engine Invariant 1 (the ±1px/tick speed limit is independent PER AXIS) in three dimensions.
9
+
10
+ *New to FRQTL? Start with **Hello, FRQTL** (`getting-started-hello-frqtl`) for the `caps.frqtl` setup-module + declarative-canvas basics this notebook assumes.*
11
+ </cell>
12
+
13
+ <cell type="markdown">
14
+ The experiment assembly — one `QuantumEmitter`, full 3D `activeAxes` — as a thin adapter over the canonical factory (see below):
15
+ </cell>
16
+
17
+ <cell type="module" name="./setups/particle-walk-3d.js">
18
+ /* setupParticleWalk3D — THIN ADAPTER over the canonical setup factory
19
+ * (WS gym-controls-as-sugar Bite 0 ADDENDUM, CEO 2026-07-03: three notebooks
20
+ * proving full 3D compliance + the object-architecture contract switching
21
+ * end-to-end through the notebook path). Same Bite-0 mechanism as every other
22
+ * de-forked notebook: the canonical factory is imported by BARE SPECIFIER
23
+ * (a relative path here would 404 — see lib/shim/notebook/frqtl-setups-importmap.js);
24
+ * this cell only bridges the notebook builder's `(frqtl, universe, options)` call
25
+ * shape to the factory's `(universe, options)` shape — ZERO physics here. The
26
+ * SAME canonical `lib/frqtl/objects/setup/setupParticleWalk3D.js` also drives the
27
+ * standalone `lib/frqtl/experiments/particle-walk-3d/` page — one experiment
28
+ * identity, no divergence possible.
29
+ */
30
+ import { setupParticleWalk3D as _setupParticleWalk3D } from '@frqtl/setups/particle-walk-3d';
31
+
32
+ export function setupParticleWalk3D(frqtl, universe, options) {
33
+ return _setupParticleWalk3D(universe, options);
34
+ }
35
+ </cell>
36
+
37
+ <cell type="markdown">
38
+ Declare a canvas that runs it. `render3d="true"` requests the three.js 3D renderer + perspective camera for this canvas (the notebook-realm mirror of an experiment page's `window._egpt3D = true;` opt-in — see `lib/components/notebook-pane/realm-frqtl.js`). Click **Run** (or **Run All**):
39
+ </cell>
40
+
41
+ <cell type="canvas" id="c-walk3d-canvas" setup="./setups/particle-walk-3d.js#setupParticleWalk3D" stage="480x480" seed="42" render3d="true"></cell>
42
+
43
+ <cell type="markdown">
44
+ ## What you are seeing
45
+
46
+ A cone of quanta streams rightward from the emitter, visibly spreading in BOTH the vertical (y) and depth (z) directions as it travels — the perspective camera makes the z-spread readable as true depth, not a flattened 2D projection. No wave equation, no cone-angle formula: the spread is the accumulated per-tick, per-axis coin-flip of Engine Invariant 6 (the transverse oscillation).
47
+
48
+ **Compare to the 2D version** (`gallery-wave-interference`, `particle-walk`): those experiments only ever exercise the x/y plane. This notebook is the SAME canonical setup factory the standalone `particle-walk-3d` experiment page drives — the render intent (`render3d`) is the only thing this notebook adds; the physics is identical.
49
+
50
+ The simulation runs live in your browser on the compiled FRQTL (WASM) engine.
51
+ </cell>
52
+
53
+ </frqtl-notebook>
@@ -0,0 +1,52 @@
1
+ <frqtl-notebook version="1" title="Wave Interference — interference without a wave equation">
2
+
3
+ <cell type="markdown">
4
+ # Wave Interference
5
+
6
+ **Interference patterns without a wave equation — only quantum particles, with real and local rules, that don't know each other exist. Classically this is supposed to be impossible.**
7
+
8
+ Using the FRQTL engine, two convenience `PointSource` emitters fire quanta (leaf Frames) radially. Where the two streams overlap, fringes emerge — with no wave function, no superposition term, no interference formula anywhere in the engine.
9
+
10
+ *New to FRQTL? Start with **Hello, FRQTL** (`getting-started-hello-frqtl`) for the `caps.frqtl` setup-module + declarative-canvas basics this notebook assumes.*
11
+ </cell>
12
+
13
+ <cell type="markdown">
14
+ Two radial emitters and their (visual-only) source circles — editable user code:
15
+ </cell>
16
+
17
+ <cell type="module" name="./setups/wave-interference.js">
18
+ /* setupWaveInterference — THIN ADAPTER over the canonical setup factory
19
+ * (WS gym-controls-as-sugar Bite 0: this cell used to hand-copy the physics —
20
+ * a divergent fork of lib/frqtl/objects/setup/setupWaveInterference.js that had
21
+ * already drifted onto a stale `universe.init(...)` positional-argument call the
22
+ * engine now FAIL-LOUDs on. The canonical factory is imported by BARE SPECIFIER
23
+ * (a relative path here would 404 — see lib/shim/notebook/frqtl-setups-importmap.js);
24
+ * this cell only bridges the notebook builder's `(frqtl, universe, options)` call
25
+ * shape to the factory's `(universe, options)` shape — ZERO physics here.)
26
+ */
27
+ import { setupWaveInterference as _setupWaveInterference } from '@frqtl/setups/wave-interference';
28
+
29
+ export function setupWaveInterference(frqtl, universe, options) {
30
+ return _setupWaveInterference(universe, options);
31
+ }
32
+ </cell>
33
+
34
+ <cell type="markdown">
35
+ Declare a canvas that runs it. The canvas names the setup module (`setup="<module>#<export>"`); the shim synthesizes and runs the builder boilerplate in the realm. `opts` is the validated driving knob, `stage`/`seed` configure the runner. Click **Run** (or **Run All**):
36
+ </cell>
37
+
38
+ <cell type="canvas" id="c-wave-canvas" setup="./setups/wave-interference.js#setupWaveInterference" opts="quanta=800" stage="480x480" seed="42"></cell>
39
+
40
+ <cell type="markdown">
41
+ ## What just happened
42
+
43
+ The two black circles are the point sources. Particles stream outward from each; where the streams overlap, regions of constructive and destructive density build into the banded fringe pattern — the classically "impossible" result, produced with no wave equation. Each particle only ever obeyed *move 1 pixel per tick*; the wave behavior is **emergent**.
44
+
45
+ **The fringe spacing is a knob.** It is set by the universe `wavelengthConstant` (`wavelength = floor((capacity / mass) × WAVELENGTH_CONSTANT)`). Raising it 2 → 32 widens the fringes from a near-uniform dense cloud to sparse, widely-separated radial spokes; lowering it tightens them until they blur together. The captured sweep is in [`docs/physics/wave-interference-wavelength.md`](../../docs/physics/wave-interference-wavelength.md).
46
+
47
+ Note the two distinct "wavelength" controls: a `PointSource`'s `opts.wavelength` sets each particle's **mass** (`mass = capacity / wavelength`), while the universe `wavelengthConstant` is the global scale on **every** particle's wavelength — the fringe-spacing knob above.
48
+
49
+ **Edit the physics:** try the `quanta` knob on the canvas (`opts="quanta=200"` or `"quanta=1500"`), or open the `./setups/wave-interference.js` tab and pass an option override to the canonical factory — e.g. change the adapter's `_setupWaveInterference(universe, options)` call to `_setupWaveInterference(universe, Object.assign({ fundamentalWaveLength: 48 }, options))` (also try `sourceSeparation`) — then re-Run. The fringes change because you edited the construction. (The physics body itself lives in the canonical `lib/frqtl/objects/setup/setupWaveInterference.js` — this cell is a thin, engine-agnostic adapter over it.) The simulation runs live in your browser on the compiled FRQTL (WASM) engine.
50
+ </cell>
51
+
52
+ </frqtl-notebook>
@@ -0,0 +1,53 @@
1
+ <frqtl-notebook version="1" title="Hello, FRQTL — your first simulation">
2
+
3
+ <cell type="markdown">
4
+ # Hello, FRQTL
5
+
6
+ FRQTL is a discrete physics engine: everything is a **Frame**, and a leaf Frame (a "quantum") obeys one rule — **move 1 pixel per tick**. Complex behavior *emerges*; nothing is hand-coded.
7
+
8
+ An experiment is two cells:
9
+
10
+ - a **`module`** cell — editable user code that *assembles* the experiment. It receives `frqtl` (the convenience registry, `caps.frqtl`: `PointSource`, `LargeObject`, `CollisionTypes`, …) and an un-initialized `universe`, and builds objects from them.
11
+ - a **`canvas`** cell — `setup="<module>#<export>"` names that setup; the shim boots the engine, runs your setup, and renders it live. `opts` is a validated driving knob; `stage`/`seed` configure the runner.
12
+
13
+ That's the whole pattern. (There is no separate builder cell — the canvas declares the setup and the shim synthesizes the wiring.)
14
+ </cell>
15
+
16
+ <cell type="markdown">
17
+ **1. The setup.** Editable user code — one emitter firing radially from the center:
18
+ </cell>
19
+
20
+ <cell type="module" name="./setups/hello.js">
21
+ export function setupHello(frqtl, universe, options) {
22
+ const { PointSource } = frqtl; // the convenience emitter, via caps.frqtl
23
+ const r = universe.universe_rect;
24
+
25
+ // init(rect, fundamentalDimension, wavelengthConstant, ...): configure + create the field.
26
+ universe.init(r, 2, 8, false, false, false, true, false);
27
+
28
+ // PointSource(universe, x, y, diameter, speed, charge, auto_fire, quantum_limit, delay, angle_increment, opts)
29
+ // one source at center; angle_increment 5° → 72 rays; opts.wavelength → particle mass.
30
+ const source = new PointSource(universe, Math.floor(r.w / 2), Math.floor(r.h / 2),
31
+ 24, 12, null, true, 50000, 0, 5, { wavelength: 32 });
32
+
33
+ return { sources: { source }, largeObjects: [] };
34
+ }
35
+ </cell>
36
+
37
+ <cell type="markdown">
38
+ **2. Render.** Declare a canvas that names the setup. The shim boots the engine and runs it — click **Run** (or **Run All**) and quanta stream outward to fill the field:
39
+ </cell>
40
+
41
+ <cell type="canvas" id="c-hello-canvas" setup="./setups/hello.js#setupHello" stage="480x480" seed="42"></cell>
42
+
43
+ <cell type="markdown">
44
+ ## That's it
45
+
46
+ You created a running physics simulation from two small cells. **Edit the setup** — move the source, change `angle_increment`, or the per-emitter `wavelength` — then re-run the canvas; the behavior changes because you changed the construction, not a label.
47
+
48
+ This runs live in your browser on the compiled FRQTL (WASM) engine.
49
+
50
+ **Next:** open **Wave Interference** (`gallery-wave-interference`) — two of these emitters produce interference fringes with no wave equation, the classically "impossible" result.
51
+ </cell>
52
+
53
+ </frqtl-notebook>
@@ -0,0 +1,203 @@
1
+ <frqtl-notebook version="1" title="U — Canonical Chain Unified (one engine, three lenses)">
2
+
3
+ <cell type="markdown">
4
+ # U — Canonical Chain Unified
5
+
6
+ Every case is an instance of the same commuting diagram:
7
+
8
+ > input ─encode─► EGPTReal[] ─engine─► EGPTReal[] ─decode─► output
9
+
10
+ The "engine" column names which `EGPTPolynomial` primitive does the work. The same handful of primitives — `forwardTransform`/`inverseTransform`, `multiply`/`add`, `divide` (→ GCD), `evaluateAt` — power number theory, linear algebra, and signal processing alike:
11
+
12
+ - **U1** `forwardTransform` ≡ pointwise `evaluateAt` at k/N (T1 / F1)
13
+ - **U2** `inverseTransform(forwardTransform(c)) = c` (M2 / F2)
14
+ - **U3** `multiply` + dense `matMul` on polynomial systems (T2 / K1–K6)
15
+ - **U4** iterated `divide` = polynomial GCD (T3 / M6 shared factor)
16
+ - **U5** `evaluateAt` on the atom-root polynomial = factor detection (N1 / N2)
17
+ - **U6** orbit polynomial + `evaluateAt` = order finding ≡ period (N3 / N4)
18
+ - **U7** one example (N=15), all three lenses at once
19
+
20
+ *(Ported from `theorems/U_CanonicalChainUnified.js`. `EGPTReal/EGPTMath/EGPTPolynomial/PrimeAtomPolynomial/OrderFinder/matMul` come from `caps.math` — no imports. Render + atom/orbit helpers inlined.)*
21
+ </cell>
22
+
23
+ <cell type="markdown">
24
+ ## Setup — inline helpers
25
+
26
+ `renderVec`/`matricesEqual` and the atom-root / orbit polynomial builders are inlined (they call only `caps.math` primitives). Exposed as a binding for the engine cells.
27
+ </cell>
28
+
29
+ <cell type="js" lane="math" id="u-setup" out="uhelp">
30
+ const { math } = caps;
31
+ const { EGPTReal, EGPTPolynomial, PrimeAtomPolynomial } = math;
32
+ const ZERO = EGPTReal.fromBigInt(0n);
33
+ const ONE = EGPTReal.fromBigInt(1n);
34
+ const intN = (n) => EGPTReal.fromBigInt(BigInt(n));
35
+ const frac = (n, d) => EGPTReal.fromRational(BigInt(n), BigInt(d));
36
+ const isZero = (e) => e.equals(ZERO);
37
+ function renderValue(v) {
38
+ if (v == null) return String(v);
39
+ if (typeof v._getPPFRationalParts === 'function') {
40
+ const { numerator, denominator } = v._getPPFRationalParts();
41
+ if (denominator === 1n || denominator === -1n) return String(denominator < 0n ? -numerator : numerator);
42
+ return `${numerator}/${denominator}`;
43
+ }
44
+ return String(v);
45
+ }
46
+ function showVec(v) { return '[ ' + v.map(renderValue).join(', ') + ' ]'; }
47
+ function matricesEqual(X, Y) {
48
+ if (X.length !== Y.length) return false;
49
+ for (let i = 0; i < X.length; i++) {
50
+ if (X[i].length !== Y[i].length) return false;
51
+ for (let j = 0; j < X[i].length; j++) if (!X[i][j].equals(Y[i][j])) return false;
52
+ }
53
+ return true;
54
+ }
55
+ function polyGCDMonic(a, b) {
56
+ let A = a.slice(), B = b.slice();
57
+ while (!B.every(isZero)) { const { remainder } = EGPTPolynomial.divide(A, B); A = B; B = EGPTPolynomial.trimZeros(remainder); }
58
+ A = EGPTPolynomial.trimZeros(A);
59
+ const lead = A[A.length - 1];
60
+ if (isZero(lead)) return A;
61
+ return EGPTPolynomial.divide(A, [lead]).quotient;
62
+ }
63
+ function buildAtomRootPolynomial(N) {
64
+ const factors = PrimeAtomPolynomial.factorize(N);
65
+ let poly = [ONE];
66
+ for (const { prime, exponent } of factors) { const linear = [intN(-prime), ONE]; for (let k = 0n; k < exponent; k++) poly = EGPTPolynomial.multiply(poly, linear); }
67
+ return poly;
68
+ }
69
+ function buildOrbitPolynomial(a, N) {
70
+ const aBi = BigInt(a), NBi = BigInt(N);
71
+ let poly = [ONE], current = 1n; const seen = new Set([1n]);
72
+ while (true) { current = (current * aBi) % NBi; if (current === 1n) break; if (seen.has(current)) break; seen.add(current); poly = EGPTPolynomial.multiply(poly, [intN(-Number(current)), ONE]); }
73
+ return EGPTPolynomial.multiply(poly, [intN(-1), ONE]);
74
+ }
75
+ return { uhelp: { renderValue, showVec, matricesEqual, polyGCDMonic, buildAtomRootPolynomial, buildOrbitPolynomial, intN, frac } };
76
+ </cell>
77
+
78
+ <cell type="markdown">
79
+ ## U1 / U2 — forwardTransform ≡ evaluateAt, and the inverse round-trip
80
+
81
+ `forwardTransform(c, N)` is per-point `evaluateAt(c, k/N)`; `inverseTransform` recovers `c` exactly.
82
+ </cell>
83
+
84
+ <cell type="js" lane="math" id="u12" in="uhelp">
85
+ const { math, display } = caps;
86
+ const { EGPTPolynomial, EGPTReal } = math;
87
+ const { showVec, intN, frac } = inputs.uhelp;
88
+ const ONE = EGPTReal.fromBigInt(1n);
89
+ function check(label, cond) { display((cond ? ' ✓ ' : ' ✗ ') + label); if (!cond) throw new Error('U1/U2 FAILED: ' + label); }
90
+ function veq(u, v) { if (u.length !== v.length) return false; for (let i = 0; i < u.length; i++) if (!u[i].equals(v[i])) return false; return true; }
91
+
92
+ // U1
93
+ const coeffs = [frac(1, 3), frac(-7, 6), ONE];
94
+ const N = 8;
95
+ const samples = EGPTPolynomial.forwardTransform(coeffs, N);
96
+ display('U1 forwardTransform(c,8) = ' + showVec(samples));
97
+ const manual = []; for (let k = 0; k < N; k++) manual.push(EGPTPolynomial.evaluateAt(coeffs, EGPTReal.fromRational(BigInt(k), BigInt(N))));
98
+ check('forwardTransform ≡ per-point evaluateAt at k/N (T1 / F1)', veq(manual, samples));
99
+
100
+ // U2
101
+ const c2 = [frac(1, 3), frac(-7, 6), ONE];
102
+ const s2 = EGPTPolynomial.forwardTransform(c2, c2.length);
103
+ const rec = EGPTPolynomial.inverseTransform(s2, c2.length);
104
+ display('U2 inverseTransform(forward(c)) = ' + showVec(rec));
105
+ check('inverseTransform(forwardTransform(c)) = c (bit-exact round trip)', veq(rec, c2));
106
+ </cell>
107
+
108
+ <cell type="markdown">
109
+ ## U3 — multiply + dense matMul on polynomial systems
110
+
111
+ Convolution (T2) is one `multiply` call; a dense 2×2 `matMul` (K1) treats rows as polynomials and accumulates via `multiply` + `add`, matching the explicit dot-product reference.
112
+ </cell>
113
+
114
+ <cell type="js" lane="math" id="u3" in="uhelp">
115
+ const { math, display } = caps;
116
+ const { EGPTPolynomial, EGPTMath, matMul } = math;
117
+ const { showVec, matricesEqual, intN } = inputs.uhelp;
118
+ function check(label, cond) { display((cond ? ' ✓ ' : ' ✗ ') + label); if (!cond) throw new Error('U3 FAILED: ' + label); }
119
+
120
+ const a = [intN(1), intN(2)], b = [intN(3), intN(4)];
121
+ const ab = EGPTPolynomial.multiply(a, b);
122
+ display('T2 multiply([1,2],[3,4]) = ' + showVec(ab));
123
+ check('T2 convolution ≡ one multiply call', ab.length === 3 && ab[0].equals(intN(3)) && ab[1].equals(intN(10)) && ab[2].equals(intN(8)));
124
+
125
+ const A = [[intN(1), intN(2)], [intN(3), intN(4)]];
126
+ const B = [[intN(5), intN(6)], [intN(7), intN(8)]];
127
+ const C = matMul(A, B);
128
+ const Cref = [
129
+ [EGPTMath.add(EGPTMath.multiply(A[0][0], B[0][0]), EGPTMath.multiply(A[0][1], B[1][0])),
130
+ EGPTMath.add(EGPTMath.multiply(A[0][0], B[0][1]), EGPTMath.multiply(A[0][1], B[1][1]))],
131
+ [EGPTMath.add(EGPTMath.multiply(A[1][0], B[0][0]), EGPTMath.multiply(A[1][1], B[1][0])),
132
+ EGPTMath.add(EGPTMath.multiply(A[1][0], B[0][1]), EGPTMath.multiply(A[1][1], B[1][1]))]
133
+ ];
134
+ display('K1 dense matMul rows-are-polynomials C = [[' + showVec(C[0]) + ',' + showVec(C[1]) + ']]');
135
+ check('K1 dense matMul via polynomial-system form matches reference', matricesEqual(C, Cref));
136
+ </cell>
137
+
138
+ <cell type="markdown">
139
+ ## U4 — iterated divide = polynomial GCD (shared factor)
140
+
141
+ Two polynomials f1, f2 both vanishing at 1/2; the Euclidean walk (iterated `divide`) recovers the monic gcd `x − 1/2` — the T3 resultant / M6 shared-factor view.
142
+ </cell>
143
+
144
+ <cell type="js" lane="math" id="u4" in="uhelp">
145
+ const { math, display } = caps;
146
+ const { EGPTPolynomial, EGPTReal } = math;
147
+ const { showVec, polyGCDMonic, frac } = inputs.uhelp;
148
+ const ZERO = EGPTReal.fromBigInt(0n);
149
+ const ONE = EGPTReal.fromBigInt(1n);
150
+ function check(label, cond) { display((cond ? ' ✓ ' : ' ✗ ') + label); if (!cond) throw new Error('U4 FAILED: ' + label); }
151
+ const f1 = [frac(1, 3), frac(-7, 6), ONE];
152
+ const f2 = [frac(1, 6), frac(-5, 6), ONE];
153
+ const g = polyGCDMonic(f1, f2);
154
+ display('U4 monic gcd(f1,f2) = ' + showVec(g) + ' (expected x − 1/2)');
155
+ check('gcd agrees with T3 resultant — exactly x − 1/2', g.length === 2 && g[0].equals(frac(-1, 2)) && g[1].equals(ONE));
156
+ check('gcd vanishes at the shared root 1/2', EGPTPolynomial.evaluateAt(g, frac(1, 2)).equals(ZERO));
157
+ </cell>
158
+
159
+ <cell type="markdown">
160
+ ## U5 / U6 / U7 — factor detection, order finding, all-lenses example
161
+
162
+ U5: roots of the atom-root polynomial of N=60 are exactly its prime factors. U6: the orbit polynomial of (3 mod 8) has degree = order. U7: N=15 — factoring, order finding, and A·I=A all run on the one engine.
163
+ </cell>
164
+
165
+ <cell type="js" lane="math" id="u567" in="uhelp">
166
+ const { math, display } = caps;
167
+ const { EGPTPolynomial, EGPTReal, PrimeAtomPolynomial, OrderFinder, matMul } = math;
168
+ const { showVec, matricesEqual, buildAtomRootPolynomial, buildOrbitPolynomial, intN } = inputs.uhelp;
169
+ const ZERO = EGPTReal.fromBigInt(0n);
170
+ function check(label, cond) { display((cond ? ' ✓ ' : ' ✗ ') + label); if (!cond) throw new Error('U5/6/7 FAILED: ' + label); }
171
+
172
+ // U5 — N=60
173
+ const N5 = 60n;
174
+ const P5 = buildAtomRootPolynomial(N5);
175
+ display('U5 P_60 = ' + showVec(P5));
176
+ for (const { prime } of PrimeAtomPolynomial.factorize(N5)) check(`P_60(${prime}) = 0 (N1/N2 coincide)`, EGPTPolynomial.evaluateAt(P5, intN(prime)).equals(ZERO));
177
+ check('P_60(7) ≠ 0 (7 is not a factor of 60)', !EGPTPolynomial.evaluateAt(P5, intN(7)).equals(ZERO));
178
+
179
+ // U6 — (3 mod 8)
180
+ const Q = buildOrbitPolynomial(3n, 8n);
181
+ const r = Number(OrderFinder.findOrder(3n, 8n));
182
+ display(`U6 orbit polynomial Q = ${showVec(Q)} order(3 mod 8) = ${r}`);
183
+ check(`deg(Q) = order(3 mod 8) = ${r} (N3 ≡ N4)`, EGPTPolynomial.degree(Q) === r);
184
+
185
+ // U7 — N=15, all lenses
186
+ const atomP = buildAtomRootPolynomial(15n);
187
+ const orbitP = buildOrbitPolynomial(7n, 15n);
188
+ const order = Number(OrderFinder.findOrder(7n, 15n));
189
+ const A = [[intN(1), intN(2)], [intN(3), intN(4)]];
190
+ const I = [[intN(1), intN(0)], [intN(0), intN(1)]];
191
+ const AI = matMul(A, I);
192
+ check('U7 N1/N2: prime 3 is a root of P_15', EGPTPolynomial.evaluateAt(atomP, intN(3)).equals(ZERO));
193
+ check('U7 N1/N2: prime 5 is a root of P_15', EGPTPolynomial.evaluateAt(atomP, intN(5)).equals(ZERO));
194
+ check('U7 N3/N4: orbit polynomial degree equals order(7 mod 15)', EGPTPolynomial.degree(orbitP) === order);
195
+ check('U7 T/K: A · I = A (one EGPTPolynomial.multiply)', matricesEqual(AI, A));
196
+ </cell>
197
+
198
+ <cell type="js" lane="math" id="u-qed">
199
+ const { display } = caps;
200
+ display('QED — one engine (EGPTPolynomial primitives), three lenses (number theory, linear algebra, signal processing).');
201
+ </cell>
202
+
203
+ </frqtl-notebook>