dotframe 0.1.2 → 0.1.4

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.
@@ -4,9 +4,15 @@
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "dotframe dev",
7
- "test": "dotframe replay verify replays/*.json"
7
+ "test": "dotframe replay verify replays/*.json",
8
+ "typecheck": "tsc"
8
9
  },
9
10
  "dependencies": {
10
11
  "dotframe": "^0.1.0"
12
+ },
13
+ "devDependencies": {
14
+ "@types/bun": "^1.3.0",
15
+ "@webgpu/types": "^0.1.74",
16
+ "typescript": "^5.9.0"
11
17
  }
12
18
  }
@@ -0,0 +1,21 @@
1
+ // Builds the web target into dist/web with a content-hashed bundle (main.<hash>.js) and a never-cached
2
+ // index.html, so browsers and Discord's proxy never run a stale build.
3
+ import { cpSync, existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
4
+
5
+ const out = "dist/web";
6
+ rmSync(out, { recursive: true, force: true });
7
+ mkdirSync(out, { recursive: true });
8
+ const built = await Bun.build({ entrypoints: ["main.web.ts"], target: "browser", minify: true, naming: "main.[hash].[ext]", outdir: out });
9
+ if (!built.success) {
10
+ for (const log of built.logs) console.error(log);
11
+ process.exit(1);
12
+ }
13
+ const bundle = built.outputs[0].path.split("/").pop() ?? "main.js";
14
+ const html = await Bun.file("index.html").text();
15
+ writeFileSync(`${out}/index.html`, html.replace("./main.js", `./${bundle}`));
16
+ writeFileSync(
17
+ `${out}/vercel.json`,
18
+ `${JSON.stringify({ headers: [{ source: "/index.html", headers: [{ key: "Cache-Control", value: "no-cache" }] }, { source: "/", headers: [{ key: "Cache-Control", value: "no-cache" }] }] }, null, 2)}\n`,
19
+ );
20
+ if (existsSync("assets")) cpSync("assets", `${out}/assets`, { recursive: true });
21
+ console.log(`${out}/${bundle}`);
@@ -7,6 +7,8 @@ export default defineSim({
7
7
  window: WINDOW,
8
8
  options: {},
9
9
  neutral: 0,
10
+ // Frames your netplay may roll back; desync warns when a link needs more. Match it when you add online play.
11
+ rollbackWindow: 20,
10
12
  encode,
11
13
  random: randomInput,
12
14
  create: (_platform: SimPlatform): SimRun => {
@@ -0,0 +1,29 @@
1
+ // Shared by main.web.ts and main.native.ts: fixed 60 Hz steps from the keyboard, then one render per frame.
2
+ import { createDraw2D } from "dotframe/src/draw2d";
3
+ import type { Frame, Setup } from "dotframe/src/gpu";
4
+ import { Key } from "dotframe/src/input";
5
+ import type { Platform } from "dotframe/src/platform";
6
+ import { createGame, keyInput, PLAYERS, render, step, WINDOW } from "./game";
7
+
8
+ const STEP = 1 / 60;
9
+
10
+ export function createSetup(): Setup {
11
+ return ({ gpu, input }: Platform): Frame => {
12
+ const draw = createDraw2D(gpu, WINDOW.width, WINDOW.height);
13
+ const game = createGame(Math.floor(Math.random() * 1e9));
14
+ let simulated = -1;
15
+ return (time: number): boolean => {
16
+ if (simulated < 0) simulated = time;
17
+ // Fixed steps, so every target plays exactly what dotframe sim simulates.
18
+ for (let n = 0; simulated + STEP <= time && n < 5; n++) {
19
+ const keys = [keyInput(input, [Key.A, Key.D, Key.W, Key.J]), keyInput(input, [Key.Left, Key.Right, Key.Up, Key.L])];
20
+ step(game, keys.slice(0, PLAYERS));
21
+ simulated += STEP;
22
+ }
23
+ draw.begin();
24
+ render(game, draw);
25
+ draw.end({ r: 0, g: 0, b: 0 });
26
+ return true;
27
+ };
28
+ };
29
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "Bundler",
6
+ "lib": ["ES2022", "DOM"],
7
+ "types": ["@webgpu/types", "bun"],
8
+ "strict": true,
9
+ "noEmit": true,
10
+ "skipLibCheck": true
11
+ },
12
+ "include": ["*.ts", "src", "scripts"],
13
+ "exclude": ["main.native.ts"]
14
+ }
@@ -88,7 +88,15 @@ export function step(game: Game, inputs: number[]): void {
88
88
  if (f.y >= GROUND) f.vy = 0;
89
89
  if (f.x < -100 || f.x > WINDOW.width + 100) {
90
90
  f.stocks -= 1;
91
- Object.assign(f, { ...fighter(WINDOW.width / 2, f.facing), stocks: f.stocks });
91
+ // Field by field: scriptc compiles records, not Object.assign.
92
+ f.x = WINDOW.width / 2;
93
+ f.y = GROUND;
94
+ f.vx = 0;
95
+ f.vy = 0;
96
+ f.damage = 0;
97
+ f.cooldown = 0;
98
+ f.stun = 0;
99
+ f.held = 0;
92
100
  if (f.stocks === 0) game.winner = 1 - i;
93
101
  }
94
102
  });
@@ -43,13 +43,9 @@ export interface Game {
43
43
  }
44
44
 
45
45
  export function createGame(_seed: number): Game {
46
- const coins = [
47
- { x: 220, y: 370 },
48
- { x: 470, y: 290 },
49
- { x: 720, y: 210 },
50
- { x: 480, y: 120 },
51
- { x: 880, y: 470 },
52
- ].map((c) => ({ ...c, taken: false }));
46
+ const spots = [220, 370, 470, 290, 720, 210, 480, 120, 880, 470];
47
+ const coins: { x: number; y: number; taken: boolean }[] = [];
48
+ for (let i = 0; i < spots.length; i += 2) coins.push({ x: spots[i], y: spots[i + 1], taken: false });
53
49
  return { frame: 0, x: 60, y: 500 - SIZE, vx: 0, vy: 0, onGround: true, held: 0, coins, winner: -1 };
54
50
  }
55
51
 
@@ -0,0 +1,2 @@
1
+ #!/bin/sh
2
+ exec zig ar "$@"
@@ -0,0 +1,2 @@
1
+ #!/bin/sh
2
+ exec zig cc -target x86_64-windows-gnu "$@"
@@ -0,0 +1,2 @@
1
+ #!/bin/sh
2
+ exec zig c++ -target x86_64-windows-gnu "$@"
@@ -0,0 +1,2 @@
1
+ #!/bin/sh
2
+ exec zig ranlib "$@"
@@ -0,0 +1,2 @@
1
+ #!/bin/sh
2
+ exec zig rc "$@"
@@ -0,0 +1,7 @@
1
+ set(CMAKE_SYSTEM_NAME Windows)
2
+ set(CMAKE_SYSTEM_PROCESSOR x86_64)
3
+ set(CMAKE_C_COMPILER "${CMAKE_CURRENT_LIST_DIR}/zig-cc.sh")
4
+ set(CMAKE_CXX_COMPILER "${CMAKE_CURRENT_LIST_DIR}/zig-cxx.sh")
5
+ set(CMAKE_AR "${CMAKE_CURRENT_LIST_DIR}/zig-ar.sh")
6
+ set(CMAKE_RANLIB "${CMAKE_CURRENT_LIST_DIR}/zig-ranlib.sh")
7
+ set(CMAKE_RC_COMPILER "${CMAKE_CURRENT_LIST_DIR}/zig-rc.sh")