@almadar/std 16.178.0 → 16.180.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 (80) hide show
  1. package/behaviors/lolo/ui/core/atoms/std-detail-layout.lolo +82 -0
  2. package/behaviors/lolo/ui/core/molecules/ui-breadcrumb.lolo +20 -2
  3. package/behaviors/lolo/ui/core/molecules/ui-fx-overlay.lolo +63 -0
  4. package/behaviors/lolo/ui/core/molecules/ui-page-header.lolo +1 -1
  5. package/behaviors/lolo/ui/core/organisms/ui-detail-panel.lolo +6 -0
  6. package/behaviors/lolo/ui/core/organisms/ui-form-section.lolo +2 -2
  7. package/behaviors/lolo/ui/core/organisms/ui-form.lolo +2 -2
  8. package/behaviors/lolo/ui/core/templates/ui-dashboard-layout.lolo +2 -2
  9. package/behaviors/lolo/ui/game/atoms/std-fx-particles.lolo +23 -4
  10. package/behaviors/lolo/ui/game/atoms/std-platformer-body.lolo +251 -0
  11. package/behaviors/lolo/ui/game/atoms/ui-draw-fx-layer.lolo +109 -0
  12. package/behaviors/lolo/ui/game/organisms/std-arcade-board-3d.lolo +32 -2
  13. package/behaviors/lolo/ui/game/organisms/std-crew-board-2d.lolo +32 -2
  14. package/behaviors/lolo/ui/game/organisms/std-dungeon-board-2d.lolo +32 -2
  15. package/behaviors/lolo/ui/game/organisms/std-market-board-3d.lolo +32 -2
  16. package/behaviors/lolo/ui/game/organisms/std-objective-board-3d.lolo +32 -2
  17. package/behaviors/lolo/ui/game/organisms/std-platformer-board-2d.lolo +391 -0
  18. package/behaviors/lolo/ui/game/organisms/std-survival-board-3d.lolo +32 -2
  19. package/behaviors/lolo/ui/game/organisms/std-tactics-board-2d.lolo +34 -6
  20. package/behaviors/lolo/ui/game/organisms/std-tactics-board-3d.lolo +34 -4
  21. package/behaviors/lolo/ui/learning/atoms/std-learn-arrangement.lolo +8 -0
  22. package/behaviors/lolo/ui/learning/atoms/std-learn-classify.lolo +8 -0
  23. package/behaviors/lolo/ui/learning/atoms/std-learn-derivation.lolo +8 -0
  24. package/behaviors/lolo/ui/learning/atoms/std-learn-doser.lolo +9 -0
  25. package/behaviors/lolo/ui/learning/atoms/std-learn-estimate.lolo +8 -0
  26. package/behaviors/lolo/ui/learning/atoms/std-learn-fx-cues.lolo +147 -0
  27. package/behaviors/lolo/ui/learning/atoms/std-learn-goal-seek.lolo +8 -0
  28. package/behaviors/lolo/ui/learning/atoms/std-learn-hotspot.lolo +8 -0
  29. package/behaviors/lolo/ui/learning/atoms/std-learn-predict.lolo +8 -0
  30. package/behaviors/lolo/ui/learning/atoms/std-learn-scatter-fit.lolo +9 -0
  31. package/behaviors/lolo/ui/learning/atoms/std-learn-speed-drill.lolo +8 -0
  32. package/behaviors/lolo/ui/learning/atoms/std-learn-tour-3d.lolo +9 -0
  33. package/behaviors/registry/ui/core/atoms/std-detail-layout.orb +265 -0
  34. package/behaviors/registry/ui/core/molecules/ui-breadcrumb.orb +55 -17
  35. package/behaviors/registry/ui/core/molecules/ui-fx-overlay.orb +281 -0
  36. package/behaviors/registry/ui/core/molecules/ui-page-header.orb +1 -1
  37. package/behaviors/registry/ui/core/organisms/ui-detail-panel.orb +8 -0
  38. package/behaviors/registry/ui/core/organisms/ui-form-section.orb +6 -0
  39. package/behaviors/registry/ui/core/organisms/ui-form.orb +6 -0
  40. package/behaviors/registry/ui/core/templates/ui-dashboard-layout.orb +2 -2
  41. package/behaviors/registry/ui/game/atoms/std-fx-particles.orb +265 -4
  42. package/behaviors/registry/ui/game/atoms/std-platformer-body.orb +2136 -0
  43. package/behaviors/registry/ui/game/atoms/ui-draw-fx-layer.orb +523 -0
  44. package/behaviors/registry/ui/game/organisms/std-arcade-board-3d.orb +159 -70
  45. package/behaviors/registry/ui/game/organisms/std-crew-board-2d.orb +148 -58
  46. package/behaviors/registry/ui/game/organisms/std-dungeon-board-2d.orb +169 -58
  47. package/behaviors/registry/ui/game/organisms/std-market-board-3d.orb +160 -70
  48. package/behaviors/registry/ui/game/organisms/std-objective-board-3d.orb +151 -60
  49. package/behaviors/registry/ui/game/organisms/std-platformer-board-2d.orb +2981 -0
  50. package/behaviors/registry/ui/game/organisms/std-survival-board-3d.orb +150 -60
  51. package/behaviors/registry/ui/game/organisms/std-tactics-board-2d.orb +163 -316
  52. package/behaviors/registry/ui/game/organisms/std-tactics-board-3d.orb +156 -184
  53. package/behaviors/registry/ui/learning/atoms/std-learn-arrangement.orb +62 -0
  54. package/behaviors/registry/ui/learning/atoms/std-learn-classify.orb +73 -0
  55. package/behaviors/registry/ui/learning/atoms/std-learn-derivation.orb +66 -0
  56. package/behaviors/registry/ui/learning/atoms/std-learn-doser.orb +71 -0
  57. package/behaviors/registry/ui/learning/atoms/std-learn-estimate.orb +72 -0
  58. package/behaviors/registry/ui/learning/atoms/std-learn-fx-cues.orb +1546 -0
  59. package/behaviors/registry/ui/learning/atoms/std-learn-goal-seek.orb +58 -0
  60. package/behaviors/registry/ui/learning/atoms/std-learn-hotspot.orb +72 -0
  61. package/behaviors/registry/ui/learning/atoms/std-learn-predict.orb +72 -0
  62. package/behaviors/registry/ui/learning/atoms/std-learn-scatter-fit.orb +71 -0
  63. package/behaviors/registry/ui/learning/atoms/std-learn-speed-drill.orb +72 -0
  64. package/behaviors/registry/ui/learning/atoms/std-learn-tour-3d.orb +176 -0
  65. package/canonical-operators.json +14 -2
  66. package/dist/behaviors/exports-reader.js +8655 -5239
  67. package/dist/behaviors/functions/index.d.ts +686 -16
  68. package/dist/behaviors/functions/index.js +8637 -5240
  69. package/dist/behaviors/index.d.ts +1 -1
  70. package/dist/behaviors/index.js +8656 -5240
  71. package/dist/behaviors/query.js +8655 -5239
  72. package/dist/behaviors-embeddings.hash.json +3 -3
  73. package/dist/behaviors-embeddings.json +381 -353
  74. package/dist/behaviors-registry.json +2415 -443
  75. package/dist/index.d.ts +1 -1
  76. package/dist/index.js +8656 -5240
  77. package/dist/knob-embeddings.hash.json +3 -3
  78. package/dist/knob-embeddings.json +1 -1
  79. package/dist/registry/factory-signatures.json +1 -1
  80. package/package.json +2 -2
