@almadar/std 16.178.0 → 16.179.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.
- package/behaviors/lolo/ui/core/molecules/ui-fx-overlay.lolo +63 -0
- package/behaviors/lolo/ui/core/molecules/ui-page-header.lolo +1 -1
- package/behaviors/lolo/ui/core/organisms/ui-form-section.lolo +2 -2
- package/behaviors/lolo/ui/core/organisms/ui-form.lolo +2 -2
- package/behaviors/lolo/ui/core/templates/ui-dashboard-layout.lolo +2 -2
- package/behaviors/lolo/ui/game/atoms/std-fx-particles.lolo +23 -4
- package/behaviors/lolo/ui/game/atoms/std-platformer-body.lolo +251 -0
- package/behaviors/lolo/ui/game/atoms/ui-draw-fx-layer.lolo +109 -0
- package/behaviors/lolo/ui/game/organisms/std-arcade-board-3d.lolo +32 -2
- package/behaviors/lolo/ui/game/organisms/std-crew-board-2d.lolo +32 -2
- package/behaviors/lolo/ui/game/organisms/std-dungeon-board-2d.lolo +32 -2
- package/behaviors/lolo/ui/game/organisms/std-market-board-3d.lolo +32 -2
- package/behaviors/lolo/ui/game/organisms/std-objective-board-3d.lolo +32 -2
- package/behaviors/lolo/ui/game/organisms/std-platformer-board-2d.lolo +391 -0
- package/behaviors/lolo/ui/game/organisms/std-survival-board-3d.lolo +32 -2
- package/behaviors/lolo/ui/game/organisms/std-tactics-board-2d.lolo +34 -6
- package/behaviors/lolo/ui/game/organisms/std-tactics-board-3d.lolo +34 -4
- package/behaviors/lolo/ui/learning/atoms/std-learn-arrangement.lolo +8 -0
- package/behaviors/lolo/ui/learning/atoms/std-learn-classify.lolo +8 -0
- package/behaviors/lolo/ui/learning/atoms/std-learn-derivation.lolo +8 -0
- package/behaviors/lolo/ui/learning/atoms/std-learn-doser.lolo +9 -0
- package/behaviors/lolo/ui/learning/atoms/std-learn-estimate.lolo +8 -0
- package/behaviors/lolo/ui/learning/atoms/std-learn-fx-cues.lolo +147 -0
- package/behaviors/lolo/ui/learning/atoms/std-learn-goal-seek.lolo +8 -0
- package/behaviors/lolo/ui/learning/atoms/std-learn-hotspot.lolo +8 -0
- package/behaviors/lolo/ui/learning/atoms/std-learn-predict.lolo +8 -0
- package/behaviors/lolo/ui/learning/atoms/std-learn-scatter-fit.lolo +9 -0
- package/behaviors/lolo/ui/learning/atoms/std-learn-speed-drill.lolo +8 -0
- package/behaviors/lolo/ui/learning/atoms/std-learn-tour-3d.lolo +9 -0
- package/behaviors/registry/ui/core/molecules/ui-fx-overlay.orb +281 -0
- package/behaviors/registry/ui/core/molecules/ui-page-header.orb +1 -1
- package/behaviors/registry/ui/core/organisms/ui-form-section.orb +6 -0
- package/behaviors/registry/ui/core/organisms/ui-form.orb +6 -0
- package/behaviors/registry/ui/core/templates/ui-dashboard-layout.orb +2 -2
- package/behaviors/registry/ui/game/atoms/std-fx-particles.orb +265 -4
- package/behaviors/registry/ui/game/atoms/std-platformer-body.orb +2136 -0
- package/behaviors/registry/ui/game/atoms/ui-draw-fx-layer.orb +523 -0
- package/behaviors/registry/ui/game/organisms/std-arcade-board-3d.orb +159 -70
- package/behaviors/registry/ui/game/organisms/std-crew-board-2d.orb +148 -58
- package/behaviors/registry/ui/game/organisms/std-dungeon-board-2d.orb +169 -58
- package/behaviors/registry/ui/game/organisms/std-market-board-3d.orb +160 -70
- package/behaviors/registry/ui/game/organisms/std-objective-board-3d.orb +151 -60
- package/behaviors/registry/ui/game/organisms/std-platformer-board-2d.orb +2981 -0
- package/behaviors/registry/ui/game/organisms/std-survival-board-3d.orb +150 -60
- package/behaviors/registry/ui/game/organisms/std-tactics-board-2d.orb +163 -316
- package/behaviors/registry/ui/game/organisms/std-tactics-board-3d.orb +156 -184
- package/behaviors/registry/ui/learning/atoms/std-learn-arrangement.orb +62 -0
- package/behaviors/registry/ui/learning/atoms/std-learn-classify.orb +73 -0
- package/behaviors/registry/ui/learning/atoms/std-learn-derivation.orb +66 -0
- package/behaviors/registry/ui/learning/atoms/std-learn-doser.orb +71 -0
- package/behaviors/registry/ui/learning/atoms/std-learn-estimate.orb +72 -0
- package/behaviors/registry/ui/learning/atoms/std-learn-fx-cues.orb +1546 -0
- package/behaviors/registry/ui/learning/atoms/std-learn-goal-seek.orb +58 -0
- package/behaviors/registry/ui/learning/atoms/std-learn-hotspot.orb +72 -0
- package/behaviors/registry/ui/learning/atoms/std-learn-predict.orb +72 -0
- package/behaviors/registry/ui/learning/atoms/std-learn-scatter-fit.orb +71 -0
- package/behaviors/registry/ui/learning/atoms/std-learn-speed-drill.orb +72 -0
- package/behaviors/registry/ui/learning/atoms/std-learn-tour-3d.orb +176 -0
- package/dist/behaviors/exports-reader.js +8369 -5005
- package/dist/behaviors/functions/index.d.ts +604 -14
- package/dist/behaviors/functions/index.js +8354 -5006
- package/dist/behaviors/index.d.ts +1 -1
- package/dist/behaviors/index.js +8370 -5006
- package/dist/behaviors/query.js +8369 -5005
- package/dist/behaviors-embeddings.hash.json +3 -3
- package/dist/behaviors-embeddings.json +351 -331
- package/dist/behaviors-registry.json +1879 -344
- package/dist/index.d.ts +1 -1
- package/dist/index.js +8370 -5006
- package/dist/knob-embeddings.hash.json +3 -3
- package/dist/knob-embeddings.json +1 -1
- package/dist/registry/factory-signatures.json +1 -1
- package/package.json +2 -2
|
@@ -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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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."
|
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
app std-platformer-board-2d "1.0.0"
|
|
2
|
+
"2D run/jump platformer board FRAME: composes platformer-body (run/jump physics, one-way AABB collision, hazard/goal/fall signals) + fx-particles + objective-flow (win/lose gate) onto one shared GameState with a side-view canvas render. The intent trait owns only game RULES — input forwarding (LEFT/RIGHT/STOP/JUMP → STEER/JUMP intents), goal scoring, hazard/pit lives with respawn, PLAY_AGAIN reset — physics, particles, and the win gate belong to the atoms. Games consume this organism and supply level geometry (platforms, in both BodyAuthority.platforms for collision and the render-side platforms knob), theme/assets, and physics feel via config/traitOverrides."
|
|
3
|
+
orbital PlatformerBoard2DOrbital {
|
|
4
|
+
uses Body from "std/behaviors/std-platformer-body"
|
|
5
|
+
uses Particles from "std/behaviors/std-fx-particles"
|
|
6
|
+
uses Gate from "std/behaviors/std-objective-flow"
|
|
7
|
+
|
|
8
|
+
type Asset = {
|
|
9
|
+
url : asset
|
|
10
|
+
atlas : asset
|
|
11
|
+
sprite : string
|
|
12
|
+
role : string
|
|
13
|
+
category : string
|
|
14
|
+
animations : [string]
|
|
15
|
+
style : string
|
|
16
|
+
variant : string
|
|
17
|
+
dimension : string
|
|
18
|
+
aspect : string
|
|
19
|
+
name : string
|
|
20
|
+
thumbnailUrl : string
|
|
21
|
+
}
|
|
22
|
+
type PlatformerBody = {
|
|
23
|
+
x : number!
|
|
24
|
+
y : number!
|
|
25
|
+
width : number!
|
|
26
|
+
height : number!
|
|
27
|
+
vx : number
|
|
28
|
+
vy : number
|
|
29
|
+
grounded : boolean
|
|
30
|
+
facingRight : boolean
|
|
31
|
+
}
|
|
32
|
+
type PlatformerPlatform = {
|
|
33
|
+
id : string
|
|
34
|
+
x : number!
|
|
35
|
+
y : number!
|
|
36
|
+
width : number!
|
|
37
|
+
height : number!
|
|
38
|
+
type : "ground" | "platform" | "hazard" | "goal"
|
|
39
|
+
}
|
|
40
|
+
type Fx = {
|
|
41
|
+
id : string!
|
|
42
|
+
type : string!
|
|
43
|
+
x : number!
|
|
44
|
+
z : number
|
|
45
|
+
y : number
|
|
46
|
+
message : string
|
|
47
|
+
ttl : number!
|
|
48
|
+
maxTtl : number
|
|
49
|
+
bornAt : number
|
|
50
|
+
space : string
|
|
51
|
+
effect : string
|
|
52
|
+
color : string
|
|
53
|
+
size : number
|
|
54
|
+
vx : number
|
|
55
|
+
vy : number
|
|
56
|
+
vz : number
|
|
57
|
+
particleCount : number
|
|
58
|
+
}
|
|
59
|
+
type FxPreset = {
|
|
60
|
+
type : string!
|
|
61
|
+
color : string
|
|
62
|
+
color2 : string
|
|
63
|
+
size : number
|
|
64
|
+
shape : string
|
|
65
|
+
count : number
|
|
66
|
+
glow : number
|
|
67
|
+
gravity : number
|
|
68
|
+
vx : number
|
|
69
|
+
vy : number
|
|
70
|
+
vz : number
|
|
71
|
+
space : string
|
|
72
|
+
effect : string
|
|
73
|
+
particleCount : number
|
|
74
|
+
}
|
|
75
|
+
type DirectionAssets = {
|
|
76
|
+
up : Asset
|
|
77
|
+
down : Asset
|
|
78
|
+
left : Asset
|
|
79
|
+
right : Asset
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
entity GameState [runtime, shared] {
|
|
83
|
+
id : string!
|
|
84
|
+
body : PlatformerBody = { x: 80, y: 320, width: 32, height: 48, vx: 0, vy: 0, grounded: false, facingRight: true }
|
|
85
|
+
fell : boolean = false
|
|
86
|
+
hazardId : string = ""
|
|
87
|
+
goalId : string = ""
|
|
88
|
+
skating : boolean = false
|
|
89
|
+
fx : [Fx] = []
|
|
90
|
+
result : string = "none"
|
|
91
|
+
score : number = 0
|
|
92
|
+
lives : number = 3
|
|
93
|
+
objectivesLeft : number = 1
|
|
94
|
+
frame : number = 0
|
|
95
|
+
celebrated : boolean = false
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
trait BodyAuthority = Body.traits.PlatformerBody -> GameState {
|
|
99
|
+
events {
|
|
100
|
+
STEER: PLAT_STEER
|
|
101
|
+
JUMP: PLAT_JUMP
|
|
102
|
+
PLACE: PLAT_PLACE
|
|
103
|
+
BODY_MOVED: PLAT_MOVED
|
|
104
|
+
BODY_JUMPED: PLAT_JUMPED
|
|
105
|
+
BODY_LANDED: PLAT_LANDED
|
|
106
|
+
BODY_HAZARD: PLAT_HAZARD
|
|
107
|
+
BODY_GOAL: PLAT_GOAL
|
|
108
|
+
BODY_FELL: PLAT_FELL
|
|
109
|
+
}
|
|
110
|
+
config {
|
|
111
|
+
running: true
|
|
112
|
+
spawn: { x: 80, y: 320, width: 32, height: 48, vx: 0, vy: 0, grounded: false, facingRight: true }
|
|
113
|
+
platforms: [
|
|
114
|
+
{ id: "g0", x: 0, y: 368, width: 800, height: 32, type: "ground" }
|
|
115
|
+
{ id: "p1", x: 150, y: 280, width: 160, height: 16, type: "platform" }
|
|
116
|
+
{ id: "p2", x: 420, y: 220, width: 160, height: 16, type: "platform" }
|
|
117
|
+
{ id: "h1", x: 580, y: 300, width: 80, height: 16, type: "hazard" }
|
|
118
|
+
{ id: "goal", x: 700, y: 340, width: 64, height: 28, type: "goal" }
|
|
119
|
+
]
|
|
120
|
+
gravity: 550
|
|
121
|
+
jumpStrength: 365
|
|
122
|
+
moveSpeed: 120
|
|
123
|
+
maxFallSpeed: 600
|
|
124
|
+
xMin: 0
|
|
125
|
+
xMax: 768
|
|
126
|
+
killY: 460
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
trait FxDecay = Particles.traits.FxParticles -> GameState {
|
|
131
|
+
config { running: true }
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
trait RoundGate = Gate.traits.ObjectiveFlow -> GameState {
|
|
135
|
+
config { running: true }
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
trait PlatformerIntent -> GameState [interaction, instance] {
|
|
139
|
+
initial: playing
|
|
140
|
+
|
|
141
|
+
state playing {
|
|
142
|
+
INIT -> playing
|
|
143
|
+
(set @entity.score 0)
|
|
144
|
+
(set @entity.lives @config.startLives)
|
|
145
|
+
(set @entity.objectivesLeft 1)
|
|
146
|
+
(set @entity.celebrated false)
|
|
147
|
+
(emit RESTART { id: "board" })
|
|
148
|
+
(render-ui main {
|
|
149
|
+
type: game-shell
|
|
150
|
+
backgroundAsset: @config.backgroundAsset
|
|
151
|
+
hudBackgroundAsset: @config.hudBackgroundAsset
|
|
152
|
+
hud: { type: stack, direction: horizontal, gap: md, justify: between, children: [ { type: game-hud, stats: [ { label: "Score", value: @entity.score }, { label: "Lives", value: @entity.lives } ] }, { type: control-grid, kind: "dpad", directionEvents: { left: "LEFT", right: "RIGHT", up: "JUMP" }, directionReleaseEvents: { left: "STOP", right: "STOP" }, directionAssets: @config.directionAssets } ] }
|
|
153
|
+
overlay: (if (== @entity.result "won") { type: game-menu, title: @config.clearTitle, subtitle: (str/concat "Score: " @entity.score), options: [ { id: "again", label: "Play Again", event: "PLAY_AGAIN", variant: "primary" } ] } (if (== @entity.result "lost") { type: game-menu, title: @config.lostTitle, subtitle: (str/concat "Score: " @entity.score), options: [ { id: "again", label: "Play Again", event: "PLAY_AGAIN", variant: "primary" } ] } null))
|
|
154
|
+
children: [ { type: canvas, camera: { mode: "follow", zoom: 1, pos: { x: (/ @config.worldWidth 2), y: (/ @config.worldHeight 2) }, target: { x: @entity.body.x, y: @entity.body.y } }, projection: "side", worldWidth: @config.worldWidth, worldHeight: @config.worldHeight, backgroundColor: @config.bgColor, backgroundImage: @config.backgroundImage, keyMap: { ArrowLeft: "LEFT", KeyA: "LEFT", ArrowRight: "RIGHT", KeyD: "RIGHT", ArrowUp: "JUMP", KeyW: "JUMP", Space: "JUMP" }, keyUpMap: { ArrowLeft: "STOP", KeyA: "STOP", ArrowRight: "STOP", KeyD: "STOP" }, drawables: [
|
|
155
|
+
{ type: draw-sprite-layer, items: (array/map @config.platforms (fn p { type: draw-sprite, position: { x: (object/get @p x), y: (object/get @p y) }, width: (object/get @p width), height: (object/get @p height), asset: (object/get @config.tileSprites (object/get @p type)) })) }
|
|
156
|
+
{ type: draw-sprite-layer, items: [ (object/merge { type: "draw-sprite", position: { x: @entity.body.x, y: @entity.body.y }, width: @entity.body.width, height: @entity.body.height, frame: @entity.frame, flipX: (not @entity.body.facingRight) } { asset: (object/merge @config.playerSprite { sprite: (if @entity.body.grounded (if (!= @entity.body.vx 0) (if (== (% @entity.frame 2) 0) "adventurer_walk1.png" "adventurer_walk2.png") "adventurer_idle.png") "adventurer_jump.png") }) }) ] }
|
|
157
|
+
{ type: draw-fx-layer, items: @entity.fx, tickMs: 500, presets: @config.fxPresets }
|
|
158
|
+
] } ]
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
LEFT -> playing when (== @entity.result "none")
|
|
162
|
+
(emit PLAT_STEER { dir: -1 })
|
|
163
|
+
|
|
164
|
+
RIGHT -> playing when (== @entity.result "none")
|
|
165
|
+
(emit PLAT_STEER { dir: 1 })
|
|
166
|
+
|
|
167
|
+
STOP -> playing when (== @entity.result "none")
|
|
168
|
+
(emit PLAT_STEER { dir: 0 })
|
|
169
|
+
|
|
170
|
+
JUMP -> playing when (== @entity.result "none")
|
|
171
|
+
(emit PLAT_JUMP {})
|
|
172
|
+
|
|
173
|
+
PLAT_GOAL -> playing when (== @entity.result "none")
|
|
174
|
+
(set @entity.score (+ @entity.score @config.goalScore))
|
|
175
|
+
(set @entity.objectivesLeft 0)
|
|
176
|
+
(emit BURST { particles: (array/map (array/filter @config.platforms (fn p (== (object/get @p "id" "") @payload.id))) (fn p { id: (str/concat "fx-goal-" @payload.id), type: "score", x: @payload.x, z: @payload.y, message: (str/concat "+" @config.goalScore), ttl: 3 })) })
|
|
177
|
+
(emit PROGRESS { objectivesLeft: 0, movesLeft: @entity.lives })
|
|
178
|
+
|
|
179
|
+
PLAT_HAZARD -> playing when (== @entity.result "none")
|
|
180
|
+
(if (<= (- @entity.lives 1) 0)
|
|
181
|
+
(do
|
|
182
|
+
(set @entity.lives 0)
|
|
183
|
+
(emit PROGRESS { objectivesLeft: 1, movesLeft: 0 }))
|
|
184
|
+
(do
|
|
185
|
+
(set @entity.lives (- @entity.lives 1))
|
|
186
|
+
(emit BURST { particles: (array/map (array/filter @config.platforms (fn p (== (object/get @p "id" "") @payload.id))) (fn p { id: (str/concat "fx-hazard-" @payload.id), type: "damage", x: @payload.x, z: @payload.y, message: "-1", ttl: 3 })) })
|
|
187
|
+
(emit PLAT_PLACE { x: @config.respawnX, y: @config.respawnY })))
|
|
188
|
+
|
|
189
|
+
PLAT_FELL -> playing when (== @entity.result "none")
|
|
190
|
+
(if (<= (- @entity.lives 1) 0)
|
|
191
|
+
(do
|
|
192
|
+
(set @entity.lives 0)
|
|
193
|
+
(emit PROGRESS { objectivesLeft: 1, movesLeft: 0 }))
|
|
194
|
+
(do
|
|
195
|
+
(set @entity.lives (- @entity.lives 1))
|
|
196
|
+
(emit BURST { particles: (array/map [ "fx-fell" ] (fn fid { id: @fid, type: "damage", x: @payload.x, z: @config.worldHeight, message: "-1", ttl: 3 })) })
|
|
197
|
+
(emit PLAT_PLACE { x: @config.respawnX, y: @config.respawnY })))
|
|
198
|
+
|
|
199
|
+
GAME_END -> playing when (== @entity.celebrated false)
|
|
200
|
+
(set @entity.celebrated true)
|
|
201
|
+
|
|
202
|
+
PLAY_AGAIN -> playing
|
|
203
|
+
(set @entity.score 0)
|
|
204
|
+
(set @entity.lives @config.startLives)
|
|
205
|
+
(set @entity.objectivesLeft 1)
|
|
206
|
+
(set @entity.celebrated false)
|
|
207
|
+
(emit RESTART { id: "board" })
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
ticks {
|
|
211
|
+
renderTick every 100ms
|
|
212
|
+
(set @entity.frame (% (+ @entity.frame 1) 8))
|
|
213
|
+
(render-ui main {
|
|
214
|
+
type: game-shell
|
|
215
|
+
backgroundAsset: @config.backgroundAsset
|
|
216
|
+
hudBackgroundAsset: @config.hudBackgroundAsset
|
|
217
|
+
hud: { type: stack, direction: horizontal, gap: md, justify: between, children: [ { type: game-hud, stats: [ { label: "Score", value: @entity.score }, { label: "Lives", value: @entity.lives } ] }, { type: control-grid, kind: "dpad", directionEvents: { left: "LEFT", right: "RIGHT", up: "JUMP" }, directionReleaseEvents: { left: "STOP", right: "STOP" }, directionAssets: @config.directionAssets } ] }
|
|
218
|
+
overlay: (if (== @entity.result "won") { type: game-menu, title: @config.clearTitle, subtitle: (str/concat "Score: " @entity.score), options: [ { id: "again", label: "Play Again", event: "PLAY_AGAIN", variant: "primary" } ] } (if (== @entity.result "lost") { type: game-menu, title: @config.lostTitle, subtitle: (str/concat "Score: " @entity.score), options: [ { id: "again", label: "Play Again", event: "PLAY_AGAIN", variant: "primary" } ] } null))
|
|
219
|
+
children: [ { type: canvas, camera: { mode: "follow", zoom: 1, pos: { x: (/ @config.worldWidth 2), y: (/ @config.worldHeight 2) }, target: { x: @entity.body.x, y: @entity.body.y } }, projection: "side", worldWidth: @config.worldWidth, worldHeight: @config.worldHeight, backgroundColor: @config.bgColor, backgroundImage: @config.backgroundImage, keyMap: { ArrowLeft: "LEFT", KeyA: "LEFT", ArrowRight: "RIGHT", KeyD: "RIGHT", ArrowUp: "JUMP", KeyW: "JUMP", Space: "JUMP" }, keyUpMap: { ArrowLeft: "STOP", KeyA: "STOP", ArrowRight: "STOP", KeyD: "STOP" }, drawables: [
|
|
220
|
+
{ type: draw-sprite-layer, items: (array/map @config.platforms (fn p { type: draw-sprite, position: { x: (object/get @p x), y: (object/get @p y) }, width: (object/get @p width), height: (object/get @p height), asset: (object/get @config.tileSprites (object/get @p type)) })) }
|
|
221
|
+
{ type: draw-sprite-layer, items: [ (object/merge { type: "draw-sprite", position: { x: @entity.body.x, y: @entity.body.y }, width: @entity.body.width, height: @entity.body.height, frame: @entity.frame, flipX: (not @entity.body.facingRight) } { asset: (object/merge @config.playerSprite { sprite: (if @entity.body.grounded (if (!= @entity.body.vx 0) (if (== (% @entity.frame 2) 0) "adventurer_walk1.png" "adventurer_walk2.png") "adventurer_idle.png") "adventurer_jump.png") }) }) ] }
|
|
222
|
+
{ type: draw-fx-layer, items: @entity.fx, tickMs: 500, presets: @config.fxPresets }
|
|
223
|
+
] } ]
|
|
224
|
+
})
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
emits {
|
|
228
|
+
LEFT -> external {
|
|
229
|
+
id : string
|
|
230
|
+
}
|
|
231
|
+
@description "Move-left intent from ArrowLeft/KeyA keydown or d-pad (forwarded to the body authority as STEER dir −1)"
|
|
232
|
+
@tier "domain"
|
|
233
|
+
RIGHT -> external {
|
|
234
|
+
id : string
|
|
235
|
+
}
|
|
236
|
+
@description "Move-right intent from ArrowRight/KeyD keydown or d-pad (forwarded to the body authority as STEER dir +1)"
|
|
237
|
+
@tier "domain"
|
|
238
|
+
STOP -> external {
|
|
239
|
+
id : string
|
|
240
|
+
}
|
|
241
|
+
@description "Horizontal key release (keyUpMap or d-pad directionReleaseEvents); forwarded as STEER dir 0 so the body stops"
|
|
242
|
+
@tier "domain"
|
|
243
|
+
JUMP -> external {
|
|
244
|
+
id : string
|
|
245
|
+
}
|
|
246
|
+
@description "Jump intent from Space/ArrowUp/KeyW or d-pad up; forwarded to the body authority, which accepts it only while grounded"
|
|
247
|
+
@tier "domain"
|
|
248
|
+
PLAT_STEER -> external {
|
|
249
|
+
dir : number!
|
|
250
|
+
}
|
|
251
|
+
@description "Renamed STEER consumed by the platformer-body authority: −1/0/+1 × moveSpeed horizontal velocity"
|
|
252
|
+
@tier "domain"
|
|
253
|
+
PLAT_JUMP -> external {
|
|
254
|
+
id : string
|
|
255
|
+
}
|
|
256
|
+
@description "Renamed JUMP consumed by the platformer-body authority (grounded-gated vertical kick)"
|
|
257
|
+
@tier "domain"
|
|
258
|
+
PLAT_PLACE -> external {
|
|
259
|
+
x : number!
|
|
260
|
+
y : number!
|
|
261
|
+
}
|
|
262
|
+
@description "Renamed PLACE consumed by the platformer-body authority; hazard/pit respawn teleport"
|
|
263
|
+
@tier "domain"
|
|
264
|
+
PLAT_GOAL -> external {
|
|
265
|
+
id : string!
|
|
266
|
+
x : number!
|
|
267
|
+
y : number!
|
|
268
|
+
}
|
|
269
|
+
@description "Goal-tile contact signal from the platformer-body authority (renamed BODY_GOAL); scores and trips the win gate"
|
|
270
|
+
@tier "domain"
|
|
271
|
+
PLAT_HAZARD -> external {
|
|
272
|
+
id : string!
|
|
273
|
+
x : number!
|
|
274
|
+
y : number!
|
|
275
|
+
}
|
|
276
|
+
@description "Hazard-tile contact signal from the platformer-body authority (renamed BODY_HAZARD); costs a life and respawns"
|
|
277
|
+
@tier "domain"
|
|
278
|
+
PLAT_FELL -> external {
|
|
279
|
+
x : number!
|
|
280
|
+
y : number!
|
|
281
|
+
}
|
|
282
|
+
@description "Pit-fall signal from the platformer-body authority (renamed BODY_FELL); costs a life and respawns"
|
|
283
|
+
@tier "domain"
|
|
284
|
+
BURST -> external {
|
|
285
|
+
particles : [Fx]
|
|
286
|
+
}
|
|
287
|
+
@description "Floating-text particle batch spawned on score/damage; fx-particles fades it"
|
|
288
|
+
@tier "domain"
|
|
289
|
+
PROGRESS -> external {
|
|
290
|
+
objectivesLeft : number!
|
|
291
|
+
movesLeft : number!
|
|
292
|
+
}
|
|
293
|
+
@description "Sparse win/lose signal consumed by the objective-flow gate: objectivesLeft 0 = won, movesLeft 0 = lost"
|
|
294
|
+
@tier "domain"
|
|
295
|
+
GAME_END -> external {
|
|
296
|
+
result : string!
|
|
297
|
+
}
|
|
298
|
+
@description "Win/lose resolution from the objective-flow gate; guarded by celebrated so it lands once"
|
|
299
|
+
@tier "domain"
|
|
300
|
+
RESTART -> external {
|
|
301
|
+
id : string
|
|
302
|
+
}
|
|
303
|
+
@description "Broadcast reset consumed by the platformer-body and objective-flow authorities on INIT/PLAY_AGAIN"
|
|
304
|
+
@tier "domain"
|
|
305
|
+
PLAY_AGAIN -> external {
|
|
306
|
+
id : string
|
|
307
|
+
}
|
|
308
|
+
@description "End-overlay restart button; reseeds score/lives/objectives and broadcasts RESTART"
|
|
309
|
+
@tier "domain"
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
config {
|
|
313
|
+
platforms : [PlatformerPlatform] = [
|
|
314
|
+
{ id: "g0", x: 0, y: 368, width: 800, height: 32, type: "ground" }
|
|
315
|
+
{ id: "p1", x: 150, y: 280, width: 160, height: 16, type: "platform" }
|
|
316
|
+
{ id: "p2", x: 420, y: 220, width: 160, height: 16, type: "platform" }
|
|
317
|
+
{ id: "h1", x: 580, y: 300, width: 80, height: 16, type: "hazard" }
|
|
318
|
+
{ id: "goal", x: 700, y: 340, width: 64, height: 28, type: "goal" }
|
|
319
|
+
]
|
|
320
|
+
@label "Platforms"
|
|
321
|
+
@description "Level geometry rendered by the canvas (must match BodyAuthority.platforms, which owns collision — override both together)"
|
|
322
|
+
@tier "domain"
|
|
323
|
+
respawnX : number = 80
|
|
324
|
+
@label "Respawn X"
|
|
325
|
+
@description "X the body teleports to after hazard/pit damage (matches BodyAuthority spawn.x)"
|
|
326
|
+
@tier "domain"
|
|
327
|
+
respawnY : number = 320
|
|
328
|
+
@label "Respawn Y"
|
|
329
|
+
@description "Y the body teleports to after hazard/pit damage (matches BodyAuthority spawn.y)"
|
|
330
|
+
@tier "domain"
|
|
331
|
+
goalScore : number = 100
|
|
332
|
+
@label "Goal Score"
|
|
333
|
+
@description "Points awarded when the body touches the goal tile"
|
|
334
|
+
@tier "domain"
|
|
335
|
+
startLives : number = 3
|
|
336
|
+
@label "Start Lives"
|
|
337
|
+
@description "Lives seeded on INIT/PLAY_AGAIN; hazard or pit contact costs one, zero loses the round"
|
|
338
|
+
@tier "domain"
|
|
339
|
+
worldWidth : number = 800
|
|
340
|
+
@label "World Width"
|
|
341
|
+
@description "World pixel width (camera + canvas bounds)"
|
|
342
|
+
@tier "presentation"
|
|
343
|
+
fxPresets : [FxPreset] = [ { type: "score", color: "#ffe066", color2: "#fff4cc", shape: "spark", size: 22, count: 6, glow: 0.15, vy: -35 }, { type: "damage", color: "#ef4444", color2: "#7f1d1d", shape: "spark", size: 20, count: 5, glow: 0.12, gravity: 40 } ]
|
|
344
|
+
@label "Fx Presets"
|
|
345
|
+
@description "This board's effect vocabulary — one look/recipe row per fx type its intent trait emits (goal score, hazard/fell damage)."
|
|
346
|
+
@tier "presentation"
|
|
347
|
+
worldHeight : number = 400
|
|
348
|
+
@label "World Height"
|
|
349
|
+
@description "World pixel height (camera + canvas bounds)"
|
|
350
|
+
@tier "presentation"
|
|
351
|
+
bgColor : string = "#5c94fc"
|
|
352
|
+
@label "Bg Color"
|
|
353
|
+
@description "Canvas background color"
|
|
354
|
+
@tier "presentation"
|
|
355
|
+
clearTitle : string = "YOU WIN!"
|
|
356
|
+
@label "Clear Title"
|
|
357
|
+
@description "Overlay title when the goal tile is reached"
|
|
358
|
+
@tier "presentation"
|
|
359
|
+
lostTitle : string = "GAME OVER"
|
|
360
|
+
@label "Lost Title"
|
|
361
|
+
@description "Overlay title when lives run out"
|
|
362
|
+
@tier "presentation"
|
|
363
|
+
playerSprite : Asset = {}
|
|
364
|
+
@label "Player Sprite"
|
|
365
|
+
@description "Player sprite Asset; its atlas must expose adventurer_idle/walk1/walk2/jump frames (or override the sprite-selection expression)"
|
|
366
|
+
@tier "presentation"
|
|
367
|
+
tileSprites : Map string Asset = {}
|
|
368
|
+
@label "Tile Sprites"
|
|
369
|
+
@description "Map of platform type (ground/platform/hazard/goal) to tile sprite Asset"
|
|
370
|
+
@tier "presentation"
|
|
371
|
+
backgroundImage : Asset = {}
|
|
372
|
+
@label "Background Image"
|
|
373
|
+
@description "Canvas background image Asset"
|
|
374
|
+
@tier "presentation"
|
|
375
|
+
backgroundAsset : Asset = {}
|
|
376
|
+
@label "Background Asset"
|
|
377
|
+
@description "Game-shell background panel sprite (theme chrome)"
|
|
378
|
+
@tier "presentation"
|
|
379
|
+
hudBackgroundAsset : Asset = {}
|
|
380
|
+
@label "HUD Background Asset"
|
|
381
|
+
@description "HUD panel background sprite (theme chrome)"
|
|
382
|
+
@tier "presentation"
|
|
383
|
+
directionAssets : DirectionAssets = {}
|
|
384
|
+
@label "Direction Assets"
|
|
385
|
+
@description "D-pad direction icon sprites"
|
|
386
|
+
@tier "presentation"
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
page "/platformer-board-2d" as PlatformerBoard2DPage -> BodyAuthority, FxDecay, RoundGate, PlatformerIntent
|
|
391
|
+
}
|
|
@@ -50,6 +50,32 @@ orbital SurvivalBoard3DOrbital {
|
|
|
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 = {
|
|
@@ -149,7 +175,7 @@ orbital SurvivalBoard3DOrbital {
|
|
|
149
175
|
{ 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)" })) }
|
|
150
176
|
{ 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" })) }
|
|
151
177
|
{ 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" })) }
|
|
152
|
-
{ type: draw-
|
|
178
|
+
{ type: draw-fx-layer, items: @entity.fx, tickMs: 500, presets: @config.fxPresets }
|
|
153
179
|
] } ]
|
|
154
180
|
})
|
|
155
181
|
|
|
@@ -195,7 +221,7 @@ orbital SurvivalBoard3DOrbital {
|
|
|
195
221
|
{ 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)" })) }
|
|
196
222
|
{ 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" })) }
|
|
197
223
|
{ 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" })) }
|
|
198
|
-
{ type: draw-
|
|
224
|
+
{ type: draw-fx-layer, items: @entity.fx, tickMs: 500, presets: @config.fxPresets }
|
|
199
225
|
] } ]
|
|
200
226
|
})
|
|
201
227
|
|
|
@@ -288,6 +314,10 @@ orbital SurvivalBoard3DOrbital {
|
|
|
288
314
|
@label "Bg Color"
|
|
289
315
|
@description "Canvas background color."
|
|
290
316
|
@tier "presentation"
|
|
317
|
+
fxPresets : [FxPreset] = [ { type: "pickup", color: "#84a98c", color2: "#6b4226", size: 0.45, shape: "spark", count: 5, vy: -0.2 } ]
|
|
318
|
+
@label "Fx Presets"
|
|
319
|
+
@description "This board's effect vocabulary — one look/recipe row per fx type its mechanics emit; unknown types fall back to a neutral spark."
|
|
320
|
+
@tier "presentation"
|
|
291
321
|
assetManifest : AssetManifest = { terrains: {}, units: {}, features: {}, effects: {} }
|
|
292
322
|
@label "Asset Manifest"
|
|
293
323
|
@description "Per-role model manifest resolving tile/unit/feature models by terrain/category key."
|