@debuffjp/cli 0.0.0-stage → 0.1.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 (81) hide show
  1. package/README.md +63 -2
  2. package/bin/debuff.js +3 -0
  3. package/client.d.ts +3 -0
  4. package/dist/agent-link.d.ts +28 -0
  5. package/dist/agent-link.d.ts.map +1 -0
  6. package/dist/agent-link.js +122 -0
  7. package/dist/agent-link.js.map +1 -0
  8. package/dist/assets/atlas.d.ts +58 -0
  9. package/dist/assets/atlas.d.ts.map +1 -0
  10. package/dist/assets/atlas.js +164 -0
  11. package/dist/assets/atlas.js.map +1 -0
  12. package/dist/assets/builtin.d.ts +5 -0
  13. package/dist/assets/builtin.d.ts.map +1 -0
  14. package/dist/assets/builtin.js +47 -0
  15. package/dist/assets/builtin.js.map +1 -0
  16. package/dist/assets/command.d.ts +4 -0
  17. package/dist/assets/command.d.ts.map +1 -0
  18. package/dist/assets/command.js +35 -0
  19. package/dist/assets/command.js.map +1 -0
  20. package/dist/assets/compile.d.ts +29 -0
  21. package/dist/assets/compile.d.ts.map +1 -0
  22. package/dist/assets/compile.js +209 -0
  23. package/dist/assets/compile.js.map +1 -0
  24. package/dist/assets/index.d.ts +5 -0
  25. package/dist/assets/index.d.ts.map +1 -0
  26. package/dist/assets/index.js +5 -0
  27. package/dist/assets/index.js.map +1 -0
  28. package/dist/cli.d.ts +3 -0
  29. package/dist/cli.d.ts.map +1 -0
  30. package/dist/cli.js +212 -0
  31. package/dist/cli.js.map +1 -0
  32. package/dist/config.d.ts +24 -0
  33. package/dist/config.d.ts.map +1 -0
  34. package/dist/config.js +53 -0
  35. package/dist/config.js.map +1 -0
  36. package/dist/index.d.ts +11 -0
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.js +10 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/inspect.d.ts +35 -0
  41. package/dist/inspect.d.ts.map +1 -0
  42. package/dist/inspect.js +37 -0
  43. package/dist/inspect.js.map +1 -0
  44. package/dist/plugin.d.ts +146 -0
  45. package/dist/plugin.d.ts.map +1 -0
  46. package/dist/plugin.js +2 -0
  47. package/dist/plugin.js.map +1 -0
  48. package/dist/report.d.ts +26 -0
  49. package/dist/report.d.ts.map +1 -0
  50. package/dist/report.js +80 -0
  51. package/dist/report.js.map +1 -0
  52. package/dist/scenario/browser.d.ts +6 -0
  53. package/dist/scenario/browser.d.ts.map +1 -0
  54. package/dist/scenario/browser.js +47 -0
  55. package/dist/scenario/browser.js.map +1 -0
  56. package/dist/scenario/index.d.ts +5 -0
  57. package/dist/scenario/index.d.ts.map +1 -0
  58. package/dist/scenario/index.js +4 -0
  59. package/dist/scenario/index.js.map +1 -0
  60. package/dist/scenario/run.d.ts +12 -0
  61. package/dist/scenario/run.d.ts.map +1 -0
  62. package/dist/scenario/run.js +230 -0
  63. package/dist/scenario/run.js.map +1 -0
  64. package/dist/scenario/schema.d.ts +8 -0
  65. package/dist/scenario/schema.d.ts.map +1 -0
  66. package/dist/scenario/schema.js +23 -0
  67. package/dist/scenario/schema.js.map +1 -0
  68. package/dist/scenario/types.d.ts +96 -0
  69. package/dist/scenario/types.d.ts.map +1 -0
  70. package/dist/scenario/types.js +2 -0
  71. package/dist/scenario/types.js.map +1 -0
  72. package/dist/vite-plugin.d.ts +18 -0
  73. package/dist/vite-plugin.d.ts.map +1 -0
  74. package/dist/vite-plugin.js +122 -0
  75. package/dist/vite-plugin.js.map +1 -0
  76. package/dist/vite.d.ts +13 -0
  77. package/dist/vite.d.ts.map +1 -0
  78. package/dist/vite.js +24 -0
  79. package/dist/vite.js.map +1 -0
  80. package/package.json +63 -4
  81. package/schema/scenario.schema.json +111 -0
