@almadar/std 16.173.0 → 16.175.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 (220) hide show
  1. package/behaviors/lolo/infra/atoms/std-cross-reference.lolo +2 -4
  2. package/behaviors/lolo/ui/core/atoms/std-board.lolo +5 -9
  3. package/behaviors/lolo/ui/core/atoms/std-browse.lolo +8 -1
  4. package/behaviors/lolo/ui/core/atoms/std-esign-flow.lolo +2 -2
  5. package/behaviors/lolo/ui/core/atoms/std-event-log.lolo +3 -7
  6. package/behaviors/lolo/ui/core/atoms/std-form-advanced.lolo +1 -1
  7. package/behaviors/lolo/ui/core/atoms/std-image-upload-multi.lolo +1 -1
  8. package/behaviors/lolo/ui/core/atoms/std-list.lolo +3 -3
  9. package/behaviors/lolo/ui/core/atoms/std-modal.lolo +2 -2
  10. package/behaviors/lolo/ui/core/atoms/std-multi-party-flow.lolo +2 -4
  11. package/behaviors/lolo/ui/core/atoms/std-rating-review.lolo +5 -13
  12. package/behaviors/lolo/ui/core/atoms/std-recurrence.lolo +3 -7
  13. package/behaviors/lolo/ui/core/atoms/std-saved-search.lolo +1 -1
  14. package/behaviors/lolo/ui/core/atoms/std-signature-capture.lolo +2 -2
  15. package/behaviors/lolo/ui/core/atoms/std-step-flow.lolo +2 -4
  16. package/behaviors/lolo/ui/core/atoms/std-tag-taxonomy.lolo +1 -1
  17. package/behaviors/lolo/ui/core/atoms/std-thread.lolo +2 -2
  18. package/behaviors/lolo/ui/core/atoms/std-vote.lolo +2 -2
  19. package/behaviors/lolo/ui/core/atoms/std-wizard.lolo +3 -7
  20. package/behaviors/lolo/ui/core/atoms/ui-atlas-image.lolo +1 -1
  21. package/behaviors/lolo/ui/core/atoms/ui-atlas-panel.lolo +1 -1
  22. package/behaviors/lolo/ui/core/atoms/ui-center.lolo +1 -1
  23. package/behaviors/lolo/ui/core/atoms/ui-hstack.lolo +1 -1
  24. package/behaviors/lolo/ui/core/atoms/ui-icon.lolo +1 -1
  25. package/behaviors/lolo/ui/core/atoms/ui-stack.lolo +1 -1
  26. package/behaviors/lolo/ui/core/atoms/ui-typography.lolo +1 -1
  27. package/behaviors/lolo/ui/core/atoms/ui-vstack.lolo +1 -1
  28. package/behaviors/lolo/ui/core/molecules/ui-content-renderer.lolo +1 -1
  29. package/behaviors/lolo/ui/core/molecules/ui-form-layout.lolo +1 -1
  30. package/behaviors/lolo/ui/core/molecules/ui-grid.lolo +1 -1
  31. package/behaviors/lolo/ui/core/molecules/ui-table-view.lolo +4 -9
  32. package/behaviors/lolo/ui/core/organisms/ui-chat-bar.lolo +1 -1
  33. package/behaviors/lolo/ui/core/organisms/ui-dashboard-grid.lolo +1 -1
  34. package/behaviors/lolo/ui/core/organisms/ui-detail-panel.lolo +1 -1
  35. package/behaviors/lolo/ui/core/organisms/ui-entity-cards.lolo +1 -1
  36. package/behaviors/lolo/ui/core/organisms/ui-entity-list.lolo +1 -1
  37. package/behaviors/lolo/ui/core/organisms/ui-entity-table.lolo +1 -1
  38. package/behaviors/lolo/ui/core/organisms/ui-form-section.lolo +9 -3
  39. package/behaviors/lolo/ui/core/organisms/ui-form.lolo +9 -3
  40. package/behaviors/lolo/ui/core/organisms/ui-master-detail.lolo +1 -1
  41. package/behaviors/lolo/ui/core/organisms/ui-media-gallery.lolo +1 -1
  42. package/behaviors/lolo/ui/core/organisms/ui-segment-renderer.lolo +7 -1
  43. package/behaviors/lolo/ui/core/organisms/ui-stat-card.lolo +1 -1
  44. package/behaviors/lolo/ui/core/organisms/ui-subagent-trace-panel.lolo +1 -1
  45. package/behaviors/lolo/ui/game/atoms/ui-action-tile.lolo +1 -1
  46. package/behaviors/lolo/ui/game/atoms/ui-draw-shape-layer.lolo +41 -9
  47. package/behaviors/lolo/ui/game/atoms/ui-draw-shape.lolo +40 -8
  48. package/behaviors/lolo/ui/game/atoms/ui-draw-sprite-layer.lolo +13 -3
  49. package/behaviors/lolo/ui/game/atoms/ui-draw-sprite.lolo +12 -2
  50. package/behaviors/lolo/ui/game/atoms/ui-draw-text-layer.lolo +3 -3
  51. package/behaviors/lolo/ui/game/atoms/ui-draw-text.lolo +2 -2
  52. package/behaviors/lolo/ui/game/organisms/std-tactics-board-3d.lolo +32 -2
  53. package/behaviors/lolo/ui/learning/atoms/std-learn-classify.lolo +133 -23
  54. package/behaviors/lolo/ui/learning/atoms/std-learn-compare.lolo +397 -0
  55. package/behaviors/lolo/ui/learning/atoms/std-learn-coupled-sim.lolo +537 -0
  56. package/behaviors/lolo/ui/learning/atoms/std-learn-derivation.lolo +428 -0
  57. package/behaviors/lolo/ui/learning/atoms/std-learn-doser.lolo +520 -0
  58. package/behaviors/lolo/ui/learning/atoms/std-learn-estimate.lolo +419 -0
  59. package/behaviors/lolo/ui/learning/atoms/std-learn-goal-seek.lolo +591 -0
  60. package/behaviors/lolo/ui/learning/atoms/std-learn-grid-sim.lolo +425 -0
  61. package/behaviors/lolo/ui/learning/atoms/std-learn-hotspot.lolo +398 -0
  62. package/behaviors/lolo/ui/learning/atoms/std-learn-measure.lolo +325 -0
  63. package/behaviors/lolo/ui/learning/atoms/std-learn-perturb.lolo +494 -0
  64. package/behaviors/lolo/ui/learning/atoms/std-learn-predict.lolo +408 -0
  65. package/behaviors/lolo/ui/learning/atoms/std-learn-scatter-fit.lolo +805 -0
  66. package/behaviors/lolo/ui/learning/atoms/std-learn-scenario.lolo +307 -0
  67. package/behaviors/lolo/ui/learning/atoms/std-learn-sim-3d.lolo +318 -0
  68. package/behaviors/lolo/ui/learning/atoms/std-learn-speed-drill.lolo +336 -0
  69. package/behaviors/lolo/ui/learning/atoms/std-learn-tour-3d.lolo +409 -0
  70. package/behaviors/lolo/ui/learning/atoms/std-learn-transport.lolo +186 -0
  71. package/behaviors/lolo/ui/learning/atoms/std-learn-tree.lolo +522 -0
  72. package/behaviors/lolo/ui/learning/atoms/ui-algo-graph-canvas.lolo +192 -0
  73. package/behaviors/lolo/ui/learning/atoms/ui-algorithm-canvas.lolo +111 -2
  74. package/behaviors/lolo/ui/learning/atoms/ui-biology-canvas.lolo +193 -5
  75. package/behaviors/lolo/ui/learning/atoms/ui-chemistry-canvas.lolo +173 -5
  76. package/behaviors/lolo/ui/learning/atoms/ui-learning-canvas.lolo +48 -1
  77. package/behaviors/lolo/ui/learning/atoms/ui-math-canvas.lolo +141 -1
  78. package/behaviors/lolo/ui/learning/atoms/ui-physics-canvas.lolo +242 -5
  79. package/behaviors/lolo/ui/marketing/organisms/ui-book-viewer.lolo +1 -1
  80. package/behaviors/lolo/ui/marketing/organisms/ui-case-study-organism.lolo +1 -1
  81. package/behaviors/lolo/ui/marketing/organisms/ui-feature-grid-organism.lolo +1 -1
  82. package/behaviors/lolo/ui/marketing/organisms/ui-hero-organism.lolo +1 -1
  83. package/behaviors/lolo/ui/marketing/organisms/ui-pricing-organism.lolo +1 -1
  84. package/behaviors/lolo/ui/marketing/organisms/ui-showcase-organism.lolo +1 -1
  85. package/behaviors/lolo/ui/marketing/organisms/ui-stats-organism.lolo +1 -1
  86. package/behaviors/lolo/ui/marketing/organisms/ui-step-flow-organism.lolo +1 -1
  87. package/behaviors/lolo/ui/marketing/organisms/ui-team-organism.lolo +1 -1
  88. package/behaviors/registry/agent/atoms/std-agent-session.orb +22 -1
  89. package/behaviors/registry/agent/atoms/std-agent-tool-call.orb +38 -2
  90. package/behaviors/registry/agent/atoms/std-agent-tool-loop.orb +38 -2
  91. package/behaviors/registry/agent/organisms/std-agent-rabit.orb +23 -1
  92. package/behaviors/registry/infra/atoms/std-approval-gate.orb +8 -16
  93. package/behaviors/registry/infra/atoms/std-cache-aside.orb +31 -62
  94. package/behaviors/registry/infra/atoms/std-circuit-breaker.orb +16 -32
  95. package/behaviors/registry/infra/atoms/std-cross-reference.orb +32 -4
  96. package/behaviors/registry/infra/atoms/std-data-erasure.orb +8 -16
  97. package/behaviors/registry/infra/atoms/std-mod-queue.orb +8 -16
  98. package/behaviors/registry/infra/atoms/std-rate-limiter.orb +14 -28
  99. package/behaviors/registry/infra/atoms/std-row-access-control.orb +30 -2
  100. package/behaviors/registry/ui/core/atoms/std-billable-hour.orb +1 -2
  101. package/behaviors/registry/ui/core/atoms/std-board.orb +19 -5
  102. package/behaviors/registry/ui/core/atoms/std-browse.orb +29 -7
  103. package/behaviors/registry/ui/core/atoms/std-dashboard-grid-embedded.orb +1 -2
  104. package/behaviors/registry/ui/core/atoms/std-esign-flow.orb +3 -5
  105. package/behaviors/registry/ui/core/atoms/std-esign-request.orb +3 -6
  106. package/behaviors/registry/ui/core/atoms/std-event-log.orb +17 -3
  107. package/behaviors/registry/ui/core/atoms/std-export.orb +2 -4
  108. package/behaviors/registry/ui/core/atoms/std-form-advanced.orb +1 -1
  109. package/behaviors/registry/ui/core/atoms/std-gallery.orb +9 -18
  110. package/behaviors/registry/ui/core/atoms/std-graphs.orb +15 -1
  111. package/behaviors/registry/ui/core/atoms/std-import.orb +2 -4
  112. package/behaviors/registry/ui/core/atoms/std-list.orb +4 -6
  113. package/behaviors/registry/ui/core/atoms/std-modal.orb +2 -2
  114. package/behaviors/registry/ui/core/atoms/std-multi-party-flow.orb +16 -2
  115. package/behaviors/registry/ui/core/atoms/std-pagination.orb +15 -1
  116. package/behaviors/registry/ui/core/atoms/std-rating-review.orb +19 -5
  117. package/behaviors/registry/ui/core/atoms/std-recurrence.orb +17 -3
  118. package/behaviors/registry/ui/core/atoms/std-rich-editor.orb +15 -1
  119. package/behaviors/registry/ui/core/atoms/std-scatter.orb +15 -1
  120. package/behaviors/registry/ui/core/atoms/std-signature-capture.orb +2 -2
  121. package/behaviors/registry/ui/core/atoms/std-stats.orb +15 -1
  122. package/behaviors/registry/ui/core/atoms/std-step-flow.orb +16 -2
  123. package/behaviors/registry/ui/core/atoms/std-thread.orb +2 -2
  124. package/behaviors/registry/ui/core/atoms/std-vote.orb +2 -2
  125. package/behaviors/registry/ui/core/atoms/std-wizard.orb +17 -3
  126. package/behaviors/registry/ui/core/atoms/ui-atlas-image.orb +4 -1
  127. package/behaviors/registry/ui/core/atoms/ui-atlas-panel.orb +4 -1
  128. package/behaviors/registry/ui/core/atoms/ui-center.orb +4 -1
  129. package/behaviors/registry/ui/core/atoms/ui-hstack.orb +4 -1
  130. package/behaviors/registry/ui/core/atoms/ui-icon.orb +4 -1
  131. package/behaviors/registry/ui/core/atoms/ui-stack.orb +4 -1
  132. package/behaviors/registry/ui/core/atoms/ui-typography.orb +4 -1
  133. package/behaviors/registry/ui/core/atoms/ui-vstack.orb +4 -1
  134. package/behaviors/registry/ui/core/molecules/ui-accordion.orb +3 -3
  135. package/behaviors/registry/ui/core/molecules/ui-content-renderer.orb +4 -1
  136. package/behaviors/registry/ui/core/molecules/ui-form-layout.orb +4 -1
  137. package/behaviors/registry/ui/core/molecules/ui-grid.orb +4 -1
  138. package/behaviors/registry/ui/core/molecules/ui-table-view.orb +4 -39
  139. package/behaviors/registry/ui/core/molecules/ui-tabs.orb +2 -2
  140. package/behaviors/registry/ui/core/molecules/ui-wizard-container.orb +1 -1
  141. package/behaviors/registry/ui/core/organisms/ui-chat-bar.orb +4 -1
  142. package/behaviors/registry/ui/core/organisms/ui-dashboard-grid.orb +5 -2
  143. package/behaviors/registry/ui/core/organisms/ui-detail-panel.orb +5 -2
  144. package/behaviors/registry/ui/core/organisms/ui-entity-cards.orb +4 -1
  145. package/behaviors/registry/ui/core/organisms/ui-entity-list.orb +4 -1
  146. package/behaviors/registry/ui/core/organisms/ui-entity-table.orb +4 -1
  147. package/behaviors/registry/ui/core/organisms/ui-form-section.orb +34 -2
  148. package/behaviors/registry/ui/core/organisms/ui-form.orb +34 -2
  149. package/behaviors/registry/ui/core/organisms/ui-master-detail.orb +4 -1
  150. package/behaviors/registry/ui/core/organisms/ui-media-gallery.orb +4 -1
  151. package/behaviors/registry/ui/core/organisms/ui-segment-renderer.orb +24 -2
  152. package/behaviors/registry/ui/core/organisms/ui-stat-card.orb +4 -1
  153. package/behaviors/registry/ui/core/organisms/ui-subagent-trace-panel.orb +4 -1
  154. package/behaviors/registry/ui/core/organisms/ui-tabbed-container.orb +1 -1
  155. package/behaviors/registry/ui/core/organisms/ui-ui-slot-renderer.orb +1 -1
  156. package/behaviors/registry/ui/game/atoms/std-fx-particles.orb +35 -1
  157. package/behaviors/registry/ui/game/atoms/ui-action-tile.orb +4 -1
  158. package/behaviors/registry/ui/game/atoms/ui-draw-shape-layer.orb +183 -13
  159. package/behaviors/registry/ui/game/atoms/ui-draw-shape.orb +104 -9
  160. package/behaviors/registry/ui/game/atoms/ui-draw-sprite-layer.orb +56 -2
  161. package/behaviors/registry/ui/game/atoms/ui-draw-sprite.orb +36 -4
  162. package/behaviors/registry/ui/game/atoms/ui-draw-text-layer.orb +21 -2
  163. package/behaviors/registry/ui/game/atoms/ui-draw-text.orb +19 -4
  164. package/behaviors/registry/ui/game/organisms/std-tactics-board-3d.orb +173 -2
  165. package/behaviors/registry/ui/learning/atoms/std-learn-classify.orb +1288 -197
  166. package/behaviors/registry/ui/learning/atoms/std-learn-compare.orb +2814 -0
  167. package/behaviors/registry/ui/learning/atoms/std-learn-coupled-sim.orb +3183 -0
  168. package/behaviors/registry/ui/learning/atoms/std-learn-derivation.orb +2512 -0
  169. package/behaviors/registry/ui/learning/atoms/std-learn-doser.orb +3678 -0
  170. package/behaviors/registry/ui/learning/atoms/std-learn-estimate.orb +2394 -0
  171. package/behaviors/registry/ui/learning/atoms/std-learn-goal-seek.orb +3951 -0
  172. package/behaviors/registry/ui/learning/atoms/std-learn-grid-sim.orb +3458 -0
  173. package/behaviors/registry/ui/learning/atoms/std-learn-hotspot.orb +2646 -0
  174. package/behaviors/registry/ui/learning/atoms/std-learn-measure.orb +1979 -0
  175. package/behaviors/registry/ui/learning/atoms/std-learn-perturb.orb +2994 -0
  176. package/behaviors/registry/ui/learning/atoms/std-learn-predict.orb +2682 -0
  177. package/behaviors/registry/ui/learning/atoms/std-learn-scatter-fit.orb +6539 -0
  178. package/behaviors/registry/ui/learning/atoms/std-learn-scenario.orb +1842 -0
  179. package/behaviors/registry/ui/learning/atoms/std-learn-sim-3d.orb +1648 -0
  180. package/behaviors/registry/ui/learning/atoms/std-learn-speed-drill.orb +2307 -0
  181. package/behaviors/registry/ui/learning/atoms/std-learn-tour-3d.orb +3118 -0
  182. package/behaviors/registry/ui/learning/atoms/std-learn-transport.orb +986 -0
  183. package/behaviors/registry/ui/learning/atoms/std-learn-tree.orb +3333 -0
  184. package/behaviors/registry/ui/learning/atoms/ui-algo-graph-canvas.orb +716 -0
  185. package/behaviors/registry/ui/learning/atoms/ui-algorithm-canvas.orb +679 -5
  186. package/behaviors/registry/ui/learning/atoms/ui-biology-canvas.orb +962 -18
  187. package/behaviors/registry/ui/learning/atoms/ui-chemistry-canvas.orb +919 -30
  188. package/behaviors/registry/ui/learning/atoms/ui-learning-canvas.orb +372 -1
  189. package/behaviors/registry/ui/learning/atoms/ui-math-canvas.orb +936 -16
  190. package/behaviors/registry/ui/learning/atoms/ui-physics-canvas.orb +1328 -43
  191. package/behaviors/registry/ui/marketing/atoms/std-marketing-article.orb +1 -2
  192. package/behaviors/registry/ui/marketing/atoms/std-marketing-footer.orb +1 -2
  193. package/behaviors/registry/ui/marketing/atoms/std-marketing-split.orb +1 -2
  194. package/behaviors/registry/ui/marketing/atoms/std-marketing-stats.orb +1 -2
  195. package/behaviors/registry/ui/marketing/atoms/std-marketing-steps.orb +1 -2
  196. package/behaviors/registry/ui/marketing/atoms/std-marketing-team.orb +1 -2
  197. package/behaviors/registry/ui/marketing/organisms/ui-book-viewer.orb +4 -1
  198. package/behaviors/registry/ui/marketing/organisms/ui-case-study-organism.orb +4 -1
  199. package/behaviors/registry/ui/marketing/organisms/ui-feature-grid-organism.orb +4 -1
  200. package/behaviors/registry/ui/marketing/organisms/ui-hero-organism.orb +4 -1
  201. package/behaviors/registry/ui/marketing/organisms/ui-pricing-organism.orb +4 -1
  202. package/behaviors/registry/ui/marketing/organisms/ui-showcase-organism.orb +4 -1
  203. package/behaviors/registry/ui/marketing/organisms/ui-stats-organism.orb +4 -1
  204. package/behaviors/registry/ui/marketing/organisms/ui-step-flow-organism.orb +4 -1
  205. package/behaviors/registry/ui/marketing/organisms/ui-team-organism.orb +4 -1
  206. package/dist/behaviors/exports-reader.js +3704 -2189
  207. package/dist/behaviors/functions/index.d.ts +2638 -254
  208. package/dist/behaviors/functions/index.js +3648 -2190
  209. package/dist/behaviors/index.d.ts +1 -1
  210. package/dist/behaviors/index.js +3705 -2190
  211. package/dist/behaviors/query.js +3704 -2189
  212. package/dist/behaviors-embeddings.hash.json +3 -3
  213. package/dist/behaviors-embeddings.json +289 -213
  214. package/dist/behaviors-registry.json +7900 -587
  215. package/dist/index.d.ts +1 -1
  216. package/dist/index.js +3705 -2190
  217. package/dist/knob-embeddings.hash.json +3 -3
  218. package/dist/knob-embeddings.json +1 -1
  219. package/dist/registry/factory-signatures.json +1 -1
  220. package/package.json +2 -2
