@descix/frqtl-node 0.0.0-stage → 0.6.0-p0.1

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 (217) hide show
  1. package/CLAUDE.md +87 -0
  2. package/README.md +84 -2
  3. package/dist/dist-manifest.json +218 -0
  4. package/dist/eyes/index.js +109 -0
  5. package/dist/fat/pkg-node/egpt_wasm.js +1277 -0
  6. package/dist/fat/pkg-node/egpt_wasm_bg.wasm +0 -0
  7. package/dist/fat/pkg-node/package.json +12 -0
  8. package/dist/frqtl/assets/vendor/chroma.mjs +64 -0
  9. package/dist/frqtl/compat/boot-node.js +34 -0
  10. package/dist/frqtl/compat/engine.js +127 -0
  11. package/dist/frqtl/compat/package-root.js +24 -0
  12. package/dist/frqtl/compat/providers/wasm-engine.js +2501 -0
  13. package/dist/frqtl/compat/providers/wasm-load-browser.js +134 -0
  14. package/dist/frqtl/compat/providers/wasm-load-node.js +59 -0
  15. package/dist/frqtl/compat/renderer/FieldBuilder.js +145 -0
  16. package/dist/frqtl/compat/renderer/Filters.js +163 -0
  17. package/dist/frqtl/compat/renderer/RenderFamily.js +85 -0
  18. package/dist/frqtl/compat/renderer/RenderMesh.js +100 -0
  19. package/dist/frqtl/compat/renderer/RenderShape.js +154 -0
  20. package/dist/frqtl/compat/renderer/camera2d-geometry.js +183 -0
  21. package/dist/frqtl/compat/renderer/captureStill-common.js +259 -0
  22. package/dist/frqtl/compat/renderer/display-slot.js +96 -0
  23. package/dist/frqtl/compat/renderer/lo-drawn-center.js +231 -0
  24. package/dist/frqtl/compat/renderer/orbit-bag.js +216 -0
  25. package/dist/frqtl/compat/renderer/providers/godrays-layer.js +213 -0
  26. package/dist/frqtl/compat/renderer/providers/index.js +22 -0
  27. package/dist/frqtl/compat/renderer/providers/p5-provider.js +861 -0
  28. package/dist/frqtl/compat/renderer/providers/three-camera-contract.js +160 -0
  29. package/dist/frqtl/compat/renderer/providers/three-camera-geometry.js +571 -0
  30. package/dist/frqtl/compat/renderer/providers/three-provider.js +2474 -0
  31. package/dist/frqtl/compat/renderer/renderCapabilities-common.js +186 -0
  32. package/dist/frqtl/compat/renderer/renderer-provider-contract.js +238 -0
  33. package/dist/frqtl/compat/renderer/unprojectStill.js +172 -0
  34. package/dist/frqtl/compat/vendor.js +196 -0
  35. package/dist/frqtl/node-entry.js +17 -0
  36. package/dist/frqtl/objects/FrqtlApp.js +2922 -0
  37. package/dist/frqtl/objects/ObjectFactory.js +297 -0
  38. package/dist/frqtl/objects/RecipeContext.js +322 -0
  39. package/dist/frqtl/objects/collectors/DataCollector.js +116 -0
  40. package/dist/frqtl/objects/constants/WallBehaviors.js +178 -0
  41. package/dist/frqtl/objects/geometry/SlabFace.js +258 -0
  42. package/dist/frqtl/objects/instruments/capture-host.js +453 -0
  43. package/dist/frqtl/objects/instruments/capture.js +711 -0
  44. package/dist/frqtl/objects/instruments/hosted-eyes.js +985 -0
  45. package/dist/frqtl/objects/kinds-entry.js +14 -0
  46. package/dist/frqtl/objects/kinds.js +190 -0
  47. package/dist/frqtl/objects/objects/Box.js +273 -0
  48. package/dist/frqtl/objects/objects/Bullet.js +155 -0
  49. package/dist/frqtl/objects/objects/CircuitGate.js +380 -0
  50. package/dist/frqtl/objects/objects/CircuitProbe.js +214 -0
  51. package/dist/frqtl/objects/objects/DirectedTunnel.js +412 -0
  52. package/dist/frqtl/objects/objects/EgptFractal.js +164 -0
  53. package/dist/frqtl/objects/objects/LightSource.js +354 -0
  54. package/dist/frqtl/objects/objects/QuantumEmitter.js +760 -0
  55. package/dist/frqtl/objects/objects/Tube.js +471 -0
  56. package/dist/frqtl/objects/objects/absorbRadiation.js +310 -0
  57. package/dist/frqtl/objects/objects/actionCompiler.js +1747 -0
  58. package/dist/frqtl/objects/objects/controlAction.js +89 -0
  59. package/dist/frqtl/objects/objects/controlBind.js +278 -0
  60. package/dist/frqtl/objects/objects/directedRedirectProgram.js +120 -0
  61. package/dist/frqtl/objects/objects/emitterProgram.js +209 -0
  62. package/dist/frqtl/objects/objects/frqtl-control-slider.js +197 -0
  63. package/dist/frqtl/objects/objects/frqtl-control-sync.js +272 -0
  64. package/dist/frqtl/objects/objects/frqtl-control-widgets.js +219 -0
  65. package/dist/frqtl/objects/objects/frqtl-control-write-queue.js +174 -0
  66. package/dist/frqtl/objects/objects/makeControlsForObject.js +824 -0
  67. package/dist/frqtl/objects/objects/makeControlsForRenderSurface.js +161 -0
  68. package/dist/frqtl/objects/objects/slitLinerScatter.js +263 -0
  69. package/dist/frqtl/objects/objects/sustainedSource.js +299 -0
  70. package/dist/frqtl/objects/objects/tagger.js +228 -0
  71. package/dist/frqtl/objects/schema/engine-scopes.js +469 -0
  72. package/dist/frqtl/objects/schema/index.js +256 -0
  73. package/dist/frqtl/objects/schema/scopes.js +457 -0
  74. package/dist/frqtl/objects/schema/validate-descriptor.js +49 -0
  75. package/dist/frqtl/objects/schema/valueNormalizer.js +366 -0
  76. package/dist/frqtl/objects/setup/_collisionMatrixLanes.js +66 -0
  77. package/dist/frqtl/objects/setup/_setupOptions.js +118 -0
  78. package/dist/frqtl/objects/setup/_worldInit.js +162 -0
  79. package/dist/frqtl/objects/setup/setupBlackbodySubstrate.js +242 -0
  80. package/dist/frqtl/objects/setup/setupCircuitBasic.js +447 -0
  81. package/dist/frqtl/objects/setup/setupCollisionMatrix.js +188 -0
  82. package/dist/frqtl/objects/setup/setupConeEmitter3D.js +251 -0
  83. package/dist/frqtl/objects/setup/setupDoubleSlit.js +327 -0
  84. package/dist/frqtl/objects/setup/setupDoubleSlit_Laser.js +229 -0
  85. package/dist/frqtl/objects/setup/setupEmpty.js +59 -0
  86. package/dist/frqtl/objects/setup/setupFxSmoke.js +209 -0
  87. package/dist/frqtl/objects/setup/setupG1Race.js +80 -0
  88. package/dist/frqtl/objects/setup/setupG2Sweep.js +89 -0
  89. package/dist/frqtl/objects/setup/setupG3Collide.js +177 -0
  90. package/dist/frqtl/objects/setup/setupLightSourceLab.js +280 -0
  91. package/dist/frqtl/objects/setup/setupOscillator.js +68 -0
  92. package/dist/frqtl/objects/setup/setupParticleWalk.js +93 -0
  93. package/dist/frqtl/objects/setup/setupParticleWalk3D.js +133 -0
  94. package/dist/frqtl/objects/setup/setupSphereEmitter3D.js +1259 -0
  95. package/dist/frqtl/objects/setup/setupTraceCircuit.js +239 -0
  96. package/dist/frqtl/objects/setup/setupTunnelLab.js +242 -0
  97. package/dist/frqtl/objects/setup/setupTunnelPointExit.js +306 -0
  98. package/dist/frqtl/objects/setup/setupWaveInterference.js +178 -0
  99. package/dist/frqtl/objects/v1-replacements.js +30 -0
  100. package/dist/frqtl/package-core.js +23 -0
  101. package/dist/frqtl/parts/CameraControls.js +643 -0
  102. package/dist/frqtl/parts/CameraPath.js +575 -0
  103. package/dist/frqtl/parts/CollisionActions.js +35 -0
  104. package/dist/frqtl/parts/CollisionTypes.js +31 -0
  105. package/dist/frqtl/parts/DetectorWall.js +496 -0
  106. package/dist/frqtl/parts/FrqtlControlOverlay.js +227 -0
  107. package/dist/frqtl/parts/FrqtlControlsPanel.js +415 -0
  108. package/dist/frqtl/parts/FrqtlVision.js +818 -0
  109. package/dist/frqtl/parts/GraphingDetectorWall.js +490 -0
  110. package/dist/frqtl/parts/LargeObject.js +406 -0
  111. package/dist/frqtl/parts/LightColor.js +255 -0
  112. package/dist/frqtl/parts/LiveChart.js +285 -0
  113. package/dist/frqtl/parts/LogicGate.js +720 -0
  114. package/dist/frqtl/parts/OvenBox.js +612 -0
  115. package/dist/frqtl/parts/PointSource.js +763 -0
  116. package/dist/frqtl/parts/Rectangle.js +200 -0
  117. package/dist/frqtl/parts/SlitLightSource.js +234 -0
  118. package/dist/frqtl/parts/SlitScreen.js +628 -0
  119. package/dist/frqtl/parts/SphereEmitter.js +946 -0
  120. package/dist/frqtl/parts/Trace.js +508 -0
  121. package/dist/frqtl/parts/Tunnel.js +1057 -0
  122. package/dist/frqtl/parts/Wall.js +1211 -0
  123. package/dist/frqtl/parts/index.js +33 -0
  124. package/dist/frqtl/scenes/absorbing-wall-3d.js +33 -0
  125. package/dist/frqtl/scenes/absorbing-wall.js +32 -0
  126. package/dist/frqtl/scenes/atomic-model.js +88 -0
  127. package/dist/frqtl/scenes/big-bang.js +46 -0
  128. package/dist/frqtl/scenes/blackbody.js +81 -0
  129. package/dist/frqtl/scenes/circuit-sat.js +127 -0
  130. package/dist/frqtl/scenes/collision-matrix-3d.js +107 -0
  131. package/dist/frqtl/scenes/counting-wall-3d.js +36 -0
  132. package/dist/frqtl/scenes/counting-wall.js +38 -0
  133. package/dist/frqtl/scenes/double-slit.js +31 -0
  134. package/dist/frqtl/scenes/dse-one-emitter.js +196 -0
  135. package/dist/frqtl/scenes/dse-one-slit.js +114 -0
  136. package/dist/frqtl/scenes/dse-photoelectric.js +70 -0
  137. package/dist/frqtl/scenes/dse-tunnel-rebuild.js +244 -0
  138. package/dist/frqtl/scenes/dse-two-emitters.js +196 -0
  139. package/dist/frqtl/scenes/dse-two-slits.js +132 -0
  140. package/dist/frqtl/scenes/empty.js +14 -0
  141. package/dist/frqtl/scenes/laser-buildup.js +49 -0
  142. package/dist/frqtl/scenes/mirror-3d.js +56 -0
  143. package/dist/frqtl/scenes/mirror-route.js +140 -0
  144. package/dist/frqtl/scenes/mirror.js +38 -0
  145. package/dist/frqtl/scenes/omni-3d.js +27 -0
  146. package/dist/frqtl/scenes/omni-source.js +22 -0
  147. package/dist/frqtl/scenes/self-interference.js +39 -0
  148. package/dist/frqtl/scenes/smoking-gun.js +122 -0
  149. package/dist/frqtl/scenes/straight-walk.js +22 -0
  150. package/dist/frqtl/scenes/sun.js +39 -0
  151. package/dist/frqtl/scenes/two-source.js +37 -0
  152. package/dist/frqtl/scenes/wave.js +26 -0
  153. package/dist/shim/bundle/frqnb.js +112 -0
  154. package/dist/shim/bundle/index.js +121 -0
  155. package/dist/shim/bundle/indexHtml.js +107 -0
  156. package/dist/shim/bundle/manifest.js +95 -0
  157. package/dist/shim/bundle/zip.js +243 -0
  158. package/dist/shim/bus.js +67 -0
  159. package/dist/shim/controls/index.js +627 -0
  160. package/dist/shim/controls/registry.js +274 -0
  161. package/dist/shim/engine/artifact-shell.js +212 -0
  162. package/dist/shim/engine/boot-phases.js +44 -0
  163. package/dist/shim/engine/engine-stack-boot.js +59 -0
  164. package/dist/shim/engine/router.js +692 -0
  165. package/dist/shim/experiment-frame/index.js +296 -0
  166. package/dist/shim/expr/ast-schema.js +369 -0
  167. package/dist/shim/field-descriptor/index.js +326 -0
  168. package/dist/shim/frame-data/index.js +224 -0
  169. package/dist/shim/index.js +67 -0
  170. package/dist/shim/notebook/canvas-guard.js +82 -0
  171. package/dist/shim/notebook/catalog.js +35 -0
  172. package/dist/shim/notebook/format.js +736 -0
  173. package/dist/shim/notebook/frqtl-setups-importmap.js +81 -0
  174. package/dist/shim/notebook/kernel.js +672 -0
  175. package/dist/shim/notebook/knob.js +151 -0
  176. package/dist/shim/notebook/module-resolver.js +260 -0
  177. package/dist/shim/notebook/notebook-knobs.js +65 -0
  178. package/dist/shim/notebook/produced-bindings.js +67 -0
  179. package/dist/shim/notebook/realm-registry.js +121 -0
  180. package/dist/shim/notebook/realm-transport.js +73 -0
  181. package/dist/shim/notebook/setup-builder.js +510 -0
  182. package/dist/shim/notebook/store.js +159 -0
  183. package/dist/shim/notebook/vendor-importmap.js +134 -0
  184. package/dist/shim/notebook/view-builder.js +189 -0
  185. package/dist/shim/notebook/view-ctx.js +100 -0
  186. package/dist/shim/notebook/view-handle.js +202 -0
  187. package/dist/shim/notebook/warmup.js +102 -0
  188. package/dist/shim/package.json +4 -0
  189. package/dist/shim/page-params/index.js +214 -0
  190. package/dist/shim/project/identity.js +112 -0
  191. package/dist/shim/project/index.js +19 -0
  192. package/dist/shim/project/link.js +402 -0
  193. package/dist/shim/project/node-specifier-hook.mjs +35 -0
  194. package/dist/shim/project/register-node.mjs +17 -0
  195. package/dist/shim/project/specifiers.js +106 -0
  196. package/dist/shim/registry/copy-gate.js +110 -0
  197. package/dist/shim/registry/exhibits.js +455 -0
  198. package/dist/shim/registry/experiments.js +215 -0
  199. package/dist/shim/registry/index.js +19 -0
  200. package/dist/shim/registry/scene-source.js +157 -0
  201. package/dist/shim/registry/walkthrough.js +807 -0
  202. package/dist/shim/render/capture-envelope.js +279 -0
  203. package/dist/shim/render/heat-colormap.js +92 -0
  204. package/dist/shim/render/render-stages.js +855 -0
  205. package/dist/shim/render/sun-look.js +33 -0
  206. package/dist/shim/render-state/apply.js +262 -0
  207. package/dist/shim/render-state/index.js +74 -0
  208. package/dist/shim/rpc/index.js +207 -0
  209. package/dist/shim/runtime/index.js +1023 -0
  210. package/dist/shim/storage/boot.js +69 -0
  211. package/dist/shim/storage/index.js +169 -0
  212. package/dist/shim/storage/local-storage-provider.js +230 -0
  213. package/dist/shim/storage/make-namespace-store.js +132 -0
  214. package/dist/shim/storage/modules.js +249 -0
  215. package/dist/shim/storage/projects.js +150 -0
  216. package/llms.txt +12 -0
  217. package/package.json +62 -4
