lecodes-sdk 2.4.9 → 2.5.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 (74) hide show
  1. package/dist/global.d.ts +35 -0
  2. package/dist/types/core/env.d.ts +25 -0
  3. package/dist/types/core/particlesConfig.d.ts +196 -0
  4. package/dist/types/g2/Font2D.d.ts +19 -0
  5. package/dist/types/g2/Material2D.d.ts +24 -0
  6. package/dist/types/g2/Node2D.d.ts +6 -5
  7. package/dist/types/g2/Particles2D.d.ts +169 -0
  8. package/dist/types/g2/Path2D.d.ts +95 -0
  9. package/dist/types/g2/Physics2D.d.ts +1 -1
  10. package/dist/types/g2/Scene2D.d.ts +15 -17
  11. package/dist/types/g2/Sprite.d.ts +12 -1
  12. package/dist/types/g2/SpriteSheet.d.ts +4 -1
  13. package/dist/types/g2/Text2D.d.ts +96 -0
  14. package/dist/types/g2/Tilemap.d.ts +8 -0
  15. package/dist/types/g2/defineScene2d.d.ts +69 -11
  16. package/dist/types/gl/Foliage.d.ts +0 -7
  17. package/dist/types/gl/Lightmap.d.ts +101 -2
  18. package/dist/types/gl/Material.d.ts +21 -15
  19. package/dist/types/gl/Model.d.ts +8 -3
  20. package/dist/types/gl/Particles.d.ts +3 -135
  21. package/dist/types/gl/Statics.d.ts +56 -0
  22. package/dist/types/gl/staticsFormat.d.ts +101 -0
  23. package/dist/types/inject.d.ts +11 -3
  24. package/dist/types/runtime/env.d.ts +10 -0
  25. package/dist/types/runtime/envValues.d.ts +8 -0
  26. package/dist/types/scene/defineScene.d.ts +17 -12
  27. package/dist/types/server/env.d.ts +14 -0
  28. package/dist/types/server/inject.d.ts +1 -0
  29. package/dist/types/ui/fonts.d.ts +4 -0
  30. package/dist/types/version.d.ts +1 -1
  31. package/dist/types.json +1 -1
  32. package/package.json +1 -1
  33. package/src/bridges/2d.d.ts +65 -5
  34. package/src/bridges/gl.d.ts +34 -15
  35. package/src/compile/bakeMacro.ts +3 -0
  36. package/src/compile/compileProject.ts +25 -4
  37. package/src/compile/envCompile.ts +74 -0
  38. package/src/compile/fontMacro.ts +11 -6
  39. package/src/compile/index.ts +6 -0
  40. package/src/compile/resourceSlots.ts +1 -0
  41. package/src/compile/serverSplit.ts +47 -4
  42. package/src/core/env.ts +47 -0
  43. package/src/core/particlesConfig.ts +422 -0
  44. package/src/g2/Font2D.ts +87 -0
  45. package/src/g2/Material2D.ts +64 -0
  46. package/src/g2/Node2D.ts +10 -6
  47. package/src/g2/Particles2D.ts +337 -0
  48. package/src/g2/Path2D.ts +215 -0
  49. package/src/g2/Physics2D.ts +1 -1
  50. package/src/g2/Scene2D.ts +16 -22
  51. package/src/g2/Sprite.ts +23 -4
  52. package/src/g2/SpriteSheet.ts +9 -5
  53. package/src/g2/Text2D.ts +178 -0
  54. package/src/g2/Tilemap.ts +10 -0
  55. package/src/g2/defineScene2d.ts +108 -21
  56. package/src/g2/groups2d.ts +2 -2
  57. package/src/gl/Foliage.ts +1 -16
  58. package/src/gl/Lightmap.ts +79 -26
  59. package/src/gl/Material.ts +51 -21
  60. package/src/gl/Model.ts +19 -5
  61. package/src/gl/Particles.ts +22 -361
  62. package/src/gl/Statics.ts +301 -0
  63. package/src/gl/nav/NavMesh.ts +4 -1
  64. package/src/gl/staticsFormat.ts +240 -0
  65. package/src/inject.ts +18 -3
  66. package/src/runtime/env.ts +13 -0
  67. package/src/runtime/envValues.ts +8 -0
  68. package/src/runtime/fetch.ts +18 -0
  69. package/src/scene/defineScene.ts +107 -27
  70. package/src/server/env.ts +25 -0
  71. package/src/server/host.ts +6 -0
  72. package/src/server/inject.ts +2 -1
  73. package/src/ui/fonts.ts +46 -0
  74. package/src/version.ts +1 -1