@@ -0,0 +1,109 @@
1
+ app ui-draw-fx-layer "1.0.0"
2
+ "DrawFxLayer — UI factory (1:1 with the @almadar/ui draw-fx-layer pattern)."
3
+ orbital DrawFxLayerOrbital {
4
+ type DrawFxLayerItemsItem = {
5
+ id : string!
6
+ type : string!
7
+ position : DrawFxLayerItemsItemPosition
8
+ x : number!
9
+ z : number
10
+ y : number
11
+ message : string
12
+ ttl : number!
13
+ maxTtl : number
14
+ bornAt : number
15
+ space : "world" | "screen"
16
+ effect : "confetti" | "flash" | "shake" | "sparkle" | "float-text" | "streak-glow"
17
+ color : string
18
+ size : number
19
+ vx : number
20
+ vy : number
21
+ vz : number
22
+ particleCount : number
23
+ }
24
+ type DrawFxLayerItemsItemPosition = {
25
+ x : number!
26
+ y : number!
27
+ z : number
28
+ }
29
+ type DrawFxLayerPresetsItem = {
30
+ type : string!
31
+ color : string
32
+ color2 : string
33
+ size : number
34
+ shape : "spark" | "ring" | "puff" | "streak"
35
+ count : number
36
+ glow : number
37
+ gravity : number
38
+ vx : number
39
+ vy : number
40
+ vz : number
41
+ space : "world" | "screen"
42
+ effect : "confetti" | "flash" | "shake" | "sparkle" | "float-text" | "streak-glow"
43
+ particleCount : number
44
+ }
45
+ type DrawFxLayerSpritesValue = {
46
+ url : asset!
47
+ role : string!
48
+ category : string!
49
+ animations : [string]
50
+ style : "pixel" | "vector" | "hd" | "1-bit" | "isometric"
51
+ variant : string
52
+ dimension : "2d" | "3d"
53
+ aspect : "1:1" | "16:9" | "5:7" | "8:1"
54
+ atlas : asset
55
+ sprite : string
56
+ name : string
57
+ thumbnailUrl : string
58
+ }
59
+
60
+ entity DrawFxLayerItem [runtime] {
61
+ id : string!
62
+ }
63
+
64
+ trait DrawFxLayerRender -> @rebindable DrawFxLayerItem [interaction, instance] {
65
+ initial: idle
66
+
67
+ state idle {
68
+ INIT -> idle
69
+ (render-ui main {
70
+ items: @config.items
71
+ presets: @config.presets
72
+ art: @config.art
73
+ sprites: @config.sprites
74
+ tickMs: @config.tickMs
75
+ textColor: @config.textColor
76
+ type: draw-fx-layer
77
+ })
78
+ }
79
+
80
+ config {
81
+ items : [DrawFxLayerItemsItem] = [{ id: "e1", x: 2, y: 2, type: "spawn", message: "Unit spawned" }, { id: "e2", x: 3, y: 1, type: "effect", message: "Attack landed" }]
82
+ @label "Items"
83
+ @description "The live fx entries — the mechanic's `@entity.fx` list passed whole; `space: 'screen'` entries are skipped (the overlay owns those)."
84
+ @tier "presentation"
85
+ presets : [DrawFxLayerPresetsItem] = []
86
+ @label "Presets"
87
+ @description "Consumer-declared effect vocabulary — one row per fx `type` (look + recipe). Unknown types fall back to a neutral spark burst."
88
+ @tier "presentation"
89
+ art : Map string Map string [object] = { item: {} }
90
+ @label "Art"
91
+ @description "Vector art per fx type (an asset-art map: type → anim-state → drawables); a type's `idle` state wins over sprites/procedural."
92
+ @tier "presentation"
93
+ sprites : Map string DrawFxLayerSpritesValue = { item: { url: "https://almadar-kflow-assets.web.app/shared/ui-roguelike-board/default/features/sword.png", role: "item", category: "item", animations: ["static"], style: "pixel", dimension: "2d", aspect: "1:1", name: "item", thumbnailUrl: "" } }
94
+ @label "Sprites"
95
+ @description "Sprite asset per fx type (an asset-manifest effects map) — used when no vector art matches."
96
+ @tier "presentation"
97
+ tickMs : number
98
+ @label "Tick Ms"
99
+ @description "The fx mechanic's decay tick period in ms; lifetime = maxTtl × tickMs. Default 500."
100
+ @tier "presentation"
101
+ textColor : string
102
+ @label "Text Color"
103
+ @description "Floating-message text color when an item declares none. Default `#ffe066`."
104
+ @tier "presentation"
105
+ }
106
+ }
107
+
108
+ page "/draw-fx-layer" as DrawFxLayerPage -> DrawFxLayerRender
109
+ }
@@ -50,6 +50,32 @@ orbital ArcadeBoard3DFrameOrbital {
50
50
  y : number
51
51
  message : string
52
52
  ttl : number!
53
+ maxTtl : number
54
+ bornAt : number
55
+ space : string
56
+ effect : string
57
+ color : string
58
+ size : number
59
+ vx : number
60
+ vy : number
61
+ vz : number
62
+ particleCount : number
63
+ }
64
+ type FxPreset = {
65
+ type : string!
66
+ color : string
67
+ color2 : string
68
+ size : number
69
+ shape : string
70
+ count : number
71
+ glow : number
72
+ gravity : number
73
+ vx : number
74
+ vy : number
75
+ vz : number
76
+ space : string
77
+ effect : string
78
+ particleCount : number
53
79
  }