package/README.md CHANGED
@@ -1,3 +1,64 @@
1
- # Temporary Holding Version
1
+ # @debuffjp/cli
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The `debuff` command: dev server, production builds with size reports, asset manifests, browser scenarios and project inspection. Built on Vite.
4
+
5
+ ```bash
6
+ npm install -D @debuffjp/cli
7
+ npx debuff --help
8
+ ```
9
+
10
+ | Command | What it does |
11
+ | --- | --- |
12
+ | `debuff create [dir]` | Scaffold a game (same as `npm create debuff`) |
13
+ | `debuff dev [--port] [--host]` | Dev server with hot reload; regenerates the asset manifest on change |
14
+ | `debuff build [--sourcemap]` | Production build, then a raw/gzip/brotli report. Fails if dev-only code leaks |
15
+ | `debuff report` | Size report for an existing `dist/` |
16
+ | `debuff assets` | Run the asset pipeline: list every asset, its importer and size, plus unused and generated files |
17
+ | `debuff scenario [files] [--update] [--strict]` | Run `scenarios/*.json` in headless Chrome/Edge |
18
+ | `debuff inspect` | JSON summary of the project |
19
+
20
+ Add `--json` for machine-readable output and `--root <dir>` to target another project.
21
+
22
+ ## Scenarios
23
+
24
+ ```json
25
+ {
26
+ "$schema": "../node_modules/@debuffjp/cli/schema/scenario.schema.json",
27
+ "steps": [
28
+ { "press": "ArrowRight" },
29
+ { "wait": 30 },
30
+ { "expect": { "state.player.x": { "gt": 200 } } },
31
+ { "set": { "player.speed": 400 } },
32
+ { "capture": "after-move" }
33
+ ]
34
+ }
35
+ ```
36
+
37
+ Time advances only through `wait` steps, so runs are deterministic. Captures are compared against per-platform baselines in `scenarios/__baselines__/`. A missing baseline is recorded unless you pass `--strict`. Set `DEBUFF_BROWSER` to use a specific Chromium build.
38
+
39
+ ## Programmatic use
40
+
41
+ ```ts
42
+ import { buildReport, compileAssets, runScenarios } from "@debuffjp/cli";
43
+ ```
44
+
45
+ ## Assets and plugins
46
+
47
+ Put source assets in `assets/`. The pipeline builds an in-memory manifest (`/assets/manifest.json`). Only files the manifest references are served in dev and emitted in builds, and sources are never modified.
48
+
49
+ Add tooling plugins in `debuff.config.ts`:
50
+
51
+ ```ts
52
+ import { defineConfig } from "@debuffjp/cli";
53
+
54
+ export default defineConfig({
55
+ plugins: [
56
+ {
57
+ name: "maps",
58
+ apiVersion: 1,
59
+ // Any language: SourceFile JSON on stdin, ImportResult JSON on stdout.
60
+ assets: [{ name: "maps", extensions: [".map"], command: ["python", "tools/import_map.py"] }],
61
+ },
62
+ ],
63
+ });
64
+ ```
package/bin/debuff.js ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ // Committed shim so npm can link the bin before dist/ is built.
3
+ import "../dist/cli.js";
package/client.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ // Ambient types for game code built by the debuff CLI (import.meta.env, asset imports).
2
+ // Add to tsconfig: "types": ["@debuffjp/cli/client"]
3
+ /// <reference types="vite/client" />
@@ -0,0 +1,28 @@
1
+ import type { ViteDevServer } from "vite";
2
+ /** Endpoints shared with `@debuffjp/dev` (page side) and `@debuffjp/mcp` (agent side). */
3
+ export declare const AGENT_PATHS: {
4
+ readonly events: "/__debuff/agent/events";
5
+ readonly attach: "/__debuff/agent/attach";
6
+ readonly result: "/__debuff/agent/result";
7
+ readonly rpc: "/__debuff/agent/rpc";
8
+ readonly status: "/__debuff/agent/status";
9
+ };
10
+ /** Written while `debuff dev` runs, so tools can find the live game. */
11
+ export declare const DEV_SERVER_FILE = ".debuff/dev-server.json";
12
+ export interface DevServerInfo {
13
+ url: string;
14
+ pid: number;
15
+ }
16
+ export interface AgentStatus {
17
+ /** Open game pages listening for agent commands. */
18
+ pages: number;
19
+ /** Agents currently attached (holding an attach connection). */
20
+ agents: number;
21
+ }
22
+ /**
23
+ * Agent link (server side): relays dev-hook calls from tools to the game open in the developer's
24
+ * browser. Pages subscribe over Server-Sent Events; a tool POSTs `{ method, args }` to the RPC endpoint,
25
+ * the newest page runs it and POSTs the result back. Dev server only, localhost only.
26
+ */
27
+ export declare function attachAgentLink(server: ViteDevServer, root: string): void;
28
+ //# sourceMappingURL=agent-link.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-link.d.ts","sourceRoot":"","sources":["../src/agent-link.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AAE1C,0FAA0F;AAC1F,eAAO,MAAM,WAAW;aACtB,MAAM,EAAE,wBAAwB;aAChC,MAAM,EAAE,wBAAwB;aAChC,MAAM,EAAE,wBAAwB;aAChC,GAAG,EAAE,qBAAqB;aAC1B,MAAM,EAAE,wBAAwB;CACxB,CAAC;AAEX,wEAAwE;AACxE,eAAO,MAAM,eAAe,4BAA4B,CAAC;AAEzD,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,WAAW;IAC1B,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,MAAM,EAAE,MAAM,CAAC;CAChB;AAOD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAqFzE"}
@@ -0,0 +1,122 @@
1
+ import { mkdirSync, rmSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ /** Endpoints shared with `@debuffjp/dev` (page side) and `@debuffjp/mcp` (agent side). */
4
+ export const AGENT_PATHS = {
5
+ events: "/__debuff/agent/events",
6
+ attach: "/__debuff/agent/attach",
7
+ result: "/__debuff/agent/result",
8
+ rpc: "/__debuff/agent/rpc",
9
+ status: "/__debuff/agent/status",
10
+ };
11
+ /** Written while `debuff dev` runs, so tools can find the live game. */
12
+ export const DEV_SERVER_FILE = ".debuff/dev-server.json";
13
+ /**
14
+ * Agent link (server side): relays dev-hook calls from tools to the game open in the developer's
15
+ * browser. Pages subscribe over Server-Sent Events; a tool POSTs `{ method, args }` to the RPC endpoint,
16
+ * the newest page runs it and POSTs the result back. Dev server only, localhost only.
17
+ */
18
+ export function attachAgentLink(server, root) {
19
+ const pages = [];
20
+ const pending = new Map();
21
+ let agents = 0;
22
+ const announce = () => {
23
+ for (const page of pages)
24
+ send(page, "presence", { agents });
25
+ };
26
+ let nextId = 1;
27
+ const send = (res, event, data) => res.write(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`);
28
+ server.middlewares.use(async (req, res, next) => {
29
+ const url = req.url?.split("?")[0];
30
+ if (!url?.startsWith("/__debuff/agent/"))
31
+ return next();
32
+ try {
33
+ if (url === AGENT_PATHS.events && req.method === "GET") {
34
+ res.writeHead(200, { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", Connection: "keep-alive" });
35
+ res.write(": debuff agent link\n\n");
36
+ pages.push(res);
37
+ send(res, "presence", { agents });
38
+ const keepAlive = setInterval(() => res.write(": ping\n\n"), 15_000);
39
+ req.on("close", () => {
40
+ clearInterval(keepAlive);
41
+ pages.splice(pages.indexOf(res), 1);
42
+ });
43
+ return;
44
+ }
45
+ if (url === AGENT_PATHS.status && req.method === "GET")
46
+ return reply(res, 200, { pages: pages.length, agents });
47
+ if (url === AGENT_PATHS.attach && req.method === "GET") {
48
+ // Held open by an agent for as long as it is attached; closing it (or the agent dying) detaches.
49
+ res.writeHead(200, { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", Connection: "keep-alive" });
50
+ res.write(": attached\n\n");
51
+ agents++;
52
+ announce();
53
+ const keepAlive = setInterval(() => res.write(": ping\n\n"), 15_000);
54
+ req.on("close", () => {
55
+ clearInterval(keepAlive);
56
+ agents--;
57
+ announce();
58
+ });
59
+ return;
60
+ }
61
+ if (url === AGENT_PATHS.result && req.method === "POST") {
62
+ const body = (await readJson(req));
63
+ const p = pending.get(body.id);
64
+ if (p) {
65
+ clearTimeout(p.timer);
66
+ pending.delete(body.id);
67
+ p.resolve(body);
68
+ }
69
+ return reply(res, 204);
70
+ }
71
+ if (url === AGENT_PATHS.rpc && req.method === "POST") {
72
+ const { method, args = [] } = (await readJson(req));
73
+ const page = pages.at(-1);
74
+ if (!page)
75
+ return reply(res, 503, { ok: false, error: "No game page is open. Open the dev server URL in a browser." });
76
+ const id = String(nextId++);
77
+ const result = await new Promise((resolve) => {
78
+ const timer = setTimeout(() => {
79
+ pending.delete(id);
80
+ resolve({ id, ok: false, error: `The game page did not answer "${method}" within 10 s (is the tab in the background?)` });
81
+ }, 10_000);
82
+ pending.set(id, { resolve, timer });
83
+ send(page, "command", { id, method, args });
84
+ });
85
+ return reply(res, 200, result);
86
+ }
87
+ reply(res, 404, { ok: false, error: `Unknown agent endpoint ${url}` });
88
+ }
89
+ catch (err) {
90
+ reply(res, 400, { ok: false, error: err instanceof Error ? err.message : String(err) });
91
+ }
92
+ });
93
+ const file = join(root, DEV_SERVER_FILE);
94
+ server.httpServer?.once("listening", () => {
95
+ const url = server.resolvedUrls?.local[0];
96
+ if (!url)
97
+ return;
98
+ mkdirSync(join(root, ".debuff"), { recursive: true });
99
+ writeFileSync(file, `${JSON.stringify({ url, pid: process.pid }, null, 2)}\n`);
100
+ });
101
+ server.httpServer?.once("close", () => {
102
+ for (const p of pending.values())
103
+ clearTimeout(p.timer);
104
+ for (const page of pages)
105
+ page.end();
106
+ rmSync(file, { force: true });
107
+ });
108
+ }
109
+ function reply(res, status, body) {
110
+ res.statusCode = status;
111
+ if (body === undefined)
112
+ return void res.end();
113
+ res.setHeader("Content-Type", "application/json");
114
+ res.end(JSON.stringify(body));
115
+ }
116
+ async function readJson(req) {
117
+ let raw = "";
118
+ for await (const chunk of req)
119
+ raw += chunk;
120
+ return JSON.parse(raw || "{}");
121
+ }
122
+ //# sourceMappingURL=agent-link.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-link.js","sourceRoot":"","sources":["../src/agent-link.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ export interface AtlasOptions {
2
+ /** Largest atlas side in pixels. Default 2048 (safe on every WebGL2 device). */
3
+ maxSize?: number;
4
+ /** Transparent gap between sprites, in pixels. Default 2. */
5
+ padding?: number;
6
+ /** Edge pixels copied outward into the padding so filtering never samples a neighbour. Default 1. */
7
+ extrude?: number;
8
+ /** Asset ids (or id prefixes ending in "/") to leave out of atlases. */
9
+ exclude?: string[];
10
+ }
11
+ export interface Placement {
12
+ x: number;
13
+ y: number;
14
+ }
15
+ export interface PackedBin {
16
+ width: number;
17
+ height: number;
18
+ /** Placement per input index, in this bin. */
19
+ items: Map<number, Placement>;
20
+ }
21
+ /**
22
+ * MaxRects bin packing (best-short-side-fit). Inputs are sorted largest-first; anything that doesn't
23
+ * fit opens a new bin. Bins are cropped to their used area (rounded up to a multiple of 4).
24
+ * Throws if a single item can't fit in an empty bin.
25
+ */
26
+ export declare function packRects(sizes: readonly {
27
+ w: number;
28
+ h: number;
29
+ }[], maxSize: number, gap: number): PackedBin[];
30
+ export interface Rgba {
31
+ width: number;
32
+ height: number;
33
+ /** RGBA, 8 bits per channel. */
34
+ data: Uint8Array;
35
+ }
36
+ /** Decode any PNG (palette, grey, RGB, 16-bit…) to 8-bit RGBA. */
37
+ export declare function decodePng(bytes: Uint8Array): Rgba;
38
+ /** Copy `img` into `atlas` at (x, y), extruding its edge pixels `extrude` px outward. */
39
+ export declare function blit(atlas: Rgba, img: Rgba, x: number, y: number, extrude: number): void;
40
+ export interface AtlasInput {
41
+ id: string;
42
+ png: Uint8Array;
43
+ }
44
+ export interface BuiltAtlas {
45
+ png: Uint8Array;
46
+ width: number;
47
+ height: number;
48
+ /** Source rectangle per input id. */
49
+ rects: Map<string, {
50
+ x: number;
51
+ y: number;
52
+ w: number;
53
+ h: number;
54
+ }>;
55
+ }
56
+ /** Pack PNGs into as few atlases as fit `maxSize`. */
57
+ export declare function buildAtlases(inputs: readonly AtlasInput[], options?: AtlasOptions): BuiltAtlas[];
58
+ //# sourceMappingURL=atlas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atlas.d.ts","sourceRoot":"","sources":["../../src/assets/atlas.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,YAAY;IAC3B,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qGAAqG;IACrG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CAC/B;AASD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,CA6B/G;AAgDD,MAAM,WAAW,IAAI;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,kEAAkE;AAClE,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CA4BjD;AAED,yFAAyF;AACzF,wBAAgB,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAkBxF;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,UAAU,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,UAAU,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpE;AAED,sDAAsD;AACtD,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,EAAE,OAAO,GAAE,YAAiB,GAAG,UAAU,EAAE,CA8BpG"}
@@ -0,0 +1,164 @@
1
+ import { convertIndexedToRgb, decode, encode } from "fast-png";
2
+ /**
3
+ * MaxRects bin packing (best-short-side-fit). Inputs are sorted largest-first; anything that doesn't
4
+ * fit opens a new bin. Bins are cropped to their used area (rounded up to a multiple of 4).
5
+ * Throws if a single item can't fit in an empty bin.
6
+ */
7
+ export function packRects(sizes, maxSize, gap) {
8
+ const order = sizes
9
+ .map((_, i) => i)
10
+ .sort((a, b) => Math.max(sizes[b]?.w ?? 0, sizes[b]?.h ?? 0) - Math.max(sizes[a]?.w ?? 0, sizes[a]?.h ?? 0));
11
+ const bins = [];
12
+ for (const index of order) {
13
+ const size = sizes[index];
14
+ if (!size)
15
+ continue;
16
+ const w = size.w + gap;
17
+ const h = size.h + gap;
18
+ if (w > maxSize || h > maxSize)
19
+ throw new Error(`An image of ${size.w}×${size.h} can't fit a ${maxSize}px atlas`);
20
+ let placed = false;
21
+ for (const bin of bins) {
22
+ const spot = findSpot(bin.free, w, h);
23
+ if (!spot)
24
+ continue;
25
+ place(bin, index, spot, w, h);
26
+ placed = true;
27
+ break;
28
+ }
29
+ if (!placed) {
30
+ const bin = { free: [{ x: 0, y: 0, w: maxSize, h: maxSize }], items: new Map(), usedW: 0, usedH: 0 };
31
+ const spot = findSpot(bin.free, w, h);
32
+ if (!spot)
33
+ throw new Error("unreachable: empty bin rejected an item that fits");
34
+ place(bin, index, spot, w, h);
35
+ bins.push(bin);
36
+ }
37
+ }
38
+ const up4 = (n) => Math.ceil(n / 4) * 4;
39
+ return bins.map((b) => ({ width: Math.min(maxSize, up4(b.usedW)), height: Math.min(maxSize, up4(b.usedH)), items: b.items }));
40
+ }
41
+ function findSpot(free, w, h) {
42
+ let best;
43
+ let bestShort = Number.POSITIVE_INFINITY;
44
+ let bestLong = Number.POSITIVE_INFINITY;
45
+ for (const f of free) {
46
+ if (w > f.w || h > f.h)
47
+ continue;
48
+ const short = Math.min(f.w - w, f.h - h);
49
+ const long = Math.max(f.w - w, f.h - h);
50
+ if (short < bestShort || (short === bestShort && long < bestLong)) {
51
+ best = f;
52
+ bestShort = short;
53
+ bestLong = long;
54
+ }
55
+ }
56
+ return best;
57
+ }
58
+ function place(bin, index, spot, w, h) {
59
+ const used = { x: spot.x, y: spot.y, w, h };
60
+ bin.items.set(index, { x: spot.x, y: spot.y });
61
+ bin.usedW = Math.max(bin.usedW, spot.x + w);
62
+ bin.usedH = Math.max(bin.usedH, spot.y + h);
63
+ // Split every free rect the placement overlaps, then drop rects contained in others.
64
+ const next = [];
65
+ for (const f of bin.free) {
66
+ if (used.x >= f.x + f.w || used.x + used.w <= f.x || used.y >= f.y + f.h || used.y + used.h <= f.y) {
67
+ next.push(f);
68
+ continue;
69
+ }
70
+ if (used.x > f.x)
71
+ next.push({ x: f.x, y: f.y, w: used.x - f.x, h: f.h });
72
+ if (used.x + used.w < f.x + f.w)
73
+ next.push({ x: used.x + used.w, y: f.y, w: f.x + f.w - used.x - used.w, h: f.h });
74
+ if (used.y > f.y)
75
+ next.push({ x: f.x, y: f.y, w: f.w, h: used.y - f.y });
76
+ if (used.y + used.h < f.y + f.h)
77
+ next.push({ x: f.x, y: used.y + used.h, w: f.w, h: f.y + f.h - used.y - used.h });
78
+ }
79
+ bin.free = next.filter((a, i) => !next.some((b, j) => i !== j && contains(b, a) && (!contains(a, b) || j < i)));
80
+ }
81
+ const contains = (outer, inner) => inner.x >= outer.x && inner.y >= outer.y && inner.x + inner.w <= outer.x + outer.w && inner.y + inner.h <= outer.y + outer.h;
82
+ /** Decode any PNG (palette, grey, RGB, 16-bit…) to 8-bit RGBA. */
83
+ export function decodePng(bytes) {
84
+ const png = decode(bytes);
85
+ const { width, height } = png;
86
+ const out = new Uint8Array(width * height * 4);
87
+ if (png.palette) {
88
+ const rgb = convertIndexedToRgb(png);
89
+ const ch = png.palette[0]?.length ?? 3;
90
+ for (let i = 0; i < width * height; i++) {
91
+ out[i * 4] = rgb[i * ch] ?? 0;
92
+ out[i * 4 + 1] = rgb[i * ch + 1] ?? 0;
93
+ out[i * 4 + 2] = rgb[i * ch + 2] ?? 0;
94
+ out[i * 4 + 3] = ch === 4 ? (rgb[i * ch + 3] ?? 255) : 255;
95
+ }
96
+ return { width, height, data: out };
97
+ }
98
+ const ch = png.channels;
99
+ const shift = png.depth === 16 ? 8 : 0;
100
+ const src = png.data;
101
+ for (let i = 0; i < width * height; i++) {
102
+ const v = (k) => (src[i * ch + k] ?? 0) >> shift;
103
+ if (ch === 1 || ch === 2) {
104
+ const g = v(0);
105
+ out.set([g, g, g, ch === 2 ? v(1) : 255], i * 4);
106
+ }
107
+ else {
108
+ out.set([v(0), v(1), v(2), ch === 4 ? v(3) : 255], i * 4);
109
+ }
110
+ }
111
+ return { width, height, data: out };
112
+ }
113
+ /** Copy `img` into `atlas` at (x, y), extruding its edge pixels `extrude` px outward. */
114
+ export function blit(atlas, img, x, y, extrude) {
115
+ const aw = atlas.width;
116
+ for (let dy = -extrude; dy < img.height + extrude; dy++) {
117
+ const ty = y + dy;
118
+ if (ty < 0 || ty >= atlas.height)
119
+ continue;
120
+ const sy = Math.min(img.height - 1, Math.max(0, dy));
121
+ for (let dx = -extrude; dx < img.width + extrude; dx++) {
122
+ const tx = x + dx;
123
+ if (tx < 0 || tx >= aw)
124
+ continue;
125
+ const sx = Math.min(img.width - 1, Math.max(0, dx));
126
+ const s = (sy * img.width + sx) * 4;
127
+ const t = (ty * aw + tx) * 4;
128
+ atlas.data[t] = img.data[s] ?? 0;
129
+ atlas.data[t + 1] = img.data[s + 1] ?? 0;
130
+ atlas.data[t + 2] = img.data[s + 2] ?? 0;
131
+ atlas.data[t + 3] = img.data[s + 3] ?? 0;
132
+ }
133
+ }
134
+ }
135
+ /** Pack PNGs into as few atlases as fit `maxSize`. */
136
+ export function buildAtlases(inputs, options = {}) {
137
+ const maxSize = options.maxSize ?? 2048;
138
+ const padding = options.padding ?? 2;
139
+ const extrude = Math.min(options.extrude ?? 1, Math.floor(padding / 2));
140
+ const images = inputs.map((i) => decodePng(i.png));
141
+ // Reserve padding on every side: items are offset by `padding` so extrusion has room at the edges.
142
+ const bins = packRects(images.map((img) => ({ w: img.width + padding, h: img.height + padding })), maxSize, 0);
143
+ return bins.map((bin) => {
144
+ const atlas = { width: bin.width, height: bin.height, data: new Uint8Array(bin.width * bin.height * 4) };
145
+ const rects = new Map();
146
+ for (const [index, at] of bin.items) {
147
+ const img = images[index];
148
+ const input = inputs[index];
149
+ if (!img || !input)
150
+ continue;
151
+ const x = at.x + Math.ceil(padding / 2);
152
+ const y = at.y + Math.ceil(padding / 2);
153
+ blit(atlas, img, x, y, extrude);
154
+ rects.set(input.id, { x, y, w: img.width, h: img.height });
155
+ }
156
+ return {
157
+ png: encode({ width: atlas.width, height: atlas.height, data: atlas.data, channels: 4, depth: 8 }),
158
+ width: atlas.width,
159
+ height: atlas.height,
160
+ rects,
161
+ };
162
+ });
163
+ }
164
+ //# sourceMappingURL=atlas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atlas.js","sourceRoot":"","sources":["../../src/assets/atlas.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { FunctionImporter } from "../plugin.js";
2
+ export declare const BUILTIN_EXTENSIONS: string[];
3
+ /** Images, JSON, audio and text, served as-is. */
4
+ export declare const builtinImporter: FunctionImporter;
5
+ //# sourceMappingURL=builtin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builtin.d.ts","sourceRoot":"","sources":["../../src/assets/builtin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,gBAAgB,EAA4B,MAAM,cAAc,CAAC;AAyB1F,eAAO,MAAM,kBAAkB,UAAqB,CAAC;AAErD,kDAAkD;AAClD,eAAO,MAAM,eAAe,EAAE,gBAoB7B,CAAC"}
@@ -0,0 +1,47 @@
1
+ const TYPES = {
2
+ ".png": "image",
3
+ ".jpg": "image",
4
+ ".jpeg": "image",
5
+ ".webp": "image",
6
+ ".avif": "image",
7
+ ".gif": "image",
8
+ ".json": "json",
9
+ // Tiled maps/tilesets and LDtk projects are JSON (load with @debuffjp/tilemap).
10
+ ".tmj": "json",
11
+ ".tsj": "json",
12
+ ".ldtk": "json",
13
+ ".ogg": "audio",
14
+ ".opus": "audio",
15
+ ".mp3": "audio",
16
+ ".wav": "audio",
17
+ ".m4a": "audio",
18
+ ".txt": "text",
19
+ };
20
+ /** `hero@16x24.png` declares a 16×24 grid and the id "hero". Explicit by design: we never guess frame sizes. */
21
+ const GRID = /@(\d+)x(\d+)$/;
22
+ export const BUILTIN_EXTENSIONS = Object.keys(TYPES);
23
+ /** Images, JSON, audio and text, served as-is. */
24
+ export const builtinImporter = {
25
+ name: "debuff:builtin",
26
+ extensions: BUILTIN_EXTENSIONS,
27
+ import(file) {
28
+ const type = TYPES[file.ext];
29
+ if (!type)
30
+ return { assets: {}, warnings: [`Skipped ${file.rel}: unsupported extension "${file.ext}"`] };
31
+ let id = file.id;
32
+ const grid = GRID.exec(id);
33
+ if (grid)
34
+ id = id.slice(0, grid.index);
35
+ return {
36
+ assets: {
37
+ [id]: {
38
+ type,
39
+ src: `assets/${file.rel}`,
40
+ ...(file.group ? { group: file.group } : {}),
41
+ ...(grid ? { grid: { frameWidth: Number(grid[1]), frameHeight: Number(grid[2]) } } : {}),
42
+ },
43
+ },
44
+ };
45
+ },
46
+ };
47
+ //# sourceMappingURL=builtin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builtin.js","sourceRoot":"","sources":["../../src/assets/builtin.ts"],"names":[],"mappings":"AAEA,MAAM,KAAK,GAA8B;IACvC,MAAM,EAAE,OAAO;IACf,MAAM,EAAE,OAAO;IACf,OAAO,EAAE,OAAO;IAChB,OAAO,EAAE,OAAO;IAChB,OAAO,EAAE,OAAO;IAChB,MAAM,EAAE,OAAO;IACf,OAAO,EAAE,MAAM;IACf,gFAAgF;IAChF,MAAM,EAAE,MAAM;IACd,MAAM,EAAE,MAAM;IACd,OAAO,EAAE,MAAM;IACf,MAAM,EAAE,OAAO;IACf,OAAO,EAAE,OAAO;IAChB,MAAM,EAAE,OAAO;IACf,MAAM,EAAE,OAAO;IACf,MAAM,EAAE,OAAO;IACf,MAAM,EAAE,MAAM;CACf,CAAC;AAEF,gHAAgH;AAChH,MAAM,IAAI,GAAG,eAAe,CAAC;AAE7B,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAErD,kDAAkD;AAClD,MAAM,CAAC,MAAM,eAAe,GAAqB;IAC/C,IAAI,EAAE,gBAAgB;IACtB,UAAU,EAAE,kBAAkB;IAC9B,MAAM,CAAC,IAAgB;QACrB,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,WAAW,IAAI,CAAC,GAAG,4BAA4B,IAAI,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC;QACzG,IAAI,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC3B,IAAI,IAAI;YAAE,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QACvC,OAAO;YACL,MAAM,EAAE;gBACN,CAAC,EAAE,CAAC,EAAE;oBACJ,IAAI;oBACJ,GAAG,EAAE,UAAU,IAAI,CAAC,GAAG,EAAE;oBACzB,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC5C,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACzF;aACF;SACF,CAAC;IACJ,CAAC;CACF,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { CommandImporter, ImportResult, SourceFile } from "../plugin.js";
2
+ /** Run a command importer: SourceFile JSON on stdin, ImportResult JSON on stdout. */
3
+ export declare function runCommandImporter(importer: CommandImporter, file: SourceFile, cwd: string): Promise<ImportResult>;
4
+ //# sourceMappingURL=command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/assets/command.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAI9E,qFAAqF;AACrF,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CA4BlH"}
@@ -0,0 +1,35 @@
1
+ import { spawn } from "node:child_process";
2
+ const TIMEOUT_MS = 60_000;
3
+ /** Run a command importer: SourceFile JSON on stdin, ImportResult JSON on stdout. */
4
+ export function runCommandImporter(importer, file, cwd) {
5
+ const [cmd, ...args] = importer.command;
6
+ return new Promise((resolve, reject) => {
7
+ const child = spawn(cmd, args, { cwd, stdio: ["pipe", "pipe", "pipe"], shell: process.platform === "win32" });
8
+ const out = [];
9
+ const err = [];
10
+ const timer = setTimeout(() => {
11
+ child.kill();
12
+ reject(new Error(`importer "${importer.name}" timed out after ${TIMEOUT_MS / 1000}s on ${file.rel}`));
13
+ }, TIMEOUT_MS);
14
+ child.stdout.on("data", (d) => out.push(d));
15
+ child.stderr.on("data", (d) => err.push(d));
16
+ child.on("error", (e) => {
17
+ clearTimeout(timer);
18
+ reject(new Error(`importer "${importer.name}" could not start \`${cmd}\`: ${e.message}`));
19
+ });
20
+ child.on("close", (code) => {
21
+ clearTimeout(timer);
22
+ const stderr = Buffer.concat(err).toString("utf8").trim();
23
+ if (code !== 0)
24
+ return reject(new Error(`importer "${importer.name}" exited ${code} on ${file.rel}${stderr ? `: ${stderr}` : ""}`));
25
+ try {
26
+ resolve(JSON.parse(Buffer.concat(out).toString("utf8")));
27
+ }
28
+ catch {
29
+ reject(new Error(`importer "${importer.name}" printed invalid JSON for ${file.rel}`));
30
+ }
31
+ });
32
+ child.stdin.end(JSON.stringify(file));
33
+ });
34
+ }
35
+ //# sourceMappingURL=command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command.js","sourceRoot":"","sources":["../../src/assets/command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAG3C,MAAM,UAAU,GAAG,MAAM,CAAC;AAE1B,qFAAqF;AACrF,MAAM,UAAU,kBAAkB,CAAC,QAAyB,EAAE,IAAgB,EAAE,GAAW;IACzF,MAAM,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC;IACxC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC,CAAC;QAC9G,MAAM,GAAG,GAAa,EAAE,CAAC;QACzB,MAAM,GAAG,GAAa,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,KAAK,CAAC,IAAI,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,KAAK,CAAC,aAAa,QAAQ,CAAC,IAAI,qBAAqB,UAAU,GAAG,IAAI,QAAQ,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACxG,CAAC,EAAE,UAAU,CAAC,CAAC;QACf,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACpD,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACpD,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;YACtB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,CAAC,IAAI,KAAK,CAAC,aAAa,QAAQ,CAAC,IAAI,uBAAuB,GAAG,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC5F,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACzB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;YAC1D,IAAI,IAAI,KAAK,CAAC;gBAAE,OAAO,MAAM,CAAC,IAAI,KAAK,CAAC,aAAa,QAAQ,CAAC,IAAI,YAAY,IAAI,OAAO,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;YACpI,IAAI,CAAC;gBACH,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAiB,CAAC,CAAC;YAC3E,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,CAAC,IAAI,KAAK,CAAC,aAAa,QAAQ,CAAC,IAAI,8BAA8B,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YACxF,CAAC;QACH,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type { CompiledEntry, ToolingPlugin } from "../plugin.js";
2
+ import { type AtlasOptions } from "./atlas.js";
3
+ export interface CompiledManifest {
4
+ version: 1;
5
+ assets: Record<string, CompiledEntry>;
6
+ }
7
+ export interface CompileResult {
8
+ manifest: CompiledManifest;
9
+ /** Generated files keyed by path relative to `assets/`. */
10
+ outputs: Map<string, Buffer>;
11
+ warnings: string[];
12
+ /** Which importer produced each asset id. */
13
+ importedBy: Record<string, string>;
14
+ }
15
+ export interface CompileOptions {
16
+ plugins?: ToolingPlugin[];
17
+ /** Cache import results by content hash under `.debuff/cache/assets`. Default true. */
18
+ cache?: boolean;
19
+ /** Pack PNG images into atlases per preload group. Default on; `false` disables. */
20
+ atlas?: AtlasOptions | false;
21
+ }
22
+ /**
23
+ * Turn `assets/` into a manifest plus generated files, entirely in memory.
24
+ * Source files are never modified; nothing is written into the source tree.
25
+ */
26
+ export declare function compileAssets(root: string, options?: CompileOptions): Promise<CompileResult>;
27
+ /** Asset ids never referenced as a string literal in `src/`. Heuristic: reports, never deletes. */
28
+ export declare function findUnused(root: string, manifest: CompiledManifest): string[];
29
+ //# sourceMappingURL=compile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/assets/compile.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAiB,aAAa,EAA2C,aAAa,EAAE,MAAM,cAAc,CAAC;AACzH,OAAO,EAAE,KAAK,YAAY,EAAgB,MAAM,YAAY,CAAC;AAI7D,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,CAAC,CAAC;IACX,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,2DAA2D;IAC3D,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,6CAA6C;IAC7C,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC;AA2BD,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC;IAC1B,uFAAuF;IACvF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,oFAAoF;IACpF,KAAK,CAAC,EAAE,YAAY,GAAG,KAAK,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,aAAa,CAAC,CA2EtG;AA+BD,mGAAmG;AACnG,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,gBAAgB,GAAG,MAAM,EAAE,CAW7E"}