@almadar/std 16.239.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 (167) hide show
  1. package/behaviors/behaviors-registry.json +4814 -553
  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-board.lolo +53 -6
  11. package/behaviors/lolo/ui/core/atoms/std-book-reader.lolo +25 -1
  12. package/behaviors/lolo/ui/core/atoms/std-card-grid.lolo +9 -0
  13. package/behaviors/lolo/ui/core/atoms/std-doc-page.lolo +153 -0
  14. package/behaviors/lolo/ui/core/atoms/std-site-header.lolo +15 -3
  15. package/behaviors/lolo/ui/core/atoms/std-tag-strip.lolo +2 -2
  16. package/behaviors/lolo/ui/core/atoms/std-tag-taxonomy.lolo +7 -7
  17. package/behaviors/lolo/ui/core/atoms/std-version-history.lolo +1 -1
  18. package/behaviors/lolo/ui/core/molecules/ui-header.lolo +5 -0
  19. package/behaviors/lolo/ui/learning/atoms/std-learn-arrangement.lolo +124 -92
  20. package/behaviors/lolo/ui/learning/atoms/std-learn-classify.lolo +114 -55
  21. package/behaviors/lolo/ui/learning/atoms/std-learn-compare.lolo +40 -14
  22. package/behaviors/lolo/ui/learning/atoms/std-learn-coupled-sim.lolo +363 -123
  23. package/behaviors/lolo/ui/learning/atoms/std-learn-derivation.lolo +93 -48
  24. package/behaviors/lolo/ui/learning/atoms/std-learn-diagram.lolo +60 -28
  25. package/behaviors/lolo/ui/learning/atoms/std-learn-doser.lolo +193 -96
  26. package/behaviors/lolo/ui/learning/atoms/std-learn-estimate.lolo +75 -32
  27. package/behaviors/lolo/ui/learning/atoms/std-learn-goal-seek.lolo +142 -86
  28. package/behaviors/lolo/ui/learning/atoms/std-learn-grid-sim.lolo +266 -98
  29. package/behaviors/lolo/ui/learning/atoms/std-learn-hotspot.lolo +103 -65
  30. package/behaviors/lolo/ui/learning/atoms/std-learn-live-sim.lolo +223 -109
  31. package/behaviors/lolo/ui/learning/atoms/std-learn-measure.lolo +232 -64
  32. package/behaviors/lolo/ui/learning/atoms/std-learn-param-explorer.lolo +69 -29
  33. package/behaviors/lolo/ui/learning/atoms/std-learn-perturb.lolo +363 -123
  34. package/behaviors/lolo/ui/learning/atoms/std-learn-predict.lolo +73 -41
  35. package/behaviors/lolo/ui/learning/atoms/std-learn-sample-accumulator.lolo +96 -38
  36. package/behaviors/lolo/ui/learning/atoms/std-learn-sandbox.lolo +65 -45
  37. package/behaviors/lolo/ui/learning/atoms/std-learn-scatter-fit.lolo +243 -117
  38. package/behaviors/lolo/ui/learning/atoms/std-learn-scenario.lolo +76 -28
  39. package/behaviors/lolo/ui/learning/atoms/std-learn-sim-3d.lolo +228 -109
  40. package/behaviors/lolo/ui/learning/atoms/std-learn-speed-drill.lolo +95 -44
  41. package/behaviors/lolo/ui/learning/atoms/std-learn-stepper.lolo +199 -125
  42. package/behaviors/lolo/ui/learning/atoms/std-learn-tour-3d.lolo +92 -48
  43. package/behaviors/lolo/ui/learning/atoms/std-learn-trace-player.lolo +239 -78
  44. package/behaviors/lolo/ui/learning/atoms/std-learn-transport.lolo +147 -38
  45. package/behaviors/lolo/ui/learning/atoms/std-learn-tree.lolo +123 -58
  46. package/behaviors/lolo/ui/learning/atoms/ui-algo-graph-canvas.lolo +22 -0
  47. package/behaviors/lolo/ui/learning/atoms/ui-algorithm-canvas.lolo +26 -0
  48. package/behaviors/lolo/ui/learning/atoms/ui-biology-canvas.lolo +26 -0
  49. package/behaviors/lolo/ui/learning/atoms/ui-chemistry-canvas.lolo +27 -1
  50. package/behaviors/lolo/ui/learning/atoms/ui-learning-canvas.lolo +27 -1
  51. package/behaviors/lolo/ui/learning/atoms/ui-math-canvas.lolo +29 -9
  52. package/behaviors/lolo/ui/learning/atoms/ui-physics-canvas.lolo +26 -0
  53. package/behaviors/lolo-behavior-contracts.json +1 -1
  54. package/behaviors/registry/agent/atoms/std-agent-memory.orb +372 -2
  55. package/behaviors/registry/agent/atoms/std-agent-session.orb +4752 -348
  56. package/behaviors/registry/agent/atoms/std-agent-tool-loop.orb +54 -42
  57. package/behaviors/registry/agent/organisms/std-agent-assistant.orb +356 -122
  58. package/behaviors/registry/factory-signatures.json +1 -1
  59. package/behaviors/registry/infra/atoms/std-page-open.orb +435 -0
  60. package/behaviors/registry/infra/atoms/std-page-search.orb +867 -0
  61. package/behaviors/registry/infra/atoms/std-page-treat.orb +494 -0
  62. package/behaviors/registry/infra/atoms/std-page-watch.orb +554 -0
  63. package/behaviors/registry/ui/core/atoms/std-board.orb +110 -14
  64. package/behaviors/registry/ui/core/atoms/std-book-reader.orb +119 -0
  65. package/behaviors/registry/ui/core/atoms/std-card-grid.orb +61 -0
  66. package/behaviors/registry/ui/core/atoms/std-doc-page.orb +594 -0
  67. package/behaviors/registry/ui/core/atoms/std-site-header.orb +40 -2
  68. package/behaviors/registry/ui/core/atoms/std-tag-strip.orb +2 -0
  69. package/behaviors/registry/ui/core/atoms/std-tag-taxonomy.orb +24 -0
  70. package/behaviors/registry/ui/core/atoms/std-version-history.orb +8 -1
  71. package/behaviors/registry/ui/core/molecules/ui-header.orb +7 -0
  72. package/behaviors/registry/ui/learning/atoms/std-learn-arrangement.orb +903 -369
  73. package/behaviors/registry/ui/learning/atoms/std-learn-classify.orb +1002 -232
  74. package/behaviors/registry/ui/learning/atoms/std-learn-compare.orb +253 -74
  75. package/behaviors/registry/ui/learning/atoms/std-learn-coupled-sim.orb +3624 -921
  76. package/behaviors/registry/ui/learning/atoms/std-learn-derivation.orb +685 -144
  77. package/behaviors/registry/ui/learning/atoms/std-learn-diagram.orb +404 -52
  78. package/behaviors/registry/ui/learning/atoms/std-learn-doser.orb +1787 -210
  79. package/behaviors/registry/ui/learning/atoms/std-learn-estimate.orb +699 -71
  80. package/behaviors/registry/ui/learning/atoms/std-learn-goal-seek.orb +1102 -578
  81. package/behaviors/registry/ui/learning/atoms/std-learn-grid-sim.orb +2760 -872
  82. package/behaviors/registry/ui/learning/atoms/std-learn-hotspot.orb +689 -152
  83. package/behaviors/registry/ui/learning/atoms/std-learn-live-sim.orb +1431 -633
  84. package/behaviors/registry/ui/learning/atoms/std-learn-measure.orb +2485 -512
  85. package/behaviors/registry/ui/learning/atoms/std-learn-param-explorer.orb +501 -197
  86. package/behaviors/registry/ui/learning/atoms/std-learn-perturb.orb +3642 -928
  87. package/behaviors/registry/ui/learning/atoms/std-learn-predict.orb +705 -125
  88. package/behaviors/registry/ui/learning/atoms/std-learn-sample-accumulator.orb +624 -114
  89. package/behaviors/registry/ui/learning/atoms/std-learn-sandbox.orb +405 -153
  90. package/behaviors/registry/ui/learning/atoms/std-learn-scatter-fit.orb +1911 -611
  91. package/behaviors/registry/ui/learning/atoms/std-learn-scenario.orb +436 -128
  92. package/behaviors/registry/ui/learning/atoms/std-learn-sim-3d.orb +2482 -485
  93. package/behaviors/registry/ui/learning/atoms/std-learn-speed-drill.orb +896 -192
  94. package/behaviors/registry/ui/learning/atoms/std-learn-stepper.orb +2001 -759
  95. package/behaviors/registry/ui/learning/atoms/std-learn-tour-3d.orb +734 -228
  96. package/behaviors/registry/ui/learning/atoms/std-learn-trace-player.orb +2501 -764
  97. package/behaviors/registry/ui/learning/atoms/std-learn-transport.orb +1591 -173
  98. package/behaviors/registry/ui/learning/atoms/std-learn-tree.orb +883 -122
  99. package/behaviors/registry/ui/learning/atoms/ui-algo-graph-canvas.orb +176 -0
  100. package/behaviors/registry/ui/learning/atoms/ui-algorithm-canvas.orb +211 -0
  101. package/behaviors/registry/ui/learning/atoms/ui-biology-canvas.orb +211 -0
  102. package/behaviors/registry/ui/learning/atoms/ui-chemistry-canvas.orb +212 -1
  103. package/behaviors/registry/ui/learning/atoms/ui-learning-canvas.orb +212 -1
  104. package/behaviors/registry/ui/learning/atoms/ui-math-canvas.orb +203 -9
  105. package/behaviors/registry/ui/learning/atoms/ui-physics-canvas.orb +211 -0
  106. package/behaviors/signatures.lolo +325 -655
  107. package/canonical-operators.json +35 -1
  108. package/dist/behaviors/exports-reader.js +41980 -35508
  109. package/dist/behaviors/functions/index.d.ts +1063 -140
  110. package/dist/behaviors/functions/index.js +41951 -35506
  111. package/dist/behaviors/index.d.ts +1 -1
  112. package/dist/behaviors/index.js +41981 -35509
  113. package/dist/behaviors/query.js +41980 -35508
  114. package/dist/behaviors-embeddings.hash.json +3 -3
  115. package/dist/behaviors-embeddings.json +47 -27
  116. package/dist/behaviors-registry.json +4814 -553
  117. package/dist/index.d.ts +4 -4
  118. package/dist/index.js +42019 -35509
  119. package/dist/knob-embeddings.hash.json +3 -3
  120. package/dist/knob-embeddings.json +623 -263
  121. package/dist/modules/anim.d.ts +1 -1
  122. package/dist/modules/array.d.ts +1 -1
  123. package/dist/modules/async.d.ts +1 -1
  124. package/dist/modules/behavior.d.ts +1 -1
  125. package/dist/modules/browser.d.ts +1 -1
  126. package/dist/modules/composition.d.ts +1 -1
  127. package/dist/modules/contract.d.ts +1 -1
  128. package/dist/modules/core.d.ts +1 -1
  129. package/dist/modules/core.js +2 -0
  130. package/dist/modules/data.d.ts +1 -1
  131. package/dist/modules/ease.d.ts +1 -1
  132. package/dist/modules/format.d.ts +1 -1
  133. package/dist/modules/geo.d.ts +1 -1
  134. package/dist/modules/graph.d.ts +1 -1
  135. package/dist/modules/grid.d.ts +1 -1
  136. package/dist/modules/i18n.d.ts +17 -0
  137. package/dist/modules/i18n.js +22 -0
  138. package/dist/modules/index.d.ts +2 -1
  139. package/dist/modules/index.js +24 -1
  140. package/dist/modules/integration.d.ts +1 -1
  141. package/dist/modules/json.d.ts +1 -1
  142. package/dist/modules/llm.d.ts +1 -1
  143. package/dist/modules/math.d.ts +1 -1
  144. package/dist/modules/memory.d.ts +1 -1
  145. package/dist/modules/nn.d.ts +1 -1
  146. package/dist/modules/noise.d.ts +1 -1
  147. package/dist/modules/object.d.ts +1 -1
  148. package/dist/modules/os.d.ts +1 -1
  149. package/dist/modules/path.d.ts +1 -1
  150. package/dist/modules/prob.d.ts +1 -1
  151. package/dist/modules/session.d.ts +1 -1
  152. package/dist/modules/str.d.ts +1 -1
  153. package/dist/modules/tensor.d.ts +1 -1
  154. package/dist/modules/time.d.ts +1 -1
  155. package/dist/modules/trace.d.ts +1 -1
  156. package/dist/modules/train.d.ts +1 -1
  157. package/dist/modules/validate.d.ts +1 -1
  158. package/dist/modules/vector.d.ts +1 -1
  159. package/dist/modules/workspace.d.ts +1 -1
  160. package/dist/registry/factory-signatures.json +1 -1
  161. package/dist/registry.d.ts +10 -3
  162. package/dist/registry.js +31 -1
  163. package/dist/{types-DLx38UFZ.d.ts → types-Cdb321uM.d.ts} +9 -3
  164. package/i18n/ar.json +1 -0
  165. package/i18n/en.json +1 -0
  166. package/i18n/sl.json +1 -0
  167. package/package.json +3 -3