54
80
  type ValidMove = { x : number! z : number! }
55
81
  type Machine = {
@@ -159,7 +185,7 @@ orbital ArcadeBoard3DFrameOrbital {
159
185
  { type: draw-shape-layer, items: (array/map @entity.units (fn u { type: draw-shape, shape: "rect", position: { x: (object/get (object/get @u position) x), y: (object/get (object/get @u position) y), z: (object/get @u z) }, offsetY: -0.6, width: 0.8, height: 0.12, fill: "rgba(0,0,0,0.6)" })) }
160
186
  { type: draw-shape-layer, items: (array/map @entity.units (fn u { type: draw-shape, shape: "rect", position: { x: (object/get (object/get @u position) x), y: (object/get (object/get @u position) y), z: (object/get @u z) }, offsetY: -0.6, width: (* 0.8 (/ (object/get @u health) (object/get @u maxHealth))), height: 0.12, fill: "#22c55e" })) }
161
187
  { type: draw-text-layer, items: (array/map @entity.units (fn u { type: draw-text, text: (object/get @u name), position: { x: (object/get (object/get @u position) x), y: (object/get (object/get @u position) y), z: (object/get @u z) }, offsetY: -0.85, color: "#ffffff" })) }
162
- { type: draw-text-layer, items: (array/map @entity.fx (fn f { type: draw-text, text: (object/get @f message), position: { x: (object/get @f x), y: (object/get @f y), z: (object/get @f z) }, color: "#ffe066" })) }
188
+ { type: draw-fx-layer, items: @entity.fx, tickMs: 500, presets: @config.fxPresets }
163
189
  ] } ]
