@ludic-labs/assembly 0.0.0-stage → 0.4.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 (78) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/LICENSE +2 -0
  3. package/README.md +50 -2
  4. package/dist/bake.d.ts +80 -0
  5. package/dist/bake.js +214 -0
  6. package/dist/browser.d.ts +89 -0
  7. package/dist/browser.js +534 -0
  8. package/dist/compat.d.ts +17 -0
  9. package/dist/compat.js +153 -0
  10. package/dist/compiler.d.ts +18 -0
  11. package/dist/compiler.js +1264 -0
  12. package/dist/diagnostics.d.ts +5 -0
  13. package/dist/diagnostics.js +8 -0
  14. package/dist/export.d.ts +54 -0
  15. package/dist/export.js +272 -0
  16. package/dist/index.d.ts +4 -0
  17. package/dist/index.js +3 -0
  18. package/dist/legacy.d.ts +36 -0
  19. package/dist/legacy.js +180 -0
  20. package/dist/math.d.ts +16 -0
  21. package/dist/math.js +62 -0
  22. package/dist/mesh.d.ts +11 -0
  23. package/dist/mesh.js +153 -0
  24. package/dist/motion.d.ts +63 -0
  25. package/dist/motion.js +1476 -0
  26. package/dist/pixel.d.ts +268 -0
  27. package/dist/pixel.js +942 -0
  28. package/dist/required.d.ts +2 -0
  29. package/dist/required.js +6 -0
  30. package/dist/shapes.d.ts +71 -0
  31. package/dist/shapes.js +396 -0
  32. package/dist/sprite-brief.d.ts +5 -0
  33. package/dist/sprite-brief.js +47 -0
  34. package/dist/sprite-compiler.d.ts +62 -0
  35. package/dist/sprite-compiler.js +1745 -0
  36. package/dist/sprite-decompile.d.ts +68 -0
  37. package/dist/sprite-decompile.js +786 -0
  38. package/dist/sprite-format.d.ts +4 -0
  39. package/dist/sprite-format.js +155 -0
  40. package/dist/sprite-guide.d.ts +40 -0
  41. package/dist/sprite-guide.js +330 -0
  42. package/dist/sprite-scene.d.ts +277 -0
  43. package/dist/sprite-scene.js +664 -0
  44. package/dist/sprite-types.d.ts +110 -0
  45. package/dist/sprite-types.js +1 -0
  46. package/dist/sprite.d.ts +8 -0
  47. package/dist/sprite.js +8 -0
  48. package/dist/svg/schema.d.ts +71 -0
  49. package/dist/svg/schema.js +217 -0
  50. package/dist/svg/types.d.ts +148 -0
  51. package/dist/svg/types.js +1 -0
  52. package/dist/svg.d.ts +26 -0
  53. package/dist/svg.js +539 -0
  54. package/dist/text.d.ts +12 -0
  55. package/dist/text.js +75 -0
  56. package/dist/types.d.ts +478 -0
  57. package/dist/types.js +1 -0
  58. package/docs/svg/README.md +150 -0
  59. package/docs/svg/specification.md +108 -0
  60. package/examples/svg/arcane-shield.json +261 -0
  61. package/examples/svg/aurora-ribbon.json +158 -0
  62. package/examples/svg/bouncing-ember.json +76 -0
  63. package/examples/svg/ember-fountain.json +224 -0
  64. package/examples/svg/lantern-keeper.json +1159 -0
  65. package/examples/svg/night-workshop.json +1120 -0
  66. package/examples/svg/waygate-platform.json +64 -0
  67. package/examples/svg/waygate-spark.json +92 -0
  68. package/examples/svg/waygate-wisp.json +105 -0
  69. package/examples/svg/waygate.json +485 -0
  70. package/package.json +132 -4
  71. package/schemas/asset-assembly-0.1.schema.json +354 -0
  72. package/schemas/asset-assembly-0.2.schema.json +429 -0
  73. package/schemas/asset-assembly-0.3.schema.json +572 -0
  74. package/schemas/motion-set-0.1.schema.json +178 -0
  75. package/schemas/pixel-sprite-0.1.schema.json +892 -0
  76. package/schemas/pixel-sprite-scene-0.1.schema.json +149 -0
  77. package/schemas/svg-asset-0.1.schema.json +1157 -0
  78. package/tools/svg-asset.mjs +106 -0
