@almadar/std 16.173.0 → 16.174.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 (203) hide show
  1. package/behaviors/lolo/infra/atoms/std-cross-reference.lolo +2 -4
  2. package/behaviors/lolo/ui/core/atoms/std-board.lolo +5 -9
  3. package/behaviors/lolo/ui/core/atoms/std-browse.lolo +8 -1
  4. package/behaviors/lolo/ui/core/atoms/std-esign-flow.lolo +2 -2
  5. package/behaviors/lolo/ui/core/atoms/std-event-log.lolo +3 -7
  6. package/behaviors/lolo/ui/core/atoms/std-form-advanced.lolo +1 -1
  7. package/behaviors/lolo/ui/core/atoms/std-image-upload-multi.lolo +1 -1
  8. package/behaviors/lolo/ui/core/atoms/std-list.lolo +3 -3
  9. package/behaviors/lolo/ui/core/atoms/std-modal.lolo +2 -2
  10. package/behaviors/lolo/ui/core/atoms/std-multi-party-flow.lolo +2 -4
  11. package/behaviors/lolo/ui/core/atoms/std-rating-review.lolo +5 -13
  12. package/behaviors/lolo/ui/core/atoms/std-recurrence.lolo +3 -7
  13. package/behaviors/lolo/ui/core/atoms/std-saved-search.lolo +1 -1
  14. package/behaviors/lolo/ui/core/atoms/std-signature-capture.lolo +2 -2
  15. package/behaviors/lolo/ui/core/atoms/std-step-flow.lolo +2 -4
  16. package/behaviors/lolo/ui/core/atoms/std-tag-taxonomy.lolo +1 -1
  17. package/behaviors/lolo/ui/core/atoms/std-thread.lolo +2 -2
  18. package/behaviors/lolo/ui/core/atoms/std-vote.lolo +2 -2
  19. package/behaviors/lolo/ui/core/atoms/std-wizard.lolo +3 -7
  20. package/behaviors/lolo/ui/core/atoms/ui-atlas-image.lolo +1 -1
  21. package/behaviors/lolo/ui/core/atoms/ui-atlas-panel.lolo +1 -1
  22. package/behaviors/lolo/ui/core/atoms/ui-center.lolo +1 -1
  23. package/behaviors/lolo/ui/core/atoms/ui-hstack.lolo +1 -1
  24. package/behaviors/lolo/ui/core/atoms/ui-icon.lolo +1 -1
  25. package/behaviors/lolo/ui/core/atoms/ui-stack.lolo +1 -1
  26. package/behaviors/lolo/ui/core/atoms/ui-typography.lolo +1 -1
  27. package/behaviors/lolo/ui/core/atoms/ui-vstack.lolo +1 -1
  28. package/behaviors/lolo/ui/core/molecules/ui-content-renderer.lolo +1 -1
  29. package/behaviors/lolo/ui/core/molecules/ui-form-layout.lolo +1 -1
  30. package/behaviors/lolo/ui/core/molecules/ui-grid.lolo +1 -1
  31. package/behaviors/lolo/ui/core/organisms/ui-chat-bar.lolo +1 -1
  32. package/behaviors/lolo/ui/core/organisms/ui-dashboard-grid.lolo +1 -1
  33. package/behaviors/lolo/ui/core/organisms/ui-detail-panel.lolo +1 -1
  34. package/behaviors/lolo/ui/core/organisms/ui-entity-cards.lolo +1 -1
  35. package/behaviors/lolo/ui/core/organisms/ui-entity-list.lolo +1 -1
  36. package/behaviors/lolo/ui/core/organisms/ui-entity-table.lolo +1 -1
  37. package/behaviors/lolo/ui/core/organisms/ui-form-section.lolo +9 -3
  38. package/behaviors/lolo/ui/core/organisms/ui-form.lolo +9 -3
  39. package/behaviors/lolo/ui/core/organisms/ui-master-detail.lolo +1 -1
  40. package/behaviors/lolo/ui/core/organisms/ui-media-gallery.lolo +1 -1
  41. package/behaviors/lolo/ui/core/organisms/ui-segment-renderer.lolo +7 -1
  42. package/behaviors/lolo/ui/core/organisms/ui-stat-card.lolo +1 -1
  43. package/behaviors/lolo/ui/core/organisms/ui-subagent-trace-panel.lolo +1 -1
  44. package/behaviors/lolo/ui/game/atoms/ui-action-tile.lolo +1 -1
  45. package/behaviors/lolo/ui/game/atoms/ui-draw-shape-layer.lolo +41 -9
  46. package/behaviors/lolo/ui/game/atoms/ui-draw-shape.lolo +40 -8
  47. package/behaviors/lolo/ui/game/atoms/ui-draw-sprite-layer.lolo +13 -3
  48. package/behaviors/lolo/ui/game/atoms/ui-draw-sprite.lolo +12 -2
  49. package/behaviors/lolo/ui/game/atoms/ui-draw-text-layer.lolo +3 -3
  50. package/behaviors/lolo/ui/game/atoms/ui-draw-text.lolo +2 -2
  51. package/behaviors/lolo/ui/game/organisms/std-tactics-board-3d.lolo +32 -2
  52. package/behaviors/lolo/ui/learning/atoms/std-learn-classify.lolo +1 -1
  53. package/behaviors/lolo/ui/learning/atoms/std-learn-compare.lolo +397 -0
  54. package/behaviors/lolo/ui/learning/atoms/std-learn-coupled-sim.lolo +537 -0
  55. package/behaviors/lolo/ui/learning/atoms/std-learn-estimate.lolo +419 -0
  56. package/behaviors/lolo/ui/learning/atoms/std-learn-goal-seek.lolo +591 -0
  57. package/behaviors/lolo/ui/learning/atoms/std-learn-grid-sim.lolo +425 -0
  58. package/behaviors/lolo/ui/learning/atoms/std-learn-hotspot.lolo +398 -0
  59. package/behaviors/lolo/ui/learning/atoms/std-learn-measure.lolo +325 -0
  60. package/behaviors/lolo/ui/learning/atoms/std-learn-perturb.lolo +494 -0
  61. package/behaviors/lolo/ui/learning/atoms/std-learn-predict.lolo +408 -0
  62. package/behaviors/lolo/ui/learning/atoms/std-learn-scenario.lolo +307 -0
  63. package/behaviors/lolo/ui/learning/atoms/std-learn-sim-3d.lolo +318 -0
  64. package/behaviors/lolo/ui/learning/atoms/std-learn-speed-drill.lolo +336 -0
  65. package/behaviors/lolo/ui/learning/atoms/std-learn-tour-3d.lolo +380 -0
  66. package/behaviors/lolo/ui/learning/atoms/ui-biology-canvas.lolo +43 -4
  67. package/behaviors/lolo/ui/learning/atoms/ui-chemistry-canvas.lolo +41 -4
  68. package/behaviors/lolo/ui/learning/atoms/ui-physics-canvas.lolo +43 -4
  69. package/behaviors/lolo/ui/marketing/organisms/ui-book-viewer.lolo +1 -1
  70. package/behaviors/lolo/ui/marketing/organisms/ui-case-study-organism.lolo +1 -1
  71. package/behaviors/lolo/ui/marketing/organisms/ui-feature-grid-organism.lolo +1 -1
  72. package/behaviors/lolo/ui/marketing/organisms/ui-hero-organism.lolo +1 -1
  73. package/behaviors/lolo/ui/marketing/organisms/ui-pricing-organism.lolo +1 -1
  74. package/behaviors/lolo/ui/marketing/organisms/ui-showcase-organism.lolo +1 -1
  75. package/behaviors/lolo/ui/marketing/organisms/ui-stats-organism.lolo +1 -1
  76. package/behaviors/lolo/ui/marketing/organisms/ui-step-flow-organism.lolo +1 -1
  77. package/behaviors/lolo/ui/marketing/organisms/ui-team-organism.lolo +1 -1
  78. package/behaviors/registry/agent/atoms/std-agent-session.orb +22 -1
  79. package/behaviors/registry/agent/atoms/std-agent-tool-call.orb +38 -2
  80. package/behaviors/registry/agent/atoms/std-agent-tool-loop.orb +38 -2
  81. package/behaviors/registry/agent/organisms/std-agent-rabit.orb +23 -1
  82. package/behaviors/registry/infra/atoms/std-approval-gate.orb +8 -16
  83. package/behaviors/registry/infra/atoms/std-cache-aside.orb +31 -62
  84. package/behaviors/registry/infra/atoms/std-circuit-breaker.orb +16 -32
  85. package/behaviors/registry/infra/atoms/std-cross-reference.orb +32 -4
  86. package/behaviors/registry/infra/atoms/std-data-erasure.orb +8 -16
  87. package/behaviors/registry/infra/atoms/std-mod-queue.orb +8 -16
  88. package/behaviors/registry/infra/atoms/std-rate-limiter.orb +14 -28
  89. package/behaviors/registry/infra/atoms/std-row-access-control.orb +30 -2
  90. package/behaviors/registry/ui/core/atoms/std-billable-hour.orb +1 -2
  91. package/behaviors/registry/ui/core/atoms/std-board.orb +19 -5
  92. package/behaviors/registry/ui/core/atoms/std-browse.orb +29 -7
  93. package/behaviors/registry/ui/core/atoms/std-dashboard-grid-embedded.orb +1 -2
  94. package/behaviors/registry/ui/core/atoms/std-esign-flow.orb +3 -5
  95. package/behaviors/registry/ui/core/atoms/std-esign-request.orb +3 -6
  96. package/behaviors/registry/ui/core/atoms/std-event-log.orb +17 -3
  97. package/behaviors/registry/ui/core/atoms/std-export.orb +2 -4
  98. package/behaviors/registry/ui/core/atoms/std-form-advanced.orb +1 -1
  99. package/behaviors/registry/ui/core/atoms/std-gallery.orb +9 -18
  100. package/behaviors/registry/ui/core/atoms/std-graphs.orb +15 -1
  101. package/behaviors/registry/ui/core/atoms/std-import.orb +2 -4
  102. package/behaviors/registry/ui/core/atoms/std-list.orb +4 -6
  103. package/behaviors/registry/ui/core/atoms/std-modal.orb +2 -2
  104. package/behaviors/registry/ui/core/atoms/std-multi-party-flow.orb +16 -2
  105. package/behaviors/registry/ui/core/atoms/std-pagination.orb +15 -1
  106. package/behaviors/registry/ui/core/atoms/std-rating-review.orb +19 -5
  107. package/behaviors/registry/ui/core/atoms/std-recurrence.orb +17 -3
  108. package/behaviors/registry/ui/core/atoms/std-rich-editor.orb +15 -1
  109. package/behaviors/registry/ui/core/atoms/std-scatter.orb +15 -1
  110. package/behaviors/registry/ui/core/atoms/std-signature-capture.orb +2 -2
  111. package/behaviors/registry/ui/core/atoms/std-stats.orb +15 -1
  112. package/behaviors/registry/ui/core/atoms/std-step-flow.orb +16 -2
  113. package/behaviors/registry/ui/core/atoms/std-thread.orb +2 -2
  114. package/behaviors/registry/ui/core/atoms/std-vote.orb +2 -2
  115. package/behaviors/registry/ui/core/atoms/std-wizard.orb +17 -3
  116. package/behaviors/registry/ui/core/atoms/ui-atlas-image.orb +4 -1
  117. package/behaviors/registry/ui/core/atoms/ui-atlas-panel.orb +4 -1
  118. package/behaviors/registry/ui/core/atoms/ui-center.orb +4 -1
  119. package/behaviors/registry/ui/core/atoms/ui-hstack.orb +4 -1
  120. package/behaviors/registry/ui/core/atoms/ui-icon.orb +4 -1
  121. package/behaviors/registry/ui/core/atoms/ui-stack.orb +4 -1
  122. package/behaviors/registry/ui/core/atoms/ui-typography.orb +4 -1
  123. package/behaviors/registry/ui/core/atoms/ui-vstack.orb +4 -1
  124. package/behaviors/registry/ui/core/molecules/ui-accordion.orb +3 -3
  125. package/behaviors/registry/ui/core/molecules/ui-content-renderer.orb +4 -1
  126. package/behaviors/registry/ui/core/molecules/ui-form-layout.orb +4 -1
  127. package/behaviors/registry/ui/core/molecules/ui-grid.orb +4 -1
  128. package/behaviors/registry/ui/core/molecules/ui-tabs.orb +2 -2
  129. package/behaviors/registry/ui/core/molecules/ui-wizard-container.orb +1 -1
  130. package/behaviors/registry/ui/core/organisms/ui-chat-bar.orb +4 -1
  131. package/behaviors/registry/ui/core/organisms/ui-dashboard-grid.orb +5 -2
  132. package/behaviors/registry/ui/core/organisms/ui-detail-panel.orb +5 -2
  133. package/behaviors/registry/ui/core/organisms/ui-entity-cards.orb +4 -1
  134. package/behaviors/registry/ui/core/organisms/ui-entity-list.orb +4 -1
  135. package/behaviors/registry/ui/core/organisms/ui-entity-table.orb +4 -1
  136. package/behaviors/registry/ui/core/organisms/ui-form-section.orb +34 -2
  137. package/behaviors/registry/ui/core/organisms/ui-form.orb +34 -2
  138. package/behaviors/registry/ui/core/organisms/ui-master-detail.orb +4 -1
  139. package/behaviors/registry/ui/core/organisms/ui-media-gallery.orb +4 -1
  140. package/behaviors/registry/ui/core/organisms/ui-segment-renderer.orb +24 -2
  141. package/behaviors/registry/ui/core/organisms/ui-stat-card.orb +4 -1
  142. package/behaviors/registry/ui/core/organisms/ui-subagent-trace-panel.orb +4 -1
  143. package/behaviors/registry/ui/core/organisms/ui-tabbed-container.orb +1 -1
  144. package/behaviors/registry/ui/core/organisms/ui-ui-slot-renderer.orb +1 -1
  145. package/behaviors/registry/ui/game/atoms/std-fx-particles.orb +35 -1
  146. package/behaviors/registry/ui/game/atoms/ui-action-tile.orb +4 -1
  147. package/behaviors/registry/ui/game/atoms/ui-draw-shape-layer.orb +183 -13
  148. package/behaviors/registry/ui/game/atoms/ui-draw-shape.orb +104 -9
  149. package/behaviors/registry/ui/game/atoms/ui-draw-sprite-layer.orb +56 -2
  150. package/behaviors/registry/ui/game/atoms/ui-draw-sprite.orb +36 -4
  151. package/behaviors/registry/ui/game/atoms/ui-draw-text-layer.orb +21 -2
  152. package/behaviors/registry/ui/game/atoms/ui-draw-text.orb +19 -4
  153. package/behaviors/registry/ui/game/organisms/std-tactics-board-3d.orb +173 -2
  154. package/behaviors/registry/ui/learning/atoms/std-learn-classify.orb +1 -1
  155. package/behaviors/registry/ui/learning/atoms/std-learn-compare.orb +2814 -0
  156. package/behaviors/registry/ui/learning/atoms/std-learn-coupled-sim.orb +3183 -0
  157. package/behaviors/registry/ui/learning/atoms/std-learn-estimate.orb +2394 -0
  158. package/behaviors/registry/ui/learning/atoms/std-learn-goal-seek.orb +3951 -0
  159. package/behaviors/registry/ui/learning/atoms/std-learn-grid-sim.orb +3458 -0
  160. package/behaviors/registry/ui/learning/atoms/std-learn-hotspot.orb +2646 -0
  161. package/behaviors/registry/ui/learning/atoms/std-learn-measure.orb +1979 -0
  162. package/behaviors/registry/ui/learning/atoms/std-learn-perturb.orb +2994 -0
  163. package/behaviors/registry/ui/learning/atoms/std-learn-predict.orb +2682 -0
  164. package/behaviors/registry/ui/learning/atoms/std-learn-scenario.orb +1842 -0
  165. package/behaviors/registry/ui/learning/atoms/std-learn-sim-3d.orb +1648 -0
  166. package/behaviors/registry/ui/learning/atoms/std-learn-speed-drill.orb +2307 -0
  167. package/behaviors/registry/ui/learning/atoms/std-learn-tour-3d.orb +2947 -0
  168. package/behaviors/registry/ui/learning/atoms/ui-algorithm-canvas.orb +173 -4
  169. package/behaviors/registry/ui/learning/atoms/ui-biology-canvas.orb +267 -7
  170. package/behaviors/registry/ui/learning/atoms/ui-chemistry-canvas.orb +263 -8
  171. package/behaviors/registry/ui/learning/atoms/ui-learning-canvas.orb +116 -1
  172. package/behaviors/registry/ui/learning/atoms/ui-math-canvas.orb +200 -4
  173. package/behaviors/registry/ui/learning/atoms/ui-physics-canvas.orb +264 -7
  174. package/behaviors/registry/ui/marketing/atoms/std-marketing-article.orb +1 -2
  175. package/behaviors/registry/ui/marketing/atoms/std-marketing-footer.orb +1 -2
  176. package/behaviors/registry/ui/marketing/atoms/std-marketing-split.orb +1 -2
  177. package/behaviors/registry/ui/marketing/atoms/std-marketing-stats.orb +1 -2
  178. package/behaviors/registry/ui/marketing/atoms/std-marketing-steps.orb +1 -2
  179. package/behaviors/registry/ui/marketing/atoms/std-marketing-team.orb +1 -2
  180. package/behaviors/registry/ui/marketing/organisms/ui-book-viewer.orb +4 -1
  181. package/behaviors/registry/ui/marketing/organisms/ui-case-study-organism.orb +4 -1
  182. package/behaviors/registry/ui/marketing/organisms/ui-feature-grid-organism.orb +4 -1
  183. package/behaviors/registry/ui/marketing/organisms/ui-hero-organism.orb +4 -1
  184. package/behaviors/registry/ui/marketing/organisms/ui-pricing-organism.orb +4 -1
  185. package/behaviors/registry/ui/marketing/organisms/ui-showcase-organism.orb +4 -1
  186. package/behaviors/registry/ui/marketing/organisms/ui-stats-organism.orb +4 -1
  187. package/behaviors/registry/ui/marketing/organisms/ui-step-flow-organism.orb +4 -1
  188. package/behaviors/registry/ui/marketing/organisms/ui-team-organism.orb +4 -1
  189. package/dist/behaviors/exports-reader.js +3440 -2189
  190. package/dist/behaviors/functions/index.d.ts +1751 -154
  191. package/dist/behaviors/functions/index.js +3402 -2190
  192. package/dist/behaviors/index.d.ts +1 -1
  193. package/dist/behaviors/index.js +3441 -2190
  194. package/dist/behaviors/query.js +3440 -2189
  195. package/dist/behaviors-embeddings.hash.json +3 -3
  196. package/dist/behaviors-embeddings.json +230 -178
  197. package/dist/behaviors-registry.json +4397 -171
  198. package/dist/index.d.ts +1 -1
  199. package/dist/index.js +3441 -2190
  200. package/dist/knob-embeddings.hash.json +3 -3
  201. package/dist/knob-embeddings.json +1 -1
  202. package/dist/registry/factory-signatures.json +1 -1
  203. package/package.json +2 -2