164
190
  })
165
191
 
@@ -205,7 +231,7 @@ orbital ArcadeBoard3DFrameOrbital {
205
231
  { type: draw-shape-layer, items: (array/map @entity.units (fn u { type: draw-shape, shape: "rect", position: { x: (object/get (object/get @u position) x), y: (object/get (object/get @u position) y), z: (object/get @u z) }, offsetY: -0.6, width: 0.8, height: 0.12, fill: "rgba(0,0,0,0.6)" })) }
206
232
  { type: draw-shape-layer, items: (array/map @entity.units (fn u { type: draw-shape, shape: "rect", position: { x: (object/get (object/get @u position) x), y: (object/get (object/get @u position) y), z: (object/get @u z) }, offsetY: -0.6, width: (* 0.8 (/ (object/get @u health) (object/get @u maxHealth))), height: 0.12, fill: "#22c55e" })) }
207
233
  { type: draw-text-layer, items: (array/map @entity.units (fn u { type: draw-text, text: (object/get @u name), position: { x: (object/get (object/get @u position) x), y: (object/get (object/get @u position) y), z: (object/get @u z) }, offsetY: -0.85, color: "#ffffff" })) }
208
- { type: draw-text-layer, items: (array/map @entity.fx (fn f { type: draw-text, text: (object/get @f message), position: { x: (object/get @f x), y: (object/get @f y), z: (object/get @f z) }, color: "#ffe066" })) }
234
+ { type: draw-fx-layer, items: @entity.fx, tickMs: 500, presets: @config.fxPresets }
209
235
  ] } ]
210
236
  })
211
237
 
@@ -315,6 +341,10 @@ orbital ArcadeBoard3DFrameOrbital {
315
341
  @label "Features"
316
342
  @description "Arcade machines + decorations rendered on the board (static; matched against machines for playability)."
317
343
  @tier "presentation"
344
+ fxPresets : [FxPreset] = [ { type: "score", color: "#ffd23f", color2: "#ff6b35", size: 0.55, shape: "spark", count: 7, glow: 0.16, vy: -0.3 }, { type: "info", color: "#38bdf8", color2: "#0c4a6e", size: 0.4, shape: "puff", count: 4 } ]
345
+ @label "Fx Presets"
346
+ @description "This board's effect vocabulary — one look/recipe row per fx type its mechanics emit; unknown types fall back to a neutral spark."
347
+ @tier "presentation"
318
348
  assetManifest : AssetManifest = { terrains: {}, units: {}, features: {}, effects: {} }
319
349
  @label "Asset Manifest"
320
350
  @description "Per-role model manifest resolving tile/unit/feature models by terrain/category key."
@@ -48,6 +48,32 @@ orbital CrewBoard2DOrbital {
48
48
  y : number
49
49
  message : string
50
50
  ttl : number!
51
+ maxTtl : number
52
+ bornAt : number
53
+ space : string
54
+ effect : string
55
+ color : string
56
+ size : number
57
+ vx : number
58
+ vy : number
59
+ vz : number
60
+ particleCount : number
61
+ }
62
+ type FxPreset = {
63
+ type : string!
64
+ color : string
65
+ color2 : string
66
+ size : number
67
+ shape : string
68
+ count : number
69
+ glow : number
70
+ gravity : number
71
+ vx : number
72
+ vy : number
73
+ vz : number
74
+ space : string
75
+ effect : string
76
+ particleCount : number
51
77
  }
52
78
  type ValidMove = { x : number! z : number! }
53
79
  type Feature = {
@@ -141,7 +167,7 @@ orbital CrewBoard2DOrbital {
141
167
  { type: draw-shape-layer, items: (array/map @entity.units (fn u { type: draw-shape, shape: "rect", position: (object/get @u position), anchor: "ground", offsetX: -0.25, offsetY: -0.6, width: 0.5, height: 0.12, fill: "rgba(0,0,0,0.6)" })) }
142
168
  { type: draw-shape-layer, items: (array/map @entity.units (fn u { type: draw-shape, shape: "rect", position: (object/get @u position), anchor: "ground", offsetX: -0.25, offsetY: -0.6, width: (* 0.5 (/ (object/get @u health) (object/get @u maxHealth))), height: 0.12, fill: "#22c55e" })) }
143
169
  { type: draw-text-layer, items: (array/map @entity.units (fn u { type: draw-text, text: (object/get @u name), position: (object/get @u position), offsetY: -0.85, color: "#ffffff" })) }
144
- { type: draw-text-layer, items: (array/map @entity.fx (fn f { type: draw-text, text: (object/get @f message), position: { x: (object/get @f x), y: (object/get @f y) }, color: "#ffe066" })) }
170
+ { type: draw-fx-layer, items: @entity.fx, tickMs: 500, presets: @config.fxPresets, sprites: (object/get @config.assetManifest effects) }
145
171
  { type: draw-sprite-layer, items: (array/map (array/filter (array/flatten (array/map @entity.units (fn u (array/flatten (array/map [ ["idle", 4], ["walk", 2], ["attack", 1], ["hit", 1], ["death", 1] ] (fn st (array/map (array/range 0 (array/nth @st 1)) (fn i (if (and (object/get (object/get @u modelUrl) url) (str/includes (object/get (object/get @u modelUrl) url) ".svg")) (str/concat (array/nth (str/split (object/get (object/get @u modelUrl) url) ".svg") 0) (str/concat "." (str/concat (array/nth @st 0) (str/concat "-" (str/concat @i ".svg"))))) ""))))))))) (fn w (!= @w ""))) (fn warmUrl { type: draw-sprite, position: { x: 0, y: 0 }, asset: { url: @warmUrl }, opacity: 0, width: 0.5, height: 0.5 })) }
146
172
  ] } ]
