@almadar/std 16.241.0 → 16.242.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 (109) hide show
  1. package/behaviors/behaviors-registry.json +4650 -535
  2. package/behaviors/lolo/agent/atoms/std-agent-memory.lolo +38 -1
  3. package/behaviors/lolo/agent/atoms/std-agent-session.lolo +1074 -47
  4. package/behaviors/lolo/agent/atoms/std-agent-tool-loop.lolo +8 -7
  5. package/behaviors/lolo/agent/organisms/std-agent-assistant.lolo +56 -37
  6. package/behaviors/lolo/infra/atoms/std-page-open.lolo +59 -0
  7. package/behaviors/lolo/infra/atoms/std-page-search.lolo +134 -0
  8. package/behaviors/lolo/infra/atoms/std-page-treat.lolo +59 -0
  9. package/behaviors/lolo/infra/atoms/std-page-watch.lolo +86 -0
  10. package/behaviors/lolo/ui/core/atoms/std-book-reader.lolo +25 -1
  11. package/behaviors/lolo/ui/core/atoms/std-card-grid.lolo +9 -0
  12. package/behaviors/lolo/ui/core/atoms/std-doc-page.lolo +153 -0
  13. package/behaviors/lolo/ui/learning/atoms/std-learn-arrangement.lolo +124 -92
  14. package/behaviors/lolo/ui/learning/atoms/std-learn-classify.lolo +114 -55
  15. package/behaviors/lolo/ui/learning/atoms/std-learn-compare.lolo +40 -14
  16. package/behaviors/lolo/ui/learning/atoms/std-learn-coupled-sim.lolo +363 -123
  17. package/behaviors/lolo/ui/learning/atoms/std-learn-derivation.lolo +93 -48
  18. package/behaviors/lolo/ui/learning/atoms/std-learn-diagram.lolo +60 -28
  19. package/behaviors/lolo/ui/learning/atoms/std-learn-doser.lolo +193 -96
  20. package/behaviors/lolo/ui/learning/atoms/std-learn-estimate.lolo +75 -32
  21. package/behaviors/lolo/ui/learning/atoms/std-learn-goal-seek.lolo +142 -86
  22. package/behaviors/lolo/ui/learning/atoms/std-learn-grid-sim.lolo +266 -98
  23. package/behaviors/lolo/ui/learning/atoms/std-learn-hotspot.lolo +103 -65
  24. package/behaviors/lolo/ui/learning/atoms/std-learn-live-sim.lolo +223 -109
  25. package/behaviors/lolo/ui/learning/atoms/std-learn-measure.lolo +232 -64
  26. package/behaviors/lolo/ui/learning/atoms/std-learn-param-explorer.lolo +69 -29
  27. package/behaviors/lolo/ui/learning/atoms/std-learn-perturb.lolo +363 -123
  28. package/behaviors/lolo/ui/learning/atoms/std-learn-predict.lolo +73 -41
  29. package/behaviors/lolo/ui/learning/atoms/std-learn-sample-accumulator.lolo +96 -38
  30. package/behaviors/lolo/ui/learning/atoms/std-learn-sandbox.lolo +65 -45
  31. package/behaviors/lolo/ui/learning/atoms/std-learn-scatter-fit.lolo +243 -117
  32. package/behaviors/lolo/ui/learning/atoms/std-learn-scenario.lolo +76 -28
  33. package/behaviors/lolo/ui/learning/atoms/std-learn-sim-3d.lolo +228 -109
  34. package/behaviors/lolo/ui/learning/atoms/std-learn-speed-drill.lolo +95 -44
  35. package/behaviors/lolo/ui/learning/atoms/std-learn-stepper.lolo +199 -125
  36. package/behaviors/lolo/ui/learning/atoms/std-learn-tour-3d.lolo +92 -48
  37. package/behaviors/lolo/ui/learning/atoms/std-learn-trace-player.lolo +239 -78
  38. package/behaviors/lolo/ui/learning/atoms/std-learn-transport.lolo +147 -38
  39. package/behaviors/lolo/ui/learning/atoms/std-learn-tree.lolo +123 -58
  40. package/behaviors/lolo/ui/learning/atoms/ui-algo-graph-canvas.lolo +22 -0
  41. package/behaviors/lolo/ui/learning/atoms/ui-algorithm-canvas.lolo +26 -0
  42. package/behaviors/lolo/ui/learning/atoms/ui-biology-canvas.lolo +26 -0
  43. package/behaviors/lolo/ui/learning/atoms/ui-chemistry-canvas.lolo +27 -1
  44. package/behaviors/lolo/ui/learning/atoms/ui-learning-canvas.lolo +27 -1
  45. package/behaviors/lolo/ui/learning/atoms/ui-math-canvas.lolo +29 -9
  46. package/behaviors/lolo/ui/learning/atoms/ui-physics-canvas.lolo +26 -0
  47. package/behaviors/lolo-behavior-contracts.json +1 -1
  48. package/behaviors/registry/agent/atoms/std-agent-memory.orb +372 -2
  49. package/behaviors/registry/agent/atoms/std-agent-session.orb +4752 -348
  50. package/behaviors/registry/agent/atoms/std-agent-tool-loop.orb +54 -42
  51. package/behaviors/registry/agent/organisms/std-agent-assistant.orb +356 -122
  52. package/behaviors/registry/factory-signatures.json +1 -1
  53. package/behaviors/registry/infra/atoms/std-page-open.orb +435 -0
  54. package/behaviors/registry/infra/atoms/std-page-search.orb +867 -0
  55. package/behaviors/registry/infra/atoms/std-page-treat.orb +494 -0
  56. package/behaviors/registry/infra/atoms/std-page-watch.orb +554 -0
  57. package/behaviors/registry/ui/core/atoms/std-book-reader.orb +119 -0
  58. package/behaviors/registry/ui/core/atoms/std-card-grid.orb +61 -0
  59. package/behaviors/registry/ui/core/atoms/std-doc-page.orb +594 -0
  60. package/behaviors/registry/ui/learning/atoms/std-learn-arrangement.orb +903 -369
  61. package/behaviors/registry/ui/learning/atoms/std-learn-classify.orb +1002 -232
  62. package/behaviors/registry/ui/learning/atoms/std-learn-compare.orb +253 -74
  63. package/behaviors/registry/ui/learning/atoms/std-learn-coupled-sim.orb +3624 -921
  64. package/behaviors/registry/ui/learning/atoms/std-learn-derivation.orb +685 -144
  65. package/behaviors/registry/ui/learning/atoms/std-learn-diagram.orb +404 -52
  66. package/behaviors/registry/ui/learning/atoms/std-learn-doser.orb +1787 -210
  67. package/behaviors/registry/ui/learning/atoms/std-learn-estimate.orb +699 -71
  68. package/behaviors/registry/ui/learning/atoms/std-learn-goal-seek.orb +1102 -578
  69. package/behaviors/registry/ui/learning/atoms/std-learn-grid-sim.orb +2760 -872
  70. package/behaviors/registry/ui/learning/atoms/std-learn-hotspot.orb +689 -152
  71. package/behaviors/registry/ui/learning/atoms/std-learn-live-sim.orb +1431 -633
  72. package/behaviors/registry/ui/learning/atoms/std-learn-measure.orb +2485 -512
  73. package/behaviors/registry/ui/learning/atoms/std-learn-param-explorer.orb +501 -197
  74. package/behaviors/registry/ui/learning/atoms/std-learn-perturb.orb +3642 -928
  75. package/behaviors/registry/ui/learning/atoms/std-learn-predict.orb +705 -125
  76. package/behaviors/registry/ui/learning/atoms/std-learn-sample-accumulator.orb +624 -114
  77. package/behaviors/registry/ui/learning/atoms/std-learn-sandbox.orb +405 -153
  78. package/behaviors/registry/ui/learning/atoms/std-learn-scatter-fit.orb +1911 -611
  79. package/behaviors/registry/ui/learning/atoms/std-learn-scenario.orb +436 -128
  80. package/behaviors/registry/ui/learning/atoms/std-learn-sim-3d.orb +2482 -485
  81. package/behaviors/registry/ui/learning/atoms/std-learn-speed-drill.orb +896 -192
  82. package/behaviors/registry/ui/learning/atoms/std-learn-stepper.orb +2001 -759
  83. package/behaviors/registry/ui/learning/atoms/std-learn-tour-3d.orb +734 -228
  84. package/behaviors/registry/ui/learning/atoms/std-learn-trace-player.orb +2501 -764
  85. package/behaviors/registry/ui/learning/atoms/std-learn-transport.orb +1591 -173
  86. package/behaviors/registry/ui/learning/atoms/std-learn-tree.orb +883 -122
  87. package/behaviors/registry/ui/learning/atoms/ui-algo-graph-canvas.orb +176 -0
  88. package/behaviors/registry/ui/learning/atoms/ui-algorithm-canvas.orb +211 -0
  89. package/behaviors/registry/ui/learning/atoms/ui-biology-canvas.orb +211 -0
  90. package/behaviors/registry/ui/learning/atoms/ui-chemistry-canvas.orb +212 -1
  91. package/behaviors/registry/ui/learning/atoms/ui-learning-canvas.orb +212 -1
  92. package/behaviors/registry/ui/learning/atoms/ui-math-canvas.orb +203 -9
  93. package/behaviors/registry/ui/learning/atoms/ui-physics-canvas.orb +211 -0
  94. package/behaviors/signatures.lolo +325 -655
  95. package/dist/behaviors/exports-reader.js +16092 -9747
  96. package/dist/behaviors/functions/index.d.ts +1052 -136
  97. package/dist/behaviors/functions/index.js +16063 -9745
  98. package/dist/behaviors/index.d.ts +1 -1
  99. package/dist/behaviors/index.js +16093 -9748
  100. package/dist/behaviors/query.js +16092 -9747
  101. package/dist/behaviors-embeddings.hash.json +3 -3
  102. package/dist/behaviors-embeddings.json +45 -25
  103. package/dist/behaviors-registry.json +4650 -535
  104. package/dist/index.d.ts +1 -1
  105. package/dist/index.js +16093 -9748
  106. package/dist/knob-embeddings.hash.json +3 -3
  107. package/dist/knob-embeddings.json +607 -263
  108. package/dist/registry/factory-signatures.json +1 -1
  109. package/package.json +3 -3