@@ -0,0 +1,380 @@
1
+ app std-learn-tour-3d "1.0.0"
2
+ "Generic guided-tour-over-3D-stations instrument. Contract: a config-declared roster of stations (id, name, caption, x, y, z, radius, color, shape, opacity) plus optional connector edges (from, to, color, label), rendered as an orbit-rotatable volumetric scene on a biology-canvas in 3D mode; pressing Tour advances the selection to the next station (mod the roster length) and clicking a shape selects its station — either way the camera retargets onto the selected station's x/y/z, the station enlarges, a name — caption narration renders, and a progress readout tracks visited stations until every station has been toured. A `backdrop` knob renders non-station scene geometry under the stations (painted, never toured). SYNC_STATIONS hot-swaps the roster mid-flight (a composed preset coordinator emits it with new stations/edges/backdrop; the tour adopts them and restarts progress at the first new station) — the single-writer entry point for dynamic rosters. Composed of a biology-canvas in 3D mode plus a tour state machine. Standalone by default; behind a lab router set matchMode and it renders only when MODE_SELECTED matches."
3
+ orbital LearnTour3DOrbital {
4
+ type Learn3DStation = {
5
+ id : string!
6
+ name : string!
7
+ caption : string
8
+ x : number!
9
+ y : number!
10
+ z : number!
11
+ radius : number
12
+ color : string
13
+ shape : string
14
+ opacity : number
15
+ }
16
+
17
+ type Learn3DEdge = {
18
+ from : string!
19
+ to : string!
20
+ color : string
21
+ label : string
22
+ }
23
+
24
+ type Learn3DClick = {
25
+ id : string
26
+ type : string
27
+ index : number!
28
+ }
29
+
30
+ entity Learn3DTourScene [runtime] {
31
+ id : string!
32
+ active : boolean = false
33
+ title : string
34
+ stations : [Learn3DStation]
35
+ backdrop : [Learn3DStation] = []
36
+ edges : [Learn3DEdge]
37
+ selectedIndex : number = 0
38
+ selectedId : string = ""
39
+ visitedIds : [string] = []
40
+ tourComplete : boolean = false
41
+ narration : string = ""
42
+ }
43
+
44
+ trait Learn3DTourSim -> @rebindable Learn3DTourScene [interaction, instance] {
45
+ initial: idle
46
+
47
+ state idle {
48
+ INIT -> idle when (== @config.matchMode "")
49
+ (set @entity.active true)
50
+ (set @entity.title @config.title)
51
+ (set @entity.stations @config.stations)
52
+ (set @entity.backdrop @config.backdrop)
53
+ (set @entity.edges @config.edges)
54
+ (set @entity.selectedIndex 0)
55
+ (set @entity.selectedId (object/get (array/nth @entity.stations 0) id))
56
+ (set @entity.visitedIds [(object/get (array/nth @entity.stations 0) id)])
57
+ (set @entity.tourComplete false)
58
+ (set @entity.narration (str/concat (object/get (array/nth @entity.stations 0) name) " — " (object/get (array/nth @entity.stations 0) caption)))
59
+ (render-ui main {
60
+ type: box
61
+ padding: md
62
+ children: [
63
+ { type: stack, direction: vertical, gap: md, children: [
64
+ { type: typography, variant: h4, content: @entity.title },
65
+ { type: stack, direction: horizontal, gap: sm, children: [
66
+ { type: button, action: TOUR, label: @config.tourLabel, variant: primary },
67
+ { type: button, action: RESET, label: @config.resetLabel, variant: ghost }
68
+ ] },
69
+ { type: biology-canvas, width: @config.width, height: @config.height, backgroundColor: @config.backgroundColor,
70
+ mode: "3d",
71
+ camera: { mode: "perspective", zoom: @config.zoom, fov: @config.fov, azimuth: @config.azimuth,
72
+ target: { x: (object/get (array/nth @entity.stations @entity.selectedIndex) x), y: (object/get (array/nth @entity.stations @entity.selectedIndex) y), z: (object/get (array/nth @entity.stations @entity.selectedIndex) z) } },
73
+ lighting: @config.lighting,
74
+ post: @config.post,
75
+ nodes: (array/map (array/concat @entity.backdrop @entity.stations) (fn n { id: (object/get @n id), x: (object/get @n x), y: (object/get @n y), z: (object/get @n z), radius: (if (== (object/get @n id) @entity.selectedId) (* (object/get @n radius) 1.4) (object/get @n radius)), color: (object/get @n color), label: (object/get @n name), shape: (object/get @n shape), opacity: (object/get @n opacity) })),
76
+ edges: @entity.edges,
77
+ interactive: true,
78
+ onShapeClick: "SELECT_STATION"
79
+ },
80
+ { type: typography, variant: body, content: @entity.narration },
81
+ { type: typography, variant: caption, content: (str/concat "Explored " (str/concat "" (array/len @entity.visitedIds)) " of " (str/concat "" (array/len @entity.stations)) (if @entity.tourComplete " — tour complete!" "")) }
82
+ ] }
83
+ ]
84
+ })
85
+ (emit TOUR_3D_UPDATED { id: @entity.selectedId, name: (object/get (array/nth @entity.stations 0) name), caption: (object/get (array/nth @entity.stations 0) caption), visited: (array/len @entity.visitedIds), total: (array/len @entity.stations), tourComplete: false })
86
+
87
+ MODE_SELECTED -> idle when (== ?mode @config.matchMode)
88
+ (set @entity.active true)
89
+ (set @entity.title @config.title)
90
+ (set @entity.stations @config.stations)
91
+ (set @entity.backdrop @config.backdrop)
92
+ (set @entity.edges @config.edges)
93
+ (set @entity.selectedIndex 0)
94
+ (set @entity.selectedId (object/get (array/nth @entity.stations 0) id))
95
+ (set @entity.visitedIds [(object/get (array/nth @entity.stations 0) id)])
96
+ (set @entity.tourComplete false)
97
+ (set @entity.narration (str/concat (object/get (array/nth @entity.stations 0) name) " — " (object/get (array/nth @entity.stations 0) caption)))
98
+ (render-ui main {
99
+ type: box
100
+ padding: md
101
+ children: [
102
+ { type: stack, direction: vertical, gap: md, children: [
103
+ { type: typography, variant: h4, content: @entity.title },
104
+ { type: stack, direction: horizontal, gap: sm, children: [
105
+ { type: button, action: TOUR, label: @config.tourLabel, variant: primary },
106
+ { type: button, action: RESET, label: @config.resetLabel, variant: ghost }
107
+ ] },
108
+ { type: biology-canvas, width: @config.width, height: @config.height, backgroundColor: @config.backgroundColor,
109
+ mode: "3d",
110
+ camera: { mode: "perspective", zoom: @config.zoom, fov: @config.fov, azimuth: @config.azimuth,
111
+ target: { x: (object/get (array/nth @entity.stations @entity.selectedIndex) x), y: (object/get (array/nth @entity.stations @entity.selectedIndex) y), z: (object/get (array/nth @entity.stations @entity.selectedIndex) z) } },
112
+ lighting: @config.lighting,
113
+ post: @config.post,
114
+ nodes: (array/map (array/concat @entity.backdrop @entity.stations) (fn n { id: (object/get @n id), x: (object/get @n x), y: (object/get @n y), z: (object/get @n z), radius: (if (== (object/get @n id) @entity.selectedId) (* (object/get @n radius) 1.4) (object/get @n radius)), color: (object/get @n color), label: (object/get @n name), shape: (object/get @n shape), opacity: (object/get @n opacity) })),
115
+ edges: @entity.edges,
116
+ interactive: true,
117
+ onShapeClick: "SELECT_STATION"
118
+ },
119
+ { type: typography, variant: body, content: @entity.narration },
120
+ { type: typography, variant: caption, content: (str/concat "Explored " (str/concat "" (array/len @entity.visitedIds)) " of " (str/concat "" (array/len @entity.stations)) (if @entity.tourComplete " — tour complete!" "")) }
121
+ ] }
122
+ ]
123
+ })
124
+ (emit TOUR_3D_UPDATED { id: @entity.selectedId, name: (object/get (array/nth @entity.stations 0) name), caption: (object/get (array/nth @entity.stations 0) caption), visited: (array/len @entity.visitedIds), total: (array/len @entity.stations), tourComplete: false })
125
+
126
+ TOUR -> idle when (== @entity.active true)
127
+ (set @entity.selectedIndex (math/mod (+ @entity.selectedIndex 1) (array/len @entity.stations)))
128
+ (set @entity.selectedId (object/get (array/nth @entity.stations @entity.selectedIndex) id))
129
+ (set @entity.visitedIds (if (array/includes @entity.visitedIds @entity.selectedId) @entity.visitedIds (array/append @entity.visitedIds @entity.selectedId)))
130
+ (set @entity.tourComplete (== (array/len @entity.visitedIds) (array/len @entity.stations)))
131
+ (set @entity.narration (str/concat (object/get (array/nth @entity.stations @entity.selectedIndex) name) " — " (object/get (array/nth @entity.stations @entity.selectedIndex) caption)))
132
+ (render-ui main {
133
+ type: box
134
+ padding: md
135
+ children: [
136
+ { type: stack, direction: vertical, gap: md, children: [
137
+ { type: typography, variant: h4, content: @entity.title },
138
+ { type: stack, direction: horizontal, gap: sm, children: [
139
+ { type: button, action: TOUR, label: @config.tourLabel, variant: primary },
140
+ { type: button, action: RESET, label: @config.resetLabel, variant: ghost }
141
+ ] },
142
+ { type: biology-canvas, width: @config.width, height: @config.height, backgroundColor: @config.backgroundColor,
143
+ mode: "3d",
144
+ camera: { mode: "perspective", zoom: @config.zoom, fov: @config.fov, azimuth: @config.azimuth,
145
+ target: { x: (object/get (array/nth @entity.stations @entity.selectedIndex) x), y: (object/get (array/nth @entity.stations @entity.selectedIndex) y), z: (object/get (array/nth @entity.stations @entity.selectedIndex) z) } },
146
+ lighting: @config.lighting,
147
+ post: @config.post,
148
+ nodes: (array/map (array/concat @entity.backdrop @entity.stations) (fn n { id: (object/get @n id), x: (object/get @n x), y: (object/get @n y), z: (object/get @n z), radius: (if (== (object/get @n id) @entity.selectedId) (* (object/get @n radius) 1.4) (object/get @n radius)), color: (object/get @n color), label: (object/get @n name), shape: (object/get @n shape), opacity: (object/get @n opacity) })),
149
+ edges: @entity.edges,
150
+ interactive: true,
151
+ onShapeClick: "SELECT_STATION"
152
+ },
153
+ { type: typography, variant: body, content: @entity.narration },
154
+ { type: typography, variant: caption, content: (str/concat "Explored " (str/concat "" (array/len @entity.visitedIds)) " of " (str/concat "" (array/len @entity.stations)) (if @entity.tourComplete " — tour complete!" "")) }
155
+ ] }
156
+ ]
157
+ })
158
+ (emit TOUR_3D_UPDATED { id: @entity.selectedId, name: (object/get (array/nth @entity.stations @entity.selectedIndex) name), caption: (object/get (array/nth @entity.stations @entity.selectedIndex) caption), visited: (array/len @entity.visitedIds), total: (array/len @entity.stations), tourComplete: @entity.tourComplete })
159
+
160
+ SELECT_STATION -> idle when (== @entity.active true)
161
+ (let (
162
+ (clickedId (object/get ?payload id))
163
+ (found (array/findIndex @entity.stations (fn n (== (object/get @n id) @clickedId))))
164
+ (idx (if (>= @found 0) @found @entity.selectedIndex))
165
+ )
166
+ (do
167
+ (set @entity.selectedIndex @idx)
168
+ (set @entity.selectedId (object/get (array/nth @entity.stations @idx) id))
169
+ (set @entity.visitedIds (if (array/includes @entity.visitedIds @entity.selectedId) @entity.visitedIds (array/append @entity.visitedIds @entity.selectedId)))
170
+ (set @entity.tourComplete (== (array/len @entity.visitedIds) (array/len @entity.stations)))
171
+ (set @entity.narration (str/concat (object/get (array/nth @entity.stations @idx) name) " — " (object/get (array/nth @entity.stations @idx) caption)))
172
+ (render-ui main {
173
+ type: box
174
+ padding: md
175
+ children: [
176
+ { type: stack, direction: vertical, gap: md, children: [
177
+ { type: typography, variant: h4, content: @entity.title },
178
+ { type: stack, direction: horizontal, gap: sm, children: [
179
+ { type: button, action: TOUR, label: @config.tourLabel, variant: primary },
180
+ { type: button, action: RESET, label: @config.resetLabel, variant: ghost }
181
+ ] },
182
+ { type: biology-canvas, width: @config.width, height: @config.height, backgroundColor: @config.backgroundColor,
183
+ mode: "3d",
184
+ camera: { mode: "perspective", zoom: @config.zoom, fov: @config.fov, azimuth: @config.azimuth,
185
+ target: { x: (object/get (array/nth @entity.stations @entity.selectedIndex) x), y: (object/get (array/nth @entity.stations @entity.selectedIndex) y), z: (object/get (array/nth @entity.stations @entity.selectedIndex) z) } },
186
+ lighting: @config.lighting,
187
+ post: @config.post,
188
+ nodes: (array/map (array/concat @entity.backdrop @entity.stations) (fn n { id: (object/get @n id), x: (object/get @n x), y: (object/get @n y), z: (object/get @n z), radius: (if (== (object/get @n id) @entity.selectedId) (* (object/get @n radius) 1.4) (object/get @n radius)), color: (object/get @n color), label: (object/get @n name), shape: (object/get @n shape), opacity: (object/get @n opacity) })),
189
+ edges: @entity.edges,
190
+ interactive: true,
191
+ onShapeClick: "SELECT_STATION"
192
+ },
193
+ { type: typography, variant: body, content: @entity.narration },
194
+ { type: typography, variant: caption, content: (str/concat "Explored " (str/concat "" (array/len @entity.visitedIds)) " of " (str/concat "" (array/len @entity.stations)) (if @entity.tourComplete " — tour complete!" "")) }
195
+ ] }
196
+ ]
197
+ })
198
+ (emit TOUR_3D_UPDATED { id: @entity.selectedId, name: (object/get (array/nth @entity.stations @idx) name), caption: (object/get (array/nth @entity.stations @idx) caption), visited: (array/len @entity.visitedIds), total: (array/len @entity.stations), tourComplete: @entity.tourComplete })
199
+ )
200
+ )
201
+
202
+ RESET -> idle when (== @entity.active true)
203
+ (set @entity.selectedIndex 0)
204
+ (set @entity.selectedId (object/get (array/nth @entity.stations 0) id))
205
+ (set @entity.visitedIds [(object/get (array/nth @entity.stations 0) id)])
206
+ (set @entity.tourComplete false)
207
+ (set @entity.narration (str/concat (object/get (array/nth @entity.stations 0) name) " — " (object/get (array/nth @entity.stations 0) caption)))
208
+ (render-ui main {
209
+ type: box
210
+ padding: md
211
+ children: [
212
+ { type: stack, direction: vertical, gap: md, children: [
213
+ { type: typography, variant: h4, content: @entity.title },
214
+ { type: stack, direction: horizontal, gap: sm, children: [
215
+ { type: button, action: TOUR, label: @config.tourLabel, variant: primary },
216
+ { type: button, action: RESET, label: @config.resetLabel, variant: ghost }
217
+ ] },
218
+ { type: biology-canvas, width: @config.width, height: @config.height, backgroundColor: @config.backgroundColor,
219
+ mode: "3d",
220
+ camera: { mode: "perspective", zoom: @config.zoom, fov: @config.fov, azimuth: @config.azimuth,
221
+ target: { x: (object/get (array/nth @entity.stations @entity.selectedIndex) x), y: (object/get (array/nth @entity.stations @entity.selectedIndex) y), z: (object/get (array/nth @entity.stations @entity.selectedIndex) z) } },
222
+ lighting: @config.lighting,
223
+ post: @config.post,
224
+ nodes: (array/map (array/concat @entity.backdrop @entity.stations) (fn n { id: (object/get @n id), x: (object/get @n x), y: (object/get @n y), z: (object/get @n z), radius: (if (== (object/get @n id) @entity.selectedId) (* (object/get @n radius) 1.4) (object/get @n radius)), color: (object/get @n color), label: (object/get @n name), shape: (object/get @n shape), opacity: (object/get @n opacity) })),
225
+ edges: @entity.edges,
226
+ interactive: true,
227
+ onShapeClick: "SELECT_STATION"
228
+ },
229
+ { type: typography, variant: body, content: @entity.narration },
230
+ { type: typography, variant: caption, content: (str/concat "Explored " (str/concat "" (array/len @entity.visitedIds)) " of " (str/concat "" (array/len @entity.stations)) (if @entity.tourComplete " — tour complete!" "")) }
231
+ ] }
232
+ ]
233
+ })
234
+ (emit TOUR_3D_UPDATED { id: @entity.selectedId, name: (object/get (array/nth @entity.stations 0) name), caption: (object/get (array/nth @entity.stations 0) caption), visited: (array/len @entity.visitedIds), total: (array/len @entity.stations), tourComplete: false })
235
+
236
+ SYNC_STATIONS -> idle when (== @entity.active true)
237
+ (set @entity.stations ?stations)
238
+ (set @entity.backdrop ?backdrop)
239
+ (set @entity.edges ?edges)
240
+ (set @entity.selectedIndex 0)
241
+ (set @entity.selectedId (object/get (array/nth @entity.stations 0) id))
242
+ (set @entity.visitedIds [(object/get (array/nth @entity.stations 0) id)])
243
+ (set @entity.tourComplete false)
244
+ (set @entity.narration (str/concat (object/get (array/nth @entity.stations 0) name) " — " (object/get (array/nth @entity.stations 0) caption)))
245
+ (render-ui main {
246
+ type: box
247
+ padding: md
248
+ children: [
249
+ { type: stack, direction: vertical, gap: md, children: [
250
+ { type: typography, variant: h4, content: @entity.title },
251
+ { type: stack, direction: horizontal, gap: sm, children: [
252
+ { type: button, action: TOUR, label: @config.tourLabel, variant: primary },
253
+ { type: button, action: RESET, label: @config.resetLabel, variant: ghost }
254
+ ] },
255
+ { type: biology-canvas, width: @config.width, height: @config.height, backgroundColor: @config.backgroundColor,
256
+ mode: "3d",
257
+ camera: { mode: "perspective", zoom: @config.zoom, fov: @config.fov, azimuth: @config.azimuth,
258
+ target: { x: (object/get (array/nth @entity.stations @entity.selectedIndex) x), y: (object/get (array/nth @entity.stations @entity.selectedIndex) y), z: (object/get (array/nth @entity.stations @entity.selectedIndex) z) } },
259
+ lighting: @config.lighting,
260
+ post: @config.post,
261
+ nodes: (array/map (array/concat @entity.backdrop @entity.stations) (fn n { id: (object/get @n id), x: (object/get @n x), y: (object/get @n y), z: (object/get @n z), radius: (if (== (object/get @n id) @entity.selectedId) (* (object/get @n radius) 1.4) (object/get @n radius)), color: (object/get @n color), label: (object/get @n name), shape: (object/get @n shape), opacity: (object/get @n opacity) })),
262
+ edges: @entity.edges,
263
+ interactive: true,
264
+ onShapeClick: "SELECT_STATION"
265
+ },
266
+ { type: typography, variant: body, content: @entity.narration },
267
+ { type: typography, variant: caption, content: (str/concat "Explored " (str/concat "" (array/len @entity.visitedIds)) " of " (str/concat "" (array/len @entity.stations)) (if @entity.tourComplete " — tour complete!" "")) }
268
+ ] }
269
+ ]
270
+ })
271
+ (emit TOUR_3D_UPDATED { id: @entity.selectedId, name: (object/get (array/nth @entity.stations 0) name), caption: (object/get (array/nth @entity.stations 0) caption), visited: (array/len @entity.visitedIds), total: (array/len @entity.stations), tourComplete: false })
272
+ }
273
+
274
+ listens {
275
+ MODE_SELECTED {
276
+ mode : string
277
+ }
278
+ @description "Lab router broadcast naming the active mode; this instrument renders when the mode equals matchMode, otherwise renders null."
279
+ @tier "domain"
280
+ SELECT_STATION {
281
+ payload : Learn3DClick
282
+ }
283
+ @description "Canvas shape-click from the 3D scene (biology-canvas onShapeClick) carrying the clicked station's id, type, and roster index."
284
+ @tier "domain"
285
+ SYNC_STATIONS {
286
+ stations : [Learn3DStation]
287
+ edges : [Learn3DEdge]
288
+ backdrop : [Learn3DStation]
289
+ }
290
+ @description "Roster hot-swap from a composed preset coordinator — the tour adopts the new stations/edges/backdrop and restarts progress at the first new station; the single-writer entry point for dynamic rosters."
291
+ @tier "domain"
292
+ }
293
+
294
+ emits {
295
+ TOUR_3D_UPDATED -> external {
296
+ id : string
297
+ name : string
298
+ caption : string
299
+ visited : number
300
+ total : number
301
+ tourComplete : boolean
302
+ }
303
+ @description "Fires on INIT/MODE_SELECTED/Tour/click/Reset with the currently selected station's id, name, and caption, plus visited/total progress and whether every station has now been visited — a composed listener (readout, quiz) can subscribe; a harmless no-op when the atom runs standalone."
304
+ @synonyms "select, choose, station, explore, tour, flythrough, pick"
305
+ @tier "domain"
306
+ }
307
+
308
+ config {
309
+ matchMode : string = ""
310
+ @label "Match Mode"
311
+ @description "When composed behind a lab router, the MODE_SELECTED mode value this instrument responds to. Empty string means standalone — render immediately on INIT."
312
+ @tier "presentation"
313
+ title : string = "3D Guided Tour"
314
+ @label "Title"
315
+ @description "Title shown above the canvas."
316
+ @tier "presentation"
317
+ stations : [Learn3DStation] = [
318
+ { id: "alpha", name: "Station Alpha", caption: "The first stop on the tour — the camera retargets here and the narration reads its caption.", x: 0, y: 0, z: 0, radius: 1, color: "#2563eb", shape: sphere, opacity: 1 },
319
+ { id: "beta", name: "Station Beta", caption: "The second stop — press Tour again or click a shape to advance the selection.", x: 3, y: 1, z: -1, radius: 0.8, color: "#7c3aed", shape: sphere, opacity: 1 },
320
+ { id: "gamma", name: "Station Gamma", caption: "The final stop — once every station has been visited the tour marks itself complete.", x: -3, y: -1, z: 1, radius: 0.8, color: "#0891b2", shape: sphere, opacity: 1 }
321
+ ]
322
+ @label "Stations"
323
+ @description "The station roster in didactic tour order — each with scene position, mesh shape, and a caption. Tour and clicks enlarge the selected station, retarget the camera onto its x/y/z, and narrate its caption."
324
+ @synonyms "station, stop, waypoint, tour, landmark, 3d"
325
+ @tier "domain"
326
+ edges : [Learn3DEdge] = []
327
+ @label "Edges"
328
+ @description "Optional connector lines drawn between stations, by id."
329
+ @synonyms "edge, link, connector, tether"
330
+ @tier "domain"
331
+ backdrop : [Learn3DStation] = []
332
+ @label "Backdrop Nodes"
333
+ @description "Non-station scene geometry rendered under the tour stations (painted first, stations on top) — painted but never tour stops and never highlight-selected; SYNC_STATIONS swaps it together with the roster, so a composed preset coordinator can re-skin the whole scene per preset."
334
+ @synonyms "backdrop, scenery, geometry, context nodes, 3d"
335
+ @tier "domain"
336
+ tourLabel : string = "Tour"
337
+ @label "Tour Button Label"
338
+ @description "Label text for the button that advances the tour to the next station."
339
+ @tier "presentation"
340
+ resetLabel : string = "Reset"
341
+ @label "Reset Button Label"
342
+ @description "Label text for the button that returns the tour to the first station."
343
+ @tier "presentation"
344
+ zoom : number = 1
345
+ @label "Zoom"
346
+ @description "Camera zoom factor for the 3D scene."
347
+ @tier "presentation"
348
+ fov : number = 50
349
+ @label "Field of View"
350
+ @description "Perspective camera field of view in degrees."
351
+ @tier "presentation"
352
+ azimuth : number = 0.6
353
+ @label "Azimuth"
354
+ @description "Camera orbit azimuth in radians; the learner can orbit freely on top of this."
355
+ @tier "presentation"
356
+ lighting : json = {}
357
+ @label "Lighting"
358
+ @description "3D scene light rig as data; empty object uses the standard rig."
359
+ @tier "presentation"
360
+ post : json = {}
361
+ @label "Post Processing"
362
+ @description "3D post-processing stack (bloom/vignette) as data; empty object disables it."
363
+ @tier "presentation"
364
+ width : number = 600
365
+ @label "Width"
366
+ @description "Canvas width in pixels."
367
+ @tier "presentation"
368
+ height : number = 400
369
+ @label "Height"
370
+ @description "Canvas height in pixels."
371
+ @tier "presentation"
372
+ backgroundColor : string = "#0f172a"
373
+ @label "Background Color"
374
+ @description "Canvas background color — a dark stage makes translucent shells and station colors read in 3D."
375
+ @tier "presentation"
376
+ }
377
+ }
378
+
379
+ page "/learn-tour-3d" as Learn3DTourPage -> Learn3DTourSim
380
+ }
@@ -5,10 +5,13 @@ orbital BiologyCanvasOrbital {
5
5
  id : string
6
6
  x : number!
7
7
  y : number!
8
+ z : number
8
9
  radius : number
9
10
  color : string
10
11
  label : string
11
12
  kind : "cell" | "organelle" | "molecule" | "organism"
13
+ shape : "box" | "sphere" | "capsule" | "cylinder" | "cone" | "torus" | "plane" | "circle" | "polyhedron"
14
+ opacity : number
12
15
  }