@@ -0,0 +1,494 @@
1
+ app std-learn-perturb "1.0.0"
2
+ "Generic equilibrium-and-shock simulation — a single named quantity relaxes each tick toward an adjustable setpoint at an adjustable recovery rate (dV = k·(E − V)), drawn live against the setpoint line. Shock buttons knock the quantity up or down mid-run and the learner watches it recover; moving the setpoint slider mid-run makes the system chase a new equilibrium, and the recovery-rate slider shows sluggish versus snappy regulation. All names and scales are config-declared, so one mechanism serves every negative-feedback lesson: body temperature homeostasis, a thermostat, market price around equilibrium, blood glucose, reservoir level, ecological resilience. Standalone by default; behind a lab router set matchMode and it renders only when MODE_SELECTED matches."
3
+ orbital PerturbOrbital {
4
+ type PerturbSample = {
5
+ x : number!
6
+ y : number!
7
+ }
8
+ type PerturbCurve = {
9
+ label : string
10
+ color : string
11
+ samples : [PerturbSample]!
12
+ }
13
+
14
+ entity PerturbScene [runtime] {
15
+ id : string!
16
+ active : boolean = false
17
+ title : string
18
+ t : number = 0
19
+ value : number = 0
20
+ setpoint : number = 0
21
+ rate : number = 0
22
+ running : boolean = false
23
+ traceSamples : [PerturbSample]
24
+ curves : [PerturbCurve]
25
+ }
26
+
27
+ trait PerturbSim -> @rebindable PerturbScene [interaction, instance] {
28
+ initial: idle
29
+
30
+ state idle {
31
+ INIT -> idle when (== @config.matchMode "")
32
+ (set @entity.active true)
33
+ (set @entity.title @config.title)
34
+ (set @entity.t 0)
35
+ (set @entity.value @config.valueStart)
36
+ (set @entity.setpoint @config.setpointDefault)
37
+ (set @entity.rate @config.rateDefault)
38
+ (set @entity.running @config.autoRun)
39
+ (set @entity.traceSamples [ { x: 0, y: @config.valueStart } ])
40
+ (set @entity.curves [
41
+ { label: @config.setpointLabel, color: @config.setpointColor, samples: [ { x: 0, y: @entity.setpoint }, { x: @config.duration, y: @entity.setpoint } ] },
42
+ { label: @config.valueLabel, color: @config.valueColor, samples: @entity.traceSamples }
43
+ ])
44
+ (render-ui main {
45
+ type: box
46
+ padding: md
47
+ children: [
48
+ { type: stack, direction: vertical, gap: md, children: [
49
+ { type: typography, variant: h4, content: @entity.title },
50
+ { type: typography, variant: body, content: @config.taskText },
51
+ { type: stack, direction: horizontal, gap: sm, children: [
52
+ { type: button, action: RUN, label: "Run", variant: primary, disabled: (if (and (== @entity.running false) (< @entity.t @config.duration)) false true) },
53
+ { type: button, action: PAUSE, label: "Pause", variant: secondary, disabled: (if @entity.running false true) },
54
+ { type: button, action: RESET, label: "Reset", variant: ghost },
55
+ { type: button, action: SHOCK, actionPayload: { delta: @config.shockSize }, label: @config.shockUpLabel, variant: secondary, size: sm },
56
+ { type: button, action: SHOCK, actionPayload: { delta: (- 0 @config.shockSize) }, label: @config.shockDownLabel, variant: secondary, size: sm }
57
+ ] },
58
+ { type: stack, direction: vertical, gap: xs, children: [
59
+ { type: typography, variant: caption, content: (str/concat @config.setpointLabel ": " (math/round @entity.setpoint 1)) },
60
+ { type: range-slider, min: @config.setpointMin, max: @config.setpointMax, step: @config.setpointStep, value: @entity.setpoint, showTooltip: true, action: "SET_POINT" }
61
+ ] },
62
+ { type: stack, direction: vertical, gap: xs, children: [
63
+ { type: typography, variant: caption, content: (str/concat @config.rateLabel ": " (math/round @entity.rate 2)) },
64
+ { type: range-slider, min: @config.rateMin, max: @config.rateMax, step: @config.rateStep, value: @entity.rate, showTooltip: true, action: "SET_RATE" }
65
+ ] },
66
+ { type: math-canvas, width: @config.width, height: @config.height, title: "", xMin: 0, xMax: @config.duration, yMin: @config.valueMin, yMax: @config.valueMax, showAxes: true, showGrid: true, gridStep: @config.gridStep, curves: @entity.curves, points: [], vectors: [], shapes: [], interactive: false, animate: false },
67
+ { type: typography, variant: body, content: (str/concat "t = " (math/round @entity.t 1) " · " @config.valueLabel " = " (math/round @entity.value 2) " · deviation: " (math/round (- @entity.value @entity.setpoint) 2)) }
68
+ ] }
69
+ ]
70
+ })
71
+
72
+ MODE_SELECTED -> idle when (== ?mode @config.matchMode)
73
+ (set @entity.active true)
74
+ (set @entity.title @config.title)
75
+ (set @entity.t 0)
76
+ (set @entity.value @config.valueStart)
77
+ (set @entity.setpoint @config.setpointDefault)
78
+ (set @entity.rate @config.rateDefault)
79
+ (set @entity.running @config.autoRun)
80
+ (set @entity.traceSamples [ { x: 0, y: @config.valueStart } ])
81
+ (set @entity.curves [
82
+ { label: @config.setpointLabel, color: @config.setpointColor, samples: [ { x: 0, y: @entity.setpoint }, { x: @config.duration, y: @entity.setpoint } ] },
83
+ { label: @config.valueLabel, color: @config.valueColor, samples: @entity.traceSamples }
84
+ ])
85
+ (render-ui main {
86
+ type: box
87
+ padding: md
88
+ children: [
89
+ { type: stack, direction: vertical, gap: md, children: [
90
+ { type: typography, variant: h4, content: @entity.title },
91
+ { type: typography, variant: body, content: @config.taskText },
92
+ { type: stack, direction: horizontal, gap: sm, children: [
93
+ { type: button, action: RUN, label: "Run", variant: primary, disabled: (if (and (== @entity.running false) (< @entity.t @config.duration)) false true) },
94
+ { type: button, action: PAUSE, label: "Pause", variant: secondary, disabled: (if @entity.running false true) },
95
+ { type: button, action: RESET, label: "Reset", variant: ghost },
96
+ { type: button, action: SHOCK, actionPayload: { delta: @config.shockSize }, label: @config.shockUpLabel, variant: secondary, size: sm },
97
+ { type: button, action: SHOCK, actionPayload: { delta: (- 0 @config.shockSize) }, label: @config.shockDownLabel, variant: secondary, size: sm }
98
+ ] },
99
+ { type: stack, direction: vertical, gap: xs, children: [
100
+ { type: typography, variant: caption, content: (str/concat @config.setpointLabel ": " (math/round @entity.setpoint 1)) },
101
+ { type: range-slider, min: @config.setpointMin, max: @config.setpointMax, step: @config.setpointStep, value: @entity.setpoint, showTooltip: true, action: "SET_POINT" }
102
+ ] },
103
+ { type: stack, direction: vertical, gap: xs, children: [
104
+ { type: typography, variant: caption, content: (str/concat @config.rateLabel ": " (math/round @entity.rate 2)) },
105
+ { type: range-slider, min: @config.rateMin, max: @config.rateMax, step: @config.rateStep, value: @entity.rate, showTooltip: true, action: "SET_RATE" }
106
+ ] },
107
+ { type: math-canvas, width: @config.width, height: @config.height, title: "", xMin: 0, xMax: @config.duration, yMin: @config.valueMin, yMax: @config.valueMax, showAxes: true, showGrid: true, gridStep: @config.gridStep, curves: @entity.curves, points: [], vectors: [], shapes: [], interactive: false, animate: false },
108
+ { type: typography, variant: body, content: (str/concat "t = " (math/round @entity.t 1) " · " @config.valueLabel " = " (math/round @entity.value 2) " · deviation: " (math/round (- @entity.value @entity.setpoint) 2)) }
109
+ ] }
110
+ ]
111
+ })
112
+
113
+ RUN -> idle when (and (== @entity.active true) (and (== @entity.running false) (< @entity.t @config.duration)))
114
+ (set @entity.running true)
115
+ (render-ui main {
116
+ type: box
117
+ padding: md
118
+ children: [
119
+ { type: stack, direction: vertical, gap: md, children: [
120
+ { type: typography, variant: h4, content: @entity.title },
121
+ { type: typography, variant: body, content: @config.taskText },
122
+ { type: stack, direction: horizontal, gap: sm, children: [
123
+ { type: button, action: RUN, label: "Run", variant: primary, disabled: (if (and (== @entity.running false) (< @entity.t @config.duration)) false true) },
124
+ { type: button, action: PAUSE, label: "Pause", variant: secondary, disabled: (if @entity.running false true) },
125
+ { type: button, action: RESET, label: "Reset", variant: ghost },
126
+ { type: button, action: SHOCK, actionPayload: { delta: @config.shockSize }, label: @config.shockUpLabel, variant: secondary, size: sm },
127
+ { type: button, action: SHOCK, actionPayload: { delta: (- 0 @config.shockSize) }, label: @config.shockDownLabel, variant: secondary, size: sm }
128
+ ] },
129
+ { type: stack, direction: vertical, gap: xs, children: [
130
+ { type: typography, variant: caption, content: (str/concat @config.setpointLabel ": " (math/round @entity.setpoint 1)) },
131
+ { type: range-slider, min: @config.setpointMin, max: @config.setpointMax, step: @config.setpointStep, value: @entity.setpoint, showTooltip: true, action: "SET_POINT" }
132
+ ] },
133
+ { type: stack, direction: vertical, gap: xs, children: [
134
+ { type: typography, variant: caption, content: (str/concat @config.rateLabel ": " (math/round @entity.rate 2)) },
135
+ { type: range-slider, min: @config.rateMin, max: @config.rateMax, step: @config.rateStep, value: @entity.rate, showTooltip: true, action: "SET_RATE" }
136
+ ] },
137
+ { type: math-canvas, width: @config.width, height: @config.height, title: "", xMin: 0, xMax: @config.duration, yMin: @config.valueMin, yMax: @config.valueMax, showAxes: true, showGrid: true, gridStep: @config.gridStep, curves: @entity.curves, points: [], vectors: [], shapes: [], interactive: false, animate: false },
138
+ { type: typography, variant: body, content: (str/concat "t = " (math/round @entity.t 1) " · " @config.valueLabel " = " (math/round @entity.value 2) " · deviation: " (math/round (- @entity.value @entity.setpoint) 2)) }
139
+ ] }
140
+ ]
141
+ })
142
+ (emit RUN_TOGGLED { running: @entity.running })
143
+
144
+ PAUSE -> idle when (and (== @entity.active true) (== @entity.running true))
145
+ (set @entity.running false)
146
+ (render-ui main {
147
+ type: box
148
+ padding: md
149
+ children: [
150
+ { type: stack, direction: vertical, gap: md, children: [
151
+ { type: typography, variant: h4, content: @entity.title },
152
+ { type: typography, variant: body, content: @config.taskText },
153
+ { type: stack, direction: horizontal, gap: sm, children: [
154
+ { type: button, action: RUN, label: "Run", variant: primary, disabled: (if (and (== @entity.running false) (< @entity.t @config.duration)) false true) },
155
+ { type: button, action: PAUSE, label: "Pause", variant: secondary, disabled: (if @entity.running false true) },
156
+ { type: button, action: RESET, label: "Reset", variant: ghost },
157
+ { type: button, action: SHOCK, actionPayload: { delta: @config.shockSize }, label: @config.shockUpLabel, variant: secondary, size: sm },
158
+ { type: button, action: SHOCK, actionPayload: { delta: (- 0 @config.shockSize) }, label: @config.shockDownLabel, variant: secondary, size: sm }
159
+ ] },
160
+ { type: stack, direction: vertical, gap: xs, children: [
161
+ { type: typography, variant: caption, content: (str/concat @config.setpointLabel ": " (math/round @entity.setpoint 1)) },
162
+ { type: range-slider, min: @config.setpointMin, max: @config.setpointMax, step: @config.setpointStep, value: @entity.setpoint, showTooltip: true, action: "SET_POINT" }
163
+ ] },
164
+ { type: stack, direction: vertical, gap: xs, children: [
165
+ { type: typography, variant: caption, content: (str/concat @config.rateLabel ": " (math/round @entity.rate 2)) },
166
+ { type: range-slider, min: @config.rateMin, max: @config.rateMax, step: @config.rateStep, value: @entity.rate, showTooltip: true, action: "SET_RATE" }
167
+ ] },
168
+ { type: math-canvas, width: @config.width, height: @config.height, title: "", xMin: 0, xMax: @config.duration, yMin: @config.valueMin, yMax: @config.valueMax, showAxes: true, showGrid: true, gridStep: @config.gridStep, curves: @entity.curves, points: [], vectors: [], shapes: [], interactive: false, animate: false },
169
+ { type: typography, variant: body, content: (str/concat "t = " (math/round @entity.t 1) " · " @config.valueLabel " = " (math/round @entity.value 2) " · deviation: " (math/round (- @entity.value @entity.setpoint) 2)) }
170
+ ] }
171
+ ]
172
+ })
173
+ (emit RUN_TOGGLED { running: @entity.running })
174
+
175
+ RESET -> idle when (== @entity.active true)
176
+ (set @entity.t 0)
177
+ (set @entity.value @config.valueStart)
178
+ (set @entity.setpoint @config.setpointDefault)
179
+ (set @entity.rate @config.rateDefault)
180
+ (set @entity.running false)
181
+ (set @entity.traceSamples [ { x: 0, y: @config.valueStart } ])
182
+ (set @entity.curves [
183
+ { label: @config.setpointLabel, color: @config.setpointColor, samples: [ { x: 0, y: @entity.setpoint }, { x: @config.duration, y: @entity.setpoint } ] },
184
+ { label: @config.valueLabel, color: @config.valueColor, samples: @entity.traceSamples }
185
+ ])
186
+ (render-ui main {
187
+ type: box
188
+ padding: md
189
+ children: [
190
+ { type: stack, direction: vertical, gap: md, children: [
191
+ { type: typography, variant: h4, content: @entity.title },
192
+ { type: typography, variant: body, content: @config.taskText },
193
+ { type: stack, direction: horizontal, gap: sm, children: [
194
+ { type: button, action: RUN, label: "Run", variant: primary, disabled: (if (and (== @entity.running false) (< @entity.t @config.duration)) false true) },
195
+ { type: button, action: PAUSE, label: "Pause", variant: secondary, disabled: (if @entity.running false true) },
196
+ { type: button, action: RESET, label: "Reset", variant: ghost },
197
+ { type: button, action: SHOCK, actionPayload: { delta: @config.shockSize }, label: @config.shockUpLabel, variant: secondary, size: sm },
198
+ { type: button, action: SHOCK, actionPayload: { delta: (- 0 @config.shockSize) }, label: @config.shockDownLabel, variant: secondary, size: sm }
199
+ ] },
200
+ { type: stack, direction: vertical, gap: xs, children: [
201
+ { type: typography, variant: caption, content: (str/concat @config.setpointLabel ": " (math/round @entity.setpoint 1)) },
202
+ { type: range-slider, min: @config.setpointMin, max: @config.setpointMax, step: @config.setpointStep, value: @entity.setpoint, showTooltip: true, action: "SET_POINT" }
203
+ ] },
204
+ { type: stack, direction: vertical, gap: xs, children: [
205
+ { type: typography, variant: caption, content: (str/concat @config.rateLabel ": " (math/round @entity.rate 2)) },
206
+ { type: range-slider, min: @config.rateMin, max: @config.rateMax, step: @config.rateStep, value: @entity.rate, showTooltip: true, action: "SET_RATE" }
207
+ ] },
208
+ { type: math-canvas, width: @config.width, height: @config.height, title: "", xMin: 0, xMax: @config.duration, yMin: @config.valueMin, yMax: @config.valueMax, showAxes: true, showGrid: true, gridStep: @config.gridStep, curves: @entity.curves, points: [], vectors: [], shapes: [], interactive: false, animate: false },
209
+ { type: typography, variant: body, content: (str/concat "t = " (math/round @entity.t 1) " · " @config.valueLabel " = " (math/round @entity.value 2) " · deviation: " (math/round (- @entity.value @entity.setpoint) 2)) }
210
+ ] }
211
+ ]
212
+ })
213
+ (emit SIM_RESET { valueStart: @config.valueStart })
214
+
215
+ SET_POINT -> idle when (== @entity.active true)
216
+ (set @entity.setpoint (math/clamp ?value @config.setpointMin @config.setpointMax))
217
+ (set @entity.curves [
218
+ { label: @config.setpointLabel, color: @config.setpointColor, samples: [ { x: 0, y: @entity.setpoint }, { x: @config.duration, y: @entity.setpoint } ] },
219
+ { label: @config.valueLabel, color: @config.valueColor, samples: @entity.traceSamples }
220
+ ])
221
+ (render-ui main {
222
+ type: box
223
+ padding: md
224
+ children: [
225
+ { type: stack, direction: vertical, gap: md, children: [
226
+ { type: typography, variant: h4, content: @entity.title },
227
+ { type: typography, variant: body, content: @config.taskText },
228
+ { type: stack, direction: horizontal, gap: sm, children: [
229
+ { type: button, action: RUN, label: "Run", variant: primary, disabled: (if (and (== @entity.running false) (< @entity.t @config.duration)) false true) },
230
+ { type: button, action: PAUSE, label: "Pause", variant: secondary, disabled: (if @entity.running false true) },
231
+ { type: button, action: RESET, label: "Reset", variant: ghost },
232
+ { type: button, action: SHOCK, actionPayload: { delta: @config.shockSize }, label: @config.shockUpLabel, variant: secondary, size: sm },
233
+ { type: button, action: SHOCK, actionPayload: { delta: (- 0 @config.shockSize) }, label: @config.shockDownLabel, variant: secondary, size: sm }
234
+ ] },
235
+ { type: stack, direction: vertical, gap: xs, children: [
236
+ { type: typography, variant: caption, content: (str/concat @config.setpointLabel ": " (math/round @entity.setpoint 1)) },
237
+ { type: range-slider, min: @config.setpointMin, max: @config.setpointMax, step: @config.setpointStep, value: @entity.setpoint, showTooltip: true, action: "SET_POINT" }
238
+ ] },
239
+ { type: stack, direction: vertical, gap: xs, children: [
240
+ { type: typography, variant: caption, content: (str/concat @config.rateLabel ": " (math/round @entity.rate 2)) },
241
+ { type: range-slider, min: @config.rateMin, max: @config.rateMax, step: @config.rateStep, value: @entity.rate, showTooltip: true, action: "SET_RATE" }
242
+ ] },
243
+ { type: math-canvas, width: @config.width, height: @config.height, title: "", xMin: 0, xMax: @config.duration, yMin: @config.valueMin, yMax: @config.valueMax, showAxes: true, showGrid: true, gridStep: @config.gridStep, curves: @entity.curves, points: [], vectors: [], shapes: [], interactive: false, animate: false },
244
+ { type: typography, variant: body, content: (str/concat "t = " (math/round @entity.t 1) " · " @config.valueLabel " = " (math/round @entity.value 2) " · deviation: " (math/round (- @entity.value @entity.setpoint) 2)) }
245
+ ] }
246
+ ]
247
+ })
248
+ (emit SETPOINT_CHANGED { setpoint: @entity.setpoint })
249
+
250
+ SET_RATE -> idle when (== @entity.active true)
251
+ (set @entity.rate (math/clamp ?value @config.rateMin @config.rateMax))
252
+ (render-ui main {
253
+ type: box
254
+ padding: md
255
+ children: [
256
+ { type: stack, direction: vertical, gap: md, children: [
257
+ { type: typography, variant: h4, content: @entity.title },
258
+ { type: typography, variant: body, content: @config.taskText },
259
+ { type: stack, direction: horizontal, gap: sm, children: [
260
+ { type: button, action: RUN, label: "Run", variant: primary, disabled: (if (and (== @entity.running false) (< @entity.t @config.duration)) false true) },
261
+ { type: button, action: PAUSE, label: "Pause", variant: secondary, disabled: (if @entity.running false true) },
262
+ { type: button, action: RESET, label: "Reset", variant: ghost },
263
+ { type: button, action: SHOCK, actionPayload: { delta: @config.shockSize }, label: @config.shockUpLabel, variant: secondary, size: sm },
264
+ { type: button, action: SHOCK, actionPayload: { delta: (- 0 @config.shockSize) }, label: @config.shockDownLabel, variant: secondary, size: sm }
265
+ ] },
266
+ { type: stack, direction: vertical, gap: xs, children: [
267
+ { type: typography, variant: caption, content: (str/concat @config.setpointLabel ": " (math/round @entity.setpoint 1)) },
268
+ { type: range-slider, min: @config.setpointMin, max: @config.setpointMax, step: @config.setpointStep, value: @entity.setpoint, showTooltip: true, action: "SET_POINT" }
269
+ ] },
270
+ { type: stack, direction: vertical, gap: xs, children: [
271
+ { type: typography, variant: caption, content: (str/concat @config.rateLabel ": " (math/round @entity.rate 2)) },
272
+ { type: range-slider, min: @config.rateMin, max: @config.rateMax, step: @config.rateStep, value: @entity.rate, showTooltip: true, action: "SET_RATE" }
273
+ ] },
274
+ { type: math-canvas, width: @config.width, height: @config.height, title: "", xMin: 0, xMax: @config.duration, yMin: @config.valueMin, yMax: @config.valueMax, showAxes: true, showGrid: true, gridStep: @config.gridStep, curves: @entity.curves, points: [], vectors: [], shapes: [], interactive: false, animate: false },
275
+ { type: typography, variant: body, content: (str/concat "t = " (math/round @entity.t 1) " · " @config.valueLabel " = " (math/round @entity.value 2) " · deviation: " (math/round (- @entity.value @entity.setpoint) 2)) }
276
+ ] }
277
+ ]
278
+ })
279
+ (emit RATE_CHANGED { rate: @entity.rate })
280
+
281
+ SHOCK -> idle when (== @entity.active true)
282
+ (set @entity.value (+ @entity.value ?delta))
283
+ (set @entity.traceSamples (array/append @entity.traceSamples { x: @entity.t, y: @entity.value }))
284
+ (set @entity.curves [
285
+ { label: @config.setpointLabel, color: @config.setpointColor, samples: [ { x: 0, y: @entity.setpoint }, { x: @config.duration, y: @entity.setpoint } ] },
286
+ { label: @config.valueLabel, color: @config.valueColor, samples: @entity.traceSamples }
287
+ ])
288
+ (render-ui main {
289
+ type: box
290
+ padding: md
291
+ children: [
292
+ { type: stack, direction: vertical, gap: md, children: [
293
+ { type: typography, variant: h4, content: @entity.title },
294
+ { type: typography, variant: body, content: @config.taskText },
295
+ { type: stack, direction: horizontal, gap: sm, children: [
296
+ { type: button, action: RUN, label: "Run", variant: primary, disabled: (if (and (== @entity.running false) (< @entity.t @config.duration)) false true) },
297
+ { type: button, action: PAUSE, label: "Pause", variant: secondary, disabled: (if @entity.running false true) },
298
+ { type: button, action: RESET, label: "Reset", variant: ghost },
299
+ { type: button, action: SHOCK, actionPayload: { delta: @config.shockSize }, label: @config.shockUpLabel, variant: secondary, size: sm },
300
+ { type: button, action: SHOCK, actionPayload: { delta: (- 0 @config.shockSize) }, label: @config.shockDownLabel, variant: secondary, size: sm }
301
+ ] },
302
+ { type: stack, direction: vertical, gap: xs, children: [
303
+ { type: typography, variant: caption, content: (str/concat @config.setpointLabel ": " (math/round @entity.setpoint 1)) },
304
+ { type: range-slider, min: @config.setpointMin, max: @config.setpointMax, step: @config.setpointStep, value: @entity.setpoint, showTooltip: true, action: "SET_POINT" }
305
+ ] },
306
+ { type: stack, direction: vertical, gap: xs, children: [
307
+ { type: typography, variant: caption, content: (str/concat @config.rateLabel ": " (math/round @entity.rate 2)) },
308
+ { type: range-slider, min: @config.rateMin, max: @config.rateMax, step: @config.rateStep, value: @entity.rate, showTooltip: true, action: "SET_RATE" }
309
+ ] },
310
+ { type: math-canvas, width: @config.width, height: @config.height, title: "", xMin: 0, xMax: @config.duration, yMin: @config.valueMin, yMax: @config.valueMax, showAxes: true, showGrid: true, gridStep: @config.gridStep, curves: @entity.curves, points: [], vectors: [], shapes: [], interactive: false, animate: false },
311
+ { type: typography, variant: body, content: (str/concat "t = " (math/round @entity.t 1) " · " @config.valueLabel " = " (math/round @entity.value 2) " · deviation: " (math/round (- @entity.value @entity.setpoint) 2)) }
312
+ ] }
313
+ ]
314
+ })
315
+ (emit SHOCK_APPLIED { delta: ?delta, value: @entity.value, deviation: (- @entity.value @entity.setpoint) })
316
+ }
317
+
318
+ ticks {
319
+ perturbTick every 100ms
320
+ when (and (== @entity.active true) (and (== @entity.running true) (< @entity.t @config.duration)))
321
+ (set @entity.t (math/min @config.duration (+ @entity.t 0.1)))
322
+ (set @entity.value (+ @entity.value (* @entity.rate (- @entity.setpoint @entity.value) 0.1)))
323
+ (set @entity.traceSamples (array/append @entity.traceSamples { x: @entity.t, y: @entity.value }))
324
+ (set @entity.curves [
325
+ { label: @config.setpointLabel, color: @config.setpointColor, samples: [ { x: 0, y: @entity.setpoint }, { x: @config.duration, y: @entity.setpoint } ] },
326
+ { label: @config.valueLabel, color: @config.valueColor, samples: @entity.traceSamples }
327
+ ])
328
+ (set @entity.running (if (>= @entity.t @config.duration) false true))
329
+ }
330
+
331
+ listens {
332
+ MODE_SELECTED {
333
+ mode : string
334
+ }
335
+ @description "Lab router broadcast naming the active mode; this instrument renders when the mode equals matchMode, otherwise renders null."
336
+ @tier "domain"
337
+ RUN {
338
+ }
339
+ @description "Learner started (or resumed) the regulation loop; the trace draws live until Pause or the configured duration."
340
+ @tier "domain"
341
+ PAUSE {
342
+ }
343
+ @description "Learner froze the simulation mid-run; shocks and slider changes still apply to the frozen state."
344
+ @tier "domain"
345
+ RESET {
346
+ }
347
+ @description "Learner restored the quantity, setpoint, rate, and clock to their configured starting values."
348
+ @tier "domain"
349
+ SET_POINT {
350
+ value : number
351
+ }
352
+ @description "Learner moved the equilibrium setpoint — mid-run the system visibly chases the new target."
353
+ @tier "domain"
354
+ SET_RATE {
355
+ value : number
356
+ }
357
+ @description "Learner retuned the recovery rate — higher snaps back fast, lower drifts sluggishly."
358
+ @tier "domain"
359
+ SHOCK {
360
+ delta : number
361
+ }
362
+ @description "Learner knocked the quantity up (positive) or down (negative) to disturb the equilibrium and watch the recovery."
363
+ @tier "domain"
364
+ }
365
+
366
+ emits {
367
+ RUN_TOGGLED -> external {
368
+ running : boolean
369
+ }
370
+ @description "The simulation was started or paused — a composed listener (readout, grader) can subscribe; a harmless no-op when the atom runs standalone."
371
+ @tier "domain"
372
+ SIM_RESET -> external {
373
+ valueStart : number
374
+ }
375
+ @description "The learner reset the system to its configured starting state."
376
+ @tier "domain"
377
+ SETPOINT_CHANGED -> external {
378
+ setpoint : number
379
+ }
380
+ @description "The equilibrium target after a slider change."
381
+ @tier "domain"
382
+ RATE_CHANGED -> external {
383
+ rate : number
384
+ }
385
+ @description "The recovery rate after a slider change."
386
+ @tier "domain"
387
+ SHOCK_APPLIED -> external {
388
+ delta : number
389
+ value : number
390
+ deviation : number
391
+ }
392
+ @description "A disturbance was injected: the shock size, the quantity right after it, and its deviation from the setpoint."
393
+ @synonyms "homeostasis, negative feedback, equilibrium, shock and recovery, thermostat, resilience"
394
+ @tier "domain"
395
+ }
396
+
397
+ config {
398
+ matchMode : string = ""
399
+ @label "Match Mode"
400
+ @description "When composed behind a lab router, the MODE_SELECTED mode value this instrument responds to. Empty string means standalone — render immediately on INIT."
401
+ @tier "presentation"
402
+ title : string = "Equilibrium & Shock"
403
+ @label "Title"
404
+ @description "Title shown above the simulation."
405
+ @tier "presentation"
406
+ taskText : string = "Run the system, shock it off its setpoint, and watch it recover — then move the setpoint mid-run."
407
+ @label "Task Text"
408
+ @description "One-sentence statement of what to explore."
409
+ @tier "domain"
410
+ valueLabel : string = "Temperature"
411
+ @label "Value Label"
412
+ @description "Display name of the regulated quantity."
413
+ @tier "domain"
414
+ setpointLabel : string = "Setpoint"
415
+ @label "Setpoint Label"
416
+ @description "Display name of the equilibrium target."
417
+ @tier "domain"
418
+ rateLabel : string = "Recovery rate"
419
+ @label "Rate Label"
420
+ @description "Display name of the relaxation-rate slider."
421
+ @tier "domain"
422
+ valueStart : number = 37
423
+ @label "Value Start"
424
+ @tier "domain"
425
+ setpointDefault : number = 37
426
+ @label "Setpoint Default"
427
+ @tier "domain"
428
+ setpointMin : number = 30
429
+ @label "Setpoint Min"
430
+ @tier "domain"
431
+ setpointMax : number = 44
432
+ @label "Setpoint Max"
433
+ @tier "domain"
434
+ setpointStep : number = 0.5
435
+ @label "Setpoint Step"
436
+ @tier "presentation"
437
+ rateDefault : number = 0.8
438
+ @label "Rate Default"
439
+ @tier "domain"
440
+ rateMin : number = 0.05
441
+ @label "Rate Min"
442
+ @tier "domain"
443
+ rateMax : number = 3
444
+ @label "Rate Max"
445
+ @tier "domain"
446
+ rateStep : number = 0.05
447
+ @label "Rate Step"
448
+ @tier "presentation"
449
+ shockSize : number = 4
450
+ @label "Shock Size"
451
+ @description "How far a shock button knocks the quantity from its current value."
452
+ @tier "domain"
453
+ shockUpLabel : string = "+ Shock up"
454
+ @label "Shock Up Label"
455
+ @tier "presentation"
456
+ shockDownLabel : string = "− Shock down"
457
+ @label "Shock Down Label"
458
+ @tier "presentation"
459
+ duration : number = 20
460
+ @label "Duration"
461
+ @description "Simulated seconds before the run stops automatically."
462
+ @tier "domain"
463
+ valueMin : number = 28
464
+ @label "Value Min"
465
+ @description "Lower bound of the chart's y axis."
466
+ @tier "presentation"
467
+ valueMax : number = 46
468
+ @label "Value Max"
469
+ @description "Upper bound of the chart's y axis."
470
+ @tier "presentation"
471
+ gridStep : number = 2
472
+ @label "Grid Step"
473
+ @tier "presentation"
474
+ valueColor : string = "#dc2626"
475
+ @label "Value Color"
476
+ @tier "presentation"
477
+ setpointColor : string = "#94a3b8"
478
+ @label "Setpoint Color"
479
+ @tier "presentation"
480
+ autoRun : boolean = true
481
+ @label "Auto Run"
482
+ @description "Whether the simulation starts running immediately on load."
483
+ @tier "domain"
484
+ width : number = 600
485
+ @label "Width"
486
+ @tier "presentation"
487
+ height : number = 360
488
+ @label "Height"
489
+ @tier "presentation"
490
+ }
491
+ }
492
+
493
+ page "/learn-perturb" as PerturbPage -> PerturbSim
494
+ }