@@ -86,25 +86,43 @@ orbital LearnScatterFitOrbital {
86
86
  padding: md
87
87
  children: [
88
88
  { type: stack, direction: vertical, gap: md, children: [
89
- { type: typography, variant: h4, content: @entity.title },
90
- { type: stack, direction: horizontal, gap: sm, children: [
91
- { type: button, action: ADD_POINT, label: @config.addPointLabel, variant: primary },
92
- { type: button, action: REVEAL_FIT, label: @config.revealLabel, variant: secondary },
93
- { type: button, action: TOGGLE_RUN, label: (if @entity.running @config.pauseLabel @config.runLabel), variant: secondary },
94
- { type: button, action: RESET, label: @config.resetLabel, variant: ghost }
89
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
90
+ { type: stack, direction: vertical, gap: xs, children: [
91
+ { type: typography, variant: h4, content: @entity.title },
92
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
93
+ ] },
94
+ { 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"))) }
95
95
  ] },
96
- { type: typography, variant: caption, content: (str/concat @config.guessSlopeCaption (math/round @entity.guessSlope 2)) },
97
- { type: range-slider, min: @config.guessSlopeMin, max: @config.guessSlopeMax, step: @config.guessSlopeStep, value: @entity.guessSlope, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "slope" } },
98
- { type: typography, variant: caption, content: (str/concat @config.guessInterceptCaption (math/round @entity.guessIntercept 1)) },
99
- { type: range-slider, min: @config.guessInterceptMin, max: @config.guessInterceptMax, step: @config.guessInterceptStep, value: @entity.guessIntercept, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "intercept" } },
100
- { type: math-canvas, 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 },
101
- { type: typography, variant: body, content: (if @config.showR (str/concat "r = " (math/round @entity.r 3) " — R² = " (math/round @entity.rSquared 3) " — guess score " @entity.guessScore "%") "") },
96
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
97
+ { type: button, action: ADD_POINT, label: @config.addPointLabel, icon: "plus", variant: primary, disabled: @entity.done },
98
+ { type: button, action: REVEAL_FIT, label: @config.revealLabel, icon: "eye", variant: secondary },
99
+ (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 }),
100
+ { type: button, action: RESET, label: @config.resetLabel, icon: "rotate-ccw", variant: ghost },
101
+ { type: typography, variant: caption, color: muted, content: (str/concat (str/concat "" (array/len @entity.points)) (str/concat " of " (str/concat "" @config.maxPoints))) }
102
+ ] },
103
+ { 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 },
104
+ { type: stack, direction: vertical, gap: sm, children: [
105
+ { type: stack, direction: vertical, gap: xs, children: [
106
+ { type: typography, variant: caption, content: (str/concat @config.guessSlopeCaption (math/round @entity.guessSlope 2)) },
107
+ { type: range-slider, min: @config.guessSlopeMin, max: @config.guessSlopeMax, step: @config.guessSlopeStep, value: @entity.guessSlope, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "slope" } }
108
+ ] },
109
+ { type: stack, direction: vertical, gap: xs, children: [
110
+ { type: typography, variant: caption, content: (str/concat @config.guessInterceptCaption (math/round @entity.guessIntercept 1)) },
111
+ { type: range-slider, min: @config.guessInterceptMin, max: @config.guessInterceptMax, step: @config.guessInterceptStep, value: @entity.guessIntercept, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "intercept" } }
112
+ ] }
113
+ ] },
114
+ { 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 "%") "") },
102
115
  { type: typography, variant: body, content: @entity.narration }
