create-debuff 0.0.0-stage → 0.2.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 (40) hide show
  1. package/README.md +14 -2
  2. package/bin/create-debuff.js +3 -0
  3. package/dist/brand.d.ts +38 -0
  4. package/dist/brand.d.ts.map +1 -0
  5. package/dist/brand.js +112 -0
  6. package/dist/brand.js.map +1 -0
  7. package/dist/cli.d.ts +3 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +13 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/index.d.ts +5 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +5 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/interactive.d.ts +10 -0
  16. package/dist/interactive.d.ts.map +1 -0
  17. package/dist/interactive.js +57 -0
  18. package/dist/interactive.js.map +1 -0
  19. package/dist/official.d.ts +13 -0
  20. package/dist/official.d.ts.map +1 -0
  21. package/dist/official.js +15 -0
  22. package/dist/official.js.map +1 -0
  23. package/dist/scaffold.d.ts +45 -0
  24. package/dist/scaffold.d.ts.map +1 -0
  25. package/dist/scaffold.js +147 -0
  26. package/dist/scaffold.js.map +1 -0
  27. package/package.json +62 -4
  28. package/templates/basic/.mcp.json +5 -0
  29. package/templates/basic/AGENTS.md +38 -0
  30. package/templates/basic/CLAUDE.md +1 -0
  31. package/templates/basic/assets/.gitkeep +0 -0
  32. package/templates/basic/gitignore +3 -0
  33. package/templates/basic/index.html +18 -0
  34. package/templates/basic/package.json +23 -0
  35. package/templates/basic/scenarios/__baselines__/move-and-pop/popped.win32.png +0 -0
  36. package/templates/basic/scenarios/__baselines__/move-and-pop/settled.win32.png +0 -0
  37. package/templates/basic/scenarios/move-and-pop.json +73 -0
  38. package/templates/basic/src/main.ts +79 -0
  39. package/templates/basic/template.json +5 -0
  40. package/templates/basic/tsconfig.json +13 -0