147
173
  })
@@ -193,7 +219,7 @@ orbital CrewBoard2DOrbital {
193
219
  { type: draw-shape-layer, items: (array/map @entity.units (fn u { type: draw-shape, shape: "rect", position: (object/get @u position), anchor: "ground", offsetX: -0.25, offsetY: -0.6, width: 0.5, height: 0.12, fill: "rgba(0,0,0,0.6)" })) }
194
220
  { type: draw-shape-layer, items: (array/map @entity.units (fn u { type: draw-shape, shape: "rect", position: (object/get @u position), anchor: "ground", offsetX: -0.25, offsetY: -0.6, width: (* 0.5 (/ (object/get @u health) (object/get @u maxHealth))), height: 0.12, fill: "#22c55e" })) }
195
221
  { type: draw-text-layer, items: (array/map @entity.units (fn u { type: draw-text, text: (object/get @u name), position: (object/get @u position), offsetY: -0.85, color: "#ffffff" })) }
196
- { type: draw-text-layer, items: (array/map @entity.fx (fn f { type: draw-text, text: (object/get @f message), position: { x: (object/get @f x), y: (object/get @f y) }, color: "#ffe066" })) }
222
+ { type: draw-fx-layer, items: @entity.fx, tickMs: 500, presets: @config.fxPresets, sprites: (object/get @config.assetManifest effects) }
197
223
  { type: draw-sprite-layer, items: (array/map (array/filter (array/flatten (array/map @entity.units (fn u (array/flatten (array/map [ ["idle", 4], ["walk", 2], ["attack", 1], ["hit", 1], ["death", 1] ] (fn st (array/map (array/range 0 (array/nth @st 1)) (fn i (if (and (object/get (object/get @u modelUrl) url) (str/includes (object/get (object/get @u modelUrl) url) ".svg")) (str/concat (array/nth (str/split (object/get (object/get @u modelUrl) url) ".svg") 0) (str/concat "." (str/concat (array/nth @st 0) (str/concat "-" (str/concat @i ".svg"))))) ""))))))))) (fn w (!= @w ""))) (fn warmUrl { type: draw-sprite, position: { x: 0, y: 0 }, asset: { url: @warmUrl }, opacity: 0, width: 0.5, height: 0.5 })) }
198
224
  ] } ]
199
225
  })