103
116
  ] }
104
117
  ]
105
118
  })
106
119
  (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 })
107
120
 
121
+ MODE_SELECTED -> idle when (and (not (== @config.matchMode "")) (not (== ?mode @config.matchMode)))
122
+ (set @entity.active false)
123
+ (set @entity.running false)
124
+ (render-ui main null)
125
+
108
126
  MODE_SELECTED -> idle when (== ?mode @config.matchMode)
109
127
  (set @entity.active true)
110
128
  (set @entity.title @config.title)
@@ -148,19 +166,32 @@ orbital LearnScatterFitOrbital {
148
166
  padding: md
149
167
  children: [
150
168
  { type: stack, direction: vertical, gap: md, children: [
151
- { type: typography, variant: h4, content: @entity.title },
152
- { type: stack, direction: horizontal, gap: sm, children: [
153
- { type: button, action: ADD_POINT, label: @config.addPointLabel, variant: primary },
154
- { type: button, action: REVEAL_FIT, label: @config.revealLabel, variant: secondary },
155
- { type: button, action: TOGGLE_RUN, label: (if @entity.running @config.pauseLabel @config.runLabel), variant: secondary },
156
- { type: button, action: RESET, label: @config.resetLabel, variant: ghost }
169
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
170
+ { type: stack, direction: vertical, gap: xs, children: [
171
+ { type: typography, variant: h4, content: @entity.title },
172
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
173
+ ] },
174
+ { 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"))) }
175
+ ] },
176
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
177
+ { type: button, action: ADD_POINT, label: @config.addPointLabel, icon: "plus", variant: primary, disabled: @entity.done },
178
+ { type: button, action: REVEAL_FIT, label: @config.revealLabel, icon: "eye", variant: secondary },
179
+ (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 }),
180
+ { type: button, action: RESET, label: @config.resetLabel, icon: "rotate-ccw", variant: ghost },
181
+ { type: typography, variant: caption, color: muted, content: (str/concat (str/concat "" (array/len @entity.points)) (str/concat " of " (str/concat "" @config.maxPoints))) }
182
+ ] },
183
+ { 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 },
184
+ { type: stack, direction: vertical, gap: sm, children: [
185
+ { type: stack, direction: vertical, gap: xs, children: [
186
+ { type: typography, variant: caption, content: (str/concat @config.guessSlopeCaption (math/round @entity.guessSlope 2)) },
187
+ { type: range-slider, min: @config.guessSlopeMin, max: @config.guessSlopeMax, step: @config.guessSlopeStep, value: @entity.guessSlope, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "slope" } }
188
+ ] },
189
+ { type: stack, direction: vertical, gap: xs, children: [
190
+ { type: typography, variant: caption, content: (str/concat @config.guessInterceptCaption (math/round @entity.guessIntercept 1)) },
191
+ { type: range-slider, min: @config.guessInterceptMin, max: @config.guessInterceptMax, step: @config.guessInterceptStep, value: @entity.guessIntercept, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "intercept" } }
192
+ ] }
157
193
  ] },
