@almadar/std 16.243.0 → 16.244.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 (140) hide show
  1. package/behaviors/behaviors-registry.json +4470 -513
  2. package/behaviors/lolo/agent/atoms/std-agent-context.lolo +24 -4
  3. package/behaviors/lolo/agent/atoms/std-agent-memory.lolo +20 -5
  4. package/behaviors/lolo/agent/atoms/std-agent-proposal.lolo +550 -0
  5. package/behaviors/lolo/agent/atoms/std-agent-session.lolo +284 -25
  6. package/behaviors/lolo/agent/atoms/std-agent-suggestions.lolo +841 -0
  7. package/behaviors/lolo/agent/atoms/std-agent-tool-loop.lolo +58 -8
  8. package/behaviors/lolo/agent/organisms/std-agent-assistant.lolo +1 -0
  9. package/behaviors/lolo/infra/atoms/std-page-treat.lolo +28 -1
  10. package/behaviors/lolo/ui/avl/atoms/ui-avl-state-machine.lolo +22 -0
  11. package/behaviors/lolo/ui/avl/atoms/ui-avl-transition-explainer.lolo +175 -0
  12. package/behaviors/lolo/ui/avl/atoms/ui-module-card.lolo +22 -0
  13. package/behaviors/lolo/ui/core/atoms/std-app-layout.lolo +23 -4
  14. package/behaviors/lolo/ui/core/atoms/std-hero.lolo +72 -33
  15. package/behaviors/lolo/ui/core/molecules/ui-agent-chat-feed.lolo +1 -1
  16. package/behaviors/lolo/ui/core/molecules/ui-markdown-content.lolo +54 -0
  17. package/behaviors/lolo/ui/core/molecules/ui-upload-drop-zone.lolo +5 -0
  18. package/behaviors/lolo/ui/core/organisms/ui-segment-renderer.lolo +127 -3
  19. package/behaviors/lolo/ui/core/organisms/ui-state-machine-view.lolo +22 -0
  20. package/behaviors/lolo/ui/core/templates/ui-dashboard-layout.lolo +2 -2
  21. package/behaviors/lolo/ui/learning/atoms/std-learn-arrangement.lolo +87 -17
  22. package/behaviors/lolo/ui/learning/atoms/std-learn-classify.lolo +172 -37
  23. package/behaviors/lolo/ui/learning/atoms/std-learn-coupled-sim.lolo +183 -70
  24. package/behaviors/lolo/ui/learning/atoms/std-learn-derivation.lolo +78 -13
  25. package/behaviors/lolo/ui/learning/atoms/std-learn-diagram.lolo +58 -2
  26. package/behaviors/lolo/ui/learning/atoms/std-learn-doser.lolo +107 -12
  27. package/behaviors/lolo/ui/learning/atoms/std-learn-estimate.lolo +83 -10
  28. package/behaviors/lolo/ui/learning/atoms/std-learn-goal-seek.lolo +130 -9
  29. package/behaviors/lolo/ui/learning/atoms/std-learn-grid-sim.lolo +143 -59
  30. package/behaviors/lolo/ui/learning/atoms/std-learn-hotspot.lolo +96 -22
  31. package/behaviors/lolo/ui/learning/atoms/std-learn-live-sim.lolo +66 -5
  32. package/behaviors/lolo/ui/learning/atoms/std-learn-predict.lolo +84 -6
  33. package/behaviors/lolo/ui/learning/atoms/std-learn-sandbox.lolo +80 -14
  34. package/behaviors/lolo/ui/learning/atoms/std-learn-scatter-fit.lolo +99 -5
  35. package/behaviors/lolo/ui/learning/atoms/std-learn-scenario.lolo +81 -7
  36. package/behaviors/lolo/ui/learning/atoms/std-learn-speed-drill.lolo +83 -7
  37. package/behaviors/lolo/ui/learning/atoms/std-learn-stepper.lolo +224 -99
  38. package/behaviors/lolo/ui/learning/atoms/std-learn-tour-3d.lolo +63 -2
  39. package/behaviors/lolo/ui/learning/atoms/std-learn-trace-player.lolo +99 -38
  40. package/behaviors/lolo/ui/learning/atoms/std-learn-transport.lolo +7 -7
  41. package/behaviors/lolo/ui/learning/atoms/std-learn-tree.lolo +69 -4
  42. package/behaviors/lolo-behavior-contracts.json +1 -1
  43. package/behaviors/registry/agent/atoms/std-agent-context.orb +205 -6
  44. package/behaviors/registry/agent/atoms/std-agent-memory.orb +146 -4
  45. package/behaviors/registry/agent/atoms/std-agent-proposal.orb +1972 -0
  46. package/behaviors/registry/agent/atoms/std-agent-session.orb +2021 -597
  47. package/behaviors/registry/agent/atoms/std-agent-suggestions.orb +5079 -0
  48. package/behaviors/registry/agent/atoms/std-agent-tool-loop.orb +287 -5
  49. package/behaviors/registry/agent/organisms/std-agent-assistant.orb +7 -0
  50. package/behaviors/registry/factory-signatures.json +1 -1
  51. package/behaviors/registry/infra/atoms/std-page-treat.orb +327 -2
  52. package/behaviors/registry/ui/avl/atoms/ui-avl-state-machine.orb +134 -0
  53. package/behaviors/registry/ui/avl/atoms/ui-avl-transition-explainer.orb +678 -0
  54. package/behaviors/registry/ui/avl/atoms/ui-module-card.orb +122 -0
  55. package/behaviors/registry/ui/core/atoms/std-app-layout.orb +73 -4
  56. package/behaviors/registry/ui/core/atoms/std-hero.orb +174 -97
  57. package/behaviors/registry/ui/core/molecules/ui-markdown-content.orb +204 -1
  58. package/behaviors/registry/ui/core/molecules/ui-upload-drop-zone.orb +12 -0
  59. package/behaviors/registry/ui/core/organisms/ui-segment-renderer.orb +683 -30
  60. package/behaviors/registry/ui/learning/atoms/std-learn-arrangement.orb +748 -21
  61. package/behaviors/registry/ui/learning/atoms/std-learn-classify.orb +1429 -41
  62. package/behaviors/registry/ui/learning/atoms/std-learn-coupled-sim.orb +1031 -185
  63. package/behaviors/registry/ui/learning/atoms/std-learn-derivation.orb +807 -132
  64. package/behaviors/registry/ui/learning/atoms/std-learn-diagram.orb +553 -6
  65. package/behaviors/registry/ui/learning/atoms/std-learn-doser.orb +987 -21
  66. package/behaviors/registry/ui/learning/atoms/std-learn-estimate.orb +582 -16
  67. package/behaviors/registry/ui/learning/atoms/std-learn-goal-seek.orb +954 -13
  68. package/behaviors/registry/ui/learning/atoms/std-learn-grid-sim.orb +828 -88
  69. package/behaviors/registry/ui/learning/atoms/std-learn-hotspot.orb +730 -28
  70. package/behaviors/registry/ui/learning/atoms/std-learn-live-sim.orb +479 -9
  71. package/behaviors/registry/ui/learning/atoms/std-learn-predict.orb +797 -46
  72. package/behaviors/registry/ui/learning/atoms/std-learn-sandbox.orb +757 -58
  73. package/behaviors/registry/ui/learning/atoms/std-learn-scatter-fit.orb +1176 -164
  74. package/behaviors/registry/ui/learning/atoms/std-learn-scenario.orb +599 -12
  75. package/behaviors/registry/ui/learning/atoms/std-learn-speed-drill.orb +832 -150
  76. package/behaviors/registry/ui/learning/atoms/std-learn-stepper.orb +1561 -127
  77. package/behaviors/registry/ui/learning/atoms/std-learn-tour-3d.orb +655 -6
  78. package/behaviors/registry/ui/learning/atoms/std-learn-trace-player.orb +634 -43
  79. package/behaviors/registry/ui/learning/atoms/std-learn-transport.orb +85 -31
  80. package/behaviors/registry/ui/learning/atoms/std-learn-tree.orb +425 -9
  81. package/canonical-operators.json +45 -2
  82. package/dist/behaviors/exports-reader.js +16667 -7868
  83. package/dist/behaviors/functions/index.d.ts +711 -32
  84. package/dist/behaviors/functions/index.js +16651 -7869
  85. package/dist/behaviors/index.d.ts +1 -1
  86. package/dist/behaviors/index.js +16668 -7869
  87. package/dist/behaviors/query.js +16667 -7868
  88. package/dist/behaviors-embeddings.hash.json +3 -3
  89. package/dist/behaviors-embeddings.json +77 -53
  90. package/dist/behaviors-registry.json +4470 -513
  91. package/dist/index.d.ts +3 -3
  92. package/dist/index.js +16101 -7275
  93. package/dist/knob-embeddings.hash.json +3 -3
  94. package/dist/knob-embeddings.json +1309 -685
  95. package/dist/modules/anim.d.ts +1 -1
  96. package/dist/modules/array.d.ts +1 -1
  97. package/dist/modules/async.d.ts +1 -1
  98. package/dist/modules/behavior.d.ts +1 -1
  99. package/dist/modules/browser.d.ts +1 -1
  100. package/dist/modules/composition.d.ts +1 -1
  101. package/dist/modules/contract.d.ts +1 -1
  102. package/dist/modules/core.d.ts +1 -1
  103. package/dist/modules/core.js +29 -2
  104. package/dist/modules/data.d.ts +1 -1
  105. package/dist/modules/ease.d.ts +1 -1
  106. package/dist/modules/format.d.ts +1 -1
  107. package/dist/modules/geo.d.ts +1 -1
  108. package/dist/modules/graph.d.ts +1 -1
  109. package/dist/modules/grid.d.ts +1 -1
  110. package/dist/modules/i18n.d.ts +1 -1
  111. package/dist/modules/index.d.ts +1 -1
  112. package/dist/modules/index.js +29 -2
  113. package/dist/modules/integration.d.ts +1 -1
  114. package/dist/modules/json.d.ts +1 -1
  115. package/dist/modules/llm.d.ts +1 -1
  116. package/dist/modules/math.d.ts +1 -1
  117. package/dist/modules/memory.d.ts +1 -1
  118. package/dist/modules/nn.d.ts +1 -1
  119. package/dist/modules/noise.d.ts +1 -1
  120. package/dist/modules/object.d.ts +1 -1
  121. package/dist/modules/os.d.ts +1 -1
  122. package/dist/modules/path.d.ts +1 -1
  123. package/dist/modules/prob.d.ts +1 -1
  124. package/dist/modules/session.d.ts +1 -1
  125. package/dist/modules/str.d.ts +1 -1
  126. package/dist/modules/tensor.d.ts +1 -1
  127. package/dist/modules/time.d.ts +1 -1
  128. package/dist/modules/trace.d.ts +1 -1
  129. package/dist/modules/train.d.ts +1 -1
  130. package/dist/modules/validate.d.ts +1 -1
  131. package/dist/modules/vector.d.ts +1 -1
  132. package/dist/modules/workspace.d.ts +1 -1
  133. package/dist/registry/factory-signatures.json +1 -1
  134. package/dist/registry.d.ts +2 -2
  135. package/dist/registry.js +29 -2
  136. package/dist/{types-Cdb321uM.d.ts → types-Y-yYWEOX.d.ts} +1 -1
  137. package/i18n/ar.json +3 -1
  138. package/i18n/en.json +2 -0
  139. package/i18n/sl.json +3 -1
  140. package/package.json +3 -3