@@ -250,6 +276,10 @@ orbital CrewBoard2DOrbital {
250
276
  @label "Features"
251
277
  @description "Decorative environment features (e.g. consoles) drawn on the board."
252
278
  @tier "presentation"
279
+ fxPresets : [FxPreset] = []
280
+ @label "Fx Presets"
281
+ @description "This board's effect vocabulary — one look/recipe row per fx type; its composed mechanics currently emit none, so the channel is forward-compat only."
282
+ @tier "presentation"
253
283
  assetManifest : AssetManifest = { terrains: {}, units: {}, features: {}, effects: {} }
254
284
  @label "Asset Manifest"
255
285
  @description "Terrain/unit/feature/effect sprite manifest."
@@ -60,6 +60,32 @@ orbital DungeonBoard2DOrbital {
60
60
  y : number
61
61
  message : string
62
62
  ttl : number!
63
+ maxTtl : number
64
+ bornAt : number
65
+ space : string
66
+ effect : string
67
+ color : string
68
+ size : number
69
+ vx : number
70
+ vy : number
71
+ vz : number
72
+ particleCount : number
73
+ }
74
+ type FxPreset = {
75
+ type : string!
76
+ color : string
77
+ color2 : string
78
+ size : number
79
+ shape : string
80
+ count : number
81
+ glow : number
82
+ gravity : number
83
+ vx : number
84
+ vy : number
85
+ vz : number
86
+ space : string
87
+ effect : string
88
+ particleCount : number
63
89
  }
64
90
  type DirectionAssets = {
65
91
  up : Asset
@@ -203,7 +229,7 @@ orbital DungeonBoard2DOrbital {
203
229
  { type: draw-shape-layer, items: (array/map (array/concat @entity.units @entity.enemies) (fn u { type: draw-shape, shape: "rect", position: (object/get @u position), anchor: "ground", offsetX: -0.25, offsetY: -0.6, width: 0.5, height: 0.12, fill: "rgba(0,0,0,0.6)" })) }
204
230
  { type: draw-shape-layer, items: (array/map (array/concat @entity.units @entity.enemies) (fn u { type: draw-shape, shape: "rect", position: (object/get @u position), anchor: "ground", offsetX: -0.25, offsetY: -0.6, width: (* 0.5 (/ (object/get @u health) (object/get @u maxHealth))), height: 0.12, fill: "#22c55e" })) }
205
231
  { type: draw-text-layer, items: (array/map (array/concat @entity.units @entity.enemies) (fn u { type: draw-text, text: (object/get @u name), position: (object/get @u position), offsetY: -0.85, color: "#ffffff" })) }
206
- { type: draw-text-layer, items: (array/map @entity.fx (fn f { type: draw-text, text: (object/get @f message), position: { x: (object/get @f x), y: (object/get @f z) }, color: "#ffe066" })) }
232
+ { type: draw-fx-layer, items: @entity.fx, tickMs: 500, presets: @config.fxPresets, sprites: (object/get @config.assetManifest effects) }
207
233
  ] } ]
208
234
  })
209
235
 
@@ -269,7 +295,7 @@ orbital DungeonBoard2DOrbital {
269
295
  { type: draw-shape-layer, items: (array/map (array/concat @entity.units @entity.enemies) (fn u { type: draw-shape, shape: "rect", position: (object/get @u position), anchor: "ground", offsetX: -0.25, offsetY: -0.6, width: 0.5, height: 0.12, fill: "rgba(0,0,0,0.6)" })) }
270
296
  { type: draw-shape-layer, items: (array/map (array/concat @entity.units @entity.enemies) (fn u { type: draw-shape, shape: "rect", position: (object/get @u position), anchor: "ground", offsetX: -0.25, offsetY: -0.6, width: (* 0.5 (/ (object/get @u health) (object/get @u maxHealth))), height: 0.12, fill: "#22c55e" })) }
271
297
  { type: draw-text-layer, items: (array/map (array/concat @entity.units @entity.enemies) (fn u { type: draw-text, text: (object/get @u name), position: (object/get @u position), offsetY: -0.85, color: "#ffffff" })) }
272
- { type: draw-text-layer, items: (array/map @entity.fx (fn f { type: draw-text, text: (object/get @f message), position: { x: (object/get @f x), y: (object/get @f z) }, color: "#ffe066" })) }
298
+ { type: draw-fx-layer, items: @entity.fx, tickMs: 500, presets: @config.fxPresets, sprites: (object/get @config.assetManifest effects) }
273
299
  ] } ]
274
300
  })
275
301
 
