@almadar/std 16.200.0 → 16.201.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 (64) hide show
  1. package/behaviors/lolo/ui/core/molecules/ui-file-tree.lolo +5 -0
  2. package/behaviors/lolo/ui/core/molecules/ui-floating-toolbar.lolo +54 -0
  3. package/behaviors/lolo/ui/core/organisms/ui-dock-layout.lolo +186 -0
  4. package/behaviors/lolo/ui/core/organisms/ui-split-pane.lolo +37 -1
  5. package/behaviors/lolo/ui/game/atoms/std-coef-pad.lolo +5 -3
  6. package/behaviors/lolo/ui/game/atoms/std-platformer-body.lolo +14 -5
  7. package/behaviors/lolo/ui/learning/atoms/ui-math-canvas.lolo +12 -0
  8. package/behaviors/registry/infra/atoms/std-approval-gate.orb +20 -10
  9. package/behaviors/registry/infra/atoms/std-cache-aside.orb +62 -31
  10. package/behaviors/registry/infra/atoms/std-circuit-breaker.orb +32 -16
  11. package/behaviors/registry/infra/atoms/std-data-erasure.orb +16 -8
  12. package/behaviors/registry/infra/atoms/std-mod-queue.orb +16 -8
  13. package/behaviors/registry/infra/atoms/std-rate-limiter.orb +28 -14
  14. package/behaviors/registry/infra/organisms/std-status-lifecycle-control.orb +2 -1
  15. package/behaviors/registry/ml/organisms/std-escalating-decision.orb +10 -5
  16. package/behaviors/registry/ml/organisms/std-knowledge-tracing.orb +4 -2
  17. package/behaviors/registry/ui/core/atoms/std-billable-hour.orb +2 -1
  18. package/behaviors/registry/ui/core/atoms/std-browse.orb +6 -3
  19. package/behaviors/registry/ui/core/atoms/std-dashboard-grid-embedded.orb +2 -1
  20. package/behaviors/registry/ui/core/atoms/std-esign-flow.orb +4 -2
  21. package/behaviors/registry/ui/core/atoms/std-esign-request.orb +6 -3
  22. package/behaviors/registry/ui/core/atoms/std-export.orb +4 -2
  23. package/behaviors/registry/ui/core/atoms/std-gallery.orb +18 -9
  24. package/behaviors/registry/ui/core/atoms/std-import.orb +4 -2
  25. package/behaviors/registry/ui/core/atoms/std-list.orb +6 -3
  26. package/behaviors/registry/ui/core/molecules/ui-file-tree.orb +8 -0
  27. package/behaviors/registry/ui/core/molecules/ui-floating-toolbar.orb +274 -0
  28. package/behaviors/registry/ui/core/organisms/ui-dock-layout.orb +521 -0
  29. package/behaviors/registry/ui/core/organisms/ui-split-pane.orb +109 -2
  30. package/behaviors/registry/ui/game/atoms/std-coef-pad.orb +170 -4
  31. package/behaviors/registry/ui/game/atoms/std-platformer-body.orb +84 -7
  32. package/behaviors/registry/ui/game/organisms/std-arcade-board-3d.orb +8 -4
  33. package/behaviors/registry/ui/game/organisms/std-crew-board-2d.orb +6 -3
  34. package/behaviors/registry/ui/game/organisms/std-dungeon-board-2d.orb +10 -5
  35. package/behaviors/registry/ui/game/organisms/std-market-board-3d.orb +8 -4
  36. package/behaviors/registry/ui/game/organisms/std-objective-board-3d.orb +8 -4
  37. package/behaviors/registry/ui/game/organisms/std-platformer-board-2d.orb +6 -3
  38. package/behaviors/registry/ui/game/organisms/std-survival-board-3d.orb +8 -4
  39. package/behaviors/registry/ui/game/organisms/std-tactics-board-2d.orb +12 -6
  40. package/behaviors/registry/ui/game/organisms/std-tactics-board-3d.orb +8 -4
  41. package/behaviors/registry/ui/game/organisms/std-worldmap-board-2d.orb +6 -3
  42. package/behaviors/registry/ui/learning/atoms/ui-math-canvas.orb +18 -0
  43. package/behaviors/registry/ui/marketing/atoms/std-marketing-article.orb +2 -1
  44. package/behaviors/registry/ui/marketing/atoms/std-marketing-footer.orb +2 -1
  45. package/behaviors/registry/ui/marketing/atoms/std-marketing-split.orb +2 -1
  46. package/behaviors/registry/ui/marketing/atoms/std-marketing-stats.orb +2 -1
  47. package/behaviors/registry/ui/marketing/atoms/std-marketing-steps.orb +2 -1
  48. package/behaviors/registry/ui/marketing/atoms/std-marketing-team.orb +2 -1
  49. package/dist/behaviors/exports-reader.js +1099 -485
  50. package/dist/behaviors/functions/index.d.ts +268 -3
  51. package/dist/behaviors/functions/index.js +1093 -486
  52. package/dist/behaviors/index.d.ts +2 -2
  53. package/dist/behaviors/index.js +1110 -486
  54. package/dist/behaviors/query.d.ts +88 -4
  55. package/dist/behaviors/query.js +1110 -486
  56. package/dist/behaviors-embeddings.hash.json +3 -3
  57. package/dist/behaviors-embeddings.json +11 -3
  58. package/dist/behaviors-registry.json +121784 -2638
  59. package/dist/index.d.ts +2 -2
  60. package/dist/index.js +1110 -486
  61. package/dist/knob-embeddings.hash.json +3 -3
  62. package/dist/knob-embeddings.json +1 -1
  63. package/dist/registry/factory-signatures.json +1 -1
  64. package/package.json +3 -3