@@ -12,6 +12,7 @@ orbital EstimateOrbital {
12
12
  id : string!
13
13
  active : boolean = false
14
14
  title : string
15
+ prompts : [EstimatePrompt]
15
16
  promptIndex : number = 0
16
17
  totalPrompts : number = 0
17
18
  estimate : number = 0
@@ -31,15 +32,16 @@ orbital EstimateOrbital {
31
32
  initial: idle
32
33
 
33
34
  state idle {
34
- INIT -> idle when (== @config.matchMode "")
35
+ INIT -> idle when (and (== @config.matchMode "") (== @config.rosterSource "config"))
36
+ (set @entity.prompts @config.prompts)
35
37
  (let (
36
- (first (array/nth @config.prompts 0))
38
+ (first (array/nth @entity.prompts 0))
37
39
  )
38
40
  (do
39
41
  (set @entity.active true)
40
42
  (set @entity.title @config.title)
41
43
  (set @entity.promptIndex 0)
42
- (set @entity.totalPrompts (array/len @config.prompts))
44
+ (set @entity.totalPrompts (array/len @entity.prompts))
43
45
  (set @entity.estimate @config.sliderDefault)
44
46
  (set @entity.locked false)
45
47
  (set @entity.band "")
@@ -90,15 +92,16 @@ orbital EstimateOrbital {
90
92
  (set @entity.active false)
91
93
  (render-ui main null)
92
94
 
93
- MODE_SELECTED -> idle when (== ?mode @config.matchMode)
95
+ MODE_SELECTED -> idle when (and (== ?mode @config.matchMode) (== @config.rosterSource "config"))
96
+ (set @entity.prompts @config.prompts)
94
97
  (let (
95
- (first (array/nth @config.prompts 0))
98
+ (first (array/nth @entity.prompts 0))
96
99
  )
97
100
  (do
98
101
  (set @entity.active true)
99
102
  (set @entity.title @config.title)
100
103
  (set @entity.promptIndex 0)
101
- (set @entity.totalPrompts (array/len @config.prompts))
104
+ (set @entity.totalPrompts (array/len @entity.prompts))
102
105
  (set @entity.estimate @config.sliderDefault)
103
106
  (set @entity.locked false)
104
107
  (set @entity.band "")
@@ -145,6 +148,66 @@ orbital EstimateOrbital {
145
148
  ]
146
149
  })
147
150
 
151
+ ROSTER_LOADED -> idle when (and (== @config.rosterSource "event") (and (== ?mode @config.matchMode) (> (array/len ?prompts) 0)))
152
+ (set @entity.prompts ?prompts)
153
+ (let (
154
+ (first (array/nth @entity.prompts 0))
155
+ )
156
+ (do
157
+ (set @entity.active true)
158
+ (set @entity.title @config.title)
159
+ (set @entity.promptIndex 0)
160
+ (set @entity.totalPrompts (array/len @entity.prompts))
161
+ (set @entity.estimate @config.sliderDefault)
162
+ (set @entity.locked false)
163
+ (set @entity.band "")
164
+ (set @entity.score 0)
165
+ (set @entity.done false)
166
+ (set @entity.promptText (object/get @first prompt))
167
+ (set @entity.promptHint (object/get @first hint ""))
168
+ (set @entity.answer (object/get @first answer))
169
+ (set @entity.unit (object/get @first unit ""))
170
+ (set @entity.feedback "")
171
+ (set @entity.view [
172
+ { type: card, variant: bordered, padding: md, children: [
173
+ { type: typography, variant: body, content: @entity.promptText },
174
+ { type: typography, variant: caption, color: muted, content: @entity.promptHint }
175
+ ] },
176
+ { type: stack, direction: vertical, gap: xs, children: [
177
+ { type: typography, variant: caption, content: (str/concat "Your estimate: " (math/round @entity.estimate 2) " " @entity.unit) },
178
+ { type: range-slider, min: @config.sliderMin, max: @config.sliderMax, step: @config.sliderStep, value: @entity.estimate, showTooltip: true, action: "SET_ESTIMATE" }
179
+ ] },
180
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
181
+ { type: button, action: LOCK_IN, label: @config.lockLabel, icon: "check", variant: primary, disabled: (if @entity.locked true false) },
182
+ { type: button, action: NEXT, label: @config.nextLabel, icon: "chevron-right", variant: secondary, disabled: (if @entity.locked false true) }
183
+ ] },
184
+ { type: stack, direction: horizontal, gap: xs, children: [
185
+ { type: typography, variant: body, content: @entity.feedback }
186
+ ] },
187
+ { type: stat-display, label: "Score", value: @entity.score, max: (* @entity.totalPrompts @config.exactPoints) }
188
+ ])))
189
+ (render-ui main {
190
+ type: box
191
+ padding: md
192
+ children: [
193
+ { type: stack, direction: vertical, gap: md, children: [
194
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
195
+ { type: stack, direction: vertical, gap: xs, children: [
196
+ { type: typography, variant: h4, content: @entity.title },
197
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
198
+ ] },
199
+ { type: badge, label: (if @entity.done "Complete" (if (== @entity.band "exact") "Spot on" (if (== @entity.band "close") "Close" (if (== @entity.band "off") "Off" "Estimating")))), variant: (if @entity.done "success" (if (== @entity.band "exact") "success" (if (== @entity.band "close") "warning" (if (== @entity.band "off") "danger" "neutral")))) }
200
+ ] },
201
+ { type: progress-bar, value: (+ @entity.promptIndex 1), max: @entity.totalPrompts, showPercentage: false, label: (str/concat "Prompt " (str/concat "" (+ @entity.promptIndex 1)) " of " (str/concat "" @entity.totalPrompts)) },
202
+ { type: stack, direction: vertical, gap: md, children: @entity.view }
203
+ ] }
204
+ ]
205
+ })
206
+
207
+ ROSTER_LOADED -> idle when (and (== @config.rosterSource "event") (not (== ?mode @config.matchMode)))
208
+ (set @entity.active false)
209
+ (render-ui main null)
210
+
148
211
  SET_ESTIMATE -> idle when (and (== @entity.active true) (and (== @entity.locked false) (== @entity.done false)))
149
212
  (set @entity.estimate (math/clamp ?value @config.sliderMin @config.sliderMax))
150
213
  (set @entity.view [
@@ -233,11 +296,11 @@ orbital EstimateOrbital {
233
296
  (emit ESTIMATE_JUDGED { band: @entity.band, estimate: @entity.estimate, answer: @entity.answer, score: @entity.score })
234
297
 
235
298
  NEXT -> idle when (and (== @entity.active true) (and (== @entity.locked true) (== @entity.done false)))
236
- (if (>= (+ @entity.promptIndex 1) (array/len @config.prompts)) (emit LEARN_ROUND_COMPLETE { score: @entity.score, total: (array/len @config.prompts) }) null)
299
+ (if (>= (+ @entity.promptIndex 1) (array/len @entity.prompts)) (emit LEARN_ROUND_COMPLETE { score: @entity.score, total: (array/len @entity.prompts) }) null)
237
300
  (let (
238
301
  (nextIndex (+ @entity.promptIndex 1))
239
- (finished (>= @nextIndex (array/len @config.prompts)))
240
- (next (array/nth @config.prompts (math/min @nextIndex (- (array/len @config.prompts) 1))))
302
+ (finished (>= @nextIndex (array/len @entity.prompts)))
303
+ (next (array/nth @entity.prompts (math/min @nextIndex (- (array/len @entity.prompts) 1))))
241
304
  )
242
305
  (do
243
306
  (set @entity.promptIndex (if @finished @entity.promptIndex @nextIndex))
@@ -296,7 +359,7 @@ orbital EstimateOrbital {
296
359
 
297
360
  RETRY -> idle when (and (== @entity.active true) (== @entity.done true))
298
361
  (let (
299
- (first (array/nth @config.prompts 0))
362
+ (first (array/nth @entity.prompts 0))
300
363
  )
301
364
  (do
302
365
  (set @entity.promptIndex 0)
@@ -354,6 +417,12 @@ orbital EstimateOrbital {
354
417
  }
355
418
  @description "Lab router broadcast naming the active mode; this instrument renders when the mode equals matchMode, otherwise renders null."
356
419
  @tier "domain"
420
+ ROSTER_LOADED {
421
+ mode : string!
422
+ prompts : [EstimatePrompt]!
423
+ }
424
+ @description "Runtime content feed, honoured only when rosterSource is event — mode names the instrument it is for (the matchMode it carries, blank when standalone) and prompts is the prompt list; a matching instrument re-initialises from it exactly as INIT does from config, any other instrument hides."
425
+ @tier "domain"
357
426
  SET_ESTIMATE {
358
427
  value : number
359
428
  }
@@ -417,6 +486,10 @@ orbital EstimateOrbital {
417
486
  @label "Concept"
418
487
  @description "One line under the title saying what the learner is looking at (keep it under ~65 characters). Empty shows no line."
419
488
  @tier "presentation"
489
+ rosterSource : "config" | "event" = "config"
490
+ @label "Roster Source"
491
+ @description "Where the prompt roster comes from: config reads the prompts knob at INIT; event waits for ROSTER_LOADED and takes the roster from its payload."
492
+ @tier "domain"
420
493
  prompts : [EstimatePrompt] = [
421
494
  { prompt: "How many meters does light travel in one microsecond?", answer: 300, unit: "m", hint: "Light covers 300,000 km every second." },
422
495
  { prompt: "What is the boiling point of water at sea level, in Fahrenheit?", answer: 212, unit: "°F", hint: "It is 100 °C." },
@@ -16,6 +16,9 @@ orbital GoalSeekOrbital {
16
16
  active : boolean = false
17
17
  title : string
18
18
  curveKind : string
19
+ goalText : string
20
+ targetA : number
21
+ targetB : number
19
22
  paramA : number
20
23
  paramB : number
21
24
  paramALabel : string
@@ -35,7 +38,7 @@ orbital GoalSeekOrbital {
35
38
  initial: idle
36
39
 
37
40
  state idle {
38
- INIT -> idle when (== @config.matchMode "")
41
+ INIT -> idle when (and (== @config.matchMode "") (== @config.rosterSource "config"))
39
42
  (let (
40
43
  (kind @config.curveKind)
41
44
  (span (- @config.xMax @config.xMin))
@@ -77,6 +80,9 @@ orbital GoalSeekOrbital {
77
80
  (set @entity.active true)
78
81
  (set @entity.title @config.title)
79
82
  (set @entity.curveKind @kind)
83
+ (set @entity.goalText @config.goalText)
84
+ (set @entity.targetA @tA)
85
+ (set @entity.targetB @tB)
80
86
  (set @entity.paramA @A)
81
87
  (set @entity.paramB @B)
82
88
  (set @entity.paramALabel @config.paramALabel)
@@ -121,7 +127,7 @@ orbital GoalSeekOrbital {
121
127
  { type: range-slider, min: @config.paramBMin, max: @config.paramBMax, step: @config.paramBStep, value: @entity.paramB, showTooltip: true, action: "SET_PARAM_B" }
122
128
  ] }
123
129
  ] },
124
- { type: typography, variant: body, content: @config.goalText },
130
+ { type: typography, variant: body, content: @entity.goalText },
125
131
  { type: typography, variant: caption, color: muted, content: @entity.feedback }
126
132
  ] }
127
133
  ]
@@ -131,7 +137,7 @@ orbital GoalSeekOrbital {
131
137
  (set @entity.active false)
132
138
  (render-ui main null)
133
139
 
134
- MODE_SELECTED -> idle when (== ?mode @config.matchMode)
140
+ MODE_SELECTED -> idle when (and (== ?mode @config.matchMode) (== @config.rosterSource "config"))
135
141
  (let (
136
142
  (kind @config.curveKind)
137
143
  (span (- @config.xMax @config.xMin))
@@ -173,6 +179,9 @@ orbital GoalSeekOrbital {
173
179
  (set @entity.active true)
174
180
  (set @entity.title @config.title)
175
181
  (set @entity.curveKind @kind)
182
+ (set @entity.goalText @config.goalText)
183
+ (set @entity.targetA @tA)
184
+ (set @entity.targetB @tB)
176
185
  (set @entity.paramA @A)
177
186
  (set @entity.paramB @B)
178
187
  (set @entity.paramALabel @config.paramALabel)
@@ -217,12 +226,111 @@ orbital GoalSeekOrbital {
217
226
  { type: range-slider, min: @config.paramBMin, max: @config.paramBMax, step: @config.paramBStep, value: @entity.paramB, showTooltip: true, action: "SET_PARAM_B" }
218
227
  ] }
219
228
  ] },
220
- { type: typography, variant: body, content: @config.goalText },
229
+ { type: typography, variant: body, content: @entity.goalText },
221
230
  { type: typography, variant: caption, color: muted, content: @entity.feedback }
222
231
  ] }
223
232
  ]
224
233
  })
225
234
 
235
+ ROSTER_LOADED -> idle when (and (== @config.rosterSource "event") (and (== ?mode @config.matchMode) (!= ?curveKind "")))
236
+ (let (
237
+ (kind ?curveKind)
238
+ (span (- @config.xMax @config.xMin))
239
+ (tA ?targetA)
240
+ (tB ?targetB)
241
+ (A @config.paramADefault)
242
+ (B @config.paramBDefault)
243
+ (targetSamples (array/map (array/range 0 81) (fn (i)
244
+ (let (
245
+ (x (+ @config.xMin (* @i (/ @span 80))))
246
+ (yVal (if (== @kind "power")
247
+ (* @tA (math/pow @x @tB))
248
+ (if (== @kind "linear")
249
+ (+ @tA (* @tB @x))
250
+ (* @tA (math/sin (* @tB @x))))))
251
+ )
252
+ { x: @x, y: @yVal }))))
253
+ (samples (array/map (array/range 0 81) (fn (i)
254
+ (let (
255
+ (x (+ @config.xMin (* @i (/ @span 80))))
256
+ (yVal (if (== @kind "power")
257
+ (* @A (math/pow @x @B))
258
+ (if (== @kind "linear")
259
+ (+ @A (* @B @x))
260
+ (* @A (math/sin (* @B @x))))))
261
+ )
262
+ { x: @x, y: @yVal }))))
263
+ (dist (math/sqrt (/ (array/sum (array/map (array/range 0 81) (fn (i)
264
+ (let (
265
+ (dY (- (object/get (array/nth @samples @i) y) (object/get (array/nth @targetSamples @i) y)))
266
+ )
267
+ (* @dY @dY))))) 81)))
268
+ (allSamples (array/concat @samples @targetSamples))
269
+ (yMinRaw (array/reduce @allSamples (object/get (array/nth @allSamples 0) y) (fn (acc s) (math/min @acc (object/get @s y)))))
270
+ (yMaxRaw (array/reduce @allSamples (object/get (array/nth @allSamples 0) y) (fn (acc s) (math/max @acc (object/get @s y)))))
271
+ (yPad (* 0.1 (math/max 0.001 (- @yMaxRaw @yMinRaw))))
272
+ )
273
+ (do
274
+ (set @entity.active true)
275
+ (set @entity.title @config.title)
276
+ (set @entity.curveKind @kind)
277
+ (set @entity.goalText ?goalText)
278
+ (set @entity.targetA ?targetA)
279
+ (set @entity.targetB ?targetB)
280
+ (set @entity.paramA @A)
281
+ (set @entity.paramB @B)
282
+ (set @entity.paramALabel @config.paramALabel)
283
+ (set @entity.paramBLabel @config.paramBLabel)
284
+ (set @entity.targetSamples @targetSamples)
285
+ (set @entity.distance @dist)
286
+ (set @entity.attempts 0)
287
+ (set @entity.solved false)
288
+ (set @entity.feedback "")
289
+ (set @entity.yMin (- @yMinRaw @yPad))
290
+ (set @entity.yMax (+ @yMaxRaw @yPad))
291
+ (set @entity.curves [
292
+ { label: @config.targetLabel, color: @config.targetColor, samples: @targetSamples },
293
+ { label: @config.learnerLabel, color: @config.learnerColor, samples: @samples }
294
+ ])))
295
+ (set @entity.resultRow (array/concat (if @entity.solved [ { type: badge, variant: success, label: "Solved" } ] []) [ { type: typography, variant: caption, content: @entity.feedback } ]))
296
+ (render-ui main {
297
+ type: box
298
+ padding: md
299
+ children: [
300
+ { type: stack, direction: vertical, gap: md, children: [
301
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
302
+ { type: stack, direction: vertical, gap: xs, children: [
303
+ { type: typography, variant: h4, content: @entity.title },
304
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
305
+ ] },
306
+ { type: badge, label: (if @entity.solved "Solved" (if (> @entity.attempts 0) "Try again" "Tuning")), variant: (if @entity.solved "success" (if (> @entity.attempts 0) "warning" "neutral")) }
307
+ ] },
308
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
309
+ { type: button, action: CHECK, label: @config.checkLabel, icon: "check", variant: primary, disabled: (if @entity.solved true false) },
310
+ { type: button, action: RESET, label: "Reset", icon: "rotate-ccw", variant: ghost },
311
+ { type: typography, variant: caption, color: muted, content: (if @config.showLiveDistance (str/concat "Distance from target: " (math/round @entity.distance 3) " · attempts: " (str/concat "" @entity.attempts)) (str/concat "Attempts: " (str/concat "" @entity.attempts))) }
312
+ ] },
313
+ { type: math-canvas, keyMap: { Space: CHECK, KeyR: RESET }, width: @config.width, height: @config.height, title: "", xMin: @config.xMin, xMax: @config.xMax, yMin: @entity.yMin, yMax: @entity.yMax, showAxes: @config.showAxes, showGrid: @config.showGrid, gridStep: @config.gridStep, curves: @entity.curves, points: [], vectors: [], shapes: [], interactive: false, animate: false },
314
+ { type: stack, direction: vertical, gap: sm, children: [
315
+ { type: stack, direction: vertical, gap: xs, children: [
316
+ { type: typography, variant: caption, content: (str/concat @entity.paramALabel ": " (math/round @entity.paramA 2)) },
317
+ { type: range-slider, min: @config.paramAMin, max: @config.paramAMax, step: @config.paramAStep, value: @entity.paramA, showTooltip: true, action: "SET_PARAM_A" }
318
+ ] },
319
+ { type: stack, direction: vertical, gap: xs, children: [
320
+ { type: typography, variant: caption, content: (str/concat @entity.paramBLabel ": " (math/round @entity.paramB 2)) },
321
+ { type: range-slider, min: @config.paramBMin, max: @config.paramBMax, step: @config.paramBStep, value: @entity.paramB, showTooltip: true, action: "SET_PARAM_B" }
322
+ ] }
323
+ ] },
324
+ { type: typography, variant: body, content: @entity.goalText },
325
+ { type: typography, variant: caption, color: muted, content: @entity.feedback }
326
+ ] }
327
+ ]
328
+ })
329
+
330
+ ROSTER_LOADED -> idle when (and (== @config.rosterSource "event") (not (== ?mode @config.matchMode)))
331
+ (set @entity.active false)
332
+ (render-ui main null)
333
+
226
334
  SET_PARAM_A -> idle when (and (== @entity.active true) (== @entity.solved false))
227
335
  (let (
228
336
  (A (math/clamp ?value @config.paramAMin @config.paramAMax))
@@ -287,7 +395,7 @@ orbital GoalSeekOrbital {
287
395
  { type: range-slider, min: @config.paramBMin, max: @config.paramBMax, step: @config.paramBStep, value: @entity.paramB, showTooltip: true, action: "SET_PARAM_B" }
288
396
  ] }
289
397
  ] },
290
- { type: typography, variant: body, content: @config.goalText },
398
+ { type: typography, variant: body, content: @entity.goalText },
291
399
  { type: typography, variant: caption, color: muted, content: @entity.feedback }
292
400
  ] }
293
401
  ]
