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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. package/CLAUDE.md +87 -0
  2. package/LICENSE.md +664 -0
  3. package/README.md +84 -2
  4. package/dist/dist-manifest.json +218 -0
  5. package/dist/eyes/index.js +109 -0
  6. package/dist/fat/pkg-node/egpt_wasm.js +1277 -0
  7. package/dist/fat/pkg-node/egpt_wasm_bg.wasm +0 -0
  8. package/dist/fat/pkg-node/package.json +12 -0
  9. package/dist/frqtl/assets/vendor/chroma.mjs +64 -0
  10. package/dist/frqtl/compat/boot-node.js +34 -0
  11. package/dist/frqtl/compat/engine.js +127 -0
  12. package/dist/frqtl/compat/package-root.js +24 -0
  13. package/dist/frqtl/compat/providers/wasm-engine.js +2499 -0
  14. package/dist/frqtl/compat/providers/wasm-load-browser.js +134 -0
  15. package/dist/frqtl/compat/providers/wasm-load-node.js +59 -0
  16. package/dist/frqtl/compat/renderer/FieldBuilder.js +145 -0
  17. package/dist/frqtl/compat/renderer/Filters.js +163 -0
  18. package/dist/frqtl/compat/renderer/RenderFamily.js +84 -0
  19. package/dist/frqtl/compat/renderer/RenderMesh.js +99 -0
  20. package/dist/frqtl/compat/renderer/RenderShape.js +154 -0
  21. package/dist/frqtl/compat/renderer/camera2d-geometry.js +183 -0
  22. package/dist/frqtl/compat/renderer/captureStill-common.js +258 -0
  23. package/dist/frqtl/compat/renderer/display-slot.js +96 -0
  24. package/dist/frqtl/compat/renderer/lo-drawn-center.js +231 -0
  25. package/dist/frqtl/compat/renderer/orbit-bag.js +216 -0
  26. package/dist/frqtl/compat/renderer/providers/godrays-layer.js +213 -0
  27. package/dist/frqtl/compat/renderer/providers/index.js +22 -0
  28. package/dist/frqtl/compat/renderer/providers/p5-provider.js +861 -0
  29. package/dist/frqtl/compat/renderer/providers/three-camera-contract.js +160 -0
  30. package/dist/frqtl/compat/renderer/providers/three-camera-geometry.js +571 -0
  31. package/dist/frqtl/compat/renderer/providers/three-provider.js +2470 -0
  32. package/dist/frqtl/compat/renderer/renderCapabilities-common.js +186 -0
  33. package/dist/frqtl/compat/renderer/renderer-provider-contract.js +238 -0
  34. package/dist/frqtl/compat/renderer/unprojectStill.js +172 -0
  35. package/dist/frqtl/compat/vendor.js +196 -0
  36. package/dist/frqtl/node-entry.js +17 -0
  37. package/dist/frqtl/objects/FrqtlApp.js +2920 -0
  38. package/dist/frqtl/objects/ObjectFactory.js +296 -0
  39. package/dist/frqtl/objects/RecipeContext.js +322 -0
  40. package/dist/frqtl/objects/collectors/DataCollector.js +116 -0
  41. package/dist/frqtl/objects/constants/WallBehaviors.js +178 -0
  42. package/dist/frqtl/objects/geometry/SlabFace.js +258 -0
  43. package/dist/frqtl/objects/instruments/capture-host.js +453 -0
  44. package/dist/frqtl/objects/instruments/capture.js +710 -0
  45. package/dist/frqtl/objects/instruments/hosted-eyes.js +984 -0
  46. package/dist/frqtl/objects/kinds-entry.js +14 -0
  47. package/dist/frqtl/objects/kinds.js +190 -0
  48. package/dist/frqtl/objects/objects/Box.js +273 -0
  49. package/dist/frqtl/objects/objects/Bullet.js +155 -0
  50. package/dist/frqtl/objects/objects/CircuitGate.js +380 -0
  51. package/dist/frqtl/objects/objects/CircuitProbe.js +214 -0
  52. package/dist/frqtl/objects/objects/DirectedTunnel.js +411 -0
  53. package/dist/frqtl/objects/objects/EgptFractal.js +164 -0
  54. package/dist/frqtl/objects/objects/LightSource.js +351 -0
  55. package/dist/frqtl/objects/objects/QuantumEmitter.js +760 -0
  56. package/dist/frqtl/objects/objects/Tube.js +471 -0
  57. package/dist/frqtl/objects/objects/absorbRadiation.js +309 -0
  58. package/dist/frqtl/objects/objects/actionCompiler.js +1747 -0
  59. package/dist/frqtl/objects/objects/controlAction.js +89 -0
  60. package/dist/frqtl/objects/objects/controlBind.js +278 -0
  61. package/dist/frqtl/objects/objects/directedRedirectProgram.js +120 -0
  62. package/dist/frqtl/objects/objects/emitterProgram.js +209 -0
  63. package/dist/frqtl/objects/objects/frqtl-control-slider.js +197 -0
  64. package/dist/frqtl/objects/objects/frqtl-control-sync.js +272 -0
  65. package/dist/frqtl/objects/objects/frqtl-control-widgets.js +219 -0
  66. package/dist/frqtl/objects/objects/frqtl-control-write-queue.js +174 -0
  67. package/dist/frqtl/objects/objects/makeControlsForObject.js +820 -0
  68. package/dist/frqtl/objects/objects/makeControlsForRenderSurface.js +161 -0
  69. package/dist/frqtl/objects/objects/slitLinerScatter.js +261 -0
  70. package/dist/frqtl/objects/objects/sustainedSource.js +298 -0
  71. package/dist/frqtl/objects/objects/tagger.js +228 -0
  72. package/dist/frqtl/objects/schema/engine-scopes.js +468 -0
  73. package/dist/frqtl/objects/schema/index.js +256 -0
  74. package/dist/frqtl/objects/schema/scopes.js +457 -0
  75. package/dist/frqtl/objects/schema/validate-descriptor.js +49 -0
  76. package/dist/frqtl/objects/schema/valueNormalizer.js +366 -0
  77. package/dist/frqtl/objects/setup/_collisionMatrixLanes.js +66 -0
  78. package/dist/frqtl/objects/setup/_setupOptions.js +118 -0
  79. package/dist/frqtl/objects/setup/_worldInit.js +162 -0
  80. package/dist/frqtl/objects/setup/setupBlackbodySubstrate.js +242 -0
  81. package/dist/frqtl/objects/setup/setupCircuitBasic.js +447 -0
  82. package/dist/frqtl/objects/setup/setupCollisionMatrix.js +188 -0
  83. package/dist/frqtl/objects/setup/setupConeEmitter3D.js +250 -0
  84. package/dist/frqtl/objects/setup/setupDoubleSlit.js +326 -0
  85. package/dist/frqtl/objects/setup/setupDoubleSlit_Laser.js +229 -0
  86. package/dist/frqtl/objects/setup/setupEmpty.js +59 -0
  87. package/dist/frqtl/objects/setup/setupFxSmoke.js +209 -0
  88. package/dist/frqtl/objects/setup/setupG1Race.js +80 -0
  89. package/dist/frqtl/objects/setup/setupG2Sweep.js +89 -0
  90. package/dist/frqtl/objects/setup/setupG3Collide.js +177 -0
  91. package/dist/frqtl/objects/setup/setupLightSourceLab.js +277 -0
  92. package/dist/frqtl/objects/setup/setupOscillator.js +68 -0
  93. package/dist/frqtl/objects/setup/setupParticleWalk.js +93 -0
  94. package/dist/frqtl/objects/setup/setupParticleWalk3D.js +133 -0
  95. package/dist/frqtl/objects/setup/setupSphereEmitter3D.js +1258 -0
  96. package/dist/frqtl/objects/setup/setupTraceCircuit.js +239 -0
  97. package/dist/frqtl/objects/setup/setupTunnelLab.js +240 -0
  98. package/dist/frqtl/objects/setup/setupTunnelPointExit.js +306 -0
  99. package/dist/frqtl/objects/setup/setupWaveInterference.js +177 -0
  100. package/dist/frqtl/objects/v1-replacements.js +29 -0
  101. package/dist/frqtl/package-core.js +23 -0
  102. package/dist/frqtl/parts/CameraControls.js +643 -0
  103. package/dist/frqtl/parts/CameraPath.js +575 -0
  104. package/dist/frqtl/parts/CollisionActions.js +34 -0
  105. package/dist/frqtl/parts/CollisionTypes.js +30 -0
  106. package/dist/frqtl/parts/DetectorWall.js +496 -0
  107. package/dist/frqtl/parts/FrqtlControlOverlay.js +227 -0
  108. package/dist/frqtl/parts/FrqtlControlsPanel.js +415 -0
  109. package/dist/frqtl/parts/FrqtlVision.js +818 -0
  110. package/dist/frqtl/parts/GraphingDetectorWall.js +489 -0
  111. package/dist/frqtl/parts/LargeObject.js +405 -0
  112. package/dist/frqtl/parts/LightColor.js +255 -0
  113. package/dist/frqtl/parts/LiveChart.js +285 -0
  114. package/dist/frqtl/parts/LogicGate.js +717 -0
  115. package/dist/frqtl/parts/OvenBox.js +611 -0
  116. package/dist/frqtl/parts/PointSource.js +762 -0
  117. package/dist/frqtl/parts/Rectangle.js +200 -0
  118. package/dist/frqtl/parts/SlitLightSource.js +234 -0
  119. package/dist/frqtl/parts/SlitScreen.js +628 -0
  120. package/dist/frqtl/parts/SphereEmitter.js +946 -0
  121. package/dist/frqtl/parts/Trace.js +508 -0
  122. package/dist/frqtl/parts/Tunnel.js +1057 -0
  123. package/dist/frqtl/parts/Wall.js +1211 -0
  124. package/dist/frqtl/parts/index.js +33 -0
  125. package/dist/frqtl/scenes/absorbing-wall-3d.js +33 -0
  126. package/dist/frqtl/scenes/absorbing-wall.js +32 -0
  127. package/dist/frqtl/scenes/atomic-model.js +88 -0
  128. package/dist/frqtl/scenes/big-bang.js +46 -0
  129. package/dist/frqtl/scenes/blackbody.js +81 -0
  130. package/dist/frqtl/scenes/circuit-sat.js +127 -0
  131. package/dist/frqtl/scenes/collision-matrix-3d.js +107 -0
  132. package/dist/frqtl/scenes/counting-wall-3d.js +36 -0
  133. package/dist/frqtl/scenes/counting-wall.js +38 -0
  134. package/dist/frqtl/scenes/double-slit.js +31 -0
  135. package/dist/frqtl/scenes/dse-one-emitter.js +196 -0
  136. package/dist/frqtl/scenes/dse-one-slit.js +114 -0
  137. package/dist/frqtl/scenes/dse-photoelectric.js +70 -0
  138. package/dist/frqtl/scenes/dse-tunnel-rebuild.js +243 -0
  139. package/dist/frqtl/scenes/dse-two-emitters.js +196 -0
  140. package/dist/frqtl/scenes/dse-two-slits.js +132 -0
  141. package/dist/frqtl/scenes/empty.js +14 -0
  142. package/dist/frqtl/scenes/laser-buildup.js +49 -0
  143. package/dist/frqtl/scenes/mirror-3d.js +56 -0
  144. package/dist/frqtl/scenes/mirror-route.js +140 -0
  145. package/dist/frqtl/scenes/mirror.js +38 -0
  146. package/dist/frqtl/scenes/omni-3d.js +27 -0
  147. package/dist/frqtl/scenes/omni-source.js +22 -0
  148. package/dist/frqtl/scenes/self-interference.js +39 -0
  149. package/dist/frqtl/scenes/smoking-gun.js +122 -0
  150. package/dist/frqtl/scenes/straight-walk.js +22 -0
  151. package/dist/frqtl/scenes/sun.js +39 -0
  152. package/dist/frqtl/scenes/two-source.js +37 -0
  153. package/dist/frqtl/scenes/wave.js +26 -0
  154. package/dist/shim/bundle/frqnb.js +112 -0
  155. package/dist/shim/bundle/index.js +121 -0
  156. package/dist/shim/bundle/indexHtml.js +107 -0
  157. package/dist/shim/bundle/manifest.js +95 -0
  158. package/dist/shim/bundle/zip.js +243 -0
  159. package/dist/shim/bus.js +67 -0
  160. package/dist/shim/controls/index.js +627 -0
  161. package/dist/shim/controls/registry.js +274 -0
  162. package/dist/shim/engine/artifact-shell.js +211 -0
  163. package/dist/shim/engine/boot-phases.js +44 -0
  164. package/dist/shim/engine/engine-stack-boot.js +59 -0
  165. package/dist/shim/engine/router.js +690 -0
  166. package/dist/shim/experiment-frame/index.js +296 -0
  167. package/dist/shim/expr/ast-schema.js +369 -0
  168. package/dist/shim/field-descriptor/index.js +325 -0
  169. package/dist/shim/frame-data/index.js +224 -0
  170. package/dist/shim/index.js +67 -0
  171. package/dist/shim/notebook/canvas-guard.js +82 -0
  172. package/dist/shim/notebook/catalog.js +35 -0
  173. package/dist/shim/notebook/format.js +736 -0
  174. package/dist/shim/notebook/frqtl-setups-importmap.js +81 -0
  175. package/dist/shim/notebook/kernel.js +671 -0
  176. package/dist/shim/notebook/knob.js +150 -0
  177. package/dist/shim/notebook/module-resolver.js +260 -0
  178. package/dist/shim/notebook/notebook-knobs.js +65 -0
  179. package/dist/shim/notebook/produced-bindings.js +67 -0
  180. package/dist/shim/notebook/realm-registry.js +121 -0
  181. package/dist/shim/notebook/realm-transport.js +73 -0
  182. package/dist/shim/notebook/setup-builder.js +507 -0
  183. package/dist/shim/notebook/store.js +159 -0
  184. package/dist/shim/notebook/vendor-importmap.js +134 -0
  185. package/dist/shim/notebook/view-builder.js +189 -0
  186. package/dist/shim/notebook/view-ctx.js +100 -0
  187. package/dist/shim/notebook/view-handle.js +202 -0
  188. package/dist/shim/notebook/warmup.js +102 -0
  189. package/dist/shim/package.json +4 -0
  190. package/dist/shim/page-params/index.js +213 -0
  191. package/dist/shim/project/identity.js +112 -0
  192. package/dist/shim/project/index.js +19 -0
  193. package/dist/shim/project/link.js +402 -0
  194. package/dist/shim/project/node-specifier-hook.mjs +35 -0
  195. package/dist/shim/project/register-node.mjs +17 -0
  196. package/dist/shim/project/specifiers.js +106 -0
  197. package/dist/shim/registry/copy-gate.js +110 -0
  198. package/dist/shim/registry/exhibits.js +455 -0
  199. package/dist/shim/registry/experiments.js +215 -0
  200. package/dist/shim/registry/index.js +19 -0
  201. package/dist/shim/registry/scene-source.js +157 -0
  202. package/dist/shim/registry/walkthrough.js +804 -0
  203. package/dist/shim/render/capture-envelope.js +279 -0
  204. package/dist/shim/render/heat-colormap.js +92 -0
  205. package/dist/shim/render/render-stages.js +855 -0
  206. package/dist/shim/render/sun-look.js +33 -0
  207. package/dist/shim/render-state/apply.js +262 -0
  208. package/dist/shim/render-state/index.js +74 -0
  209. package/dist/shim/rpc/index.js +207 -0
  210. package/dist/shim/runtime/index.js +1023 -0
  211. package/dist/shim/storage/boot.js +69 -0
  212. package/dist/shim/storage/index.js +169 -0
  213. package/dist/shim/storage/local-storage-provider.js +230 -0
  214. package/dist/shim/storage/make-namespace-store.js +132 -0
  215. package/dist/shim/storage/modules.js +249 -0
  216. package/dist/shim/storage/projects.js +150 -0
  217. package/llms.txt +12 -0
  218. package/package.json +63 -4