@@ -0,0 +1,285 @@
1
+ /* Copyright 2023-2026 by Essam Abadir */
2
+
3
+ /**
4
+ * LiveChart — an in-scene live chart of a counting Wall's histogram: a NONE-collision, render-only
5
+ * LargeObject (zero physics, SU1) carrying a `chartSpec` bag and an empty `liveCanvas` ferry slot.
6
+ *
7
+ * var chart = exp.addObject(LiveChart, { source: 'screen', rect: [620, 40, 200, 140] });
8
+ *
9
+ * THE FACTORY SHAPE (Pixi's `Sprite.from`, Matter's `Bodies.rectangle`): `LiveChart` is a KIND TOKEN.
10
+ * Its registered build constructs the chart and returns it — a LargeObject (`chart instanceof
11
+ * LargeObject`, never `instanceof LiveChart`) stamped `_schemaKind = LiveChart.name`. Constructing
12
+ * the token itself (`new LiveChart()`) THROWS naming the declaration form. A fork that renames the
13
+ * class stamps its own kind, because the stamp reads the class name, never a literal.
14
+ *
15
+ * The chart is DRAWN by the host wiring (lib/components/live-chart-wiring), which renders Chart.js
16
+ * to an OFFSCREEN canvas and assigns it onto `lo.liveCanvas`; the providers composite that canvas
17
+ * natively (p5 image / three CanvasTexture). This part imports NO Chart.js — pure sugar below the shim.
18
+ */
19
+
20
+ import { LargeObject } from './LargeObject.js';
21
+ import { CollisionTypes } from './CollisionTypes.js';
22
+ import * as ValueNormalizer from '../objects/schema/valueNormalizer.js';
23
+ import { registerKind } from '../objects/kinds.js';
24
+
25
+ class LiveChart {
26
+ constructor() {
27
+ throw new Error('[LiveChart] LiveChart is a kind token — declare it with exp.addObject(LiveChart, props) ' +
28
+ '(or exp.addObject(\'LiveChart\', props)); its build returns the chart. (FAIL-LOUD.)');
29
+ }
30
+ }
31
+
32
+ // A "chart source" is any Wall facade exposing a between-tick read method the LiveChart
33
+ // wiring's projectors consume: getCollisionHistogram (detectorHistogram), getAbsorbStats
34
+ // (absorberStats) OR getLiveCount (liveCount). The build only needs to know a handle is
35
+ // PLAUSIBLE — the wiring (lib/components/live-chart-wiring PROJECTOR_SPEC, above the shim)
36
+ // owns the projector→method dispatch and surfaces projector/source mismatches at WIRE time
37
+ // (FAIL-LOUD).
38
+ function _isChartSource(obj) {
39
+ return !!obj && (typeof obj.getCollisionHistogram === 'function' ||
40
+ typeof obj.getAbsorbStats === 'function' ||
41
+ typeof obj.getLiveCount === 'function');
42
+ }
43
+
44
+ /** Resolve a chart source by NAME through the runner's declared registry (the ONE by-name
45
+ * authority — FrqtlApp.getObjectByName). Null when nothing declared matches; the caller
46
+ * decides whether that is FAIL-LOUD. */
47
+ function _resolveHistogramSource(runner, name) {
48
+ if (!runner || typeof runner.getObjectByName !== 'function') {
49
+ throw new Error('[ObjectFactory] a named LiveChart source resolves through runner.getObjectByName ' +
50
+ '(the declared-object registry); this runner has none. (FAIL-LOUD.)');
51
+ }
52
+ return runner.getObjectByName(name, _isChartSource);
53
+ }
54
+
55
+ // ── The kind (objects/kinds.js): descriptor, construction defaults, palette, builder ──────────
56
+
57
+ /**
58
+ * LiveChart — an IN-SCENE live chart of a counting Wall's running histogram.
59
+ * Modeled on BackdropDescriptor: a NONE-collision, render-only LargeObject
60
+ * (zero physics, SU1) that carries a `chartSpec` bag naming the source wall +
61
+ * projector. The Chart.js chart renders to an OFFSCREEN canvas (the ONE
62
+ * makeChartEnv authority, ABOVE the shim) and is ferried onto the LO's
63
+ * `liveCanvas` slot; the renderer wraps that canvas as a native drawable (p5
64
+ * image / three CanvasTexture) — Chart.js never enters a renderer.
65
+ *
66
+ * Unlike a Design-only emitter marker, a LiveChart is VISIBLE during Run — its
67
+ * entire value is accumulating on-screen while the sim runs (shellRender 'run').
68
+ * All fields are render-only (engineVisible:false).
69
+ */
70
+ var LiveChartDescriptor = {
71
+ description: 'An in-scene live chart panel that plots a counting Wall\'s running ' +
72
+ 'y→count histogram (getCollisionHistogram) as the sim runs. A render-only ' +
73
+ 'LargeObject (NONE collision, zero physics) — the Chart.js chart renders to an ' +
74
+ 'offscreen canvas and is composited into the scene as a texture/image, so it ' +
75
+ 'moves and scales with the scene. Point it at a detect/count Wall; a non-counting ' +
76
+ 'source fails loud.',
77
+ // STUDIO UX: a chart panel has a real draggable/resizable extent, and it is
78
+ // VISIBLE during Run (its whole point), so shellRender:'run' (NOT a Design-only
79
+ // marker). 2D drag; 3D reposition via the camera.
80
+ ux: {
81
+ resizable: true,
82
+ draggable: { '2d': true },
83
+ shellRender: 'run'
84
+ },
85
+ fields: [
86
+ {
87
+ name: 'rect',
88
+ type: 'rect',
89
+ engineVisible: false,
90
+ unit: 'px',
91
+ description: 'Placement + size of the chart panel in physics pixels ' + ValueNormalizer.rectTupleText(4) + '. Render-only — never a collision region.'
92
+ },
93
+ {
94
+ name: 'source',
95
+ type: 'string',
96
+ engineVisible: false,
97
+ description: 'Name of the source Wall that feeds this chart (a direct wall handle is ' +
98
+ 'also accepted at construction). For projector detectorHistogram: a detect/count ' +
99
+ 'wall (getCollisionHistogram). For projector absorberStats: an ABSORB wall ' +
100
+ '(getAbsorbStats). For projector liveCount: a count-hook wall (getLiveCount). ' +
101
+ 'A source lacking the projector\'s read method fails loud at wire time.'
102
+ },
103
+ {
104
+ name: 'projector',
105
+ type: 'enum',
106
+ constraint: { values: { detectorHistogram: 'detectorHistogram', absorberStats: 'absorberStats', liveCount: 'liveCount', detectorSurface: 'detectorSurface' } },
107
+ engineVisible: false,
108
+ description: 'The blessed live-chart projector to poll (default detectorHistogram). ' +
109
+ 'detectorHistogram = a counting Wall\'s y→count column-profile (fringes); ' +
110
+ 'absorberStats = an ABSORB Wall\'s {stored,absorbed,radiated} mass ledger; ' +
111
+ 'liveCount = a counting Wall\'s per-tick collided-frame count (a full-area ' +
112
+ 'background wall\'s live population); ' +
113
+ 'detectorSurface = the SAME counting Wall\'s hits binned over its FACE (y×z) ' +
114
+ 'and drawn as a topology heightfield — the 3D instrument, where a detector is ' +
115
+ 'a plane and the fringes read as ridges. ' +
116
+ 'One vocabulary, owned by live-chart-controller\'s LIVE_CHART_PROJECTORS.'
117
+ },
118
+ {
119
+ name: 'series',
120
+ type: 'enum',
121
+ constraint: { values: { bar: 'bar', line: 'line' } },
122
+ engineVisible: false,
123
+ description: 'Chart series kind: bar (default, a histogram) or line.'
124
+ },
125
+ {
126
+ name: 'orientation',
127
+ type: 'enum',
128
+ constraint: { values: { '0': '0', '90': '90' } },
129
+ engineVisible: false,
130
+ live: true,
131
+ description: 'Chart orientation in degrees. 0 = standard vertical bars (bins along x). ' +
132
+ '90 = the GYM detector-histogram presentation: HORIZONTAL bars stacked along y ' +
133
+ '(Chart.js indexAxis:y, y-axis reversed to run top-down) so a detector column-profile ' +
134
+ 'aligns SPATIALLY with the vertical detector wall beside it. Default: 90 for a ' +
135
+ 'detectorHistogram chart (detector-aligned), 0 otherwise. Live-editable in the Inspector.'
136
+ },
137
+ {
138
+ name: 'label',
139
+ type: 'string',
140
+ engineVisible: false,
141
+ description: 'Dataset label shown in the chart legend (default = the source name).'
142
+ },
143
+ {
144
+ name: 'refreshMs',
145
+ type: 'number',
146
+ constraint: { min: 16, integer: true },
147
+ engineVisible: false,
148
+ unit: 'ms',
149
+ description: 'Redraw cadence in ms (default 100 → ~10 fps). Caps Chart.js redraw cost ' +
150
+ 'regardless of tick rate; accumulation still runs EVERY tick (no dropped counts).'
151
+ },
152
+ {
153
+ name: 'visible',
154
+ type: 'boolean',
155
+ engineVisible: false,
156
+ live: true,
157
+ description: 'Whether the chart panel is rendered (render-only).'
158
+ },
159
+ {
160
+ name: 'alpha',
161
+ type: 'number',
162
+ constraint: { min: 0, max: 255, integer: true },
163
+ engineVisible: false,
164
+ live: true,
165
+ widgetHint: 'slider',
166
+ description: 'Render opacity 0-255 (render-only).'
167
+ }
168
+ ]
169
+ };
170
+
171
+ //
172
+ // An in-scene live chart of a counting Wall's histogram (the C-workstream visual
173
+ // sugar object). Builds a NONE-collision, render-only LargeObject (zero physics,
174
+ // SU1 — like a backdrop) carrying a `chartSpec` bag + an empty `liveCanvas` ferry
175
+ // slot. The chart is DRAWN by the host wiring (lib/components/live-chart-wiring),
176
+ // which renders Chart.js to an OFFSCREEN canvas and assigns it onto lo.liveCanvas;
177
+ // the providers composite that canvas natively (p5 image / three CanvasTexture).
178
+ // The object imports NO Chart.js — it stays pure sugar below the shim.
179
+ //
180
+ // `source` accepts a direct counting-Wall handle (getCollisionHistogram) OR its
181
+ // name string. A named source is resolved here at build time — MISSING → THROW
182
+ // (FAIL-LOUD build-time). The count-hook validity (a detect/count wall) is surfaced
183
+ // at WIRE time by letting Wall.getCollisionHistogram's own throw propagate.
184
+ registerKind(LiveChart, {
185
+ from: import.meta.url,
186
+ descriptor: LiveChartDescriptor,
187
+ defaults: {
188
+ w: 200,
189
+ h: 140,
190
+ projector: 'detectorHistogram',
191
+ series: 'bar',
192
+ refreshMs: 100,
193
+ color: [30, 40, 55]
194
+ },
195
+ palette: { displayName: 'Live Chart', category: 'measurement', iconHint: 'chart', rank: 4 },
196
+ build: function (props, ctx, Class) {
197
+ var LO = LargeObject;
198
+ var CT = CollisionTypes;
199
+
200
+ // Rect: an explicit rect (array [l,t,w,h] / [l,t,z,w,h,d] OR object {left,top,w,h})
201
+ // wins; else center a default panel on the drop point (ctx.x/ctx.y).
202
+ var _r = props.rect;
203
+ var cw, ch, cl, ct;
204
+ if (Array.isArray(_r)) {
205
+ if (_r.length >= 6) { cl = _r[0]; ct = _r[1]; cw = _r[3]; ch = _r[4]; }
206
+ else { cl = _r[0]; ct = _r[1]; cw = _r[2]; ch = _r[3]; }
207
+ } else if (_r && _r.left != null) {
208
+ cl = _r.left; ct = _r.top; cw = _r.w; ch = _r.h;
209
+ } else {
210
+ cw = props.w || 200;
211
+ ch = props.h || 140;
212
+ cl = Math.round(ctx.x - cw / 2);
213
+ ct = Math.round(ctx.y - ch / 2);
214
+ }
215
+ var name = props.name || ('livechart ' + (ctx.runner.largeObjects.length + 1));
216
+ var color = props.color || [30, 40, 55];
217
+
218
+ var lo = new LO(ctx.runner.universe, [cl, ct, cw, ch], CT.NONE, [], name,
219
+ 'closest', null, 1, color);
220
+ if (props.alpha != null) { lo.alpha = props.alpha; }
221
+ if (props.visible != null) { lo.visible = props.visible; }
222
+ lo._schemaKind = Class.name; // a LargeObject on purpose, stamped with the registered kind
223
+
224
+ // Resolve the source (handle | name | unbound).
225
+ var source = props.source;
226
+ var sourceHandle = null, sourceName = null;
227
+ if (source && typeof source === 'object' && _isChartSource(source)) {
228
+ sourceHandle = source;
229
+ sourceName = (typeof source.name === 'string') ? source.name : null;
230
+ } else if (typeof source === 'string' && source) {
231
+ sourceName = source;
232
+ sourceHandle = _resolveHistogramSource(ctx.runner, source);
233
+ if (!sourceHandle) {
234
+ throw new Error('[ObjectFactory] LiveChart source wall "' + source +
235
+ '" not found among the registered objects — a LiveChart must be pointed ' +
236
+ 'at an already-added counting/absorbing Wall (by name or handle). (FAIL-LOUD.)');
237
+ }
238
+ } else if (source != null) {
239
+ throw new Error('[ObjectFactory] LiveChart `source` must be a Wall handle ' +
240
+ '(exposing getCollisionHistogram or getAbsorbStats) or its name string; got ' +
241
+ typeof source + '. (FAIL-LOUD.)');
242
+ }
243
+ // source == null → an unbound chart (bare palette drop); the host wiring skips
244
+ // it until a source is set (it draws its empty panel shell meanwhile).
245
+
246
+ var projector = props.projector || 'detectorHistogram';
247
+ // Orientation: explicit 0|90 wins; else DEFAULT a detectorHistogram chart to 90 (the
248
+ // GYM detector-aligned horizontal-bar presentation — a detector column-profile stacks
249
+ // along y beside the vertical detector wall), any other projector (e.g. absorberStats,
250
+ // a 3-bar ledger) to 0 (standard vertical bars). CEO ruling 2026-07-24 (Living Log df36a229).
251
+ var orientation;
252
+ if (props.orientation === 90 || props.orientation === '90') { orientation = 90; }
253
+ else if (props.orientation === 0 || props.orientation === '0') { orientation = 0; }
254
+ else { orientation = (projector === 'detectorHistogram') ? 90 : 0; }
255
+ // Mirror onto the LO wrapper as the render-only, Inspector-live field (updateObjectProperty
256
+ // mirror-writes lo.orientation); the wiring reads it live with a chartSpec fallback.
257
+ lo.orientation = String(orientation);
258
+
259
+ lo.chartSpec = {
260
+ source: sourceName, // serializable name (or null)
261
+ sourceHandle: sourceHandle, // resolved handle (runtime only; or null)
262
+ projector: projector,
263
+ kind: (props.series === 'line') ? 'line' : 'bar',
264
+ label: props.label || sourceName || 'detector',
265
+ refreshMs: (typeof props.refreshMs === 'number') ? props.refreshMs : 100,
266
+ orientation: orientation // 0 | 90 (numeric default; lo.orientation is the live source)
267
+ };
268
+ // Mirror the SERIALIZABLE chartSpec fields onto the LO under their DESCRIPTOR
269
+ // names (restart-bug fix, 2026-07-25): captureProps(lo, LiveChartDescriptor)
270
+ // reads lo[field.name], so without these mirrors a codegen round-trip (Save /
271
+ // Restart evals the generated module) silently rebuilt every chart UNBOUND
272
+ // with default projector/label ("detector"). The name string — never the live
273
+ // sourceHandle — is the captured source (re-resolved here on rebuild).
274
+ lo.source = sourceName;
275
+ lo.projector = projector;
276
+ lo.series = lo.chartSpec.kind;
277
+ lo.label = lo.chartSpec.label;
278
+ lo.refreshMs = lo.chartSpec.refreshMs;
279
+ lo.liveCanvas = null; // empty ferry slot — the host wiring assigns the rendered canvas
280
+
281
+ return lo;
282
+ }
283
+ });
284
+
285
+ export { LiveChart };