158
- { type: typography, variant: caption, content: (str/concat @config.guessSlopeCaption (math/round @entity.guessSlope 2)) },
159
- { type: range-slider, min: @config.guessSlopeMin, max: @config.guessSlopeMax, step: @config.guessSlopeStep, value: @entity.guessSlope, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "slope" } },
160
- { type: typography, variant: caption, content: (str/concat @config.guessInterceptCaption (math/round @entity.guessIntercept 1)) },
161
- { type: range-slider, min: @config.guessInterceptMin, max: @config.guessInterceptMax, step: @config.guessInterceptStep, value: @entity.guessIntercept, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "intercept" } },
162
- { type: math-canvas, 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 },
163
- { type: typography, variant: body, content: (if @config.showR (str/concat "r = " (math/round @entity.r 3) " — R² = " (math/round @entity.rSquared 3) " — guess score " @entity.guessScore "%") "") },
194
+ { 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 "%") "") },
164
195
  { type: typography, variant: body, content: @entity.narration }
165
196
  ] }
166
197
  ]
@@ -219,19 +250,32 @@ orbital LearnScatterFitOrbital {
219
250
  padding: md
220
251
  children: [
221
252
  { type: stack, direction: vertical, gap: md, children: [
222
- { type: typography, variant: h4, content: @entity.title },
223
- { type: stack, direction: horizontal, gap: sm, children: [
224
- { type: button, action: ADD_POINT, label: @config.addPointLabel, variant: primary },
225
- { type: button, action: REVEAL_FIT, label: @config.revealLabel, variant: secondary },
226
- { type: button, action: TOGGLE_RUN, label: (if @entity.running @config.pauseLabel @config.runLabel), variant: secondary },
227
- { type: button, action: RESET, label: @config.resetLabel, variant: ghost }
253
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
254
+ { type: stack, direction: vertical, gap: xs, children: [
255
+ { type: typography, variant: h4, content: @entity.title },
256
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
257
+ ] },
258
+ { 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"))) }
228
259
  ] },
229
- { type: typography, variant: caption, content: (str/concat @config.guessSlopeCaption (math/round @entity.guessSlope 2)) },
230
- { type: range-slider, min: @config.guessSlopeMin, max: @config.guessSlopeMax, step: @config.guessSlopeStep, value: @entity.guessSlope, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "slope" } },
231
- { type: typography, variant: caption, content: (str/concat @config.guessInterceptCaption (math/round @entity.guessIntercept 1)) },
232
- { type: range-slider, min: @config.guessInterceptMin, max: @config.guessInterceptMax, step: @config.guessInterceptStep, value: @entity.guessIntercept, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "intercept" } },
233
- { type: math-canvas, 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 },
234
- { type: typography, variant: body, content: (if @config.showR (str/concat "r = " (math/round @entity.r 3) " — R² = " (math/round @entity.rSquared 3) " — guess score " @entity.guessScore "%") "") },
260
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
261
+ { type: button, action: ADD_POINT, label: @config.addPointLabel, icon: "plus", variant: primary, disabled: @entity.done },
262
+ { type: button, action: REVEAL_FIT, label: @config.revealLabel, icon: "eye", variant: secondary },
263
+ (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 }),
264
+ { type: button, action: RESET, label: @config.resetLabel, icon: "rotate-ccw", variant: ghost },
265
+ { type: typography, variant: caption, color: muted, content: (str/concat (str/concat "" (array/len @entity.points)) (str/concat " of " (str/concat "" @config.maxPoints))) }
266
+ ] },
267
+ { 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 },
268
+ { type: stack, direction: vertical, gap: sm, children: [
269
+ { type: stack, direction: vertical, gap: xs, children: [
270
+ { type: typography, variant: caption, content: (str/concat @config.guessSlopeCaption (math/round @entity.guessSlope 2)) },
271
+ { type: range-slider, min: @config.guessSlopeMin, max: @config.guessSlopeMax, step: @config.guessSlopeStep, value: @entity.guessSlope, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "slope" } }
272
+ ] },
273
+ { type: stack, direction: vertical, gap: xs, children: [
274
+ { type: typography, variant: caption, content: (str/concat @config.guessInterceptCaption (math/round @entity.guessIntercept 1)) },
275
+ { type: range-slider, min: @config.guessInterceptMin, max: @config.guessInterceptMax, step: @config.guessInterceptStep, value: @entity.guessIntercept, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "intercept" } }
276
+ ] }
277
+ ] },
278
+ { 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 "%") "") },
235
279
  { type: typography, variant: body, content: @entity.narration }
236
280
  ] }
237
281
  ]
