@almadar/std 16.242.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.
- package/behaviors/behaviors-registry.json +4470 -513
- package/behaviors/lolo/agent/atoms/std-agent-context.lolo +24 -4
- package/behaviors/lolo/agent/atoms/std-agent-memory.lolo +20 -5
- package/behaviors/lolo/agent/atoms/std-agent-proposal.lolo +550 -0
- package/behaviors/lolo/agent/atoms/std-agent-session.lolo +284 -25
- package/behaviors/lolo/agent/atoms/std-agent-suggestions.lolo +841 -0
- package/behaviors/lolo/agent/atoms/std-agent-tool-loop.lolo +58 -8
- package/behaviors/lolo/agent/organisms/std-agent-assistant.lolo +1 -0
- package/behaviors/lolo/infra/atoms/std-page-search.lolo +3 -1
- package/behaviors/lolo/infra/atoms/std-page-treat.lolo +28 -1
- package/behaviors/lolo/infra/atoms/std-page-watch.lolo +3 -1
- package/behaviors/lolo/ui/avl/atoms/ui-avl-state-machine.lolo +22 -0
- package/behaviors/lolo/ui/avl/atoms/ui-avl-transition-explainer.lolo +175 -0
- package/behaviors/lolo/ui/avl/atoms/ui-module-card.lolo +22 -0
- package/behaviors/lolo/ui/core/atoms/std-app-layout.lolo +23 -4
- package/behaviors/lolo/ui/core/atoms/std-hero.lolo +72 -33
- package/behaviors/lolo/ui/core/molecules/ui-agent-chat-feed.lolo +1 -1
- package/behaviors/lolo/ui/core/molecules/ui-markdown-content.lolo +54 -0
- package/behaviors/lolo/ui/core/molecules/ui-upload-drop-zone.lolo +5 -0
- package/behaviors/lolo/ui/core/organisms/ui-segment-renderer.lolo +127 -3
- package/behaviors/lolo/ui/core/organisms/ui-state-machine-view.lolo +22 -0
- package/behaviors/lolo/ui/core/templates/ui-dashboard-layout.lolo +2 -2
- package/behaviors/lolo/ui/learning/atoms/std-learn-arrangement.lolo +87 -17
- package/behaviors/lolo/ui/learning/atoms/std-learn-classify.lolo +172 -37
- package/behaviors/lolo/ui/learning/atoms/std-learn-coupled-sim.lolo +183 -70
- package/behaviors/lolo/ui/learning/atoms/std-learn-derivation.lolo +78 -13
- package/behaviors/lolo/ui/learning/atoms/std-learn-diagram.lolo +58 -2
- package/behaviors/lolo/ui/learning/atoms/std-learn-doser.lolo +107 -12
- package/behaviors/lolo/ui/learning/atoms/std-learn-estimate.lolo +83 -10
- package/behaviors/lolo/ui/learning/atoms/std-learn-goal-seek.lolo +130 -9
- package/behaviors/lolo/ui/learning/atoms/std-learn-grid-sim.lolo +143 -59
- package/behaviors/lolo/ui/learning/atoms/std-learn-hotspot.lolo +96 -22
- package/behaviors/lolo/ui/learning/atoms/std-learn-live-sim.lolo +66 -5
- package/behaviors/lolo/ui/learning/atoms/std-learn-predict.lolo +84 -6
- package/behaviors/lolo/ui/learning/atoms/std-learn-sandbox.lolo +80 -14
- package/behaviors/lolo/ui/learning/atoms/std-learn-scatter-fit.lolo +99 -5
- package/behaviors/lolo/ui/learning/atoms/std-learn-scenario.lolo +81 -7
- package/behaviors/lolo/ui/learning/atoms/std-learn-speed-drill.lolo +83 -7
- package/behaviors/lolo/ui/learning/atoms/std-learn-stepper.lolo +224 -99
- package/behaviors/lolo/ui/learning/atoms/std-learn-tour-3d.lolo +63 -2
- package/behaviors/lolo/ui/learning/atoms/std-learn-trace-player.lolo +99 -38
- package/behaviors/lolo/ui/learning/atoms/std-learn-transport.lolo +7 -7
- package/behaviors/lolo/ui/learning/atoms/std-learn-tree.lolo +69 -4
- package/behaviors/lolo-behavior-contracts.json +1 -1
- package/behaviors/registry/agent/atoms/std-agent-context.orb +205 -6
- package/behaviors/registry/agent/atoms/std-agent-memory.orb +146 -4
- package/behaviors/registry/agent/atoms/std-agent-proposal.orb +1972 -0
- package/behaviors/registry/agent/atoms/std-agent-session.orb +2021 -597
- package/behaviors/registry/agent/atoms/std-agent-suggestions.orb +5079 -0
- package/behaviors/registry/agent/atoms/std-agent-tool-loop.orb +287 -5
- package/behaviors/registry/agent/organisms/std-agent-assistant.orb +7 -0
- package/behaviors/registry/factory-signatures.json +1 -1
- package/behaviors/registry/infra/atoms/std-page-search.orb +19 -1
- package/behaviors/registry/infra/atoms/std-page-treat.orb +327 -2
- package/behaviors/registry/infra/atoms/std-page-watch.orb +19 -1
- package/behaviors/registry/ui/avl/atoms/ui-avl-state-machine.orb +134 -0
- package/behaviors/registry/ui/avl/atoms/ui-avl-transition-explainer.orb +678 -0
- package/behaviors/registry/ui/avl/atoms/ui-module-card.orb +122 -0
- package/behaviors/registry/ui/core/atoms/std-app-layout.orb +73 -4
- package/behaviors/registry/ui/core/atoms/std-hero.orb +174 -97
- package/behaviors/registry/ui/core/molecules/ui-markdown-content.orb +204 -1
- package/behaviors/registry/ui/core/molecules/ui-upload-drop-zone.orb +12 -0
- package/behaviors/registry/ui/core/organisms/ui-segment-renderer.orb +683 -30
- package/behaviors/registry/ui/learning/atoms/std-learn-arrangement.orb +748 -21
- package/behaviors/registry/ui/learning/atoms/std-learn-classify.orb +1429 -41
- package/behaviors/registry/ui/learning/atoms/std-learn-coupled-sim.orb +1031 -185
- package/behaviors/registry/ui/learning/atoms/std-learn-derivation.orb +807 -132
- package/behaviors/registry/ui/learning/atoms/std-learn-diagram.orb +553 -6
- package/behaviors/registry/ui/learning/atoms/std-learn-doser.orb +987 -21
- package/behaviors/registry/ui/learning/atoms/std-learn-estimate.orb +582 -16
- package/behaviors/registry/ui/learning/atoms/std-learn-goal-seek.orb +954 -13
- package/behaviors/registry/ui/learning/atoms/std-learn-grid-sim.orb +828 -88
- package/behaviors/registry/ui/learning/atoms/std-learn-hotspot.orb +730 -28
- package/behaviors/registry/ui/learning/atoms/std-learn-live-sim.orb +479 -9
- package/behaviors/registry/ui/learning/atoms/std-learn-predict.orb +797 -46
- package/behaviors/registry/ui/learning/atoms/std-learn-sandbox.orb +757 -58
- package/behaviors/registry/ui/learning/atoms/std-learn-scatter-fit.orb +1176 -164
- package/behaviors/registry/ui/learning/atoms/std-learn-scenario.orb +599 -12
- package/behaviors/registry/ui/learning/atoms/std-learn-speed-drill.orb +832 -150
- package/behaviors/registry/ui/learning/atoms/std-learn-stepper.orb +1561 -127
- package/behaviors/registry/ui/learning/atoms/std-learn-tour-3d.orb +655 -6
- package/behaviors/registry/ui/learning/atoms/std-learn-trace-player.orb +634 -43
- package/behaviors/registry/ui/learning/atoms/std-learn-transport.orb +85 -31
- package/behaviors/registry/ui/learning/atoms/std-learn-tree.orb +425 -9
- package/canonical-operators.json +45 -2
- package/dist/behaviors/exports-reader.js +16667 -7868
- package/dist/behaviors/functions/index.d.ts +711 -32
- package/dist/behaviors/functions/index.js +16651 -7869
- package/dist/behaviors/index.d.ts +1 -1
- package/dist/behaviors/index.js +16668 -7869
- package/dist/behaviors/query.js +16667 -7868
- package/dist/behaviors-embeddings.hash.json +3 -3
- package/dist/behaviors-embeddings.json +77 -53
- package/dist/behaviors-registry.json +4470 -513
- package/dist/index.d.ts +3 -3
- package/dist/index.js +16101 -7275
- package/dist/knob-embeddings.hash.json +3 -3
- package/dist/knob-embeddings.json +1309 -685
- package/dist/modules/anim.d.ts +1 -1
- package/dist/modules/array.d.ts +1 -1
- package/dist/modules/async.d.ts +1 -1
- package/dist/modules/behavior.d.ts +1 -1
- package/dist/modules/browser.d.ts +1 -1
- package/dist/modules/composition.d.ts +1 -1
- package/dist/modules/contract.d.ts +1 -1
- package/dist/modules/core.d.ts +1 -1
- package/dist/modules/core.js +29 -2
- package/dist/modules/data.d.ts +1 -1
- package/dist/modules/ease.d.ts +1 -1
- package/dist/modules/format.d.ts +1 -1
- package/dist/modules/geo.d.ts +1 -1
- package/dist/modules/graph.d.ts +1 -1
- package/dist/modules/grid.d.ts +1 -1
- package/dist/modules/i18n.d.ts +1 -1
- package/dist/modules/index.d.ts +1 -1
- package/dist/modules/index.js +29 -2
- package/dist/modules/integration.d.ts +1 -1
- package/dist/modules/json.d.ts +1 -1
- package/dist/modules/llm.d.ts +1 -1
- package/dist/modules/math.d.ts +1 -1
- package/dist/modules/memory.d.ts +1 -1
- package/dist/modules/nn.d.ts +1 -1
- package/dist/modules/noise.d.ts +1 -1
- package/dist/modules/object.d.ts +1 -1
- package/dist/modules/os.d.ts +1 -1
- package/dist/modules/path.d.ts +1 -1
- package/dist/modules/prob.d.ts +1 -1
- package/dist/modules/session.d.ts +1 -1
- package/dist/modules/str.d.ts +1 -1
- package/dist/modules/tensor.d.ts +1 -1
- package/dist/modules/time.d.ts +1 -1
- package/dist/modules/trace.d.ts +1 -1
- package/dist/modules/train.d.ts +1 -1
- package/dist/modules/validate.d.ts +1 -1
- package/dist/modules/vector.d.ts +1 -1
- package/dist/modules/workspace.d.ts +1 -1
- package/dist/registry/factory-signatures.json +1 -1
- package/dist/registry.d.ts +2 -2
- package/dist/registry.js +29 -2
- package/dist/{types-Cdb321uM.d.ts → types-Y-yYWEOX.d.ts} +1 -1
- package/i18n/ar.json +3 -1
- package/i18n/en.json +2 -0
- package/i18n/sl.json +3 -1
- package/package.json +3 -3
|
@@ -24,6 +24,7 @@ orbital LearnScatterFitOrbital {
|
|
|
24
24
|
id : string!
|
|
25
25
|
active : boolean = false
|
|
26
26
|
title : string
|
|
27
|
+
initialPoints : [LearnScatterFitPoint]
|
|
27
28
|
points : [LearnScatterFitPoint]
|
|
28
29
|
slope : number
|
|
29
30
|
intercept : number
|
|
@@ -43,7 +44,8 @@ orbital LearnScatterFitOrbital {
|
|
|
43
44
|
initial: idle
|
|
44
45
|
|
|
45
46
|
state idle {
|
|
46
|
-
INIT -> idle when (== @config.matchMode "")
|
|
47
|
+
INIT -> idle when (and (== @config.matchMode "") (== @config.rosterSource "config"))
|
|
48
|
+
(set @entity.initialPoints @config.initialPoints)
|
|
47
49
|
(set @entity.active true)
|
|
48
50
|
(set @entity.title @config.title)
|
|
49
51
|
(set @entity.points @config.initialPoints)
|
|
@@ -123,7 +125,8 @@ orbital LearnScatterFitOrbital {
|
|
|
123
125
|
(set @entity.running false)
|
|
124
126
|
(render-ui main null)
|
|
125
127
|
|
|
126
|
-
MODE_SELECTED -> idle when (== ?mode @config.matchMode)
|
|
128
|
+
MODE_SELECTED -> idle when (and (== ?mode @config.matchMode) (== @config.rosterSource "config"))
|
|
129
|
+
(set @entity.initialPoints @config.initialPoints)
|
|
127
130
|
(set @entity.active true)
|
|
128
131
|
(set @entity.title @config.title)
|
|
129
132
|
(set @entity.points @config.initialPoints)
|
|
@@ -198,6 +201,87 @@ orbital LearnScatterFitOrbital {
|
|
|
198
201
|
})
|
|
199
202
|
(emit LEARN_SCATTER_FIT_UPDATED { slope: @entity.slope, intercept: @entity.intercept, r: @entity.r, rSquared: @entity.rSquared, pointCount: (array/len @entity.points), narration: @entity.narration })
|
|
200
203
|
|
|
204
|
+
ROSTER_LOADED -> idle when (and (== @config.rosterSource "event") (== ?mode @config.matchMode))
|
|
205
|
+
(set @entity.initialPoints ?initialPoints)
|
|
206
|
+
(set @entity.active true)
|
|
207
|
+
(set @entity.title @config.title)
|
|
208
|
+
(set @entity.points ?initialPoints)
|
|
209
|
+
(set @entity.guessSlope 0)
|
|
210
|
+
(set @entity.guessIntercept (/ (+ @config.axisYMin @config.axisYMax) 2))
|
|
211
|
+
(set @entity.revealed false)
|
|
212
|
+
(set @entity.running @config.autoRun)
|
|
213
|
+
(let (
|
|
214
|
+
(pts ?initialPoints)
|
|
215
|
+
(n (array/len @pts))
|
|
216
|
+
(meanX (if (> @n 0) (/ (array/reduce @pts 0 (fn (acc p) (+ @acc (object/get @p x)))) @n) 0))
|
|
217
|
+
(meanY (if (> @n 0) (/ (array/reduce @pts 0 (fn (acc p) (+ @acc (object/get @p y)))) @n) 0))
|
|
218
|
+
(sxx (array/reduce @pts 0 (fn (acc p) (let ((dx (- (object/get @p x) @meanX))) (+ @acc (* @dx @dx))))))
|
|
219
|
+
(syy (array/reduce @pts 0 (fn (acc p) (let ((dy (- (object/get @p y) @meanY))) (+ @acc (* @dy @dy))))))
|
|
220
|
+
(sxy (array/reduce @pts 0 (fn (acc p) (+ @acc (* (- (object/get @p x) @meanX) (- (object/get @p y) @meanY))))))
|
|
221
|
+
(newSlope (if (> @sxx 0) (/ @sxy @sxx) 0))
|
|
222
|
+
(newIntercept (- @meanY (* @newSlope @meanX)))
|
|
223
|
+
(newR (if (and (> @sxx 0) (> @syy 0)) (/ @sxy (math/sqrt (* @sxx @syy))) 0))
|
|
224
|
+
(fitCurve { label: @config.fitLabel, color: @config.fitColor, samples: [
|
|
225
|
+
{ x: @config.axisXMin, y: (math/clamp @newIntercept @config.axisYMin @config.axisYMax) },
|
|
226
|
+
{ x: @config.axisXMax, y: (math/clamp (+ (* @newSlope @config.axisXMax) @newIntercept) @config.axisYMin @config.axisYMax) }
|
|
227
|
+
]})
|
|
228
|
+
(residualCurves (if @config.showResiduals
|
|
229
|
+
(array/map @pts (fn p { label: "", color: @config.residualColor, dash: @config.residualDash, samples: [ { x: (object/get @p x), y: (object/get @p y) }, { x: (object/get @p x), y: (+ (* @newSlope (object/get @p x)) @newIntercept) } ] }))
|
|
230
|
+
[]))
|
|
231
|
+
)
|
|
232
|
+
(do
|
|
233
|
+
(set @entity.slope @newSlope)
|
|
234
|
+
(set @entity.intercept @newIntercept)
|
|
235
|
+
(set @entity.r @newR)
|
|
236
|
+
(set @entity.rSquared (* @newR @newR))
|
|
237
|
+
(set @entity.guessScore 0)
|
|
238
|
+
(set @entity.curves (array/concat (array/append [] @fitCurve) @residualCurves))
|
|
239
|
+
(set @entity.done (>= @n @config.maxPoints))
|
|
240
|
+
(set @entity.narration (str/concat (str/concat "" @n) " " @config.narrationLoadedTemplate " — r = " (str/concat "" (math/round @newR 3)) ", R² = " (str/concat "" (math/round (* @newR @newR) 3))))
|
|
241
|
+
)
|
|
242
|
+
)
|
|
243
|
+
(render-ui main {
|
|
244
|
+
type: box
|
|
245
|
+
padding: md
|
|
246
|
+
children: [
|
|
247
|
+
{ type: stack, direction: vertical, gap: md, children: [
|
|
248
|
+
{ type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
|
|
249
|
+
{ type: stack, direction: vertical, gap: xs, children: [
|
|
250
|
+
{ type: typography, variant: h4, content: @entity.title },
|
|
251
|
+
(if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
|
|
252
|
+
] },
|
|
253
|
+
{ type: badge, label: (if @entity.revealed "Revealed" (if @entity.done "Max points" (if @entity.running "Adding points" (if @config.guessMode "Guessing" "Fitted")))), variant: (if @entity.revealed "success" (if @entity.done "neutral" (if @entity.running "primary" "neutral"))) }
|
|
254
|
+
] },
|
|
255
|
+
{ type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
|
|
256
|
+
{ type: button, action: ADD_POINT, label: @config.addPointLabel, icon: "plus", variant: primary, disabled: @entity.done },
|
|
257
|
+
{ type: button, action: REVEAL_FIT, label: @config.revealLabel, icon: "eye", variant: secondary },
|
|
258
|
+
(if @entity.running { type: button, action: TOGGLE_RUN, label: @config.pauseLabel, icon: "pause", variant: secondary, aria-pressed: "true" } { type: button, action: TOGGLE_RUN, label: @config.runLabel, icon: "play", variant: secondary, aria-pressed: "false", disabled: @entity.done }),
|
|
259
|
+
{ type: button, action: RESET, label: @config.resetLabel, icon: "rotate-ccw", variant: ghost },
|
|
260
|
+
{ type: typography, variant: caption, color: muted, content: (str/concat (str/concat "" (array/len @entity.points)) (str/concat " of " (str/concat "" @config.maxPoints))) }
|
|
261
|
+
] },
|
|
262
|
+
{ type: math-canvas, keyMap: { Space: TOGGLE_RUN, ArrowRight: ADD_POINT, KeyR: RESET }, width: @config.width, height: @config.height, xMin: @config.axisXMin, xMax: @config.axisXMax, yMin: @config.axisYMin, yMax: @config.axisYMax, showAxes: @config.showAxes, showGrid: @config.showGrid, gridStep: @config.gridStep, showTickLabels: @config.showTickLabels, curves: @entity.curves, points: @entity.points, vectors: [], interactive: @config.interactive, animate: @config.animate },
|
|
263
|
+
{ type: stack, direction: vertical, gap: sm, children: [
|
|
264
|
+
{ type: stack, direction: vertical, gap: xs, children: [
|
|
265
|
+
{ type: typography, variant: caption, content: (str/concat @config.guessSlopeCaption (math/round @entity.guessSlope 2)) },
|
|
266
|
+
{ type: range-slider, min: @config.guessSlopeMin, max: @config.guessSlopeMax, step: @config.guessSlopeStep, value: @entity.guessSlope, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "slope" } }
|
|
267
|
+
] },
|
|
268
|
+
{ type: stack, direction: vertical, gap: xs, children: [
|
|
269
|
+
{ type: typography, variant: caption, content: (str/concat @config.guessInterceptCaption (math/round @entity.guessIntercept 1)) },
|
|
270
|
+
{ type: range-slider, min: @config.guessInterceptMin, max: @config.guessInterceptMax, step: @config.guessInterceptStep, value: @entity.guessIntercept, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "intercept" } }
|
|
271
|
+
] }
|
|
272
|
+
] },
|
|
273
|
+
{ type: typography, variant: caption, color: muted, content: (if @config.showR (str/concat "r = " (math/round @entity.r 3) " — R² = " (math/round @entity.rSquared 3) " — guess score " @entity.guessScore "%") "") },
|
|
274
|
+
{ type: typography, variant: body, content: @entity.narration }
|
|
275
|
+
] }
|
|
276
|
+
]
|
|
277
|
+
})
|
|
278
|
+
(emit LEARN_SCATTER_FIT_UPDATED { slope: @entity.slope, intercept: @entity.intercept, r: @entity.r, rSquared: @entity.rSquared, pointCount: (array/len @entity.points), narration: @entity.narration })
|
|
279
|
+
|
|
280
|
+
ROSTER_LOADED -> idle when (and (== @config.rosterSource "event") (not (== ?mode @config.matchMode)))
|
|
281
|
+
(set @entity.active false)
|
|
282
|
+
(set @entity.running false)
|
|
283
|
+
(render-ui main null)
|
|
284
|
+
|
|
201
285
|
ADD_POINT -> idle when (and @entity.active (not @entity.done))
|
|
202
286
|
(let (
|
|
203
287
|
(marginX (* (- @config.axisXMax @config.axisXMin) @config.pointMarginPct))
|
|
@@ -531,13 +615,13 @@ orbital LearnScatterFitOrbital {
|
|
|
531
615
|
(emit LEARN_SCATTER_FIT_UPDATED { slope: @entity.slope, intercept: @entity.intercept, r: @entity.r, rSquared: @entity.rSquared, pointCount: (array/len @entity.points), narration: @entity.narration })
|
|
532
616
|
|
|
533
617
|
RESET -> idle when (== @entity.active true)
|
|
534
|
-
(set @entity.points @
|
|
618
|
+
(set @entity.points @entity.initialPoints)
|
|
535
619
|
(set @entity.guessSlope 0)
|
|
536
620
|
(set @entity.guessIntercept (/ (+ @config.axisYMin @config.axisYMax) 2))
|
|
537
621
|
(set @entity.revealed false)
|
|
538
622
|
(set @entity.running @config.autoRun)
|
|
539
623
|
(let (
|
|
540
|
-
(pts @
|
|
624
|
+
(pts @entity.initialPoints)
|
|
541
625
|
(n (array/len @pts))
|
|
542
626
|
(meanX (if (> @n 0) (/ (array/reduce @pts 0 (fn (acc p) (+ @acc (object/get @p x)))) @n) 0))
|
|
543
627
|
(meanY (if (> @n 0) (/ (array/reduce @pts 0 (fn (acc p) (+ @acc (object/get @p y)))) @n) 0))
|
|
@@ -697,6 +781,12 @@ orbital LearnScatterFitOrbital {
|
|
|
697
781
|
}
|
|
698
782
|
@description "Lab router broadcast naming the active mode; this instrument renders when the mode equals matchMode, otherwise renders null."
|
|
699
783
|
@tier "domain"
|
|
784
|
+
ROSTER_LOADED {
|
|
785
|
+
mode : string!
|
|
786
|
+
initialPoints : [LearnScatterFitPoint]!
|
|
787
|
+
}
|
|
788
|
+
@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 initialPoints is the starting point set; a matching instrument re-initialises from it exactly as INIT does from config, any other instrument hides."
|
|
789
|
+
@tier "domain"
|
|
700
790
|
DRAG_POINT {
|
|
701
791
|
id : string
|
|
702
792
|
x : number
|
|
@@ -736,7 +826,7 @@ orbital LearnScatterFitOrbital {
|
|
|
736
826
|
config {
|
|
737
827
|
matchMode : string = ""
|
|
738
828
|
@label "Match Mode"
|
|
739
|
-
@description "When composed behind a lab router, the MODE_SELECTED mode value this instrument responds to. Empty string means standalone — render immediately on INIT."
|
|
829
|
+
@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."
|
|
740
830
|
@tier "presentation"
|
|
741
831
|
autoRun : boolean = false
|
|
742
832
|
@label "Auto Run"
|
|
@@ -750,6 +840,10 @@ orbital LearnScatterFitOrbital {
|
|
|
750
840
|
@label "Concept"
|
|
751
841
|
@description "One line under the title saying what the learner is looking at (keep it under ~65 characters). Empty shows no line."
|
|
752
842
|
@tier "presentation"
|
|
843
|
+
rosterSource : "config" | "event" = "config"
|
|
844
|
+
@label "Roster Source"
|
|
845
|
+
@description "Where the roster comes from: config reads initialPoints knob at INIT; event waits for ROSTER_LOADED and takes the roster from its payload."
|
|
846
|
+
@tier "domain"
|
|
753
847
|
initialPoints : [LearnScatterFitPoint] = [
|
|
754
848
|
{ id: "p0", x: 15, y: 25, label: "", color: "ink", radius: 5 },
|
|
755
849
|
{ id: "p1", x: 32, y: 40, label: "", color: "ink", radius: 5 },
|
|
@@ -18,6 +18,8 @@ orbital ScenarioOrbital {
|
|
|
18
18
|
id : string!
|
|
19
19
|
active : boolean = false
|
|
20
20
|
title : string
|
|
21
|
+
nodes : [ScenarioNode]
|
|
22
|
+
startId : string
|
|
21
23
|
currentId : string
|
|
22
24
|
situation : string
|
|
23
25
|
choices : [ScenarioChoice]
|
|
@@ -34,7 +36,9 @@ orbital ScenarioOrbital {
|
|
|
34
36
|
initial: idle
|
|
35
37
|
|
|
36
38
|
state idle {
|
|
37
|
-
INIT -> idle when (== @config.matchMode "")
|
|
39
|
+
INIT -> idle when (and (== @config.matchMode "") (== @config.rosterSource "config"))
|
|
40
|
+
(set @entity.nodes @config.nodes)
|
|
41
|
+
(set @entity.startId @config.startId)
|
|
38
42
|
(let (
|
|
39
43
|
(start (array/find @config.nodes (fn n (== (object/get @n id) @config.startId))))
|
|
40
44
|
)
|
|
@@ -89,7 +93,9 @@ orbital ScenarioOrbital {
|
|
|
89
93
|
(set @entity.active false)
|
|
90
94
|
(render-ui main null)
|
|
91
95
|
|
|
92
|
-
MODE_SELECTED -> idle when (== ?mode @config.matchMode)
|
|
96
|
+
MODE_SELECTED -> idle when (and (== ?mode @config.matchMode) (== @config.rosterSource "config"))
|
|
97
|
+
(set @entity.nodes @config.nodes)
|
|
98
|
+
(set @entity.startId @config.startId)
|
|
93
99
|
(let (
|
|
94
100
|
(start (array/find @config.nodes (fn n (== (object/get @n id) @config.startId))))
|
|
95
101
|
)
|
|
@@ -140,11 +146,68 @@ orbital ScenarioOrbital {
|
|
|
140
146
|
]
|
|
141
147
|
})
|
|
142
148
|
|
|
149
|
+
ROSTER_LOADED -> idle when (and (== @config.rosterSource "event") (and (== ?mode @config.matchMode) (> (array/len ?nodes) 0)))
|
|
150
|
+
(set @entity.nodes ?nodes)
|
|
151
|
+
(set @entity.startId ?startId)
|
|
152
|
+
(let (
|
|
153
|
+
(start (array/find ?nodes (fn n (== (object/get @n id) ?startId))))
|
|
154
|
+
)
|
|
155
|
+
(do
|
|
156
|
+
(set @entity.active true)
|
|
157
|
+
(set @entity.title @config.title)
|
|
158
|
+
(set @entity.currentId ?startId)
|
|
159
|
+
(set @entity.situation (object/get @start situation))
|
|
160
|
+
(set @entity.choices (object/get @start choices []))
|
|
161
|
+
(set @entity.metricA @config.metricAStart)
|
|
162
|
+
(set @entity.metricB @config.metricBStart)
|
|
163
|
+
(set @entity.stepCount 0)
|
|
164
|
+
(set @entity.path [])
|
|
165
|
+
(set @entity.done false)
|
|
166
|
+
(set @entity.feedback "")
|
|
167
|
+
(set @entity.view [
|
|
168
|
+
{ type: card, variant: bordered, padding: md, children: [
|
|
169
|
+
{ type: typography, variant: body, content: @entity.situation }
|
|
170
|
+
] }
|
|
171
|
+
])))
|
|
172
|
+
(render-ui main {
|
|
173
|
+
type: box
|
|
174
|
+
padding: md
|
|
175
|
+
children: [
|
|
176
|
+
{ type: stack, direction: vertical, gap: md, children: [
|
|
177
|
+
{ type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
|
|
178
|
+
{ type: stack, direction: vertical, gap: xs, children: [
|
|
179
|
+
{ type: typography, variant: h4, content: @entity.title },
|
|
180
|
+
(if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
|
|
181
|
+
] },
|
|
182
|
+
{ type: badge, label: (if @entity.done "Ended" (str/concat "Decision " (+ @entity.stepCount 1))), variant: (if @entity.done "primary" "neutral") }
|
|
183
|
+
] },
|
|
184
|
+
{ type: stack, direction: horizontal, align: center, gap: md, wrap: true, children: [
|
|
185
|
+
{ type: stat-display, label: @config.metricALabel, value: (math/round @entity.metricA 0) },
|
|
186
|
+
{ type: stat-display, label: @config.metricBLabel, value: (math/round @entity.metricB 0) }
|
|
187
|
+
] },
|
|
188
|
+
{ type: stack, direction: vertical, gap: md, children: @entity.view },
|
|
189
|
+
{ type: stack, direction: vertical, gap: sm, children: (array/map (array/range 0 (array/len @entity.choices)) (fn (i)
|
|
190
|
+
{ type: button, action: CHOOSE, actionPayload: { index: @i }, label: (object/get (array/nth @entity.choices @i) label), variant: secondary, size: lg, disabled: (if @entity.done true false) })) },
|
|
191
|
+
{ type: typography, variant: body, content: @entity.feedback },
|
|
192
|
+
{ type: stack, direction: vertical, gap: xs, children: (array/map @entity.path (fn (line)
|
|
193
|
+
{ type: typography, variant: caption, color: muted, content: @line })) },
|
|
194
|
+
{ type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
|
|
195
|
+
{ type: button, action: RESTART, label: @config.restartLabel, icon: "rotate-ccw", variant: primary, disabled: (if @entity.done false true) },
|
|
196
|
+
{ type: typography, variant: caption, color: muted, content: (str/concat "Decisions " @entity.stepCount) }
|
|
197
|
+
] }
|
|
198
|
+
] }
|
|
199
|
+
]
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
ROSTER_LOADED -> idle when (and (== @config.rosterSource "event") (not (== ?mode @config.matchMode)))
|
|
203
|
+
(set @entity.active false)
|
|
204
|
+
(render-ui main null)
|
|
205
|
+
|
|
143
206
|
CHOOSE -> idle when (and (== @entity.active true) (== @entity.done false))
|
|
144
207
|
(let (
|
|
145
208
|
(choice (array/nth @entity.choices ?index))
|
|
146
209
|
(nextId (object/get @choice next))
|
|
147
|
-
(nextNode (array/find @
|
|
210
|
+
(nextNode (array/find @entity.nodes (fn n (== (object/get @n id) @nextId))))
|
|
148
211
|
(nextChoices (object/get @nextNode choices []))
|
|
149
212
|
(ended (== (array/len @nextChoices) 0))
|
|
150
213
|
(note (object/get @choice note ""))
|
|
@@ -208,12 +271,12 @@ orbital ScenarioOrbital {
|
|
|
208
271
|
|
|
209
272
|
RESTART -> idle when (and (== @entity.active true) (== @entity.done true))
|
|
210
273
|
(let (
|
|
211
|
-
(start (array/find @
|
|
274
|
+
(start (array/find @entity.nodes (fn n (== (object/get @n id) @entity.startId))))
|
|
212
275
|
)
|
|
213
276
|
(do
|
|
214
277
|
(set @entity.active true)
|
|
215
278
|
(set @entity.title @config.title)
|
|
216
|
-
(set @entity.currentId @
|
|
279
|
+
(set @entity.currentId @entity.startId)
|
|
217
280
|
(set @entity.situation (object/get @start situation))
|
|
218
281
|
(set @entity.choices (object/get @start choices []))
|
|
219
282
|
(set @entity.metricA @config.metricAStart)
|
|
@@ -256,7 +319,7 @@ orbital ScenarioOrbital {
|
|
|
256
319
|
] }
|
|
257
320
|
]
|
|
258
321
|
})
|
|
259
|
-
(emit SCENARIO_RESTARTED { startId: @
|
|
322
|
+
(emit SCENARIO_RESTARTED { startId: @entity.startId })
|
|
260
323
|
}
|
|
261
324
|
|
|
262
325
|
listens {
|
|
@@ -265,6 +328,13 @@ orbital ScenarioOrbital {
|
|
|
265
328
|
}
|
|
266
329
|
@description "Lab router broadcast naming the active mode; this instrument renders when the mode equals matchMode, otherwise renders null."
|
|
267
330
|
@tier "domain"
|
|
331
|
+
ROSTER_LOADED {
|
|
332
|
+
mode : string!
|
|
333
|
+
nodes : [ScenarioNode]!
|
|
334
|
+
startId : string!
|
|
335
|
+
}
|
|
336
|
+
@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 nodes is the decision graph and startId the node it opens on; a matching instrument re-initialises from it exactly as INIT does from config, any other instrument hides."
|
|
337
|
+
@tier "domain"
|
|
268
338
|
CHOOSE {
|
|
269
339
|
index : number
|
|
270
340
|
}
|
|
@@ -296,7 +366,7 @@ orbital ScenarioOrbital {
|
|
|
296
366
|
config {
|
|
297
367
|
matchMode : string = ""
|
|
298
368
|
@label "Match Mode"
|
|
299
|
-
@description "When composed behind a lab router, the MODE_SELECTED mode value this instrument responds to. Empty string means standalone — render immediately on INIT."
|
|
369
|
+
@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."
|
|
300
370
|
@tier "presentation"
|
|
301
371
|
title : string = "Decision Scenario"
|
|
302
372
|
@label "Title"
|
|
@@ -324,6 +394,10 @@ orbital ScenarioOrbital {
|
|
|
324
394
|
@label "Start Node"
|
|
325
395
|
@description "Id of the node the scenario opens on."
|
|
326
396
|
@tier "domain"
|
|
397
|
+
rosterSource : "config" | "event" = "config"
|
|
398
|
+
@label "Roster Source"
|
|
399
|
+
@description "Where the roster comes from: config reads nodes and startId knobs at INIT; event waits for ROSTER_LOADED and takes the roster from its payload."
|
|
400
|
+
@tier "domain"
|
|
327
401
|
nodes : [ScenarioNode] = [
|
|
328
402
|
{ id: "start", situation: "Your town's river floods every spring. The council asks you to lead the response.", choices: [
|
|
329
403
|
{ label: "Build a levee now", next: "levee", deltaA: -60, deltaB: 10, note: "Fast protection, most of the budget gone." },
|
|
@@ -11,6 +11,7 @@ orbital SpeedDrillOrbital {
|
|
|
11
11
|
id : string!
|
|
12
12
|
active : boolean = false
|
|
13
13
|
title : string
|
|
14
|
+
items : [SpeedDrillItem]
|
|
14
15
|
itemIndex : number = 0
|
|
15
16
|
totalItems : number = 0
|
|
16
17
|
remaining : number = 0
|
|
@@ -32,7 +33,8 @@ orbital SpeedDrillOrbital {
|
|
|
32
33
|
initial: idle
|
|
33
34
|
|
|
34
35
|
state idle {
|
|
35
|
-
INIT -> idle when (== @config.matchMode "")
|
|
36
|
+
INIT -> idle when (and (== @config.matchMode "") (== @config.rosterSource "config"))
|
|
37
|
+
(set @entity.items @config.items)
|
|
36
38
|
(let (
|
|
37
39
|
(first (array/nth @config.items 0))
|
|
38
40
|
)
|
|
@@ -94,7 +96,8 @@ orbital SpeedDrillOrbital {
|
|
|
94
96
|
(set @entity.running false)
|
|
95
97
|
(render-ui main null)
|
|
96
98
|
|
|
97
|
-
MODE_SELECTED -> idle when (== ?mode @config.matchMode)
|
|
99
|
+
MODE_SELECTED -> idle when (and (== ?mode @config.matchMode) (== @config.rosterSource "config"))
|
|
100
|
+
(set @entity.items @config.items)
|
|
98
101
|
(let (
|
|
99
102
|
(first (array/nth @config.items 0))
|
|
100
103
|
)
|
|
@@ -151,6 +154,69 @@ orbital SpeedDrillOrbital {
|
|
|
151
154
|
]
|
|
152
155
|
})
|
|
153
156
|
|
|
157
|
+
ROSTER_LOADED -> idle when (and (== @config.rosterSource "event") (and (== ?mode @config.matchMode) (> (array/len ?items) 0)))
|
|
158
|
+
(set @entity.items ?items)
|
|
159
|
+
(let (
|
|
160
|
+
(first (array/nth ?items 0))
|
|
161
|
+
)
|
|
162
|
+
(do
|
|
163
|
+
(set @entity.active true)
|
|
164
|
+
(set @entity.title @config.title)
|
|
165
|
+
(set @entity.itemIndex 0)
|
|
166
|
+
(set @entity.totalItems (array/len ?items))
|
|
167
|
+
(set @entity.remaining (* @config.timeLimit 10))
|
|
168
|
+
(set @entity.running true)
|
|
169
|
+
(set @entity.verdict "")
|
|
170
|
+
(set @entity.pickedIndex -1)
|
|
171
|
+
(set @entity.score 0)
|
|
172
|
+
(set @entity.streak 0)
|
|
173
|
+
(set @entity.bestStreak 0)
|
|
174
|
+
(set @entity.done false)
|
|
175
|
+
(set @entity.promptText (object/get @first prompt))
|
|
176
|
+
(set @entity.options (object/get @first options))
|
|
177
|
+
(set @entity.correctIndex (object/get @first correctIndex))
|
|
178
|
+
(set @entity.feedback "")
|
|
179
|
+
(set @entity.view [
|
|
180
|
+
{ type: card, variant: bordered, padding: md, children: [
|
|
181
|
+
{ type: typography, variant: h4, content: @entity.promptText }
|
|
182
|
+
] }
|
|
183
|
+
])))
|
|
184
|
+
(render-ui main {
|
|
185
|
+
type: box
|
|
186
|
+
padding: md
|
|
187
|
+
children: [
|
|
188
|
+
{ type: stack, direction: vertical, gap: md, children: [
|
|
189
|
+
{ type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
|
|
190
|
+
{ type: stack, direction: vertical, gap: xs, children: [
|
|
191
|
+
{ type: typography, variant: h4, content: @entity.title },
|
|
192
|
+
(if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
|
|
193
|
+
] },
|
|
194
|
+
{ type: badge, label: (if @entity.done "Round complete" (str/concat @entity.score " pts · streak " @entity.streak)), variant: (if @entity.done "primary" (if (== @entity.verdict "correct") "success" (if (== @entity.verdict "") "neutral" "error"))) }
|
|
195
|
+
] },
|
|
196
|
+
{ type: progress-bar, value: (+ @entity.itemIndex 1), max: @entity.totalItems, showPercentage: false, label: (str/concat "Item " (str/concat "" (+ @entity.itemIndex 1)) " of " (str/concat "" @entity.totalItems)) },
|
|
197
|
+
{ type: progress-bar, value: @entity.remaining, max: (* @config.timeLimit 10), variant: (if (< @entity.remaining (* @config.timeLimit 3)) "warning" "primary"), showPercentage: false, label: (str/concat "Time left: " (math/round (/ @entity.remaining 10) 1) "s") },
|
|
198
|
+
{ type: stack, direction: vertical, gap: md, children: @entity.view },
|
|
199
|
+
{ type: stack, direction: vertical, gap: sm, children: (array/map (array/range 0 (array/len @entity.options)) (fn (i)
|
|
200
|
+
{ type: button, action: ANSWER, actionPayload: { index: @i }, label: (array/nth @entity.options @i), size: lg, disabled: (not @entity.running), variant: (if @entity.running "secondary" (if (== @i @entity.correctIndex) "success" (if (== @i @entity.pickedIndex) "danger" "ghost"))) })) },
|
|
201
|
+
(if (or (== @entity.feedback "") @entity.done) null { type: stack, direction: vertical, gap: xs, children: [
|
|
202
|
+
{ type: badge, variant: (if (== @entity.verdict "correct") "success" "error"), label: (if (== @entity.verdict "correct") "Correct" (if (== @entity.verdict "timeout") "Time's up" "Incorrect")) },
|
|
203
|
+
{ type: typography, variant: body, content: @entity.feedback }
|
|
204
|
+
] }),
|
|
205
|
+
(if @entity.done { type: typography, variant: body, content: @entity.feedback } null),
|
|
206
|
+
{ type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
|
|
207
|
+
{ type: button, action: NEXT, label: @config.nextLabel, icon: "chevron-right", variant: primary, disabled: (if (and (== @entity.running false) (and (!= @entity.verdict "") (== @entity.done false))) false true) },
|
|
208
|
+
{ type: button, action: RETRY, label: @config.retryLabel, icon: "rotate-ccw", variant: ghost, disabled: (if @entity.done false true) },
|
|
209
|
+
{ type: typography, variant: caption, color: muted, content: (str/concat "Best streak " @entity.bestStreak) }
|
|
210
|
+
] }
|
|
211
|
+
] }
|
|
212
|
+
]
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
ROSTER_LOADED -> idle when (and (== @config.rosterSource "event") (not (== ?mode @config.matchMode)))
|
|
216
|
+
(set @entity.active false)
|
|
217
|
+
(set @entity.running false)
|
|
218
|
+
(render-ui main null)
|
|
219
|
+
|
|
154
220
|
ANSWER -> idle when (and (== @entity.active true) (and (== @entity.running true) (== @entity.done false)))
|
|
155
221
|
(let (
|
|
156
222
|
(correct (== ?index @entity.correctIndex))
|
|
@@ -171,11 +237,11 @@ orbital SpeedDrillOrbital {
|
|
|
171
237
|
(emit ANSWER_JUDGED { correct: (== @entity.verdict "correct"), timeLeftTenths: @entity.remaining, score: @entity.score, streak: @entity.streak })
|
|
172
238
|
|
|
173
239
|
NEXT -> idle when (and (== @entity.active true) (and (== @entity.running false) (and (!= @entity.verdict "") (== @entity.done false))))
|
|
174
|
-
(if (>= (+ @entity.itemIndex 1) (array/len @
|
|
240
|
+
(if (>= (+ @entity.itemIndex 1) (array/len @entity.items)) (emit LEARN_ROUND_COMPLETE { score: @entity.score, total: (array/len @entity.items) }) null)
|
|
175
241
|
(let (
|
|
176
242
|
(nextIndex (+ @entity.itemIndex 1))
|
|
177
|
-
(finished (>= @nextIndex (array/len @
|
|
178
|
-
(next (array/nth @
|
|
243
|
+
(finished (>= @nextIndex (array/len @entity.items)))
|
|
244
|
+
(next (array/nth @entity.items (math/min @nextIndex (- (array/len @entity.items) 1))))
|
|
179
245
|
)
|
|
180
246
|
(do
|
|
181
247
|
(set @entity.itemIndex (if @finished @entity.itemIndex @nextIndex))
|
|
@@ -233,7 +299,7 @@ orbital SpeedDrillOrbital {
|
|
|
233
299
|
|
|
234
300
|
RETRY -> idle when (and (== @entity.active true) (== @entity.done true))
|
|
235
301
|
(let (
|
|
236
|
-
(first (array/nth @
|
|
302
|
+
(first (array/nth @entity.items 0))
|
|
237
303
|
)
|
|
238
304
|
(do
|
|
239
305
|
(set @entity.itemIndex 0)
|
|
@@ -303,6 +369,12 @@ orbital SpeedDrillOrbital {
|
|
|
303
369
|
}
|
|
304
370
|
@description "Lab router broadcast naming the active mode; this instrument renders when the mode equals matchMode, otherwise renders null."
|
|
305
371
|
@tier "domain"
|
|
372
|
+
ROSTER_LOADED {
|
|
373
|
+
mode : string!
|
|
374
|
+
items : [SpeedDrillItem]!
|
|
375
|
+
}
|
|
376
|
+
@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 items is the drill roster; a matching instrument re-initialises from it exactly as INIT does from config, any other instrument hides."
|
|
377
|
+
@tier "domain"
|
|
306
378
|
ANSWER {
|
|
307
379
|
index : number
|
|
308
380
|
}
|
|
@@ -352,7 +424,7 @@ orbital SpeedDrillOrbital {
|
|
|
352
424
|
config {
|
|
353
425
|
matchMode : string = ""
|
|
354
426
|
@label "Match Mode"
|
|
355
|
-
@description "When composed behind a lab router, the MODE_SELECTED mode value this instrument responds to. Empty string means standalone — render immediately on INIT."
|
|
427
|
+
@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."
|
|
356
428
|
@tier "presentation"
|
|
357
429
|
title : string = "Speed Drill"
|
|
358
430
|
@label "Title"
|
|
@@ -362,6 +434,10 @@ orbital SpeedDrillOrbital {
|
|
|
362
434
|
@label "Concept"
|
|
363
435
|
@description "One line under the title saying what is being drilled (keep it under ~65 characters). Empty shows no line."
|
|
364
436
|
@tier "presentation"
|
|
437
|
+
rosterSource : "config" | "event" = "config"
|
|
438
|
+
@label "Roster Source"
|
|
439
|
+
@description "Where the roster comes from: config reads items knob at INIT; event waits for ROSTER_LOADED and takes the roster from its payload."
|
|
440
|
+
@tier "domain"
|
|
365
441
|
items : [SpeedDrillItem] = [
|
|
366
442
|
{ prompt: "7 × 8", options: ["54", "56", "63", "48"], correctIndex: 1 },
|
|
367
443
|
{ prompt: "9 × 6", options: ["54", "56", "45", "63"], correctIndex: 0 },
|