@@ -59,12 +59,12 @@ orbital EstimateOrbital {
59
59
  { type: typography, variant: caption, content: (str/concat "Your estimate: " (math/round @entity.estimate 2) " " @entity.unit) },
60
60
  { type: range-slider, min: @config.sliderMin, max: @config.sliderMax, step: @config.sliderStep, value: @entity.estimate, showTooltip: true, action: "SET_ESTIMATE" }
61
61
  ] },
62
- { type: stack, direction: horizontal, gap: sm, children: [
63
- { type: button, action: LOCK_IN, label: @config.lockLabel, variant: primary, disabled: (if @entity.locked true false) },
64
- { type: button, action: NEXT, label: @config.nextLabel, variant: secondary, disabled: (if @entity.locked false true) }
62
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
63
+ { type: button, action: LOCK_IN, label: @config.lockLabel, icon: "check", variant: primary, disabled: (if @entity.locked true false) },
64
+ { type: button, action: NEXT, label: @config.nextLabel, icon: "chevron-right", variant: secondary, disabled: (if @entity.locked false true) }
65
65
  ] },
66
66
  { type: stack, direction: horizontal, gap: xs, children: [
67
- { type: typography, variant: caption, content: @entity.feedback }
67
+ { type: typography, variant: body, content: @entity.feedback }
68
68
  ] },
69
69
  { type: stat-display, label: "Score", value: @entity.score, max: (* @entity.totalPrompts @config.exactPoints) }
70
70
  ])))
