@nodetool-ai/game-nodes 0.8.1
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/README.md +61 -0
- package/dist/.nodetool-build-stamp +1 -0
- package/dist/atlas-preparation.d.ts +9 -0
- package/dist/atlas-preparation.d.ts.map +1 -0
- package/dist/atlas-preparation.js +117 -0
- package/dist/atlas-preparation.js.map +1 -0
- package/dist/fills.d.ts +31 -0
- package/dist/fills.d.ts.map +1 -0
- package/dist/fills.js +100 -0
- package/dist/fills.js.map +1 -0
- package/dist/font-preparation.d.ts +3 -0
- package/dist/font-preparation.d.ts.map +1 -0
- package/dist/font-preparation.js +26 -0
- package/dist/font-preparation.js.map +1 -0
- package/dist/image-preparation.d.ts +73 -0
- package/dist/image-preparation.d.ts.map +1 -0
- package/dist/image-preparation.js +107 -0
- package/dist/image-preparation.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/nodes/game.d.ts +102 -0
- package/dist/nodes/game.d.ts.map +1 -0
- package/dist/nodes/game.js +201 -0
- package/dist/nodes/game.js.map +1 -0
- package/dist/templates.d.ts +9 -0
- package/dist/templates.d.ts.map +1 -0
- package/dist/templates.js +25 -0
- package/dist/templates.js.map +1 -0
- package/package.json +67 -0
package/README.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Native game asset nodes
|
|
2
|
+
|
|
3
|
+
`LoadGameTemplate` lists the slots in a native template. `SlotPrompt` provides
|
|
4
|
+
generation prompts and checker properties. `StageGameAssets` validates checked
|
|
5
|
+
media and stages content-addressed candidate bindings for a full game ID.
|
|
6
|
+
|
|
7
|
+
Install candidate bindings through the authorized game revision operation.
|
|
8
|
+
Staging does not edit scenes or behaviors.
|
|
9
|
+
|
|
10
|
+
`StageGameAssets.preparation` maps slot IDs to image settings. Each entry may set
|
|
11
|
+
`trimAlpha`, `targetWidth` and `targetHeight`, `cropPolicy` (`cover`, `contain`,
|
|
12
|
+
`stretch`), `mirrorX`, `mirrorY`, `pivot`, and `sampling`. Resizing, trimming and
|
|
13
|
+
mirror tiling apply to single-image slots. Sheet and tile slots retain their
|
|
14
|
+
checked grid and accept sampling and pivot settings. A sheet may also set
|
|
15
|
+
`sheet: {cols, rows, baseline?}` when its grid matches the checked spritesheet.
|
|
16
|
+
The node decodes the
|
|
17
|
+
checked image, verifies its dimensions, writes prepared PNG bytes, then hashes
|
|
18
|
+
those bytes. A trimmed binding records its original dimensions and crop offset;
|
|
19
|
+
the renderer preserves its anchor. Mirror tiling duplicates reflected edge
|
|
20
|
+
pixels, so both repeat boundaries meet. The maximum prepared dimension is
|
|
21
|
+
4096 pixels per axis.
|
|
22
|
+
|
|
23
|
+
`SlotPrompt.reference_images` exposes the selected style image for an
|
|
24
|
+
image-to-image generator. The guided graph uses that image as a provider input
|
|
25
|
+
when the chosen style has `reference_asset_id`; it records the reference in the
|
|
26
|
+
staged binding. `StageGameAssets.fonts` maps logical font IDs to local or asset
|
|
27
|
+
URIs for TrueType or OpenType files. Install those bindings through the same
|
|
28
|
+
revision operation as images. New preparation and font bindings require a
|
|
29
|
+
schema version 2 game document.
|
|
30
|
+
|
|
31
|
+
The `generate_game_asset` agent tool also prepares imported or generated images:
|
|
32
|
+
|
|
33
|
+
- `sheet: {cols, rows, baseline?}` produces an atlas with equal-sized frames.
|
|
34
|
+
Each pose is centered horizontally by its alpha bounds and shifted so its
|
|
35
|
+
lowest opaque row lies at `baseline`, a zero-based cell row. The default is
|
|
36
|
+
the last row of the cell. A grid that would discard pixels or a baseline
|
|
37
|
+
that would clip a pose is rejected. Empty cells stay transparent. The tool
|
|
38
|
+
returns `frames` and bindings named `<slot>.frame.<index>` sharing one atlas.
|
|
39
|
+
- `tileset: {tileWidth?, tileHeight?, edges?, highlight?, shadow?}` resizes a
|
|
40
|
+
source texture to one tile and bakes a 4×4 atlas of exposed-edge variants.
|
|
41
|
+
Defaults are 32×32 tiles, a two-pixel edge, highlight 1.16 and shadow 0.72.
|
|
42
|
+
The mask bits are top `1`, right `2`, bottom `4` and left `8`. Mask zero is
|
|
43
|
+
the interior. The tool returns `tiles` and `<slot>.tile.<mask>` bindings.
|
|
44
|
+
- `lut: {size?, brightness?, contrast?, saturation?, lift?, gain?, gamma?}`
|
|
45
|
+
creates an opaque `size² × size` color cube directly, without an image model.
|
|
46
|
+
Size defaults to 16. The default grade is identity. It applies saturation,
|
|
47
|
+
contrast and brightness, then channel lift, gamma and gain. It packs red
|
|
48
|
+
within a blue slice on the horizontal axis and green on the vertical axis,
|
|
49
|
+
matching the game's LUT renderer.
|
|
50
|
+
|
|
51
|
+
These modes cannot be combined with each other or with trimming, resizing or
|
|
52
|
+
mirror tiling. Bind the returned frame bindings in one `edit_native_game`
|
|
53
|
+
operation batch or pass them to the game builder's `registerAssets` helper.
|
|
54
|
+
The generated atlas is installed once. Frame bindings reuse its full asset ID.
|
|
55
|
+
|
|
56
|
+
`generate_game_asset` accepts `input_file` as an owned asset URI, including a
|
|
57
|
+
unique 12-character ID prefix, or a workspace-relative path. `font` imports
|
|
58
|
+
TrueType and OpenType files. `sfx` imports WAV, Ogg or MP3 audio, or runs an
|
|
59
|
+
explicit registered sound-effect `node_type` with its `params` forwarded as
|
|
60
|
+
node inputs. Use `search_nodes` and `get_node_info` to select the node and its
|
|
61
|
+
inputs. Sound-effect node generation is synchronous. Speech remains `audio`.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2026-09-28T09:19:13.819Z
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { gameLutPreparation, gameSheetPreparation, gameTilesetPreparation } from "@nodetool-ai/protocol";
|
|
3
|
+
import type { PreparedImage } from "./image-preparation.js";
|
|
4
|
+
export declare function prepareSheet(bytes: Uint8Array, width: number, height: number, settings: z.infer<typeof gameSheetPreparation>): Promise<PreparedImage>;
|
|
5
|
+
/** Edge bits are top=1, right=2, bottom=4, left=8. Mask zero is the interior tile. */
|
|
6
|
+
export declare function prepareTileset(bytes: Uint8Array, originalWidth: number, originalHeight: number, settings: z.infer<typeof gameTilesetPreparation>, sampling: "nearest" | "linear"): Promise<PreparedImage>;
|
|
7
|
+
/** Produce a color cube directly so LUTs never depend on an image model's pixels. */
|
|
8
|
+
export declare function prepareLut(settings: z.infer<typeof gameLutPreparation>): Promise<PreparedImage>;
|
|
9
|
+
//# sourceMappingURL=atlas-preparation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atlas-preparation.d.ts","sourceRoot":"","sources":["../src/atlas-preparation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AACzG,OAAO,KAAK,EAAiB,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAS3E,wBAAsB,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EACjF,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CA2CxE;AAED,sFAAsF;AACtF,wBAAsB,cAAc,CAAC,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EACnG,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,EAAE,QAAQ,EAAE,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC,aAAa,CAAC,CA8B1G;AAED,qFAAqF;AACrF,wBAAsB,UAAU,CAAC,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAyBrG"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import sharp from "sharp";
|
|
2
|
+
const MAX_PIXELS = 4096 * 4096;
|
|
3
|
+
async function encode(pixels, width, height) {
|
|
4
|
+
return sharp(pixels, { raw: { width, height, channels: 4 } })
|
|
5
|
+
.png({ compressionLevel: 9, palette: false }).toBuffer();
|
|
6
|
+
}
|
|
7
|
+
export async function prepareSheet(bytes, width, height, settings) {
|
|
8
|
+
if (width % settings.cols !== 0 || height % settings.rows !== 0) {
|
|
9
|
+
throw new Error("Sprite sheet dimensions must be divisible by cols and rows");
|
|
10
|
+
}
|
|
11
|
+
const cellWidth = width / settings.cols;
|
|
12
|
+
const cellHeight = height / settings.rows;
|
|
13
|
+
const baseline = settings.baseline ?? cellHeight - 1;
|
|
14
|
+
if (baseline >= cellHeight) {
|
|
15
|
+
throw new Error("Sprite sheet baseline must lie inside each cell");
|
|
16
|
+
}
|
|
17
|
+
const source = await sharp(bytes, { limitInputPixels: MAX_PIXELS }).ensureAlpha().raw().toBuffer();
|
|
18
|
+
const output = Buffer.alloc(width * height * 4);
|
|
19
|
+
const frames = [];
|
|
20
|
+
for (let row = 0; row < settings.rows; row += 1) {
|
|
21
|
+
for (let col = 0; col < settings.cols; col += 1) {
|
|
22
|
+
const frame = { x: col * cellWidth, y: row * cellHeight, width: cellWidth, height: cellHeight };
|
|
23
|
+
frames.push(frame);
|
|
24
|
+
let left = cellWidth;
|
|
25
|
+
let top = cellHeight;
|
|
26
|
+
let right = 0;
|
|
27
|
+
let bottom = 0;
|
|
28
|
+
for (let y = 0; y < cellHeight; y += 1) {
|
|
29
|
+
for (let x = 0; x < cellWidth; x += 1) {
|
|
30
|
+
if (source[((frame.y + y) * width + frame.x + x) * 4 + 3] === 0) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
left = Math.min(left, x);
|
|
34
|
+
top = Math.min(top, y);
|
|
35
|
+
right = Math.max(right, x + 1);
|
|
36
|
+
bottom = Math.max(bottom, y + 1);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (bottom === 0) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const poseWidth = right - left;
|
|
43
|
+
const poseHeight = bottom - top;
|
|
44
|
+
if (poseHeight > baseline + 1) {
|
|
45
|
+
throw new Error(`Sprite sheet baseline would clip pose ${frames.length - 1}`);
|
|
46
|
+
}
|
|
47
|
+
const xOffset = Math.floor((cellWidth - poseWidth) / 2);
|
|
48
|
+
const yOffset = baseline + 1 - poseHeight;
|
|
49
|
+
for (let y = 0; y < poseHeight; y += 1) {
|
|
50
|
+
const start = ((frame.y + top + y) * width + frame.x + left) * 4;
|
|
51
|
+
source.copy(output, ((frame.y + yOffset + y) * width + frame.x + xOffset) * 4, start, start + poseWidth * 4);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return { bytes: await encode(output, width, height), width, height, originalWidth: width,
|
|
56
|
+
originalHeight: height, frames, baseline };
|
|
57
|
+
}
|
|
58
|
+
/** Edge bits are top=1, right=2, bottom=4, left=8. Mask zero is the interior tile. */
|
|
59
|
+
export async function prepareTileset(bytes, originalWidth, originalHeight, settings, sampling) {
|
|
60
|
+
const tileWidth = settings.tileWidth;
|
|
61
|
+
const tileHeight = settings.tileHeight;
|
|
62
|
+
const width = tileWidth * 4;
|
|
63
|
+
const height = tileHeight * 4;
|
|
64
|
+
const source = await sharp(bytes, { limitInputPixels: MAX_PIXELS }).ensureAlpha()
|
|
65
|
+
.resize(tileWidth, tileHeight, { fit: "cover", kernel: sampling === "nearest" ? "nearest" : "lanczos3" })
|
|
66
|
+
.raw().toBuffer();
|
|
67
|
+
const output = Buffer.alloc(width * height * 4);
|
|
68
|
+
const tiles = [];
|
|
69
|
+
for (let mask = 0; mask < 16; mask += 1) {
|
|
70
|
+
const frame = { x: (mask % 4) * tileWidth, y: Math.floor(mask / 4) * tileHeight, width: tileWidth, height: tileHeight };
|
|
71
|
+
tiles.push({ mask, frame });
|
|
72
|
+
for (let y = 0; y < tileHeight; y += 1) {
|
|
73
|
+
for (let x = 0; x < tileWidth; x += 1) {
|
|
74
|
+
const sourceOffset = (y * tileWidth + x) * 4;
|
|
75
|
+
const destination = ((frame.y + y) * width + frame.x + x) * 4;
|
|
76
|
+
const top = (mask & 1) !== 0 && y < settings.edges;
|
|
77
|
+
const right = (mask & 2) !== 0 && x >= tileWidth - settings.edges;
|
|
78
|
+
const bottom = (mask & 4) !== 0 && y >= tileHeight - settings.edges;
|
|
79
|
+
const left = (mask & 8) !== 0 && x < settings.edges;
|
|
80
|
+
const factor = (top || left ? settings.highlight : 1) * (right || bottom ? settings.shadow : 1);
|
|
81
|
+
for (let channel = 0; channel < 3; channel += 1) {
|
|
82
|
+
output[destination + channel] = Math.min(255, Math.round(source[sourceOffset + channel] * factor));
|
|
83
|
+
}
|
|
84
|
+
output[destination + 3] = source[sourceOffset + 3];
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return { bytes: await encode(output, width, height), width, height, originalWidth, originalHeight, tiles };
|
|
89
|
+
}
|
|
90
|
+
/** Produce a color cube directly so LUTs never depend on an image model's pixels. */
|
|
91
|
+
export async function prepareLut(settings) {
|
|
92
|
+
const size = settings.size;
|
|
93
|
+
const width = size * size;
|
|
94
|
+
const height = size;
|
|
95
|
+
const output = Buffer.alloc(width * height * 4);
|
|
96
|
+
const clamp = (value) => Math.min(1, Math.max(0, value));
|
|
97
|
+
for (let b = 0; b < size; b += 1) {
|
|
98
|
+
for (let g = 0; g < size; g += 1) {
|
|
99
|
+
for (let r = 0; r < size; r += 1) {
|
|
100
|
+
const values = [r, g, b].map((value) => value / (size - 1));
|
|
101
|
+
const luma = values[0] * 0.2126 + values[1] * 0.7152 + values[2] * 0.0722;
|
|
102
|
+
const offset = (g * width + b * size + r) * 4;
|
|
103
|
+
for (let channel = 0; channel < 3; channel += 1) {
|
|
104
|
+
const saturated = luma + (values[channel] - luma) * settings.saturation;
|
|
105
|
+
const contrasted = (saturated - 0.5) * settings.contrast + 0.5 + settings.brightness;
|
|
106
|
+
const lifted = clamp(contrasted + settings.lift[channel]);
|
|
107
|
+
const graded = Math.pow(lifted, 1 / settings.gamma[channel]) * settings.gain[channel];
|
|
108
|
+
output[offset + channel] = Math.round(clamp(graded) * 255);
|
|
109
|
+
}
|
|
110
|
+
output[offset + 3] = 255;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return { bytes: await encode(output, width, height), width, height, originalWidth: width,
|
|
115
|
+
originalHeight: height, lutSize: size };
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=atlas-preparation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atlas-preparation.js","sourceRoot":"","sources":["../src/atlas-preparation.ts"],"names":[],"mappings":"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"}
|
package/dist/fills.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading a graph's `fills` input into a native game asset candidate manifest.
|
|
3
|
+
*
|
|
4
|
+
* A `nodetool.game.*` checker emits two handles: `fill`, the {@link SlotFill}
|
|
5
|
+
* it validated, and `output`, the stored image or audio ref carrying that same
|
|
6
|
+
* fill under `metadata.nodetool_slot`. Only the second one knows where the
|
|
7
|
+
* bytes are, so that is the handle `StageGameAssets` wants — and a bare fill
|
|
8
|
+
* is rejected with the wiring that fixes it rather than exported as a project
|
|
9
|
+
* with no art in it.
|
|
10
|
+
*/
|
|
11
|
+
import { type FilledManifest } from "@nodetool-ai/protocol";
|
|
12
|
+
import type { MediaRefValue } from "@nodetool-ai/runtime";
|
|
13
|
+
export interface ResolvedFills {
|
|
14
|
+
manifest: FilledManifest;
|
|
15
|
+
/** The ref to read bytes from, per asset id the writer will copy. */
|
|
16
|
+
refs: Map<string, MediaRefValue>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The filled manifest `fills` describes, plus the ref each asset's bytes come
|
|
20
|
+
* from.
|
|
21
|
+
*
|
|
22
|
+
* An entry is either a checker's stamped `output` ref or a whole
|
|
23
|
+
* `{slot_id, asset, fill}` record. An empty list is a filled manifest with no
|
|
24
|
+
* slots — the blank-template export, which ships the template's own art. An
|
|
25
|
+
* asset id is taken from the ref when it has one and derived from the slot id
|
|
26
|
+
* when it does not, so a hermetic run — one whose context cannot create
|
|
27
|
+
* assets, where every checker returns its ref inline — still exports a project
|
|
28
|
+
* with deterministic resource ids.
|
|
29
|
+
*/
|
|
30
|
+
export declare function resolveFills(template: string, fills: readonly unknown[]): ResolvedFills;
|
|
31
|
+
//# sourceMappingURL=fills.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fills.d.ts","sourceRoot":"","sources":["../src/fills.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAKL,KAAK,cAAc,EAGpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AA+B1D,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,cAAc,CAAC;IACzB,qEAAqE;IACrE,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CAClC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,SAAS,OAAO,EAAE,GACxB,aAAa,CAmEf"}
|
package/dist/fills.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading a graph's `fills` input into a native game asset candidate manifest.
|
|
3
|
+
*
|
|
4
|
+
* A `nodetool.game.*` checker emits two handles: `fill`, the {@link SlotFill}
|
|
5
|
+
* it validated, and `output`, the stored image or audio ref carrying that same
|
|
6
|
+
* fill under `metadata.nodetool_slot`. Only the second one knows where the
|
|
7
|
+
* bytes are, so that is the handle `StageGameAssets` wants — and a bare fill
|
|
8
|
+
* is rejected with the wiring that fixes it rather than exported as a project
|
|
9
|
+
* with no art in it.
|
|
10
|
+
*/
|
|
11
|
+
import { SLOT_METADATA_KEY, filledManifest, filledSlot, slotFill } from "@nodetool-ai/protocol";
|
|
12
|
+
/** The default extension per fill kind, when a ref's uri carries none. */
|
|
13
|
+
const DEFAULT_EXTENSION = {
|
|
14
|
+
spritesheet: "png",
|
|
15
|
+
tileset: "png",
|
|
16
|
+
image: "png",
|
|
17
|
+
sfx: "wav",
|
|
18
|
+
music: "wav"
|
|
19
|
+
};
|
|
20
|
+
const isAudio = (kind) => kind === "sfx" || kind === "music";
|
|
21
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22
|
+
const text = (value) => typeof value === "string" ? value.trim() : "";
|
|
23
|
+
/** `asset://player.png` → `player`; anything else → "". */
|
|
24
|
+
function idFromUri(uri) {
|
|
25
|
+
if (!uri.startsWith("asset://"))
|
|
26
|
+
return "";
|
|
27
|
+
return uri.slice("asset://".length).split(".")[0] ?? "";
|
|
28
|
+
}
|
|
29
|
+
function extensionFromUri(uri) {
|
|
30
|
+
const match = /\.([a-z0-9]+)$/i.exec(uri);
|
|
31
|
+
return match ? match[1].toLowerCase() : "";
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The filled manifest `fills` describes, plus the ref each asset's bytes come
|
|
35
|
+
* from.
|
|
36
|
+
*
|
|
37
|
+
* An entry is either a checker's stamped `output` ref or a whole
|
|
38
|
+
* `{slot_id, asset, fill}` record. An empty list is a filled manifest with no
|
|
39
|
+
* slots — the blank-template export, which ships the template's own art. An
|
|
40
|
+
* asset id is taken from the ref when it has one and derived from the slot id
|
|
41
|
+
* when it does not, so a hermetic run — one whose context cannot create
|
|
42
|
+
* assets, where every checker returns its ref inline — still exports a project
|
|
43
|
+
* with deterministic resource ids.
|
|
44
|
+
*/
|
|
45
|
+
export function resolveFills(template, fills) {
|
|
46
|
+
const slots = [];
|
|
47
|
+
const refs = new Map();
|
|
48
|
+
for (const [index, entry] of fills.entries()) {
|
|
49
|
+
const at = `fills[${index}]`;
|
|
50
|
+
if (!isRecord(entry)) {
|
|
51
|
+
throw new Error(`${at} is not a slot fill.`);
|
|
52
|
+
}
|
|
53
|
+
const whole = filledSlot.safeParse(entry);
|
|
54
|
+
if (whole.success) {
|
|
55
|
+
slots.push(whole.data);
|
|
56
|
+
refs.set(whole.data.asset.asset_id, {
|
|
57
|
+
uri: whole.data.asset.uri,
|
|
58
|
+
asset_id: whole.data.asset.asset_id
|
|
59
|
+
});
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const stamped = slotFill.safeParse(isRecord(entry.metadata) ? entry.metadata[SLOT_METADATA_KEY] : undefined);
|
|
63
|
+
if (!stamped.success) {
|
|
64
|
+
const bare = slotFill.safeParse(entry);
|
|
65
|
+
throw new Error(bare.success
|
|
66
|
+
? `${at} is a bare ${bare.data.kind} fill for slot ${bare.data.slot_id}, ` +
|
|
67
|
+
`which says nothing about where the bytes are. Wire the checker's ` +
|
|
68
|
+
`output handle instead of its fill handle.`
|
|
69
|
+
: `${at} carries no slot fill. Run the asset through the nodetool.game ` +
|
|
70
|
+
`node for its kind first (SpriteSheet, Tileset, SeamlessImage, ` +
|
|
71
|
+
`SoundEffect, MusicLoop).`);
|
|
72
|
+
}
|
|
73
|
+
const fill = stamped.data;
|
|
74
|
+
const uri = text(entry.uri);
|
|
75
|
+
const assetId = text(entry.asset_id) || idFromUri(uri) || fill.slot_id.replace(/\./g, "_");
|
|
76
|
+
const extension = extensionFromUri(uri) || DEFAULT_EXTENSION[fill.kind];
|
|
77
|
+
slots.push({
|
|
78
|
+
slot_id: fill.slot_id,
|
|
79
|
+
asset: {
|
|
80
|
+
type: isAudio(fill.kind) ? "audio" : "image",
|
|
81
|
+
uri: `asset://${assetId}.${extension}`,
|
|
82
|
+
asset_id: assetId
|
|
83
|
+
},
|
|
84
|
+
fill
|
|
85
|
+
});
|
|
86
|
+
refs.set(assetId, entry);
|
|
87
|
+
}
|
|
88
|
+
const parsed = filledManifest.safeParse({
|
|
89
|
+
manifest_version: 1,
|
|
90
|
+
template,
|
|
91
|
+
slots
|
|
92
|
+
});
|
|
93
|
+
if (!parsed.success) {
|
|
94
|
+
throw new Error(`the filled slots do not form a manifest: ${parsed.error.issues
|
|
95
|
+
.map((i) => `${i.path.join(".") || "<root>"}: ${i.message}`)
|
|
96
|
+
.join("; ")}`);
|
|
97
|
+
}
|
|
98
|
+
return { manifest: parsed.data, refs };
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=fills.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fills.js","sourceRoot":"","sources":["../src/fills.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"font-preparation.d.ts","sourceRoot":"","sources":["../src/font-preparation.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI,CAetE"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Detect the font containers accepted by the game renderer and export builder. */
|
|
2
|
+
export function gameFontFormat(bytes) {
|
|
3
|
+
if (bytes.length < 12) {
|
|
4
|
+
return null;
|
|
5
|
+
}
|
|
6
|
+
const trueType = bytes[0] === 0 && bytes[1] === 1 && bytes[2] === 0 && bytes[3] === 0;
|
|
7
|
+
const openType = bytes[0] === 79 && bytes[1] === 84 && bytes[2] === 84 && bytes[3] === 79;
|
|
8
|
+
if (!trueType && !openType) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
const tables = bytes[4] * 256 + bytes[5];
|
|
12
|
+
if (tables < 1 || 12 + tables * 16 > bytes.length) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
16
|
+
for (let index = 0; index < tables; index += 1) {
|
|
17
|
+
const position = 12 + index * 16;
|
|
18
|
+
const offset = view.getUint32(position + 8);
|
|
19
|
+
const length = view.getUint32(position + 12);
|
|
20
|
+
if (offset < 12 + tables * 16 || offset + length > bytes.length) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return trueType ? "ttf" : "otf";
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=font-preparation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"font-preparation.js","sourceRoot":"","sources":["../src/font-preparation.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,MAAM,UAAU,cAAc,CAAC,KAAiB;IAC9C,IAAI,KAAK,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QAAC,OAAO,IAAI,CAAC;IAAC,CAAC;IACvC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACtF,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;IAC1F,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,EAAE,CAAC;QAAC,OAAO,IAAI,CAAC;IAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACzC,IAAI,MAAM,GAAG,CAAC,IAAI,EAAE,GAAG,MAAM,GAAG,EAAE,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QAAC,OAAO,IAAI,CAAC;IAAC,CAAC;IACnE,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IAC5E,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC/C,MAAM,QAAQ,GAAG,EAAE,GAAG,KAAK,GAAG,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,GAAG,EAAE,CAAC,CAAC;QAC7C,IAAI,MAAM,GAAG,EAAE,GAAG,MAAM,GAAG,EAAE,IAAI,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YAAC,OAAO,IAAI,CAAC;QAAC,CAAC;IACnF,CAAC;IACD,OAAO,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const imagePreparationSettings: z.ZodObject<{
|
|
3
|
+
sheet: z.ZodOptional<z.ZodObject<{
|
|
4
|
+
cols: z.ZodNumber;
|
|
5
|
+
rows: z.ZodNumber;
|
|
6
|
+
baseline: z.ZodOptional<z.ZodNumber>;
|
|
7
|
+
}, z.core.$strict>>;
|
|
8
|
+
tileset: z.ZodOptional<z.ZodObject<{
|
|
9
|
+
tileWidth: z.ZodDefault<z.ZodNumber>;
|
|
10
|
+
tileHeight: z.ZodDefault<z.ZodNumber>;
|
|
11
|
+
edges: z.ZodDefault<z.ZodNumber>;
|
|
12
|
+
highlight: z.ZodDefault<z.ZodNumber>;
|
|
13
|
+
shadow: z.ZodDefault<z.ZodNumber>;
|
|
14
|
+
}, z.core.$strict>>;
|
|
15
|
+
lut: z.ZodOptional<z.ZodObject<{
|
|
16
|
+
size: z.ZodDefault<z.ZodNumber>;
|
|
17
|
+
brightness: z.ZodDefault<z.ZodNumber>;
|
|
18
|
+
contrast: z.ZodDefault<z.ZodNumber>;
|
|
19
|
+
saturation: z.ZodDefault<z.ZodNumber>;
|
|
20
|
+
lift: z.ZodDefault<z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber], null>>;
|
|
21
|
+
gain: z.ZodDefault<z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber], null>>;
|
|
22
|
+
gamma: z.ZodDefault<z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber], null>>;
|
|
23
|
+
}, z.core.$strict>>;
|
|
24
|
+
trimAlpha: z.ZodDefault<z.ZodBoolean>;
|
|
25
|
+
targetWidth: z.ZodOptional<z.ZodNumber>;
|
|
26
|
+
targetHeight: z.ZodOptional<z.ZodNumber>;
|
|
27
|
+
cropPolicy: z.ZodOptional<z.ZodEnum<{
|
|
28
|
+
contain: "contain";
|
|
29
|
+
cover: "cover";
|
|
30
|
+
stretch: "stretch";
|
|
31
|
+
}>>;
|
|
32
|
+
mirrorX: z.ZodDefault<z.ZodBoolean>;
|
|
33
|
+
mirrorY: z.ZodDefault<z.ZodBoolean>;
|
|
34
|
+
pivot: z.ZodDefault<z.ZodObject<{
|
|
35
|
+
x: z.ZodNumber;
|
|
36
|
+
y: z.ZodNumber;
|
|
37
|
+
}, z.core.$strict>>;
|
|
38
|
+
sampling: z.ZodDefault<z.ZodEnum<{
|
|
39
|
+
linear: "linear";
|
|
40
|
+
nearest: "nearest";
|
|
41
|
+
}>>;
|
|
42
|
+
}, z.core.$strict>;
|
|
43
|
+
export type ImagePreparationSettings = z.infer<typeof imagePreparationSettings>;
|
|
44
|
+
export interface PreparedImage {
|
|
45
|
+
readonly bytes: Uint8Array;
|
|
46
|
+
readonly width: number;
|
|
47
|
+
readonly height: number;
|
|
48
|
+
readonly originalWidth: number;
|
|
49
|
+
readonly originalHeight: number;
|
|
50
|
+
readonly trim?: {
|
|
51
|
+
readonly sourceWidth: number;
|
|
52
|
+
readonly sourceHeight: number;
|
|
53
|
+
readonly x: number;
|
|
54
|
+
readonly y: number;
|
|
55
|
+
};
|
|
56
|
+
readonly frames?: readonly PreparedFrame[];
|
|
57
|
+
readonly baseline?: number;
|
|
58
|
+
readonly tiles?: readonly {
|
|
59
|
+
readonly mask: number;
|
|
60
|
+
readonly frame: PreparedFrame;
|
|
61
|
+
}[];
|
|
62
|
+
readonly lutSize?: number;
|
|
63
|
+
}
|
|
64
|
+
export interface PreparedFrame {
|
|
65
|
+
readonly x: number;
|
|
66
|
+
readonly y: number;
|
|
67
|
+
readonly width: number;
|
|
68
|
+
readonly height: number;
|
|
69
|
+
}
|
|
70
|
+
export declare function imagePreparationMetadata(settings: ImagePreparationSettings): NonNullable<import("@nodetool-ai/protocol").GameAssetBinding["preparation"]>;
|
|
71
|
+
/** Decode, transform and encode canonical PNG bytes before a digest is computed. */
|
|
72
|
+
export declare function prepareGameImage(bytes: Uint8Array, settings: ImagePreparationSettings): Promise<PreparedImage>;
|
|
73
|
+
//# sourceMappingURL=image-preparation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-preparation.d.ts","sourceRoot":"","sources":["../src/image-preparation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAmBwC,CAAC;AAC9E,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAEhF,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACxH,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;IAC3C,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAA;KAAE,EAAE,CAAC;IACrF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AACD,MAAM,WAAW,aAAa;IAAG,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AAE1H,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,wBAAwB,GAAG,WAAW,CAAC,OAAO,uBAAuB,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAC,CAGzJ;AAED,oFAAoF;AACpF,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,wBAAwB,GAAG,OAAO,CAAC,aAAa,CAAC,CA+DpH"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import sharp from "sharp";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { gameImagePreparation } from "@nodetool-ai/protocol";
|
|
4
|
+
import { prepareSheet, prepareTileset, prepareLut } from "./atlas-preparation.js";
|
|
5
|
+
const MAX_DIMENSION = 4096;
|
|
6
|
+
const dimension = z.number().int().min(1).max(MAX_DIMENSION);
|
|
7
|
+
export const imagePreparationSettings = gameImagePreparation.extend({
|
|
8
|
+
trimAlpha: z.boolean().default(false),
|
|
9
|
+
targetWidth: dimension.optional(),
|
|
10
|
+
targetHeight: dimension.optional(),
|
|
11
|
+
cropPolicy: z.enum(["cover", "contain", "stretch"]).optional(),
|
|
12
|
+
mirrorX: z.boolean().default(false),
|
|
13
|
+
mirrorY: z.boolean().default(false),
|
|
14
|
+
pivot: z.strictObject({ x: z.number().finite().min(0).max(1), y: z.number().finite().min(0).max(1) }).default({ x: 0.5, y: 0.5 }),
|
|
15
|
+
sampling: z.enum(["nearest", "linear"]).default("nearest")
|
|
16
|
+
}).refine((settings) => (settings.targetWidth === undefined) === (settings.targetHeight === undefined), "targetWidth and targetHeight must be set together")
|
|
17
|
+
.refine((settings) => !settings.cropPolicy || settings.targetWidth !== undefined, "cropPolicy needs targetWidth and targetHeight")
|
|
18
|
+
.refine((settings) => !(settings.trimAlpha && (settings.mirrorX || settings.mirrorY)), "alpha trimming and mirror tiling cannot be combined")
|
|
19
|
+
.refine((settings) => [settings.sheet, settings.tileset, settings.lut].filter(Boolean).length <= 1, "choose only one of sheet, tileset or lut")
|
|
20
|
+
.refine((settings) => !(settings.sheet || settings.tileset || settings.lut) ||
|
|
21
|
+
!(settings.trimAlpha || settings.targetWidth || settings.mirrorX || settings.mirrorY), "sheet, tileset and lut cannot be combined with single-image transforms");
|
|
22
|
+
export function imagePreparationMetadata(settings) {
|
|
23
|
+
const { pivot: _pivot, sampling: _sampling, ...metadata } = settings;
|
|
24
|
+
return metadata;
|
|
25
|
+
}
|
|
26
|
+
/** Decode, transform and encode canonical PNG bytes before a digest is computed. */
|
|
27
|
+
export async function prepareGameImage(bytes, settings) {
|
|
28
|
+
if (settings.lut) {
|
|
29
|
+
return prepareLut(settings.lut);
|
|
30
|
+
}
|
|
31
|
+
const metadata = await sharp(bytes, { failOn: "error", limitInputPixels: MAX_DIMENSION * MAX_DIMENSION }).metadata();
|
|
32
|
+
const originalWidth = metadata.width;
|
|
33
|
+
const originalHeight = metadata.height;
|
|
34
|
+
if (!originalWidth || !originalHeight || originalWidth > MAX_DIMENSION || originalHeight > MAX_DIMENSION) {
|
|
35
|
+
throw new Error("Game image has invalid dimensions");
|
|
36
|
+
}
|
|
37
|
+
if (settings.sheet) {
|
|
38
|
+
return prepareSheet(bytes, originalWidth, originalHeight, settings.sheet);
|
|
39
|
+
}
|
|
40
|
+
if (settings.tileset) {
|
|
41
|
+
return prepareTileset(bytes, originalWidth, originalHeight, settings.tileset, settings.sampling);
|
|
42
|
+
}
|
|
43
|
+
const resized = sharp(bytes, { failOn: "error", limitInputPixels: MAX_DIMENSION * MAX_DIMENSION }).ensureAlpha();
|
|
44
|
+
if (settings.targetWidth && settings.targetHeight) {
|
|
45
|
+
resized.resize(settings.targetWidth, settings.targetHeight, {
|
|
46
|
+
fit: settings.cropPolicy === "stretch" ? "fill" : settings.cropPolicy ?? "contain",
|
|
47
|
+
background: { r: 0, g: 0, b: 0, alpha: 0 },
|
|
48
|
+
kernel: settings.sampling === "nearest" ? "nearest" : "lanczos3"
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
const decoded = await resized.raw().toBuffer({ resolveWithObject: true });
|
|
52
|
+
const source = decoded.data;
|
|
53
|
+
const sourceWidth = decoded.info.width;
|
|
54
|
+
const sourceHeight = decoded.info.height;
|
|
55
|
+
let left = 0;
|
|
56
|
+
let top = 0;
|
|
57
|
+
let right = sourceWidth;
|
|
58
|
+
let bottom = sourceHeight;
|
|
59
|
+
if (settings.trimAlpha) {
|
|
60
|
+
left = sourceWidth;
|
|
61
|
+
top = sourceHeight;
|
|
62
|
+
right = 0;
|
|
63
|
+
bottom = 0;
|
|
64
|
+
for (let y = 0; y < sourceHeight; y += 1) {
|
|
65
|
+
for (let x = 0; x < sourceWidth; x += 1) {
|
|
66
|
+
if (source[(y * sourceWidth + x) * 4 + 3] === 0) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
left = Math.min(left, x);
|
|
70
|
+
top = Math.min(top, y);
|
|
71
|
+
right = Math.max(right, x + 1);
|
|
72
|
+
bottom = Math.max(bottom, y + 1);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (right === 0 || bottom === 0) {
|
|
76
|
+
throw new Error("Cannot trim a fully transparent game image");
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const contentWidth = right - left;
|
|
80
|
+
const contentHeight = bottom - top;
|
|
81
|
+
const width = contentWidth * (settings.mirrorX ? 2 : 1);
|
|
82
|
+
const height = contentHeight * (settings.mirrorY ? 2 : 1);
|
|
83
|
+
if (width > MAX_DIMENSION || height > MAX_DIMENSION) {
|
|
84
|
+
throw new Error("Prepared game image exceeds 4096 pixels per axis");
|
|
85
|
+
}
|
|
86
|
+
const output = Buffer.alloc(width * height * 4);
|
|
87
|
+
for (let y = 0; y < height; y += 1) {
|
|
88
|
+
const localY = y < contentHeight ? y : 2 * contentHeight - y - 1;
|
|
89
|
+
for (let x = 0; x < width; x += 1) {
|
|
90
|
+
const localX = x < contentWidth ? x : 2 * contentWidth - x - 1;
|
|
91
|
+
const sourceOffset = ((top + localY) * sourceWidth + left + localX) * 4;
|
|
92
|
+
source.copy(output, (y * width + x) * 4, sourceOffset, sourceOffset + 4);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const prepared = await sharp(output, { raw: { width, height, channels: 4 } }).png({ compressionLevel: 9, palette: false }).toBuffer();
|
|
96
|
+
const decodedPrepared = await sharp(prepared).metadata();
|
|
97
|
+
if (decodedPrepared.width !== width || decodedPrepared.height !== height) {
|
|
98
|
+
throw new Error("Prepared image dimensions changed during encoding");
|
|
99
|
+
}
|
|
100
|
+
const trimmed = left !== 0 || top !== 0 || contentWidth !== sourceWidth || contentHeight !== sourceHeight;
|
|
101
|
+
const result = { bytes: prepared, width, height, originalWidth, originalHeight };
|
|
102
|
+
if (trimmed) {
|
|
103
|
+
return { ...result, trim: { sourceWidth, sourceHeight, x: left, y: top } };
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=image-preparation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-preparation.js","sourceRoot":"","sources":["../src/image-preparation.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { LoadGameTemplateNode, SlotPromptNode, StageGameAssetsNode, GAME_TEMPLATE_NODES, LEGACY_GAME_NODE_DIAGNOSTIC } from "./nodes/game.js";
|
|
2
|
+
export { resolveFills, type ResolvedFills } from "./fills.js";
|
|
3
|
+
export { getNativeTemplate, listNativeTemplates, type NativeGameTemplate } from "./templates.js";
|
|
4
|
+
export { prepareGameImage, imagePreparationSettings, imagePreparationMetadata, type ImagePreparationSettings, type PreparedImage } from "./image-preparation.js";
|
|
5
|
+
export { gameFontFormat } from "./font-preparation.js";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,cAAc,EACd,mBAAmB,EACnB,mBAAmB,EACnB,2BAA2B,EAC5B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,KAAK,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACjG,OAAO,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,wBAAwB,EAAE,KAAK,wBAAwB,EAAE,KAAK,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACjK,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { LoadGameTemplateNode, SlotPromptNode, StageGameAssetsNode, GAME_TEMPLATE_NODES, LEGACY_GAME_NODE_DIAGNOSTIC } from "./nodes/game.js";
|
|
2
|
+
export { resolveFills } from "./fills.js";
|
|
3
|
+
export { getNativeTemplate, listNativeTemplates } from "./templates.js";
|
|
4
|
+
export { prepareGameImage, imagePreparationSettings, imagePreparationMetadata } from "./image-preparation.js";
|
|
5
|
+
export { gameFontFormat } from "./font-preparation.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,cAAc,EACd,mBAAmB,EACnB,mBAAmB,EACnB,2BAA2B,EAC5B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,YAAY,EAAsB,MAAM,YAAY,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAA2B,MAAM,gBAAgB,CAAC;AACjG,OAAO,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,wBAAwB,EAAqD,MAAM,wBAAwB,CAAC;AACjK,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { BaseNode } from "@nodetool-ai/node-sdk";
|
|
2
|
+
import { type Entity, type GameAssetBinding, type GameAssetManifest, type GameSlotSpec, type InputMode } from "@nodetool-ai/protocol";
|
|
3
|
+
import { type ProcessingContext } from "@nodetool-ai/runtime";
|
|
4
|
+
type LoadGameTemplateOutputs = {
|
|
5
|
+
manifest: GameAssetManifest;
|
|
6
|
+
slots: GameSlotSpec[];
|
|
7
|
+
slot: GameSlotSpec;
|
|
8
|
+
};
|
|
9
|
+
export declare class LoadGameTemplateNode extends BaseNode {
|
|
10
|
+
static readonly nodeType = "nodetool.game.LoadGameTemplate";
|
|
11
|
+
static readonly title = "Load Game Template";
|
|
12
|
+
static readonly description = "Read a native game template's asset slots for generation.";
|
|
13
|
+
static readonly metadataOutputTypes: {
|
|
14
|
+
manifest: string;
|
|
15
|
+
slots: string;
|
|
16
|
+
slot: string;
|
|
17
|
+
};
|
|
18
|
+
static readonly inlineFields: string[];
|
|
19
|
+
static readonly inputFields: string[];
|
|
20
|
+
static readonly inputMode: InputMode;
|
|
21
|
+
static readonly outputCorrelation: {
|
|
22
|
+
slot: {
|
|
23
|
+
kind: "iteration";
|
|
24
|
+
source: string;
|
|
25
|
+
group: string;
|
|
26
|
+
};
|
|
27
|
+
slots: {
|
|
28
|
+
kind: "single";
|
|
29
|
+
source: string;
|
|
30
|
+
};
|
|
31
|
+
manifest: {
|
|
32
|
+
kind: "single";
|
|
33
|
+
source: string;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
template: string;
|
|
37
|
+
process(): Promise<LoadGameTemplateOutputs>;
|
|
38
|
+
genProcess(): AsyncGenerator<Partial<LoadGameTemplateOutputs>>;
|
|
39
|
+
}
|
|
40
|
+
type SlotPromptOutputs = {
|
|
41
|
+
prompt: string;
|
|
42
|
+
width: number;
|
|
43
|
+
height: number;
|
|
44
|
+
kind: string;
|
|
45
|
+
checker: Record<string, unknown>;
|
|
46
|
+
seconds: number;
|
|
47
|
+
reference_images: NonNullable<Entity["reference_images"]>;
|
|
48
|
+
reference_asset_id: string;
|
|
49
|
+
};
|
|
50
|
+
export declare class SlotPromptNode extends BaseNode {
|
|
51
|
+
static readonly nodeType = "nodetool.game.SlotPrompt";
|
|
52
|
+
static readonly title = "Slot Prompt";
|
|
53
|
+
static readonly description = "Turn a native game asset slot into a generation prompt and checker properties.";
|
|
54
|
+
static readonly metadataOutputTypes: {
|
|
55
|
+
prompt: string;
|
|
56
|
+
width: string;
|
|
57
|
+
height: string;
|
|
58
|
+
kind: string;
|
|
59
|
+
checker: string;
|
|
60
|
+
seconds: string;
|
|
61
|
+
reference_images: string;
|
|
62
|
+
reference_asset_id: string;
|
|
63
|
+
};
|
|
64
|
+
static readonly inlineFields: string[];
|
|
65
|
+
static readonly inputFields: string[];
|
|
66
|
+
slot: unknown;
|
|
67
|
+
style: Entity | null;
|
|
68
|
+
cast: Entity[];
|
|
69
|
+
process(context?: ProcessingContext): Promise<SlotPromptOutputs>;
|
|
70
|
+
}
|
|
71
|
+
type StageGameAssetsOutputs = {
|
|
72
|
+
output: {
|
|
73
|
+
gameId: string;
|
|
74
|
+
bindings: Record<string, GameAssetBinding>;
|
|
75
|
+
};
|
|
76
|
+
bindings: Record<string, GameAssetBinding>;
|
|
77
|
+
paths: string[];
|
|
78
|
+
};
|
|
79
|
+
/** Stage validated media; a separate revision operation installs selected bindings. */
|
|
80
|
+
export declare class StageGameAssetsNode extends BaseNode {
|
|
81
|
+
static readonly nodeType = "nodetool.game.StageGameAssets";
|
|
82
|
+
static readonly title = "Stage Game Assets";
|
|
83
|
+
static readonly description = "Validate generated media and stage candidate bindings for a native game.";
|
|
84
|
+
static readonly metadataOutputTypes: {
|
|
85
|
+
output: string;
|
|
86
|
+
bindings: string;
|
|
87
|
+
paths: string;
|
|
88
|
+
};
|
|
89
|
+
static readonly inlineFields: string[];
|
|
90
|
+
static readonly inputFields: string[];
|
|
91
|
+
template: string;
|
|
92
|
+
game_id: string;
|
|
93
|
+
fills: unknown[];
|
|
94
|
+
preparation: Record<string, unknown>;
|
|
95
|
+
reference_asset_id: string;
|
|
96
|
+
fonts: Record<string, string>;
|
|
97
|
+
process(context?: ProcessingContext): Promise<StageGameAssetsOutputs>;
|
|
98
|
+
}
|
|
99
|
+
export declare const LEGACY_GAME_NODE_DIAGNOSTIC = "ExportGodotProject was removed. Create a native game, reconnect surviving asset checkers to StageGameAssets, then install selected bindings into a game revision. GDScript and Godot scenes require manual reconstruction.";
|
|
100
|
+
export declare const GAME_TEMPLATE_NODES: (typeof LoadGameTemplateNode | typeof SlotPromptNode | typeof StageGameAssetsNode)[];
|
|
101
|
+
export {};
|
|
102
|
+
//# sourceMappingURL=game.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"game.d.ts","sourceRoot":"","sources":["../../src/nodes/game.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { createHash } from "node:crypto";
|
|
8
|
+
import { BaseNode, isString, prop } from "@nodetool-ai/node-sdk";
|
|
9
|
+
import { checkSlotFill, gameSlotSpec, LEGACY_GAME_EXPORT_DIAGNOSTIC, slotPrompt } from "@nodetool-ai/protocol";
|
|
10
|
+
import { loadMediaRefBytes, resolveEntities } from "@nodetool-ai/runtime";
|
|
11
|
+
import { tagAsServer } from "@nodetool-ai/nodes-utils";
|
|
12
|
+
import { resolveFills } from "../fills.js";
|
|
13
|
+
import { getNativeTemplate, listNativeTemplates } from "../templates.js";
|
|
14
|
+
import { imagePreparationMetadata, imagePreparationSettings, prepareGameImage } from "../image-preparation.js";
|
|
15
|
+
import { gameFontFormat } from "../font-preparation.js";
|
|
16
|
+
const TEMPLATE_IDS = listNativeTemplates().map((template) => template.id);
|
|
17
|
+
const trimmed = (value) => isString(value) ? value.trim() : "";
|
|
18
|
+
export class LoadGameTemplateNode extends BaseNode {
|
|
19
|
+
static nodeType = "nodetool.game.LoadGameTemplate";
|
|
20
|
+
static title = "Load Game Template";
|
|
21
|
+
static description = "Read a native game template's asset slots for generation.";
|
|
22
|
+
static metadataOutputTypes = { manifest: "dict", slots: "list[game_slot]", slot: "game_slot" };
|
|
23
|
+
static inlineFields = ["template"];
|
|
24
|
+
static inputFields = [];
|
|
25
|
+
static inputMode = "buffered";
|
|
26
|
+
static outputCorrelation = {
|
|
27
|
+
slot: { kind: "iteration", source: "__execution__", group: "slots" },
|
|
28
|
+
slots: { kind: "single", source: "__execution__" },
|
|
29
|
+
manifest: { kind: "single", source: "__execution__" }
|
|
30
|
+
};
|
|
31
|
+
async process() {
|
|
32
|
+
const manifest = getNativeTemplate(trimmed(this.template)).manifest;
|
|
33
|
+
return { manifest, slots: manifest.slots, slot: manifest.slots[0] };
|
|
34
|
+
}
|
|
35
|
+
async *genProcess() {
|
|
36
|
+
const manifest = getNativeTemplate(trimmed(this.template)).manifest;
|
|
37
|
+
for (const slot of manifest.slots)
|
|
38
|
+
yield { slot };
|
|
39
|
+
yield { manifest, slots: manifest.slots };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
__decorate([
|
|
43
|
+
prop({ type: "str", default: "topdown", title: "Template", values: TEMPLATE_IDS })
|
|
44
|
+
], LoadGameTemplateNode.prototype, "template", void 0);
|
|
45
|
+
export class SlotPromptNode extends BaseNode {
|
|
46
|
+
static nodeType = "nodetool.game.SlotPrompt";
|
|
47
|
+
static title = "Slot Prompt";
|
|
48
|
+
static description = "Turn a native game asset slot into a generation prompt and checker properties.";
|
|
49
|
+
static metadataOutputTypes = { prompt: "str", width: "int", height: "int", kind: "str", checker: "dict", seconds: "float",
|
|
50
|
+
reference_images: "list[image]", reference_asset_id: "str" };
|
|
51
|
+
static inlineFields = [];
|
|
52
|
+
static inputFields = ["slot", "style", "cast"];
|
|
53
|
+
async process(context) {
|
|
54
|
+
const parsed = gameSlotSpec.safeParse(this.slot);
|
|
55
|
+
if (!parsed.success)
|
|
56
|
+
throw new Error(`Slot Prompt: invalid game slot: ${parsed.error.message}`);
|
|
57
|
+
const slot = parsed.data;
|
|
58
|
+
const [style] = await resolveEntities(this.style ? [this.style] : [], context);
|
|
59
|
+
const cast = await resolveEntities(Array.isArray(this.cast) ? this.cast : [], context);
|
|
60
|
+
const result = slotPrompt(slot, style ?? null, cast);
|
|
61
|
+
return { prompt: result.prompt, width: result.width, height: result.height, kind: slot.kind, checker: result.checker,
|
|
62
|
+
seconds: slot.kind === "sfx" || slot.kind === "music" ? slot.seconds : 0,
|
|
63
|
+
reference_images: result.referenceImages, reference_asset_id: result.referenceAssetId };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
__decorate([
|
|
67
|
+
prop({ type: "game_slot", default: null, title: "Slot" })
|
|
68
|
+
], SlotPromptNode.prototype, "slot", void 0);
|
|
69
|
+
__decorate([
|
|
70
|
+
prop({ type: "entity", default: null, title: "Style" })
|
|
71
|
+
], SlotPromptNode.prototype, "style", void 0);
|
|
72
|
+
__decorate([
|
|
73
|
+
prop({ type: "list[entity]", default: [], title: "Cast" })
|
|
74
|
+
], SlotPromptNode.prototype, "cast", void 0);
|
|
75
|
+
/** Stage validated media; a separate revision operation installs selected bindings. */
|
|
76
|
+
export class StageGameAssetsNode extends BaseNode {
|
|
77
|
+
static nodeType = "nodetool.game.StageGameAssets";
|
|
78
|
+
static title = "Stage Game Assets";
|
|
79
|
+
static description = "Validate generated media and stage candidate bindings for a native game.";
|
|
80
|
+
static metadataOutputTypes = { output: "dict", bindings: "dict", paths: "list[str]" };
|
|
81
|
+
static inlineFields = ["template", "game_id"];
|
|
82
|
+
static inputFields = ["fills", "game_id", "preparation", "reference_asset_id", "fonts"];
|
|
83
|
+
async process(context) {
|
|
84
|
+
if (!context?.workspace)
|
|
85
|
+
throw new Error("Stage Game Assets requires a project workspace");
|
|
86
|
+
const gameId = trimmed(this.game_id);
|
|
87
|
+
if (!/^[a-f0-9]{32}$/.test(gameId))
|
|
88
|
+
throw new Error("Stage Game Assets requires a full 32-character game ID");
|
|
89
|
+
const manifest = getNativeTemplate(trimmed(this.template)).manifest;
|
|
90
|
+
const resolved = resolveFills(manifest.template, Array.isArray(this.fills) ? this.fills : []);
|
|
91
|
+
const specs = new Map(manifest.slots.map((slot) => [slot.id, slot]));
|
|
92
|
+
for (const slotId of Object.keys(this.preparation ?? {})) {
|
|
93
|
+
if (!specs.has(slotId))
|
|
94
|
+
throw new Error(`Unknown preparation slot ${slotId}`);
|
|
95
|
+
}
|
|
96
|
+
const bindings = {};
|
|
97
|
+
const paths = [];
|
|
98
|
+
for (const slot of resolved.manifest.slots) {
|
|
99
|
+
const spec = specs.get(slot.slot_id);
|
|
100
|
+
if (!spec)
|
|
101
|
+
throw new Error(`Unknown template slot ${slot.slot_id}`);
|
|
102
|
+
const problems = checkSlotFill(spec, slot.fill);
|
|
103
|
+
if (problems.length > 0)
|
|
104
|
+
throw new Error(`Invalid fill for ${slot.slot_id}: ${problems.join("; ")}`);
|
|
105
|
+
if (bindings[slot.slot_id])
|
|
106
|
+
throw new Error(`Slot ${slot.slot_id} is filled twice`);
|
|
107
|
+
const ref = resolved.refs.get(slot.asset.asset_id);
|
|
108
|
+
if (!ref)
|
|
109
|
+
throw new Error(`Missing media reference for ${slot.slot_id}`);
|
|
110
|
+
const sourceBytes = await loadMediaRefBytes(ref, context);
|
|
111
|
+
if (!sourceBytes || sourceBytes.length === 0)
|
|
112
|
+
throw new Error(`Cannot read media bytes for ${slot.slot_id}`);
|
|
113
|
+
const extension = slot.fill.kind === "sfx" || slot.fill.kind === "music" ? "wav" : "png";
|
|
114
|
+
const requested = this.preparation?.[slot.slot_id];
|
|
115
|
+
if (extension === "wav" && requested !== undefined)
|
|
116
|
+
throw new Error(`Preparation is only supported for images: ${slot.slot_id}`);
|
|
117
|
+
const parsed = extension === "png" ? imagePreparationSettings.safeParse(requested ?? {}) : null;
|
|
118
|
+
if (parsed && !parsed.success)
|
|
119
|
+
throw new Error(`Invalid preparation for ${slot.slot_id}: ${parsed.error.message}`);
|
|
120
|
+
const settings = parsed?.success ? parsed.data : null;
|
|
121
|
+
if (settings && slot.fill.kind !== "image" &&
|
|
122
|
+
(settings.trimAlpha || settings.targetWidth !== undefined || settings.mirrorX || settings.mirrorY || settings.tileset || settings.lut)) {
|
|
123
|
+
throw new Error(`Only single-image slots support trimming, resizing, mirror tiling, tileset creation and LUT creation: ${slot.slot_id}`);
|
|
124
|
+
}
|
|
125
|
+
if (settings?.sheet && (slot.fill.kind !== "spritesheet" || settings.sheet.cols !== slot.fill.columns || settings.sheet.rows !== slot.fill.rows)) {
|
|
126
|
+
throw new Error(`Sheet preparation must match the checked spritesheet grid: ${slot.slot_id}`);
|
|
127
|
+
}
|
|
128
|
+
const expectedWidth = slot.fill.kind === "spritesheet" || slot.fill.kind === "tileset" ? slot.fill.columns * slot.fill.cell[0] : slot.fill.kind === "image" ? slot.fill.size[0] : 1;
|
|
129
|
+
const expectedHeight = slot.fill.kind === "spritesheet" || slot.fill.kind === "tileset" ? slot.fill.rows * slot.fill.cell[1] : slot.fill.kind === "image" ? slot.fill.size[1] : 1;
|
|
130
|
+
const prepared = settings ? await prepareGameImage(sourceBytes, settings) : null;
|
|
131
|
+
if (prepared && (prepared.originalWidth !== expectedWidth || prepared.originalHeight !== expectedHeight)) {
|
|
132
|
+
throw new Error(`Image dimensions for ${slot.slot_id} are ${prepared.originalWidth}x${prepared.originalHeight}, expected ${expectedWidth}x${expectedHeight}`);
|
|
133
|
+
}
|
|
134
|
+
const bytes = prepared?.bytes ?? sourceBytes;
|
|
135
|
+
const digest = createHash("sha256").update(bytes).digest("hex");
|
|
136
|
+
const path = `games/${gameId}/assets/${digest}.${extension}`;
|
|
137
|
+
await context.workspace.write(path, bytes);
|
|
138
|
+
paths.push(path);
|
|
139
|
+
const referenceAssetId = trimmed(this.reference_asset_id);
|
|
140
|
+
const binding = { assetId: slot.asset.asset_id, digest, mediaKind: extension === "wav" ? "audio" : "image",
|
|
141
|
+
width: prepared?.width ?? expectedWidth, height: prepared?.height ?? expectedHeight,
|
|
142
|
+
pivot: settings?.pivot ?? { x: 0.5, y: 0.5 }, sampling: settings?.sampling ?? "nearest",
|
|
143
|
+
provenance: `template:${manifest.template}:${slot.slot_id}${referenceAssetId ? `:style:${referenceAssetId}` : ""}` };
|
|
144
|
+
if (prepared?.baseline !== undefined && prepared.frames?.[0]) {
|
|
145
|
+
binding.pivot = { x: 0.5, y: (prepared.baseline + 1) / prepared.frames[0].height };
|
|
146
|
+
}
|
|
147
|
+
if (settings && requested !== undefined) {
|
|
148
|
+
binding.preparation = imagePreparationMetadata(settings);
|
|
149
|
+
}
|
|
150
|
+
if (prepared?.trim)
|
|
151
|
+
binding.trim = prepared.trim;
|
|
152
|
+
if (prepared && requested !== undefined)
|
|
153
|
+
binding.originalDimensions = { width: prepared.originalWidth, height: prepared.originalHeight };
|
|
154
|
+
if (referenceAssetId)
|
|
155
|
+
binding.referenceAssetId = referenceAssetId;
|
|
156
|
+
bindings[slot.slot_id] = binding;
|
|
157
|
+
}
|
|
158
|
+
for (const [fontId, uri] of Object.entries(this.fonts ?? {})) {
|
|
159
|
+
if (!/^[a-z][a-z0-9_.-]*$/.test(fontId) || typeof uri !== "string" || !uri.trim()) {
|
|
160
|
+
throw new Error(`Invalid font source for ${fontId}`);
|
|
161
|
+
}
|
|
162
|
+
if (bindings[fontId])
|
|
163
|
+
throw new Error(`Font ID conflicts with a template slot: ${fontId}`);
|
|
164
|
+
const bytes = await loadMediaRefBytes({ type: "image", uri }, context);
|
|
165
|
+
if (!bytes || bytes.length < 4)
|
|
166
|
+
throw new Error(`Cannot read font bytes for ${fontId}`);
|
|
167
|
+
const fontFormat = gameFontFormat(bytes);
|
|
168
|
+
if (!fontFormat)
|
|
169
|
+
throw new Error(`Font ${fontId} must be a TrueType or OpenType font`);
|
|
170
|
+
const digest = createHash("sha256").update(bytes).digest("hex");
|
|
171
|
+
const path = `games/${gameId}/assets/${digest}.${fontFormat}`;
|
|
172
|
+
await context.workspace.write(path, bytes);
|
|
173
|
+
paths.push(path);
|
|
174
|
+
bindings[fontId] = { assetId: uri, digest, mediaKind: "font", fontFormat, width: 1, height: 1,
|
|
175
|
+
pivot: { x: 0.5, y: 0.5 }, sampling: "nearest", required: true,
|
|
176
|
+
provenance: `font:${fontId}` };
|
|
177
|
+
}
|
|
178
|
+
return { output: { gameId, bindings }, bindings, paths };
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
__decorate([
|
|
182
|
+
prop({ type: "str", default: "topdown", title: "Template", values: TEMPLATE_IDS })
|
|
183
|
+
], StageGameAssetsNode.prototype, "template", void 0);
|
|
184
|
+
__decorate([
|
|
185
|
+
prop({ type: "str", default: "", title: "Game ID" })
|
|
186
|
+
], StageGameAssetsNode.prototype, "game_id", void 0);
|
|
187
|
+
__decorate([
|
|
188
|
+
prop({ type: "list[union[image,audio]]", default: [], title: "Checked assets" })
|
|
189
|
+
], StageGameAssetsNode.prototype, "fills", void 0);
|
|
190
|
+
__decorate([
|
|
191
|
+
prop({ type: "dict", default: {}, title: "Preparation by slot" })
|
|
192
|
+
], StageGameAssetsNode.prototype, "preparation", void 0);
|
|
193
|
+
__decorate([
|
|
194
|
+
prop({ type: "str", default: "", title: "Shared style image asset ID" })
|
|
195
|
+
], StageGameAssetsNode.prototype, "reference_asset_id", void 0);
|
|
196
|
+
__decorate([
|
|
197
|
+
prop({ type: "dict", default: {}, title: "Font asset URIs by logical ID" })
|
|
198
|
+
], StageGameAssetsNode.prototype, "fonts", void 0);
|
|
199
|
+
export const LEGACY_GAME_NODE_DIAGNOSTIC = LEGACY_GAME_EXPORT_DIAGNOSTIC;
|
|
200
|
+
export const GAME_TEMPLATE_NODES = tagAsServer([LoadGameTemplateNode, SlotPromptNode, StageGameAssetsNode]);
|
|
201
|
+
//# sourceMappingURL=game.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"game.js","sourceRoot":"","sources":["../../src/nodes/game.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type GameAssetManifest } from "@nodetool-ai/protocol";
|
|
2
|
+
export interface NativeGameTemplate {
|
|
3
|
+
readonly id: string;
|
|
4
|
+
readonly name: string;
|
|
5
|
+
readonly manifest: GameAssetManifest;
|
|
6
|
+
}
|
|
7
|
+
export declare function listNativeTemplates(): readonly NativeGameTemplate[];
|
|
8
|
+
export declare function getNativeTemplate(id: string): NativeGameTemplate;
|
|
9
|
+
//# sourceMappingURL=templates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../src/templates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAElF,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;CACtC;AAkBD,wBAAgB,mBAAmB,IAAI,SAAS,kBAAkB,EAAE,CAEnE;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,kBAAkB,CAGhE"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { gameAssetManifest } from "@nodetool-ai/protocol";
|
|
2
|
+
const TOP_DOWN = {
|
|
3
|
+
id: "topdown",
|
|
4
|
+
name: "Top-down room",
|
|
5
|
+
manifest: gameAssetManifest.parse({
|
|
6
|
+
version: 1,
|
|
7
|
+
template: "topdown",
|
|
8
|
+
engineVersion: "1",
|
|
9
|
+
slots: [
|
|
10
|
+
{ id: "player", kind: "spritesheet", cell: [32, 32], animations: { idle: 1, walk: 4 }, prompt: "top-down player character" },
|
|
11
|
+
{ id: "wall", kind: "tileset", cell: [32, 32], count: 1, prompt: "top-down stone wall tile" },
|
|
12
|
+
{ id: "gem", kind: "spritesheet", cell: [32, 32], animations: { idle: 1 }, prompt: "bright collectible gem" },
|
|
13
|
+
{ id: "sfx.collect", kind: "sfx", seconds: 0.4, prompt: "short collection chime" }
|
|
14
|
+
]
|
|
15
|
+
})
|
|
16
|
+
};
|
|
17
|
+
export function listNativeTemplates() {
|
|
18
|
+
return [TOP_DOWN];
|
|
19
|
+
}
|
|
20
|
+
export function getNativeTemplate(id) {
|
|
21
|
+
if (id === TOP_DOWN.id)
|
|
22
|
+
return TOP_DOWN;
|
|
23
|
+
throw new Error(`Unknown native game template ${id}. Available: ${TOP_DOWN.id}`);
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=templates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../src/templates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAA0B,MAAM,uBAAuB,CAAC;AAQlF,MAAM,QAAQ,GAAuB;IACnC,EAAE,EAAE,SAAS;IACb,IAAI,EAAE,eAAe;IACrB,QAAQ,EAAE,iBAAiB,CAAC,KAAK,CAAC;QAChC,OAAO,EAAE,CAAC;QACV,QAAQ,EAAE,SAAS;QACnB,aAAa,EAAE,GAAG;QAClB,KAAK,EAAE;YACL,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,2BAA2B,EAAE;YAC5H,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,0BAA0B,EAAE;YAC7F,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,wBAAwB,EAAE;YAC7G,EAAE,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,wBAAwB,EAAE;SACnF;KACF,CAAC;CACH,CAAC;AAEF,MAAM,UAAU,mBAAmB;IACjC,OAAO,CAAC,QAAQ,CAAC,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,EAAU;IAC1C,IAAI,EAAE,KAAK,QAAQ,CAAC,EAAE;QAAE,OAAO,QAAQ,CAAC;IACxC,MAAM,IAAI,KAAK,CAAC,gCAAgC,EAAE,gBAAgB,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;AACnF,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nodetool-ai/game-nodes",
|
|
3
|
+
"version": "0.8.1",
|
|
4
|
+
"description": "NodeTool native game asset generation and staging nodes",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=22.0.0"
|
|
8
|
+
},
|
|
9
|
+
"main": "dist/index.js",
|
|
10
|
+
"types": "dist/index.d.ts",
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "node ../../scripts/build-typescript-workspace.mjs",
|
|
13
|
+
"test": "node ../../scripts/run-vitest.mjs run",
|
|
14
|
+
"test:watch": "node ../../scripts/run-vitest.mjs",
|
|
15
|
+
"lint": "node ../../scripts/run-tsc.mjs --noEmit"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@nodetool-ai/node-sdk": "^0.8.1",
|
|
19
|
+
"@nodetool-ai/nodes-utils": "^0.8.1",
|
|
20
|
+
"@nodetool-ai/protocol": "^0.8.1",
|
|
21
|
+
"@nodetool-ai/runtime": "^0.8.1",
|
|
22
|
+
"sharp": "^0.35.3"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@nodetool-ai/audio-nodes": "*",
|
|
26
|
+
"@nodetool-ai/image-nodes": "*",
|
|
27
|
+
"@nodetool-ai/storage": "*",
|
|
28
|
+
"@types/node": "^22.0.0",
|
|
29
|
+
"typescript": "npm:@typescript/typescript6@6.0.2",
|
|
30
|
+
"vitest": "^5.0.1"
|
|
31
|
+
},
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"import": "./dist/index.js",
|
|
36
|
+
"default": "./dist/index.js"
|
|
37
|
+
},
|
|
38
|
+
"./nodes/*": {
|
|
39
|
+
"types": "./dist/nodes/*.d.ts",
|
|
40
|
+
"import": "./dist/nodes/*.js",
|
|
41
|
+
"default": "./dist/nodes/*.js"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"files": [
|
|
46
|
+
"dist",
|
|
47
|
+
"README.md"
|
|
48
|
+
],
|
|
49
|
+
"repository": {
|
|
50
|
+
"type": "git",
|
|
51
|
+
"url": "https://github.com/nodetool-ai/nodetool.git",
|
|
52
|
+
"directory": "packages/game-nodes"
|
|
53
|
+
},
|
|
54
|
+
"homepage": "https://nodetool.ai",
|
|
55
|
+
"bugs": {
|
|
56
|
+
"url": "https://github.com/nodetool-ai/nodetool/issues"
|
|
57
|
+
},
|
|
58
|
+
"publishConfig": {
|
|
59
|
+
"access": "public"
|
|
60
|
+
},
|
|
61
|
+
"keywords": [
|
|
62
|
+
"nodetool",
|
|
63
|
+
"game",
|
|
64
|
+
"workflow",
|
|
65
|
+
"typescript"
|
|
66
|
+
]
|
|
67
|
+
}
|