@@ -345,6 +371,10 @@ orbital DungeonBoard2DOrbital {
345
371
  @label "Font Family"
346
372
  @description "game-shell font family (e.g. pixel)."
347
373
  @tier "presentation"
374
+ fxPresets : [FxPreset] = [ { type: "explosion", color: "#fb923c", color2: "#7c2d12", shape: "ring", size: 0.85, count: 8, glow: 0.2, gravity: 0.4 }, { type: "pickup", color: "#ffe066", color2: "#fff4cc", shape: "spark", size: 0.4, count: 5, glow: 0.1, vy: -0.5 } ]
375
+ @label "Fx Presets"
376
+ @description "This board's effect vocabulary — one look/recipe row per fx type its mechanics emit; unknown types fall back to a neutral spark."
377
+ @tier "presentation"
348
378
  assetManifest : AssetManifest = { terrains: {}, units: {}, features: {}, effects: {} }
349
379
  @label "Asset Manifest"
350
380
  @description "Terrain/unit/feature/effect sprite manifest."
@@ -59,6 +59,32 @@ orbital MarketBoard3DOrbital {
59
59
  y : number
60
60
  message : string
61
61
  ttl : number!
62
+ maxTtl : number
63
+ bornAt : number
64
+ space : string
65
+ effect : string
66
+ color : string
67
+ size : number
68
+ vx : number
69
+ vy : number
70
+ vz : number
71
+ particleCount : number
72
+ }
73
+ type FxPreset = {
74
+ type : string!
75
+ color : string
76
+ color2 : string
77
+ size : number
78
+ shape : string
79
+ count : number
80
+ glow : number
81
+ gravity : number
82
+ vx : number
83
+ vy : number
84
+ vz : number
85
+ space : string
86
+ effect : string
87
+ particleCount : number
62
88
  }
63
89
  type ValidMove = { x : number! z : number! }
64
90
  type Feature = {
@@ -182,7 +208,7 @@ orbital MarketBoard3DOrbital {
182
208
  { type: draw-shape-layer, items: (array/concat (array/map @entity.units (fn u { type: draw-shape, shape: "rect", position: { x: (object/get (object/get @u position) x), y: (object/get (object/get @u position) y), z: (object/get @u z) }, offsetY: -0.6, width: 0.8, height: 0.12, fill: "rgba(0,0,0,0.6)" })) (array/map @entity.customers (fn c { type: draw-shape, shape: "rect", position: (object/get @c position), offsetY: -0.6, width: 0.8, height: 0.12, fill: "rgba(0,0,0,0.6)" }))) }
183
209
  { type: draw-shape-layer, items: (array/concat (array/map @entity.units (fn u { type: draw-shape, shape: "rect", position: { x: (object/get (object/get @u position) x), y: (object/get (object/get @u position) y), z: (object/get @u z) }, offsetY: -0.6, width: (* 0.8 (/ (object/get @u health) (object/get @u maxHealth))), height: 0.12, fill: "#22c55e" })) (array/map @entity.customers (fn c { type: draw-shape, shape: "rect", position: (object/get @c position), offsetY: -0.6, width: 0.8, height: 0.12, fill: "#22c55e" }))) }
184
210
  { type: draw-text-layer, items: (array/concat (array/map @entity.units (fn u { type: draw-text, text: (object/get @u name), position: { x: (object/get (object/get @u position) x), y: (object/get (object/get @u position) y), z: (object/get @u z) }, offsetY: -0.85, color: "#ffffff" })) (array/map @entity.customers (fn c { type: draw-text, text: (object/get @c name), position: (object/get @c position), offsetY: -0.85, color: "#ffffff" }))) }
185
- { type: draw-text-layer, items: (array/map @entity.fx (fn f { type: draw-text, text: (object/get @f message), position: { x: (object/get @f x), y: (object/get @f y), z: (object/get @f z) }, color: "#ffe066" })) }
211
+ { type: draw-fx-layer, items: @entity.fx, tickMs: 500, presets: @config.fxPresets }
186
212
  ] } ]
187
213
  })
188
214
 
@@ -225,7 +251,7 @@ orbital MarketBoard3DOrbital {
225
251
  { type: draw-shape-layer, items: (array/concat (array/map @entity.units (fn u { type: draw-shape, shape: "rect", position: { x: (object/get (object/get @u position) x), y: (object/get (object/get @u position) y), z: (object/get @u z) }, offsetY: -0.6, width: 0.8, height: 0.12, fill: "rgba(0,0,0,0.6)" })) (array/map @entity.customers (fn c { type: draw-shape, shape: "rect", position: (object/get @c position), offsetY: -0.6, width: 0.8, height: 0.12, fill: "rgba(0,0,0,0.6)" }))) }
226
252
  { type: draw-shape-layer, items: (array/concat (array/map @entity.units (fn u { type: draw-shape, shape: "rect", position: { x: (object/get (object/get @u position) x), y: (object/get (object/get @u position) y), z: (object/get @u z) }, offsetY: -0.6, width: (* 0.8 (/ (object/get @u health) (object/get @u maxHealth))), height: 0.12, fill: "#22c55e" })) (array/map @entity.customers (fn c { type: draw-shape, shape: "rect", position: (object/get @c position), offsetY: -0.6, width: 0.8, height: 0.12, fill: "#22c55e" }))) }
227
253
  { type: draw-text-layer, items: (array/concat (array/map @entity.units (fn u { type: draw-text, text: (object/get @u name), position: { x: (object/get (object/get @u position) x), y: (object/get (object/get @u position) y), z: (object/get @u z) }, offsetY: -0.85, color: "#ffffff" })) (array/map @entity.customers (fn c { type: draw-text, text: (object/get @c name), position: (object/get @c position), offsetY: -0.85, color: "#ffffff" }))) }
228
- { type: draw-text-layer, items: (array/map @entity.fx (fn f { type: draw-text, text: (object/get @f message), position: { x: (object/get @f x), y: (object/get @f y), z: (object/get @f z) }, color: "#ffe066" })) }
254
+ { type: draw-fx-layer, items: @entity.fx, tickMs: 500, presets: @config.fxPresets }
229
255
  ] } ]
230
256
  })
231
257
  }