@@ -36,6 +36,7 @@ orbital FileTreeOrbital {
36
36
  onNodeAction: @config.onNodeAction
37
37
  nodeActionIcon: @config.nodeActionIcon
38
38
  nodeActionLabel: @config.nodeActionLabel
39
+ onNodeReorder: @config.onNodeReorder
39
40
  className: @config.className
40
41
  indent: @config.indent
41
42
  type: file-tree
@@ -91,6 +92,10 @@ orbital FileTreeOrbital {
91
92
  @label "Node Action Label"
92
93
  @description "Accessible label/tooltip for the row hover action."
93
94
  @tier "presentation"
95
+ onNodeReorder : event = ""
96
+ @label "On Node Reorder"
97
+ @description "Called when a row is dropped onto another, in flat `items` mode; carries the moved node's id, its new parent id (`null` for a root drop), and its index within the new parent's children. Presence-gated: binding this prop is what turns on row dragging."
98
+ @tier "presentation"
94
99
  className : string
95
100
  @label "Class Name"
96
101
  @description "CSS class"
@@ -0,0 +1,54 @@
1
+ app ui-floating-toolbar "1.0.0"
2
+ "FloatingToolbar — UI factory (1:1 with the @almadar/ui floating-toolbar pattern)."
3
+ orbital FloatingToolbarOrbital {
4
+ type FloatingToolbarItemsItem = {
5
+ id : string!
6
+ icon : icon!
7
+ label : string!
8
+ event : string
9
+ action : string
10
+ actionPayload : Map string scalar
11
+ active : boolean
12
+ disabled : boolean
13
+ }
14
+
15
+ entity FloatingToolbarItem [runtime] {
16
+ id : string!
17
+ }
18
+
19
+ trait FloatingToolbarRender -> @rebindable FloatingToolbarItem [interaction, instance] {
20
+ initial: idle
21
+
22
+ state idle {
23
+ INIT -> idle
24
+ (render-ui main {
25
+ items: @config.items
26
+ position: @config.position
27
+ children: @config.children
28
+ className: @config.className
29
+ type: floating-toolbar
30
+ })
31
+ }
32
+
33
+ config {
34
+ items : [FloatingToolbarItemsItem] = [{ id: "Id", icon: "circle", label: "Label", action: "Action", active: false, disabled: false }, { id: "Id 2", icon: "circle", label: "Label 2", action: "Action 2", active: true, disabled: true }]
35
+ @label "Items"
36
+ @description "Tool items rendered as icon buttons"
37
+ @tier "presentation"
38
+ position : "bottom-center" | "bottom-left" | "bottom-right" = "bottom-center"
39
+ @label "Position"
40
+ @description "Strip position within the app frame."
41
+ @tier "presentation"
42
+ children : node
43
+ @label "Children"
44
+ @description "Custom cells appended after the items, separated by a divider"
45
+ @tier "presentation"
46
+ className : string
47
+ @label "Class Name"
48
+ @description "Additional CSS classes on the positioned root"
49
+ @tier "presentation"
50
+ }
51
+ }
52
+
53
+ page "/floating-toolbar" as FloatingToolbarPage -> FloatingToolbarRender
54
+ }
@@ -0,0 +1,186 @@
1
+ app ui-dock-layout "1.0.0"
2
+ "DockLayout — UI factory (1:1 with the @almadar/ui dock-layout pattern)."
3
+ orbital DockLayoutOrbital {
4
+ entity DockLayoutItem [runtime] {
5
+ id : string!
6
+ }
7
+
8
+ trait DockLayoutRender -> @rebindable DockLayoutItem [interaction, instance] {
9
+ initial: idle
10
+
11
+ state idle {
12
+ INIT -> idle
13
+ (render-ui main {
14
+ rail: @config.rail
15
+ sidebar: @config.sidebar
16
+ main: @config.main
17
+ bottomPanel: @config.bottomPanel
18
+ statusBar: @config.statusBar
19
+ secondarySidebar: @config.secondarySidebar
20
+ railWidth: @config.railWidth
21
+ secondarySidebarWidth: @config.secondarySidebarWidth
22
+ sidebarCollapsed: @config.sidebarCollapsed
23
+ onSidebarCollapsedChange: @config.onSidebarCollapsedChange
24
+ sidebarWidth: @config.sidebarWidth
25
+ onSidebarWidthChange: @config.onSidebarWidthChange
26
+ sidebarMinSize: @config.sidebarMinSize
27
+ bottomPanelCollapsed: @config.bottomPanelCollapsed
28
+ onBottomPanelCollapsedChange: @config.onBottomPanelCollapsedChange
29
+ bottomPanelHeight: @config.bottomPanelHeight
30
+ onBottomPanelHeightChange: @config.onBottomPanelHeightChange
31
+ bottomPanelMinSize: @config.bottomPanelMinSize
32
+ secondarySidebarCollapsed: @config.secondarySidebarCollapsed
33
+ onSecondarySidebarCollapsedChange: @config.onSecondarySidebarCollapsedChange
34
+ className: @config.className
35
+ railClassName: @config.railClassName
36
+ sidebarClassName: @config.sidebarClassName
37
+ mainClassName: @config.mainClassName
38
+ bottomPanelClassName: @config.bottomPanelClassName
39
+ statusBarClassName: @config.statusBarClassName
40
+ secondarySidebarClassName: @config.secondarySidebarClassName
41
+ type: dock-layout
42
+ })
43
+ }
44
+
45
+ emits {
46
+ @config.onSidebarCollapsedChange -> external {
47
+ collapsed : boolean
48
+ }
49
+ @description "onSidebarCollapsedChange prop"
50
+ @tier "essential"
51
+ @config.onSidebarWidthChange -> external {
52
+ width : number
53
+ }
54
+ @description "onSidebarWidthChange prop"
55
+ @tier "essential"
56
+ @config.onBottomPanelCollapsedChange -> external {
57
+ collapsed : boolean
58
+ }
59
+ @description "onBottomPanelCollapsedChange prop"
60
+ @tier "essential"
61
+ @config.onBottomPanelHeightChange -> external {
62
+ height : number
63
+ }
64
+ @description "onBottomPanelHeightChange prop"
65
+ @tier "essential"
66
+ @config.onSecondarySidebarCollapsedChange -> external {
67
+ collapsed : boolean
68
+ }
69
+ @description "onSecondarySidebarCollapsedChange prop"
70
+ @tier "essential"
71
+ }
72
+
73
+ config {
74
+ rail : node
75
+ @label "Rail"
76
+ @description "Fixed-width far-left vertical strip (e.g. an icon nav rail)."
77
+ @tier "presentation"
78
+ sidebar : node
79
+ @label "Sidebar"
80
+ @description "Collapsible, resizable left sidebar."
81
+ @tier "presentation"
82
+ main : node = []
83
+ @label "Main"
84
+ @description "Required center region."
85
+ @tier "presentation"
86
+ bottomPanel : node
87
+ @label "Bottom Panel"
88
+ @description "Collapsible, resizable-height bottom panel."
89
+ @tier "presentation"
90
+ statusBar : node
91
+ @label "Status Bar"
92
+ @description "Slim strip pinned to the bottom of the frame, below the bottom panel."
93
+ @tier "presentation"
94
+ secondarySidebar : node
95
+ @label "Secondary Sidebar"
96
+ @description "Collapsible right sidebar."
97
+ @tier "presentation"
98
+ railWidth : number = 56
99
+ @label "Rail Width"
100
+ @description "Width of `rail` in pixels. @default 56"
101
+ @tier "presentation"
102
+ secondarySidebarWidth : number = 280
103
+ @label "Secondary Sidebar Width"
104
+ @description "Width of `secondarySidebar` in pixels (fixed — not resizable). @default 280"
105
+ @tier "presentation"
106
+ sidebarCollapsed : boolean = false
107
+ @label "Sidebar Collapsed"
108
+ @description "Whether `sidebar` is collapsed. @default false"
109
+ @tier "presentation"
110
+ onSidebarCollapsedChange : event = "SIDEBAR_COLLAPSED_CHANGE"
111
+ @label "On Sidebar Collapsed Change"
112
+ @description "onSidebarCollapsedChange prop"
113
+ @tier "presentation"
114
+ sidebarWidth : number = 20
115
+ @label "Sidebar Width"
116
+ @description "Sidebar size as a SplitPane ratio (0-100, percentage of the sidebar/main split). @default 20"
117
+ @tier "presentation"
118
+ onSidebarWidthChange : event = "SIDEBAR_WIDTH_CHANGE"
119
+ @label "On Sidebar Width Change"
120
+ @description "onSidebarWidthChange prop"
121
+ @tier "presentation"
122
+ sidebarMinSize : number = 160
123
+ @label "Sidebar Min Size"
124
+ @description "Minimum sidebar size in pixels, forwarded to SplitPane's `minSize`. @default 160"
125
+ @tier "presentation"
126
+ bottomPanelCollapsed : boolean = false
127
+ @label "Bottom Panel Collapsed"
128
+ @description "Whether `bottomPanel` is collapsed. @default false"
129
+ @tier "presentation"
130
+ onBottomPanelCollapsedChange : event = "BOTTOM_PANEL_COLLAPSED_CHANGE"
131
+ @label "On Bottom Panel Collapsed Change"
132
+ @description "onBottomPanelCollapsedChange prop"
133
+ @tier "presentation"
134
+ bottomPanelHeight : number = 30
135
+ @label "Bottom Panel Height"
136
+ @description "Bottom panel size as a SplitPane ratio (0-100, percentage given to the panel). @default 30"
137
+ @tier "presentation"
138
+ onBottomPanelHeightChange : event = "BOTTOM_PANEL_HEIGHT_CHANGE"
139
+ @label "On Bottom Panel Height Change"
140
+ @description "onBottomPanelHeightChange prop"
141
+ @tier "presentation"
142
+ bottomPanelMinSize : number = 120
143
+ @label "Bottom Panel Min Size"
144
+ @description "Minimum bottom panel size in pixels, forwarded to SplitPane's `minSize`. @default 120"
145
+ @tier "presentation"
146
+ secondarySidebarCollapsed : boolean = false
147
+ @label "Secondary Sidebar Collapsed"
148
+ @description "Whether `secondarySidebar` is collapsed. @default false"
149
+ @tier "presentation"
150
+ onSecondarySidebarCollapsedChange : event = "SECONDARY_SIDEBAR_COLLAPSED_CHANGE"
151
+ @label "On Secondary Sidebar Collapsed Change"
152
+ @description "onSecondarySidebarCollapsedChange prop"
153
+ @tier "presentation"
154
+ className : string
155
+ @label "Class Name"
156
+ @description "Additional CSS classes on the root frame."
157
+ @tier "presentation"
158
+ railClassName : string
159
+ @label "Rail Class Name"
160
+ @description "railClassName prop"
161
+ @tier "presentation"
162
+ sidebarClassName : string
163
+ @label "Sidebar Class Name"
164
+ @description "sidebarClassName prop"
165
+ @tier "presentation"
166
+ mainClassName : string
167
+ @label "Main Class Name"
168
+ @description "mainClassName prop"
169
+ @tier "presentation"
170
+ bottomPanelClassName : string
171
+ @label "Bottom Panel Class Name"
172
+ @description "bottomPanelClassName prop"
173
+ @tier "presentation"
174
+ statusBarClassName : string
175
+ @label "Status Bar Class Name"
176
+ @description "statusBarClassName prop"
177
+ @tier "presentation"
178
+ secondarySidebarClassName : string
179
+ @label "Secondary Sidebar Class Name"
180
+ @description "secondarySidebarClassName prop"
181
+ @tier "presentation"
182
+ }
183
+ }
184
+
185
+ page "/dock-layout" as DockLayoutPage -> DockLayoutRender
186
+ }
@@ -3,6 +3,7 @@ app ui-split-pane "1.0.0"
3
3
  orbital SplitPaneOrbital {
4
4
  entity SplitPaneItem [runtime] {
5
5
  id : string!
6
+ ratio : number
6
7
  }
7
8
 
8
9
  trait SplitPaneRender -> @rebindable SplitPaneItem [interaction, instance] {
@@ -10,9 +11,10 @@ orbital SplitPaneOrbital {
10
11
 
11
12
  state idle {
12
13
  INIT -> idle
14
+ (set @entity.ratio @config.ratio)
13
15
  (render-ui main {
14
16
  direction: @config.direction
15
- ratio: @config.ratio
17
+ ratio: @entity.ratio
16
18
  minSize: @config.minSize
17
19
  resizable: @config.resizable
18
20
  left: @config.left
@@ -20,8 +22,38 @@ orbital SplitPaneOrbital {
20
22
  className: @config.className
21
23
  leftClassName: @config.leftClassName
22
24
  rightClassName: @config.rightClassName
25
+ onRatioChange: @config.onRatioChange
23
26
  type: split-pane
24
27
  })
28
+ RATIO_CHANGE -> idle
29
+ (set @entity.ratio ?ratio)
30
+ (render-ui main {
31
+ direction: @config.direction
32
+ ratio: @entity.ratio
33
+ minSize: @config.minSize
34
+ resizable: @config.resizable
35
+ left: @config.left
36
+ right: @config.right
37
+ className: @config.className
38
+ leftClassName: @config.leftClassName
39
+ rightClassName: @config.rightClassName
40
+ onRatioChange: @config.onRatioChange
41
+ type: split-pane
42
+ })
43
+ }
44
+
45
+ emits {
46
+ @config.onRatioChange -> external {
47
+ ratio : number
48
+ }
49
+ @description "Called with the new ratio while dragging. Providing this makes `ratio` controlled — the rendered split always tracks the prop instead of internal state, mirroring a controlled input. Omit for uncontrolled (self-tracked) behavior."
50
+ @tier "essential"
51
+ }
52
+
53
+ listens {
54
+ RATIO_CHANGE {
55
+ ratio : number
56
+ }
25
57
  }
26
58
 
27
59
  config {
@@ -61,6 +93,10 @@ orbital SplitPaneOrbital {
61
93
  @label "Right Class Name"
62
94
  @description "Class for right/bottom pane"
63
95
  @tier "presentation"
96
+ onRatioChange : event = "RATIO_CHANGE"
97
+ @label "On Ratio Change"
98
+ @description "Called with the new ratio while dragging. Providing this makes `ratio` controlled — the rendered split always tracks the prop instead of internal state, mirroring a controlled input. Omit for uncontrolled (self-tracked) behavior."
99
+ @tier "presentation"
64
100
  }
65
101
  }
66
102
 
@@ -5,6 +5,7 @@ orbital CoefPadOrbital {
5
5
  x0 : number!
6
6
  x1 : number!
7
7
  a : number!
8
+ b : number
8
9
  h : number!
9
10
  k : number!
10
11
  }
@@ -50,7 +51,7 @@ orbital CoefPadOrbital {
50
51
  (let ((remaining (array/len (array/filter @entity.coefPads (fn c (and (== (object/get @c applied) false) (!= (object/get @c id) (object/get @p id))))))))
51
52
  (do
52
53
  (set @entity.coefPads (array/map @entity.coefPads (fn c (if (== (object/get @c id) (object/get @p id)) (object/merge @c { applied: true }) @c))))
53
- (emit COEF_PAD_APPLIED { id: (object/get @p id), x: (object/get @p x), y: (object/get @p y), x0: (object/get @m x0), x1: (object/get @m x1), a: (object/get @m a), h: (object/get @m h), k: (object/get @m k), hint: (object/get @p hint), hop: (object/get @p hop), samples: (object/get @p samples) })
54
+ (emit COEF_PAD_APPLIED { id: (object/get @p id), x: (object/get @p x), y: (object/get @p y), x0: (object/get @m x0), x1: (object/get @m x1), a: (object/get @m a), b: (if (== (object/get @m b) null) 1 (object/get @m b)), h: (object/get @m h), k: (object/get @m k), hint: (object/get @p hint), hop: (object/get @p hop), samples: (object/get @p samples) })
54
55
  (if (and (== @entity.coefCompleted false) (== @remaining 0))
55
56
  (do
56
57
  (set @entity.coefCompleted true)
@@ -71,13 +72,14 @@ orbital CoefPadOrbital {
71
72
  x0 : number!
72
73
  x1 : number!
73
74
  a : number!
75
+ b : number
74
76
  h : number!
75
77
  k : number!
76
78
  hint : string
77
79
  hop : boolean
78
80
  samples : [CoefModSample]
79
81
  }
80
- @description "The player stood on an unapplied coefficient pad; carries the pad position and the full mod (x0, x1, a, h, k) so the board appends it to the body authority's curveMods and hops the player onto the reshaped road. Fires once per pad per run."
82
+ @description "The player stood on an unapplied coefficient pad; carries the pad position and the full mod (x0, x1, a, b, h, k) so the board appends it to the body authority's curveMods and hops the player onto the reshaped road. Fires once per pad per run."
81
83
  @tier "domain"
82
84
  COEF_PAD_SET_COMPLETED -> external {
83
85
  }
@@ -97,7 +99,7 @@ orbital CoefPadOrbital {
97
99
  @tier "domain"
98
100
  coefPads : [CoefPad] = []
99
101
  @label "Coefficient Pads"
100
- @description "One row per pad: id, center (x, y in world units), the mod applied to the road while inside x0..x1 (a scales slope+height, h shifts horizontally, k lifts), and the hint floated on apply, and hop (true = the board teleports the player onto the reshaped surface — use when the mod steps the road far from the pad; false = the skate snap carries the player, preserving speed). applied is stamped at runtime."
102
+ @description "One row per pad: id, center (x, y in world units), the mod applied to the road while inside x0..x1 (a scales slope+height, b compresses/stretch period, h shifts horizontally, k lifts), and the hint floated on apply, and hop (true = the board teleports the player onto the reshaped surface — use when the mod steps the road far from the pad; false = the skate snap carries the player, preserving speed). applied is stamped at runtime."
101
103
  @tier "domain"
102
104
  reachX : number = 0.7
103
105
  @label "Reach X"
@@ -36,6 +36,7 @@ orbital PlatformerBodyOrbital {
36
36
  x0 : number!
37
37
  x1 : number!
38
38
  a : number!
39
+ b : number!
39
40
  h : number!
40
41
  k : number!
41
42
  }
@@ -81,7 +82,10 @@ orbital PlatformerBodyOrbital {
81
82
  (set @entity.skating false)
82
83
 
83
84
  CURVE_MOD_ADD -> active when @config.curveModsEnabled
84
- (set @entity.curveMods (array/append @entity.curveMods { x0: @payload.x0, x1: @payload.x1, a: @payload.a, h: @payload.h, k: @payload.k }))
85
+ (set @entity.curveMods (array/append @entity.curveMods { x0: @payload.x0, x1: @payload.x1, a: @payload.a, b: (if (== @payload.b null) 1 @payload.b), h: @payload.h, k: @payload.k }))
86
+
87
+ CURVE_MOD_CLEAR -> active when @config.curveModsEnabled
88
+ (set @entity.curveMods [])
85
89
 
86
90
  SET_TUNING -> active
87
91
  (set @entity.tuning (object/merge @entity.tuning (if (== @payload.jumpStrength null) {} { jumpStrength: @payload.jumpStrength })))
@@ -123,7 +127,7 @@ orbital PlatformerBodyOrbital {
123
127
  (let ((gapBreak (and (> @config.skateMaxGap 0) (> (- (object/get @rightSamp x) (object/get @leftSamp x)) @config.skateMaxGap))))
124
128
  (let ((mods (if (and @config.curveModsEnabled @inRange) (array/filter @entity.curveMods (fn m (and (>= @cx (object/get @m x0)) (<= @cx (object/get @m x1))))) [])))
125
129
  (let ((modded (array/reduce @mods { y: @curveY, s: @slope } (fn (acc m)
126
- (let ((modX (- @cx (object/get @m h))))
130
+ (let ((modX (* (object/get @m b) (- @cx (object/get @m h)))))
127
131
  (let ((modInRange (and (>= @modX (object/get (array/first @config.skateCurve) x)) (< @modX (object/get (array/last @config.skateCurve) x)))))
128
132
  (let ((modLeft (if @modInRange (array/last (array/filter @config.skateCurve (fn s (<= (object/get @s x) @modX)))) null)))
129
133
  (let ((modRight (if @modInRange (array/first (array/filter @config.skateCurve (fn s (> (object/get @s x) @modX)))) null)))
@@ -131,7 +135,7 @@ orbital PlatformerBodyOrbital {
131
135
  (let ((modSlope (if @modOK (/ (- (object/get @modRight y) (object/get @modLeft y)) (- (object/get @modRight x) (object/get @modLeft x))) 0)))
132
136
  (let ((modCurveY (if @modOK (+ (object/get @modLeft y) (* @modSlope (- @modX (object/get @modLeft x)))) 0)))
133
137
  (if @modOK
134
- { y: (+ (object/get @acc y) (- (+ (* (object/get @m a) @modCurveY) (object/get @m k)) @curveY)), s: (+ (object/get @acc s) (- (* (object/get @m a) @modSlope) @slope)) }
138
+ { y: (+ (object/get @acc y) (- (+ (* (object/get @m a) @modCurveY) (object/get @m k)) @curveY)), s: (+ (object/get @acc s) (- (* (* (object/get @m a) (object/get @m b)) @modSlope) @slope)) }
135
139
  @acc))))))))))))
136
140
  (let ((slope (object/get @modded s)))
137
141
  (let ((curveY (object/get @modded y)))
@@ -236,13 +240,18 @@ orbital PlatformerBodyOrbital {
236
240
  }
237
241
  @description "Body crossed killY in the gravity direction (pit fall); fires once per fall and re-arms on PLACE/RESTART, leaving the respawn rule to the board"
238
242
  @tier "domain"
243
+ CURVE_MOD_CLEAR -> external {
244
+ }
245
+ @description "Curve mods were cleared; the skate surface is back to the base skateCurve until a new mod is added."
246
+ @tier "domain"
239
247
  }
240
248
 
241
249
  listens {
242
250
  STEER { dir : number! }
243
251
  JUMP { id : string }
244
252
  PLACE { x : number!, y : number! }
245
- CURVE_MOD_ADD { x0 : number!, x1 : number!, a : number!, h : number!, k : number! }
253
+ CURVE_MOD_ADD { x0 : number!, x1 : number!, a : number!, b : number, h : number!, k : number! }
254
+ CURVE_MOD_CLEAR { }
246
255
  SET_TUNING { jumpStrength : number, moveSpeed : number, gravity : number }
247
256
  RESTART { id : string }
248
257
  }
@@ -266,7 +275,7 @@ orbital PlatformerBodyOrbital {
266
275
  @tier "domain"
267
276
  curveModsEnabled : boolean = false
268
277
  @label "Curve Mods Enabled"
269
- @description "When true, entity.curveMods reshape the skate surface inside each mod's x-range: the road samples the base curve at (x − h) and applies a·y + k (slope scales by a) — coefficient pads lift/tilt the segment the player is riding. Multiple overlapping mods stack by summing each mod's delta from the base surface; a mod whose shifted sample leaves the curve range is skipped. Default off: boards without coef pads pay nothing."
278
+ @description "When true, entity.curveMods reshape the skate surface inside each mod's x-range: the road samples the base curve at b·(x − h) and applies a·y + k (slope scales by a·b) — coefficient pads lift/tilt/compress the segment the player is riding. Multiple overlapping mods stack by summing each mod's delta from the base surface; a mod whose shifted sample leaves the curve range is skipped. Default off: boards without coef pads pay nothing."
270
279
  @tier "domain"
271
280
  jumpStrength : number = 11
272
281
  @label "Jump Strength"
@@ -172,6 +172,8 @@ orbital MathCanvasOrbital {
172
172
  gridColor: @config.gridColor
173
173
  axisColor: @config.axisColor
174
174
  showTickLabels: @config.showTickLabels
175
+ tickLabelFontSize: @config.tickLabelFontSize
176
+ labelFontSize: @config.labelFontSize
175
177
  showCurveLabels: @config.showCurveLabels
176
178
  curves: @config.curves
177
179
  points: @config.points
@@ -211,6 +213,8 @@ orbital MathCanvasOrbital {
211
213
  gridColor: @config.gridColor
212
214
  axisColor: @config.axisColor
213
215
  showTickLabels: @config.showTickLabels
216
+ tickLabelFontSize: @config.tickLabelFontSize
217
+ labelFontSize: @config.labelFontSize
214
218
  showCurveLabels: @config.showCurveLabels
215
219
  curves: @payload.curves
216
220
  points: @payload.points
@@ -324,6 +328,14 @@ orbital MathCanvasOrbital {
324
328
  @label "Show Tick Labels"
325
329
  @description "Draw numeric labels on grid lines (default false)."
326
330
  @tier "presentation"
331
+ tickLabelFontSize : number = 10
332
+ @label "Tick Label Font Size"
333
+ @description "Font size in px for axis tick labels (default 10)."
334
+ @tier "presentation"
335
+ labelFontSize : number = 12
336
+ @label "Label Font Size"
337
+ @description "Base font size in px for all other canvas annotations (points, vectors, guides, curves, regions, angles, hops; default 12)."
338
+ @tier "presentation"
327
339
  showCurveLabels : boolean = false
328
340
  @label "Show Curve Labels"
329
341
  @description "Draw each curve's `label` at its last in-range sample (default false)."
@@ -382,7 +382,8 @@
382
382
  "linkedEntity": "ApprovalRequest",
383
383
  "linkedEntityId": "ent_01KXG04EYQFWN6TM97JNWHHSF4",
384
384
  "name": "LoadingSpinner",
385
- "ref": "Spinner.traits.SpinnerRender"
385
+ "ref": "Spinner.traits.SpinnerRender",
386
+ "refId": "trt_01KXG04KQTE55FSTDE4V4XKESN"
386
387
  },
387
388
  {
388
389
  "config": {
@@ -395,7 +396,8 @@
395
396
  "linkedEntity": "ApprovalRequest",
396
397
  "linkedEntityId": "ent_01KXG04EYQFWN6TM97JNWHHSF4",
397
398
  "name": "ErrorSpinner",
398
- "ref": "Spinner.traits.SpinnerRender"
399
+ "ref": "Spinner.traits.SpinnerRender",
400
+ "refId": "trt_01KXG04KQTE55FSTDE4V4XKESN"
399
401
  },
400
402
  {
401
403
  "config": {
@@ -416,7 +418,8 @@
416
418
  "linkedEntity": "ApprovalRequest",
417
419
  "linkedEntityId": "ent_01KXG04EYQFWN6TM97JNWHHSF4",
418
420
  "name": "LoadingText",
419
- "ref": "Typography.traits.TypographyRender"
421
+ "ref": "Typography.traits.TypographyRender",
422
+ "refId": "trt_01KXG04MN4YEZRM29MVNFTYM98"
420
423
  },
421
424
  {
422
425
  "config": {
@@ -429,7 +432,8 @@
429
432
  "linkedEntity": "ApprovalRequest",
430
433
  "linkedEntityId": "ent_01KXG04EYQFWN6TM97JNWHHSF4",
431
434
  "name": "ShieldCheckIcon",
432
- "ref": "Icon.traits.IconRender"
435
+ "ref": "Icon.traits.IconRender",
436
+ "refId": "trt_01KXG04K2JE4GSQVWEWHAHDE2A"
433
437
  },
434
438
  {
435
439
  "config": {
@@ -446,7 +450,8 @@
446
450
  "linkedEntity": "ApprovalRequest",
447
451
  "linkedEntityId": "ent_01KXG04EYQFWN6TM97JNWHHSF4",
448
452
  "name": "ApprovalQueueTitle",
449
- "ref": "Typography.traits.TypographyRender"
453
+ "ref": "Typography.traits.TypographyRender",
454
+ "refId": "trt_01KXG04MN4YEZRM29MVNFTYM98"
450
455
  },
451
456
  {
452
457
  "config": {
@@ -463,7 +468,8 @@
463
468
  "linkedEntity": "ApprovalRequest",
464
469
  "linkedEntityId": "ent_01KXG04EYQFWN6TM97JNWHHSF4",
465
470
  "name": "DenyReasonTitle",
466
- "ref": "Typography.traits.TypographyRender"
471
+ "ref": "Typography.traits.TypographyRender",
472
+ "refId": "trt_01KXG04MN4YEZRM29MVNFTYM98"
467
473
  },
468
474
  {
469
475
  "config": {
@@ -484,7 +490,8 @@
484
490
  "linkedEntity": "ApprovalRequest",
485
491
  "linkedEntityId": "ent_01KXG04EYQFWN6TM97JNWHHSF4",
486
492
  "name": "DenyReasonHint",
487
- "ref": "Typography.traits.TypographyRender"
493
+ "ref": "Typography.traits.TypographyRender",
494
+ "refId": "trt_01KXG04MN4YEZRM29MVNFTYM98"
488
495
  },
489
496
  {
490
497
  "config": {
@@ -509,14 +516,16 @@
509
516
  "linkedEntity": "ApprovalRequest",
510
517
  "linkedEntityId": "ent_01KXG04EYQFWN6TM97JNWHHSF4",
511
518
  "name": "CloseButton",
512
- "ref": "Button.traits.ButtonRender"
519
+ "ref": "Button.traits.ButtonRender",
520
+ "refId": "trt_01KXG04JBQPWD7RW8X33NXPXG9"
513
521
  },
514
522
  {
515
523
  "id": "trt_01KY21K6QC0P4NS69R6ATZPC18",
516
524
  "linkedEntity": "ApprovalRequest",
517
525
  "linkedEntityId": "ent_01KXG04EYQFWN6TM97JNWHHSF4",
518
526
  "name": "ApprovalDivider",
519
- "ref": "Divider.traits.DividerRender"
527
+ "ref": "Divider.traits.DividerRender",
528
+ "refId": "trt_01KXG04JVTJZ479S2KPR7HD1KB"
520
529
  },
521
530
  {
522
531
  "config": {
@@ -533,7 +542,8 @@
533
542
  "linkedEntity": "ApprovalRequest",
534
543
  "linkedEntityId": "ent_01KXG04EYQFWN6TM97JNWHHSF4",
535
544
  "name": "ErrorAlert",
536
- "ref": "Alert.traits.AlertRender"
545
+ "ref": "Alert.traits.AlertRender",
546
+ "refId": "trt_01KXG04MT125AX1BGFS3ZNGX67"
537
547
  },
538
548
  {
539
549
  "capabilities": [