@@ -285,19 +329,32 @@ orbital LearnScatterFitOrbital {
285
329
  padding: md
286
330
  children: [
287
331
  { type: stack, direction: vertical, gap: md, children: [
288
- { type: typography, variant: h4, content: @entity.title },
289
- { type: stack, direction: horizontal, gap: sm, children: [
290
- { type: button, action: ADD_POINT, label: @config.addPointLabel, variant: primary },
291
- { type: button, action: REVEAL_FIT, label: @config.revealLabel, variant: secondary },
292
- { type: button, action: TOGGLE_RUN, label: (if @entity.running @config.pauseLabel @config.runLabel), variant: secondary },
293
- { type: button, action: RESET, label: @config.resetLabel, variant: ghost }
332
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
333
+ { type: stack, direction: vertical, gap: xs, children: [
334
+ { type: typography, variant: h4, content: @entity.title },
335
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
336
+ ] },
337
+ { 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"))) }
338
+ ] },
339
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
340
+ { type: button, action: ADD_POINT, label: @config.addPointLabel, icon: "plus", variant: primary, disabled: @entity.done },
341
+ { type: button, action: REVEAL_FIT, label: @config.revealLabel, icon: "eye", variant: secondary },
342
+ (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 }),
343
+ { type: button, action: RESET, label: @config.resetLabel, icon: "rotate-ccw", variant: ghost },
344
+ { type: typography, variant: caption, color: muted, content: (str/concat (str/concat "" (array/len @entity.points)) (str/concat " of " (str/concat "" @config.maxPoints))) }
294
345
  ] },
295
- { type: typography, variant: caption, content: (str/concat @config.guessSlopeCaption (math/round @entity.guessSlope 2)) },
296
- { type: range-slider, min: @config.guessSlopeMin, max: @config.guessSlopeMax, step: @config.guessSlopeStep, value: @entity.guessSlope, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "slope" } },
297
- { type: typography, variant: caption, content: (str/concat @config.guessInterceptCaption (math/round @entity.guessIntercept 1)) },
298
- { type: range-slider, min: @config.guessInterceptMin, max: @config.guessInterceptMax, step: @config.guessInterceptStep, value: @entity.guessIntercept, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "intercept" } },
299
- { type: math-canvas, 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 },
300
- { type: typography, variant: body, content: (if @config.showR (str/concat "r = " (math/round @entity.r 3) " — R² = " (math/round @entity.rSquared 3) " — guess score " @entity.guessScore "%") "") },
346
+ { 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 },
347
+ { type: stack, direction: vertical, gap: sm, children: [
348
+ { type: stack, direction: vertical, gap: xs, children: [
349
+ { type: typography, variant: caption, content: (str/concat @config.guessSlopeCaption (math/round @entity.guessSlope 2)) },
350
+ { type: range-slider, min: @config.guessSlopeMin, max: @config.guessSlopeMax, step: @config.guessSlopeStep, value: @entity.guessSlope, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "slope" } }
351
+ ] },
352
+ { type: stack, direction: vertical, gap: xs, children: [
353
+ { type: typography, variant: caption, content: (str/concat @config.guessInterceptCaption (math/round @entity.guessIntercept 1)) },
354
+ { type: range-slider, min: @config.guessInterceptMin, max: @config.guessInterceptMax, step: @config.guessInterceptStep, value: @entity.guessIntercept, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "intercept" } }
355
+ ] }
356
+ ] },
357
+ { 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 "%") "") },
301
358
  { type: typography, variant: body, content: @entity.narration }
302
359
  ] }
303
360
  ]
@@ -345,19 +402,32 @@ orbital LearnScatterFitOrbital {
345
402
  padding: md
346
403
  children: [
347
404
  { type: stack, direction: vertical, gap: md, children: [
348
- { type: typography, variant: h4, content: @entity.title },
349
- { type: stack, direction: horizontal, gap: sm, children: [
350
- { type: button, action: ADD_POINT, label: @config.addPointLabel, variant: primary },
351
- { type: button, action: REVEAL_FIT, label: @config.revealLabel, variant: secondary },
352
- { type: button, action: TOGGLE_RUN, label: (if @entity.running @config.pauseLabel @config.runLabel), variant: secondary },
353
- { type: button, action: RESET, label: @config.resetLabel, variant: ghost }
405
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
406
+ { type: stack, direction: vertical, gap: xs, children: [
407
+ { type: typography, variant: h4, content: @entity.title },
408
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
409
+ ] },
410
+ { 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"))) }
411
+ ] },
412
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
413
+ { type: button, action: ADD_POINT, label: @config.addPointLabel, icon: "plus", variant: primary, disabled: @entity.done },
414
+ { type: button, action: REVEAL_FIT, label: @config.revealLabel, icon: "eye", variant: secondary },
415
+ (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 }),
416
+ { type: button, action: RESET, label: @config.resetLabel, icon: "rotate-ccw", variant: ghost },
417
+ { type: typography, variant: caption, color: muted, content: (str/concat (str/concat "" (array/len @entity.points)) (str/concat " of " (str/concat "" @config.maxPoints))) }
354
418
  ] },
355
- { type: typography, variant: caption, content: (str/concat @config.guessSlopeCaption (math/round @entity.guessSlope 2)) },
356
- { type: range-slider, min: @config.guessSlopeMin, max: @config.guessSlopeMax, step: @config.guessSlopeStep, value: @entity.guessSlope, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "slope" } },
357
- { type: typography, variant: caption, content: (str/concat @config.guessInterceptCaption (math/round @entity.guessIntercept 1)) },
358
- { type: range-slider, min: @config.guessInterceptMin, max: @config.guessInterceptMax, step: @config.guessInterceptStep, value: @entity.guessIntercept, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "intercept" } },
359
- { type: math-canvas, 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 },
360
- { type: typography, variant: body, content: (if @config.showR (str/concat "r = " (math/round @entity.r 3) " — R² = " (math/round @entity.rSquared 3) " — guess score " @entity.guessScore "%") "") },
419
+ { 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 },
420
+ { type: stack, direction: vertical, gap: sm, children: [
421
+ { type: stack, direction: vertical, gap: xs, children: [
422
+ { type: typography, variant: caption, content: (str/concat @config.guessSlopeCaption (math/round @entity.guessSlope 2)) },
423
+ { type: range-slider, min: @config.guessSlopeMin, max: @config.guessSlopeMax, step: @config.guessSlopeStep, value: @entity.guessSlope, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "slope" } }
424
+ ] },
425
+ { type: stack, direction: vertical, gap: xs, children: [
426
+ { type: typography, variant: caption, content: (str/concat @config.guessInterceptCaption (math/round @entity.guessIntercept 1)) },
427
+ { type: range-slider, min: @config.guessInterceptMin, max: @config.guessInterceptMax, step: @config.guessInterceptStep, value: @entity.guessIntercept, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "intercept" } }
428
+ ] }
429
+ ] },
430
+ { 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 "%") "") },
361
431
  { type: typography, variant: body, content: @entity.narration }
362
432
  ] }
363
433
  ]