@@ -0,0 +1,325 @@
1
+ /* Copyright 2023-2026 by Essam Abadir */
2
+
3
+ /**
4
+ * lib/shim/field-descriptor — the shared FIELD-SHAPE vocabulary contract.
5
+ *
6
+ * Studio Controls Realignment §7 r2, C1: a single FIELD shape — `{name, type, constraint, unit,
7
+ * description, engineVisible, widgetHint, widgetConfig, default}` — and its
8
+ * closed TYPE vocabulary were about to be re-derived THREE times (physics
9
+ * object schema, the new render-capability descriptors, and a future Rosetta
10
+ * `paramsSchema`) instead of owned once. This module is that ONE owner — the
11
+ * peer of `lib/shim/controls` (which owns the CONTROL-descriptor shape one
12
+ * layer up) and `lib/shim/frame-data` (which owns the data-bubble shape) —
13
+ * same layout convention (closed vocabulary + a throw-or-apply `normalize`,
14
+ * named ES-module exports).
15
+ *
16
+ * ── Why this exists ──────────────────────────────────────────────────────────
17
+ *
18
+ * `lib/frqtl/objects/schema/index.js` (`ObjectSchema`) already declares
19
+ * ~200 fields across 16 kinds using EXACTLY this shape, documented only as a
20
+ * comment block (`type:'rect' → …`, `type:'rgb' → …`, …). Separately,
21
+ * `lib/frqtl/objects/objects/makeControlsForObject.js`'s `TYPE_DISPATCH` map
22
+ * independently enumerates the SAME 12 field types as its object keys — two
23
+ * hand-written lists that happen to agree today but have no shared owner
24
+ * enforcing that they always will (the exact schema-mirror-drift class root
25
+ * `CLAUDE.md` §Engineering Culture calls out: "the same data breaks in one
26
+ * consumer but not another"). `renderCapabilities()` (S5a item 2,
27
+ * `lib/frqtl/compat/renderer/providers/{p5,three}-provider.js`) needed the
28
+ * SAME field shape for a THIRD surface — the trigger for this extraction.
29
+ *
30
+ * ── Scope ─────────────────────────────────────────────────────────────────
31
+ *
32
+ * This module owns:
33
+ * - `FIELD_TYPES` — the closed field-TYPE vocabulary (12 members,
34
+ * mechanically identical to `ObjectSchema`'s documented comment list AND
35
+ * `makeControlsForObject.js`'s `TYPE_DISPATCH` keys — see the drift test).
36
+ * - `FIELD_ENVELOPE_KEYS` — the field-SHAPE envelope key list (documentation/
37
+ * introspection use — NOT a required-keys gate; most fields omit most of
38
+ * these optional keys, only `name`/`type`/`description` are mandatory).
39
+ * - `normalizeFieldDescriptor(partial)` — throw-or-apply validation of ONE
40
+ * field descriptor's envelope (name/type/description required; constraint/
41
+ * unit/engineVisible/widgetHint/widgetConfig/default validated IF present).
42
+ *
43
+ * This module does NOT:
44
+ * - Re-list or replace `ObjectSchema`'s ~200 existing per-kind field arrays —
45
+ * those stay EXACTLY as authored (byte-identical); `ObjectSchema` merely
46
+ * IMPORTS `FIELD_TYPES` from here to assert (at load time) that every field
47
+ * it declares uses a member of the ONE vocabulary, instead of hand-copying
48
+ * the type list into its own comment block as the only enforcement.
49
+ * - Replace `lib/shim/controls`'s CONTROL-descriptor shape (`{kind, id, label,
50
+ * min, max, step, value, fmt, onChange, bind, channel}`) — that is a
51
+ * DIFFERENT, downstream shape (a UI/live-knob descriptor), consumed by a
52
+ * factory that READS field descriptors of THIS shape and EMITS control
53
+ * descriptors of THAT shape. The two are peers, not the same contract.
54
+ *
55
+ * Usage:
56
+ * import { FIELD_TYPES, normalizeFieldDescriptor } from 'lib/shim/field-descriptor/index.js';
57
+ * var f = normalizeFieldDescriptor({
58
+ * name: 'godrays', type: 'number', unit: 'intensity',
59
+ * constraint: { min: 0, max: 3 }, default: 0,
60
+ * description: 'God-rays post-process intensity (render-only).'
61
+ * });
62
+ */
63
+
64
+
65
+
66
+ // ── Field type vocabulary (closed, 12 members) ──────────────────────────────
67
+ //
68
+ // Mechanically identical to the set actually used across ObjectSchema's field
69
+ // declarations (lib/frqtl/objects/schema/index.js) and
70
+ // makeControlsForObject.js's TYPE_DISPATCH keys — verified exhaustively by
71
+ // lib/shim/field-descriptor/test/field-descriptor.test.mjs's drift assertion.
72
+ // Adding a 13th type is a THREE-PLACE change (here, TYPE_DISPATCH, and any
73
+ // descriptor that uses it) — the drift test makes forgetting one of the three
74
+ // a CI failure rather than a silent runtime gap.
75
+ //
76
+ // number — numeric scalar; constraint: { min?, max?, integer? }
77
+ // boolean — true | false
78
+ // string — free string
79
+ // enum — one value from constraint.values object
80
+ // enum-set — array of zero or more values from constraint.values object
81
+ // rgb — [r, g, b] (0-255 integers)
82
+ // rect — { left, top, w, h } (+ optional z, d — WASM-only)
83
+ // rect-array — array of rect-shaped tuples
84
+ // readonly — derived/computed: inspectable but not editable
85
+ // forbidden — engine-owned topology: any write attempt throws
86
+ // object — an arbitrary structured bag (e.g. an op-program)
87
+ // writable — Frame-kind-only ACCESS-LEVEL tag (the actual value type is
88
+ // inferred from the live read — number/boolean/string/object)
89
+ var FIELD_TYPES = Object.freeze([
90
+ 'number', 'boolean', 'string', 'enum', 'enum-set',
91
+ 'rgb', 'rect', 'rect-array', 'readonly', 'forbidden',
92
+ 'object', 'writable'
93
+ ]);
94
+
95
+ // ── Field envelope keys (documentation/introspection — NOT a required list) ─
96
+ //
97
+ // Every field descriptor MAY carry these keys; only name/type/description are
98
+ // mandatory (validated by normalizeFieldDescriptor below). `default` is the
99
+ // C1 addition renderCapabilities() descriptors need (a physics ObjectSchema
100
+ // field's live value comes from the constructed object instead — `default`
101
+ // was rarely populated there and stays optional here for that reason).
102
+ var FIELD_ENVELOPE_KEYS = Object.freeze([
103
+ 'name', 'type', 'constraint', 'unit', 'description',
104
+ 'engineVisible', 'widgetHint', 'widgetConfig', 'default'
105
+ ]);
106
+
107
+ function _isStr(v) { return typeof v === 'string' && v.length > 0; }
108
+ function _isPlainObject(v) { return v !== null && typeof v === 'object' && !Array.isArray(v); }
109
+
110
+ function _fail(name, msg) {
111
+ throw new Error('[lib/shim/field-descriptor] normalizeFieldDescriptor(name="' + String(name) +
112
+ '"): ' + msg + ' (FAIL-LOUD — throw-or-apply, never silently dropped/defaulted-around.)');
113
+ }
114
+
115
+ /**
116
+ * normalizeFieldDescriptor(partial) → full bag.
117
+ *
118
+ * THROW-OR-APPLY: a malformed field descriptor throws here — never silently
119
+ * dropped or coerced. Mandatory: `name` (non-empty string), `type` (member of
120
+ * FIELD_TYPES), `description` (non-empty string — every ObjectSchema field
121
+ * already carries one; see schema.test.mjs assertion (a)). Optional, validated
122
+ * IF present: `unit` (string), `constraint`/`widgetConfig` (plain object),
123
+ * `engineVisible` (boolean), `widgetHint` (string). `default` accepts ANY
124
+ * value (its shape depends on `type` — a number, a string, an array for rgb/
125
+ * rect, …) so it is NOT type-checked here.
126
+ *
127
+ * @param {object} partial
128
+ * @returns {object} a NEW object (input never mutated) carrying every input
129
+ * key verbatim.
130
+ * @throws {Error} FAIL-LOUD on a missing/empty `name`, an unrecognized `type`,
131
+ * a missing/empty `description`, or a mistyped optional key.
132
+ */
133
+ function normalizeFieldDescriptor(partial) {
134
+ if (!partial || typeof partial !== 'object') {
135
+ throw new Error('[lib/shim/field-descriptor] normalizeFieldDescriptor requires a field ' +
136
+ 'descriptor object; got ' + (partial === null ? 'null' : typeof partial) +
137
+ '. (FAIL-LOUD.)');
138
+ }
139
+ var name = partial.name;
140
+ if (!_isStr(name)) {
141
+ _fail(name, '"name" must be a non-empty string.');
142
+ }
143
+ var type = partial.type;
144
+ if (FIELD_TYPES.indexOf(type) === -1) {
145
+ _fail(name, '"type" must be one of [' + FIELD_TYPES.join(', ') + ']; got "' + String(type) + '".');
146
+ }
147
+ if (!_isStr(partial.description)) {
148
+ _fail(name, '"description" must be a non-empty string.');
149
+ }
150
+ if (partial.unit !== undefined && !_isStr(partial.unit)) {
151
+ _fail(name, '"unit", when present, must be a non-empty string.');
152
+ }
153
+ if (partial.constraint !== undefined && !_isPlainObject(partial.constraint)) {
154
+ _fail(name, '"constraint", when present, must be a plain object.');
155
+ }
156
+ if (partial.engineVisible !== undefined && typeof partial.engineVisible !== 'boolean') {
157
+ _fail(name, '"engineVisible", when present, must be a boolean.');
158
+ }
159
+ if (partial.widgetHint !== undefined && !_isStr(partial.widgetHint)) {
160
+ _fail(name, '"widgetHint", when present, must be a non-empty string.');
161
+ }
162
+ if (partial.widgetConfig !== undefined && !_isPlainObject(partial.widgetConfig)) {
163
+ _fail(name, '"widgetConfig", when present, must be a plain object.');
164
+ }
165
+
166
+ // Fresh bag — never mutate the caller's object (mirrors frame-data's
167
+ // normalizeDataBubble / controls' normalizeControlDescriptor convention).
168
+ var bag = {};
169
+ for (var k in partial) {
170
+ if (Object.prototype.hasOwnProperty.call(partial, k)) { bag[k] = partial[k]; }
171
+ }
172
+ bag.name = name;
173
+ bag.type = type;
174
+ return bag;
175
+ }
176
+
177
+ // ── UX presentation vocabulary ──────────────────────────────────────────────
178
+ //
179
+ // A per-KIND `ux:{}` block rides ON the ObjectSchema descriptor (peer of `fields`
180
+ // — a presentation contract, NOT a parallel `UxSchema`; Q-A0). Its
181
+ // closed value vocabularies live HERE, the PEER of FIELD_TYPES, so STUDIO's
182
+ // overlay AND a headless game consume ONE list (the SAME hooks a game uses
183
+ // programmatically). The vocab is READ DOWNWARD ONLY (shim → objects/
184
+ // features); no lib/frqtl/objects file re-lists these strings, and
185
+ // author-bbox-overlay.js (lib/features) FERRIES `UX_HANDLE_ZONES` (asserting its
186
+ // own returned zone names are members) instead of being a second owner.
187
+ //
188
+ // R6 legacy tolerance: a descriptor with NO `ux` block ⇒ `normalizeUx(undefined)`
189
+ // ⇒ today's behavior (resizable everywhere, 2D-draggable, all handle zones live,
190
+ // marker shell design-only).
191
+ // normalizeUx NEVER throws on an absent block — only on an INVALID member.
192
+
193
+ // The bbox interaction zones hitBboxZone (author-bbox-overlay.js) can classify a
194
+ // pointer into. 'move' = interior drag; 'scale-*' = a corner/edge resize handle.
195
+ // This is the ONE owner; author-bbox-overlay.js ferries it (drift = load-time throw).
196
+ var UX_HANDLE_ZONES = Object.freeze([
197
+ 'move',
198
+ 'scale-tl', 'scale-tr', 'scale-bl', 'scale-br',
199
+ 'scale-t', 'scale-b', 'scale-l', 'scale-r'
200
+ ]);
201
+
202
+ // The render modes a part may be cursor-dragged in. Only 2D: a 3D scene never cursor-drags
203
+ // (reposition is the aim + SPACE carry), so there is no per-object 3D knob to declare.
204
+ var UX_DRAGGABLE_MODES = Object.freeze(['2d']);
205
+
206
+ // When a manipulable object's visual shell renders (generalizes the
207
+ // `_designMarker` boolean at the ONE _visibleLargeObjects authority):
208
+ // design — only while authoring (Design mode). The marker default.
209
+ // run — always visible (the "red light bulb" opt-in).
210
+ // never — never drawn.
211
+ var UX_SHELL_RENDER = Object.freeze(['design', 'run', 'never']);
212
+
213
+ // The `ux` envelope keys (documentation/introspection — NOT a required list; a
214
+ // partial ux block fills the rest from the legacy defaults below).
215
+ var UX_ENVELOPE_KEYS = Object.freeze([
216
+ 'resizable', 'draggable', 'handles', 'shellRender'
217
+ ]);
218
+
219
+ // Keys a ux block may NOT carry any more, each with what replaced it (FAIL-LOUD on use).
220
+ var UX_DELETED_KEYS = Object.freeze({
221
+ inspectorSections: 'the Inspector shows a DECLARED object through its own descriptor (no per-role section list)'
222
+ });
223
+
224
+ function _uxFail(msg) {
225
+ throw new Error('[lib/shim/field-descriptor] normalizeUx: ' + msg +
226
+ ' (FAIL-LOUD — throw-or-apply, never silently dropped/defaulted-around.)');
227
+ }
228
+
229
+ /**
230
+ * normalizeUx(partial) → full ux bag.
231
+ *
232
+ * THROW-OR-APPLY: an INVALID member throws here; an ABSENT block (undefined/null)
233
+ * yields the legacy defaults (today's behavior, R6). Every field is optional; a
234
+ * partial block fills the rest from the defaults.
235
+ *
236
+ * resizable — boolean (default true). false ⇒ scale handles are never
237
+ * offered even for the SELECTED object (its corners never
238
+ * resize; the first-and-every interaction is select/move).
239
+ * draggable — { '2d':boolean } (default true). false disables the 2D
240
+ * cursor-drag. (A 3D scene never cursor-drags; '3d' is not a key.)
241
+ * handles — string[] ⊆ UX_HANDLE_ZONES (default = ALL zones). The
242
+ * live interaction zones; a zone NOT listed is downgraded
243
+ * to 'move' by the overlay (never a resize on the selecting
244
+ * click). `resizable:false` is the ergonomic shorthand for
245
+ * handles:['move'].
246
+ * shellRender — one of UX_SHELL_RENDER (default 'design'). When the
247
+ * object's visual shell/marker paints.
248
+ *
249
+ * @param {object|null|undefined} partial
250
+ * @returns {{resizable:boolean, draggable:{'2d':boolean}, handles:string[], shellRender:string}}
251
+ */
252
+ function normalizeUx(partial) {
253
+ var bag = {
254
+ resizable: true,
255
+ draggable: { '2d': true },
256
+ handles: UX_HANDLE_ZONES.slice(),
257
+ shellRender: 'design'
258
+ };
259
+ if (partial === null || partial === undefined) { return bag; }
260
+ if (typeof partial !== 'object' || Array.isArray(partial)) {
261
+ _uxFail('a ux block must be a plain object; got ' +
262
+ (Array.isArray(partial) ? 'array' : typeof partial) + '.');
263
+ }
264
+ Object.keys(UX_DELETED_KEYS).forEach(function (k) {
265
+ if (partial[k] !== undefined) { _uxFail('"' + k + '" is DELETED — ' + UX_DELETED_KEYS[k] + '.'); }
266
+ });
267
+ if (partial.resizable !== undefined) {
268
+ if (typeof partial.resizable !== 'boolean') { _uxFail('"resizable" must be a boolean.'); }
269
+ bag.resizable = partial.resizable;
270
+ }
271
+ if (partial.draggable !== undefined) {
272
+ if (!_isPlainObject(partial.draggable)) { _uxFail('"draggable" must be a { "2d" } object.'); }
273
+ Object.keys(partial.draggable).forEach(function (k) {
274
+ if (UX_DRAGGABLE_MODES.indexOf(k) === -1) {
275
+ _uxFail('"draggable.' + k + '" is not a draggable mode ([' + UX_DRAGGABLE_MODES.join(', ') +
276
+ ']) — a 3D scene never cursor-drags.');
277
+ }
278
+ });
279
+ var dr = { '2d': true };
280
+ for (var m = 0; m < UX_DRAGGABLE_MODES.length; m++) {
281
+ var mode = UX_DRAGGABLE_MODES[m];
282
+ if (partial.draggable[mode] !== undefined) {
283
+ if (typeof partial.draggable[mode] !== 'boolean') {
284
+ _uxFail('"draggable.' + mode + '" must be a boolean.');
285
+ }
286
+ dr[mode] = partial.draggable[mode];
287
+ }
288
+ }
289
+ bag.draggable = dr;
290
+ }
291
+ if (partial.handles !== undefined) {
292
+ if (!Array.isArray(partial.handles)) { _uxFail('"handles" must be an array of zone names.'); }
293
+ for (var h = 0; h < partial.handles.length; h++) {
294
+ if (UX_HANDLE_ZONES.indexOf(partial.handles[h]) === -1) {
295
+ _uxFail('"handles" entry "' + String(partial.handles[h]) + '" is not a member of ' +
296
+ 'UX_HANDLE_ZONES ([' + UX_HANDLE_ZONES.join(', ') + ']).');
297
+ }
298
+ }
299
+ bag.handles = partial.handles.slice();
300
+ } else if (partial.resizable === false) {
301
+ // Ergonomic shorthand: an explicitly non-resizable object offers ONLY move.
302
+ bag.handles = ['move'];
303
+ }
304
+ if (partial.shellRender !== undefined) {
305
+ if (UX_SHELL_RENDER.indexOf(partial.shellRender) === -1) {
306
+ _uxFail('"shellRender" must be one of [' + UX_SHELL_RENDER.join(', ') + ']; got "' +
307
+ String(partial.shellRender) + '".');
308
+ }
309
+ bag.shellRender = partial.shellRender;
310
+ }
311
+ return bag;
312
+ }
313
+
314
+ // ── Export ────────────────────────────────────────────────────────────────────
315
+
316
+ export {
317
+ FIELD_TYPES,
318
+ FIELD_ENVELOPE_KEYS,
319
+ normalizeFieldDescriptor,
320
+ UX_HANDLE_ZONES,
321
+ UX_DRAGGABLE_MODES,
322
+ UX_SHELL_RENDER,
323
+ UX_ENVELOPE_KEYS,
324
+ normalizeUx
325
+ };
@@ -0,0 +1,224 @@
1
+ /* Copyright 2023-2026 by Essam Abadir */
2
+
3
+ /**
4
+ * lib/shim/frame-data — The data-bubble schema contract.
5
+ *
6
+ * Single authority for the FrameData.data bag shape (§6 of
7
+ * the engine contract). The bubble is GENERIC and engine-opaque:
8
+ * SECTION_KEYS = ['detection', 'string_map']. The engine interprets NOTHING in
9
+ * string_map — it ferries every key verbatim across the JS↔WASM boundary.
10
+ *
11
+ * The data bubble has two cross-engine reserved namespaces (+ a JS-only ext):
12
+ * detection — written by the engine (MARK/DETECT primitives). Contains
13
+ * detector_name and any future detection tags.
14
+ * string_map — op-program-writable via `set 0.data.<key> = StrLit(value)`;
15
+ * a flat { key: string, ... } the engine carries opaque. ALL
16
+ * render data rides here as opaque keys: color is
17
+ * string_map['render.color'] (CSV 'r,g,b,a'); outline is
18
+ * string_map['render.outline'] === 'true'. Sugar/renderer code
19
+ * serializes on write and deserializes on read — there is NO
20
+ * typed `render` section (RETIRED: FrameDataRender,
21
+ * FrameMetaData.render, render_color SoA field, normalizeRender).
22
+ * ext — developer-extensible; engine carries opaque, never reads.
23
+ * NOTE (D2 decision): ext is JS-only. The Rust side has no ext
24
+ * field — serde_wasm_bindgen v0.6 cannot round-trip a free-form
25
+ * map through JsValue without serde_json::Value (which drops its
26
+ * contents). ext writes are carried through JS-only paths and are
27
+ * not asserted in cross-engine conformance. If ext survives a
28
+ * JS→WASM→JS round-trip, treat it as undefined behavior.
29
+ *
30
+ * The canonical section key list drives conformance (see §5 — the data-bubble
31
+ * round-trip oracle iterates over SECTION_KEYS to assert completeness).
32
+ *
33
+ * Usage:
34
+ * import { SECTION_KEYS, normalizeDataBubble, RENDER_INTENT_KEYS,
35
+ * normalizeRenderIntent } from 'lib/shim/frame-data/index.js';
36
+ */
37
+
38
+
39
+
40
+ /**
41
+ * Canonical section key table.
42
+ * Conformance iterates this list — adding a section here MUST be accompanied
43
+ * by a conformance assertion (cross-engine oracle, §5 item 2).
44
+ *
45
+ * Sections:
46
+ * detection — engine-writable (MARK/DETECT); { detector_name: string|null }
47
+ * string_map — op-program-writable via `set 0.data.<key> = StrLit(value)`;
48
+ * flat object { key: string, ... }. Absent → null in normalized form.
49
+ * Cross-engine (JS + WASM). Owner: this file + FrameMetaData (tick_data.rs).
50
+ * ALL render hints ride here as opaque keys (render.color, render.outline);
51
+ * there is no typed `render` section.
52
+ */
53
+ // 'render' section RETIRED — color (and all render hints) are opaque user-space data on
54
+ // string_map; the engine never carries a typed render section. Owner: this file + FrameMetaData.
55
+ const SECTION_KEYS = ['detection', 'string_map'];
56
+ // NOTE: 'ext' is deliberately excluded because it is not cross-engine assertable.
57
+
58
+ /**
59
+ * Normalize a partial data bag to the full canonical shape.
60
+ *
61
+ * Rules:
62
+ * - Each reserved section (detection, string_map) is present as an object or null.
63
+ * - Absent → null (mirrors the JS toFrameData() :2872 and Rust skip_serializing_if).
64
+ * - Extra keys inside a section are preserved (pass-through).
65
+ * - The ext key is passed through as-is (JS-only, not normalized).
66
+ *
67
+ * @param {object|null|undefined} partial — partial data bag from a frame or FrameData
68
+ * @returns {{ detection: object|null, string_map: object|null, ext: any }}
69
+ */
70
+ function normalizeDataBubble(partial) {
71
+ if (partial === null || partial === undefined) {
72
+ return { detection: null, string_map: null };
73
+ }
74
+ return {
75
+ detection: (partial.detection !== null && partial.detection !== undefined)
76
+ ? partial.detection
77
+ : null,
78
+ string_map: (partial.string_map !== null && partial.string_map !== undefined &&
79
+ typeof partial.string_map === 'object')
80
+ ? partial.string_map
81
+ : null,
82
+ ext: partial.ext !== undefined ? partial.ext : undefined,
83
+ };
84
+ }
85
+
86
+ /**
87
+ * Normalize the detection sub-section.
88
+ * detector_name: string|null
89
+ */
90
+ function normalizeDetection(partial) {
91
+ if (!partial) return { detector_name: null };
92
+ return {
93
+ detector_name: (partial.detector_name !== null && partial.detector_name !== undefined)
94
+ ? String(partial.detector_name)
95
+ : null,
96
+ };
97
+ }
98
+
99
+ // ── Render-intent vocabulary (Part C) ────────────────────────────────────────
100
+ //
101
+ // Render-intent keys are opaque string_map keys that sugar objects and experiment
102
+ // setups write to describe per-frame render intent. Providers deserialize them on
103
+ // read — the engine carries them verbatim and interprets nothing (I1 preserved).
104
+ //
105
+ // Key list owned HERE (single source). Conformance assertions MUST be driven off
106
+ // this list so that adding a key automatically extends the test surface.
107
+ //
108
+ // Priority in any provider:
109
+ // render.color (exact CSV r,g,b,a) > render.colorScheme ramp via LightColor > renderer default
110
+
111
+ /**
112
+ * RENDER_INTENT_KEYS — the canonical set of render-intent string_map keys.
113
+ *
114
+ * Conformance tests iterate this list. To add a new render-intent key:
115
+ * 1. Add the key string here.
116
+ * 2. Add its allowed values to RENDER_INTENT_VALUES.
117
+ * 3. Update normalizeRenderIntent to pass it through.
118
+ * 4. Add a conformance assertion (cross-engine oracle).
119
+ * 5. Update both providers to consume it.
120
+ *
121
+ * Current keys:
122
+ * render.color — CSV 'r,g,b,a' exact RGBA override (highest priority); existing. OPEN-ID (no value set).
123
+ * render.outline — 'true' | 'false' (or absent); existing. ENUM.
124
+ * render.shape — 'ball' | 'box' | 'circle' | 'cube' | 'sphere' (per-frame shape; absent → renderer default). ENUM.
125
+ * 'sphere' = a TRUE 3D instanced-sphere mesh (three, _is3D), symmetric with 'cube';
126
+ * in 2D / p5 it degrades to the filled 'ball' disc (no per-provider map — RenderShape
127
+ * is the one authority; the three sphere path is gated on _is3D like the cube path).
128
+ * render.colorScheme — 'roygbiv' | 'warmcool' (named LightColor ramp; absent → default). ENUM.
129
+ * render.mesh — external-geometry asset id (e.g. an Objaverse glTF id); absent → sprite/cube path.
130
+ * OPEN-ID: no RENDER_INTENT_VALUES entry (accept-any-string); the renderer's RenderMesh
131
+ * resolver FAILS LOUD at the output boundary if the asset cannot load — never silent.
132
+ * render.meshScale — per-frame scale MULTIPLIER for the frame's render.mesh clone (a number as a string;
133
+ * local override of the experiment-wide setRenderOption('meshScale',…)). OPEN-ID.
134
+ * render.meshRotation— per-frame euler rotation for the frame's render.mesh clone, a CSV of THREE radians
135
+ * 'rx,ry,rz' (same unit as a LargeObject's lo.meshRotation → clone.rotation.set). OPEN-ID.
136
+ * (R3-3: previously written ad-hoc but undeclared + unread; declared
137
+ * here at the owner and read per-clone in three-provider's _layoutMeshClones.)
138
+ *
139
+ * Two contract shapes:
140
+ * ENUM key — has a RENDER_INTENT_VALUES[] array; decoders ferry the array (no re-listing); conformance-validated.
141
+ * OPEN-ID key — has NO RENDER_INTENT_VALUES entry → assertRenderIntentConformance accepts any string; the
142
+ * decoder/resolver owns load-time validation and fails loud. Covers render.color and render.mesh.
143
+ */
144
+ const RENDER_INTENT_KEYS = [
145
+ 'render.color',
146
+ 'render.outline',
147
+ 'render.shape',
148
+ 'render.colorScheme',
149
+ 'render.mesh',
150
+ 'render.meshScale', // OPEN-ID — per-frame mesh scale multiplier (R3-3)
151
+ 'render.meshRotation' // OPEN-ID — per-frame mesh euler radians CSV (R3-3)
152
+ ];
153
+
154
+ /**
155
+ * RENDER_INTENT_VALUES — allowed values for each key (for validation).
156
+ * Keys without an entry accept any string (e.g. render.color is a CSV).
157
+ */
158
+ const RENDER_INTENT_VALUES = {
159
+ 'render.shape': ['ball', 'box', 'circle', 'cube', 'sphere'],
160
+ 'render.colorScheme': ['roygbiv', 'warmcool'],
161
+ 'render.outline': ['true', 'false']
162
+ // NOTE: render.color, render.mesh, render.meshScale, render.meshRotation are OPEN-ID keys —
163
+ // deliberately NO entry here (accept-any-string: a CSV / an asset id / a number / an euler CSV).
164
+ // Their decoders/resolvers own validation and fail loud at the boundary.
165
+ };
166
+
167
+ /**
168
+ * normalizeRenderIntent — ferry a partial render-intent bag to the full canonical shape.
169
+ *
170
+ * Reads only the keys declared in RENDER_INTENT_KEYS; copies them into the normalized
171
+ * bag if present; absent keys are omitted (not defaulted — the renderer defaults apply).
172
+ * This is the "ferry the bag" pattern: the caller never re-enumerates the key list.
173
+ *
174
+ * @param {object|null|undefined} partial — partial string_map or explicit intent object
175
+ * @returns {{ 'render.color'?: string, 'render.outline'?: string,
176
+ * 'render.shape'?: string, 'render.colorScheme'?: string }}
177
+ */
178
+ function normalizeRenderIntent(partial) {
179
+ var bag = {};
180
+ if (!partial || typeof partial !== 'object') return bag;
181
+ for (var i = 0; i < RENDER_INTENT_KEYS.length; i++) {
182
+ var k = RENDER_INTENT_KEYS[i];
183
+ if (partial[k] !== undefined && partial[k] !== null) {
184
+ bag[k] = String(partial[k]);
185
+ }
186
+ }
187
+ return bag;
188
+ }
189
+
190
+ /**
191
+ * assertRenderIntentConformance — throw if any key in a string_map bag violates the contract.
192
+ *
193
+ * Validates values for keys whose allowed set is enumerated in RENDER_INTENT_VALUES.
194
+ * Keys with unconstrained values (render.color, render.outline) are passed through.
195
+ * Unknown keys outside RENDER_INTENT_KEYS are ignored (the engine carries all keys opaque).
196
+ *
197
+ * @param {object} bag — string_map object to validate
198
+ * @throws {Error} if a constrained key holds an unknown value
199
+ */
200
+ function assertRenderIntentConformance(bag) {
201
+ if (!bag) return;
202
+ for (var i = 0; i < RENDER_INTENT_KEYS.length; i++) {
203
+ var k = RENDER_INTENT_KEYS[i];
204
+ var allowed = RENDER_INTENT_VALUES[k];
205
+ if (allowed && bag[k] !== undefined && allowed.indexOf(bag[k]) === -1) {
206
+ throw new Error(
207
+ 'render-intent conformance: key "' + k + '" has invalid value "' + bag[k] +
208
+ '"; allowed: ' + allowed.join('|')
209
+ );
210
+ }
211
+ }
212
+ }
213
+
214
+ // ── Export ────────────────────────────────────────────────────────────────────
215
+
216
+ export {
217
+ SECTION_KEYS,
218
+ normalizeDataBubble,
219
+ normalizeDetection,
220
+ RENDER_INTENT_KEYS,
221
+ RENDER_INTENT_VALUES,
222
+ normalizeRenderIntent,
223
+ assertRenderIntentConformance
224
+ };
@@ -0,0 +1,67 @@
1
+ /* Copyright 2023-2026 by Essam Abadir */
2
+
3
+ /**
4
+ * lib/shim — the unified shim router (was lib/common).
5
+ *
6
+ * ESM barrel: re-exports all named exports. A missing import is a hard
7
+ * FAIL-LOUD load error — no window.Common* ambient globals.
8
+ *
9
+ * Usage (under vite with alias 'lib' → repo-root/lib):
10
+ * import { Bus, Runtime, EXPERIMENTS, engineRouter } from 'lib/shim';
11
+ *
12
+ * Usage (direct relative path):
13
+ * import { Bus } from '../../lib/shim/index.js';
14
+ */
15
+
16
+ export { Bus } from './bus.js';
17
+ export { Runtime } from './runtime/index.js';
18
+ export { EXPERIMENTS, EXPERIMENT_TIERS, experimentById, experimentIs3D,
19
+ isPublicExperiment, publicExperiments,
20
+ internalExperiments } from './registry/experiments.js';
21
+ export { WALKTHROUGH, walkthroughIs3D, walkthroughModes, walkthroughGroup,
22
+ walkthroughById,
23
+ FIRST_CONTACT_WALKTHROUGH_ID,
24
+ defaultWalkthroughModeId, effectiveRenderState } from './registry/walkthrough.js';
25
+ export { loadSceneSource, scenePath, EMPTY_SCENE } from './registry/scene-source.js';
26
+ // The host-side experiment-iframe guard (the false-200 trap). Exported from the
27
+ // barrel so every host that frames an experiment page (lib/features/ide's GYM)
28
+ // asserts against the SAME contract.
29
+ export { EXPERIMENT_PAGE_MARKERS, HOST_SHELL_ROOT_SELECTOR, FRAME_VERDICTS,
30
+ DEFAULT_FRAME_TIMEOUT_MS, classifyFrameProbe, probeExperimentFrame,
31
+ paintFrameGuardOverlay, watchExperimentFrame } from './experiment-frame/index.js';
32
+ export { engineRouter, DEV_CORE_PROFILE, DIST_PROFILE } from './engine/router.js';
33
+ // Math backend registry — re-exported so lib/features can import from the shim
34
+ // barrel (the sanctioned route) without reaching past the shim into lib/egpt directly.
35
+ // Module identity is preserved: both the barrel re-export and any direct import of
36
+ // MathBackendRegistry.js resolve to the SAME singleton because ESM caches by
37
+ // canonical URL — there is only one MathBackendRegistry instance. The registry
38
+ // module has zero imports; the JS reference core never enters this graph.
39
+ export { MathBackendRegistry, MathBackendNotAvailableError } from '../egpt/js/model/backend/MathBackendRegistry.js';
40
+ // Notebook spine: the native format parser/serializer and the
41
+ // per-notebook kernel. The kernel calls Runtime.runCell directly (no Bus
42
+ // executor). Consumers (the A2 notebook pane) import these from the barrel.
43
+ export { parse, serialize, normalize } from './notebook/format.js';
44
+ export { NotebookKernel, NOTEBOOK_CELL_STATUS } from './notebook/kernel.js';
45
+ // Cell-as-module resolver (B2) — the host-neutral in-memory
46
+ // blob closure logic. Re-exported so tests + any host can build the closure
47
+ // (Runtime injects the browser blob minter; the resolver itself is DOM-free and
48
+ // must NOT assume a pane exists — model-gate rule 6).
49
+ export {
50
+ canonKey, resolveRelativeKey, hasImport, splitImportsAndBody,
51
+ rewriteRelativeToSiblingBlobs, buildModuleClosure, compileEntryModuleSource
52
+ } from './notebook/module-resolver.js';
53
+ // Notebook webview-realm model: the FOURTH BYO pluggable
54
+ // surface. ONE registry authority + the frozen view-handle contract + the in-app
55
+ // transport (same-origin direct fast path). A realm pre-load
56
+ // is an above-the-shim renderer env; the frqtl pre-load co-locates the engine.
57
+ export * as RealmRegistry from './notebook/realm-registry.js';
58
+ export { makeViewHandle, isViewHandle, assertSerializable } from './notebook/view-handle.js';
59
+ export { inAppTransport } from './notebook/realm-transport.js';
60
+ // Realm import map — buildImportMap (vendor manifest → `{ imports }`), buildRealmImportMap
61
+ // (vendor + @frqtl/setups, through ONE router) and spliceRealmImportMap (the ONE splice the
62
+ // served hosts, lib/server/realm-html.js, and the static bake, apps/ide/vite.config.js, both
63
+ // call). PURE, DOM-free.
64
+ export { buildImportMap, buildRealmImportMap, spliceRealmImportMap } from './notebook/vendor-importmap.js';
65
+ // Canonical setup-factory bare-specifier surface — the manifest and its import-map fragment
66
+ // (merged by buildRealmImportMap above). PURE, DOM-free.
67
+ export { buildFrqtlSetupsImportMap, FRQTL_SETUPS_MANIFEST } from './notebook/frqtl-setups-importmap.js';