@downdraft/cli 0.0.0 → 0.1.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.
Files changed (84) hide show
  1. package/README.md +11 -0
  2. package/package.json +36 -3
  3. package/scripts/default-icon.png +0 -0
  4. package/scripts/package-desktop.mjs +931 -0
  5. package/scripts/package-mobile.mjs +822 -0
  6. package/scripts/package-native.mjs +638 -0
  7. package/src/args.ts +333 -0
  8. package/src/assets.ts +523 -0
  9. package/src/blob-store-s3.ts +145 -0
  10. package/src/build-games.ts +45 -0
  11. package/src/build.ts +40 -0
  12. package/src/bun-env.d.ts +6 -0
  13. package/src/debug.ts +56 -0
  14. package/src/dev.ts +231 -0
  15. package/src/dist.ts +36 -0
  16. package/src/export.ts +38 -0
  17. package/src/index.ts +131 -0
  18. package/src/list-games.ts +37 -0
  19. package/src/mcp.ts +320 -0
  20. package/src/new.ts +63 -0
  21. package/src/paths.ts +101 -0
  22. package/src/plugin-command.ts +214 -0
  23. package/src/process-utils.ts +179 -0
  24. package/src/release.ts +432 -0
  25. package/src/scaffold-plugin.ts +280 -0
  26. package/src/scaffold.ts +207 -0
  27. package/src/test.ts +187 -0
  28. package/src/usage.ts +256 -0
  29. package/templates/_shared/ai-companion/devin-config.eta +11 -0
  30. package/templates/_shared/ai-companion/engine-prompt.eta +155 -0
  31. package/templates/_shared/ai-companion/logging-rule.eta +3 -0
  32. package/templates/_shared/ai-companion/loops-rule.eta +3 -0
  33. package/templates/_shared/partials/config-json-fields.eta +3 -0
  34. package/templates/_shared/partials/dev-deps.eta +8 -0
  35. package/templates/_shared/partials/package-json-fields.eta +12 -0
  36. package/templates/_shared/partials/tsconfig.eta +16 -0
  37. package/templates/_shared/partials/vscode-extensions.eta +11 -0
  38. package/templates/_shared/partials/vscode-settings.eta +29 -0
  39. package/templates/_shared/partials/vscode-tasks.eta +93 -0
  40. package/templates/full/.gitignore.eta +5 -0
  41. package/templates/full/.vscode/extensions.json.eta +1 -0
  42. package/templates/full/.vscode/settings.json.eta +1 -0
  43. package/templates/full/.vscode/tasks.json.eta +1 -0
  44. package/templates/full/README.md.eta +45 -0
  45. package/templates/full/assets/shaders/.eta +0 -0
  46. package/templates/full/downdraft.config.json.eta +10 -0
  47. package/templates/full/package.json.eta +9 -0
  48. package/templates/full/src/entities/.eta +0 -0
  49. package/templates/full/src/game-module.ts.eta +30 -0
  50. package/templates/full/src/native-entry.ts.eta +14 -0
  51. package/templates/full/src/sim-host.ts.eta +19 -0
  52. package/templates/full/src/sim-worker.ts.eta +99 -0
  53. package/templates/full/src/systems/.eta +0 -0
  54. package/templates/full/tsconfig.json.eta +1 -0
  55. package/templates/gamemodule/README.md.eta +32 -0
  56. package/templates/gamemodule/downdraft.config.json.eta +3 -0
  57. package/templates/gamemodule/package.json.eta +9 -0
  58. package/templates/gamemodule/src/game-module.ts.eta +63 -0
  59. package/templates/gamemodule/src/native-entry.ts.eta +14 -0
  60. package/templates/gamemodule/src/sim-host.ts.eta +25 -0
  61. package/templates/gamemodule/src/sim-worker.ts.eta +24 -0
  62. package/templates/gamemodule/tsconfig.json.eta +1 -0
  63. package/templates/minimal/.gitignore.eta +5 -0
  64. package/templates/minimal/.vscode/extensions.json.eta +1 -0
  65. package/templates/minimal/.vscode/settings.json.eta +1 -0
  66. package/templates/minimal/.vscode/tasks.json.eta +1 -0
  67. package/templates/minimal/README.md.eta +32 -0
  68. package/templates/minimal/downdraft.config.json.eta +3 -0
  69. package/templates/minimal/package.json.eta +9 -0
  70. package/templates/minimal/src/game-module.ts.eta +44 -0
  71. package/templates/minimal/src/native-entry.ts.eta +14 -0
  72. package/templates/minimal/tsconfig.json.eta +1 -0
  73. package/templates/physics/.gitignore.eta +5 -0
  74. package/templates/physics/.vscode/extensions.json.eta +1 -0
  75. package/templates/physics/.vscode/settings.json.eta +1 -0
  76. package/templates/physics/.vscode/tasks.json.eta +1 -0
  77. package/templates/physics/README.md.eta +36 -0
  78. package/templates/physics/downdraft.config.json.eta +6 -0
  79. package/templates/physics/package.json.eta +9 -0
  80. package/templates/physics/src/game-module.ts.eta +29 -0
  81. package/templates/physics/src/native-entry.ts.eta +14 -0
  82. package/templates/physics/src/sim-host.ts.eta +19 -0
  83. package/templates/physics/src/sim-worker.ts.eta +155 -0
  84. package/templates/physics/tsconfig.json.eta +1 -0