@@ -73,13 +73,23 @@ orbital EstimateOrbital {
73
73
  padding: md
74
74
  children: [
75
75
  { type: stack, direction: vertical, gap: md, children: [
76
- { type: typography, variant: h4, content: @entity.title },
76
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
77
+ { type: stack, direction: vertical, gap: xs, children: [
78
+ { type: typography, variant: h4, content: @entity.title },
79
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
80
+ ] },
81
+ { type: badge, label: (if @entity.done "Complete" (if (== @entity.band "exact") "Spot on" (if (== @entity.band "close") "Close" (if (== @entity.band "off") "Off" "Estimating")))), variant: (if @entity.done "success" (if (== @entity.band "exact") "success" (if (== @entity.band "close") "warning" (if (== @entity.band "off") "danger" "neutral")))) }
82
+ ] },
77
83
  { type: progress-bar, value: (+ @entity.promptIndex 1), max: @entity.totalPrompts, showPercentage: false, label: (str/concat "Prompt " (str/concat "" (+ @entity.promptIndex 1)) " of " (str/concat "" @entity.totalPrompts)) },
78
84
  { type: stack, direction: vertical, gap: md, children: @entity.view }
79
85
  ] }
80
86
  ]
81
87
  })
82
88
 
89
+ MODE_SELECTED -> idle when (and (not (== @config.matchMode "")) (not (== ?mode @config.matchMode)))
90
+ (set @entity.active false)
91
+ (render-ui main null)
92
+
83
93
  MODE_SELECTED -> idle when (== ?mode @config.matchMode)
84
94
  (let (
85
95
  (first (array/nth @config.prompts 0))
@@ -108,12 +118,12 @@ orbital EstimateOrbital {
108
118
  { type: typography, variant: caption, content: (str/concat "Your estimate: " (math/round @entity.estimate 2) " " @entity.unit) },
109
119
  { type: range-slider, min: @config.sliderMin, max: @config.sliderMax, step: @config.sliderStep, value: @entity.estimate, showTooltip: true, action: "SET_ESTIMATE" }
110
120
  ] },
111
- { type: stack, direction: horizontal, gap: sm, children: [
112
- { type: button, action: LOCK_IN, label: @config.lockLabel, variant: primary, disabled: (if @entity.locked true false) },
113
- { type: button, action: NEXT, label: @config.nextLabel, variant: secondary, disabled: (if @entity.locked false true) }
121
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
122
+ { type: button, action: LOCK_IN, label: @config.lockLabel, icon: "check", variant: primary, disabled: (if @entity.locked true false) },
123
+ { type: button, action: NEXT, label: @config.nextLabel, icon: "chevron-right", variant: secondary, disabled: (if @entity.locked false true) }
114
124
  ] },
115
125
  { type: stack, direction: horizontal, gap: xs, children: [
116
- { type: typography, variant: caption, content: @entity.feedback }
126
+ { type: typography, variant: body, content: @entity.feedback }
117
127
  ] },
118
128
  { type: stat-display, label: "Score", value: @entity.score, max: (* @entity.totalPrompts @config.exactPoints) }
119
129
  ])))
@@ -122,7 +132,13 @@ orbital EstimateOrbital {
122
132
  padding: md
123
133
  children: [
124
134
  { type: stack, direction: vertical, gap: md, children: [
125
- { type: typography, variant: h4, content: @entity.title },
135
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
136
+ { type: stack, direction: vertical, gap: xs, children: [
137
+ { type: typography, variant: h4, content: @entity.title },
138
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
139
+ ] },
140
+ { type: badge, label: (if @entity.done "Complete" (if (== @entity.band "exact") "Spot on" (if (== @entity.band "close") "Close" (if (== @entity.band "off") "Off" "Estimating")))), variant: (if @entity.done "success" (if (== @entity.band "exact") "success" (if (== @entity.band "close") "warning" (if (== @entity.band "off") "danger" "neutral")))) }
141
+ ] },
126
142
  { type: progress-bar, value: (+ @entity.promptIndex 1), max: @entity.totalPrompts, showPercentage: false, label: (str/concat "Prompt " (str/concat "" (+ @entity.promptIndex 1)) " of " (str/concat "" @entity.totalPrompts)) },
127
143
  { type: stack, direction: vertical, gap: md, children: @entity.view }
128
144
  ] }
@@ -140,12 +156,12 @@ orbital EstimateOrbital {
140
156
  { type: typography, variant: caption, content: (str/concat "Your estimate: " (math/round @entity.estimate 2) " " @entity.unit) },
141
157
  { type: range-slider, min: @config.sliderMin, max: @config.sliderMax, step: @config.sliderStep, value: @entity.estimate, showTooltip: true, action: "SET_ESTIMATE" }
142
158
  ] },
143
- { type: stack, direction: horizontal, gap: sm, children: [
144
- { type: button, action: LOCK_IN, label: @config.lockLabel, variant: primary, disabled: (if @entity.locked true false) },
145
- { type: button, action: NEXT, label: @config.nextLabel, variant: secondary, disabled: (if @entity.locked false true) }
159
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
160
+ { type: button, action: LOCK_IN, label: @config.lockLabel, icon: "check", variant: primary, disabled: (if @entity.locked true false) },
161
+ { type: button, action: NEXT, label: @config.nextLabel, icon: "chevron-right", variant: secondary, disabled: (if @entity.locked false true) }
146
162
  ] },
147
163
  { type: stack, direction: horizontal, gap: xs, children: [
148
- { type: typography, variant: caption, content: @entity.feedback }
164
+ { type: typography, variant: body, content: @entity.feedback }
149
165
  ] },
150
166
  { type: stat-display, label: "Score", value: @entity.score, max: (* @entity.totalPrompts @config.exactPoints) }
151
167
  ])
@@ -154,7 +170,13 @@ orbital EstimateOrbital {
154
170
  padding: md
155
171
  children: [
156
172
  { type: stack, direction: vertical, gap: md, children: [
157
- { type: typography, variant: h4, content: @entity.title },
173
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
174
+ { type: stack, direction: vertical, gap: xs, children: [
175
+ { type: typography, variant: h4, content: @entity.title },
176
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
177
+ ] },
178
+ { type: badge, label: (if @entity.done "Complete" (if (== @entity.band "exact") "Spot on" (if (== @entity.band "close") "Close" (if (== @entity.band "off") "Off" "Estimating")))), variant: (if @entity.done "success" (if (== @entity.band "exact") "success" (if (== @entity.band "close") "warning" (if (== @entity.band "off") "danger" "neutral")))) }
179
+ ] },
158
180
  { type: progress-bar, value: (+ @entity.promptIndex 1), max: @entity.totalPrompts, showPercentage: false, label: (str/concat "Prompt " (str/concat "" (+ @entity.promptIndex 1)) " of " (str/concat "" @entity.totalPrompts)) },
159
181
  { type: stack, direction: vertical, gap: md, children: @entity.view }
160
182
  ] }
@@ -182,13 +204,12 @@ orbital EstimateOrbital {
182
204
  { type: typography, variant: caption, content: (str/concat "Your estimate: " (math/round @entity.estimate 2) " " @entity.unit) },
183
205
  { type: range-slider, min: @config.sliderMin, max: @config.sliderMax, step: @config.sliderStep, value: @entity.estimate, showTooltip: true, action: "SET_ESTIMATE" }
184
206
  ] },
185
- { type: stack, direction: horizontal, gap: sm, children: [
186
- { type: button, action: LOCK_IN, label: @config.lockLabel, variant: primary, disabled: (if @entity.locked true false) },
187
- { type: button, action: NEXT, label: @config.nextLabel, variant: secondary, disabled: (if @entity.locked false true) }
207
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
208
+ { type: button, action: LOCK_IN, label: @config.lockLabel, icon: "check", variant: primary, disabled: (if @entity.locked true false) },
209
+ { type: button, action: NEXT, label: @config.nextLabel, icon: "chevron-right", variant: secondary, disabled: (if @entity.locked false true) }
188
210
  ] },