@@ -358,7 +466,7 @@ orbital GoalSeekOrbital {
358
466
  { type: range-slider, min: @config.paramBMin, max: @config.paramBMax, step: @config.paramBStep, value: @entity.paramB, showTooltip: true, action: "SET_PARAM_B" }
359
467
  ] }
360
468
  ] },
361
- { type: typography, variant: body, content: @config.goalText },
469
+ { type: typography, variant: body, content: @entity.goalText },
362
470
  { type: typography, variant: caption, color: muted, content: @entity.feedback }
363
471
  ] }
364
472
  ]
@@ -400,7 +508,7 @@ orbital GoalSeekOrbital {
400
508
  { type: range-slider, min: @config.paramBMin, max: @config.paramBMax, step: @config.paramBStep, value: @entity.paramB, showTooltip: true, action: "SET_PARAM_B" }
401
509
  ] }
402
510
  ] },
403
- { type: typography, variant: body, content: @config.goalText },
511
+ { type: typography, variant: body, content: @entity.goalText },
404
512
  { type: typography, variant: caption, color: muted, content: @entity.feedback }
405
513
  ] }
406
514
  ]
@@ -476,7 +584,7 @@ orbital GoalSeekOrbital {
476
584
  { type: range-slider, min: @config.paramBMin, max: @config.paramBMax, step: @config.paramBStep, value: @entity.paramB, showTooltip: true, action: "SET_PARAM_B" }
477
585
  ] }