@@ -388,19 +458,32 @@ orbital LearnScatterFitOrbital {
388
458
  padding: md
389
459
  children: [
390
460
  { type: stack, direction: vertical, gap: md, children: [
391
- { type: typography, variant: h4, content: @entity.title },
392
- { type: stack, direction: horizontal, gap: sm, children: [
393
- { type: button, action: ADD_POINT, label: @config.addPointLabel, variant: primary },
394
- { type: button, action: REVEAL_FIT, label: @config.revealLabel, variant: secondary },
395
- { type: button, action: TOGGLE_RUN, label: (if @entity.running @config.pauseLabel @config.runLabel), variant: secondary },
396
- { type: button, action: RESET, label: @config.resetLabel, variant: ghost }
461
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
462
+ { type: stack, direction: vertical, gap: xs, children: [
463
+ { type: typography, variant: h4, content: @entity.title },
464
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
465
+ ] },
466
+ { 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"))) }
467
+ ] },
468
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
469
+ { type: button, action: ADD_POINT, label: @config.addPointLabel, icon: "plus", variant: primary, disabled: @entity.done },
470
+ { type: button, action: REVEAL_FIT, label: @config.revealLabel, icon: "eye", variant: secondary },
471
+ (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 }),
472
+ { type: button, action: RESET, label: @config.resetLabel, icon: "rotate-ccw", variant: ghost },
473
+ { type: typography, variant: caption, color: muted, content: (str/concat (str/concat "" (array/len @entity.points)) (str/concat " of " (str/concat "" @config.maxPoints))) }
474
+ ] },
475
+ { 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 },
476
+ { type: stack, direction: vertical, gap: sm, children: [
477
+ { type: stack, direction: vertical, gap: xs, children: [
478
+ { type: typography, variant: caption, content: (str/concat @config.guessSlopeCaption (math/round @entity.guessSlope 2)) },
479
+ { type: range-slider, min: @config.guessSlopeMin, max: @config.guessSlopeMax, step: @config.guessSlopeStep, value: @entity.guessSlope, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "slope" } }
480
+ ] },
481
+ { type: stack, direction: vertical, gap: xs, children: [
482
+ { type: typography, variant: caption, content: (str/concat @config.guessInterceptCaption (math/round @entity.guessIntercept 1)) },
483
+ { type: range-slider, min: @config.guessInterceptMin, max: @config.guessInterceptMax, step: @config.guessInterceptStep, value: @entity.guessIntercept, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "intercept" } }
484
+ ] }
397
485
  ] },
398
- { type: typography, variant: caption, content: (str/concat @config.guessSlopeCaption (math/round @entity.guessSlope 2)) },
399
- { type: range-slider, min: @config.guessSlopeMin, max: @config.guessSlopeMax, step: @config.guessSlopeStep, value: @entity.guessSlope, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "slope" } },
400
- { type: typography, variant: caption, content: (str/concat @config.guessInterceptCaption (math/round @entity.guessIntercept 1)) },
401
- { type: range-slider, min: @config.guessInterceptMin, max: @config.guessInterceptMax, step: @config.guessInterceptStep, value: @entity.guessIntercept, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "intercept" } },
402
- { type: math-canvas, 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 },
403
- { type: typography, variant: body, content: (if @config.showR (str/concat "r = " (math/round @entity.r 3) " — R² = " (math/round @entity.rSquared 3) " — guess score " @entity.guessScore "%") "") },
486
+ { 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 "%") "") },
404
487
  { type: typography, variant: body, content: @entity.narration }
405
488
  ] }
406
489
  ]
@@ -415,19 +498,32 @@ orbital LearnScatterFitOrbital {
415
498
  padding: md
416
499
  children: [
417
500
  { type: stack, direction: vertical, gap: md, children: [
418
- { type: typography, variant: h4, content: @entity.title },
419
- { type: stack, direction: horizontal, gap: sm, children: [
420
- { type: button, action: ADD_POINT, label: @config.addPointLabel, variant: primary },
421
- { type: button, action: REVEAL_FIT, label: @config.revealLabel, variant: secondary },
422
- { type: button, action: TOGGLE_RUN, label: (if @entity.running @config.pauseLabel @config.runLabel), variant: secondary },
423
- { type: button, action: RESET, label: @config.resetLabel, variant: ghost }
501
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
502
+ { type: stack, direction: vertical, gap: xs, children: [
503
+ { type: typography, variant: h4, content: @entity.title },
504
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
505
+ ] },
506
+ { 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"))) }
507
+ ] },
508
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
509
+ { type: button, action: ADD_POINT, label: @config.addPointLabel, icon: "plus", variant: primary, disabled: @entity.done },
510
+ { type: button, action: REVEAL_FIT, label: @config.revealLabel, icon: "eye", variant: secondary },
511
+ (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 }),
512
+ { type: button, action: RESET, label: @config.resetLabel, icon: "rotate-ccw", variant: ghost },
513
+ { type: typography, variant: caption, color: muted, content: (str/concat (str/concat "" (array/len @entity.points)) (str/concat " of " (str/concat "" @config.maxPoints))) }
514
+ ] },
515
+ { 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 },
516
+ { type: stack, direction: vertical, gap: sm, children: [
517
+ { type: stack, direction: vertical, gap: xs, children: [
518
+ { type: typography, variant: caption, content: (str/concat @config.guessSlopeCaption (math/round @entity.guessSlope 2)) },
519
+ { type: range-slider, min: @config.guessSlopeMin, max: @config.guessSlopeMax, step: @config.guessSlopeStep, value: @entity.guessSlope, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "slope" } }
520
+ ] },
521
+ { type: stack, direction: vertical, gap: xs, children: [
522
+ { type: typography, variant: caption, content: (str/concat @config.guessInterceptCaption (math/round @entity.guessIntercept 1)) },
523
+ { type: range-slider, min: @config.guessInterceptMin, max: @config.guessInterceptMax, step: @config.guessInterceptStep, value: @entity.guessIntercept, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "intercept" } }
524
+ ] }
424
525
  ] },