@@ -0,0 +1,95 @@
1
+ import { type ColorInput } from "../core/color";
2
+ import { Vec2, type Vec2Like } from "../math/vec";
3
+ import { Node2D } from "./Node2D";
4
+ import type { Material2D } from "./Material2D";
5
+ export type StrokeJoin2D = "miter" | "round" | "bevel";
6
+ export type StrokeCap2D = "butt" | "round" | "square";
7
+ export type Stroke2D = {
8
+ /** Line width. In `units: 'world'` (default) world units; in `'px'` logical screen pixels — constant
9
+ * on screen while the camera zooms (map roads, debug lines). */
10
+ width: number;
11
+ /** Default white. */
12
+ color?: ColorInput;
13
+ units?: "world" | "px";
14
+ /** How segments meet; default 'miter'. */
15
+ join?: StrokeJoin2D;
16
+ /** How an OPEN path's ends look; default 'butt'. */
17
+ cap?: StrokeCap2D;
18
+ /** A band around the line, `width` in the stroke's units; default colour black. Drawn UNDER every
19
+ * node's body at the same z, so two outlined roads merge at their junction (give a class of roads
20
+ * one z; a different z isolates). */
21
+ outline?: {
22
+ width: number;
23
+ color?: ColorInput;
24
+ };
25
+ };
26
+ export type Path2DOptions = {
27
+ /** The outer ring, in the node's local frame. */
28
+ points: readonly Vec2Like[];
29
+ /** Close the ring (a polygon). Fills always close; this is about the stroke. Default false for
30
+ * line() and a plain constructor, true for polygon() / rect() / circle(). */
31
+ closed?: boolean;
32
+ /** A number = `{ width }`. Omit = no stroke. */
33
+ stroke?: Stroke2D | number;
34
+ /** Omit = no fill. */
35
+ fill?: ColorInput;
36
+ /** Hole rings — fills only. */
37
+ holes?: readonly (readonly Vec2Like[])[];
38
+ /** Edge anti-aliasing (default true). Off for crisp pixel-art lines. */
39
+ antialias?: boolean;
40
+ position?: Vec2Like;
41
+ /** Degrees, CCW. */
42
+ rotation?: number;
43
+ scale?: Vec2Like | number;
44
+ /** Draw order within a renderPriority — see {@link Node2D.z}. */
45
+ z?: number;
46
+ /** Coarse draw order 0..7, default 4 — see {@link Node2D.renderPriority}. */
47
+ renderPriority?: number;
48
+ /** Only `blend` matters for a path (no texture); see Material2D. */
49
+ material?: Material2D;
50
+ };
51
+ type ShapeOptions = Omit<Path2DOptions, "points" | "closed">;
52
+ export declare class Path2D extends Node2D {
53
+ private _pts;
54
+ private _closed;
55
+ private _stroke;
56
+ private _outlined;
57
+ private _fill;
58
+ private _holes;
59
+ private _antialias;
60
+ private _material?;
61
+ constructor(options: Path2DOptions);
62
+ /** An open polyline. */
63
+ static line(points: readonly Vec2Like[], stroke: Stroke2D | number, options?: Omit<Path2DOptions, "points" | "stroke" | "fill" | "closed">): Path2D;
64
+ /** A closed polygon; give it a `fill` and / or a `stroke`. */
65
+ static polygon(points: readonly Vec2Like[], options?: ShapeOptions): Path2D;
66
+ /** A rectangle of `size` centred on the node's origin. */
67
+ static rect(size: Vec2Like, options?: ShapeOptions): Path2D;
68
+ /** A circle centred on the node's origin. `segments` defaults to clamp(round(radius / 2), 12, 96) —
69
+ * generous, because a fill is not re-tessellated when the camera zooms in. */
70
+ static circle(radius: number, options?: ShapeOptions & {
71
+ segments?: number;
72
+ }): Path2D;
73
+ /** The outer ring (local frame). A write re-tessellates natively — move the node instead when you can. */
74
+ get points(): Vec2[];
75
+ set points(points: readonly Vec2Like[]);
76
+ /** Whether the stroke closes the ring (fills always close). */
77
+ get closed(): boolean;
78
+ set closed(v: boolean);
79
+ /** The stroke, or null = none. A number = `{ width }`. */
80
+ get stroke(): Stroke2D | null;
81
+ set stroke(s: Stroke2D | number | null);
82
+ /** The fill colour, or null = no fill. */
83
+ get fill(): ColorInput | null;
84
+ set fill(c: ColorInput | null);
85
+ /** Hole rings (fills only). A write replaces them all. */
86
+ get holes(): Vec2[][];
87
+ set holes(rings: readonly (readonly Vec2Like[])[]);
88
+ /** Edge anti-aliasing (default true); off for crisp pixel-art lines. */
89
+ get antialias(): boolean;
90
+ set antialias(v: boolean);
91
+ /** Blend ({@link Material2D}) — only `blend` matters for a path. Undefined = the default (alpha). */
92
+ get material(): Material2D | undefined;
93
+ set material(m: Material2D);
94
+ }
95
+ export {};
@@ -124,7 +124,7 @@ export declare class Physics2D extends Aspect<"physics", Node2D> {
124
124
  * between us". Capped at 32 hits. */
125
125
  static raycastAll(from: Vec2Like, to: Vec2Like, q?: Query2D): RayHit[];
126
126
  /** Topmost body (solid or sensor) whose shape contains the world point, or null. "Topmost" means
127
- * by DRAW order - layer, then z - so picking agrees with what the player sees. */
127
+ * by DRAW order - renderPriority, then z - so picking agrees with what the player sees. */
128
128
  static overlapPoint(p: Vec2Like, q?: Query2D): Node2D | null;
129
129
  /** Everything within `radius` of a point - an explosion, an aura, an aggro range. */
130
130
  static overlapCircle(centre: Vec2Like, radius: number, q?: Query2D): Node2D[];
@@ -9,21 +9,16 @@ import { type Node2D } from "./Node2D";
9
9
  export type Scene2DOptions = {
10
10
  /** Background color — '#10131a', 0x10131a, or [r,g,b]/[r,g,b,a] in 0..1. */
11
11
  background?: ColorInput;
12
- /** Texture sampling for the 2D renderer: `'nearest'` (default — crisp pixel art) or `'linear'`
13
- * (smooth — for hi-res / non-pixel-art assets). Applied when the scene is opened, so switching
14
- * scenes restores the active scene's choice. NOTE: this is a GLOBAL renderer setting (one sampler
15
- * for ALL textures, not per-texture), so the currently-open scene's filter wins. Omit to leave the
16
- * current setting (engine default is nearest). */
12
+ /** The renderer's DEFAULT texture sampling: `'nearest'` (crisp pixel art — the engine default) or
13
+ * `'linear'` (smooth — hi-res / non-pixel-art assets). A node's `Material2D` `filter` overrides it
14
+ * per sprite / tilemap; this is what a material without one samples with. A GLOBAL renderer
15
+ * setting, so it is reasserted when the scene is opened (switching scenes restores the active
16
+ * scene's choice). Omit to leave the current setting. */
17
17
  filter?: 'nearest' | 'linear';
18
+ /** Top-down depth: among nodes of one renderPriority and one z, the one lower on screen (smaller
19
+ * world Y) draws on top. See {@link Scene2D.ySort}. */
20
+ ySort?: boolean;
18
21
  };
19
- /** Returned by scene2d.layer(n); chain .ySort() to enable top-down depth sorting for that layer. */
20
- declare class LayerHandle {
21
- private readonly sceneId;
22
- private readonly layer;
23
- constructor(sceneId: number, layer: number);
24
- /** In this layer, lower-on-screen sprites overlap higher ones (top-down feet sorting). */
25
- ySort(enabled?: boolean): this;
26
- }
27
22
  export declare class Scene2D implements Presentable {
28
23
  /** Native scene handle. */
29
24
  readonly id: number;
@@ -34,12 +29,16 @@ export declare class Scene2D implements Presentable {
34
29
  * engine variant of an app built with `lecodes app`; there `new Scene2D()` throws. */
35
30
  static get supported(): boolean;
36
31
  readonly _touchStartListeners: Array<(ev: TouchStartEvent<Node2D | null>) => void>;
37
- /** Texture filter to (re)assert on open(); the sampler is global, so each scene reclaims it. */
32
+ /** Default texture filter to (re)assert on open(); the setting is global, so each scene reclaims it. */
38
33
  private readonly _filter?;
34
+ private _ySort;
39
35
  constructor(options?: Scene2DOptions);
40
36
  set background(color: ColorInput);
41
- /** Address a draw layer to configure it, e.g. scene2d.layer(1).ySort(). */
42
- layer(n: number): LayerHandle;
37
+ /** Top-down depth sorting, one flag for the scene: among nodes of one `renderPriority` and one `z`,
38
+ * the one lower on screen (smaller world Y) draws on top — give characters and props a feet anchor
39
+ * (`[0.5, 1]`). Draw order is renderPriority, then z, then this. Default off. */
40
+ get ySort(): boolean;
41
+ set ySort(v: boolean);
43
42
  /** Topmost visible sprite whose world bounds contain the world point, or null. Body-free
44
43
  * hit-test for tap/click picking — pair with camera.screenToWorld(). */
45
44
  pick(worldPoint: Vec2Like): Node2D | null;
@@ -84,4 +83,3 @@ export declare class Scene2D implements Presentable {
84
83
  close(options?: DismissOptions): this;
85
84
  destroy(): void;
86
85
  }
87
- export {};
@@ -3,6 +3,7 @@ import { Vec2, type Vec2Like } from "../math/vec";
3
3
  import { Canvas } from "../canvas/Canvas";
4
4
  import { Node2D, type Node2DTweenProps } from "./Node2D";
5
5
  import type { Texture2D } from "./Texture2D";
6
+ import type { Material2D } from "./Material2D";
6
7
  import { type TweenMeta } from "../animate/tween/spec";
7
8
  import type { Animation } from "../animate/tween/Animation";
8
9
  /** Animatable sprite props on top of the 2D transform. */
@@ -13,6 +14,7 @@ export type SpriteTweenProps = Node2DTweenProps & {
13
14
  /** Anything that can back a sprite: a texture, or a Canvas (baked to a texture on assign). */
14
15
  export type TextureSource = Texture2D | Canvas;
15
16
  export type SpriteOptions = {
17
+ /** Omit the texture for a solid rect of `color` with `size`. */
16
18
  texture?: TextureSource;
17
19
  /** Pivot, [0,0] = top-left .. [1,1] = bottom-right. Use [0.5, 1] (feet) for Y-sorted depth. */
18
20
  anchor?: Vec2Like;
@@ -23,7 +25,10 @@ export type SpriteOptions = {
23
25
  /** Tint multiplied with the texture. */
24
26
  color?: ColorInput;
25
27
  opacity?: number;
26
- layer?: number;
28
+ /** Coarse draw order 0..7, default 4 — see {@link Node2D.renderPriority}. */
29
+ renderPriority?: number;
30
+ /** Blend + sampling — see {@link Material2D}. Default `Material2D.default`. */
31
+ material?: Material2D;
27
32
  position?: Vec2Like;
28
33
  };
29
34
  export declare class Sprite extends Node2D {
@@ -34,7 +39,9 @@ export declare class Sprite extends Node2D {
34
39
  private _flipX;
35
40
  private _flipY;
36
41
  private _size;
42
+ private _material?;
37
43
  constructor(options?: SpriteOptions);
44
+ /** The art; undefined = a solid rect of `color` (the engine's white texture). */
38
45
  get texture(): Texture2D | undefined;
39
46
  set texture(t: TextureSource | undefined);
40
47
  /** Current world size: explicit override if set, else the texture's pixel dimensions (a Canvas-backed
@@ -54,6 +61,10 @@ export declare class Sprite extends Node2D {
54
61
  set color(c: ColorInput);
55
62
  get opacity(): number;
56
63
  set opacity(a: number);
64
+ /** Blend + sampling ({@link Material2D}); undefined = the default (alpha, renderer filter, clamp).
65
+ * A material is data: assign a new one to change it. */
66
+ get material(): Material2D | undefined;
67
+ set material(m: Material2D);
57
68
  get flipX(): boolean;
58
69
  set flipX(v: boolean);
59
70
  get flipY(): boolean;
@@ -33,7 +33,10 @@ export type SpriteSheetDef = {
33
33
  };
34
34
  export type SpriteMakeOptions = {
35
35
  position?: Vec2Like;
36
- layer?: number;
36
+ /** Coarse draw order 0..7, default 4 — see {@link Node2D.renderPriority}. */
37
+ renderPriority?: number;
38
+ /** Draw order within a renderPriority — see {@link Node2D.z}. */
39
+ z?: number;
37
40
  /** Overrides the sheet/sprite anchor. */
38
41
  anchor?: Vec2Like;
39
42
  /** Start this clip immediately (sliced sprites with clips). */
@@ -0,0 +1,96 @@
1
+ import { type ColorInput } from "../core/color";
2
+ import { Vec2, type Vec2Like } from "../math/vec";
3
+ import { Node2D } from "./Node2D";
4
+ import type { Font2D } from "./Font2D";
5
+ import type { Material2D } from "./Material2D";
6
+ export type TextAlign2D = "left" | "center" | "right";
7
+ export type TextOutline2D = {
8
+ /** Halo width in em: 0.05 thin … 0.15 the maximum. 0 = none. */
9
+ width: number;
10
+ /** Default black. */
11
+ color?: ColorInput;
12
+ };
13
+ export type Text2DOptions = {
14
+ font: Font2D;
15
+ text: string;
16
+ /** Em height. `units: 'world'` (default) world units; `'px'` logical screen px — constant while the
17
+ * camera zooms (map labels, nameplates). Default 16. */
18
+ fontSize?: number;
19
+ units?: "world" | "px";
20
+ /** Default white. */
21
+ color?: ColorInput;
22
+ /** Line alignment inside the block; default 'left'. */
23
+ align?: TextAlign2D;
24
+ /** Wrap width in fontSize units; omit = no wrap. '\n' always breaks. */
25
+ maxWidth?: number;
26
+ /** Multiplier of the font's own line height (default: the font's). */
27
+ lineHeight?: number;
28
+ /** Extra spacing between letters, in em. Default 0. */
29
+ letterSpacing?: number;
30
+ /** A halo around the glyphs; omit = none. */
31
+ outline?: TextOutline2D;
32
+ /** Block anchor, [0,0] top-left … [1,1] bottom-right; default [0.5, 0.5] (centred on the node). */
33
+ anchor?: Vec2Like;
34
+ position?: Vec2Like;
35
+ /** Degrees, CCW. */
36
+ rotation?: number;
37
+ scale?: Vec2Like | number;
38
+ /** Draw order within a renderPriority — see {@link Node2D.z}. */
39
+ z?: number;
40
+ /** Coarse draw order 0..7, default 4 — see {@link Node2D.renderPriority}. */
41
+ renderPriority?: number;
42
+ /** Only `blend` matters for a text; see Material2D. */
43
+ material?: Material2D;
44
+ };
45
+ export declare class Text2D extends Node2D {
46
+ private _font;
47
+ private _text;
48
+ private _fontSize;
49
+ private _units;
50
+ private _color;
51
+ private _align;
52
+ private _maxWidth?;
53
+ private _lineHeight?;
54
+ private _letterSpacing;
55
+ private _outline;
56
+ private _anchor;
57
+ private _material?;
58
+ constructor(options: Text2DOptions);
59
+ private _sendText;
60
+ private _sendStyle;
61
+ /** The string; '\n' breaks a line. A write re-lays out the block natively. */
62
+ get text(): string;
63
+ set text(v: string);
64
+ get font(): Font2D;
65
+ set font(f: Font2D);
66
+ /** Em height, in `units`. */
67
+ get fontSize(): number;
68
+ set fontSize(v: number);
69
+ /** 'world' (default) scales with the camera; 'px' = logical screen px, constant while zooming. */
70
+ get units(): "world" | "px";
71
+ set units(v: "world" | "px");
72
+ get color(): ColorInput;
73
+ set color(c: ColorInput);
74
+ get align(): TextAlign2D;
75
+ set align(v: TextAlign2D);
76
+ /** Wrap width in fontSize units; undefined = no wrap. */
77
+ get maxWidth(): number | undefined;
78
+ set maxWidth(v: number | undefined);
79
+ /** Multiplier of the font's own line height; undefined = the font's. */
80
+ get lineHeight(): number | undefined;
81
+ set lineHeight(v: number | undefined);
82
+ /** Extra spacing between letters, in em. */
83
+ get letterSpacing(): number;
84
+ set letterSpacing(v: number);
85
+ /** The halo, or null = none. */
86
+ get outline(): TextOutline2D | null;
87
+ set outline(o: TextOutline2D | null);
88
+ /** Block anchor, [0,0] top-left … [1,1] bottom-right. */
89
+ get anchor(): Vec2;
90
+ set anchor(v: Vec2Like);
91
+ /** Blend ({@link Material2D}) — only `blend` matters for a text. Undefined = the default (alpha). */
92
+ get material(): Material2D | undefined;
93
+ set material(m: Material2D);
94
+ /** The laid-out block [width, height] in fontSize units (from the engine). */
95
+ get bounds(): Vec2;
96
+ }
@@ -1,5 +1,6 @@
1
1
  import { Node2D } from "./Node2D";
2
2
  import type { Texture2D } from "./Texture2D";
3
+ import type { Material2D } from "./Material2D";
3
4
  export type TilemapOptions = {
4
5
  texture: Texture2D;
5
6
  /** Map grid size (in tiles). */
@@ -11,10 +12,17 @@ export type TilemapOptions = {
11
12
  atlas: [number, number];
12
13
  /** Row-major tile indices into the atlas (-1 = empty), length cols*rows. Row 0 is the top row. */
13
14
  data: number[] | Int32Array;
15
+ /** Blend + sampling — see {@link Material2D}. Default `Material2D.default`. */
16
+ material?: Material2D;
14
17
  };
15
18
  export declare class Tilemap extends Node2D {
16
19
  readonly cols: number;
17
20
  readonly rows: number;
21
+ private _material?;
18
22
  constructor(options: TilemapOptions);
23
+ /** Blend + sampling ({@link Material2D}); undefined = the default (alpha, renderer filter, clamp).
24
+ * A material is data: assign a new one to change it. */
25
+ get material(): Material2D | undefined;
26
+ set material(m: Material2D);
19
27
  setTile(x: number, y: number, index: number): this;
20
28
  }
@@ -5,6 +5,10 @@ import { Scene2D } from "./Scene2D";
5
5
  import { Node2D } from "./Node2D";
6
6
  import { Sprite } from "./Sprite";
7
7
  import { Tilemap } from "./Tilemap";
8
+ import { Path2D, type Stroke2D } from "./Path2D";
9
+ import { Text2D, type TextAlign2D, type TextOutline2D } from "./Text2D";
10
+ import { Particles2D, type Particles2DOptions } from "./Particles2D";
11
+ import { type Material2DOptions } from "./Material2D";
8
12
  import { SpriteSheet } from "./SpriteSheet";
9
13
  import type { SpriteAnimation } from "./SpriteAnimation";
10
14
  import type { CellsData } from "./cells";
@@ -12,8 +16,12 @@ import type { With } from "../core/Aspect";
12
16
  export type Scene2dEnv = {
13
17
  /** Background color — '#5a6b3b', 0x5a6b3b, or [r,g,b] in 0..1. */
14
18
  background?: ColorInput;
15
- /** Texture sampling: 'nearest' (crisp pixel art, engine default) or 'linear'. */
19
+ /** Default texture sampling: 'nearest' (crisp pixel art, engine default) or 'linear'. A node's
20
+ * `material.filter` overrides it. */
16
21
  filter?: "nearest" | "linear";
22
+ /** Top-down depth: among nodes of one renderPriority and one z, the one lower on screen draws on
23
+ * top (see Scene2D.ySort). */
24
+ ySort?: boolean;
17
25
  /** Pixel-art crispness: snap the camera to whole screen pixels (seeds CameraFollow's
18
26
  * `pixelSnap`, and the initial camera position lands on whole world units). */
19
27
  pixelPerfect?: boolean;
@@ -47,6 +55,48 @@ export type TilemapSourceDef = {
47
55
  data: number[] | Int32Array;
48
56
  };
49
57
  };
58
+ /** A vector node (Path2D): a polyline / polygon in the node's local frame. */
59
+ export type PathSourceDef = {
60
+ points: readonly Vec2Like[];
61
+ /** Close the stroke's ring (fills always close). Default false. */
62
+ closed?: boolean;
63
+ /** A number = `{ width }`. Omit = no stroke. */
64
+ stroke?: Stroke2D | number;
65
+ /** Omit = no fill. */
66
+ fill?: ColorInput;
67
+ /** Hole rings — fills only. */
68
+ holes?: readonly (readonly Vec2Like[])[];
69
+ /** Edge anti-aliasing (default true). */
70
+ antialias?: boolean;
71
+ };
72
+ /** A text node (Text2D). `font` is a STRING: a family registered by `font("…")` (what the macro
73
+ * compiles to, e.g. "Inter") or a font file URL — `asset('./fonts/Brand.ttf')`. */
74
+ export type TextSourceDef = {
75
+ font: string;
76
+ text: string;
77
+ /** Em height (default 16), in `units`. */
78
+ fontSize?: number;
79
+ /** 'world' (default) or 'px' — logical screen px, constant while the camera zooms. */
80
+ units?: "world" | "px";
81
+ /** Default white. */
82
+ color?: ColorInput;
83
+ align?: TextAlign2D;
84
+ /** Wrap width in fontSize units; omit = no wrap. */
85
+ maxWidth?: number;
86
+ /** Multiplier of the font's own line height. */
87
+ lineHeight?: number;
88
+ /** Extra spacing in em. */
89
+ letterSpacing?: number;
90
+ outline?: TextOutline2D;
91
+ /** Block anchor, [0,0] top-left … [1,1] bottom-right; default [0.5, 0.5]. */
92
+ anchor?: Vec2Like;
93
+ };
94
+ /** A particle system node (Particles2D): the Particles2D options, with `texture` as a STRING — the
95
+ * sheet image's URL (`asset('./spark.png')`), loaded with Texture2D.load. The blend is the node's
96
+ * generic `material`; position / z / renderPriority are the node's too. */
97
+ export type Particles2DSourceDef = Omit<Particles2DOptions, "texture" | "material" | "position" | "z" | "renderPriority"> & {
98
+ texture?: string;
99
+ };
50
100
  /** A camera marker node: seeds the scene camera's starting position (+ zoom). To MOVE the camera
51
101
  * in play, attach `CameraFollow` to the node being followed — not aspects on this marker. */
52
102
  export type Camera2dNodeDef = {
@@ -55,6 +105,9 @@ export type Camera2dNodeDef = {
55
105
  export type Scene2dNodeDef = {
56
106
  sprite?: SpriteSourceDef;
57
107
  tilemap?: TilemapSourceDef;
108
+ path?: PathSourceDef;
109
+ text?: TextSourceDef;
110
+ particles?: Particles2DSourceDef;
58
111
  camera?: Camera2dNodeDef;
59
112
  /** A code-built subtree — `make(factoryFn, { ...literal args })`, factory returns a Node2D. */
60
113
  make?: SharedMakeEntry<any, Node2D>;
@@ -62,11 +115,14 @@ export type Scene2dNodeDef = {
62
115
  /** Degrees, CCW. */
63
116
  rotation?: number;
64
117
  scale?: Vec2Like | number;
65
- /** Draw layer (int) — higher renders on top. */
66
- layer?: number;
67
- /** Intra-layer depth for non-Y-sorted layers. */
118
+ /** Coarse draw order 0 (first) … 7 (last), default 4 — see Node2D.renderPriority. */
119
+ renderPriority?: number;
120
+ /** Draw order within a renderPriority (higher = on top); with `env.ySort`, equal z sorts by Y. */
68
121
  z?: number;
69
- /** Sprite tint (sprite nodes only). */
122
+ /** Blend + sampling (sprite, tilemap, text and particles nodes; only `blend` matters for a text) —
123
+ * see Material2D. */
124
+ material?: Material2DOptions;
125
+ /** Sprite tint / text colour (sprite and text nodes). */
70
126
  color?: ColorInput;
71
127
  /** Sprite opacity 0..1 (sprite nodes only). */
72
128
  opacity?: number;
@@ -84,10 +140,6 @@ export type Scene2dCameraDef = {
84
140
  };
85
141
  export type Scene2dDef = {
86
142
  env?: Scene2dEnv;
87
- /** Per-layer config, keyed by layer number: `layers: { 1: { ySort: true } }`. */
88
- layers?: Record<number | string, {
89
- ySort?: boolean;
90
- }>;
91
143
  /** Starting camera when there's no camera NODE (a camera node wins). */
92
144
  camera?: Scene2dCameraDef;
93
145
  nodes?: Record<string, Scene2dNodeDef>;
@@ -102,7 +154,13 @@ type SourceNodeOf<N extends Scene2dNodeDef> = N extends {
102
154
  sprite: SpriteSourceDef;
103
155
  } ? Sprite : N extends {
104
156
  tilemap: TilemapSourceDef;
105
- } ? Tilemap : Node2D;
157
+ } ? Tilemap : N extends {
158
+ path: PathSourceDef;
159
+ } ? Path2D : N extends {
160
+ text: TextSourceDef;
161
+ } ? Text2D : N extends {
162
+ particles: Particles2DSourceDef;
163
+ } ? Particles2D : Node2D;
106
164
  type AspectsOf<N extends Scene2dNodeDef> = N extends {
107
165
  aspects: readonly AspectEntry<infer A>[];
108
166
  } ? A : never;
@@ -135,7 +193,7 @@ export declare class Scene2dHandle<D extends Scene2dDef = Scene2dDef> {
135
193
  /**
136
194
  * Define a 2D scene as data — the default export of a `.scene2d.ts` file. Returns a typed handle:
137
195
  * `const { scene, nodes } = await handle.open()` gives `nodes.<name>` typed by its source block
138
- * (Sprite / Tilemap / Node2D) with its `use(...)`d aspects attached.
196
+ * (Sprite / Tilemap / Path2D / Text2D / Particles2D / Node2D) with its `use(...)`d aspects attached.
139
197
  */
140
198
  export declare const defineScene2d: <const D extends Scene2dDef>(def: D) => Scene2dHandle<D>;
141
199
  export {};
@@ -38,13 +38,6 @@ export type FoliageOptions = {
38
38
  /** 0..1: how far the baked per-vertex sky visibility (the crown's interior, the trunk under it) darkens the ambient.
39
39
  * Default 0.7. */
40
40
  skyAo?: number;
41
- /** 0..1: a leaf card's shading normal, from the card's own plane (0) to the crown's hull normal (1) — what hides that a
42
- * crown is flat quads: each card is lit as the part of the volume it sits in. Default 0.7. */
43
- canopy?: number;
44
- /** The cards' normal-map strength (a strong map brings the planes back). Default 0.5. */
45
- normalMap?: number;
46
- /** A card seen edge-on dissolves over this much of |N·V| — no paper edges on the silhouette. Default 0.15, 0 = none. */
47
- edgeFade?: number;
48
41
  /** Coverage held over distance: the cards' alpha × (1 + coverage × mip level), so a far crown does not thin out as its
49
42
  * atlas mips away. Default 0.25, 0 = none; past ~0.5 a crown turns into a solid mass. */
50
43
  coverage?: number;
@@ -1,3 +1,4 @@
1
+ import { Texture } from "./Texture";
1
2
  import { Node } from "./Node";
2
3
  import type { Scene } from "./Scene";
3
4
  /** The level's bake / load options: `bake()`'s second argument (an object literal, copied into the def as written). */
@@ -25,7 +26,7 @@ export type LightmapOptions = {
25
26
  * what is under it by the solid angle it fills, with no picture. Dense canvas: `{ through: 0.08, diffuse: 0.25 }`. */
26
27
  transmit?: Record<string, LightmapTransmit>;
27
28
  /** FOR THE BAKE: CUBES BY NAME — regular expressions (ECMAScript, case-sensitive) searched in every record's key
28
- * (`<node key>@<ordinal>`: `"SM_pipe"` takes every pipe node, `"@1$"` the second mesh of each): a record that matches
29
+ * (`<node key>@<ordinal>`: `"SM_pipe"` takes every pipe node, `"@1$"` the second node primitive of each): a record that matches
29
30
  * leaves the atlas like a small or thin one — an occluder lit by ambient cubes baked where it stands — whatever its size
30
31
  * or charts. Added to the CLI's `--cube` patterns (both apply). */
31
32
  cube?: string[];
@@ -69,6 +70,9 @@ export type LightmapFiles = {
69
70
  /** THE PACKED LIGHTMAP UV1 (`<stem>-uv1.bin`): the bake packs every mesh's lightmap charts into a square of their own
70
71
  * and its rects map that uv1 — the engine swaps it into the models' TEXCOORD_1 before the rects go on. */
71
72
  uv1?: string;
73
+ /** THE STATIC LEVEL CACHE (`<stem>.static`, gl/Statics.ts): the snapshot `lecodes static` wrote beside the bake; the macro
74
+ * stages it when it exists, and `load()` rebuilds the level's statics from it when its digest still matches. */
75
+ statics?: string;
72
76
  };
73
77
  /** What `bake('<path>.bake', options)` compiles to — the files of the bake and the level's options in one literal:
74
78
  * `env.lightmap` in a scene file, `Lightmap.load`'s argument in a hand-built scene. */
@@ -81,6 +85,7 @@ export type LightmapDebugParams = {
81
85
  };
82
86
  /** What `Lightmap.probe` answers: the baked texel under a screen point. */
83
87
  export type LightmapProbe = {
88
+ /** the bake's record (`<key>@<ordinal>`) whose rect holds the texel; "" when none does */
84
89
  key: string;
85
90
  entity: number;
86
91
  node: string;
@@ -100,6 +105,91 @@ export type LightmapAddOptions = {
100
105
  * (`--object-slab`). Default false. */
101
106
  cube?: boolean;
102
107
  };
108
+ /** a small static's light where it stands (creator-bake objects.h): its SLABS along `axis` (0 x, 1 y, 2 z; its bounds run
109
+ * from `from` to `to` along it) — one for a small one, round(length / objectSlab) for a long one — and per slab per side
110
+ * of its box (+x -x +y -y +z -z) the irradiance rgb in lux + the sky visibility; probes = a, b, a's weight (-1 = none,
111
+ * -2 = the sky) */
112
+ export type BakeObjectLight = {
113
+ at: number[];
114
+ axis: number;
115
+ from: number;
116
+ to: number;
117
+ cubes: number[][][];
118
+ probes: number[];
119
+ };
120
+ /** a RECORD of the .bake: a registered node's key, or `<key>@<ordinal>` for one mesh of a model (creator-bake atlas.h) */
121
+ export type BakeInstance = {
122
+ key: string;
123
+ receiver: boolean;
124
+ small?: boolean;
125
+ light?: BakeObjectLight;
126
+ page?: number;
127
+ rect?: number[];
128
+ st?: number[];
129
+ };
130
+ type BakeProbes = {
131
+ file: string;
132
+ size: number;
133
+ levels: number;
134
+ count: number;
135
+ oct: number;
136
+ tile: number[];
137
+ perRow: number;
138
+ atlas: number[];
139
+ spacing: number;
140
+ layout: "rooms" | "grid";
141
+ /** the block size of the pages' probe maps (atlas texels) and the range their records decode with: lo xyz, size xyz */
142
+ map: number;
143
+ encode: number[];
144
+ positions: number[][];
145
+ boxes: number[][];
146
+ /** per probe: its open share of the sphere (0 = a room, over 0.15 = under the sky) */
147
+ sky: number[];
148
+ };
149
+ export type BakeData = {
150
+ version: number;
151
+ size: number;
152
+ pages: number;
153
+ texel: number;
154
+ lightScale: number;
155
+ texels?: number;
156
+ light: string[];
157
+ aux: string[];
158
+ direct?: string[];
159
+ indirect?: string[];
160
+ probes?: BakeProbes | null;
161
+ /** the light grid (creator-bake volume.h): its file and lattice */
162
+ volume?: {
163
+ file: string;
164
+ n: number[];
165
+ origin: number[];
166
+ cell: number[];
167
+ valid: number;
168
+ } | null;
169
+ /** the packed lightmap uv1 the rects map (creator-bake atlas.h), null = the models' own */
170
+ uv1?: string | null;
171
+ sun?: {
172
+ direction: number[];
173
+ color: number[];
174
+ lux: number;
175
+ } | null;
176
+ sunMap?: boolean;
177
+ sunMapLevels?: number;
178
+ mips?: number;
179
+ emissiveNits?: number;
180
+ instances: BakeInstance[];
181
+ };
182
+ /** What `Lightmap.prepare` hands `apply`: the bake read and its pages loaded. */
183
+ export type LightmapPrepared = {
184
+ def: LightmapDef;
185
+ data: BakeData;
186
+ n: number;
187
+ light: Texture[];
188
+ aux: Texture[];
189
+ probes: number;
190
+ probeAtlas?: Texture;
191
+ t: number[];
192
+ };
103
193
  export declare class Lightmap {
104
194
  /** True while `lecodes lightmap bake` runs the app — skip menus and build the scene straight away. */
105
195
  static get baking(): boolean;
@@ -145,6 +235,14 @@ export declare class Lightmap {
145
235
  * to (a scene file's `env.lightmap`). Resolves to null when nothing was applied (no bake yet, a host without the
146
236
  * feature, bake mode). */
147
237
  private static scene;
238
+ /** `load` in two halves (the static level cache binds records as it clones, so the pages must be in BEFORE the
239
+ * statics build): `prepare` reads the bake, swaps the uv1 in, loads the pages / probes and sets the level-wide
240
+ * options; `apply` binds the rects of the statics the SDK registered, then the light grid. */
241
+ static prepare(scene: Scene, def: LightmapDef): Promise<LightmapPrepared | null>;
242
+ /** The bake's page texture ids, light / aux interleaved per page — what the static level cache binds with. */
243
+ static pageIds(p: LightmapPrepared): Uint32Array;
244
+ static apply(p: LightmapPrepared): Promise<LightmapInfo | null>;
245
+ /** Bind a bake to the level: the statics registered so far take their rects, the movers the light grid. */
148
246
  static load(scene: Scene, def: LightmapDef): Promise<LightmapInfo | null>;
149
247
  /** The bake's `<key>@k` records by their node key: a model's meshes (k = the primitive's ordinal in its file). */
150
248
  private static recordsOf;
@@ -161,7 +259,7 @@ export declare class Lightmap {
161
259
  static debugProbes(on: boolean, radius?: number): number;
162
260
  /** The view names in `lightmapDebug`'s order — for a knob that cycles them. */
163
261
  static get debugModes(): readonly LightmapDebugMode[];
164
- /** The baked texel under a screen point (logical px): its instance key, page and texel column / row,
262
+ /** The baked texel under a screen point (logical px): its record key, page and texel column / row,
165
263
  * so the value can be looked up in the bake's debug layers (`lecodes lightmap inspect`). null when
166
264
  * nothing baked is under the point or the host has no triangle pick. */
167
265
  static probe(screenX: number, screenY: number): LightmapProbe | null;
@@ -176,3 +274,4 @@ export declare class Lightmap {
176
274
  private static meshMaterial;
177
275
  private static bake;
178
276
  }
277
+ export {};