13
16
  type BiologyCanvasEdgesItem = {
14
17
  from : string!
@@ -74,9 +77,15 @@ orbital BiologyCanvasOrbital {
74
77
  height: @config.height
75
78
  title: @config.title
76
79
  backgroundColor: @config.backgroundColor
80
+ mode: @config.mode
81
+ camera: @config.camera
82
+ lighting: @config.lighting
83
+ post: @config.post
77
84
  nodes: @config.nodes
78
85
  edges: @config.edges
79
86
  shapes: @config.shapes
87
+ showGrid: @config.showGrid
88
+ shadows: @config.shadows
80
89
  interactive: @config.interactive
81
90
  animate: @config.animate
82
91
  onShapeClick: @config.onShapeClick
@@ -91,9 +100,15 @@ orbital BiologyCanvasOrbital {
91
100
  height: @config.height
92
101
  title: @config.title
93
102
  backgroundColor: @config.backgroundColor
103
+ mode: @config.mode
104
+ camera: @config.camera
105
+ lighting: @config.lighting
106
+ post: @config.post
94
107
  nodes: @payload.nodes
95
108
  edges: @payload.edges
96
109
  shapes: @payload.shapes
110
+ showGrid: @config.showGrid
111
+ shadows: @config.shadows
97
112
  interactive: @config.interactive
98
113
  animate: @config.animate
99
114
  onShapeClick: @config.onShapeClick
@@ -143,6 +158,22 @@ orbital BiologyCanvasOrbital {
143
158
  @label "Background Color"
144
159
  @description "backgroundColor prop"
145
160
  @tier "presentation"
161
+ mode : "2d" | "3d" = "2d"
162
+ @label "Mode"
163
+ @description "Painter: 2D raster (default) or 3D mesh scene via the lazy three.js host."
164
+ @tier "presentation"
165
+ camera : json = {}
166
+ @label "Camera"
167
+ @description "3D only: neutral camera pose ({ mode, zoom, fov, azimuth, target })."
168
+ @tier "presentation"
169
+ lighting : json = {}
170
+ @label "Lighting"
171
+ @description "3D only: scene light rig as data."
172
+ @tier "presentation"
173
+ post : json = {}
174
+ @label "Post"
175
+ @description "3D only: post-processing stack (bloom/vignette)."
176
+ @tier "presentation"
146
177
  nodes : [BiologyCanvasNodesItem] = []
147
178
  @label "Nodes"
148
179
  @description "nodes prop"
@@ -153,15 +184,23 @@ orbital BiologyCanvasOrbital {
153
184
  @tier "presentation"
154
185
  shapes : [BiologyCanvasShapesItem] = []
155
186
  @label "Shapes"
156
- @description "Extra declarative shapes in canvas pixel coordinates."
187
+ @description "Extra declarative shapes in canvas pixel coordinates (2D mode only — ignored in 3D)."
188
+ @tier "presentation"
189
+ showGrid : boolean
190
+ @label "Show Grid"
191
+ @description "3D only: show the ground grid (default off)."
192
+ @tier "presentation"
193
+ shadows : boolean
194
+ @label "Shadows"
195
+ @description "3D only: enable shadows. Omitted → the host default."
157
196
  @tier "presentation"
158
- interactive : boolean = false
197
+ interactive : boolean
159
198
  @label "Interactive"
160
- @description "interactive prop"
199
+ @description "2D: pointer interaction (click/hover). 3D: orbit camera controls."
161
200
  @tier "presentation"
162
201
  animate : boolean = false
163
202
  @label "Animate"
164
- @description "animate prop"
203
+ @description "2D only: continuous redraw loop. 3D motion is entity-state driven."
165
204
  @tier "presentation"
166
205
  onShapeClick : string = "SHAPE_CLICK"
167
206
  @label "On Shape Click"
@@ -5,6 +5,7 @@ orbital ChemistryCanvasOrbital {
5
5
  id : string
6
6
  x : number!
7
7
  y : number!
8
+ z : number
8
9
  element : string
9
10
  radius : number
10
11
  color : string
@@ -81,10 +82,16 @@ orbital ChemistryCanvasOrbital {
81
82
  height: @config.height
82
83
  title: @config.title
83
84
  backgroundColor: @config.backgroundColor
85
+ mode: @config.mode
86
+ camera: @config.camera
87
+ lighting: @config.lighting
88
+ post: @config.post
84
89
  atoms: @config.atoms
85
90
  bonds: @config.bonds
86
91
  arrows: @config.arrows
87
92
  shapes: @config.shapes
93
+ showGrid: @config.showGrid
94
+ shadows: @config.shadows
88
95
  interactive: @config.interactive
89
96
  animate: @config.animate
90
97
  onShapeClick: @config.onShapeClick
@@ -99,10 +106,16 @@ orbital ChemistryCanvasOrbital {
99
106
  height: @config.height
100
107
  title: @config.title
101
108
  backgroundColor: @config.backgroundColor
109
+ mode: @config.mode
110
+ camera: @config.camera
111
+ lighting: @config.lighting
112
+ post: @config.post
102
113
  atoms: @payload.atoms
103
114
  bonds: @payload.bonds
104
115
  arrows: @payload.arrows
105
116
  shapes: @payload.shapes
117
+ showGrid: @config.showGrid
118
+ shadows: @config.shadows
106
119
  interactive: @config.interactive
107
120
  animate: @config.animate
108
121
  onShapeClick: @config.onShapeClick
@@ -153,6 +166,22 @@ orbital ChemistryCanvasOrbital {
153
166
  @label "Background Color"
154
167
  @description "backgroundColor prop"
155
168
  @tier "presentation"
169
+ mode : "2d" | "3d" = "2d"
170
+ @label "Mode"
171
+ @description "Painter: 2D raster (default) or 3D mesh scene via the lazy three.js host."
172
+ @tier "presentation"
173
+ camera : json = {}
174
+ @label "Camera"
175
+ @description "3D only: neutral camera pose ({ mode, zoom, fov, azimuth, target })."
176
+ @tier "presentation"
177
+ lighting : json = {}
178
+ @label "Lighting"
179
+ @description "3D only: scene light rig as data."
180
+ @tier "presentation"
181
+ post : json = {}
182
+ @label "Post"
183
+ @description "3D only: post-processing stack (bloom/vignette)."
184
+ @tier "presentation"
156
185
  atoms : [ChemistryCanvasAtomsItem] = []
157
186
  @label "Atoms"
158
187
  @description "atoms prop"
@@ -167,15 +196,23 @@ orbital ChemistryCanvasOrbital {
167
196
  @tier "presentation"
168
197
  shapes : [ChemistryCanvasShapesItem] = []
169
198
  @label "Shapes"
170
- @description "Extra declarative shapes in canvas pixel coordinates."
199
+ @description "Extra declarative shapes in canvas pixel coordinates (2D mode only — ignored in 3D)."
200
+ @tier "presentation"
201
+ showGrid : boolean
202
+ @label "Show Grid"
203
+ @description "3D only: show the ground grid (default off)."
204
+ @tier "presentation"
205
+ shadows : boolean
206
+ @label "Shadows"
207
+ @description "3D only: enable shadows. Omitted → the host default."
171
208
  @tier "presentation"
172
- interactive : boolean = false
209
+ interactive : boolean
173
210
  @label "Interactive"
174
- @description "interactive prop"
211
+ @description "2D: pointer interaction (click/hover). 3D: orbit camera controls."
175
212
  @tier "presentation"
176
213
  animate : boolean = false
177
214
  @label "Animate"
178
- @description "animate prop"
215
+ @description "2D only: continuous redraw loop. 3D motion is entity-state driven."
179
216
  @tier "presentation"
180
217
  onShapeClick : string = "SHAPE_CLICK"
181
218
  @label "On Shape Click"