@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,3678 @@
1
+ {
2
+ "description": "Generic monotone-accumulation dosing instrument — the learner adds a quantity in large or small config-declared increments (or lets it auto-drip on its own inline clock) and watches an accumulated dose climb through a config-declared roster of bands/zones (thresholds, labels, colors all config), rendered as a reservoir/source vessel pair plus a dose-history trace on a canvas. Crossing into a terminal band is irreversible — done latches true and only Reset revives it. Standalone by default it renders its own control strip AND scene canvas; set showCanvas false to embed only the control strip (via @trait.<name>) beneath a composed sibling trait that owns the domain-accurate scene — see std-chem-titration for the transport-sibling shape. Behind a lab router set matchMode and it renders only when MODE_SELECTED matches.",
3
+ "ledger": {
4
+ "entries": {
5
+ "ent_01M0CGZ8SP7WAX9ZZT3E63FRWT": {
6
+ "bakedName": "DoserScene",
7
+ "curName": "DoserScene",
8
+ "id": "ent_01M0CGZ8SP7WAX9ZZT3E63FRWT",
9
+ "kind": "entity",
10
+ "owner": "workspace",
11
+ "renames": []
12
+ },
13
+ "evt_01M0CGZ8SP47VR9A9YFGEFRMH1": {
14
+ "bakedName": "ADD_LARGE",
15
+ "curName": "ADD_LARGE",
16
+ "id": "evt_01M0CGZ8SP47VR9A9YFGEFRMH1",
17
+ "kind": "event",
18
+ "owner": "workspace",
19
+ "parent": "trt_01M0CGZ8SPD6WYV3H0J6SV7NBD",
20
+ "renames": []
21
+ },
22
+ "evt_01M0CGZ8SP7AZV95SQDK8RN1ZT": {
23
+ "bakedName": "TOGGLE_DRIP",
24
+ "curName": "TOGGLE_DRIP",
25
+ "id": "evt_01M0CGZ8SP7AZV95SQDK8RN1ZT",
26
+ "kind": "event",
27
+ "owner": "workspace",
28
+ "parent": "trt_01M0CGZ8SPD6WYV3H0J6SV7NBD",
29
+ "renames": []
30
+ },
31
+ "evt_01M0CGZ8SP8J631040FCXA6CWV": {
32
+ "bakedName": "DOSE_RESET",
33
+ "curName": "DOSE_RESET",
34
+ "id": "evt_01M0CGZ8SP8J631040FCXA6CWV",
35
+ "kind": "event",
36
+ "owner": "workspace",
37
+ "parent": "trt_01M0CGZ8SPD6WYV3H0J6SV7NBD",
38
+ "renames": []
39
+ },
40
+ "evt_01M0CGZ8SPACRAV5BKCG4WH64Y": {
41
+ "bakedName": "ADD_SMALL",
42
+ "curName": "ADD_SMALL",
43
+ "id": "evt_01M0CGZ8SPACRAV5BKCG4WH64Y",
44
+ "kind": "event",
45
+ "owner": "workspace",
46
+ "parent": "trt_01M0CGZ8SPD6WYV3H0J6SV7NBD",
47
+ "renames": []
48
+ },
49
+ "evt_01M0CGZ8SPCJWD38ZCMJGGA4EF": {
50
+ "bakedName": "MODE_SELECTED",
51
+ "curName": "MODE_SELECTED",
52
+ "id": "evt_01M0CGZ8SPCJWD38ZCMJGGA4EF",
53
+ "kind": "event",
54
+ "owner": "workspace",
55
+ "parent": "trt_01M0CGZ8SPD6WYV3H0J6SV7NBD",
56
+ "renames": []
57
+ },
58
+ "evt_01M0CGZ8SPH5C42ESXGKNMKQMQ": {
59
+ "bakedName": "INIT",
60
+ "curName": "INIT",
61
+ "id": "evt_01M0CGZ8SPH5C42ESXGKNMKQMQ",
62
+ "kind": "event",
63
+ "owner": "workspace",
64
+ "parent": "trt_01M0CGZ8SPD6WYV3H0J6SV7NBD",
65
+ "renames": []
66
+ },
67
+ "evt_01M0CGZ8SPNYYB1MGF8J852CMC": {
68
+ "bakedName": "DOSE_ADDED",
69
+ "curName": "DOSE_ADDED",
70
+ "id": "evt_01M0CGZ8SPNYYB1MGF8J852CMC",
71
+ "kind": "event",
72
+ "owner": "workspace",
73
+ "parent": "trt_01M0CGZ8SPD6WYV3H0J6SV7NBD",
74
+ "renames": []
75
+ },
76
+ "evt_01M0CGZ8SPY3RGTNR91KY2T7FK": {
77
+ "bakedName": "DOSER_UPDATED",
78
+ "curName": "DOSER_UPDATED",
79
+ "id": "evt_01M0CGZ8SPY3RGTNR91KY2T7FK",
80
+ "kind": "event",
81
+ "owner": "workspace",
82
+ "parent": "trt_01M0CGZ8SPD6WYV3H0J6SV7NBD",
83
+ "renames": []
84
+ },
85
+ "evt_01M0CGZ8SPYR8QYSEEQF1PQ6D8": {
86
+ "bakedName": "RESET",
87
+ "curName": "RESET",
88
+ "id": "evt_01M0CGZ8SPYR8QYSEEQF1PQ6D8",
89
+ "kind": "event",
90
+ "owner": "workspace",
91
+ "parent": "trt_01M0CGZ8SPD6WYV3H0J6SV7NBD",
92
+ "renames": []
93
+ },
94
+ "orb_01M0CGZ8SPVWFV0VMERY7EXKM3": {
95
+ "bakedName": "LearnDoserOrbital",
96
+ "curName": "LearnDoserOrbital",
97
+ "id": "orb_01M0CGZ8SPVWFV0VMERY7EXKM3",
98
+ "kind": "orbital",
99
+ "owner": "workspace",
100
+ "renames": []
101
+ },
102
+ "pag_01M0CGZ8SQMYB1J062HC0XSXFG": {
103
+ "bakedName": "LearnDoserPage",
104
+ "curName": "LearnDoserPage",
105
+ "id": "pag_01M0CGZ8SQMYB1J062HC0XSXFG",
106
+ "kind": "page",
107
+ "owner": "workspace",
108
+ "renames": []
109
+ },
110
+ "trt_01M0CGZ8SPD6WYV3H0J6SV7NBD": {
111
+ "bakedName": "LearnDoserSim",
112
+ "curName": "LearnDoserSim",
113
+ "id": "trt_01M0CGZ8SPD6WYV3H0J6SV7NBD",
114
+ "kind": "trait",
115
+ "owner": "workspace",
116
+ "renames": []
117
+ }
118
+ },
119
+ "schemaVersion": 1
120
+ },
121
+ "name": "std-learn-doser",
122
+ "orbitals": [
123
+ {
124
+ "entity": {
125
+ "fields": [
126
+ {
127
+ "name": "id",
128
+ "required": true,
129
+ "type": "string"
130
+ },
131
+ {
132
+ "default": false,
133
+ "name": "active",
134
+ "type": "boolean"
135
+ },
136
+ {
137
+ "name": "title",
138
+ "type": "string"
139
+ },
140
+ {
141
+ "default": false,
142
+ "name": "done",
143
+ "type": "boolean"
144
+ },
145
+ {
146
+ "default": false,
147
+ "name": "running",
148
+ "type": "boolean"
149
+ },
150
+ {
151
+ "default": 0.0,
152
+ "name": "elapsedMs",
153
+ "type": "number"
154
+ },
155
+ {
156
+ "default": 0.0,
157
+ "name": "dose",
158
+ "type": "number"
159
+ },
160
+ {
161
+ "name": "bandLabel",
162
+ "type": "string"
163
+ },
164
+ {
165
+ "name": "bandColor",
166
+ "type": "string"
167
+ },
168
+ {
169
+ "name": "narration",
170
+ "type": "string"
171
+ },
172
+ {
173
+ "items": {
174
+ "properties": {
175
+ "divider": {
176
+ "name": "divider",
177
+ "required": false,
178
+ "type": "string",
179
+ "values": [
180
+ "none",
181
+ "solid",
182
+ "dashed",
183
+ "dotted"
184
+ ]
185
+ },
186
+ "height": {
187
+ "name": "height",
188
+ "required": false,
189
+ "type": "number"
190
+ },
191
+ "label": {
192
+ "name": "label",
193
+ "required": false,
194
+ "type": "string"
195
+ },
196
+ "level": {
197
+ "name": "level",
198
+ "required": false,
199
+ "type": "number"
200
+ },
201
+ "levelColor": {
202
+ "name": "levelColor",
203
+ "required": false,
204
+ "type": "string"
205
+ },
206
+ "width": {
207
+ "name": "width",
208
+ "required": false,
209
+ "type": "number"
210
+ },
211
+ "x": {
212
+ "name": "x",
213
+ "required": false,
214
+ "type": "number"
215
+ },
216
+ "y": {
217
+ "name": "y",
218
+ "required": false,
219
+ "type": "number"
220
+ }
221
+ },
222
+ "type": "object"
223
+ },
224
+ "name": "containers",
225
+ "type": "array"
226
+ },
227
+ {
228
+ "items": {
229
+ "properties": {
230
+ "label": {
231
+ "name": "label",
232
+ "required": false,
233
+ "type": "string"
234
+ },
235
+ "value": {
236
+ "name": "value",
237
+ "required": false,
238
+ "type": "string"
239
+ }
240
+ },
241
+ "type": "object"
242
+ },
243
+ "name": "readouts",
244
+ "type": "array"
245
+ },
246
+ {
247
+ "items": {
248
+ "properties": {
249
+ "x": {
250
+ "name": "x",
251
+ "required": true,
252
+ "type": "number"
253
+ },
254
+ "y": {
255
+ "name": "y",
256
+ "required": true,
257
+ "type": "number"
258
+ }
259
+ },
260
+ "type": "object"
261
+ },
262
+ "name": "doseSeries",
263
+ "type": "array"
264
+ }
265
+ ],
266
+ "id": "ent_01M0CGZ8SP7WAX9ZZT3E63FRWT",
267
+ "name": "DoserScene",
268
+ "persistence": "runtime",
269
+ "shared": true
270
+ },
271
+ "id": "orb_01M0CGZ8SPVWFV0VMERY7EXKM3",
272
+ "name": "LearnDoserOrbital",
273
+ "pages": [
274
+ {
275
+ "id": "pag_01M0CGZ8SQMYB1J062HC0XSXFG",
276
+ "name": "LearnDoserPage",
277
+ "path": "/learn-doser",
278
+ "traits": [
279
+ {
280
+ "ref": "LearnDoserSim",
281
+ "refId": "trt_01M0CGZ8SPD6WYV3H0J6SV7NBD"
282
+ }
283
+ ]
284
+ }
285
+ ],
286
+ "traits": [
287
+ {
288
+ "category": "interaction",
289
+ "config": {
290
+ "autoDrip": {
291
+ "default": false,
292
+ "description": "When true, INIT/MODE_SELECTED/Reset start the drip clock adding a small increment each interval; toggle live with the Auto-dose/Pause button.",
293
+ "label": "Auto Drip",
294
+ "tier": "domain",
295
+ "type": "boolean"
296
+ },
297
+ "backgroundColor": {
298
+ "default": "#fafafa",
299
+ "description": "Canvas background color.",
300
+ "label": "Background Color",
301
+ "tier": "presentation",
302
+ "type": "string"
303
+ },
304
+ "bands": {
305
+ "default": [
306
+ {
307
+ "color": "#94a3b8",
308
+ "label": "Low",
309
+ "terminal": false,
310
+ "upperBound": 50.0
311
+ },
312
+ {
313
+ "color": "#16a34a",
314
+ "label": "High",
315
+ "terminal": true,
316
+ "upperBound": 999999999.0
317
+ }
318
+ ],
319
+ "description": "Ordered ascending roster of dose bands/zones — each carries the dose upper bound it covers, a label, a color, and whether crossing into it is terminal (irreversible; sets done true until Reset). The accumulated dose is classified into the first band whose upperBound it does not exceed, falling through to the last band beyond all bounds.",
320
+ "items": {
321
+ "properties": {
322
+ "color": {
323
+ "name": "color",
324
+ "required": true,
325
+ "type": "string"
326
+ },
327
+ "label": {
328
+ "name": "label",
329
+ "required": true,
330
+ "type": "string"
331
+ },
332
+ "terminal": {
333
+ "name": "terminal",
334
+ "required": false,
335
+ "type": "boolean"
336
+ },
337
+ "upperBound": {
338
+ "name": "upperBound",
339
+ "required": true,
340
+ "type": "number"
341
+ }
342
+ },
343
+ "type": "object"
344
+ },
345
+ "label": "Bands",
346
+ "synonyms": "zone, band, threshold, region, stage, phase, tier",
347
+ "tier": "domain",
348
+ "type": "[DoserBand]"
349
+ },
350
+ "capacity": {
351
+ "default": 100.0,
352
+ "description": "Maximum total dose the source can deliver; the source vessel drains to empty and additions clamp once accumulated dose reaches this cap.",
353
+ "label": "Capacity",
354
+ "tier": "domain",
355
+ "type": "number"
356
+ },
357
+ "dripIntervalMs": {
358
+ "default": 500.0,
359
+ "description": "Milliseconds of running clock per auto-drip increment — the 32ms base tick accumulates elapsed time and adds a small step each time this interval elapses.",
360
+ "label": "Drip Interval (ms)",
361
+ "tier": "domain",
362
+ "type": "number"
363
+ },
364
+ "height": {
365
+ "default": 400.0,
366
+ "description": "Canvas height in pixels.",
367
+ "label": "Height",
368
+ "tier": "presentation",
369
+ "type": "number"
370
+ },
371
+ "historyLength": {
372
+ "default": 300.0,
373
+ "description": "Maximum points kept in the dose-history trace; older points drop off once exceeded.",
374
+ "label": "Dose History",
375
+ "tier": "domain",
376
+ "type": "number"
377
+ },
378
+ "matchMode": {
379
+ "default": "",
380
+ "description": "When composed behind a lab router, the MODE_SELECTED mode value this instrument responds to. Empty string means standalone — render immediately on INIT.",
381
+ "label": "Match Mode",
382
+ "tier": "presentation",
383
+ "type": "string"
384
+ },
385
+ "quantityLabel": {
386
+ "default": "Dose",
387
+ "description": "Label used for the accumulated-quantity readout and in the narration line.",
388
+ "label": "Quantity Label",
389
+ "synonyms": "quantity, amount, dose, volume, level",
390
+ "tier": "domain",
391
+ "type": "string"
392
+ },
393
+ "reservoirLabel": {
394
+ "default": "Reservoir",
395
+ "description": "Label for the vessel that fills as dose accumulates.",
396
+ "label": "Reservoir Label",
397
+ "synonyms": "reservoir, beaker, tank, container, receiving vessel",
398
+ "tier": "presentation",
399
+ "type": "string"
400
+ },
401
+ "showCanvas": {
402
+ "default": true,
403
+ "description": "When true (the default, standalone use) the instrument renders its own reservoir/source canvas and narration below the control strip. Set false when a domain sibling trait composes this atom via @rebindable and owns the accurate scene render itself — then only the control strip (add/drip/reset buttons) embeds via @trait.<name>, avoiding a duplicate canvas.",
404
+ "label": "Show Canvas",
405
+ "tier": "presentation",
406
+ "type": "boolean"
407
+ },
408
+ "sourceColor": {
409
+ "default": "#60a5fa",
410
+ "description": "Fill color for the source vessel.",
411
+ "label": "Source Color",
412
+ "tier": "presentation",
413
+ "type": "string"
414
+ },
415
+ "sourceLabel": {
416
+ "default": "Source",
417
+ "description": "Label for the vessel that drains as dose is delivered from it.",
418
+ "label": "Source Label",
419
+ "synonyms": "source, burette, supply, dispenser",
420
+ "tier": "presentation",
421
+ "type": "string"
422
+ },
423
+ "stepLarge": {
424
+ "default": 5.0,
425
+ "description": "Quantity added per press of the coarse add button.",
426
+ "label": "Large Step",
427
+ "tier": "domain",
428
+ "type": "number"
429
+ },
430
+ "stepSmall": {
431
+ "default": 1.0,
432
+ "description": "Quantity added per press of the fine add button, and per auto-drip tick — for precise control near a band boundary.",
433
+ "label": "Small Step",
434
+ "tier": "domain",
435
+ "type": "number"
436
+ },
437
+ "title": {
438
+ "default": "Doser",
439
+ "description": "Title shown above the instrument.",
440
+ "label": "Title",
441
+ "tier": "presentation",
442
+ "type": "string"
443
+ },
444
+ "unit": {
445
+ "default": "",
446
+ "description": "Unit suffix appended to the step-size button labels (e.g. \"mL\", \"mg\", \"units\"); empty means no unit shown.",
447
+ "label": "Unit",
448
+ "tier": "domain",
449
+ "type": "string"
450
+ },
451
+ "width": {
452
+ "default": 600.0,
453
+ "description": "Canvas width in pixels.",
454
+ "label": "Width",
455
+ "tier": "presentation",
456
+ "type": "number"
457
+ },
458
+ "zoneReadoutLabel": {
459
+ "default": "Zone",
460
+ "description": "Label used for the current-band readout row.",
461
+ "label": "Zone Readout Label",
462
+ "tier": "presentation",
463
+ "type": "string"
464
+ }
465
+ },
466
+ "emits": [
467
+ {
468
+ "description": "Fires after every dose increase — from the small/large add buttons or an auto-drip tick — with the accumulated dose and its classified band. A composed sibling trait transitions on it to recompute a domain-specific response (e.g. a chemistry pH curve) and repaint the scene it owns. A harmless no-op when the atom runs standalone.",
469
+ "event": "DOSE_ADDED",
470
+ "eventId": "evt_01M0CGZ8SPNYYB1MGF8J852CMC",
471
+ "payloadSchema": [
472
+ {
473
+ "name": "dose",
474
+ "type": "number"
475
+ },
476
+ {
477
+ "name": "bandLabel",
478
+ "type": "string"
479
+ },
480
+ {
481
+ "name": "bandColor",
482
+ "type": "string"
483
+ },
484
+ {
485
+ "name": "done",
486
+ "type": "boolean"
487
+ }
488
+ ],
489
+ "scope": "external",
490
+ "synonyms": "dose added, increment, add, drip, titrant added, quantity added",
491
+ "tier": "domain"
492
+ },
493
+ {
494
+ "description": "Fires on Reset after the dose, band, and done flag re-zero. A composed sibling trait reseeds its own domain state from config on it. A harmless no-op when the atom runs standalone.",
495
+ "event": "DOSE_RESET",
496
+ "eventId": "evt_01M0CGZ8SP8J631040FCXA6CWV",
497
+ "scope": "external",
498
+ "synonyms": "reset, reseed, restart, clear",
499
+ "tier": "domain"
500
+ },
501
+ {
502
+ "description": "Fires on INIT/MODE_SELECTED/auto-drip toggle with the transport-level state — running flag, dose, current band, done — so a composed sibling trait can repaint its own shell. A harmless no-op when the atom runs standalone.",
503
+ "event": "DOSER_UPDATED",
504
+ "eventId": "evt_01M0CGZ8SPY3RGTNR91KY2T7FK",
505
+ "payloadSchema": [
506
+ {
507
+ "name": "running",
508
+ "type": "boolean"
509
+ },
510
+ {
511
+ "name": "dose",
512
+ "type": "number"
513
+ },
514
+ {
515
+ "name": "bandLabel",
516
+ "type": "string"
517
+ },
518
+ {
519
+ "name": "done",
520
+ "type": "boolean"
521
+ }
522
+ ],
523
+ "scope": "external",
524
+ "synonyms": "drip toggle, running state, auto-dose",
525
+ "tier": "domain"
526
+ }
527
+ ],
528
+ "entityContract": {
529
+ "provides": [
530
+ "active",
531
+ "bandColor",
532
+ "bandLabel",
533
+ "containers",
534
+ "done",
535
+ "dose",
536
+ "doseSeries",
537
+ "elapsedMs",
538
+ "narration",
539
+ "readouts",
540
+ "running",
541
+ "title"
542
+ ],
543
+ "requires": []
544
+ },
545
+ "entityRebindable": true,
546
+ "entityRefIds": {
547
+ "DoserScene": "ent_01M0CGZ8SP7WAX9ZZT3E63FRWT"
548
+ },
549
+ "id": "trt_01M0CGZ8SPD6WYV3H0J6SV7NBD",
550
+ "linkedEntity": "DoserScene",
551
+ "linkedEntityId": "ent_01M0CGZ8SP7WAX9ZZT3E63FRWT",
552
+ "name": "LearnDoserSim",
553
+ "scope": "instance",
554
+ "stateMachine": {
555
+ "events": [
556
+ {
557
+ "id": "evt_01M0CGZ8SPH5C42ESXGKNMKQMQ",
558
+ "key": "INIT",
559
+ "name": "Initialize"
560
+ },
561
+ {
562
+ "description": "Lab router broadcast naming the active mode; this instrument renders when the mode equals matchMode, otherwise renders null.",
563
+ "id": "evt_01M0CGZ8SPCJWD38ZCMJGGA4EF",
564
+ "key": "MODE_SELECTED",
565
+ "name": "Mode Selected",
566
+ "payloadSchema": [
567
+ {
568
+ "name": "mode",
569
+ "type": "string"
570
+ }
571
+ ],
572
+ "tier": "domain"
573
+ },
574
+ {
575
+ "id": "evt_01M0CGZ8SPACRAV5BKCG4WH64Y",
576
+ "key": "ADD_SMALL",
577
+ "name": "Add Small"
578
+ },
579
+ {
580
+ "id": "evt_01M0CGZ8SP47VR9A9YFGEFRMH1",
581
+ "key": "ADD_LARGE",
582
+ "name": "Add Large"
583
+ },
584
+ {
585
+ "id": "evt_01M0CGZ8SP7AZV95SQDK8RN1ZT",
586
+ "key": "TOGGLE_DRIP",
587
+ "name": "Toggle Drip"
588
+ },
589
+ {
590
+ "id": "evt_01M0CGZ8SPYR8QYSEEQF1PQ6D8",
591
+ "key": "RESET",
592
+ "name": "Reset"
593
+ },
594
+ {
595
+ "description": "Fires after every dose increase — from the small/large add buttons or an auto-drip tick — with the accumulated dose and its classified band. A composed sibling trait transitions on it to recompute a domain-specific response (e.g. a chemistry pH curve) and repaint the scene it owns. A harmless no-op when the atom runs standalone.",
596
+ "id": "evt_01M0CGZ8SPNYYB1MGF8J852CMC",
597
+ "key": "DOSE_ADDED",
598
+ "name": "Dose Added",
599
+ "payloadSchema": [
600
+ {
601
+ "name": "dose",
602
+ "type": "number"
603
+ },
604
+ {
605
+ "name": "bandLabel",
606
+ "type": "string"
607
+ },
608
+ {
609
+ "name": "bandColor",
610
+ "type": "string"
611
+ },
612
+ {
613
+ "name": "done",
614
+ "type": "boolean"
615
+ }
616
+ ],
617
+ "synonyms": "dose added, increment, add, drip, titrant added, quantity added",
618
+ "tier": "domain"
619
+ },
620
+ {
621
+ "description": "Fires on Reset after the dose, band, and done flag re-zero. A composed sibling trait reseeds its own domain state from config on it. A harmless no-op when the atom runs standalone.",
622
+ "id": "evt_01M0CGZ8SP8J631040FCXA6CWV",
623
+ "key": "DOSE_RESET",
624
+ "name": "Dose Reset",
625
+ "synonyms": "reset, reseed, restart, clear",
626
+ "tier": "domain"
627
+ },
628
+ {
629
+ "description": "Fires on INIT/MODE_SELECTED/auto-drip toggle with the transport-level state — running flag, dose, current band, done — so a composed sibling trait can repaint its own shell. A harmless no-op when the atom runs standalone.",
630
+ "id": "evt_01M0CGZ8SPY3RGTNR91KY2T7FK",
631
+ "key": "DOSER_UPDATED",
632
+ "name": "Doser Updated",
633
+ "payloadSchema": [
634
+ {
635
+ "name": "running",
636
+ "type": "boolean"
637
+ },
638
+ {
639
+ "name": "dose",
640
+ "type": "number"
641
+ },
642
+ {
643
+ "name": "bandLabel",
644
+ "type": "string"
645
+ },
646
+ {
647
+ "name": "done",
648
+ "type": "boolean"
649
+ }
650
+ ],
651
+ "synonyms": "drip toggle, running state, auto-dose",
652
+ "tier": "domain"
653
+ }
654
+ ],
655
+ "states": [
656
+ {
657
+ "isInitial": true,
658
+ "name": "idle"
659
+ }
660
+ ],
661
+ "transitions": [
662
+ {
663
+ "effects": [
664
+ [
665
+ "set",
666
+ "@entity.active",
667
+ true
668
+ ],
669
+ [
670
+ "set",
671
+ "@entity.title",
672
+ "@config.title"
673
+ ],
674
+ [
675
+ "set",
676
+ "@entity.dose",
677
+ 0.0
678
+ ],
679
+ [
680
+ "set",
681
+ "@entity.done",
682
+ false
683
+ ],
684
+ [
685
+ "set",
686
+ "@entity.running",
687
+ "@config.autoDrip"
688
+ ],
689
+ [
690
+ "set",
691
+ "@entity.elapsedMs",
692
+ 0.0
693
+ ],
694
+ [
695
+ "let",
696
+ [
697
+ [
698
+ "matched",
699
+ [
700
+ "array/filter",
701
+ "@config.bands",
702
+ [
703
+ "fn",
704
+ "b",
705
+ [
706
+ "<=",
707
+ "@entity.dose",
708
+ [
709
+ "object/get",
710
+ "@b",
711
+ "upperBound"
712
+ ]
713
+ ]
714
+ ]
715
+ ]
716
+ ],
717
+ [
718
+ "band",
719
+ [
720
+ "if",
721
+ [
722
+ ">",
723
+ [
724
+ "array/len",
725
+ "@matched"
726
+ ],
727
+ 0.0
728
+ ],
729
+ [
730
+ "array/first",
731
+ "@matched"
732
+ ],
733
+ [
734
+ "array/nth",
735
+ "@config.bands",
736
+ [
737
+ "-",
738
+ [
739
+ "array/len",
740
+ "@config.bands"
741
+ ],
742
+ 1.0
743
+ ]
744
+ ]
745
+ ]
746
+ ]
747
+ ],
748
+ [
749
+ "do",
750
+ [
751
+ "set",
752
+ "@entity.bandLabel",
753
+ [
754
+ "object/get",
755
+ "@band",
756
+ "label"
757
+ ]
758
+ ],
759
+ [
760
+ "set",
761
+ "@entity.bandColor",
762
+ [
763
+ "object/get",
764
+ "@band",
765
+ "color"
766
+ ]
767
+ ],
768
+ [
769
+ "set",
770
+ "@entity.done",
771
+ [
772
+ "if",
773
+ [
774
+ "object/get",
775
+ "@band",
776
+ "terminal",
777
+ false
778
+ ],
779
+ true,
780
+ "@entity.done"
781
+ ]
782
+ ]
783
+ ]
784
+ ],
785
+ [
786
+ "set",
787
+ "@entity.containers",
788
+ [
789
+ {
790
+ "divider": "none",
791
+ "height": [
792
+ "*",
793
+ "@config.height",
794
+ 0.6
795
+ ],
796
+ "label": "@config.reservoirLabel",
797
+ "level": [
798
+ "math/clamp",
799
+ [
800
+ "/",
801
+ "@entity.dose",
802
+ "@config.capacity"
803
+ ],
804
+ 0.0,
805
+ 1.0
806
+ ],
807
+ "levelColor": "@entity.bandColor",
808
+ "width": [
809
+ "*",
810
+ "@config.width",
811
+ 0.28
812
+ ],
813
+ "x": [
814
+ "*",
815
+ "@config.width",
816
+ 0.12
817
+ ],
818
+ "y": [
819
+ "*",
820
+ "@config.height",
821
+ 0.3
822
+ ]
823
+ },
824
+ {
825
+ "divider": "none",
826
+ "height": [
827
+ "*",
828
+ "@config.height",
829
+ 0.55
830
+ ],
831
+ "label": "@config.sourceLabel",
832
+ "level": [
833
+ "math/clamp",
834
+ [
835
+ "/",
836
+ [
837
+ "-",
838
+ "@config.capacity",
839
+ "@entity.dose"
840
+ ],
841
+ "@config.capacity"
842
+ ],
843
+ 0.0,
844
+ 1.0
845
+ ],
846
+ "levelColor": "@config.sourceColor",
847
+ "width": [
848
+ "*",
849
+ "@config.width",
850
+ 0.06
851
+ ],
852
+ "x": [
853
+ "*",
854
+ "@config.width",
855
+ 0.58
856
+ ],
857
+ "y": [
858
+ "*",
859
+ "@config.height",
860
+ 0.05
861
+ ]
862
+ }
863
+ ]
864
+ ],
865
+ [
866
+ "set",
867
+ "@entity.readouts",
868
+ [
869
+ {
870
+ "label": "@config.quantityLabel",
871
+ "value": [
872
+ "str/concat",
873
+ "",
874
+ [
875
+ "math/round",
876
+ "@entity.dose",
877
+ 2.0
878
+ ]
879
+ ]
880
+ },
881
+ {
882
+ "label": "@config.zoneReadoutLabel",
883
+ "value": "@entity.bandLabel"
884
+ }
885
+ ]
886
+ ],
887
+ [
888
+ "set",
889
+ "@entity.doseSeries",
890
+ [
891
+ {
892
+ "x": 0.0,
893
+ "y": "@entity.dose"
894
+ }
895
+ ]
896
+ ],
897
+ [
898
+ "set",
899
+ "@entity.narration",
900
+ [
901
+ "str/concat",
902
+ "@config.quantityLabel",
903
+ [
904
+ "str/concat",
905
+ " at ",
906
+ [
907
+ "str/concat",
908
+ [
909
+ "str/concat",
910
+ "",
911
+ [
912
+ "math/round",
913
+ "@entity.dose",
914
+ 2.0
915
+ ]
916
+ ],
917
+ [
918
+ "str/concat",
919
+ " — ",
920
+ "@entity.bandLabel"
921
+ ]
922
+ ]
923
+ ]
924
+ ]
925
+ ],
926
+ [
927
+ "if",
928
+ "@config.showCanvas",
929
+ [
930
+ "render-ui",
931
+ "main",
932
+ {
933
+ "children": [
934
+ {
935
+ "children": [
936
+ {
937
+ "content": "@entity.title",
938
+ "type": "typography",
939
+ "variant": "h4"
940
+ },
941
+ {
942
+ "children": [
943
+ {
944
+ "action": "ADD_SMALL",
945
+ "label": [
946
+ "str/concat",
947
+ "+ ",
948
+ [
949
+ "str/concat",
950
+ [
951
+ "str/concat",
952
+ "",
953
+ "@config.stepSmall"
954
+ ],
955
+ [
956
+ "if",
957
+ [
958
+ "==",
959
+ "@config.unit",
960
+ ""
961
+ ],
962
+ "",
963
+ [
964
+ "str/concat",
965
+ " ",
966
+ "@config.unit"
967
+ ]
968
+ ]
969
+ ]
970
+ ],
971
+ "type": "button",
972
+ "variant": "primary"
973
+ },
974
+ {
975
+ "action": "ADD_LARGE",
976
+ "label": [
977
+ "str/concat",
978
+ "+ ",
979
+ [
980
+ "str/concat",
981
+ [
982
+ "str/concat",
983
+ "",
984
+ "@config.stepLarge"
985
+ ],
986
+ [
987
+ "if",
988
+ [
989
+ "==",
990
+ "@config.unit",
991
+ ""
992
+ ],
993
+ "",
994
+ [
995
+ "str/concat",
996
+ " ",
997
+ "@config.unit"
998
+ ]
999
+ ]
1000
+ ]
1001
+ ],
1002
+ "type": "button",
1003
+ "variant": "secondary"
1004
+ },
1005
+ {
1006
+ "action": "TOGGLE_DRIP",
1007
+ "label": [
1008
+ "if",
1009
+ "@entity.running",
1010
+ "Pause",
1011
+ "Auto-dose"
1012
+ ],
1013
+ "type": "button",
1014
+ "variant": "secondary"
1015
+ },
1016
+ {
1017
+ "action": "RESET",
1018
+ "label": "Reset",
1019
+ "type": "button",
1020
+ "variant": "ghost"
1021
+ }
1022
+ ],
1023
+ "direction": "horizontal",
1024
+ "gap": "sm",
1025
+ "type": "stack"
1026
+ },
1027
+ {
1028
+ "backgroundColor": "@config.backgroundColor",
1029
+ "containers": "@entity.containers",
1030
+ "height": "@config.height",
1031
+ "readouts": "@entity.readouts",
1032
+ "traces": [
1033
+ {
1034
+ "series": [
1035
+ {
1036
+ "label": "@config.quantityLabel",
1037
+ "samples": "@entity.doseSeries"
1038
+ }
1039
+ ],
1040
+ "xLabel": "step",
1041
+ "yLabel": "@config.quantityLabel"
1042
+ }
1043
+ ],
1044
+ "type": "chemistry-canvas",
1045
+ "width": "@config.width"
1046
+ },
1047
+ {
1048
+ "content": "@entity.narration",
1049
+ "type": "typography",
1050
+ "variant": "body"
1051
+ }
1052
+ ],
1053
+ "direction": "vertical",
1054
+ "gap": "md",
1055
+ "type": "stack"
1056
+ }
1057
+ ],
1058
+ "padding": "md",
1059
+ "type": "box"
1060
+ }
1061
+ ],
1062
+ [
1063
+ "render-ui",
1064
+ "main",
1065
+ {
1066
+ "children": [
1067
+ {
1068
+ "children": [
1069
+ {
1070
+ "content": "@entity.title",
1071
+ "type": "typography",
1072
+ "variant": "h4"
1073
+ },
1074
+ {
1075
+ "children": [
1076
+ {
1077
+ "action": "ADD_SMALL",
1078
+ "label": [
1079
+ "str/concat",
1080
+ "+ ",
1081
+ [
1082
+ "str/concat",
1083
+ [
1084
+ "str/concat",
1085
+ "",
1086
+ "@config.stepSmall"
1087
+ ],
1088
+ [
1089
+ "if",
1090
+ [
1091
+ "==",
1092
+ "@config.unit",
1093
+ ""
1094
+ ],
1095
+ "",
1096
+ [
1097
+ "str/concat",
1098
+ " ",
1099
+ "@config.unit"
1100
+ ]
1101
+ ]
1102
+ ]
1103
+ ],
1104
+ "type": "button",
1105
+ "variant": "primary"
1106
+ },
1107
+ {
1108
+ "action": "ADD_LARGE",
1109
+ "label": [
1110
+ "str/concat",
1111
+ "+ ",
1112
+ [
1113
+ "str/concat",
1114
+ [
1115
+ "str/concat",
1116
+ "",
1117
+ "@config.stepLarge"
1118
+ ],
1119
+ [
1120
+ "if",
1121
+ [
1122
+ "==",
1123
+ "@config.unit",
1124
+ ""
1125
+ ],
1126
+ "",
1127
+ [
1128
+ "str/concat",
1129
+ " ",
1130
+ "@config.unit"
1131
+ ]
1132
+ ]
1133
+ ]
1134
+ ],
1135
+ "type": "button",
1136
+ "variant": "secondary"
1137
+ },
1138
+ {
1139
+ "action": "TOGGLE_DRIP",
1140
+ "label": [
1141
+ "if",
1142
+ "@entity.running",
1143
+ "Pause",
1144
+ "Auto-dose"
1145
+ ],
1146
+ "type": "button",
1147
+ "variant": "secondary"
1148
+ },
1149
+ {
1150
+ "action": "RESET",
1151
+ "label": "Reset",
1152
+ "type": "button",
1153
+ "variant": "ghost"
1154
+ }
1155
+ ],
1156
+ "direction": "horizontal",
1157
+ "gap": "sm",
1158
+ "type": "stack"
1159
+ }
1160
+ ],
1161
+ "direction": "vertical",
1162
+ "gap": "md",
1163
+ "type": "stack"
1164
+ }
1165
+ ],
1166
+ "padding": "md",
1167
+ "type": "box"
1168
+ }
1169
+ ]
1170
+ ],
1171
+ [
1172
+ "emit",
1173
+ "DOSER_UPDATED",
1174
+ {
1175
+ "bandLabel": "@entity.bandLabel",
1176
+ "done": "@entity.done",
1177
+ "dose": "@entity.dose",
1178
+ "running": "@entity.running"
1179
+ }
1180
+ ]
1181
+ ],
1182
+ "event": "INIT",
1183
+ "eventId": "evt_01M0CGZ8SPH5C42ESXGKNMKQMQ",
1184
+ "from": "idle",
1185
+ "guard": [
1186
+ "==",
1187
+ "@config.matchMode",
1188
+ ""
1189
+ ],
1190
+ "to": "idle"
1191
+ },
1192
+ {
1193
+ "effects": [
1194
+ [
1195
+ "set",
1196
+ "@entity.active",
1197
+ true
1198
+ ],
1199
+ [
1200
+ "set",
1201
+ "@entity.title",
1202
+ "@config.title"
1203
+ ],
1204
+ [
1205
+ "set",
1206
+ "@entity.dose",
1207
+ 0.0
1208
+ ],
1209
+ [
1210
+ "set",
1211
+ "@entity.done",
1212
+ false
1213
+ ],
1214
+ [
1215
+ "set",
1216
+ "@entity.running",
1217
+ "@config.autoDrip"
1218
+ ],
1219
+ [
1220
+ "set",
1221
+ "@entity.elapsedMs",
1222
+ 0.0
1223
+ ],
1224
+ [
1225
+ "let",
1226
+ [
1227
+ [
1228
+ "matched",
1229
+ [
1230
+ "array/filter",
1231
+ "@config.bands",
1232
+ [
1233
+ "fn",
1234
+ "b",
1235
+ [
1236
+ "<=",
1237
+ "@entity.dose",
1238
+ [
1239
+ "object/get",
1240
+ "@b",
1241
+ "upperBound"
1242
+ ]
1243
+ ]
1244
+ ]
1245
+ ]
1246
+ ],
1247
+ [
1248
+ "band",
1249
+ [
1250
+ "if",
1251
+ [
1252
+ ">",
1253
+ [
1254
+ "array/len",
1255
+ "@matched"
1256
+ ],
1257
+ 0.0
1258
+ ],
1259
+ [
1260
+ "array/first",
1261
+ "@matched"
1262
+ ],
1263
+ [
1264
+ "array/nth",
1265
+ "@config.bands",
1266
+ [
1267
+ "-",
1268
+ [
1269
+ "array/len",
1270
+ "@config.bands"
1271
+ ],
1272
+ 1.0
1273
+ ]
1274
+ ]
1275
+ ]
1276
+ ]
1277
+ ],
1278
+ [
1279
+ "do",
1280
+ [
1281
+ "set",
1282
+ "@entity.bandLabel",
1283
+ [
1284
+ "object/get",
1285
+ "@band",
1286
+ "label"
1287
+ ]
1288
+ ],
1289
+ [
1290
+ "set",
1291
+ "@entity.bandColor",
1292
+ [
1293
+ "object/get",
1294
+ "@band",
1295
+ "color"
1296
+ ]
1297
+ ],
1298
+ [
1299
+ "set",
1300
+ "@entity.done",
1301
+ [
1302
+ "if",
1303
+ [
1304
+ "object/get",
1305
+ "@band",
1306
+ "terminal",
1307
+ false
1308
+ ],
1309
+ true,
1310
+ "@entity.done"
1311
+ ]
1312
+ ]
1313
+ ]
1314
+ ],
1315
+ [
1316
+ "set",
1317
+ "@entity.containers",
1318
+ [
1319
+ {
1320
+ "divider": "none",
1321
+ "height": [
1322
+ "*",
1323
+ "@config.height",
1324
+ 0.6
1325
+ ],
1326
+ "label": "@config.reservoirLabel",
1327
+ "level": [
1328
+ "math/clamp",
1329
+ [
1330
+ "/",
1331
+ "@entity.dose",
1332
+ "@config.capacity"
1333
+ ],
1334
+ 0.0,
1335
+ 1.0
1336
+ ],
1337
+ "levelColor": "@entity.bandColor",
1338
+ "width": [
1339
+ "*",
1340
+ "@config.width",
1341
+ 0.28
1342
+ ],
1343
+ "x": [
1344
+ "*",
1345
+ "@config.width",
1346
+ 0.12
1347
+ ],
1348
+ "y": [
1349
+ "*",
1350
+ "@config.height",
1351
+ 0.3
1352
+ ]
1353
+ },
1354
+ {
1355
+ "divider": "none",
1356
+ "height": [
1357
+ "*",
1358
+ "@config.height",
1359
+ 0.55
1360
+ ],
1361
+ "label": "@config.sourceLabel",
1362
+ "level": [
1363
+ "math/clamp",
1364
+ [
1365
+ "/",
1366
+ [
1367
+ "-",
1368
+ "@config.capacity",
1369
+ "@entity.dose"
1370
+ ],
1371
+ "@config.capacity"
1372
+ ],
1373
+ 0.0,
1374
+ 1.0
1375
+ ],
1376
+ "levelColor": "@config.sourceColor",
1377
+ "width": [
1378
+ "*",
1379
+ "@config.width",
1380
+ 0.06
1381
+ ],
1382
+ "x": [
1383
+ "*",
1384
+ "@config.width",
1385
+ 0.58
1386
+ ],
1387
+ "y": [
1388
+ "*",
1389
+ "@config.height",
1390
+ 0.05
1391
+ ]
1392
+ }
1393
+ ]
1394
+ ],
1395
+ [
1396
+ "set",
1397
+ "@entity.readouts",
1398
+ [
1399
+ {
1400
+ "label": "@config.quantityLabel",
1401
+ "value": [
1402
+ "str/concat",
1403
+ "",
1404
+ [
1405
+ "math/round",
1406
+ "@entity.dose",
1407
+ 2.0
1408
+ ]
1409
+ ]
1410
+ },
1411
+ {
1412
+ "label": "@config.zoneReadoutLabel",
1413
+ "value": "@entity.bandLabel"
1414
+ }
1415
+ ]
1416
+ ],
1417
+ [
1418
+ "set",
1419
+ "@entity.doseSeries",
1420
+ [
1421
+ {
1422
+ "x": 0.0,
1423
+ "y": "@entity.dose"
1424
+ }
1425
+ ]
1426
+ ],
1427
+ [
1428
+ "set",
1429
+ "@entity.narration",
1430
+ [
1431
+ "str/concat",
1432
+ "@config.quantityLabel",
1433
+ [
1434
+ "str/concat",
1435
+ " at ",
1436
+ [
1437
+ "str/concat",
1438
+ [
1439
+ "str/concat",
1440
+ "",
1441
+ [
1442
+ "math/round",
1443
+ "@entity.dose",
1444
+ 2.0
1445
+ ]
1446
+ ],
1447
+ [
1448
+ "str/concat",
1449
+ " — ",
1450
+ "@entity.bandLabel"
1451
+ ]
1452
+ ]
1453
+ ]
1454
+ ]
1455
+ ],
1456
+ [
1457
+ "if",
1458
+ "@config.showCanvas",
1459
+ [
1460
+ "render-ui",
1461
+ "main",
1462
+ {
1463
+ "children": [
1464
+ {
1465
+ "children": [
1466
+ {
1467
+ "content": "@entity.title",
1468
+ "type": "typography",
1469
+ "variant": "h4"
1470
+ },
1471
+ {
1472
+ "children": [
1473
+ {
1474
+ "action": "ADD_SMALL",
1475
+ "label": [
1476
+ "str/concat",
1477
+ "+ ",
1478
+ [
1479
+ "str/concat",
1480
+ [
1481
+ "str/concat",
1482
+ "",
1483
+ "@config.stepSmall"
1484
+ ],
1485
+ [
1486
+ "if",
1487
+ [
1488
+ "==",
1489
+ "@config.unit",
1490
+ ""
1491
+ ],
1492
+ "",
1493
+ [
1494
+ "str/concat",
1495
+ " ",
1496
+ "@config.unit"
1497
+ ]
1498
+ ]
1499
+ ]
1500
+ ],
1501
+ "type": "button",
1502
+ "variant": "primary"
1503
+ },
1504
+ {
1505
+ "action": "ADD_LARGE",
1506
+ "label": [
1507
+ "str/concat",
1508
+ "+ ",
1509
+ [
1510
+ "str/concat",
1511
+ [
1512
+ "str/concat",
1513
+ "",
1514
+ "@config.stepLarge"
1515
+ ],
1516
+ [
1517
+ "if",
1518
+ [
1519
+ "==",
1520
+ "@config.unit",
1521
+ ""
1522
+ ],
1523
+ "",
1524
+ [
1525
+ "str/concat",
1526
+ " ",
1527
+ "@config.unit"
1528
+ ]
1529
+ ]
1530
+ ]
1531
+ ],
1532
+ "type": "button",
1533
+ "variant": "secondary"
1534
+ },
1535
+ {
1536
+ "action": "TOGGLE_DRIP",
1537
+ "label": [
1538
+ "if",
1539
+ "@entity.running",
1540
+ "Pause",
1541
+ "Auto-dose"
1542
+ ],
1543
+ "type": "button",
1544
+ "variant": "secondary"
1545
+ },
1546
+ {
1547
+ "action": "RESET",
1548
+ "label": "Reset",
1549
+ "type": "button",
1550
+ "variant": "ghost"
1551
+ }
1552
+ ],
1553
+ "direction": "horizontal",
1554
+ "gap": "sm",
1555
+ "type": "stack"
1556
+ },
1557
+ {
1558
+ "backgroundColor": "@config.backgroundColor",
1559
+ "containers": "@entity.containers",
1560
+ "height": "@config.height",
1561
+ "readouts": "@entity.readouts",
1562
+ "traces": [
1563
+ {
1564
+ "series": [
1565
+ {
1566
+ "label": "@config.quantityLabel",
1567
+ "samples": "@entity.doseSeries"
1568
+ }
1569
+ ],
1570
+ "xLabel": "step",
1571
+ "yLabel": "@config.quantityLabel"
1572
+ }
1573
+ ],
1574
+ "type": "chemistry-canvas",
1575
+ "width": "@config.width"
1576
+ },
1577
+ {
1578
+ "content": "@entity.narration",
1579
+ "type": "typography",
1580
+ "variant": "body"
1581
+ }
1582
+ ],
1583
+ "direction": "vertical",
1584
+ "gap": "md",
1585
+ "type": "stack"
1586
+ }
1587
+ ],
1588
+ "padding": "md",
1589
+ "type": "box"
1590
+ }
1591
+ ],
1592
+ [
1593
+ "render-ui",
1594
+ "main",
1595
+ {
1596
+ "children": [
1597
+ {
1598
+ "children": [
1599
+ {
1600
+ "content": "@entity.title",
1601
+ "type": "typography",
1602
+ "variant": "h4"
1603
+ },
1604
+ {
1605
+ "children": [
1606
+ {
1607
+ "action": "ADD_SMALL",
1608
+ "label": [
1609
+ "str/concat",
1610
+ "+ ",
1611
+ [
1612
+ "str/concat",
1613
+ [
1614
+ "str/concat",
1615
+ "",
1616
+ "@config.stepSmall"
1617
+ ],
1618
+ [
1619
+ "if",
1620
+ [
1621
+ "==",
1622
+ "@config.unit",
1623
+ ""
1624
+ ],
1625
+ "",
1626
+ [
1627
+ "str/concat",
1628
+ " ",
1629
+ "@config.unit"
1630
+ ]
1631
+ ]
1632
+ ]
1633
+ ],
1634
+ "type": "button",
1635
+ "variant": "primary"
1636
+ },
1637
+ {
1638
+ "action": "ADD_LARGE",
1639
+ "label": [
1640
+ "str/concat",
1641
+ "+ ",
1642
+ [
1643
+ "str/concat",
1644
+ [
1645
+ "str/concat",
1646
+ "",
1647
+ "@config.stepLarge"
1648
+ ],
1649
+ [
1650
+ "if",
1651
+ [
1652
+ "==",
1653
+ "@config.unit",
1654
+ ""
1655
+ ],
1656
+ "",
1657
+ [
1658
+ "str/concat",
1659
+ " ",
1660
+ "@config.unit"
1661
+ ]
1662
+ ]
1663
+ ]
1664
+ ],
1665
+ "type": "button",
1666
+ "variant": "secondary"
1667
+ },
1668
+ {
1669
+ "action": "TOGGLE_DRIP",
1670
+ "label": [
1671
+ "if",
1672
+ "@entity.running",
1673
+ "Pause",
1674
+ "Auto-dose"
1675
+ ],
1676
+ "type": "button",
1677
+ "variant": "secondary"
1678
+ },
1679
+ {
1680
+ "action": "RESET",
1681
+ "label": "Reset",
1682
+ "type": "button",
1683
+ "variant": "ghost"
1684
+ }
1685
+ ],
1686
+ "direction": "horizontal",
1687
+ "gap": "sm",
1688
+ "type": "stack"
1689
+ }
1690
+ ],
1691
+ "direction": "vertical",
1692
+ "gap": "md",
1693
+ "type": "stack"
1694
+ }
1695
+ ],
1696
+ "padding": "md",
1697
+ "type": "box"
1698
+ }
1699
+ ]
1700
+ ],
1701
+ [
1702
+ "emit",
1703
+ "DOSER_UPDATED",
1704
+ {
1705
+ "bandLabel": "@entity.bandLabel",
1706
+ "done": "@entity.done",
1707
+ "dose": "@entity.dose",
1708
+ "running": "@entity.running"
1709
+ }
1710
+ ]
1711
+ ],
1712
+ "event": "MODE_SELECTED",
1713
+ "eventId": "evt_01M0CGZ8SPCJWD38ZCMJGGA4EF",
1714
+ "from": "idle",
1715
+ "guard": [
1716
+ "==",
1717
+ "@payload.mode",
1718
+ "@config.matchMode"
1719
+ ],
1720
+ "to": "idle"
1721
+ },
1722
+ {
1723
+ "effects": [
1724
+ [
1725
+ "set",
1726
+ "@entity.dose",
1727
+ [
1728
+ "math/min",
1729
+ [
1730
+ "+",
1731
+ "@entity.dose",
1732
+ "@config.stepSmall"
1733
+ ],
1734
+ "@config.capacity"
1735
+ ]
1736
+ ],
1737
+ [
1738
+ "let",
1739
+ [
1740
+ [
1741
+ "matched",
1742
+ [
1743
+ "array/filter",
1744
+ "@config.bands",
1745
+ [
1746
+ "fn",
1747
+ "b",
1748
+ [
1749
+ "<=",
1750
+ "@entity.dose",
1751
+ [
1752
+ "object/get",
1753
+ "@b",
1754
+ "upperBound"
1755
+ ]
1756
+ ]
1757
+ ]
1758
+ ]
1759
+ ],
1760
+ [
1761
+ "band",
1762
+ [
1763
+ "if",
1764
+ [
1765
+ ">",
1766
+ [
1767
+ "array/len",
1768
+ "@matched"
1769
+ ],
1770
+ 0.0
1771
+ ],
1772
+ [
1773
+ "array/first",
1774
+ "@matched"
1775
+ ],
1776
+ [
1777
+ "array/nth",
1778
+ "@config.bands",
1779
+ [
1780
+ "-",
1781
+ [
1782
+ "array/len",
1783
+ "@config.bands"
1784
+ ],
1785
+ 1.0
1786
+ ]
1787
+ ]
1788
+ ]
1789
+ ]
1790
+ ],
1791
+ [
1792
+ "do",
1793
+ [
1794
+ "set",
1795
+ "@entity.bandLabel",
1796
+ [
1797
+ "object/get",
1798
+ "@band",
1799
+ "label"
1800
+ ]
1801
+ ],
1802
+ [
1803
+ "set",
1804
+ "@entity.bandColor",
1805
+ [
1806
+ "object/get",
1807
+ "@band",
1808
+ "color"
1809
+ ]
1810
+ ],
1811
+ [
1812
+ "set",
1813
+ "@entity.done",
1814
+ [
1815
+ "if",
1816
+ [
1817
+ "object/get",
1818
+ "@band",
1819
+ "terminal",
1820
+ false
1821
+ ],
1822
+ true,
1823
+ "@entity.done"
1824
+ ]
1825
+ ]
1826
+ ]
1827
+ ],
1828
+ [
1829
+ "set",
1830
+ "@entity.containers",
1831
+ [
1832
+ {
1833
+ "divider": "none",
1834
+ "height": [
1835
+ "*",
1836
+ "@config.height",
1837
+ 0.6
1838
+ ],
1839
+ "label": "@config.reservoirLabel",
1840
+ "level": [
1841
+ "math/clamp",
1842
+ [
1843
+ "/",
1844
+ "@entity.dose",
1845
+ "@config.capacity"
1846
+ ],
1847
+ 0.0,
1848
+ 1.0
1849
+ ],
1850
+ "levelColor": "@entity.bandColor",
1851
+ "width": [
1852
+ "*",
1853
+ "@config.width",
1854
+ 0.28
1855
+ ],
1856
+ "x": [
1857
+ "*",
1858
+ "@config.width",
1859
+ 0.12
1860
+ ],
1861
+ "y": [
1862
+ "*",
1863
+ "@config.height",
1864
+ 0.3
1865
+ ]
1866
+ },
1867
+ {
1868
+ "divider": "none",
1869
+ "height": [
1870
+ "*",
1871
+ "@config.height",
1872
+ 0.55
1873
+ ],
1874
+ "label": "@config.sourceLabel",
1875
+ "level": [
1876
+ "math/clamp",
1877
+ [
1878
+ "/",
1879
+ [
1880
+ "-",
1881
+ "@config.capacity",
1882
+ "@entity.dose"
1883
+ ],
1884
+ "@config.capacity"
1885
+ ],
1886
+ 0.0,
1887
+ 1.0
1888
+ ],
1889
+ "levelColor": "@config.sourceColor",
1890
+ "width": [
1891
+ "*",
1892
+ "@config.width",
1893
+ 0.06
1894
+ ],
1895
+ "x": [
1896
+ "*",
1897
+ "@config.width",
1898
+ 0.58
1899
+ ],
1900
+ "y": [
1901
+ "*",
1902
+ "@config.height",
1903
+ 0.05
1904
+ ]
1905
+ }
1906
+ ]
1907
+ ],
1908
+ [
1909
+ "set",
1910
+ "@entity.readouts",
1911
+ [
1912
+ {
1913
+ "label": "@config.quantityLabel",
1914
+ "value": [
1915
+ "str/concat",
1916
+ "",
1917
+ [
1918
+ "math/round",
1919
+ "@entity.dose",
1920
+ 2.0
1921
+ ]
1922
+ ]
1923
+ },
1924
+ {
1925
+ "label": "@config.zoneReadoutLabel",
1926
+ "value": "@entity.bandLabel"
1927
+ }
1928
+ ]
1929
+ ],
1930
+ [
1931
+ "set",
1932
+ "@entity.doseSeries",
1933
+ [
1934
+ "array/takeLast",
1935
+ [
1936
+ "array/append",
1937
+ "@entity.doseSeries",
1938
+ {
1939
+ "x": [
1940
+ "array/len",
1941
+ "@entity.doseSeries"
1942
+ ],
1943
+ "y": "@entity.dose"
1944
+ }
1945
+ ],
1946
+ "@config.historyLength"
1947
+ ]
1948
+ ],
1949
+ [
1950
+ "set",
1951
+ "@entity.narration",
1952
+ [
1953
+ "str/concat",
1954
+ "@config.quantityLabel",
1955
+ [
1956
+ "str/concat",
1957
+ " at ",
1958
+ [
1959
+ "str/concat",
1960
+ [
1961
+ "str/concat",
1962
+ "",
1963
+ [
1964
+ "math/round",
1965
+ "@entity.dose",
1966
+ 2.0
1967
+ ]
1968
+ ],
1969
+ [
1970
+ "str/concat",
1971
+ " — ",
1972
+ [
1973
+ "str/concat",
1974
+ "@entity.bandLabel",
1975
+ [
1976
+ "if",
1977
+ "@entity.done",
1978
+ " — locked",
1979
+ [
1980
+ "if",
1981
+ "@entity.running",
1982
+ " — auto-dosing",
1983
+ " — ready"
1984
+ ]
1985
+ ]
1986
+ ]
1987
+ ]
1988
+ ]
1989
+ ]
1990
+ ]
1991
+ ],
1992
+ [
1993
+ "if",
1994
+ "@config.showCanvas",
1995
+ [
1996
+ "render-ui",
1997
+ "main",
1998
+ {
1999
+ "children": [
2000
+ {
2001
+ "children": [
2002
+ {
2003
+ "content": "@entity.title",
2004
+ "type": "typography",
2005
+ "variant": "h4"
2006
+ },
2007
+ {
2008
+ "children": [
2009
+ {
2010
+ "action": "ADD_SMALL",
2011
+ "label": [
2012
+ "str/concat",
2013
+ "+ ",
2014
+ [
2015
+ "str/concat",
2016
+ [
2017
+ "str/concat",
2018
+ "",
2019
+ "@config.stepSmall"
2020
+ ],
2021
+ [
2022
+ "if",
2023
+ [
2024
+ "==",
2025
+ "@config.unit",
2026
+ ""
2027
+ ],
2028
+ "",
2029
+ [
2030
+ "str/concat",
2031
+ " ",
2032
+ "@config.unit"
2033
+ ]
2034
+ ]
2035
+ ]
2036
+ ],
2037
+ "type": "button",
2038
+ "variant": "primary"
2039
+ },
2040
+ {
2041
+ "action": "ADD_LARGE",
2042
+ "label": [
2043
+ "str/concat",
2044
+ "+ ",
2045
+ [
2046
+ "str/concat",
2047
+ [
2048
+ "str/concat",
2049
+ "",
2050
+ "@config.stepLarge"
2051
+ ],
2052
+ [
2053
+ "if",
2054
+ [
2055
+ "==",
2056
+ "@config.unit",
2057
+ ""
2058
+ ],
2059
+ "",
2060
+ [
2061
+ "str/concat",
2062
+ " ",
2063
+ "@config.unit"
2064
+ ]
2065
+ ]
2066
+ ]
2067
+ ],
2068
+ "type": "button",
2069
+ "variant": "secondary"
2070
+ },
2071
+ {
2072
+ "action": "TOGGLE_DRIP",
2073
+ "label": [
2074
+ "if",
2075
+ "@entity.running",
2076
+ "Pause",
2077
+ "Auto-dose"
2078
+ ],
2079
+ "type": "button",
2080
+ "variant": "secondary"
2081
+ },
2082
+ {
2083
+ "action": "RESET",
2084
+ "label": "Reset",
2085
+ "type": "button",
2086
+ "variant": "ghost"
2087
+ }
2088
+ ],
2089
+ "direction": "horizontal",
2090
+ "gap": "sm",
2091
+ "type": "stack"
2092
+ },
2093
+ {
2094
+ "backgroundColor": "@config.backgroundColor",
2095
+ "containers": "@entity.containers",
2096
+ "height": "@config.height",
2097
+ "readouts": "@entity.readouts",
2098
+ "traces": [
2099
+ {
2100
+ "series": [
2101
+ {
2102
+ "label": "@config.quantityLabel",
2103
+ "samples": "@entity.doseSeries"
2104
+ }
2105
+ ],
2106
+ "xLabel": "step",
2107
+ "yLabel": "@config.quantityLabel"
2108
+ }
2109
+ ],
2110
+ "type": "chemistry-canvas",
2111
+ "width": "@config.width"
2112
+ },
2113
+ {
2114
+ "content": "@entity.narration",
2115
+ "type": "typography",
2116
+ "variant": "body"
2117
+ }
2118
+ ],
2119
+ "direction": "vertical",
2120
+ "gap": "md",
2121
+ "type": "stack"
2122
+ }
2123
+ ],
2124
+ "padding": "md",
2125
+ "type": "box"
2126
+ }
2127
+ ],
2128
+ [
2129
+ "render-ui",
2130
+ "main",
2131
+ {
2132
+ "children": [
2133
+ {
2134
+ "children": [
2135
+ {
2136
+ "content": "@entity.title",
2137
+ "type": "typography",
2138
+ "variant": "h4"
2139
+ },
2140
+ {
2141
+ "children": [
2142
+ {
2143
+ "action": "ADD_SMALL",
2144
+ "label": [
2145
+ "str/concat",
2146
+ "+ ",
2147
+ [
2148
+ "str/concat",
2149
+ [
2150
+ "str/concat",
2151
+ "",
2152
+ "@config.stepSmall"
2153
+ ],
2154
+ [
2155
+ "if",
2156
+ [
2157
+ "==",
2158
+ "@config.unit",
2159
+ ""
2160
+ ],
2161
+ "",
2162
+ [
2163
+ "str/concat",
2164
+ " ",
2165
+ "@config.unit"
2166
+ ]
2167
+ ]
2168
+ ]
2169
+ ],
2170
+ "type": "button",
2171
+ "variant": "primary"
2172
+ },
2173
+ {
2174
+ "action": "ADD_LARGE",
2175
+ "label": [
2176
+ "str/concat",
2177
+ "+ ",
2178
+ [
2179
+ "str/concat",
2180
+ [
2181
+ "str/concat",
2182
+ "",
2183
+ "@config.stepLarge"
2184
+ ],
2185
+ [
2186
+ "if",
2187
+ [
2188
+ "==",
2189
+ "@config.unit",
2190
+ ""
2191
+ ],
2192
+ "",
2193
+ [
2194
+ "str/concat",
2195
+ " ",
2196
+ "@config.unit"
2197
+ ]
2198
+ ]
2199
+ ]
2200
+ ],
2201
+ "type": "button",
2202
+ "variant": "secondary"
2203
+ },
2204
+ {
2205
+ "action": "TOGGLE_DRIP",
2206
+ "label": [
2207
+ "if",
2208
+ "@entity.running",
2209
+ "Pause",
2210
+ "Auto-dose"
2211
+ ],
2212
+ "type": "button",
2213
+ "variant": "secondary"
2214
+ },
2215
+ {
2216
+ "action": "RESET",
2217
+ "label": "Reset",
2218
+ "type": "button",
2219
+ "variant": "ghost"
2220
+ }
2221
+ ],
2222
+ "direction": "horizontal",
2223
+ "gap": "sm",
2224
+ "type": "stack"
2225
+ }
2226
+ ],
2227
+ "direction": "vertical",
2228
+ "gap": "md",
2229
+ "type": "stack"
2230
+ }
2231
+ ],
2232
+ "padding": "md",
2233
+ "type": "box"
2234
+ }
2235
+ ]
2236
+ ],
2237
+ [
2238
+ "emit",
2239
+ "DOSE_ADDED",
2240
+ {
2241
+ "bandColor": "@entity.bandColor",
2242
+ "bandLabel": "@entity.bandLabel",
2243
+ "done": "@entity.done",
2244
+ "dose": "@entity.dose"
2245
+ }
2246
+ ]
2247
+ ],
2248
+ "event": "ADD_SMALL",
2249
+ "eventId": "evt_01M0CGZ8SPACRAV5BKCG4WH64Y",
2250
+ "from": "idle",
2251
+ "guard": [
2252
+ "and",
2253
+ [
2254
+ "==",
2255
+ "@entity.active",
2256
+ true
2257
+ ],
2258
+ [
2259
+ "==",
2260
+ "@entity.done",
2261
+ false
2262
+ ]
2263
+ ],
2264
+ "to": "idle"
2265
+ },
2266
+ {
2267
+ "effects": [
2268
+ [
2269
+ "set",
2270
+ "@entity.dose",
2271
+ [
2272
+ "math/min",
2273
+ [
2274
+ "+",
2275
+ "@entity.dose",
2276
+ "@config.stepLarge"
2277
+ ],
2278
+ "@config.capacity"
2279
+ ]
2280
+ ],
2281
+ [
2282
+ "let",
2283
+ [
2284
+ [
2285
+ "matched",
2286
+ [
2287
+ "array/filter",
2288
+ "@config.bands",
2289
+ [
2290
+ "fn",
2291
+ "b",
2292
+ [
2293
+ "<=",
2294
+ "@entity.dose",
2295
+ [
2296
+ "object/get",
2297
+ "@b",
2298
+ "upperBound"
2299
+ ]
2300
+ ]
2301
+ ]
2302
+ ]
2303
+ ],
2304
+ [
2305
+ "band",
2306
+ [
2307
+ "if",
2308
+ [
2309
+ ">",
2310
+ [
2311
+ "array/len",
2312
+ "@matched"
2313
+ ],
2314
+ 0.0
2315
+ ],
2316
+ [
2317
+ "array/first",
2318
+ "@matched"
2319
+ ],
2320
+ [
2321
+ "array/nth",
2322
+ "@config.bands",
2323
+ [
2324
+ "-",
2325
+ [
2326
+ "array/len",
2327
+ "@config.bands"
2328
+ ],
2329
+ 1.0
2330
+ ]
2331
+ ]
2332
+ ]
2333
+ ]
2334
+ ],
2335
+ [
2336
+ "do",
2337
+ [
2338
+ "set",
2339
+ "@entity.bandLabel",
2340
+ [
2341
+ "object/get",
2342
+ "@band",
2343
+ "label"
2344
+ ]
2345
+ ],
2346
+ [
2347
+ "set",
2348
+ "@entity.bandColor",
2349
+ [
2350
+ "object/get",
2351
+ "@band",
2352
+ "color"
2353
+ ]
2354
+ ],
2355
+ [
2356
+ "set",
2357
+ "@entity.done",
2358
+ [
2359
+ "if",
2360
+ [
2361
+ "object/get",
2362
+ "@band",
2363
+ "terminal",
2364
+ false
2365
+ ],
2366
+ true,
2367
+ "@entity.done"
2368
+ ]
2369
+ ]
2370
+ ]
2371
+ ],
2372
+ [
2373
+ "set",
2374
+ "@entity.containers",
2375
+ [
2376
+ {
2377
+ "divider": "none",
2378
+ "height": [
2379
+ "*",
2380
+ "@config.height",
2381
+ 0.6
2382
+ ],
2383
+ "label": "@config.reservoirLabel",
2384
+ "level": [
2385
+ "math/clamp",
2386
+ [
2387
+ "/",
2388
+ "@entity.dose",
2389
+ "@config.capacity"
2390
+ ],
2391
+ 0.0,
2392
+ 1.0
2393
+ ],
2394
+ "levelColor": "@entity.bandColor",
2395
+ "width": [
2396
+ "*",
2397
+ "@config.width",
2398
+ 0.28
2399
+ ],
2400
+ "x": [
2401
+ "*",
2402
+ "@config.width",
2403
+ 0.12
2404
+ ],
2405
+ "y": [
2406
+ "*",
2407
+ "@config.height",
2408
+ 0.3
2409
+ ]
2410
+ },
2411
+ {
2412
+ "divider": "none",
2413
+ "height": [
2414
+ "*",
2415
+ "@config.height",
2416
+ 0.55
2417
+ ],
2418
+ "label": "@config.sourceLabel",
2419
+ "level": [
2420
+ "math/clamp",
2421
+ [
2422
+ "/",
2423
+ [
2424
+ "-",
2425
+ "@config.capacity",
2426
+ "@entity.dose"
2427
+ ],
2428
+ "@config.capacity"
2429
+ ],
2430
+ 0.0,
2431
+ 1.0
2432
+ ],
2433
+ "levelColor": "@config.sourceColor",
2434
+ "width": [
2435
+ "*",
2436
+ "@config.width",
2437
+ 0.06
2438
+ ],
2439
+ "x": [
2440
+ "*",
2441
+ "@config.width",
2442
+ 0.58
2443
+ ],
2444
+ "y": [
2445
+ "*",
2446
+ "@config.height",
2447
+ 0.05
2448
+ ]
2449
+ }
2450
+ ]
2451
+ ],
2452
+ [
2453
+ "set",
2454
+ "@entity.readouts",
2455
+ [
2456
+ {
2457
+ "label": "@config.quantityLabel",
2458
+ "value": [
2459
+ "str/concat",
2460
+ "",
2461
+ [
2462
+ "math/round",
2463
+ "@entity.dose",
2464
+ 2.0
2465
+ ]
2466
+ ]
2467
+ },
2468
+ {
2469
+ "label": "@config.zoneReadoutLabel",
2470
+ "value": "@entity.bandLabel"
2471
+ }
2472
+ ]
2473
+ ],
2474
+ [
2475
+ "set",
2476
+ "@entity.doseSeries",
2477
+ [
2478
+ "array/takeLast",
2479
+ [
2480
+ "array/append",
2481
+ "@entity.doseSeries",
2482
+ {
2483
+ "x": [
2484
+ "array/len",
2485
+ "@entity.doseSeries"
2486
+ ],
2487
+ "y": "@entity.dose"
2488
+ }
2489
+ ],
2490
+ "@config.historyLength"
2491
+ ]
2492
+ ],
2493
+ [
2494
+ "set",
2495
+ "@entity.narration",
2496
+ [
2497
+ "str/concat",
2498
+ "@config.quantityLabel",
2499
+ [
2500
+ "str/concat",
2501
+ " at ",
2502
+ [
2503
+ "str/concat",
2504
+ [
2505
+ "str/concat",
2506
+ "",
2507
+ [
2508
+ "math/round",
2509
+ "@entity.dose",
2510
+ 2.0
2511
+ ]
2512
+ ],
2513
+ [
2514
+ "str/concat",
2515
+ " — ",
2516
+ [
2517
+ "str/concat",
2518
+ "@entity.bandLabel",
2519
+ [
2520
+ "if",
2521
+ "@entity.done",
2522
+ " — locked",
2523
+ [
2524
+ "if",
2525
+ "@entity.running",
2526
+ " — auto-dosing",
2527
+ " — ready"
2528
+ ]
2529
+ ]
2530
+ ]
2531
+ ]
2532
+ ]
2533
+ ]
2534
+ ]
2535
+ ],
2536
+ [
2537
+ "if",
2538
+ "@config.showCanvas",
2539
+ [
2540
+ "render-ui",
2541
+ "main",
2542
+ {
2543
+ "children": [
2544
+ {
2545
+ "children": [
2546
+ {
2547
+ "content": "@entity.title",
2548
+ "type": "typography",
2549
+ "variant": "h4"
2550
+ },
2551
+ {
2552
+ "children": [
2553
+ {
2554
+ "action": "ADD_SMALL",
2555
+ "label": [
2556
+ "str/concat",
2557
+ "+ ",
2558
+ [
2559
+ "str/concat",
2560
+ [
2561
+ "str/concat",
2562
+ "",
2563
+ "@config.stepSmall"
2564
+ ],
2565
+ [
2566
+ "if",
2567
+ [
2568
+ "==",
2569
+ "@config.unit",
2570
+ ""
2571
+ ],
2572
+ "",
2573
+ [
2574
+ "str/concat",
2575
+ " ",
2576
+ "@config.unit"
2577
+ ]
2578
+ ]
2579
+ ]
2580
+ ],
2581
+ "type": "button",
2582
+ "variant": "primary"
2583
+ },
2584
+ {
2585
+ "action": "ADD_LARGE",
2586
+ "label": [
2587
+ "str/concat",
2588
+ "+ ",
2589
+ [
2590
+ "str/concat",
2591
+ [
2592
+ "str/concat",
2593
+ "",
2594
+ "@config.stepLarge"
2595
+ ],
2596
+ [
2597
+ "if",
2598
+ [
2599
+ "==",
2600
+ "@config.unit",
2601
+ ""
2602
+ ],
2603
+ "",
2604
+ [
2605
+ "str/concat",
2606
+ " ",
2607
+ "@config.unit"
2608
+ ]
2609
+ ]
2610
+ ]
2611
+ ],
2612
+ "type": "button",
2613
+ "variant": "secondary"
2614
+ },
2615
+ {
2616
+ "action": "TOGGLE_DRIP",
2617
+ "label": [
2618
+ "if",
2619
+ "@entity.running",
2620
+ "Pause",
2621
+ "Auto-dose"
2622
+ ],
2623
+ "type": "button",
2624
+ "variant": "secondary"
2625
+ },
2626
+ {
2627
+ "action": "RESET",
2628
+ "label": "Reset",
2629
+ "type": "button",
2630
+ "variant": "ghost"
2631
+ }
2632
+ ],
2633
+ "direction": "horizontal",
2634
+ "gap": "sm",
2635
+ "type": "stack"
2636
+ },
2637
+ {
2638
+ "backgroundColor": "@config.backgroundColor",
2639
+ "containers": "@entity.containers",
2640
+ "height": "@config.height",
2641
+ "readouts": "@entity.readouts",
2642
+ "traces": [
2643
+ {
2644
+ "series": [
2645
+ {
2646
+ "label": "@config.quantityLabel",
2647
+ "samples": "@entity.doseSeries"
2648
+ }
2649
+ ],
2650
+ "xLabel": "step",
2651
+ "yLabel": "@config.quantityLabel"
2652
+ }
2653
+ ],
2654
+ "type": "chemistry-canvas",
2655
+ "width": "@config.width"
2656
+ },
2657
+ {
2658
+ "content": "@entity.narration",
2659
+ "type": "typography",
2660
+ "variant": "body"
2661
+ }
2662
+ ],
2663
+ "direction": "vertical",
2664
+ "gap": "md",
2665
+ "type": "stack"
2666
+ }
2667
+ ],
2668
+ "padding": "md",
2669
+ "type": "box"
2670
+ }
2671
+ ],
2672
+ [
2673
+ "render-ui",
2674
+ "main",
2675
+ {
2676
+ "children": [
2677
+ {
2678
+ "children": [
2679
+ {
2680
+ "content": "@entity.title",
2681
+ "type": "typography",
2682
+ "variant": "h4"
2683
+ },
2684
+ {
2685
+ "children": [
2686
+ {
2687
+ "action": "ADD_SMALL",
2688
+ "label": [
2689
+ "str/concat",
2690
+ "+ ",
2691
+ [
2692
+ "str/concat",
2693
+ [
2694
+ "str/concat",
2695
+ "",
2696
+ "@config.stepSmall"
2697
+ ],
2698
+ [
2699
+ "if",
2700
+ [
2701
+ "==",
2702
+ "@config.unit",
2703
+ ""
2704
+ ],
2705
+ "",
2706
+ [
2707
+ "str/concat",
2708
+ " ",
2709
+ "@config.unit"
2710
+ ]
2711
+ ]
2712
+ ]
2713
+ ],
2714
+ "type": "button",
2715
+ "variant": "primary"
2716
+ },
2717
+ {
2718
+ "action": "ADD_LARGE",
2719
+ "label": [
2720
+ "str/concat",
2721
+ "+ ",
2722
+ [
2723
+ "str/concat",
2724
+ [
2725
+ "str/concat",
2726
+ "",
2727
+ "@config.stepLarge"
2728
+ ],
2729
+ [
2730
+ "if",
2731
+ [
2732
+ "==",
2733
+ "@config.unit",
2734
+ ""
2735
+ ],
2736
+ "",
2737
+ [
2738
+ "str/concat",
2739
+ " ",
2740
+ "@config.unit"
2741
+ ]
2742
+ ]
2743
+ ]
2744
+ ],
2745
+ "type": "button",
2746
+ "variant": "secondary"
2747
+ },
2748
+ {
2749
+ "action": "TOGGLE_DRIP",
2750
+ "label": [
2751
+ "if",
2752
+ "@entity.running",
2753
+ "Pause",
2754
+ "Auto-dose"
2755
+ ],
2756
+ "type": "button",
2757
+ "variant": "secondary"
2758
+ },
2759
+ {
2760
+ "action": "RESET",
2761
+ "label": "Reset",
2762
+ "type": "button",
2763
+ "variant": "ghost"
2764
+ }
2765
+ ],
2766
+ "direction": "horizontal",
2767
+ "gap": "sm",
2768
+ "type": "stack"
2769
+ }
2770
+ ],
2771
+ "direction": "vertical",
2772
+ "gap": "md",
2773
+ "type": "stack"
2774
+ }
2775
+ ],
2776
+ "padding": "md",
2777
+ "type": "box"
2778
+ }
2779
+ ]
2780
+ ],
2781
+ [
2782
+ "emit",
2783
+ "DOSE_ADDED",
2784
+ {
2785
+ "bandColor": "@entity.bandColor",
2786
+ "bandLabel": "@entity.bandLabel",
2787
+ "done": "@entity.done",
2788
+ "dose": "@entity.dose"
2789
+ }
2790
+ ]
2791
+ ],
2792
+ "event": "ADD_LARGE",
2793
+ "eventId": "evt_01M0CGZ8SP47VR9A9YFGEFRMH1",
2794
+ "from": "idle",
2795
+ "guard": [
2796
+ "and",
2797
+ [
2798
+ "==",
2799
+ "@entity.active",
2800
+ true
2801
+ ],
2802
+ [
2803
+ "==",
2804
+ "@entity.done",
2805
+ false
2806
+ ]
2807
+ ],
2808
+ "to": "idle"
2809
+ },
2810
+ {
2811
+ "effects": [
2812
+ [
2813
+ "set",
2814
+ "@entity.running",
2815
+ [
2816
+ "not",
2817
+ "@entity.running"
2818
+ ]
2819
+ ],
2820
+ [
2821
+ "set",
2822
+ "@entity.elapsedMs",
2823
+ 0.0
2824
+ ],
2825
+ [
2826
+ "if",
2827
+ "@config.showCanvas",
2828
+ [
2829
+ "render-ui",
2830
+ "main",
2831
+ {
2832
+ "children": [
2833
+ {
2834
+ "children": [
2835
+ {
2836
+ "content": "@entity.title",
2837
+ "type": "typography",
2838
+ "variant": "h4"
2839
+ },
2840
+ {
2841
+ "children": [
2842
+ {
2843
+ "action": "ADD_SMALL",
2844
+ "label": [
2845
+ "str/concat",
2846
+ "+ ",
2847
+ [
2848
+ "str/concat",
2849
+ [
2850
+ "str/concat",
2851
+ "",
2852
+ "@config.stepSmall"
2853
+ ],
2854
+ [
2855
+ "if",
2856
+ [
2857
+ "==",
2858
+ "@config.unit",
2859
+ ""
2860
+ ],
2861
+ "",
2862
+ [
2863
+ "str/concat",
2864
+ " ",
2865
+ "@config.unit"
2866
+ ]
2867
+ ]
2868
+ ]
2869
+ ],
2870
+ "type": "button",
2871
+ "variant": "primary"
2872
+ },
2873
+ {
2874
+ "action": "ADD_LARGE",
2875
+ "label": [
2876
+ "str/concat",
2877
+ "+ ",
2878
+ [
2879
+ "str/concat",
2880
+ [
2881
+ "str/concat",
2882
+ "",
2883
+ "@config.stepLarge"
2884
+ ],
2885
+ [
2886
+ "if",
2887
+ [
2888
+ "==",
2889
+ "@config.unit",
2890
+ ""
2891
+ ],
2892
+ "",
2893
+ [
2894
+ "str/concat",
2895
+ " ",
2896
+ "@config.unit"
2897
+ ]
2898
+ ]
2899
+ ]
2900
+ ],
2901
+ "type": "button",
2902
+ "variant": "secondary"
2903
+ },
2904
+ {
2905
+ "action": "TOGGLE_DRIP",
2906
+ "label": [
2907
+ "if",
2908
+ "@entity.running",
2909
+ "Pause",
2910
+ "Auto-dose"
2911
+ ],
2912
+ "type": "button",
2913
+ "variant": "secondary"
2914
+ },
2915
+ {
2916
+ "action": "RESET",
2917
+ "label": "Reset",
2918
+ "type": "button",
2919
+ "variant": "ghost"
2920
+ }
2921
+ ],
2922
+ "direction": "horizontal",
2923
+ "gap": "sm",
2924
+ "type": "stack"
2925
+ },
2926
+ {
2927
+ "backgroundColor": "@config.backgroundColor",
2928
+ "containers": "@entity.containers",
2929
+ "height": "@config.height",
2930
+ "readouts": "@entity.readouts",
2931
+ "traces": [
2932
+ {
2933
+ "series": [
2934
+ {
2935
+ "label": "@config.quantityLabel",
2936
+ "samples": "@entity.doseSeries"
2937
+ }
2938
+ ],
2939
+ "xLabel": "step",
2940
+ "yLabel": "@config.quantityLabel"
2941
+ }
2942
+ ],
2943
+ "type": "chemistry-canvas",
2944
+ "width": "@config.width"
2945
+ },
2946
+ {
2947
+ "content": "@entity.narration",
2948
+ "type": "typography",
2949
+ "variant": "body"
2950
+ }
2951
+ ],
2952
+ "direction": "vertical",
2953
+ "gap": "md",
2954
+ "type": "stack"
2955
+ }
2956
+ ],
2957
+ "padding": "md",
2958
+ "type": "box"
2959
+ }
2960
+ ],
2961
+ [
2962
+ "render-ui",
2963
+ "main",
2964
+ {
2965
+ "children": [
2966
+ {
2967
+ "children": [
2968
+ {
2969
+ "content": "@entity.title",
2970
+ "type": "typography",
2971
+ "variant": "h4"
2972
+ },
2973
+ {
2974
+ "children": [
2975
+ {
2976
+ "action": "ADD_SMALL",
2977
+ "label": [
2978
+ "str/concat",
2979
+ "+ ",
2980
+ [
2981
+ "str/concat",
2982
+ [
2983
+ "str/concat",
2984
+ "",
2985
+ "@config.stepSmall"
2986
+ ],
2987
+ [
2988
+ "if",
2989
+ [
2990
+ "==",
2991
+ "@config.unit",
2992
+ ""
2993
+ ],
2994
+ "",
2995
+ [
2996
+ "str/concat",
2997
+ " ",
2998
+ "@config.unit"
2999
+ ]
3000
+ ]
3001
+ ]
3002
+ ],
3003
+ "type": "button",
3004
+ "variant": "primary"
3005
+ },
3006
+ {
3007
+ "action": "ADD_LARGE",
3008
+ "label": [
3009
+ "str/concat",
3010
+ "+ ",
3011
+ [
3012
+ "str/concat",
3013
+ [
3014
+ "str/concat",
3015
+ "",
3016
+ "@config.stepLarge"
3017
+ ],
3018
+ [
3019
+ "if",
3020
+ [
3021
+ "==",
3022
+ "@config.unit",
3023
+ ""
3024
+ ],
3025
+ "",
3026
+ [
3027
+ "str/concat",
3028
+ " ",
3029
+ "@config.unit"
3030
+ ]
3031
+ ]
3032
+ ]
3033
+ ],
3034
+ "type": "button",
3035
+ "variant": "secondary"
3036
+ },
3037
+ {
3038
+ "action": "TOGGLE_DRIP",
3039
+ "label": [
3040
+ "if",
3041
+ "@entity.running",
3042
+ "Pause",
3043
+ "Auto-dose"
3044
+ ],
3045
+ "type": "button",
3046
+ "variant": "secondary"
3047
+ },
3048
+ {
3049
+ "action": "RESET",
3050
+ "label": "Reset",
3051
+ "type": "button",
3052
+ "variant": "ghost"
3053
+ }
3054
+ ],
3055
+ "direction": "horizontal",
3056
+ "gap": "sm",
3057
+ "type": "stack"
3058
+ }
3059
+ ],
3060
+ "direction": "vertical",
3061
+ "gap": "md",
3062
+ "type": "stack"
3063
+ }
3064
+ ],
3065
+ "padding": "md",
3066
+ "type": "box"
3067
+ }
3068
+ ]
3069
+ ],
3070
+ [
3071
+ "emit",
3072
+ "DOSER_UPDATED",
3073
+ {
3074
+ "bandLabel": "@entity.bandLabel",
3075
+ "done": "@entity.done",
3076
+ "dose": "@entity.dose",
3077
+ "running": "@entity.running"
3078
+ }
3079
+ ]
3080
+ ],
3081
+ "event": "TOGGLE_DRIP",
3082
+ "eventId": "evt_01M0CGZ8SP7AZV95SQDK8RN1ZT",
3083
+ "from": "idle",
3084
+ "guard": [
3085
+ "==",
3086
+ "@entity.active",
3087
+ true
3088
+ ],
3089
+ "to": "idle"
3090
+ },
3091
+ {
3092
+ "effects": [
3093
+ [
3094
+ "set",
3095
+ "@entity.title",
3096
+ "@config.title"
3097
+ ],
3098
+ [
3099
+ "set",
3100
+ "@entity.dose",
3101
+ 0.0
3102
+ ],
3103
+ [
3104
+ "set",
3105
+ "@entity.done",
3106
+ false
3107
+ ],
3108
+ [
3109
+ "set",
3110
+ "@entity.running",
3111
+ "@config.autoDrip"
3112
+ ],
3113
+ [
3114
+ "set",
3115
+ "@entity.elapsedMs",
3116
+ 0.0
3117
+ ],
3118
+ [
3119
+ "let",
3120
+ [
3121
+ [
3122
+ "matched",
3123
+ [
3124
+ "array/filter",
3125
+ "@config.bands",
3126
+ [
3127
+ "fn",
3128
+ "b",
3129
+ [
3130
+ "<=",
3131
+ "@entity.dose",
3132
+ [
3133
+ "object/get",
3134
+ "@b",
3135
+ "upperBound"
3136
+ ]
3137
+ ]
3138
+ ]
3139
+ ]
3140
+ ],
3141
+ [
3142
+ "band",
3143
+ [
3144
+ "if",
3145
+ [
3146
+ ">",
3147
+ [
3148
+ "array/len",
3149
+ "@matched"
3150
+ ],
3151
+ 0.0
3152
+ ],
3153
+ [
3154
+ "array/first",
3155
+ "@matched"
3156
+ ],
3157
+ [
3158
+ "array/nth",
3159
+ "@config.bands",
3160
+ [
3161
+ "-",
3162
+ [
3163
+ "array/len",
3164
+ "@config.bands"
3165
+ ],
3166
+ 1.0
3167
+ ]
3168
+ ]
3169
+ ]
3170
+ ]
3171
+ ],
3172
+ [
3173
+ "do",
3174
+ [
3175
+ "set",
3176
+ "@entity.bandLabel",
3177
+ [
3178
+ "object/get",
3179
+ "@band",
3180
+ "label"
3181
+ ]
3182
+ ],
3183
+ [
3184
+ "set",
3185
+ "@entity.bandColor",
3186
+ [
3187
+ "object/get",
3188
+ "@band",
3189
+ "color"
3190
+ ]
3191
+ ],
3192
+ [
3193
+ "set",
3194
+ "@entity.done",
3195
+ [
3196
+ "if",
3197
+ [
3198
+ "object/get",
3199
+ "@band",
3200
+ "terminal",
3201
+ false
3202
+ ],
3203
+ true,
3204
+ "@entity.done"
3205
+ ]
3206
+ ]
3207
+ ]
3208
+ ],
3209
+ [
3210
+ "set",
3211
+ "@entity.containers",
3212
+ [
3213
+ {
3214
+ "divider": "none",
3215
+ "height": [
3216
+ "*",
3217
+ "@config.height",
3218
+ 0.6
3219
+ ],
3220
+ "label": "@config.reservoirLabel",
3221
+ "level": [
3222
+ "math/clamp",
3223
+ [
3224
+ "/",
3225
+ "@entity.dose",
3226
+ "@config.capacity"
3227
+ ],
3228
+ 0.0,
3229
+ 1.0
3230
+ ],
3231
+ "levelColor": "@entity.bandColor",
3232
+ "width": [
3233
+ "*",
3234
+ "@config.width",
3235
+ 0.28
3236
+ ],
3237
+ "x": [
3238
+ "*",
3239
+ "@config.width",
3240
+ 0.12
3241
+ ],
3242
+ "y": [
3243
+ "*",
3244
+ "@config.height",
3245
+ 0.3
3246
+ ]
3247
+ },
3248
+ {
3249
+ "divider": "none",
3250
+ "height": [
3251
+ "*",
3252
+ "@config.height",
3253
+ 0.55
3254
+ ],
3255
+ "label": "@config.sourceLabel",
3256
+ "level": [
3257
+ "math/clamp",
3258
+ [
3259
+ "/",
3260
+ [
3261
+ "-",
3262
+ "@config.capacity",
3263
+ "@entity.dose"
3264
+ ],
3265
+ "@config.capacity"
3266
+ ],
3267
+ 0.0,
3268
+ 1.0
3269
+ ],
3270
+ "levelColor": "@config.sourceColor",
3271
+ "width": [
3272
+ "*",
3273
+ "@config.width",
3274
+ 0.06
3275
+ ],
3276
+ "x": [
3277
+ "*",
3278
+ "@config.width",
3279
+ 0.58
3280
+ ],
3281
+ "y": [
3282
+ "*",
3283
+ "@config.height",
3284
+ 0.05
3285
+ ]
3286
+ }
3287
+ ]
3288
+ ],
3289
+ [
3290
+ "set",
3291
+ "@entity.readouts",
3292
+ [
3293
+ {
3294
+ "label": "@config.quantityLabel",
3295
+ "value": [
3296
+ "str/concat",
3297
+ "",
3298
+ [
3299
+ "math/round",
3300
+ "@entity.dose",
3301
+ 2.0
3302
+ ]
3303
+ ]
3304
+ },
3305
+ {
3306
+ "label": "@config.zoneReadoutLabel",
3307
+ "value": "@entity.bandLabel"
3308
+ }
3309
+ ]
3310
+ ],
3311
+ [
3312
+ "set",
3313
+ "@entity.doseSeries",
3314
+ [
3315
+ {
3316
+ "x": 0.0,
3317
+ "y": "@entity.dose"
3318
+ }
3319
+ ]
3320
+ ],
3321
+ [
3322
+ "set",
3323
+ "@entity.narration",
3324
+ [
3325
+ "str/concat",
3326
+ "@config.quantityLabel",
3327
+ [
3328
+ "str/concat",
3329
+ " at ",
3330
+ [
3331
+ "str/concat",
3332
+ [
3333
+ "str/concat",
3334
+ "",
3335
+ [
3336
+ "math/round",
3337
+ "@entity.dose",
3338
+ 2.0
3339
+ ]
3340
+ ],
3341
+ [
3342
+ "str/concat",
3343
+ " — ",
3344
+ "@entity.bandLabel"
3345
+ ]
3346
+ ]
3347
+ ]
3348
+ ]
3349
+ ],
3350
+ [
3351
+ "if",
3352
+ "@config.showCanvas",
3353
+ [
3354
+ "render-ui",
3355
+ "main",
3356
+ {
3357
+ "children": [
3358
+ {
3359
+ "children": [
3360
+ {
3361
+ "content": "@entity.title",
3362
+ "type": "typography",
3363
+ "variant": "h4"
3364
+ },
3365
+ {
3366
+ "children": [
3367
+ {
3368
+ "action": "ADD_SMALL",
3369
+ "label": [
3370
+ "str/concat",
3371
+ "+ ",
3372
+ [
3373
+ "str/concat",
3374
+ [
3375
+ "str/concat",
3376
+ "",
3377
+ "@config.stepSmall"
3378
+ ],
3379
+ [
3380
+ "if",
3381
+ [
3382
+ "==",
3383
+ "@config.unit",
3384
+ ""
3385
+ ],
3386
+ "",
3387
+ [
3388
+ "str/concat",
3389
+ " ",
3390
+ "@config.unit"
3391
+ ]
3392
+ ]
3393
+ ]
3394
+ ],
3395
+ "type": "button",
3396
+ "variant": "primary"
3397
+ },
3398
+ {
3399
+ "action": "ADD_LARGE",
3400
+ "label": [
3401
+ "str/concat",
3402
+ "+ ",
3403
+ [
3404
+ "str/concat",
3405
+ [
3406
+ "str/concat",
3407
+ "",
3408
+ "@config.stepLarge"
3409
+ ],
3410
+ [
3411
+ "if",
3412
+ [
3413
+ "==",
3414
+ "@config.unit",
3415
+ ""
3416
+ ],
3417
+ "",
3418
+ [
3419
+ "str/concat",
3420
+ " ",
3421
+ "@config.unit"
3422
+ ]
3423
+ ]
3424
+ ]
3425
+ ],
3426
+ "type": "button",
3427
+ "variant": "secondary"
3428
+ },
3429
+ {
3430
+ "action": "TOGGLE_DRIP",
3431
+ "label": [
3432
+ "if",
3433
+ "@entity.running",
3434
+ "Pause",
3435
+ "Auto-dose"
3436
+ ],
3437
+ "type": "button",
3438
+ "variant": "secondary"
3439
+ },
3440
+ {
3441
+ "action": "RESET",
3442
+ "label": "Reset",
3443
+ "type": "button",
3444
+ "variant": "ghost"
3445
+ }
3446
+ ],
3447
+ "direction": "horizontal",
3448
+ "gap": "sm",
3449
+ "type": "stack"
3450
+ },
3451
+ {
3452
+ "backgroundColor": "@config.backgroundColor",
3453
+ "containers": "@entity.containers",
3454
+ "height": "@config.height",
3455
+ "readouts": "@entity.readouts",
3456
+ "traces": [
3457
+ {
3458
+ "series": [
3459
+ {
3460
+ "label": "@config.quantityLabel",
3461
+ "samples": "@entity.doseSeries"
3462
+ }
3463
+ ],
3464
+ "xLabel": "step",
3465
+ "yLabel": "@config.quantityLabel"
3466
+ }
3467
+ ],
3468
+ "type": "chemistry-canvas",
3469
+ "width": "@config.width"
3470
+ },
3471
+ {
3472
+ "content": "@entity.narration",
3473
+ "type": "typography",
3474
+ "variant": "body"
3475
+ }
3476
+ ],
3477
+ "direction": "vertical",
3478
+ "gap": "md",
3479
+ "type": "stack"
3480
+ }
3481
+ ],
3482
+ "padding": "md",
3483
+ "type": "box"
3484
+ }
3485
+ ],
3486
+ [
3487
+ "render-ui",
3488
+ "main",
3489
+ {
3490
+ "children": [
3491
+ {
3492
+ "children": [
3493
+ {
3494
+ "content": "@entity.title",
3495
+ "type": "typography",
3496
+ "variant": "h4"
3497
+ },
3498
+ {
3499
+ "children": [
3500
+ {
3501
+ "action": "ADD_SMALL",
3502
+ "label": [
3503
+ "str/concat",
3504
+ "+ ",
3505
+ [
3506
+ "str/concat",
3507
+ [
3508
+ "str/concat",
3509
+ "",
3510
+ "@config.stepSmall"
3511
+ ],
3512
+ [
3513
+ "if",
3514
+ [
3515
+ "==",
3516
+ "@config.unit",
3517
+ ""
3518
+ ],
3519
+ "",
3520
+ [
3521
+ "str/concat",
3522
+ " ",
3523
+ "@config.unit"
3524
+ ]
3525
+ ]
3526
+ ]
3527
+ ],
3528
+ "type": "button",
3529
+ "variant": "primary"
3530
+ },
3531
+ {
3532
+ "action": "ADD_LARGE",
3533
+ "label": [
3534
+ "str/concat",
3535
+ "+ ",
3536
+ [
3537
+ "str/concat",
3538
+ [
3539
+ "str/concat",
3540
+ "",
3541
+ "@config.stepLarge"
3542
+ ],
3543
+ [
3544
+ "if",
3545
+ [
3546
+ "==",
3547
+ "@config.unit",
3548
+ ""
3549
+ ],
3550
+ "",
3551
+ [
3552
+ "str/concat",
3553
+ " ",
3554
+ "@config.unit"
3555
+ ]
3556
+ ]
3557
+ ]
3558
+ ],
3559
+ "type": "button",
3560
+ "variant": "secondary"
3561
+ },
3562
+ {
3563
+ "action": "TOGGLE_DRIP",
3564
+ "label": [
3565
+ "if",
3566
+ "@entity.running",
3567
+ "Pause",
3568
+ "Auto-dose"
3569
+ ],
3570
+ "type": "button",
3571
+ "variant": "secondary"
3572
+ },
3573
+ {
3574
+ "action": "RESET",
3575
+ "label": "Reset",
3576
+ "type": "button",
3577
+ "variant": "ghost"
3578
+ }
3579
+ ],
3580
+ "direction": "horizontal",
3581
+ "gap": "sm",
3582
+ "type": "stack"
3583
+ }
3584
+ ],
3585
+ "direction": "vertical",
3586
+ "gap": "md",
3587
+ "type": "stack"
3588
+ }
3589
+ ],
3590
+ "padding": "md",
3591
+ "type": "box"
3592
+ }
3593
+ ]
3594
+ ],
3595
+ [
3596
+ "emit",
3597
+ "DOSE_RESET",
3598
+ {}
3599
+ ]
3600
+ ],
3601
+ "event": "RESET",
3602
+ "eventId": "evt_01M0CGZ8SPYR8QYSEEQF1PQ6D8",
3603
+ "from": "idle",
3604
+ "guard": [
3605
+ "==",
3606
+ "@entity.active",
3607
+ true
3608
+ ],
3609
+ "to": "idle"
3610
+ }
3611
+ ]
3612
+ },
3613
+ "ticks": [
3614
+ {
3615
+ "effects": [
3616
+ [
3617
+ "set",
3618
+ "@entity.elapsedMs",
3619
+ [
3620
+ "+",
3621
+ "@entity.elapsedMs",
3622
+ 32.0
3623
+ ]
3624
+ ],
3625
+ [
3626
+ "when",
3627
+ [
3628
+ ">=",
3629
+ "@entity.elapsedMs",
3630
+ "@config.dripIntervalMs"
3631
+ ],
3632
+ [
3633
+ "do",
3634
+ [
3635
+ "set",
3636
+ "@entity.elapsedMs",
3637
+ 0.0
3638
+ ],
3639
+ [
3640
+ "emit",
3641
+ "ADD_SMALL",
3642
+ {}
3643
+ ]
3644
+ ]
3645
+ ]
3646
+ ],
3647
+ "guard": [
3648
+ "and",
3649
+ [
3650
+ "==",
3651
+ "@entity.active",
3652
+ true
3653
+ ],
3654
+ [
3655
+ "and",
3656
+ [
3657
+ "==",
3658
+ "@entity.running",
3659
+ true
3660
+ ],
3661
+ [
3662
+ "==",
3663
+ "@entity.done",
3664
+ false
3665
+ ]
3666
+ ]
3667
+ ],
3668
+ "interval": 32.0,
3669
+ "name": "dripTick"
3670
+ }
3671
+ ]
3672
+ }
3673
+ ]
3674
+ }
3675
+ ],
3676
+ "schemaVersion": 1,
3677
+ "version": "1.0.0"
3678
+ }