189
211
  { type: stack, direction: horizontal, gap: xs, children: [
190
- { type: badge, variant: (if (== @entity.band "exact") "success" (if (== @entity.band "close") "warning" "danger")), label: (if (== @entity.band "exact") "Spot on" (if (== @entity.band "close") "Close" "Off")) },
191
- { type: typography, variant: caption, content: @entity.feedback }
212
+ { type: typography, variant: body, content: @entity.feedback }
192
213
  ] },
193
214
  { type: stat-display, label: "Score", value: @entity.score, max: (* @entity.totalPrompts @config.exactPoints) }
194
215
  ])))
@@ -197,7 +218,13 @@ orbital EstimateOrbital {
197
218
  padding: md
198
219
  children: [
199
220
  { type: stack, direction: vertical, gap: md, children: [
200
- { type: typography, variant: h4, content: @entity.title },
221
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
222
+ { type: stack, direction: vertical, gap: xs, children: [
223
+ { type: typography, variant: h4, content: @entity.title },
224
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
225
+ ] },
226
+ { type: badge, label: (if @entity.done "Complete" (if (== @entity.band "exact") "Spot on" (if (== @entity.band "close") "Close" (if (== @entity.band "off") "Off" "Estimating")))), variant: (if @entity.done "success" (if (== @entity.band "exact") "success" (if (== @entity.band "close") "warning" (if (== @entity.band "off") "danger" "neutral")))) }
227
+ ] },
201
228
  { type: progress-bar, value: (+ @entity.promptIndex 1), max: @entity.totalPrompts, showPercentage: false, label: (str/concat "Prompt " (str/concat "" (+ @entity.promptIndex 1)) " of " (str/concat "" @entity.totalPrompts)) },
202
229
  { type: stack, direction: vertical, gap: md, children: @entity.view }
203
230
  ] }
@@ -227,7 +254,7 @@ orbital EstimateOrbital {
227
254
  [
228
255
  { type: typography, variant: h4, content: "Round Complete" },
229
256
  { type: stat-display, label: "Final score", value: @entity.score, max: (* @entity.totalPrompts @config.exactPoints) },
230
- { type: button, action: RETRY, label: @config.retryLabel, variant: primary }
257
+ { type: button, action: RETRY, label: @config.retryLabel, icon: "rotate-ccw", variant: primary }
231
258
  ]
232
259
  [
233
260
  { type: card, variant: bordered, padding: md, children: [
@@ -238,12 +265,12 @@ orbital EstimateOrbital {
238
265
  { type: typography, variant: caption, content: (str/concat "Your estimate: " (math/round @entity.estimate 2) " " @entity.unit) },
239
266
  { type: range-slider, min: @config.sliderMin, max: @config.sliderMax, step: @config.sliderStep, value: @entity.estimate, showTooltip: true, action: "SET_ESTIMATE" }
240
267
  ] },
241
- { type: stack, direction: horizontal, gap: sm, children: [
242
- { type: button, action: LOCK_IN, label: @config.lockLabel, variant: primary, disabled: (if @entity.locked true false) },
243
- { type: button, action: NEXT, label: @config.nextLabel, variant: secondary, disabled: (if @entity.locked false true) }
268
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
269
+ { type: button, action: LOCK_IN, label: @config.lockLabel, icon: "check", variant: primary, disabled: (if @entity.locked true false) },
270
+ { type: button, action: NEXT, label: @config.nextLabel, icon: "chevron-right", variant: secondary, disabled: (if @entity.locked false true) }
244
271
  ] },
245
272
  { type: stack, direction: horizontal, gap: xs, children: [
246
- { type: typography, variant: caption, content: @entity.feedback }
273
+ { type: typography, variant: body, content: @entity.feedback }
247
274
  ] },
248
275
  { type: stat-display, label: "Score", value: @entity.score, max: (* @entity.totalPrompts @config.exactPoints) }
249
276
  ])))
@@ -253,7 +280,13 @@ orbital EstimateOrbital {
253
280
  padding: md
254
281
  children: [
255
282
  { type: stack, direction: vertical, gap: md, children: [
256
- { type: typography, variant: h4, content: @entity.title },
283
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
284
+ { type: stack, direction: vertical, gap: xs, children: [
285
+ { type: typography, variant: h4, content: @entity.title },
286
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
287
+ ] },
288
+ { type: badge, label: (if @entity.done "Complete" (if (== @entity.band "exact") "Spot on" (if (== @entity.band "close") "Close" (if (== @entity.band "off") "Off" "Estimating")))), variant: (if @entity.done "success" (if (== @entity.band "exact") "success" (if (== @entity.band "close") "warning" (if (== @entity.band "off") "danger" "neutral")))) }
289
+ ] },
257
290
  { type: progress-bar, value: (+ @entity.promptIndex 1), max: @entity.totalPrompts, showPercentage: false, label: (str/concat "Prompt " (str/concat "" (+ @entity.promptIndex 1)) " of " (str/concat "" @entity.totalPrompts)) },
258
291
  { type: stack, direction: vertical, gap: md, children: @entity.view }
259
292
  ] }
@@ -286,12 +319,12 @@ orbital EstimateOrbital {
286
319
  { type: typography, variant: caption, content: (str/concat "Your estimate: " (math/round @entity.estimate 2) " " @entity.unit) },
287
320
  { type: range-slider, min: @config.sliderMin, max: @config.sliderMax, step: @config.sliderStep, value: @entity.estimate, showTooltip: true, action: "SET_ESTIMATE" }
288
321
  ] },
289
- { type: stack, direction: horizontal, gap: sm, children: [
290
- { type: button, action: LOCK_IN, label: @config.lockLabel, variant: primary, disabled: (if @entity.locked true false) },
291
- { type: button, action: NEXT, label: @config.nextLabel, variant: secondary, disabled: (if @entity.locked false true) }
322
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
323
+ { type: button, action: LOCK_IN, label: @config.lockLabel, icon: "check", variant: primary, disabled: (if @entity.locked true false) },
324
+ { type: button, action: NEXT, label: @config.nextLabel, icon: "chevron-right", variant: secondary, disabled: (if @entity.locked false true) }
292
325
  ] },
293
326
  { type: stack, direction: horizontal, gap: xs, children: [
294
- { type: typography, variant: caption, content: @entity.feedback }
327
+ { type: typography, variant: body, content: @entity.feedback }
295
328
  ] },
296
329
  { type: stat-display, label: "Score", value: @entity.score, max: (* @entity.totalPrompts @config.exactPoints) }
297
330
  ])))
@@ -300,7 +333,13 @@ orbital EstimateOrbital {
300
333
  padding: md
301
334
  children: [
302
335
  { type: stack, direction: vertical, gap: md, children: [
303
- { type: typography, variant: h4, content: @entity.title },
336
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
337
+ { type: stack, direction: vertical, gap: xs, children: [
338
+ { type: typography, variant: h4, content: @entity.title },
339
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
340
+ ] },
341
+ { type: badge, label: (if @entity.done "Complete" (if (== @entity.band "exact") "Spot on" (if (== @entity.band "close") "Close" (if (== @entity.band "off") "Off" "Estimating")))), variant: (if @entity.done "success" (if (== @entity.band "exact") "success" (if (== @entity.band "close") "warning" (if (== @entity.band "off") "danger" "neutral")))) }
342
+ ] },
304
343
  { type: progress-bar, value: (+ @entity.promptIndex 1), max: @entity.totalPrompts, showPercentage: false, label: (str/concat "Prompt " (str/concat "" (+ @entity.promptIndex 1)) " of " (str/concat "" @entity.totalPrompts)) },
305
344
  { type: stack, direction: vertical, gap: md, children: @entity.view }
306
345
  ] }