@@ -0,0 +1,268 @@
1
+ /**
2
+ * Experimental pixel-art presentation for compiled assets (`pixel-profile/0.1`).
3
+ *
4
+ * Renders compiled meshes straight to a logical pixel grid with supersampling,
5
+ * then applies explicit pixel-art rules: material ramps derived in OKLCH with
6
+ * hue-shifted shadows, banded camera-relative light, coloured outlines, inner
7
+ * lines decided once per pair of parts, accents for declared features and tiny
8
+ * parts, sub-pixel face suppression and orphan cleanup. Surface patterns are
9
+ * evaluated in each asset's own frame, so they need no UVs and cover any mesh.
10
+ *
11
+ * The asset stays an ordinary three-dimensional definition; profiles, cameras
12
+ * and surfaces are presentation options. Pure and deterministic: no DOM, IO,
13
+ * randomness or mutation of inputs. The format is experimental and may change.
14
+ */
15
+ import type { CompiledAsset, Diagnostic, MeshData, Vec3 } from "./types.js";
16
+ export declare const PIXEL_PROFILE_FORMAT = "pixel-profile/0.1";
17
+ export declare const PIXEL_IMAGE_FORMAT = "pixel-image/0.1";
18
+ /** Upper bound on logical width or height. */
19
+ export declare const PIXEL_MAX_DIMENSION = 2048;
20
+ /** Upper bound on supersamples (width * height * samples^2) per render. */
21
+ export declare const PIXEL_MAX_SUBSAMPLES = 16777216;
22
+ export interface PixelRampStep {
23
+ /** OKLab lightness offset from the material colour. */
24
+ dL: number;
25
+ /** Degrees toward the cool (negative) or warm (positive) hue. */
26
+ hueShift: number;
27
+ /** Chroma multiplier. */
28
+ chroma: number;
29
+ /** Chroma floor, so near-gray materials still receive tinted shadows. */
30
+ minChroma: number;
31
+ }
32
+ export interface PixelProfile {
33
+ format: typeof PIXEL_PROFILE_FORMAT;
34
+ name: string;
35
+ coolHue: number;
36
+ warmHue: number;
37
+ /** Exactly five steps: outline, deep, shadow, mid (material colour), light. */
38
+ steps: readonly PixelRampStep[];
39
+ /** Key light in camera space (screen right, screen up, toward the viewer). */
40
+ light: {
41
+ right: number;
42
+ up: number;
43
+ back: number;
44
+ };
45
+ /** Added brightness proportional to the world-up normal component. */
46
+ topBias: number;
47
+ /** Descending n.L thresholds for light, mid and shadow; below the last is deep. */
48
+ bands: readonly [number, number, number];
49
+ /**
50
+ * "coloured": each part's own darkest ramp step; "dark": one shared line
51
+ * colour; "none". (A true selective outline that breaks lit edges is not
52
+ * implemented.)
53
+ */
54
+ outline: "coloured" | "dark" | "none";
55
+ /** Shared line colour for outline "dark". */
56
+ outlineColor: string;
57
+ /** Draw a line on the nearer part where one part is in front of another. */
58
+ innerLines: boolean;
59
+ /** Metres one part must be in front of another to count as in front. */
60
+ depthGap: number;
61
+ /** Share of boundary votes needed to decide that one part is in front. */
62
+ frontVotes: number;
63
+ /** Faces with less area than this per touched pixel are dropped. */
64
+ sliverThinness: number;
65
+ /** Parts with at most this many pixels are drawn as accents. */
66
+ accentArea: number;
67
+ /** Coverage weight that lets a declared feature win a contested pixel. */
68
+ featureWeight: number;
69
+ orphanCleanup: boolean;
70
+ /** Smallest pattern gap, in pixels, that is drawn rather than suppressed. */
71
+ patternMinPixels: number;
72
+ /** Fill tones: 4 (deep, shadow, mid, light) or 3 (deep merges into shadow). */
73
+ tones: 3 | 4;
74
+ /**
75
+ * Maximum distinct opaque colours, or null for no cap. The palette is
76
+ * derived from every input material and surface colour, not from visible
77
+ * pixels, so it is identical across views of the same scene.
78
+ */
79
+ paletteCap: number | null;
80
+ }
81
+ /**
82
+ * Built-in profiles, after a survey of itch.io environment packs (see
83
+ * docs/pixel-art.md). Experimental; none has owner visual acceptance.
84
+ */
85
+ export declare const PIXEL_PROFILES: Readonly<Record<"scene" | "fantasy" | "arcade", PixelProfile>>;
86
+ /** Profile, camera and density bundles for the built-in profiles. */
87
+ export declare const PIXEL_PRESETS: Readonly<Record<"scene" | "fantasy" | "arcade", {
88
+ profile: PixelProfile;
89
+ camera: string;
90
+ pixelsPerMetre: number;
91
+ }>>;
92
+ export interface PixelCamera {
93
+ name: string;
94
+ /** Orthonormal world-space basis: screen right, screen up and toward the viewer. */
95
+ right: Vec3;
96
+ up: Vec3;
97
+ back: Vec3;
98
+ }
99
+ /** Orthographic camera looking from `yaw` (about +Y, from +Z toward +X) and `pitch` above the horizon. */
100
+ export declare function pixelCamera(yawDegrees: number, pitchDegrees: number, name?: string): PixelCamera;
101
+ /**
102
+ * Camera presets. The dimetric presets use a 30 degree pitch at a diagonal
103
+ * yaw, which projects the ground axes to exact 2:1 pixel slopes.
104
+ */
105
+ export declare const PIXEL_CAMERAS: Readonly<Record<string, PixelCamera>>;
106
+ export interface PixelInstance {
107
+ /** Unique instance ID, used for picking. */
108
+ id: string;
109
+ /** Source part name; declared features refer to it. */
110
+ part: string;
111
+ material: string;
112
+ /** World-space mesh to draw (rest or posed). */
113
+ mesh: MeshData;
114
+ /**
115
+ * Positions in the asset's own rest frame, aligned with `mesh.positions`, for
116
+ * surface patterns. Defaults to `mesh.positions`. Supplying rest positions
117
+ * keeps patterns attached through posing and scene placement.
118
+ */
119
+ restPositions?: readonly number[] | null;
120
+ }
121
+ export interface PixelPlacement {
122
+ id: string;
123
+ asset: CompiledAsset;
124
+ /** World position of the asset origin, metres. */
125
+ position: Vec3;
126
+ /** Rotation about +Y, degrees. */
127
+ yawDegrees?: number;
128
+ /** Tint for tintable materials, #rrggbb. */
129
+ tint?: string | null;
130
+ }
131
+ /**
132
+ * Rest-pose instances of a compiled asset (instances hidden in rest states are
133
+ * omitted). `tint` (#rrggbb) multiplies tintable materials, as in meshForAsset.
134
+ */
135
+ export declare function pixelInstances(asset: CompiledAsset, tint?: string | null): PixelInstance[];
136
+ /**
137
+ * Places compiled assets in one scene. Each placement rotates about +Y and
138
+ * translates its rest meshes; IDs become `<placement>/<instance>` and patterns
139
+ * stay in each asset's own frame.
140
+ */
141
+ export declare function composePixelScene(placements: readonly PixelPlacement[]): PixelInstance[];
142
+ export type PixelPattern = {
143
+ type: "stripes";
144
+ axis: "x" | "y" | "z";
145
+ period: number;
146
+ width: number;
147
+ } | {
148
+ type: "checker";
149
+ period: number;
150
+ } | {
151
+ type: "grid";
152
+ axes: readonly ("x" | "y" | "z")[];
153
+ period: number;
154
+ width: number;
155
+ } | {
156
+ type: "bricks";
157
+ course: number;
158
+ length: number;
159
+ mortar: number;
160
+ axis: "x" | "z";
161
+ };
162
+ export interface PixelSurface {
163
+ /** Material name the pattern covers. */
164
+ material: string;
165
+ /**
166
+ * Scene placement ID the surface is limited to (instance IDs starting with
167
+ * `<scope>/`), or null for every instance using the material.
168
+ */
169
+ scope?: string | null;
170
+ pattern: PixelPattern;
171
+ /** Pattern colour, #rrggbb; shading bands still apply. */
172
+ color: string;
173
+ }
174
+ /**
175
+ * Whether a point in the asset's own frame lies on the drawn part of a
176
+ * pattern. `lineWidth` is the minimum line width in metres (0 for none). The
177
+ * same function can drive an ordinary 3D renderer as a solid texture.
178
+ */
179
+ export declare function samplePixelPattern(p: PixelPattern, point: Vec3, lineWidth?: number): boolean;
180
+ export interface PixelFrame {
181
+ /** World point placed at the canvas centre. */
182
+ center: Vec3;
183
+ width: number;
184
+ height: number;
185
+ }
186
+ export interface PixelArtOptions {
187
+ camera?: PixelCamera;
188
+ /** Fixed pixel density. Default 32. */
189
+ pixelsPerMetre?: number;
190
+ /** Empty pixels around fitted content. Default 4. Ignored with `frame`. */
191
+ margin?: number;
192
+ /** Fixed canvas around a world point instead of fitting the content. */
193
+ frame?: PixelFrame | null;
194
+ /** Supersamples per pixel axis, 1 to 4. Default 4. */
195
+ samples?: number;
196
+ profile?: PixelProfile;
197
+ /** Part names drawn as protected accents (handles, eyes, controls). */
198
+ features?: readonly string[];
199
+ surfaces?: readonly PixelSurface[];
200
+ /** Background #rrggbb, or null for transparent. Default null. */
201
+ background?: string | null;
202
+ }
203
+ export declare class PixelArtError extends Error {
204
+ readonly diagnostics: Diagnostic[];
205
+ constructor(diagnostics: Diagnostic[]);
206
+ }
207
+ /** Structural validation of render options. Errors only; render warnings are returned with the image. */
208
+ export declare function validatePixelOptions(options: PixelArtOptions): Diagnostic[];
209
+ /** Linear sRGB to OKLab (Ottosson 2020). */
210
+ export declare function linearToOklab(rgb: Vec3): Vec3;
211
+ /** OKLab to linear sRGB. */
212
+ export declare function oklabToLinear(lab: Vec3): Vec3;
213
+ /** Ramp step indices. */
214
+ export declare const PIXEL_RAMP: Readonly<{
215
+ outline: 0;
216
+ deep: 1;
217
+ shadow: 2;
218
+ mid: 3;
219
+ light: 4;
220
+ }>;
221
+ /** Five-step hue-shifted ramp (#rrggbb) for a linear-sRGB colour. */
222
+ export declare function pixelRamp(linearRgb: Vec3, profile?: PixelProfile): string[];
223
+ export interface PixelImage {
224
+ format: typeof PIXEL_IMAGE_FORMAT;
225
+ width: number;
226
+ height: number;
227
+ pixelsPerMetre: number;
228
+ camera: string;
229
+ profile: string;
230
+ /** RGBA, row-major, top row first. Background pixels are transparent unless a background is set. */
231
+ rgba: Uint8Array;
232
+ /** Index into `instances` per pixel, or -1 for background. */
233
+ owners: Int32Array;
234
+ /** Ramp step per pixel (see PIXEL_RAMP), or -1 for background. */
235
+ roles: Int8Array;
236
+ /**
237
+ * Distance toward the camera (world units along `camera.back`) of the owner's
238
+ * nearest surface in each pixel, or NaN for background. Larger is nearer.
239
+ * Lets 2D layers drawn over the image be depth-composited.
240
+ */
241
+ depth: Float32Array;
242
+ instances: {
243
+ id: string;
244
+ part: string;
245
+ material: string;
246
+ }[];
247
+ /** Distinct opaque colours used, sorted. */
248
+ palette: string[];
249
+ stats: {
250
+ outline: number;
251
+ inner: number;
252
+ accent: number;
253
+ fill: number;
254
+ pattern: number;
255
+ orphansCleaned: number;
256
+ sliverFaces: number;
257
+ frontPairs: number;
258
+ };
259
+ /** Non-fatal conditions, for example patterns suppressed below the pixel grid. */
260
+ warnings: Diagnostic[];
261
+ }
262
+ /** Instance and part under a pixel, or null for background and out-of-range coordinates. */
263
+ export declare function pickPixel(image: PixelImage, x: number, y: number): {
264
+ id: string;
265
+ part: string;
266
+ } | null;
267
+ /** Renders an asset or a composed scene to pixel art. Throws PixelArtError on invalid options or empty input. */
268
+ export declare function renderPixelArt(source: CompiledAsset | readonly PixelInstance[], options?: PixelArtOptions): PixelImage;