425
- { type: typography, variant: caption, content: (str/concat @config.guessSlopeCaption (math/round @entity.guessSlope 2)) },
426
- { type: range-slider, min: @config.guessSlopeMin, max: @config.guessSlopeMax, step: @config.guessSlopeStep, value: @entity.guessSlope, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "slope" } },
427
- { type: typography, variant: caption, content: (str/concat @config.guessInterceptCaption (math/round @entity.guessIntercept 1)) },
428
- { type: range-slider, min: @config.guessInterceptMin, max: @config.guessInterceptMax, step: @config.guessInterceptStep, value: @entity.guessIntercept, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "intercept" } },
429
- { type: math-canvas, 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 },
430
- { type: typography, variant: body, content: (if @config.showR (str/concat "r = " (math/round @entity.r 3) " — R² = " (math/round @entity.rSquared 3) " — guess score " @entity.guessScore "%") "") },
526
+ { 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 "%") "") },
431
527
  { type: typography, variant: body, content: @entity.narration }
432
528
  ] }
433
529
  ]
@@ -475,19 +571,32 @@ orbital LearnScatterFitOrbital {
475
571
  padding: md
476
572
  children: [
477
573
  { type: stack, direction: vertical, gap: md, children: [
478
- { type: typography, variant: h4, content: @entity.title },
479
- { type: stack, direction: horizontal, gap: sm, children: [
480
- { type: button, action: ADD_POINT, label: @config.addPointLabel, variant: primary },
481
- { type: button, action: REVEAL_FIT, label: @config.revealLabel, variant: secondary },
482
- { type: button, action: TOGGLE_RUN, label: (if @entity.running @config.pauseLabel @config.runLabel), variant: secondary },
483
- { type: button, action: RESET, label: @config.resetLabel, variant: ghost }
574
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
575
+ { type: stack, direction: vertical, gap: xs, children: [
576
+ { type: typography, variant: h4, content: @entity.title },
577
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
578
+ ] },
579
+ { 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"))) }
484
580
  ] },
485
- { type: typography, variant: caption, content: (str/concat @config.guessSlopeCaption (math/round @entity.guessSlope 2)) },
486
- { type: range-slider, min: @config.guessSlopeMin, max: @config.guessSlopeMax, step: @config.guessSlopeStep, value: @entity.guessSlope, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "slope" } },
487
- { type: typography, variant: caption, content: (str/concat @config.guessInterceptCaption (math/round @entity.guessIntercept 1)) },
488
- { type: range-slider, min: @config.guessInterceptMin, max: @config.guessInterceptMax, step: @config.guessInterceptStep, value: @entity.guessIntercept, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "intercept" } },
489
- { type: math-canvas, 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 },
490
- { type: typography, variant: body, content: (if @config.showR (str/concat "r = " (math/round @entity.r 3) " — R² = " (math/round @entity.rSquared 3) " — guess score " @entity.guessScore "%") "") },
581
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
582
+ { type: button, action: ADD_POINT, label: @config.addPointLabel, icon: "plus", variant: primary, disabled: @entity.done },
583
+ { type: button, action: REVEAL_FIT, label: @config.revealLabel, icon: "eye", variant: secondary },
584
+ (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 }),
585
+ { type: button, action: RESET, label: @config.resetLabel, icon: "rotate-ccw", variant: ghost },
586
+ { type: typography, variant: caption, color: muted, content: (str/concat (str/concat "" (array/len @entity.points)) (str/concat " of " (str/concat "" @config.maxPoints))) }
587
+ ] },
588
+ { 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 },
589
+ { type: stack, direction: vertical, gap: sm, children: [
590
+ { type: stack, direction: vertical, gap: xs, children: [
591
+ { type: typography, variant: caption, content: (str/concat @config.guessSlopeCaption (math/round @entity.guessSlope 2)) },
592
+ { type: range-slider, min: @config.guessSlopeMin, max: @config.guessSlopeMax, step: @config.guessSlopeStep, value: @entity.guessSlope, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "slope" } }
593
+ ] },
594
+ { type: stack, direction: vertical, gap: xs, children: [
595
+ { type: typography, variant: caption, content: (str/concat @config.guessInterceptCaption (math/round @entity.guessIntercept 1)) },
596
+ { type: range-slider, min: @config.guessInterceptMin, max: @config.guessInterceptMax, step: @config.guessInterceptStep, value: @entity.guessIntercept, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "intercept" } }
597
+ ] }
598
+ ] },
599
+ { 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 "%") "") },
491
600
  { type: typography, variant: body, content: @entity.narration }
492
601
  ] }
493
602
  ]