@@ -374,6 +413,10 @@ orbital EstimateOrbital {
374
413
  @label "Title"
375
414
  @description "Title shown above the drill."
376
415
  @tier "presentation"
416
+ summary : string = ""
417
+ @label "Concept"
418
+ @description "One line under the title saying what the learner is looking at (keep it under ~65 characters). Empty shows no line."
419
+ @tier "presentation"
377
420
  prompts : [EstimatePrompt] = [
378
421
  { prompt: "How many meters does light travel in one microsecond?", answer: 300, unit: "m", hint: "Light covers 300,000 km every second." },
379
422
  { prompt: "What is the boiling point of water at sea level, in Fahrenheit?", answer: 212, unit: "°F", hint: "It is 100 °C." },
@@ -98,27 +98,39 @@ orbital GoalSeekOrbital {
98
98
  padding: md
99
99
  children: [
100
100
  { type: stack, direction: vertical, gap: md, children: [
101
- { type: typography, variant: h4, content: @entity.title },
102
- { type: typography, variant: body, content: @config.goalText },
103
- { type: stack, direction: vertical, gap: xs, children: [
104
- { type: typography, variant: caption, content: (str/concat @entity.paramALabel ": " (math/round @entity.paramA 2)) },
105
- { type: range-slider, min: @config.paramAMin, max: @config.paramAMax, step: @config.paramAStep, value: @entity.paramA, showTooltip: true, action: "SET_PARAM_A" }
101
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
102
+ { type: stack, direction: vertical, gap: xs, children: [
103
+ { type: typography, variant: h4, content: @entity.title },
104
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
105
+ ] },
106
+ { type: badge, label: (if @entity.solved "Solved" (if (> @entity.attempts 0) "Try again" "Tuning")), variant: (if @entity.solved "success" (if (> @entity.attempts 0) "warning" "neutral")) }
106
107
  ] },
107
- { type: stack, direction: vertical, gap: xs, children: [
108
- { type: typography, variant: caption, content: (str/concat @entity.paramBLabel ": " (math/round @entity.paramB 2)) },
109
- { type: range-slider, min: @config.paramBMin, max: @config.paramBMax, step: @config.paramBStep, value: @entity.paramB, showTooltip: true, action: "SET_PARAM_B" }
108
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
109
+ { type: button, action: CHECK, label: @config.checkLabel, icon: "check", variant: primary, disabled: (if @entity.solved true false) },
110
+ { type: button, action: RESET, label: "Reset", icon: "rotate-ccw", variant: ghost },
111
+ { type: typography, variant: caption, color: muted, content: (if @config.showLiveDistance (str/concat "Distance from target: " (math/round @entity.distance 3) " · attempts: " (str/concat "" @entity.attempts)) (str/concat "Attempts: " (str/concat "" @entity.attempts))) }
110
112
  ] },
111
- { type: math-canvas, width: @config.width, height: @config.height, title: "", xMin: @config.xMin, xMax: @config.xMax, yMin: @entity.yMin, yMax: @entity.yMax, showAxes: @config.showAxes, showGrid: @config.showGrid, gridStep: @config.gridStep, curves: @entity.curves, points: [], vectors: [], shapes: [], interactive: false, animate: false },
112
- { type: typography, variant: body, content: (if @config.showLiveDistance (str/concat "Distance from target: " (math/round @entity.distance 3) " · attempts: " (str/concat "" @entity.attempts)) (str/concat "Attempts: " (str/concat "" @entity.attempts))) },
113
- { type: stack, direction: horizontal, gap: sm, children: [
114
- { type: button, action: CHECK, label: @config.checkLabel, variant: primary, disabled: (if @entity.solved true false) },
115
- { type: button, action: RESET, label: "Reset", variant: ghost }
113
+ { type: math-canvas, keyMap: { Space: CHECK, KeyR: RESET }, width: @config.width, height: @config.height, title: "", xMin: @config.xMin, xMax: @config.xMax, yMin: @entity.yMin, yMax: @entity.yMax, showAxes: @config.showAxes, showGrid: @config.showGrid, gridStep: @config.gridStep, curves: @entity.curves, points: [], vectors: [], shapes: [], interactive: false, animate: false },
114
+ { type: stack, direction: vertical, gap: sm, children: [
115
+ { type: stack, direction: vertical, gap: xs, children: [
116
+ { type: typography, variant: caption, content: (str/concat @entity.paramALabel ": " (math/round @entity.paramA 2)) },
117
+ { type: range-slider, min: @config.paramAMin, max: @config.paramAMax, step: @config.paramAStep, value: @entity.paramA, showTooltip: true, action: "SET_PARAM_A" }
118
+ ] },
119
+ { type: stack, direction: vertical, gap: xs, children: [
120
+ { type: typography, variant: caption, content: (str/concat @entity.paramBLabel ": " (math/round @entity.paramB 2)) },
121
+ { type: range-slider, min: @config.paramBMin, max: @config.paramBMax, step: @config.paramBStep, value: @entity.paramB, showTooltip: true, action: "SET_PARAM_B" }
122
+ ] }
116
123
  ] },
117
- { type: stack, direction: horizontal, gap: xs, children: @entity.resultRow }
124
+ { type: typography, variant: body, content: @config.goalText },
125
+ { type: typography, variant: caption, color: muted, content: @entity.feedback }
118
126
  ] }
119
127
  ]
120
128
  })
121
129
 
130
+ MODE_SELECTED -> idle when (and (not (== @config.matchMode "")) (not (== ?mode @config.matchMode)))
131
+ (set @entity.active false)
132
+ (render-ui main null)
133
+
122
134
  MODE_SELECTED -> idle when (== ?mode @config.matchMode)
123
135
  (let (
124
136
  (kind @config.curveKind)
@@ -182,23 +194,31 @@ orbital GoalSeekOrbital {
182
194
  padding: md
183
195
  children: [
184
196
  { type: stack, direction: vertical, gap: md, children: [
185
- { type: typography, variant: h4, content: @entity.title },
186
- { type: typography, variant: body, content: @config.goalText },
187
- { type: stack, direction: vertical, gap: xs, children: [
188
- { type: typography, variant: caption, content: (str/concat @entity.paramALabel ": " (math/round @entity.paramA 2)) },
189
- { type: range-slider, min: @config.paramAMin, max: @config.paramAMax, step: @config.paramAStep, value: @entity.paramA, showTooltip: true, action: "SET_PARAM_A" }
197
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
198
+ { type: stack, direction: vertical, gap: xs, children: [
199
+ { type: typography, variant: h4, content: @entity.title },
200
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
201
+ ] },
202
+ { type: badge, label: (if @entity.solved "Solved" (if (> @entity.attempts 0) "Try again" "Tuning")), variant: (if @entity.solved "success" (if (> @entity.attempts 0) "warning" "neutral")) }
190
203
  ] },
191
- { type: stack, direction: vertical, gap: xs, children: [
192
- { type: typography, variant: caption, content: (str/concat @entity.paramBLabel ": " (math/round @entity.paramB 2)) },
193
- { type: range-slider, min: @config.paramBMin, max: @config.paramBMax, step: @config.paramBStep, value: @entity.paramB, showTooltip: true, action: "SET_PARAM_B" }
204
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
205
+ { type: button, action: CHECK, label: @config.checkLabel, icon: "check", variant: primary, disabled: (if @entity.solved true false) },
206
+ { type: button, action: RESET, label: "Reset", icon: "rotate-ccw", variant: ghost },
207
+ { type: typography, variant: caption, color: muted, content: (if @config.showLiveDistance (str/concat "Distance from target: " (math/round @entity.distance 3) " · attempts: " (str/concat "" @entity.attempts)) (str/concat "Attempts: " (str/concat "" @entity.attempts))) }
194
208
  ] },
195
- { type: math-canvas, width: @config.width, height: @config.height, title: "", xMin: @config.xMin, xMax: @config.xMax, yMin: @entity.yMin, yMax: @entity.yMax, showAxes: @config.showAxes, showGrid: @config.showGrid, gridStep: @config.gridStep, curves: @entity.curves, points: [], vectors: [], shapes: [], interactive: false, animate: false },
196
- { type: typography, variant: body, content: (if @config.showLiveDistance (str/concat "Distance from target: " (math/round @entity.distance 3) " · attempts: " (str/concat "" @entity.attempts)) (str/concat "Attempts: " (str/concat "" @entity.attempts))) },
197
- { type: stack, direction: horizontal, gap: sm, children: [
198
- { type: button, action: CHECK, label: @config.checkLabel, variant: primary, disabled: (if @entity.solved true false) },
199
- { type: button, action: RESET, label: "Reset", variant: ghost }
209
+ { type: math-canvas, keyMap: { Space: CHECK, KeyR: RESET }, width: @config.width, height: @config.height, title: "", xMin: @config.xMin, xMax: @config.xMax, yMin: @entity.yMin, yMax: @entity.yMax, showAxes: @config.showAxes, showGrid: @config.showGrid, gridStep: @config.gridStep, curves: @entity.curves, points: [], vectors: [], shapes: [], interactive: false, animate: false },
210
+ { type: stack, direction: vertical, gap: sm, children: [
211
+ { type: stack, direction: vertical, gap: xs, children: [
212
+ { type: typography, variant: caption, content: (str/concat @entity.paramALabel ": " (math/round @entity.paramA 2)) },
213
+ { type: range-slider, min: @config.paramAMin, max: @config.paramAMax, step: @config.paramAStep, value: @entity.paramA, showTooltip: true, action: "SET_PARAM_A" }
214
+ ] },
215
+ { type: stack, direction: vertical, gap: xs, children: [
216
+ { type: typography, variant: caption, content: (str/concat @entity.paramBLabel ": " (math/round @entity.paramB 2)) },
217
+ { type: range-slider, min: @config.paramBMin, max: @config.paramBMax, step: @config.paramBStep, value: @entity.paramB, showTooltip: true, action: "SET_PARAM_B" }
218
+ ] }
200
219
  ] },
201
- { type: stack, direction: horizontal, gap: xs, children: @entity.resultRow }
220
+ { type: typography, variant: body, content: @config.goalText },
221
+ { type: typography, variant: caption, color: muted, content: @entity.feedback }
202
222
  ] }
203
223
  ]
204
224
  })
@@ -244,23 +264,31 @@ orbital GoalSeekOrbital {
244
264
  padding: md
245
265
  children: [
246
266
  { type: stack, direction: vertical, gap: md, children: [
247
- { type: typography, variant: h4, content: @entity.title },
248
- { type: typography, variant: body, content: @config.goalText },
249
- { type: stack, direction: vertical, gap: xs, children: [
250
- { type: typography, variant: caption, content: (str/concat @entity.paramALabel ": " (math/round @entity.paramA 2)) },
251
- { type: range-slider, min: @config.paramAMin, max: @config.paramAMax, step: @config.paramAStep, value: @entity.paramA, showTooltip: true, action: "SET_PARAM_A" }
267
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
268
+ { type: stack, direction: vertical, gap: xs, children: [
269
+ { type: typography, variant: h4, content: @entity.title },
270
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
271
+ ] },
272
+ { type: badge, label: (if @entity.solved "Solved" (if (> @entity.attempts 0) "Try again" "Tuning")), variant: (if @entity.solved "success" (if (> @entity.attempts 0) "warning" "neutral")) }
252
273
  ] },
253
- { type: stack, direction: vertical, gap: xs, children: [
254
- { type: typography, variant: caption, content: (str/concat @entity.paramBLabel ": " (math/round @entity.paramB 2)) },
255
- { type: range-slider, min: @config.paramBMin, max: @config.paramBMax, step: @config.paramBStep, value: @entity.paramB, showTooltip: true, action: "SET_PARAM_B" }
274
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
275
+ { type: button, action: CHECK, label: @config.checkLabel, icon: "check", variant: primary, disabled: (if @entity.solved true false) },
276
+ { type: button, action: RESET, label: "Reset", icon: "rotate-ccw", variant: ghost },
277
+ { type: typography, variant: caption, color: muted, content: (if @config.showLiveDistance (str/concat "Distance from target: " (math/round @entity.distance 3) " · attempts: " (str/concat "" @entity.attempts)) (str/concat "Attempts: " (str/concat "" @entity.attempts))) }
256
278
  ] },
257
- { type: math-canvas, width: @config.width, height: @config.height, title: "", xMin: @config.xMin, xMax: @config.xMax, yMin: @entity.yMin, yMax: @entity.yMax, showAxes: @config.showAxes, showGrid: @config.showGrid, gridStep: @config.gridStep, curves: @entity.curves, points: [], vectors: [], shapes: [], interactive: false, animate: false },
258
- { type: typography, variant: body, content: (if @config.showLiveDistance (str/concat "Distance from target: " (math/round @entity.distance 3) " · attempts: " (str/concat "" @entity.attempts)) (str/concat "Attempts: " (str/concat "" @entity.attempts))) },
259
- { type: stack, direction: horizontal, gap: sm, children: [
260
- { type: button, action: CHECK, label: @config.checkLabel, variant: primary, disabled: (if @entity.solved true false) },
261
- { type: button, action: RESET, label: "Reset", variant: ghost }
279
+ { type: math-canvas, keyMap: { Space: CHECK, KeyR: RESET }, width: @config.width, height: @config.height, title: "", xMin: @config.xMin, xMax: @config.xMax, yMin: @entity.yMin, yMax: @entity.yMax, showAxes: @config.showAxes, showGrid: @config.showGrid, gridStep: @config.gridStep, curves: @entity.curves, points: [], vectors: [], shapes: [], interactive: false, animate: false },
280
+ { type: stack, direction: vertical, gap: sm, children: [
281
+ { type: stack, direction: vertical, gap: xs, children: [
282
+ { type: typography, variant: caption, content: (str/concat @entity.paramALabel ": " (math/round @entity.paramA 2)) },
283
+ { type: range-slider, min: @config.paramAMin, max: @config.paramAMax, step: @config.paramAStep, value: @entity.paramA, showTooltip: true, action: "SET_PARAM_A" }
284
+ ] },
285
+ { type: stack, direction: vertical, gap: xs, children: [
286
+ { type: typography, variant: caption, content: (str/concat @entity.paramBLabel ": " (math/round @entity.paramB 2)) },
287
+ { type: range-slider, min: @config.paramBMin, max: @config.paramBMax, step: @config.paramBStep, value: @entity.paramB, showTooltip: true, action: "SET_PARAM_B" }
288
+ ] }
262
289
  ] },
263
- { type: stack, direction: horizontal, gap: xs, children: @entity.resultRow }
290
+ { type: typography, variant: body, content: @config.goalText },
291
+ { type: typography, variant: caption, color: muted, content: @entity.feedback }
264
292
  ] }
265
293
  ]
266
294
  })
@@ -307,23 +335,31 @@ orbital GoalSeekOrbital {
307
335
  padding: md
308
336
  children: [
309
337
  { type: stack, direction: vertical, gap: md, children: [
310
- { type: typography, variant: h4, content: @entity.title },
311
- { type: typography, variant: body, content: @config.goalText },
312
- { type: stack, direction: vertical, gap: xs, children: [
313
- { type: typography, variant: caption, content: (str/concat @entity.paramALabel ": " (math/round @entity.paramA 2)) },
314
- { type: range-slider, min: @config.paramAMin, max: @config.paramAMax, step: @config.paramAStep, value: @entity.paramA, showTooltip: true, action: "SET_PARAM_A" }
338
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
339
+ { type: stack, direction: vertical, gap: xs, children: [
340
+ { type: typography, variant: h4, content: @entity.title },
341
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
342
+ ] },
343
+ { type: badge, label: (if @entity.solved "Solved" (if (> @entity.attempts 0) "Try again" "Tuning")), variant: (if @entity.solved "success" (if (> @entity.attempts 0) "warning" "neutral")) }
315
344
  ] },
316
- { type: stack, direction: vertical, gap: xs, children: [
317
- { type: typography, variant: caption, content: (str/concat @entity.paramBLabel ": " (math/round @entity.paramB 2)) },
318
- { type: range-slider, min: @config.paramBMin, max: @config.paramBMax, step: @config.paramBStep, value: @entity.paramB, showTooltip: true, action: "SET_PARAM_B" }
345
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
346
+ { type: button, action: CHECK, label: @config.checkLabel, icon: "check", variant: primary, disabled: (if @entity.solved true false) },
347
+ { type: button, action: RESET, label: "Reset", icon: "rotate-ccw", variant: ghost },
348
+ { type: typography, variant: caption, color: muted, content: (if @config.showLiveDistance (str/concat "Distance from target: " (math/round @entity.distance 3) " · attempts: " (str/concat "" @entity.attempts)) (str/concat "Attempts: " (str/concat "" @entity.attempts))) }
319
349
  ] },
320
- { type: math-canvas, width: @config.width, height: @config.height, title: "", xMin: @config.xMin, xMax: @config.xMax, yMin: @entity.yMin, yMax: @entity.yMax, showAxes: @config.showAxes, showGrid: @config.showGrid, gridStep: @config.gridStep, curves: @entity.curves, points: [], vectors: [], shapes: [], interactive: false, animate: false },
321
- { type: typography, variant: body, content: (if @config.showLiveDistance (str/concat "Distance from target: " (math/round @entity.distance 3) " · attempts: " (str/concat "" @entity.attempts)) (str/concat "Attempts: " (str/concat "" @entity.attempts))) },
322
- { type: stack, direction: horizontal, gap: sm, children: [
323
- { type: button, action: CHECK, label: @config.checkLabel, variant: primary, disabled: (if @entity.solved true false) },
324
- { type: button, action: RESET, label: "Reset", variant: ghost }
350
+ { type: math-canvas, keyMap: { Space: CHECK, KeyR: RESET }, width: @config.width, height: @config.height, title: "", xMin: @config.xMin, xMax: @config.xMax, yMin: @entity.yMin, yMax: @entity.yMax, showAxes: @config.showAxes, showGrid: @config.showGrid, gridStep: @config.gridStep, curves: @entity.curves, points: [], vectors: [], shapes: [], interactive: false, animate: false },
351
+ { type: stack, direction: vertical, gap: sm, children: [
352
+ { type: stack, direction: vertical, gap: xs, children: [
353
+ { type: typography, variant: caption, content: (str/concat @entity.paramALabel ": " (math/round @entity.paramA 2)) },
354
+ { type: range-slider, min: @config.paramAMin, max: @config.paramAMax, step: @config.paramAStep, value: @entity.paramA, showTooltip: true, action: "SET_PARAM_A" }
355
+ ] },
356
+ { type: stack, direction: vertical, gap: xs, children: [
357
+ { type: typography, variant: caption, content: (str/concat @entity.paramBLabel ": " (math/round @entity.paramB 2)) },
358
+ { type: range-slider, min: @config.paramBMin, max: @config.paramBMax, step: @config.paramBStep, value: @entity.paramB, showTooltip: true, action: "SET_PARAM_B" }
359
+ ] }
325
360
  ] },
326
- { type: stack, direction: horizontal, gap: xs, children: @entity.resultRow }
361
+ { type: typography, variant: body, content: @config.goalText },
362
+ { type: typography, variant: caption, color: muted, content: @entity.feedback }
327
363
  ] }
328
364
  ]
329
365
  })
@@ -341,23 +377,31 @@ orbital GoalSeekOrbital {
341
377
  padding: md
342
378
  children: [
343
379
  { type: stack, direction: vertical, gap: md, children: [
344
- { type: typography, variant: h4, content: @entity.title },
345
- { type: typography, variant: body, content: @config.goalText },
346
- { type: stack, direction: vertical, gap: xs, children: [
347
- { type: typography, variant: caption, content: (str/concat @entity.paramALabel ": " (math/round @entity.paramA 2)) },
348
- { type: range-slider, min: @config.paramAMin, max: @config.paramAMax, step: @config.paramAStep, value: @entity.paramA, showTooltip: true, action: "SET_PARAM_A" }
380
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
381
+ { type: stack, direction: vertical, gap: xs, children: [
382
+ { type: typography, variant: h4, content: @entity.title },
383
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
384
+ ] },
385
+ { type: badge, label: (if @entity.solved "Solved" (if (> @entity.attempts 0) "Try again" "Tuning")), variant: (if @entity.solved "success" (if (> @entity.attempts 0) "warning" "neutral")) }
349
386
  ] },
350
- { type: stack, direction: vertical, gap: xs, children: [
351
- { type: typography, variant: caption, content: (str/concat @entity.paramBLabel ": " (math/round @entity.paramB 2)) },
352
- { type: range-slider, min: @config.paramBMin, max: @config.paramBMax, step: @config.paramBStep, value: @entity.paramB, showTooltip: true, action: "SET_PARAM_B" }
387
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
388
+ { type: button, action: CHECK, label: @config.checkLabel, icon: "check", variant: primary, disabled: (if @entity.solved true false) },
389
+ { type: button, action: RESET, label: "Reset", icon: "rotate-ccw", variant: ghost },
390
+ { type: typography, variant: caption, color: muted, content: (if @config.showLiveDistance (str/concat "Distance from target: " (math/round @entity.distance 3) " · attempts: " (str/concat "" @entity.attempts)) (str/concat "Attempts: " (str/concat "" @entity.attempts))) }
353
391
  ] },
354
- { type: math-canvas, width: @config.width, height: @config.height, title: "", xMin: @config.xMin, xMax: @config.xMax, yMin: @entity.yMin, yMax: @entity.yMax, showAxes: @config.showAxes, showGrid: @config.showGrid, gridStep: @config.gridStep, curves: @entity.curves, points: [], vectors: [], shapes: [], interactive: false, animate: false },
355
- { type: typography, variant: body, content: (if @config.showLiveDistance (str/concat "Distance from target: " (math/round @entity.distance 3) " · attempts: " (str/concat "" @entity.attempts)) (str/concat "Attempts: " (str/concat "" @entity.attempts))) },
356
- { type: stack, direction: horizontal, gap: sm, children: [
357
- { type: button, action: CHECK, label: @config.checkLabel, variant: primary, disabled: (if @entity.solved true false) },
358
- { type: button, action: RESET, label: "Reset", variant: ghost }
392
+ { type: math-canvas, keyMap: { Space: CHECK, KeyR: RESET }, width: @config.width, height: @config.height, title: "", xMin: @config.xMin, xMax: @config.xMax, yMin: @entity.yMin, yMax: @entity.yMax, showAxes: @config.showAxes, showGrid: @config.showGrid, gridStep: @config.gridStep, curves: @entity.curves, points: [], vectors: [], shapes: [], interactive: false, animate: false },
393
+ { type: stack, direction: vertical, gap: sm, children: [
394
+ { type: stack, direction: vertical, gap: xs, children: [
395
+ { type: typography, variant: caption, content: (str/concat @entity.paramALabel ": " (math/round @entity.paramA 2)) },
396
+ { type: range-slider, min: @config.paramAMin, max: @config.paramAMax, step: @config.paramAStep, value: @entity.paramA, showTooltip: true, action: "SET_PARAM_A" }
397
+ ] },
398
+ { type: stack, direction: vertical, gap: xs, children: [
399
+ { type: typography, variant: caption, content: (str/concat @entity.paramBLabel ": " (math/round @entity.paramB 2)) },
400
+ { type: range-slider, min: @config.paramBMin, max: @config.paramBMax, step: @config.paramBStep, value: @entity.paramB, showTooltip: true, action: "SET_PARAM_B" }
401
+ ] }
359
402
  ] },
360
- { type: stack, direction: horizontal, gap: xs, children: @entity.resultRow }
403
+ { type: typography, variant: body, content: @config.goalText },
404
+ { type: typography, variant: caption, color: muted, content: @entity.feedback }
361
405
  ] }
362
406
  ]
363
407
  })
@@ -409,23 +453,31 @@ orbital GoalSeekOrbital {
409
453
  padding: md
410
454
  children: [
411
455
  { type: stack, direction: vertical, gap: md, children: [
412
- { type: typography, variant: h4, content: @entity.title },
413
- { type: typography, variant: body, content: @config.goalText },
414
- { type: stack, direction: vertical, gap: xs, children: [
415
- { type: typography, variant: caption, content: (str/concat @entity.paramALabel ": " (math/round @entity.paramA 2)) },
416
- { type: range-slider, min: @config.paramAMin, max: @config.paramAMax, step: @config.paramAStep, value: @entity.paramA, showTooltip: true, action: "SET_PARAM_A" }
456
+ { type: stack, direction: horizontal, justify: between, align: start, gap: md, children: [
457
+ { type: stack, direction: vertical, gap: xs, children: [
458
+ { type: typography, variant: h4, content: @entity.title },
459
+ (if (== @config.summary "") null { type: typography, variant: body2, color: muted, content: @config.summary })
460
+ ] },
461
+ { type: badge, label: (if @entity.solved "Solved" (if (> @entity.attempts 0) "Try again" "Tuning")), variant: (if @entity.solved "success" (if (> @entity.attempts 0) "warning" "neutral")) }
417
462
  ] },
418
- { type: stack, direction: vertical, gap: xs, children: [
419
- { type: typography, variant: caption, content: (str/concat @entity.paramBLabel ": " (math/round @entity.paramB 2)) },
420
- { type: range-slider, min: @config.paramBMin, max: @config.paramBMax, step: @config.paramBStep, value: @entity.paramB, showTooltip: true, action: "SET_PARAM_B" }
463
+ { type: stack, direction: horizontal, align: center, gap: sm, wrap: true, children: [
464
+ { type: button, action: CHECK, label: @config.checkLabel, icon: "check", variant: primary, disabled: (if @entity.solved true false) },
465
+ { type: button, action: RESET, label: "Reset", icon: "rotate-ccw", variant: ghost },
466
+ { type: typography, variant: caption, color: muted, content: (if @config.showLiveDistance (str/concat "Distance from target: " (math/round @entity.distance 3) " · attempts: " (str/concat "" @entity.attempts)) (str/concat "Attempts: " (str/concat "" @entity.attempts))) }
421
467
  ] },
422
- { type: math-canvas, width: @config.width, height: @config.height, title: "", xMin: @config.xMin, xMax: @config.xMax, yMin: @entity.yMin, yMax: @entity.yMax, showAxes: @config.showAxes, showGrid: @config.showGrid, gridStep: @config.gridStep, curves: @entity.curves, points: [], vectors: [], shapes: [], interactive: false, animate: false },
423
- { type: typography, variant: body, content: (if @config.showLiveDistance (str/concat "Distance from target: " (math/round @entity.distance 3) " · attempts: " (str/concat "" @entity.attempts)) (str/concat "Attempts: " (str/concat "" @entity.attempts))) },
424
- { type: stack, direction: horizontal, gap: sm, children: [
425
- { type: button, action: CHECK, label: @config.checkLabel, variant: primary, disabled: (if @entity.solved true false) },
426
- { type: button, action: RESET, label: "Reset", variant: ghost }
468
+ { type: math-canvas, keyMap: { Space: CHECK, KeyR: RESET }, width: @config.width, height: @config.height, title: "", xMin: @config.xMin, xMax: @config.xMax, yMin: @entity.yMin, yMax: @entity.yMax, showAxes: @config.showAxes, showGrid: @config.showGrid, gridStep: @config.gridStep, curves: @entity.curves, points: [], vectors: [], shapes: [], interactive: false, animate: false },
469
+ { type: stack, direction: vertical, gap: sm, children: [
470
+ { type: stack, direction: vertical, gap: xs, children: [
471
+ { type: typography, variant: caption, content: (str/concat @entity.paramALabel ": " (math/round @entity.paramA 2)) },
472
+ { type: range-slider, min: @config.paramAMin, max: @config.paramAMax, step: @config.paramAStep, value: @entity.paramA, showTooltip: true, action: "SET_PARAM_A" }
473
+ ] },
474
+ { type: stack, direction: vertical, gap: xs, children: [
475
+ { type: typography, variant: caption, content: (str/concat @entity.paramBLabel ": " (math/round @entity.paramB 2)) },
476
+ { type: range-slider, min: @config.paramBMin, max: @config.paramBMax, step: @config.paramBStep, value: @entity.paramB, showTooltip: true, action: "SET_PARAM_B" }
477
+ ] }
427
478
  ] },
428
- { type: stack, direction: horizontal, gap: xs, children: @entity.resultRow }
479
+ { type: typography, variant: body, content: @config.goalText },
480
+ { type: typography, variant: caption, color: muted, content: @entity.feedback }
429
481
  ] }
430
482
  ]
431
483
  })
@@ -497,6 +549,10 @@ orbital GoalSeekOrbital {
497
549
  @label "Title"
498
550
  @description "Title shown above the canvas."
499
551
  @tier "presentation"
552
+ summary : string = ""
553
+ @label "Concept"
554
+ @description "One line under the title saying what the learner is looking at (keep it under ~65 characters). Empty shows no line."
555
+ @tier "presentation"
500
556
  goalText : string = "Tune the two sliders until your curve matches the target curve, then press Check."
501
557
  @label "Goal Text"
502
558
  @description "One-sentence statement of the inverse problem the learner must solve."
@@ -562,10 +618,10 @@ orbital GoalSeekOrbital {
562
618
  learnerLabel : string = "Yours"
563
619
  @label "Learner Label"
564
620
  @tier "presentation"
565
- targetColor : string = "#94a3b8"
621
+ targetColor : string = "guide"
566
622
  @label "Target Color"
567
623
  @tier "presentation"
568
- learnerColor : string = "#3b82f6"
624
+ learnerColor : string = "series-2"
569
625
  @label "Learner Color"
570
626
  @tier "presentation"
571
627
  checkLabel : string = "Check"