478
586
  ] },
479
- { type: typography, variant: body, content: @config.goalText },
587
+ { type: typography, variant: body, content: @entity.goalText },
480
588
  { type: typography, variant: caption, color: muted, content: @entity.feedback }
481
589
  ] }
482
590
  ]
@@ -490,6 +598,15 @@ orbital GoalSeekOrbital {
490
598
  }
491
599
  @description "Lab router broadcast naming the active mode; this instrument renders when the mode equals matchMode, otherwise renders null."
492
600
  @tier "domain"
601
+ ROSTER_LOADED {
602
+ mode : string!
603
+ goalText : string!
604
+ curveKind : string!
605
+ targetA : number!
606
+ targetB : number!
607
+ }
608
+ @description "Runtime content feed, honoured only when rosterSource is event — mode names the instrument it is for (the matchMode it carries, blank when standalone) and goalText, curveKind, targetA and targetB define the inverse problem; a matching instrument re-initialises from it exactly as INIT does from config, any other instrument hides."
609
+ @tier "domain"
493
610
  SET_PARAM_A {
494
611
  value : number
495
612
  }
@@ -543,8 +660,12 @@ orbital GoalSeekOrbital {
543
660
  config {
544
661
  matchMode : string = ""
545
662
  @label "Match Mode"
546
- @description "When composed behind a lab router, the MODE_SELECTED mode value this instrument responds to. Empty string means standalone — render immediately on INIT."
663
+ @description "When composed behind a lab router, the MODE_SELECTED mode value this instrument responds to. Empty string means standalone — render immediately on INIT (or on ROSTER_LOADED when rosterSource is event)."
547
664
  @tier "presentation"
665
+ rosterSource : "config" | "event" = "config"
666
+ @label "Roster Source"
667
+ @description "Where the problem definition (goalText, curveKind, targetA, targetB) comes from: config reads those knobs at INIT; event waits for ROSTER_LOADED and takes them from its payload."
668
+ @tier "domain"
548
669
  title : string = "Goal Seek"
549
670
  @label "Title"
550
671
  @description "Title shown above the canvas."