@@ -317,6 +343,10 @@ orbital MarketBoard3DOrbital {
317
343
  @label "Features"
318
344
  @description "Static decorative props (shelves/freezers/checkout/etc); never mutated by any mechanic."
319
345
  @tier "presentation"
346
+ fxPresets : [FxPreset] = [ { type: "score", color: "#fbbf24", color2: "#fde68a", size: 0.45, shape: "spark", count: 6, glow: 0.1, vy: -0.3 }, { type: "damage", color: "#ef4444", color2: "#450a0a", size: 0.5, shape: "puff", count: 4, gravity: 0.3 } ]
347
+ @label "Fx Presets"
348
+ @description "This board's effect vocabulary — one look/recipe row per fx type its mechanics emit; unknown types fall back to a neutral spark."
349
+ @tier "presentation"
320
350
  assetManifest : AssetManifest = { terrains: {}, units: {}, features: {}, effects: {} }
321
351
  @label "Asset Manifest"
322
352
  @description "Per-role model manifest resolving tile models by terrain key."
@@ -50,6 +50,32 @@ orbital ObjectiveBoard3DOrbital {
50
50
  y : number
51
51
  message : string
52
52
  ttl : number!
53
+ maxTtl : number
54
+ bornAt : number
55
+ space : string
56
+ effect : string
57
+ color : string
58
+ size : number
59
+ vx : number
60
+ vy : number
61
+ vz : number
62
+ particleCount : number
63
+ }
64
+ type FxPreset = {
65
+ type : string!
66
+ color : string
67
+ color2 : string
68
+ size : number
69
+ shape : string
70
+ count : number
71
+ glow : number
72
+ gravity : number
73
+ vx : number
74
+ vy : number
75
+ vz : number
76
+ space : string
77
+ effect : string
78
+ particleCount : number
53
79
  }
54
80
  type ValidMove = { x : number! z : number! }
55
81
  type Feature = {
@@ -174,7 +200,7 @@ orbital ObjectiveBoard3DOrbital {
174
200
  { type: draw-shape-layer, items: (array/map @entity.units (fn u { type: draw-shape, shape: "rect", position: (object/get @u position), offsetY: -0.6, width: 0.8, height: 0.12, fill: "rgba(0,0,0,0.6)" })) }
175
201
  { type: draw-shape-layer, items: (array/map @entity.units (fn u { type: draw-shape, shape: "rect", position: (object/get @u position), offsetY: -0.6, width: (* 0.8 (/ (object/get @u health) (object/get @u maxHealth))), height: 0.12, fill: "#22c55e" })) }
176
202
  { type: draw-text-layer, items: (array/map @entity.units (fn u { type: draw-text, text: (object/get @u name), position: (object/get @u position), offsetY: -0.85, color: "#ffffff" })) }
177
- { type: draw-text-layer, items: (array/map @entity.fx (fn f { type: draw-text, text: (object/get @f message), position: { x: (object/get @f x), y: (object/get @f y) }, color: "#ffe066" })) }
203
+ { type: draw-fx-layer, items: @entity.fx, tickMs: 500, presets: @config.fxPresets }
178
204
  ] } ]
179
205
  })
180
206
 
@@ -217,7 +243,7 @@ orbital ObjectiveBoard3DOrbital {
217
243
  { type: draw-shape-layer, items: (array/map @entity.units (fn u { type: draw-shape, shape: "rect", position: (object/get @u position), offsetY: -0.6, width: 0.8, height: 0.12, fill: "rgba(0,0,0,0.6)" })) }
218
244
  { type: draw-shape-layer, items: (array/map @entity.units (fn u { type: draw-shape, shape: "rect", position: (object/get @u position), offsetY: -0.6, width: (* 0.8 (/ (object/get @u health) (object/get @u maxHealth))), height: 0.12, fill: "#22c55e" })) }
219
245
  { type: draw-text-layer, items: (array/map @entity.units (fn u { type: draw-text, text: (object/get @u name), position: (object/get @u position), offsetY: -0.85, color: "#ffffff" })) }
220
- { type: draw-text-layer, items: (array/map @entity.fx (fn f { type: draw-text, text: (object/get @f message), position: { x: (object/get @f x), y: (object/get @f y) }, color: "#ffe066" })) }
246
+ { type: draw-fx-layer, items: @entity.fx, tickMs: 500, presets: @config.fxPresets }
221
247
  ] } ]
222
248
  })
223
249
 
@@ -305,6 +331,10 @@ orbital ObjectiveBoard3DOrbital {
305
331
  @label "Bg Color"
306
332
  @description "Canvas background color."
307
333
  @tier "presentation"
334
+ fxPresets : [FxPreset] = [ { type: "pickup", color: "#ffe066", color2: "#ffffff", size: 0.5, shape: "spark", count: 6, glow: 0.14, vy: -0.3 } ]
335
+ @label "Fx Presets"
336
+ @description "This board's effect vocabulary — one look/recipe row per fx type its mechanics emit; unknown types fall back to a neutral spark."
337
+ @tier "presentation"
308
338
  assetManifest : AssetManifest = { terrains: {}, units: {}, features: {}, effects: {} }
309
339
  @label "Asset Manifest"
310
340
  @description "Per-role model manifest resolving tile/unit/feature models by terrain/category key."