package/README.md CHANGED
@@ -1,3 +1,15 @@
1
- # Temporary Holding Version
1
+ # create-debuff
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
+ Scaffold a new [debuff](https://github.com/debuffjp/debuff) game.
4
+
5
+ ```bash
6
+ npm create debuff@latest my-game
7
+ # or: pnpm create debuff · yarn create debuff · bun create debuff
8
+ ```
9
+
10
+ Options:
11
+
12
+ - `--template <id>`: `basic` (default, bundled) or `platformer` (downloaded on demand), or any git source such as `github:user/repo`
13
+ - `--yes`: accept defaults without prompting (CI, agents)
14
+
15
+ Runs without prompts when stdin isn't a TTY.
@@ -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";
@@ -0,0 +1,38 @@
1
+ /** debuff palette. Lime is the brand; the accents are for splashes of colour in tooling. */
2
+ export declare const PALETTE: {
3
+ readonly lime: "#cffb2d";
4
+ readonly limeSoft: "#e7fd96";
5
+ readonly ink: "#11140d";
6
+ readonly sky: "#38bdf8";
7
+ readonly pink: "#f472b6";
8
+ readonly amber: "#fbbf24";
9
+ readonly violet: "#a78bfa";
10
+ readonly red: "#f87171";
11
+ };
12
+ export type PaletteColor = keyof typeof PALETTE;
13
+ /** @deprecated Use PALETTE.lime. Kept for existing imports. */
14
+ export declare const LIME: {
15
+ hex: "#cffb2d";
16
+ rgb: [number, number, number];
17
+ };
18
+ /** Paint text in a palette colour. */
19
+ export declare function paint(name: PaletteColor, text: string): string;
20
+ export declare const lime: (text: string) => string;
21
+ export declare const sky: (text: string) => string;
22
+ export declare const pink: (text: string) => string;
23
+ export declare const amber: (text: string) => string;
24
+ export declare const violet: (text: string) => string;
25
+ /** The ` debuff ` badge used in CLI headers. */
26
+ export declare function badge(text?: string): string;
27
+ export type Mood = "idle" | "happy" | "oops";
28
+ /**
29
+ * buff rendered with half-block characters: two pixel rows per text line (3 lines tall).
30
+ * Returns no lines when the terminal can't show 24-bit colour, so callers can just skip it.
31
+ */
32
+ export declare function buff(mood?: Mood): string[];
33
+ /**
34
+ * buff beside up to three lines of text, for command headers and results.
35
+ * Falls back to the badge and text when buff can't be drawn.
36
+ */
37
+ export declare function banner(mood: Mood, lines: string[]): string;
38
+ //# sourceMappingURL=brand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brand.d.ts","sourceRoot":"","sources":["../src/brand.ts"],"names":[],"mappings":"AAEA,4FAA4F;AAC5F,eAAO,MAAM,OAAO;aAClB,IAAI,EAAE,SAAS;aACf,QAAQ,EAAE,SAAS;aACnB,GAAG,EAAE,SAAS;aACd,GAAG,EAAE,SAAS;aACd,IAAI,EAAE,SAAS;aACf,KAAK,EAAE,SAAS;aAChB,MAAM,EAAE,SAAS;aACjB,GAAG,EAAE,SAAS;CACN,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,MAAM,OAAO,OAAO,CAAC;AAEhD,+DAA+D;AAC/D,eAAO,MAAM,IAAI;IAAK,GAAG;IAAgB,GAAG;CAAqB,CAAC;AAkBlE,sCAAsC;AACtC,wBAAgB,KAAK,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAK9D;AAED,eAAO,MAAM,IAAI,SAAU,MAAM,WAAwB,CAAC;AAC1D,eAAO,MAAM,GAAG,SAAU,MAAM,WAAuB,CAAC;AACxD,eAAO,MAAM,IAAI,SAAU,MAAM,WAAwB,CAAC;AAC1D,eAAO,MAAM,KAAK,SAAU,MAAM,WAAyB,CAAC;AAC5D,eAAO,MAAM,MAAM,SAAU,MAAM,WAA0B,CAAC;AAE9D,gDAAgD;AAChD,wBAAgB,KAAK,CAAC,IAAI,SAAa,GAAG,MAAM,CAK/C;AAED,MAAM,MAAM,IAAI,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAc7C;;;GAGG;AACH,wBAAgB,IAAI,CAAC,IAAI,GAAE,IAAa,GAAG,MAAM,EAAE,CAmBlD;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAI1D"}
package/dist/brand.js ADDED
@@ -0,0 +1,112 @@
1
+ import pc from "picocolors";
2
+ /** debuff palette. Lime is the brand; the accents are for splashes of colour in tooling. */
3
+ export const PALETTE = {
4
+ lime: "#cffb2d",
5
+ limeSoft: "#e7fd96",
6
+ ink: "#11140d",
7
+ sky: "#38bdf8",
8
+ pink: "#f472b6",
9
+ amber: "#fbbf24",
10
+ violet: "#a78bfa",
11
+ red: "#f87171",
12
+ };
13
+ /** @deprecated Use PALETTE.lime. Kept for existing imports. */
14
+ export const LIME = { hex: PALETTE.lime, rgb: rgb(PALETTE.lime) };
15
+ const color = pc.isColorSupported;
16
+ const truecolor = color && (/truecolor|24bit/i.test(process.env.COLORTERM ?? "") || process.platform === "win32" || process.env.TERM_PROGRAM === "vscode");
17
+ /** Fallbacks for terminals without 24-bit colour. */
18
+ const BASIC = {
19
+ lime: pc.green,
20
+ limeSoft: pc.greenBright,
21
+ ink: pc.black,
22
+ sky: pc.cyan,
23
+ pink: pc.magenta,
24
+ amber: pc.yellow,
25
+ violet: pc.blue,
26
+ red: pc.red,
27
+ };
28
+ /** Paint text in a palette colour. */
29
+ export function paint(name, text) {
30
+ if (!color)
31
+ return text;
32
+ if (!truecolor)
33
+ return BASIC[name](text);
34
+ const [r, g, b] = rgb(PALETTE[name]);
35
+ return `\x1b[38;2;${r};${g};${b}m${text}\x1b[39m`;
36
+ }
37
+ export const lime = (text) => paint("lime", text);
38
+ export const sky = (text) => paint("sky", text);
39
+ export const pink = (text) => paint("pink", text);
40
+ export const amber = (text) => paint("amber", text);
41
+ export const violet = (text) => paint("violet", text);
42
+ /** The ` debuff ` badge used in CLI headers. */
43
+ export function badge(text = " debuff ") {
44
+ if (!color)
45
+ return `[${text.trim()}]`;
46
+ if (!truecolor)
47
+ return pc.bgGreen(pc.black(text));
48
+ const [r, g, b] = rgb(PALETTE.lime);
49
+ return `\x1b[48;2;${r};${g};${b}m${pc.black(pc.bold(text))}\x1b[49m`;
50
+ }
51
+ /**
52
+ * buff, the debuff mascot, as pixel art. Each string is a pixel row:
53
+ * L lime, H highlight, K ink, R red (oops), . transparent.
54
+ */
55
+ const BUFF = {
56
+ idle: [".LLLLLL.", "LHHHHHHL", "LLKLLKLL", "LLKLLKLL", "LLLLLLLL", ".LLLLLL."],
57
+ happy: [".LLLLLL.", "LHHHHHHL", "LKLKKLKL", "LLLLLLLL", "LLKKKKLL", ".LLLLLL."],
58
+ oops: [".LLLLLL.", "LHHHHHHL", "LRLLLLRL", "LLRLLRLL", "LLLKKLLL", ".LLLLLL."],
59
+ };
60
+ const PIXEL = { L: PALETTE.lime, H: PALETTE.limeSoft, K: PALETTE.ink, R: PALETTE.red };
61
+ /**
62
+ * buff rendered with half-block characters: two pixel rows per text line (3 lines tall).
63
+ * Returns no lines when the terminal can't show 24-bit colour, so callers can just skip it.
64
+ */
65
+ export function buff(mood = "idle") {
66
+ if (!truecolor)
67
+ return [];
68
+ const rows = BUFF[mood];
69
+ const lines = [];
70
+ for (let y = 0; y < rows.length; y += 2) {
71
+ const top = rows[y] ?? "";
72
+ const bottom = rows[y + 1] ?? "";
73
+ let line = "";
74
+ for (let x = 0; x < top.length; x++) {
75
+ const t = PIXEL[top[x] ?? "."];
76
+ const b = PIXEL[bottom[x] ?? "."];
77
+ if (!t && !b)
78
+ line += " ";
79
+ else if (t && b)
80
+ line += `${fg(t)}${bg(b)}▀\x1b[0m`;
81
+ else if (t)
82
+ line += `${fg(t)}▀\x1b[0m`;
83
+ else if (b)
84
+ line += `${fg(b)}▄\x1b[0m`;
85
+ }
86
+ lines.push(line);
87
+ }
88
+ return lines;
89
+ }
90
+ /**
91
+ * buff beside up to three lines of text, for command headers and results.
92
+ * Falls back to the badge and text when buff can't be drawn.
93
+ */
94
+ export function banner(mood, lines) {
95
+ const art = buff(mood);
96
+ if (!art.length)
97
+ return [`${badge()} ${lines[0] ?? ""}`, ...lines.slice(1).map((l) => ` ${l}`)].join("\n");
98
+ return art.map((row, i) => ` ${row} ${lines[i] ?? ""}`).join("\n");
99
+ }
100
+ function rgb(hex) {
101
+ const n = Number.parseInt(hex.slice(1), 16);
102
+ return [(n >> 16) & 255, (n >> 8) & 255, n & 255];
103
+ }
104
+ const fg = (hex) => {
105
+ const [r, g, b] = rgb(hex);
106
+ return `\x1b[38;2;${r};${g};${b}m`;
107
+ };
108
+ const bg = (hex) => {
109
+ const [r, g, b] = rgb(hex);
110
+ return `\x1b[48;2;${r};${g};${b}m`;
111
+ };
112
+ //# sourceMappingURL=brand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brand.js","sourceRoot":"","sources":["../src/brand.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import { runCreate } from "./interactive.js";
3
+ const args = process.argv.slice(2);
4
+ const flag = (n) => {
5
+ const i = args.indexOf(`--${n}`);
6
+ return i >= 0 ? args[i + 1] : undefined;
7
+ };
8
+ const dir = args.find((a, i) => !a.startsWith("-") && !args[i - 1]?.startsWith("--"));
9
+ runCreate({ dir, template: flag("template"), yes: args.includes("--yes") || args.includes("-y") }).then((code) => process.exit(code), (err) => {
10
+ console.error(err instanceof Error ? err.message : err);
11
+ process.exit(1);
12
+ });
13
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,EAAE;IACzB,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACjC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC1C,CAAC,CAAC;AACF,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;AAEtF,SAAS,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CACrG,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAC5B,CAAC,GAAY,EAAE,EAAE;IACf,OAAO,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CACF,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { amber, badge, banner, buff, LIME, lime, type Mood, PALETTE, type PaletteColor, paint, pink, sky, violet } from "./brand.js";
2
+ export { type CreateOptions, runCreate } from "./interactive.js";
3
+ export { OFFICIAL_TEMPLATES, type OfficialTemplate } from "./official.js";
4
+ export { create, detectPackageManager, isEmptyDir, isRemoteTemplate, listTemplates, ownVersion, packageName, pinnedSource, resolveTemplate, type ScaffoldOptions, scaffold, scaffoldRemote, type TemplateInfo, templatesDir, } from "./scaffold.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACrI,OAAO,EAAE,KAAK,aAAa,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EACL,MAAM,EACN,oBAAoB,EACpB,UAAU,EACV,gBAAgB,EAChB,aAAa,EACb,UAAU,EACV,WAAW,EACX,YAAY,EACZ,eAAe,EACf,KAAK,eAAe,EACpB,QAAQ,EACR,cAAc,EACd,KAAK,YAAY,EACjB,YAAY,GACb,MAAM,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { amber, badge, banner, buff, LIME, lime, PALETTE, paint, pink, sky, violet } from "./brand.js";
2
+ export { runCreate } from "./interactive.js";
3
+ export { OFFICIAL_TEMPLATES } from "./official.js";
4
+ export { create, detectPackageManager, isEmptyDir, isRemoteTemplate, listTemplates, ownVersion, packageName, pinnedSource, resolveTemplate, scaffold, scaffoldRemote, templatesDir, } from "./scaffold.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAa,OAAO,EAAqB,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACrI,OAAO,EAAsB,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAyB,MAAM,eAAe,CAAC;AAC1E,OAAO,EACL,MAAM,EACN,oBAAoB,EACpB,UAAU,EACV,gBAAgB,EAChB,aAAa,EACb,UAAU,EACV,WAAW,EACX,YAAY,EACZ,eAAe,EAEf,QAAQ,EACR,cAAc,EAEd,YAAY,GACb,MAAM,eAAe,CAAC"}
@@ -0,0 +1,10 @@
1
+ export interface CreateOptions {
2
+ dir?: string | undefined;
3
+ template?: string | undefined;
4
+ /** Accept defaults without prompting (CI, agents). */
5
+ yes?: boolean;
6
+ }
7
+ /** Interactive scaffold flow. Falls back to defaults when stdin is not a TTY so agents
8
+ * and CI can call it non-interactively. */
9
+ export declare function runCreate(options: CreateOptions): Promise<number>;
10
+ //# sourceMappingURL=interactive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../src/interactive.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,sDAAsD;IACtD,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED;4CAC4C;AAC5C,wBAAsB,SAAS,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAgDvE"}
@@ -0,0 +1,57 @@
1
+ import { relative } from "node:path";
2
+ import * as p from "@clack/prompts";
3
+ import pc from "picocolors";
4
+ import { banner, lime, pink, sky } from "./brand.js";
5
+ import { create, detectPackageManager, isEmptyDir, listTemplates, ownVersion, resolveTemplate } from "./scaffold.js";
6
+ /** Interactive scaffold flow. Falls back to defaults when stdin is not a TTY so agents
7
+ * and CI can call it non-interactively. */
8
+ export async function runCreate(options) {
9
+ const interactive = process.stdin.isTTY && !options.yes;
10
+ console.log(`\n${banner("idle", [`${lime(pc.bold("debuff"))} ${pc.dim(`v${ownVersion()}`)}`, pc.bold("let's make a game"), pc.dim(pc.italic("more room for play"))])}\n`);
11
+ let dir = options.dir;
12
+ if (!dir) {
13
+ if (!interactive) {
14
+ p.cancel("Pass a directory: create-debuff <dir>");
15
+ return 1;
16
+ }
17
+ const answer = await p.text({
18
+ message: "Where should we create your game?",
19
+ placeholder: "./my-game",
20
+ defaultValue: "my-game",
21
+ validate: (v) => (v && !isEmptyDir(v) ? "That directory is not empty" : undefined),
22
+ });
23
+ if (p.isCancel(answer))
24
+ return cancelled();
25
+ dir = answer;
26
+ }
27
+ if (!isEmptyDir(dir)) {
28
+ p.cancel(`${dir} is not empty`);
29
+ return 1;
30
+ }
31
+ const templates = listTemplates();
32
+ let template = options.template;
33
+ if (!template && interactive && templates.length > 1) {
34
+ const answer = await p.select({
35
+ message: "Pick a template",
36
+ options: templates.map((t) => ({ value: t.id, label: t.title, hint: t.description })),
37
+ });
38
+ if (p.isCancel(answer))
39
+ return cancelled();
40
+ template = answer;
41
+ }
42
+ const s = p.spinner();
43
+ const resolved = resolveTemplate(template ?? "basic");
44
+ s.start(resolved.kind === "remote" ? `Downloading ${resolved.source}` : "Scaffolding");
45
+ const dest = await create({ dir, ...(template ? { template } : {}) });
46
+ s.stop(`Created ${lime(relative(process.cwd(), dest) || ".")}`);
47
+ const pm = detectPackageManager();
48
+ const run = pm === "npm" ? "npm run" : pm;
49
+ p.note([`cd ${relative(process.cwd(), dest) || "."}`, `${pm} install`, `${run} dev`].map((c) => sky(c)).join("\n"), "Next steps");
50
+ console.log(`\n${banner("happy", [lime(pc.bold("happy jamming!")), `${pc.dim("buff is waiting in")} ${pink("src/main.ts")}`, ""])}\n`);
51
+ return 0;
52
+ }
53
+ function cancelled() {
54
+ p.cancel("Cancelled");
55
+ return 1;
56
+ }
57
+ //# sourceMappingURL=interactive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive.js","sourceRoot":"","sources":["../src/interactive.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Official templates that are not bundled into the create-debuff package. They're downloaded on
3
+ * demand from the debuff repo, so adding templates never grows the npm download.
4
+ */
5
+ export interface OfficialTemplate {
6
+ id: string;
7
+ title: string;
8
+ description: string;
9
+ /** giget source: where the template lives in the debuff repo. `create()` pins it to this release's tag. */
10
+ source: string;
11
+ }
12
+ export declare const OFFICIAL_TEMPLATES: readonly OfficialTemplate[];
13
+ //# sourceMappingURL=official.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"official.d.ts","sourceRoot":"","sources":["../src/official.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,2GAA2G;IAC3G,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,kBAAkB,EAAE,SAAS,gBAAgB,EAczD,CAAC"}
@@ -0,0 +1,15 @@
1
+ export const OFFICIAL_TEMPLATES = [
2
+ {
3
+ id: "platformer",
4
+ title: "Platformer",
5
+ description: "buff runs and jumps through a Tiled level: tilemap, collision, atlas, tunable movement, coins",
6
+ source: "github:debuffjp/debuff/templates/platformer",
7
+ },
8
+ {
9
+ id: "mossfell",
10
+ title: "Mossfell",
11
+ description: "Top-down action-adventure: screen-by-screen scrolling, sword combat, hearts, enemies, a key and locked door, a small dungeon",
12
+ source: "github:debuffjp/debuff/templates/mossfell",
13
+ },
14
+ ];
15
+ //# sourceMappingURL=official.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"official.js","sourceRoot":"","sources":["../src/official.ts"],"names":[],"mappings":"AAYA,MAAM,CAAC,MAAM,kBAAkB,GAAgC;IAC7D;QACE,EAAE,EAAE,YAAY;QAChB,KAAK,EAAE,YAAY;QACnB,WAAW,EAAE,+FAA+F;QAC5G,MAAM,EAAE,6CAA6C;KACtD;IACD;QACE,EAAE,EAAE,UAAU;QACd,KAAK,EAAE,UAAU;QACjB,WAAW,EACT,8HAA8H;QAChI,MAAM,EAAE,2CAA2C;KACpD;CACF,CAAC"}
@@ -0,0 +1,45 @@
1
+ /** Templates ship inside the published package (copied at build) and live at the repo
2
+ * root during development. */
3
+ export declare function templatesDir(): string;
4
+ export interface TemplateInfo {
5
+ id: string;
6
+ title: string;
7
+ description: string;
8
+ }
9
+ /** Every template: local ones plus official templates that download on demand. */
10
+ export declare function listTemplates(): TemplateInfo[];
11
+ /**
12
+ * Where a template comes from: a local folder (bundled, or the repo checkout during development),
13
+ * an official template's git source, or a git source given directly.
14
+ */
15
+ export declare function resolveTemplate(template: string): {
16
+ kind: "local";
17
+ dir: string;
18
+ } | {
19
+ kind: "remote";
20
+ source: string;
21
+ };
22
+ export interface ScaffoldOptions {
23
+ dir: string;
24
+ template?: string;
25
+ /** Package name; defaults to the directory name. */
26
+ name?: string;
27
+ }
28
+ export declare function packageName(dir: string): string;
29
+ export declare function isEmptyDir(dir: string): boolean;
30
+ /** Copy a template into `dir`. Throws if `dir` is non-empty. Returns the resolved path. */
31
+ /** Git-hosted templates: `github:user/repo`, `gitlab:user/repo/subdir#ref`, also `bitbucket:` and `sourcehut:`. */
32
+ export declare function isRemoteTemplate(template: string): boolean;
33
+ /** Download a git-hosted template (via giget, no git binary needed) and scaffold from it. */
34
+ export declare function scaffoldRemote(options: ScaffoldOptions & {
35
+ template: string;
36
+ }): Promise<string>;
37
+ /** Scaffold from a local template. Use `create()` to also handle official and git-hosted templates. */
38
+ export declare function scaffold(options: ScaffoldOptions): string;
39
+ /** Scaffold from any template: local, official (downloaded on demand) or a git source. */
40
+ export declare function create(options: ScaffoldOptions): Promise<string>;
41
+ /** Pin an official template to the git tag of this create-debuff release, so it matches the published CLI. */
42
+ export declare function pinnedSource(source: string, version: string): string;
43
+ export declare function ownVersion(): string;
44
+ export declare function detectPackageManager(): "npm" | "pnpm" | "yarn" | "bun";
45
+ //# sourceMappingURL=scaffold.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAQA;+BAC+B;AAC/B,wBAAgB,YAAY,IAAI,MAAM,CAUrC;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAcD,kFAAkF;AAClF,wBAAgB,aAAa,IAAI,YAAY,EAAE,CAQ9C;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAWrH;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO/C;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE/C;AAED,2FAA2F;AAC3F,mHAAmH;AACnH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED,6FAA6F;AAC7F,wBAAsB,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAYrG;AAED,uGAAuG;AACvG,wBAAgB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAOzD;AAED,0FAA0F;AAC1F,wBAAsB,MAAM,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAItE;AAuBD,8GAA8G;AAC9G,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,wBAAgB,oBAAoB,IAAI,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAMtE"}
@@ -0,0 +1,147 @@
1
+ import { cpSync, existsSync, mkdtempSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { basename, dirname, join, resolve, sep } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { OFFICIAL_TEMPLATES } from "./official.js";
6
+ const here = dirname(fileURLToPath(import.meta.url));
7
+ /** Templates ship inside the published package (copied at build) and live at the repo
8
+ * root during development. */
9
+ export function templatesDir() {
10
+ // Installed from npm: the bundled copy. In a repo checkout: the repo's templates/, so a stale
11
+ // bundled copy left by `npm pack` can never shadow the real templates during development.
12
+ const bundled = join(here, "..", "templates");
13
+ const repo = join(here, "..", "..", "..", "templates");
14
+ const installed = here.split(sep).includes("node_modules");
15
+ for (const dir of installed ? [bundled] : [repo, bundled]) {
16
+ if (existsSync(dir))
17
+ return dir;
18
+ }
19
+ throw new Error("create-debuff: templates directory not found");
20
+ }
21
+ /** Templates available locally (bundled in the package, or every template in a repo checkout). */
22
+ function localTemplates() {
23
+ const dir = templatesDir();
24
+ return readdirSync(dir)
25
+ .filter((id) => existsSync(join(dir, id, "package.json")))
26
+ .map((id) => {
27
+ const meta = join(dir, id, "template.json");
28
+ const info = existsSync(meta) ? JSON.parse(readFileSync(meta, "utf8")) : {};
29
+ return { id, title: info.title ?? id, description: info.description ?? "" };
30
+ });
31
+ }
32
+ /** Every template: local ones plus official templates that download on demand. */
33
+ export function listTemplates() {
34
+ const local = localTemplates();
35
+ const remote = OFFICIAL_TEMPLATES.filter((t) => !local.some((l) => l.id === t.id)).map(({ id, title, description }) => ({
36
+ id,
37
+ title,
38
+ description,
39
+ }));
40
+ return [...local, ...remote];
41
+ }
42
+ /**
43
+ * Where a template comes from: a local folder (bundled, or the repo checkout during development),
44
+ * an official template's git source, or a git source given directly.
45
+ */
46
+ export function resolveTemplate(template) {
47
+ if (isRemoteTemplate(template))
48
+ return { kind: "remote", source: template };
49
+ const dir = join(templatesDir(), template);
50
+ if (existsSync(join(dir, "package.json")))
51
+ return { kind: "local", dir };
52
+ const official = OFFICIAL_TEMPLATES.find((t) => t.id === template);
53
+ if (official)
54
+ return { kind: "remote", source: pinnedSource(official.source, ownVersion()) };
55
+ throw new Error(`Unknown template "${template}". Available: ${listTemplates()
56
+ .map((t) => t.id)
57
+ .join(", ")}, or a git source like github:user/repo`);
58
+ }
59
+ export function packageName(dir) {
60
+ return (basename(resolve(dir))
61
+ .toLowerCase()
62
+ .replace(/[^a-z0-9-~._]/g, "-")
63
+ .replace(/^[._-]+/, "") || "debuff-game");
64
+ }
65
+ export function isEmptyDir(dir) {
66
+ return !existsSync(dir) || readdirSync(dir).length === 0;
67
+ }
68
+ /** Copy a template into `dir`. Throws if `dir` is non-empty. Returns the resolved path. */
69
+ /** Git-hosted templates: `github:user/repo`, `gitlab:user/repo/subdir#ref`, also `bitbucket:` and `sourcehut:`. */
70
+ export function isRemoteTemplate(template) {
71
+ return /^(github|gitlab|bitbucket|sourcehut):/.test(template);
72
+ }
73
+ /** Download a git-hosted template (via giget, no git binary needed) and scaffold from it. */
74
+ export async function scaffoldRemote(options) {
75
+ const dest = resolve(options.dir);
76
+ if (!isEmptyDir(dest))
77
+ throw new Error(`${dest} is not empty`);
78
+ const { downloadTemplate } = await import("giget");
79
+ const staging = mkdtempSync(join(tmpdir(), "create-debuff-"));
80
+ try {
81
+ const { dir } = await downloadTemplate(options.template, { dir: join(staging, "template"), force: true });
82
+ if (!existsSync(join(dir, "package.json")))
83
+ throw new Error(`Template "${options.template}" has no package.json at its root`);
84
+ return copyTemplate(dir, dest, options.name);
85
+ }
86
+ finally {
87
+ rmSync(staging, { recursive: true, force: true });
88
+ }
89
+ }
90
+ /** Scaffold from a local template. Use `create()` to also handle official and git-hosted templates. */
91
+ export function scaffold(options) {
92
+ const dest = resolve(options.dir);
93
+ if (!isEmptyDir(dest))
94
+ throw new Error(`${dest} is not empty`);
95
+ const resolved = resolveTemplate(options.template ?? "basic");
96
+ if (resolved.kind === "remote")
97
+ throw new Error(`"${options.template}" downloads from ${resolved.source}; use create() or scaffoldRemote()`);
98
+ return copyTemplate(resolved.dir, dest, options.name);
99
+ }
100
+ /** Scaffold from any template: local, official (downloaded on demand) or a git source. */
101
+ export async function create(options) {
102
+ const resolved = resolveTemplate(options.template ?? "basic");
103
+ if (resolved.kind === "local")
104
+ return scaffold(options);
105
+ return scaffoldRemote({ ...options, template: resolved.source });
106
+ }
107
+ function copyTemplate(src, dest, name) {
108
+ const skip = new Set(["template.json", "node_modules", "dist", ".debuff", ".git"]);
109
+ cpSync(src, dest, { recursive: true, filter: (p) => !skip.has(basename(p)) });
110
+ // npm strips .gitignore from published packages, so templates ship it without the dot.
111
+ if (existsSync(join(dest, "gitignore")))
112
+ renameSync(join(dest, "gitignore"), join(dest, ".gitignore"));
113
+ const pkgPath = join(dest, "package.json");
114
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
115
+ pkg.name = name ?? packageName(dest);
116
+ const version = ownVersion();
117
+ // Pin @debuffjp/* to this release; the 0.0.0 placeholders are only meaningful inside the monorepo.
118
+ if (version !== "0.0.0") {
119
+ for (const field of ["dependencies", "devDependencies"]) {
120
+ const deps = pkg[field];
121
+ if (typeof deps === "object")
122
+ for (const dep of Object.keys(deps))
123
+ if (dep.startsWith("@debuffjp/"))
124
+ deps[dep] = `^${version}`;
125
+ }
126
+ }
127
+ writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
128
+ return dest;
129
+ }
130
+ /** Pin an official template to the git tag of this create-debuff release, so it matches the published CLI. */
131
+ export function pinnedSource(source, version) {
132
+ return version === "0.0.0" || source.includes("#") ? source : `${source}#create-debuff@${version}`;
133
+ }
134
+ export function ownVersion() {
135
+ return JSON.parse(readFileSync(join(here, "..", "package.json"), "utf8")).version;
136
+ }
137
+ export function detectPackageManager() {
138
+ const ua = process.env.npm_config_user_agent ?? "";
139
+ if (ua.startsWith("pnpm"))
140
+ return "pnpm";
141
+ if (ua.startsWith("yarn"))
142
+ return "yarn";
143
+ if (ua.startsWith("bun"))
144
+ return "bun";
145
+ return "npm";
146
+ }
147
+ //# sourceMappingURL=scaffold.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,64 @@
1
1
  {
2
2
  "name": "create-debuff",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.2.0",
4
+ "description": "Scaffold a new debuff game: npm create debuff",
5
+ "keywords": [
6
+ "game",
7
+ "gamedev",
8
+ "game-engine",
9
+ "2d",
10
+ "html5-game",
11
+ "browser-game",
12
+ "debuff",
13
+ "create",
14
+ "scaffold",
15
+ "template",
16
+ "starter",
17
+ "game-jam"
18
+ ],
19
+ "license": "MIT",
20
+ "homepage": "https://debuff.jp",
21
+ "bugs": "https://github.com/debuffjp/debuff/issues",
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/debuffjp/debuff.git",
25
+ "directory": "tooling/create-debuff"
26
+ },
27
+ "type": "module",
28
+ "bin": {
29
+ "create-debuff": "bin/create-debuff.js"
30
+ },
31
+ "main": "./dist/index.js",
32
+ "types": "./dist/index.d.ts",
33
+ "exports": {
34
+ ".": {
35
+ "types": "./dist/index.d.ts",
36
+ "default": "./dist/index.js"
37
+ }
38
+ },
39
+ "files": [
40
+ "bin",
41
+ "dist",
42
+ "templates",
43
+ "README.md"
44
+ ],
45
+ "scripts": {
46
+ "build": "tsc -b",
47
+ "prepack": "node scripts/copy-templates.mjs"
48
+ },
49
+ "dependencies": {
50
+ "@clack/prompts": "^1.8.1",
51
+ "giget": "^3.3.1",
52
+ "picocolors": "^1.1.1"
53
+ },
54
+ "devDependencies": {
55
+ "@types/node": "^26.6.5"
56
+ },
57
+ "engines": {
58
+ "node": ">=22"
59
+ },
60
+ "publishConfig": {
61
+ "access": "public",
62
+ "provenance": false
63
+ }
64
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "mcpServers": {
3
+ "debuff": { "command": "npx", "args": ["-y", "@debuffjp/mcp"] }
4
+ }
5
+ }
@@ -0,0 +1,38 @@
1
+ # Agent guide
2
+
3
+ This is a 2D browser game made with **debuff** (https://debuff.jp). These notes are for AI coding agents working on it. The human you're working with makes the creative calls; you do the implementation, testing and chores.
4
+
5
+ ## Commands
6
+
7
+ | Command | What it does |
8
+ | --- | --- |
9
+ | `npm run dev` | Dev server with hot reload. Press <kbd>`</kbd> in the game for the dev panel |
10
+ | `npm test` | Runs `scenarios/*.json` in a headless browser and compares screenshots |
11
+ | `npx debuff fuzz` | Plays the game with random input for a few minutes. Each crash, stuck state or back-and-forth loop is saved as a scenario in `.debuff/fuzz/` that replays it exactly |
12
+ | `npm run build` | Type-checks, builds to `dist/` and prints a size report. Fails if dev-only code leaks |
13
+ | `npm run assets` | Regenerates the asset manifest and lists unused assets |
14
+ | `npx debuff inspect` | Project summary as JSON: packages, plugins, assets, last build size |
15
+ | `npx debuff scenario --update` | Accept new screenshot baselines. **Only after the human has approved the visual change** |
16
+
17
+ ## Layout
18
+
19
+ - `src/main.ts`: the game, which creates `new Game(...)`, scenes (`update`, `render`, `inspect`) and params.
20
+ - `assets/`: source art, audio and data. The manifest and atlases are generated from it, and only files the game references ship. Don't edit generated files.
21
+ - `scenarios/`: JSON test scripts (steps, inputs, expectations, captures). Add one for each mechanic you build.
22
+ - `.mcp.json`: connects the debuff MCP server, so you can play and inspect the running game.
23
+
24
+ ## Work loop
25
+
26
+ 1. **Look before you change.** With the MCP server, call `game_start`. If the human has the game open under `npm run dev`, you attach to it live, so read `game_notes` first: they're moments the human flagged, and `game_replay` with a note's tick saves a scenario that reproduces it. Then use `game_state`, `game_capture` and `game_errors`.
27
+ 2. **Tune before you rewrite.** Feel values (speed, gravity, timings) live in `game.params.define(...)`. Change them with `game_set_param` and show the human before editing code. The human can undo your changes in the dev panel.
28
+ 3. **Make the smallest change that works.** Keep dev-only code inside `if (import.meta.env.DEV)`.
29
+ 4. **Verify.** Run `npm test` and `npm run build`, and check `game_errors` is empty. Before calling a feature done, run `npx debuff fuzz`: to fix a finding, replay its file with `npx debuff scenario <file>`, fix, and replay again until it passes. Errors come back explained: `kind` says whose bug it is (`your-code`, `debuff-usage`, `debuff-bug`, `outside`) and `where` gives the source line.
30
+ 5. **Report** what changed, what you verified, and anything you couldn't check.
31
+
32
+ ## Rules
33
+
34
+ - **Creative direction belongs to the human:** art, feel, difficulty, story and names. Propose two or three options; don't decide.
35
+ - Don't update screenshot baselines (`--update`) without the human's say-so.
36
+ - If `game_errors` reports `debuff-bug`, it's a bug in debuff, not this game. Tell the human and share its `reportUrl`; don't work around debuff internals.
37
+ - Prefer debuff's APIs (`draw`, `input`, `assets`, `params`, `juice`) over adding new runtime dependencies. The game should stay small.
38
+ - API reference: https://debuff.jp/api/ · Guides: https://debuff.jp/docs/getting-started
@@ -0,0 +1 @@
1
+ @AGENTS.md
File without changes
@@ -0,0 +1,3 @@
1
+ node_modules/
2
+ dist/
3
+ .debuff/
@@ -0,0 +1,18 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>My debuff game</title>
7
+ <style>
8
+ html, body { margin: 0; height: 100%; background: #0a0c08; overflow: hidden; }
9
+ /* The game scales the canvas to fit this container (see GameOptions.scale). */
10
+ #app { position: fixed; inset: 0; display: grid; place-items: center; }
11
+ canvas { display: block; outline: none; }
12
+ </style>
13
+ </head>
14
+ <body>
15
+ <main id="app"><canvas id="game" tabindex="0"></canvas></main>
16
+ <script type="module" src="/src/main.ts"></script>
17
+ </body>
18
+ </html>
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@debuffjp/template-basic",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "debuff dev",
8
+ "build": "tsc --noEmit && debuff build",
9
+ "assets": "debuff assets",
10
+ "test": "debuff scenario"
11
+ },
12
+ "dependencies": {
13
+ "@debuffjp/audio": "0.2.0",
14
+ "@debuffjp/core": "0.2.0",
15
+ "@debuffjp/input": "0.2.0",
16
+ "@debuffjp/juice": "0.2.0"
17
+ },
18
+ "devDependencies": {
19
+ "@debuffjp/cli": "0.2.0",
20
+ "typescript": "^7.0.2",
21
+ "@debuffjp/dev": "0.2.0"
22
+ }
23
+ }
@@ -0,0 +1,73 @@
1
+ {
2
+ "$schema": "../node_modules/@debuffjp/cli/schema/scenario.schema.json",
3
+ "steps": [
4
+ {
5
+ "wait": 10
6
+ },
7
+ {
8
+ "expect": {
9
+ "scene": {
10
+ "eq": "play"
11
+ },
12
+ "renderer": {
13
+ "eq": "webgl2"
14
+ },
15
+ "state.player.x": {
16
+ "eq": 160
17
+ }
18
+ }
19
+ },
20
+ {
21
+ "press": "ArrowRight"
22
+ },
23
+ {
24
+ "wait": 30
25
+ },
26
+ {
27
+ "release": "ArrowRight"
28
+ },
29
+ {
30
+ "expect": {
31
+ "state.player.x": {
32
+ "gt": 200
33
+ }
34
+ }
35
+ },
36
+ {
37
+ "set": {
38
+ "player.speed": 400
39
+ }
40
+ },
41
+ {
42
+ "press": "Space"
43
+ },
44
+ {
45
+ "wait": 1
46
+ },
47
+ {
48
+ "release": "Space"
49
+ },
50
+ {
51
+ "wait": 4
52
+ },
53
+ {
54
+ "expect": {
55
+ "state.pops": {
56
+ "eq": 1
57
+ },
58
+ "state.particles": {
59
+ "gt": 0
60
+ }
61
+ }
62
+ },
63
+ {
64
+ "capture": "popped"
65
+ },
66
+ {
67
+ "wait": 60
68
+ },
69
+ {
70
+ "capture": "settled"
71
+ }
72
+ ]
73
+ }
@@ -0,0 +1,79 @@
1
+ import { Audio } from "@debuffjp/audio";
2
+ import { approach, clamp, Game, lerp, type Scene, Storage } from "@debuffjp/core";
3
+ import { devOverlay, devTools } from "@debuffjp/dev";
4
+ import { Input } from "@debuffjp/input";
5
+ import { Particles, squash, Tweens } from "@debuffjp/juice";
6
+
7
+ const canvas = document.querySelector<HTMLCanvasElement>("#game");
8
+ if (!canvas) throw new Error('Missing <canvas id="game">');
9
+
10
+ const game = new Game({ canvas, width: 320, height: 180, background: "#11140d" });
11
+ const input = new Input(game, {
12
+ bindings: {
13
+ left: ["ArrowLeft", "KeyA", "PadLeft", "PadStickLeft"],
14
+ right: ["ArrowRight", "KeyD", "PadRight", "PadStickRight"],
15
+ pop: ["Space", "PadA", "Pointer"],
16
+ },
17
+ });
18
+ const audio = new Audio();
19
+ const tweens = new Tweens();
20
+ const particles = new Particles(() => game.random.next());
21
+ const save = new Storage("my-game", { pops: 0 });
22
+
23
+ // Creative parameters: typed, ranged and live-tunable.
24
+ // Try in the console: __DEBUFF_DEV__.setParam("player", "speed", 300)
25
+ const tuning = game.params.define("player", {
26
+ speed: { type: "number", default: 140, min: 0, max: 600, units: "px/s" },
27
+ accel: { type: "number", default: 1200, min: 0, max: 5000, units: "px/s²" },
28
+ });
29
+
30
+ // prevX is where buff was a step ago: render blends toward x so motion stays smooth on fast displays.
31
+ const player = { x: 160, prevX: 160, y: 120, vx: 0, scaleX: 1, scaleY: 1 };
32
+
33
+ const play: Scene = {
34
+ id: "play",
35
+
36
+ update(dt) {
37
+ player.prevX = player.x;
38
+ let dir = input.axis("left", "right");
39
+ if (input.pointer.down) dir = Math.sign(input.pointer.x - player.x);
40
+ player.vx = approach(player.vx, dir * tuning.values.speed, tuning.values.accel * dt);
41
+ player.x = clamp(player.x + player.vx * dt, 8, game.width - 8);
42
+
43
+ if (input.pressed("pop")) {
44
+ save.set("pops", save.get("pops") + 1);
45
+ squash(tweens, player, 0.35);
46
+ particles.emit({ x: player.x, y: player.y - 8, count: 16, colors: ["#cffb2d", "#f3fecb"], gravity: 200 });
47
+ game.camera.shake(0.3);
48
+ audio.synth({ freq: 660, freqEnd: 220, decay: 0.15 });
49
+ }
50
+ tweens.update(dt);
51
+ particles.update(dt);
52
+ },
53
+
54
+ render(draw, alpha) {
55
+ draw.withCamera(game.camera, () => {
56
+ // buff, the debuff mascot: a lime block with eyes, squashing from its feet.
57
+ draw.push();
58
+ draw.translate(lerp(player.prevX, player.x, alpha), player.y);
59
+ draw.scale(player.scaleX, player.scaleY);
60
+ draw.rect(-8, -16, 16, 16, "#cffb2d");
61
+ draw.rect(-5, -12, 3, 4, "#11140d");
62
+ draw.rect(2, -12, 3, 4, "#11140d");
63
+ draw.pop();
64
+ particles.draw(draw);
65
+ });
66
+ },
67
+
68
+ // Snapshot for scenarios and agents (dev only).
69
+ inspect() {
70
+ return { player: { x: Math.round(player.x), vx: Math.round(player.vx) }, pops: save.get("pops"), particles: particles.count };
71
+ },
72
+ };
73
+
74
+ game.add(play).go("play");
75
+ game.start();
76
+
77
+ // Dev-only plugins: window.__DEBUFF_DEV__ for scenarios and agents, and an overlay (toggle with `) with
78
+ // a frame-time graph and live sliders for every param. Both are stripped from production builds.
79
+ if (import.meta.env.DEV) game.use(devTools({ input })).use(devOverlay());
@@ -0,0 +1,5 @@
1
+ {
2
+ "title": "Basic",
3
+ "bundled": true,
4
+ "description": "Minimal starter: buff on a WebGL2 canvas with input, juice, audio, dev tools and a scenario"
5
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "Bundler",
6
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
7
+ "types": ["@debuffjp/cli/client"],
8
+ "strict": true,
9
+ "noEmit": true,
10
+ "skipLibCheck": true
11
+ },
12
+ "include": ["src"]
13
+ }