@@ -0,0 +1,45 @@
1
+ # <%= it.name %>
2
+
3
+ <% if (it.description) { %><%= it.description %><% } else { %>A full-featured game built with the DownDraft Engine.<% } %>
4
+
5
+ ## Getting Started
6
+
7
+ ```bash
8
+ # Install dependencies
9
+ bun install
10
+
11
+ # Start dev server (includes DevTools panel)
12
+ npm run dev
13
+
14
+ # Build for production
15
+ npm run build
16
+
17
+ # Export for distribution
18
+ npm run export
19
+ ```
20
+
21
+ ## Project Structure
22
+
23
+ ```
24
+ src/ Game source code
25
+ native-entry.ts Native runtime entry (draft dev)
26
+ systems/ Game systems (ECS)
27
+ entities/ Entity definitions and prefabs
28
+ assets/ Game assets
29
+ shaders/ Custom WGSL shaders
30
+ models/ 3D models (GLTF, PLY, 3DS)
31
+ textures/ Textures (PNG, WebP, KTX2, DDS, HDR)
32
+ downdraft.config.json Engine configuration
33
+ ```
34
+
35
+ ## Plugins
36
+
37
+ - **@downdraft/engine/libraries/water** — Gerstner wave simulation, refraction, reflection
38
+ - **@downdraft/engine/libraries/physics-rapier** — Rapier physics backend
39
+ - **@downdraft/engine/libraries/marching-cubes** — Volumetric deformable terrain
40
+ - **@downdraft/engine/libraries/models** — Model loading (GLTF/GLB, PLY, 3DS)
41
+ - **@downdraft/engine/modules/devtools** — DevTools panel with scene inspector, GPU debugging
42
+
43
+ ## Engine
44
+
45
+ Built with [DownDraft Engine](https://github.com/downdraft-engine) — a TypeScript-first game engine on WebGPU — native runtime (Bun + SDL + wgpu).
File without changes
@@ -0,0 +1,10 @@
1
+ {
2
+ <%~ include("_shared/partials/config-json-fields", it) %>,
3
+ "plugins": [
4
+ "physics-rapier",
5
+ "water",
6
+ "marching-cubes",
7
+ "models",
8
+ "devtools"
9
+ ]
10
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "<%= it.name %>",
3
+ <%~ include("_shared/partials/package-json-fields", it) %>
4
+ "dependencies": {
5
+ "@downdraft/engine": "^0.1.0",
6
+ "@downdraft/platform-native": "^0.1.0"
7
+ },
8
+ <%~ include("_shared/partials/dev-deps", it) %>
9
+ }
File without changes
@@ -0,0 +1,30 @@
1
+ import { GameRenderer } from "@downdraft/engine";
2
+ import type { GameModule } from "@downdraft/engine/app/renderer";
3
+ import { SimHost } from "./sim-host";
4
+
5
+ // ============================================================================
6
+ // Full template — ECS sim worker + GameRenderer + engine libraries
7
+ //
8
+ // The sim runs in sim-worker.ts (a Web Worker): an ECS World with a rotation
9
+ // system. The SAME module drives both entry points:
10
+ // src/native-entry.ts — Bun + SDL + wgpu-native (draft dev, the default)
11
+ // Engine libraries can be declared via GameModule.libraries[] for automatic
12
+ // SAB allocation + DI wiring.
13
+ // ============================================================================
14
+
15
+ export const gameModule: GameModule = {
16
+ // ── Renderer + Sim ──
17
+ renderer: (canvas) => new GameRenderer(canvas),
18
+ sim: () => new SimHost(),
19
+ simConfig: { seed: 12345 },
20
+
21
+ // ── Post-init wiring ──
22
+ onReady: (ctx) => {
23
+ console.log("[game] ready", { simSAB: ctx.simSAB, inputSAB: ctx.inputSAB });
24
+ },
25
+
26
+ // ── Cleanup ──
27
+ onDispose: () => {
28
+ console.log("[game] disposed");
29
+ },
30
+ };
@@ -0,0 +1,14 @@
1
+ import { runNativeGameModule } from "@downdraft/platform-native";
2
+ import { gameModule } from "./game-module";
3
+
4
+ // Native entry — `draft dev`/`draft release` runtime (winit + wgpu under Bun, Node, or Deno).
5
+ // Saves, MCP, display info, and screenshots work through the in-process
6
+ // HostAPI bridge.
7
+
8
+ await runNativeGameModule(gameModule, {
9
+ title: "<%= it.name %> — Native",
10
+ appId: "downdraft-<%= it.name %>",
11
+ }).catch((e) => {
12
+ console.error("[native-entry] Fatal:", e);
13
+ process.exit(1);
14
+ });
@@ -0,0 +1,19 @@
1
+ import { SimWorkerHost } from "@downdraft/engine";
2
+
3
+ // Sim worker host — spawns sim-worker.ts on the main (renderer) thread and
4
+ // exposes the sim SAB + event stream to startGame().
5
+ export class SimHost extends SimWorkerHost {
6
+ constructor() {
7
+ // Replace with your game's sim-buffer allocation (see the SAB APIs in
8
+ // @downdraft/engine, e.g. defineRecordBuffer/allocateSimBuffer).
9
+ super(new SharedArrayBuffer(4096));
10
+ }
11
+
12
+ protected createWorker(): Worker {
13
+ return new Worker(new URL("./sim-worker.ts", import.meta.url), { type: "module" });
14
+ }
15
+
16
+ protected async onInit(): Promise<void> {
17
+ await this.getProxy()!.proxy.init(this.getSimBuffer());
18
+ }
19
+ }
@@ -0,0 +1,99 @@
1
+ import {
2
+ c,
3
+ Component,
4
+ createLogger,
5
+ createSimWorker,
6
+ Query,
7
+ q,
8
+ spawn,
9
+ Stage,
10
+ systemWithParams,
11
+ World,
12
+ } from "@downdraft/engine";
13
+
14
+ const log = createLogger();
15
+
16
+ // Full template sim worker — an ECS World with a rotation system.
17
+ // createSimWorker owns the tick loop, worker protocol, and stats;
18
+ // this file provides onInit + onTick.
19
+
20
+ // --- Components ---
21
+
22
+ type TransformData = {
23
+ position: [number, number, number];
24
+ rotation: [number, number, number];
25
+ scale: number;
26
+ };
27
+
28
+ const Transform = Component.register<TransformData>("Transform", {
29
+ position: [0, 0, 0],
30
+ rotation: [0, 0, 0],
31
+ scale: 1,
32
+ });
33
+
34
+ type RenderableData = {
35
+ mesh: string;
36
+ color: [number, number, number];
37
+ };
38
+
39
+ const Renderable = Component.register<RenderableData>("Renderable", {
40
+ mesh: "cube",
41
+ color: [1, 1, 1],
42
+ });
43
+
44
+ // --- Queries ---
45
+
46
+ const rotateQuery = new Query([Transform.id, Renderable.id]);
47
+
48
+ let world: World;
49
+
50
+ createSimWorker({
51
+ fixedDt: 1 / 60,
52
+
53
+ onInit() {
54
+ world = new World();
55
+
56
+ // Spawn ground entity
57
+ spawn(world,
58
+ c(Transform, { position: [0, -0.5, 0], scale: 10 }),
59
+ c(Renderable, { mesh: "cube", color: [0.3, 0.5, 0.3] }),
60
+ );
61
+
62
+ // Spawn rotating entities
63
+ for (let i = 0; i < 5; i++) {
64
+ spawn(world,
65
+ c(Transform, { position: [(i - 2) * 2, 0.5, 0] }),
66
+ c(Renderable, {
67
+ mesh: i % 2 === 0 ? "cube" : "sphere",
68
+ color: [Math.random(), Math.random(), Math.random()],
69
+ }),
70
+ );
71
+ }
72
+
73
+ // Register system using systemWithParams for typed dependency injection
74
+ const rotateSystem = systemWithParams(
75
+ "rotate-entities",
76
+ Stage.Update,
77
+ [q(Transform, Renderable)],
78
+ (ctx, entities) => {
79
+ entities.iterate(ctx.tick, (_entity, comps) => {
80
+ const transform = comps[0] as TransformData;
81
+ const [rx, ry, rz] = transform.rotation;
82
+ transform.rotation = [rx, ry + ctx.dt * 0.5, rz];
83
+ });
84
+ },
85
+ );
86
+
87
+ world.schedule.addSystem(rotateSystem);
88
+
89
+ log.info("sim", "full demo initialized — 5 entities on a ground plane");
90
+ },
91
+
92
+ onTick(dt) {
93
+ world.step(dt);
94
+ },
95
+
96
+ onShutdown() {
97
+ log.info("sim", "sim worker shutdown");
98
+ },
99
+ });
File without changes
@@ -0,0 +1 @@
1
+ <%~ include("_shared/partials/tsconfig", it) %>
@@ -0,0 +1,32 @@
1
+ # <%= it.name %>
2
+
3
+ <% if (it.description) { %><%= it.description %><% } else { %>A game built with the DownDraft Engine.<% } %>
4
+
5
+ ## Getting Started
6
+
7
+ ```bash
8
+ # Install dependencies
9
+ bun install
10
+
11
+ # Start dev server
12
+ npm run dev
13
+
14
+ # Build for production
15
+ npm run build
16
+
17
+ # Export for distribution
18
+ npm run export
19
+ ```
20
+
21
+ ## Project Structure
22
+
23
+ ```
24
+ src/ Game source code
25
+ native-entry.ts Native runtime entry (draft dev)
26
+ assets/ Game assets (models, textures, shaders)
27
+ downdraft.config.json Engine configuration
28
+ ```
29
+
30
+ ## Engine
31
+
32
+ Built with [DownDraft Engine](https://github.com/downdraft-engine) — a TypeScript-first game engine on WebGPU — native runtime (Bun + SDL + wgpu).
@@ -0,0 +1,3 @@
1
+ {
2
+ <%~ include("_shared/partials/config-json-fields", it) %>
3
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "<%= it.name %>",
3
+ <%~ include("_shared/partials/package-json-fields", it) %>
4
+ "dependencies": {
5
+ "@downdraft/engine": "^0.1.0",
6
+ "@downdraft/platform-native": "^0.1.0"
7
+ },
8
+ <%~ include("_shared/partials/dev-deps", it) %>
9
+ }
@@ -0,0 +1,63 @@
1
+ import { GameRenderer } from "@downdraft/engine";
2
+ import type { GameModule, SimWorkerSeed } from "@downdraft/engine/app/renderer";
3
+ import { WaterLib } from "@downdraft/engine/libraries/water";
4
+ import { SimHost } from "./sim-host";
5
+
6
+ // ============================================================================
7
+ // GameModule template — declarative game with libraries + plugins
8
+ //
9
+ // The SAME module drives both entry points:
10
+ // src/native-entry.ts — Bun + SDL + wgpu-native (draft dev, the default)
11
+ //
12
+ // This template shows the full declarative pattern:
13
+ // - Engine libraries (WaterLib) for SAB allocation + DI tokens
14
+ // - Declarative event routing (events map)
15
+ // - Save config
16
+ // - Game-specific hooks (onReady, onDispose)
17
+ //
18
+ // Feature modules such as @downdraft/engine/modules/terrain can be registered on the
19
+ // renderer's module host inside onReady.
20
+ // ============================================================================
21
+
22
+ export const gameModule: GameModule = {
23
+ // ── Engine libraries (declarative SAB allocation + DI tokens) ──
24
+ libraries: [WaterLib],
25
+
26
+ // ── Renderer + Sim ──
27
+ renderer: (canvas) => new GameRenderer(canvas),
28
+ sim: (seed?: SimWorkerSeed) => new SimHost(seed?.libraryBuffers),
29
+ simConfig: { seed: 12345, gamemode: 0, rules: {} },
30
+
31
+ // ── Sim→Renderer event routing (declarative) ──
32
+ events: {
33
+ ready: (_data, _ctx) => {
34
+ console.log("[game] Sim ready");
35
+ },
36
+ error: (data) => {
37
+ console.error("[game] Sim error:", data);
38
+ },
39
+ },
40
+
41
+ // ── Save ──
42
+ save: {
43
+ mode: "auto",
44
+ engineVersion: "0.1.0",
45
+ maxGenerations: 3,
46
+ },
47
+
48
+ // ── Post-init wiring ──
49
+ onReady: (ctx) => {
50
+ // Library-allocated SABs are available on ctx.extraBuffers, keyed by the
51
+ // library descriptor's channel name.
52
+ console.log("[game] ready", {
53
+ simSAB: ctx.simSAB,
54
+ inputSAB: ctx.inputSAB,
55
+ water: ctx.extraBuffers.water,
56
+ });
57
+ },
58
+
59
+ // ── Cleanup ──
60
+ onDispose: () => {
61
+ console.log("[game] disposed");
62
+ },
63
+ };
@@ -0,0 +1,14 @@
1
+ import { runNativeGameModule } from "@downdraft/platform-native";
2
+ import { gameModule } from "./game-module";
3
+
4
+ // Native entry — `draft dev`/`draft release` runtime (winit + wgpu under Bun, Node, or Deno).
5
+ // Saves, MCP, display info, and screenshots work through the in-process
6
+ // HostAPI bridge.
7
+
8
+ await runNativeGameModule(gameModule, {
9
+ title: "<%= it.name %> — Native",
10
+ appId: "downdraft-<%= it.name %>",
11
+ }).catch((e) => {
12
+ console.error("[native-entry] Fatal:", e);
13
+ process.exit(1);
14
+ });
@@ -0,0 +1,25 @@
1
+ import { SimWorkerHost } from "@downdraft/engine";
2
+
3
+ // Sim worker host — spawns sim-worker.ts on the main (renderer) thread and
4
+ // exposes the sim SAB + event stream to startGame().
5
+ //
6
+ // `libraryBuffers` are the SABs allocated by EngineLibrary descriptors in
7
+ // GameModule.libraries[] — forwarded to the worker via the init RPC.
8
+ export class SimHost extends SimWorkerHost {
9
+ private libraryBuffers?: Record<string, SharedArrayBuffer>;
10
+
11
+ constructor(libraryBuffers?: Record<string, SharedArrayBuffer>) {
12
+ // Replace with your game's sim-buffer allocation (see the SAB APIs in
13
+ // @downdraft/engine, e.g. defineRecordBuffer/allocateSimBuffer).
14
+ super(new SharedArrayBuffer(4096));
15
+ this.libraryBuffers = libraryBuffers;
16
+ }
17
+
18
+ protected createWorker(): Worker {
19
+ return new Worker(new URL("./sim-worker.ts", import.meta.url), { type: "module" });
20
+ }
21
+
22
+ protected async onInit(): Promise<void> {
23
+ await this.getProxy()!.proxy.init(this.getSimBuffer(), this.libraryBuffers);
24
+ }
25
+ }
@@ -0,0 +1,24 @@
1
+ import { createSimWorker } from "@downdraft/engine";
2
+
3
+ // Sim worker — runs the fixed-timestep simulation loop in a Web Worker.
4
+ // createSimWorker handles the tick loop, pause/resume/step control, stats,
5
+ // and the "ready" event; you provide onInit + onTick.
6
+ //
7
+ // The init RPC args sent by SimHost arrive after `control`:
8
+ // proxy.init(simBuffer, libraryBuffers) → onInit(sab, control, libraryBuffers)
9
+ createSimWorker({
10
+ fixedDt: 1 / 60,
11
+
12
+ onInit(sab, _control, libraryBuffers?: Record<string, SharedArrayBuffer>) {
13
+ // `sab` is the sim state buffer shared with the renderer.
14
+ // `libraryBuffers` are the SABs allocated by your EngineLibrary
15
+ // descriptors (e.g. WaterLib's water channel) — wire them into your sim.
16
+ void sab;
17
+ void libraryBuffers;
18
+ },
19
+
20
+ onTick(dt, _ctx) {
21
+ // Step your simulation here. `dt` equals fixedDt.
22
+ void dt;
23
+ },
24
+ });
@@ -0,0 +1 @@
1
+ <%~ include("_shared/partials/tsconfig", it) %>
@@ -0,0 +1,5 @@
1
+ node_modules/
2
+ dist/
3
+ export/
4
+ *.log
5
+ .DS_Store
@@ -0,0 +1 @@
1
+ <%~ include("_shared/partials/vscode-extensions", it) %>
@@ -0,0 +1 @@
1
+ <%~ include("_shared/partials/vscode-settings", it) %>
@@ -0,0 +1 @@
1
+ <%~ include("_shared/partials/vscode-tasks", it) %>
@@ -0,0 +1,32 @@
1
+ # <%= it.name %>
2
+
3
+ <% if (it.description) { %><%= it.description %><% } else { %>A game built with the DownDraft Engine.<% } %>
4
+
5
+ ## Getting Started
6
+
7
+ ```bash
8
+ # Install dependencies
9
+ bun install
10
+
11
+ # Start dev server
12
+ npm run dev
13
+
14
+ # Build for production
15
+ npm run build
16
+
17
+ # Export for distribution
18
+ npm run export
19
+ ```
20
+
21
+ ## Project Structure
22
+
23
+ ```
24
+ src/ Game source code
25
+ native-entry.ts Native runtime entry (draft dev)
26
+ assets/ Game assets (models, textures, shaders)
27
+ downdraft.config.json Engine configuration
28
+ ```
29
+
30
+ ## Engine
31
+
32
+ Built with [DownDraft Engine](https://github.com/downdraft-engine) — a TypeScript-first game engine on WebGPU — native runtime (Bun + SDL + wgpu).
@@ -0,0 +1,3 @@
1
+ {
2
+ <%~ include("_shared/partials/config-json-fields", it) %>
3
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "<%= it.name %>",
3
+ <%~ include("_shared/partials/package-json-fields", it) %>
4
+ "dependencies": {
5
+ "@downdraft/engine": "^0.1.0",
6
+ "@downdraft/platform-native": "^0.1.0"
7
+ },
8
+ <%~ include("_shared/partials/dev-deps", it) %>
9
+ }
@@ -0,0 +1,44 @@
1
+ import type { GameModule } from "@downdraft/engine/app/renderer";
2
+
3
+ // ============================================================================
4
+ // Minimal game template — declarative GameModule
5
+ //
6
+ // The SAME module drives both entry points:
7
+ // src/native-entry.ts — Bun + SDL + wgpu-native (draft dev, the default)
8
+ //
9
+ // For a more complete example with WebGPU rendering, sim worker, and
10
+ // libraries, see the "full" template (`draft init --template full`).
11
+ // ============================================================================
12
+
13
+ export const gameModule: GameModule = {
14
+ // Renderer factory — creates the renderer from a canvas element
15
+ renderer: (canvas) => ({
16
+ async init() { return true; },
17
+ setBuffers() {},
18
+ setupInputListeners() {},
19
+ render() {},
20
+ stop() {},
21
+ getFPS() { return 0; },
22
+ }),
23
+
24
+ // Sim worker factory — creates the sim worker
25
+ sim: () => ({
26
+ async start(_config: unknown) {},
27
+ onEvent(_cb: (msg: any) => void) {},
28
+ getSimBuffer() { return new SharedArrayBuffer(1024); },
29
+ getInputBuffer() { return new SharedArrayBuffer(1024); },
30
+ }),
31
+
32
+ // Sim config (passed to sim.start())
33
+ simConfig: { seed: 12345 },
34
+
35
+ // Post-init wiring — called after renderer init + sim start
36
+ onReady: (ctx) => {
37
+ console.log("[game] ready", { sim: ctx.sim, renderer: ctx.renderer });
38
+ },
39
+
40
+ // Cleanup — called on hot-reload dispose
41
+ onDispose: () => {
42
+ console.log("[game] disposed");
43
+ },
44
+ };
@@ -0,0 +1,14 @@
1
+ import { runNativeGameModule } from "@downdraft/platform-native";
2
+ import { gameModule } from "./game-module";
3
+
4
+ // Native entry — `draft dev`/`draft release` runtime (winit + wgpu under Bun, Node, or Deno).
5
+ // Saves, MCP, display info, and screenshots work through the in-process
6
+ // HostAPI bridge.
7
+
8
+ await runNativeGameModule(gameModule, {
9
+ title: "<%= it.name %> — Native",
10
+ appId: "downdraft-<%= it.name %>",
11
+ }).catch((e) => {
12
+ console.error("[native-entry] Fatal:", e);
13
+ process.exit(1);
14
+ });
@@ -0,0 +1 @@
1
+ <%~ include("_shared/partials/tsconfig", it) %>
@@ -0,0 +1,5 @@
1
+ node_modules/
2
+ dist/
3
+ export/
4
+ *.log
5
+ .DS_Store
@@ -0,0 +1 @@
1
+ <%~ include("_shared/partials/vscode-extensions", it) %>
@@ -0,0 +1 @@
1
+ <%~ include("_shared/partials/vscode-settings", it) %>
@@ -0,0 +1 @@
1
+ <%~ include("_shared/partials/vscode-tasks", it) %>
@@ -0,0 +1,36 @@
1
+ # <%= it.name %>
2
+
3
+ <% if (it.description) { %><%= it.description %><% } else { %>A physics-based game built with the DownDraft Engine.<% } %>
4
+
5
+ ## Getting Started
6
+
7
+ ```bash
8
+ # Install dependencies
9
+ bun install
10
+
11
+ # Start dev server
12
+ npm run dev
13
+
14
+ # Build for production
15
+ npm run build
16
+
17
+ # Export for distribution
18
+ npm run export
19
+ ```
20
+
21
+ ## Project Structure
22
+
23
+ ```
24
+ src/ Game source code
25
+ native-entry.ts Native runtime entry (draft dev)
26
+ assets/ Game assets (models, textures, shaders)
27
+ downdraft.config.json Engine configuration (physics-rapier plugin enabled)
28
+ ```
29
+
30
+ ## Plugins
31
+
32
+ - **@downdraft/engine/libraries/physics-rapier** — Rapier physics backend for rigid body simulation, colliders, and raycasting.
33
+
34
+ ## Engine
35
+
36
+ Built with [DownDraft Engine](https://github.com/downdraft-engine) — a TypeScript-first game engine on WebGPU — native runtime (Bun + SDL + wgpu).
@@ -0,0 +1,6 @@
1
+ {
2
+ <%~ include("_shared/partials/config-json-fields", it) %>,
3
+ "plugins": [
4
+ "physics-rapier"
5
+ ]
6
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "<%= it.name %>",
3
+ <%~ include("_shared/partials/package-json-fields", it) %>
4
+ "dependencies": {
5
+ "@downdraft/engine": "^0.1.0",
6
+ "@downdraft/platform-native": "^0.1.0"
7
+ },
8
+ <%~ include("_shared/partials/dev-deps", it) %>
9
+ }
@@ -0,0 +1,29 @@
1
+ import { GameRenderer } from "@downdraft/engine";
2
+ import type { GameModule } from "@downdraft/engine/app/renderer";
3
+ import { SimHost } from "./sim-host";
4
+
5
+ // ============================================================================
6
+ // Physics template — ECS sim worker + GameRenderer
7
+ //
8
+ // The sim runs in sim-worker.ts (a Web Worker): an ECS World with gravity and
9
+ // integration systems that spawns falling shapes. The SAME module drives
10
+ // both entry points:
11
+ // src/native-entry.ts — Bun + SDL + wgpu-native (draft dev, the default)
12
+ // ============================================================================
13
+
14
+ export const gameModule: GameModule = {
15
+ // ── Renderer + Sim ──
16
+ renderer: (canvas) => new GameRenderer(canvas),
17
+ sim: () => new SimHost(),
18
+ simConfig: { seed: 12345 },
19
+
20
+ // ── Post-init wiring ──
21
+ onReady: (ctx) => {
22
+ console.log("[game] ready", { simSAB: ctx.simSAB, inputSAB: ctx.inputSAB });
23
+ },
24
+
25
+ // ── Cleanup ──
26
+ onDispose: () => {
27
+ console.log("[game] disposed");
28
+ },
29
+ };