@@ -549,19 +658,32 @@ orbital LearnScatterFitOrbital {
549
658
  padding: md
550
659
  children: [
551
660
  { type: stack, direction: vertical, gap: md, children: [
552
- { type: typography, variant: h4, content: @entity.title },
553
- { type: stack, direction: horizontal, gap: sm, children: [
554
- { type: button, action: ADD_POINT, label: @config.addPointLabel, variant: primary },
555
- { type: button, action: REVEAL_FIT, label: @config.revealLabel, variant: secondary },
556
- { type: button, action: TOGGLE_RUN, label: (if @entity.running @config.pauseLabel @config.runLabel), variant: secondary },
557
- { type: button, action: RESET, label: @config.resetLabel, variant: ghost }
661
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
662
+ { type: stack, direction: vertical, gap: xs, children: [
663
+ { type: typography, variant: h4, content: @entity.title },
664
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
665
+ ] },
666
+ { 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"))) }
667
+ ] },
668
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
669
+ { type: button, action: ADD_POINT, label: @config.addPointLabel, icon: "plus", variant: primary, disabled: @entity.done },
670
+ { type: button, action: REVEAL_FIT, label: @config.revealLabel, icon: "eye", variant: secondary },
671
+ (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 }),
672
+ { type: button, action: RESET, label: @config.resetLabel, icon: "rotate-ccw", variant: ghost },
673
+ { type: typography, variant: caption, color: muted, content: (str/concat (str/concat "" (array/len @entity.points)) (str/concat " of " (str/concat "" @config.maxPoints))) }
558
674
  ] },
559
- { type: typography, variant: caption, content: (str/concat @config.guessSlopeCaption (math/round @entity.guessSlope 2)) },
560
- { type: range-slider, min: @config.guessSlopeMin, max: @config.guessSlopeMax, step: @config.guessSlopeStep, value: @entity.guessSlope, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "slope" } },
561
- { type: typography, variant: caption, content: (str/concat @config.guessInterceptCaption (math/round @entity.guessIntercept 1)) },
562
- { type: range-slider, min: @config.guessInterceptMin, max: @config.guessInterceptMax, step: @config.guessInterceptStep, value: @entity.guessIntercept, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "intercept" } },
563
- { type: math-canvas, 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 },
564
- { type: typography, variant: body, content: (if @config.showR (str/concat "r = " (math/round @entity.r 3) " — R² = " (math/round @entity.rSquared 3) " — guess score " @entity.guessScore "%") "") },
675
+ { 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 },
676
+ { type: stack, direction: vertical, gap: sm, children: [
677
+ { type: stack, direction: vertical, gap: xs, children: [
678
+ { type: typography, variant: caption, content: (str/concat @config.guessSlopeCaption (math/round @entity.guessSlope 2)) },
679
+ { type: range-slider, min: @config.guessSlopeMin, max: @config.guessSlopeMax, step: @config.guessSlopeStep, value: @entity.guessSlope, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "slope" } }
680
+ ] },
681
+ { type: stack, direction: vertical, gap: xs, children: [
682
+ { type: typography, variant: caption, content: (str/concat @config.guessInterceptCaption (math/round @entity.guessIntercept 1)) },
683
+ { type: range-slider, min: @config.guessInterceptMin, max: @config.guessInterceptMax, step: @config.guessInterceptStep, value: @entity.guessIntercept, showTooltip: true, action: "GUESS_LINE", actionPayload: { param: "intercept" } }
684
+ ] }
685
+ ] },
686
+ { 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 "%") "") },
565
687
  { type: typography, variant: body, content: @entity.narration }
566
688
  ] }
567
689
  ]
@@ -624,12 +746,16 @@ orbital LearnScatterFitOrbital {
624
746
  @label "Title"
625
747
  @description "Title shown above the canvas."
626
748
  @tier "presentation"
749
+ summary : string = ""
750
+ @label "Concept"
751
+ @description "One line under the title saying what the learner is looking at (keep it under ~65 characters). Empty shows no line."
752
+ @tier "presentation"
627
753
  initialPoints : [LearnScatterFitPoint] = [
628
- { id: "p0", x: 15, y: 25, label: "", color: "#334155", radius: 5 },
629
- { id: "p1", x: 32, y: 40, label: "", color: "#334155", radius: 5 },
630
- { id: "p2", x: 48, y: 44, label: "", color: "#334155", radius: 5 },
631
- { id: "p3", x: 63, y: 62, label: "", color: "#334155", radius: 5 },
632
- { id: "p4", x: 80, y: 70, label: "", color: "#334155", radius: 5 }
754
+ { id: "p0", x: 15, y: 25, label: "", color: "ink", radius: 5 },
755
+ { id: "p1", x: 32, y: 40, label: "", color: "ink", radius: 5 },
756
+ { id: "p2", x: 48, y: 44, label: "", color: "ink", radius: 5 },
757
+ { id: "p3", x: 63, y: 62, label: "", color: "ink", radius: 5 },
758
+ { id: "p4", x: 80, y: 70, label: "", color: "ink", radius: 5 }
633
759
  ]
634
760
  @label "Initial Points"
635
761
  @description "Scatter points the canvas starts with, in axis data coordinates; Reset reseeds from this roster."
@@ -703,23 +829,23 @@ orbital LearnScatterFitOrbital {
703
829
  @label "Fit Curve Label"
704
830
  @description "Legend label for the computed least-squares fit line."
705
831
  @tier "presentation"
706
- fitColor : string = "#2563eb"
832
+ fitColor : string = "series-2"
707
833
  @label "Fit Curve Color"
708
834
  @tier "presentation"
709
835
  guessLabel : string = "your guess"
710
836
  @label "Guess Curve Label"
711
837
  @description "Legend label for the learner's proposed line, shown while guessMode is on and the fit isn't yet revealed."
712
838
  @tier "presentation"
713
- guessColor : string = "#dc2626"
839
+ guessColor : string = "series-3"
714
840
  @label "Guess Curve Color"
715
841
  @tier "presentation"
716
- residualColor : string = "#f59e0b"
842
+ residualColor : string = "guide"
717
843
  @label "Residual Color"
718
844
  @tier "presentation"
719
845
  residualDash : "dashed" | "dotted" = "dashed"
720
846
  @label "Residual Dash Style"
721
847
  @tier "presentation"
722
- newPointColor : string = "#334155"
848
+ newPointColor : string = "ink"
723
849
  @label "New Point Color"
724
850
  @description "Fill color assigned to points created by Add Point or the auto-add tick."
725
851
  @tier "presentation"