@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.
- package/README.md +11 -0
- package/package.json +36 -3
- package/scripts/default-icon.png +0 -0
- package/scripts/package-desktop.mjs +931 -0
- package/scripts/package-mobile.mjs +822 -0
- package/scripts/package-native.mjs +638 -0
- package/src/args.ts +333 -0
- package/src/assets.ts +523 -0
- package/src/blob-store-s3.ts +145 -0
- package/src/build-games.ts +45 -0
- package/src/build.ts +40 -0
- package/src/bun-env.d.ts +6 -0
- package/src/debug.ts +56 -0
- package/src/dev.ts +231 -0
- package/src/dist.ts +36 -0
- package/src/export.ts +38 -0
- package/src/index.ts +131 -0
- package/src/list-games.ts +37 -0
- package/src/mcp.ts +320 -0
- package/src/new.ts +63 -0
- package/src/paths.ts +101 -0
- package/src/plugin-command.ts +214 -0
- package/src/process-utils.ts +179 -0
- package/src/release.ts +432 -0
- package/src/scaffold-plugin.ts +280 -0
- package/src/scaffold.ts +207 -0
- package/src/test.ts +187 -0
- package/src/usage.ts +256 -0
- package/templates/_shared/ai-companion/devin-config.eta +11 -0
- package/templates/_shared/ai-companion/engine-prompt.eta +155 -0
- package/templates/_shared/ai-companion/logging-rule.eta +3 -0
- package/templates/_shared/ai-companion/loops-rule.eta +3 -0
- package/templates/_shared/partials/config-json-fields.eta +3 -0
- package/templates/_shared/partials/dev-deps.eta +8 -0
- package/templates/_shared/partials/package-json-fields.eta +12 -0
- package/templates/_shared/partials/tsconfig.eta +16 -0
- package/templates/_shared/partials/vscode-extensions.eta +11 -0
- package/templates/_shared/partials/vscode-settings.eta +29 -0
- package/templates/_shared/partials/vscode-tasks.eta +93 -0
- package/templates/full/.gitignore.eta +5 -0
- package/templates/full/.vscode/extensions.json.eta +1 -0
- package/templates/full/.vscode/settings.json.eta +1 -0
- package/templates/full/.vscode/tasks.json.eta +1 -0
- package/templates/full/README.md.eta +45 -0
- package/templates/full/assets/shaders/.eta +0 -0
- package/templates/full/downdraft.config.json.eta +10 -0
- package/templates/full/package.json.eta +9 -0
- package/templates/full/src/entities/.eta +0 -0
- package/templates/full/src/game-module.ts.eta +30 -0
- package/templates/full/src/native-entry.ts.eta +14 -0
- package/templates/full/src/sim-host.ts.eta +19 -0
- package/templates/full/src/sim-worker.ts.eta +99 -0
- package/templates/full/src/systems/.eta +0 -0
- package/templates/full/tsconfig.json.eta +1 -0
- package/templates/gamemodule/README.md.eta +32 -0
- package/templates/gamemodule/downdraft.config.json.eta +3 -0
- package/templates/gamemodule/package.json.eta +9 -0
- package/templates/gamemodule/src/game-module.ts.eta +63 -0
- package/templates/gamemodule/src/native-entry.ts.eta +14 -0
- package/templates/gamemodule/src/sim-host.ts.eta +25 -0
- package/templates/gamemodule/src/sim-worker.ts.eta +24 -0
- package/templates/gamemodule/tsconfig.json.eta +1 -0
- package/templates/minimal/.gitignore.eta +5 -0
- package/templates/minimal/.vscode/extensions.json.eta +1 -0
- package/templates/minimal/.vscode/settings.json.eta +1 -0
- package/templates/minimal/.vscode/tasks.json.eta +1 -0
- package/templates/minimal/README.md.eta +32 -0
- package/templates/minimal/downdraft.config.json.eta +3 -0
- package/templates/minimal/package.json.eta +9 -0
- package/templates/minimal/src/game-module.ts.eta +44 -0
- package/templates/minimal/src/native-entry.ts.eta +14 -0
- package/templates/minimal/tsconfig.json.eta +1 -0
- package/templates/physics/.gitignore.eta +5 -0
- package/templates/physics/.vscode/extensions.json.eta +1 -0
- package/templates/physics/.vscode/settings.json.eta +1 -0
- package/templates/physics/.vscode/tasks.json.eta +1 -0
- package/templates/physics/README.md.eta +36 -0
- package/templates/physics/downdraft.config.json.eta +6 -0
- package/templates/physics/package.json.eta +9 -0
- package/templates/physics/src/game-module.ts.eta +29 -0
- package/templates/physics/src/native-entry.ts.eta +14 -0
- package/templates/physics/src/sim-host.ts.eta +19 -0
- package/templates/physics/src/sim-worker.ts.eta +155 -0
- 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
|
|
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,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 @@
|
|
|
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,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 @@
|
|
|
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,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
|
+
};
|