picopilot 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/LICENSE +661 -0
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +4 -0
- package/dist/bin.js.map +1 -0
- package/dist/cli.d.ts +15 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +59 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/audio.d.ts +17 -0
- package/dist/commands/audio.d.ts.map +1 -0
- package/dist/commands/audio.js +315 -0
- package/dist/commands/audio.js.map +1 -0
- package/dist/commands/export.d.ts +36 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +257 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/gfx.d.ts +28 -0
- package/dist/commands/gfx.d.ts.map +1 -0
- package/dist/commands/gfx.js +521 -0
- package/dist/commands/gfx.js.map +1 -0
- package/dist/commands/init.d.ts +34 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +151 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/lint.d.ts +20 -0
- package/dist/commands/lint.d.ts.map +1 -0
- package/dist/commands/lint.js +90 -0
- package/dist/commands/lint.js.map +1 -0
- package/dist/commands/minify.d.ts +20 -0
- package/dist/commands/minify.d.ts.map +1 -0
- package/dist/commands/minify.js +129 -0
- package/dist/commands/minify.js.map +1 -0
- package/dist/commands/music.d.ts +13 -0
- package/dist/commands/music.d.ts.map +1 -0
- package/dist/commands/music.js +241 -0
- package/dist/commands/music.js.map +1 -0
- package/dist/commands/playtest.d.ts +29 -0
- package/dist/commands/playtest.d.ts.map +1 -0
- package/dist/commands/playtest.js +631 -0
- package/dist/commands/playtest.js.map +1 -0
- package/dist/commands/run.d.ts +30 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +224 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/serve.d.ts +50 -0
- package/dist/commands/serve.d.ts.map +1 -0
- package/dist/commands/serve.js +213 -0
- package/dist/commands/serve.js.map +1 -0
- package/dist/commands/sfx.d.ts +13 -0
- package/dist/commands/sfx.d.ts.map +1 -0
- package/dist/commands/sfx.js +254 -0
- package/dist/commands/sfx.js.map +1 -0
- package/dist/commands/tokens.d.ts +36 -0
- package/dist/commands/tokens.d.ts.map +1 -0
- package/dist/commands/tokens.js +129 -0
- package/dist/commands/tokens.js.map +1 -0
- package/dist/commands/verify.d.ts +57 -0
- package/dist/commands/verify.d.ts.map +1 -0
- package/dist/commands/verify.js +213 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/commands/version.d.ts +12 -0
- package/dist/commands/version.d.ts.map +1 -0
- package/dist/commands/version.js +24 -0
- package/dist/commands/version.js.map +1 -0
- package/dist/engine/audio/index.d.ts +14 -0
- package/dist/engine/audio/index.d.ts.map +1 -0
- package/dist/engine/audio/index.js +14 -0
- package/dist/engine/audio/index.js.map +1 -0
- package/dist/engine/audio/music.d.ts +116 -0
- package/dist/engine/audio/music.d.ts.map +1 -0
- package/dist/engine/audio/music.js +138 -0
- package/dist/engine/audio/music.js.map +1 -0
- package/dist/engine/audio/section.d.ts +34 -0
- package/dist/engine/audio/section.d.ts.map +1 -0
- package/dist/engine/audio/section.js +67 -0
- package/dist/engine/audio/section.js.map +1 -0
- package/dist/engine/audio/sfx.d.ts +141 -0
- package/dist/engine/audio/sfx.d.ts.map +1 -0
- package/dist/engine/audio/sfx.js +506 -0
- package/dist/engine/audio/sfx.js.map +1 -0
- package/dist/engine/cart/cart.d.ts +75 -0
- package/dist/engine/cart/cart.d.ts.map +1 -0
- package/dist/engine/cart/cart.js +153 -0
- package/dist/engine/cart/cart.js.map +1 -0
- package/dist/engine/cart/errors.d.ts +29 -0
- package/dist/engine/cart/errors.d.ts.map +1 -0
- package/dist/engine/cart/errors.js +26 -0
- package/dist/engine/cart/errors.js.map +1 -0
- package/dist/engine/cart/gfx.d.ts +79 -0
- package/dist/engine/cart/gfx.d.ts.map +1 -0
- package/dist/engine/cart/gfx.js +171 -0
- package/dist/engine/cart/gfx.js.map +1 -0
- package/dist/engine/cart/index.d.ts +15 -0
- package/dist/engine/cart/index.d.ts.map +1 -0
- package/dist/engine/cart/index.js +15 -0
- package/dist/engine/cart/index.js.map +1 -0
- package/dist/engine/cart/map.d.ts +46 -0
- package/dist/engine/cart/map.d.ts.map +1 -0
- package/dist/engine/cart/map.js +118 -0
- package/dist/engine/cart/map.js.map +1 -0
- package/dist/engine/config/config.d.ts +74 -0
- package/dist/engine/config/config.d.ts.map +1 -0
- package/dist/engine/config/config.js +103 -0
- package/dist/engine/config/config.js.map +1 -0
- package/dist/engine/config/index.d.ts +7 -0
- package/dist/engine/config/index.d.ts.map +1 -0
- package/dist/engine/config/index.js +7 -0
- package/dist/engine/config/index.js.map +1 -0
- package/dist/engine/gfx/grid.d.ts +51 -0
- package/dist/engine/gfx/grid.d.ts.map +1 -0
- package/dist/engine/gfx/grid.js +116 -0
- package/dist/engine/gfx/grid.js.map +1 -0
- package/dist/engine/gfx/index.d.ts +17 -0
- package/dist/engine/gfx/index.d.ts.map +1 -0
- package/dist/engine/gfx/index.js +17 -0
- package/dist/engine/gfx/index.js.map +1 -0
- package/dist/engine/gfx/label.d.ts +34 -0
- package/dist/engine/gfx/label.d.ts.map +1 -0
- package/dist/engine/gfx/label.js +190 -0
- package/dist/engine/gfx/label.js.map +1 -0
- package/dist/engine/gfx/overlap.d.ts +42 -0
- package/dist/engine/gfx/overlap.d.ts.map +1 -0
- package/dist/engine/gfx/overlap.js +57 -0
- package/dist/engine/gfx/overlap.js.map +1 -0
- package/dist/engine/gfx/palette.d.ts +29 -0
- package/dist/engine/gfx/palette.d.ts.map +1 -0
- package/dist/engine/gfx/palette.js +46 -0
- package/dist/engine/gfx/palette.js.map +1 -0
- package/dist/engine/gfx/png.d.ts +31 -0
- package/dist/engine/gfx/png.d.ts.map +1 -0
- package/dist/engine/gfx/png.js +165 -0
- package/dist/engine/gfx/png.js.map +1 -0
- package/dist/engine/gfx/render.d.ts +42 -0
- package/dist/engine/gfx/render.d.ts.map +1 -0
- package/dist/engine/gfx/render.js +72 -0
- package/dist/engine/gfx/render.js.map +1 -0
- package/dist/engine/index.d.ts +22 -0
- package/dist/engine/index.d.ts.map +1 -0
- package/dist/engine/index.js +22 -0
- package/dist/engine/index.js.map +1 -0
- package/dist/engine/pico8/adapter.d.ts +267 -0
- package/dist/engine/pico8/adapter.d.ts.map +1 -0
- package/dist/engine/pico8/adapter.js +37 -0
- package/dist/engine/pico8/adapter.js.map +1 -0
- package/dist/engine/pico8/drive.d.ts +308 -0
- package/dist/engine/pico8/drive.d.ts.map +1 -0
- package/dist/engine/pico8/drive.js +581 -0
- package/dist/engine/pico8/drive.js.map +1 -0
- package/dist/engine/pico8/harness.d.ts +146 -0
- package/dist/engine/pico8/harness.d.ts.map +1 -0
- package/dist/engine/pico8/harness.js +251 -0
- package/dist/engine/pico8/harness.js.map +1 -0
- package/dist/engine/pico8/index.d.ts +21 -0
- package/dist/engine/pico8/index.d.ts.map +1 -0
- package/dist/engine/pico8/index.js +21 -0
- package/dist/engine/pico8/index.js.map +1 -0
- package/dist/engine/pico8/sentinel.d.ts +63 -0
- package/dist/engine/pico8/sentinel.d.ts.map +1 -0
- package/dist/engine/pico8/sentinel.js +86 -0
- package/dist/engine/pico8/sentinel.js.map +1 -0
- package/dist/engine/pico8/session-daemon-entry.d.ts +10 -0
- package/dist/engine/pico8/session-daemon-entry.d.ts.map +1 -0
- package/dist/engine/pico8/session-daemon-entry.js +11 -0
- package/dist/engine/pico8/session-daemon-entry.js.map +1 -0
- package/dist/engine/pico8/session-daemon-main.d.ts +44 -0
- package/dist/engine/pico8/session-daemon-main.d.ts.map +1 -0
- package/dist/engine/pico8/session-daemon-main.js +71 -0
- package/dist/engine/pico8/session-daemon-main.js.map +1 -0
- package/dist/engine/pico8/session-daemon.d.ts +68 -0
- package/dist/engine/pico8/session-daemon.d.ts.map +1 -0
- package/dist/engine/pico8/session-daemon.js +264 -0
- package/dist/engine/pico8/session-daemon.js.map +1 -0
- package/dist/engine/pico8/session.d.ts +140 -0
- package/dist/engine/pico8/session.d.ts.map +1 -0
- package/dist/engine/pico8/session.js +250 -0
- package/dist/engine/pico8/session.js.map +1 -0
- package/dist/engine/pico8/shell.d.ts +103 -0
- package/dist/engine/pico8/shell.d.ts.map +1 -0
- package/dist/engine/pico8/shell.js +324 -0
- package/dist/engine/pico8/shell.js.map +1 -0
- package/dist/engine/pico8/supervisor.d.ts +137 -0
- package/dist/engine/pico8/supervisor.d.ts.map +1 -0
- package/dist/engine/pico8/supervisor.js +140 -0
- package/dist/engine/pico8/supervisor.js.map +1 -0
- package/dist/engine/scaffold/index.d.ts +8 -0
- package/dist/engine/scaffold/index.d.ts.map +1 -0
- package/dist/engine/scaffold/index.js +8 -0
- package/dist/engine/scaffold/index.js.map +1 -0
- package/dist/engine/scaffold/scaffold.d.ts +49 -0
- package/dist/engine/scaffold/scaffold.d.ts.map +1 -0
- package/dist/engine/scaffold/scaffold.js +259 -0
- package/dist/engine/scaffold/scaffold.js.map +1 -0
- package/dist/engine/shrinko/adapter.d.ts +167 -0
- package/dist/engine/shrinko/adapter.d.ts.map +1 -0
- package/dist/engine/shrinko/adapter.js +107 -0
- package/dist/engine/shrinko/adapter.js.map +1 -0
- package/dist/engine/shrinko/index.d.ts +13 -0
- package/dist/engine/shrinko/index.d.ts.map +1 -0
- package/dist/engine/shrinko/index.js +13 -0
- package/dist/engine/shrinko/index.js.map +1 -0
- package/dist/engine/shrinko/shell.d.ts +69 -0
- package/dist/engine/shrinko/shell.d.ts.map +1 -0
- package/dist/engine/shrinko/shell.js +156 -0
- package/dist/engine/shrinko/shell.js.map +1 -0
- package/dist/engine/skills/index.d.ts +8 -0
- package/dist/engine/skills/index.d.ts.map +1 -0
- package/dist/engine/skills/index.js +8 -0
- package/dist/engine/skills/index.js.map +1 -0
- package/dist/engine/skills/skills.d.ts +104 -0
- package/dist/engine/skills/skills.d.ts.map +1 -0
- package/dist/engine/skills/skills.js +149 -0
- package/dist/engine/skills/skills.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +19 -0
- package/dist/version.js.map +1 -0
- package/package.json +48 -2
- package/src/bin.ts +4 -0
- package/src/cli.ts +61 -0
- package/src/commands/audio.test.ts +280 -0
- package/src/commands/audio.ts +410 -0
- package/src/commands/export.test.ts +310 -0
- package/src/commands/export.ts +316 -0
- package/src/commands/gfx-io.test.ts +178 -0
- package/src/commands/gfx.test.ts +470 -0
- package/src/commands/gfx.ts +645 -0
- package/src/commands/init.test.ts +482 -0
- package/src/commands/init.ts +193 -0
- package/src/commands/lint.test.ts +137 -0
- package/src/commands/lint.ts +117 -0
- package/src/commands/minify.test.ts +166 -0
- package/src/commands/minify.ts +156 -0
- package/src/commands/music.test.ts +272 -0
- package/src/commands/music.ts +288 -0
- package/src/commands/playtest.test.ts +317 -0
- package/src/commands/playtest.ts +773 -0
- package/src/commands/run.test.ts +264 -0
- package/src/commands/run.ts +285 -0
- package/src/commands/serve.test.ts +227 -0
- package/src/commands/serve.ts +272 -0
- package/src/commands/sfx.test.ts +349 -0
- package/src/commands/sfx.ts +300 -0
- package/src/commands/tokens.test.ts +212 -0
- package/src/commands/tokens.ts +168 -0
- package/src/commands/verify.test.ts +238 -0
- package/src/commands/verify.ts +256 -0
- package/src/commands/version.test.ts +70 -0
- package/src/commands/version.ts +24 -0
- package/src/engine/audio/index.ts +47 -0
- package/src/engine/audio/music.test.ts +188 -0
- package/src/engine/audio/music.ts +218 -0
- package/src/engine/audio/section.test.ts +124 -0
- package/src/engine/audio/section.ts +79 -0
- package/src/engine/audio/sfx.test.ts +410 -0
- package/src/engine/audio/sfx.ts +694 -0
- package/src/engine/cart/cart.test.ts +304 -0
- package/src/engine/cart/cart.ts +211 -0
- package/src/engine/cart/errors.ts +39 -0
- package/src/engine/cart/fixtures/crlf.p8 +6 -0
- package/src/engine/cart/fixtures/full.p8 +174 -0
- package/src/engine/cart/fixtures/header-only.p8 +2 -0
- package/src/engine/cart/fixtures/malformed-no-header.p8 +2 -0
- package/src/engine/cart/fixtures/minimal.p8 +10 -0
- package/src/engine/cart/fixtures/no-trailing-newline.p8 +6 -0
- package/src/engine/cart/gfx.ts +195 -0
- package/src/engine/cart/index.ts +27 -0
- package/src/engine/cart/map.ts +134 -0
- package/src/engine/config/config.ts +115 -0
- package/src/engine/config/index.ts +12 -0
- package/src/engine/gfx/grid.test.ts +128 -0
- package/src/engine/gfx/grid.ts +136 -0
- package/src/engine/gfx/index.ts +34 -0
- package/src/engine/gfx/label.test.ts +105 -0
- package/src/engine/gfx/label.ts +229 -0
- package/src/engine/gfx/overlap.test.ts +71 -0
- package/src/engine/gfx/overlap.ts +66 -0
- package/src/engine/gfx/palette.test.ts +35 -0
- package/src/engine/gfx/palette.ts +54 -0
- package/src/engine/gfx/png.test.ts +111 -0
- package/src/engine/gfx/png.ts +196 -0
- package/src/engine/gfx/render.test.ts +180 -0
- package/src/engine/gfx/render.ts +106 -0
- package/src/engine/index.ts +21 -0
- package/src/engine/pico8/adapter.ts +303 -0
- package/src/engine/pico8/drive.test.ts +415 -0
- package/src/engine/pico8/drive.ts +729 -0
- package/src/engine/pico8/harness.test.ts +181 -0
- package/src/engine/pico8/harness.ts +354 -0
- package/src/engine/pico8/index.ts +20 -0
- package/src/engine/pico8/sentinel.test.ts +80 -0
- package/src/engine/pico8/sentinel.ts +93 -0
- package/src/engine/pico8/session-daemon-entry.ts +12 -0
- package/src/engine/pico8/session-daemon-main.ts +98 -0
- package/src/engine/pico8/session-daemon.test.ts +212 -0
- package/src/engine/pico8/session-daemon.ts +306 -0
- package/src/engine/pico8/session.test.ts +239 -0
- package/src/engine/pico8/session.ts +321 -0
- package/src/engine/pico8/shell.test.ts +583 -0
- package/src/engine/pico8/shell.ts +412 -0
- package/src/engine/pico8/supervisor.test.ts +105 -0
- package/src/engine/pico8/supervisor.ts +197 -0
- package/src/engine/scaffold/index.ts +15 -0
- package/src/engine/scaffold/scaffold.ts +278 -0
- package/src/engine/shrinko/adapter.ts +241 -0
- package/src/engine/shrinko/fixtures/count-no-compressed.txt +2 -0
- package/src/engine/shrinko/fixtures/count-over-budget.txt +3 -0
- package/src/engine/shrinko/fixtures/count-under-budget.txt +3 -0
- package/src/engine/shrinko/index.ts +33 -0
- package/src/engine/shrinko/shell.ts +224 -0
- package/src/engine/shrinko/shrinko.test.ts +182 -0
- package/src/engine/skills/index.ts +14 -0
- package/src/engine/skills/skills.test.ts +376 -0
- package/src/engine/skills/skills.ts +205 -0
- package/src/index.ts +13 -0
- package/src/skills/game-design-reference/SKILL.md +70 -0
- package/src/skills/game-jam/SKILL.md +45 -0
- package/src/skills/picopilot-art/SKILL.md +62 -0
- package/src/skills/picopilot-audio/SKILL.md +194 -0
- package/src/skills/picopilot-code/SKILL.md +97 -0
- package/src/skills/picopilot-code/reference/README.md +42 -0
- package/src/skills/picopilot-code/reference/mode7-racing.md +95 -0
- package/src/skills/picopilot-code/reference/platformer.md +119 -0
- package/src/skills/picopilot-code/reference/puzzle-grid.md +106 -0
- package/src/skills/picopilot-code/reference/rpg-menus-dialog.md +122 -0
- package/src/skills/picopilot-code/reference/top-down-adventure.md +117 -0
- package/src/skills/picopilot-code/reference/twin-stick-arcade.md +128 -0
- package/src/skills/picopilot-debug/SKILL.md +195 -0
- package/src/skills/picopilot-overview/SKILL.md +52 -0
- package/src/version.ts +22 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { CartRangeError } from './errors.js';
|
|
2
|
+
/**
|
|
3
|
+
* Addressable view over a cart's `__map__` section: the tile map as a grid of
|
|
4
|
+
* 8-bit tile indices, NOT an opaque hex string.
|
|
5
|
+
*
|
|
6
|
+
* The text `__map__` stores the base map: up to 32 rows of 128 tiles, each tile
|
|
7
|
+
* a byte written as two hex chars (`grid[y][x]`). Rows 32..63 (the shared half)
|
|
8
|
+
* are NOT stored here in the text format (they live in `__gfx__`'s upper bank
|
|
9
|
+
), see `gfx.ts` {@link mapRowsForSprite}; this view models the `__map__` body
|
|
10
|
+
* as written. The 0x1000 overlap check reads a shared-bank sprite's aliased map
|
|
11
|
+
* region through {@link nonZeroTilesInRows} to decide whether a write clobbers
|
|
12
|
+
* real tiles.
|
|
13
|
+
*
|
|
14
|
+
* Reads/writes go through the parsed grid; call {@link commit} to write it back
|
|
15
|
+
* into the cart's `__map__` body. A missing/short section reads as zero tiles.
|
|
16
|
+
*/
|
|
17
|
+
export const MAP_WIDTH = 128;
|
|
18
|
+
export const MAP_ROWS = 32;
|
|
19
|
+
export class MapData {
|
|
20
|
+
/** `tiles[y][x]` is the 0..255 tile index at map cell (x, y). */
|
|
21
|
+
tiles;
|
|
22
|
+
newline;
|
|
23
|
+
constructor(tiles, newline) {
|
|
24
|
+
this.tiles = tiles;
|
|
25
|
+
this.newline = newline;
|
|
26
|
+
}
|
|
27
|
+
/** Builds an addressable map from a cart's `__map__` body (all-zero if absent). */
|
|
28
|
+
static fromBody(body) {
|
|
29
|
+
const newline = body !== undefined && /\r\n/.test(body) ? '\r\n' : '\n';
|
|
30
|
+
const lines = body === undefined ? [] : body.split(/\r?\n/);
|
|
31
|
+
const tiles = [];
|
|
32
|
+
for (let y = 0; y < MAP_ROWS; y++) {
|
|
33
|
+
const line = lines[y] ?? '';
|
|
34
|
+
const row = [];
|
|
35
|
+
for (let x = 0; x < MAP_WIDTH; x++) {
|
|
36
|
+
const hi = line[x * 2];
|
|
37
|
+
const lo = line[x * 2 + 1];
|
|
38
|
+
row.push(hi === undefined || lo === undefined ? 0 : hexByte(hi, lo));
|
|
39
|
+
}
|
|
40
|
+
tiles.push(row);
|
|
41
|
+
}
|
|
42
|
+
return new MapData(tiles, newline);
|
|
43
|
+
}
|
|
44
|
+
/** Reads the tile index (0..255) at map cell (x, y). */
|
|
45
|
+
getTile(x, y) {
|
|
46
|
+
this.assertCell(x, y);
|
|
47
|
+
return this.tiles[y]?.[x] ?? 0;
|
|
48
|
+
}
|
|
49
|
+
/** Writes the tile index (0..255) at map cell (x, y). */
|
|
50
|
+
setTile(x, y, value) {
|
|
51
|
+
this.assertCell(x, y);
|
|
52
|
+
if (!Number.isInteger(value) || value < 0 || value > 255) {
|
|
53
|
+
throw new CartRangeError(`tile value ${value} out of range 0..255`);
|
|
54
|
+
}
|
|
55
|
+
const row = this.tiles[y];
|
|
56
|
+
if (row !== undefined)
|
|
57
|
+
row[x] = value;
|
|
58
|
+
}
|
|
59
|
+
/** Reads one full map row (128 tile indices) at row `y`. */
|
|
60
|
+
getRow(y) {
|
|
61
|
+
if (!Number.isInteger(y) || y < 0 || y >= MAP_ROWS) {
|
|
62
|
+
throw new CartRangeError(`map row ${y} out of range 0..${MAP_ROWS - 1}`);
|
|
63
|
+
}
|
|
64
|
+
return (this.tiles[y] ?? []).slice();
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Counts non-zero tiles across a half-open row range `[start, end)`, clamped
|
|
68
|
+
* to the stored `__map__` rows (0..31). Shared-bank rows (32..63) that the
|
|
69
|
+
* text `__map__` does not store contribute zero. This is the primitive the
|
|
70
|
+
* gfx/map overlap smart-refuse uses to decide whether a shared-bank sprite
|
|
71
|
+
* write would clobber real map data.
|
|
72
|
+
*/
|
|
73
|
+
nonZeroTilesInRows(start, end) {
|
|
74
|
+
let count = 0;
|
|
75
|
+
for (let y = Math.max(0, start); y < Math.min(MAP_ROWS, end); y++) {
|
|
76
|
+
for (let x = 0; x < MAP_WIDTH; x++)
|
|
77
|
+
if ((this.tiles[y]?.[x] ?? 0) !== 0)
|
|
78
|
+
count++;
|
|
79
|
+
}
|
|
80
|
+
return count;
|
|
81
|
+
}
|
|
82
|
+
/** Serializes the grid back to a `__map__` body (32 lines of 256 hex chars). */
|
|
83
|
+
toBody() {
|
|
84
|
+
const lines = [];
|
|
85
|
+
for (let y = 0; y < MAP_ROWS; y++) {
|
|
86
|
+
let line = '';
|
|
87
|
+
for (let x = 0; x < MAP_WIDTH; x++)
|
|
88
|
+
line += byteHex(this.tiles[y]?.[x] ?? 0);
|
|
89
|
+
lines.push(line);
|
|
90
|
+
}
|
|
91
|
+
return lines.join(this.newline) + this.newline;
|
|
92
|
+
}
|
|
93
|
+
/** Writes the grid back into the cart's `__map__` section. */
|
|
94
|
+
commit(cart) {
|
|
95
|
+
cart.setSection('map', this.toBody());
|
|
96
|
+
}
|
|
97
|
+
assertCell(x, y) {
|
|
98
|
+
if (!Number.isInteger(x) ||
|
|
99
|
+
!Number.isInteger(y) ||
|
|
100
|
+
x < 0 ||
|
|
101
|
+
y < 0 ||
|
|
102
|
+
x >= MAP_WIDTH ||
|
|
103
|
+
y >= MAP_ROWS) {
|
|
104
|
+
throw new CartRangeError(`map cell (${x}, ${y}) out of range 0..${MAP_WIDTH - 1} x 0..${MAP_ROWS - 1}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function hexByte(hi, lo) {
|
|
109
|
+
const v = Number.parseInt(`${hi}${lo}`, 16);
|
|
110
|
+
if (Number.isNaN(v)) {
|
|
111
|
+
throw new CartRangeError(`invalid hex byte "${hi}${lo}" in __map__`);
|
|
112
|
+
}
|
|
113
|
+
return v;
|
|
114
|
+
}
|
|
115
|
+
function byteHex(value) {
|
|
116
|
+
return value.toString(16).padStart(2, '0');
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"map.js","sourceRoot":"","sources":["../../../src/engine/cart/map.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { z } from 'incur';
|
|
2
|
+
/**
|
|
3
|
+
* The per-cart `picopilot.json` config, US #10.
|
|
4
|
+
*
|
|
5
|
+
* picopilot's config is incur's built-in `config: { files: ['picopilot.json'] }`
|
|
6
|
+
* mechanism (declared in `createCli`): a JSON file whose values become option
|
|
7
|
+
* DEFAULTS for the matching command, with precedence `argv > config > zod
|
|
8
|
+
* defaults`. incur keys config by command path, a command's options live under
|
|
9
|
+
* `commands.<group>.commands.<name>.options.<key>`, so a policy an agent sets
|
|
10
|
+
* once (like `allowMapOverlap`) is stored where the command that reads it looks.
|
|
11
|
+
*
|
|
12
|
+
* This module is the single source of truth for the config SHAPE: `init`
|
|
13
|
+
* scaffolds a file from {@link defaultConfigFile}, and the later `gfx set`
|
|
14
|
+
* command reads `allowMapOverlap` through incur's config layer (its own
|
|
15
|
+
* `--allow-map-overlap` option default). Keeping the shape here, rather than
|
|
16
|
+
* inlining a blob in `init`, means the scaffolded file and the reader cannot
|
|
17
|
+
* drift.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* The `gfx set` options that `picopilot.json` may set as defaults.
|
|
21
|
+
*
|
|
22
|
+
* `allowMapOverlap` authorises `gfx set` to write sprites 128-255 even when the
|
|
23
|
+
* overlapping `__map__` rows hold real tiles (see ADR-0004). It is a rarely /
|
|
24
|
+
* once-set PROJECT setting: OFF by default (the smart-refuse is the safety), so
|
|
25
|
+
* a fresh cart never silently loses map data. The matching invocation flag is
|
|
26
|
+
* `--allow-map-overlap`; `argv > config > default` means the flag always wins.
|
|
27
|
+
*/
|
|
28
|
+
export declare const GfxSetOptions: z.ZodObject<{
|
|
29
|
+
allowMapOverlap: z.ZodDefault<z.ZodBoolean>;
|
|
30
|
+
}, z.core.$strip>;
|
|
31
|
+
/**
|
|
32
|
+
* The full `picopilot.json` document shape, mirroring incur's config tree
|
|
33
|
+
* (`commands.<path>.options`). Only the keys picopilot actually reads are
|
|
34
|
+
* modelled; the schema is `.strict()`-free on purpose so a human/agent may add
|
|
35
|
+
* config for commands this version does not yet know about without a parse
|
|
36
|
+
* failure.
|
|
37
|
+
*/
|
|
38
|
+
export declare const PicopilotConfig: z.ZodObject<{
|
|
39
|
+
$schema: z.ZodOptional<z.ZodString>;
|
|
40
|
+
commands: z.ZodOptional<z.ZodObject<{
|
|
41
|
+
gfx: z.ZodOptional<z.ZodObject<{
|
|
42
|
+
commands: z.ZodOptional<z.ZodObject<{
|
|
43
|
+
set: z.ZodOptional<z.ZodObject<{
|
|
44
|
+
options: z.ZodOptional<z.ZodObject<{
|
|
45
|
+
allowMapOverlap: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
|
|
46
|
+
}, z.core.$strip>>;
|
|
47
|
+
}, z.core.$strip>>;
|
|
48
|
+
}, z.core.$strip>>;
|
|
49
|
+
}, z.core.$strip>>;
|
|
50
|
+
}, z.core.$strip>>;
|
|
51
|
+
}, z.core.$strip>;
|
|
52
|
+
export type PicopilotConfig = z.infer<typeof PicopilotConfig>;
|
|
53
|
+
/**
|
|
54
|
+
* The default `picopilot.json` written by `init`: valid, minimal, and
|
|
55
|
+
* self-documenting via `$schema`. It sets `allowMapOverlap: false` explicitly
|
|
56
|
+
* so the one policy knob an agent is likely to flip is visible in the file (an
|
|
57
|
+
* agent is FREE to read/write this to match a higher-level instruction, US #10)
|
|
58
|
+
* rather than hidden behind a zod default.
|
|
59
|
+
*/
|
|
60
|
+
export declare const defaultConfig: PicopilotConfig;
|
|
61
|
+
/** The default `picopilot.json` serialized as it is written to disk (trailing newline). */
|
|
62
|
+
export declare function defaultConfigFile(): string;
|
|
63
|
+
/**
|
|
64
|
+
* Reads `allowMapOverlap` out of a parsed `picopilot.json` tree, tolerating a
|
|
65
|
+
* partially-shaped or absent config. Returns `false` when the key is missing or
|
|
66
|
+
* the file is malformed enough that the value cannot be found, the SAFE default
|
|
67
|
+
* (the smart-refuse still guards the genuine data-loss corner).
|
|
68
|
+
*
|
|
69
|
+
* `gfx set` normally gets this value through incur's config → option-default
|
|
70
|
+
* layer; this helper exists for callers that hold a raw config object (and to
|
|
71
|
+
* keep the "where allowMapOverlap lives" knowledge in one place).
|
|
72
|
+
*/
|
|
73
|
+
export declare function readAllowMapOverlap(config: unknown): boolean;
|
|
74
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/engine/config/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,CAAC,EAAC,MAAM,OAAO,CAAC;AAExB;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa;;iBAOxB,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;iBAsB1B,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,EAAE,eAa3B,CAAC;AAEF,2FAA2F;AAC3F,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAM5D"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { z } from 'incur';
|
|
2
|
+
/**
|
|
3
|
+
* The per-cart `picopilot.json` config, US #10.
|
|
4
|
+
*
|
|
5
|
+
* picopilot's config is incur's built-in `config: { files: ['picopilot.json'] }`
|
|
6
|
+
* mechanism (declared in `createCli`): a JSON file whose values become option
|
|
7
|
+
* DEFAULTS for the matching command, with precedence `argv > config > zod
|
|
8
|
+
* defaults`. incur keys config by command path, a command's options live under
|
|
9
|
+
* `commands.<group>.commands.<name>.options.<key>`, so a policy an agent sets
|
|
10
|
+
* once (like `allowMapOverlap`) is stored where the command that reads it looks.
|
|
11
|
+
*
|
|
12
|
+
* This module is the single source of truth for the config SHAPE: `init`
|
|
13
|
+
* scaffolds a file from {@link defaultConfigFile}, and the later `gfx set`
|
|
14
|
+
* command reads `allowMapOverlap` through incur's config layer (its own
|
|
15
|
+
* `--allow-map-overlap` option default). Keeping the shape here, rather than
|
|
16
|
+
* inlining a blob in `init`, means the scaffolded file and the reader cannot
|
|
17
|
+
* drift.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* The `gfx set` options that `picopilot.json` may set as defaults.
|
|
21
|
+
*
|
|
22
|
+
* `allowMapOverlap` authorises `gfx set` to write sprites 128-255 even when the
|
|
23
|
+
* overlapping `__map__` rows hold real tiles (see ADR-0004). It is a rarely /
|
|
24
|
+
* once-set PROJECT setting: OFF by default (the smart-refuse is the safety), so
|
|
25
|
+
* a fresh cart never silently loses map data. The matching invocation flag is
|
|
26
|
+
* `--allow-map-overlap`; `argv > config > default` means the flag always wins.
|
|
27
|
+
*/
|
|
28
|
+
export const GfxSetOptions = z.object({
|
|
29
|
+
allowMapOverlap: z
|
|
30
|
+
.boolean()
|
|
31
|
+
.default(false)
|
|
32
|
+
.describe('Authorise `gfx set` to overwrite __map__ tiles that alias sprites 128-255 (ADR-0004). Off by default; the smart-refuse is the safety.'),
|
|
33
|
+
});
|
|
34
|
+
/**
|
|
35
|
+
* The full `picopilot.json` document shape, mirroring incur's config tree
|
|
36
|
+
* (`commands.<path>.options`). Only the keys picopilot actually reads are
|
|
37
|
+
* modelled; the schema is `.strict()`-free on purpose so a human/agent may add
|
|
38
|
+
* config for commands this version does not yet know about without a parse
|
|
39
|
+
* failure.
|
|
40
|
+
*/
|
|
41
|
+
export const PicopilotConfig = z.object({
|
|
42
|
+
$schema: z.string().optional().describe('JSON Schema reference (optional).'),
|
|
43
|
+
commands: z
|
|
44
|
+
.object({
|
|
45
|
+
gfx: z
|
|
46
|
+
.object({
|
|
47
|
+
commands: z
|
|
48
|
+
.object({
|
|
49
|
+
set: z
|
|
50
|
+
.object({
|
|
51
|
+
options: GfxSetOptions.partial().optional(),
|
|
52
|
+
})
|
|
53
|
+
.optional(),
|
|
54
|
+
})
|
|
55
|
+
.optional(),
|
|
56
|
+
})
|
|
57
|
+
.optional(),
|
|
58
|
+
})
|
|
59
|
+
.optional()
|
|
60
|
+
.describe('Per-command option defaults, keyed by command path (incur config layout).'),
|
|
61
|
+
});
|
|
62
|
+
/**
|
|
63
|
+
* The default `picopilot.json` written by `init`: valid, minimal, and
|
|
64
|
+
* self-documenting via `$schema`. It sets `allowMapOverlap: false` explicitly
|
|
65
|
+
* so the one policy knob an agent is likely to flip is visible in the file (an
|
|
66
|
+
* agent is FREE to read/write this to match a higher-level instruction, US #10)
|
|
67
|
+
* rather than hidden behind a zod default.
|
|
68
|
+
*/
|
|
69
|
+
export const defaultConfig = {
|
|
70
|
+
$schema: './picopilot.schema.json',
|
|
71
|
+
commands: {
|
|
72
|
+
gfx: {
|
|
73
|
+
commands: {
|
|
74
|
+
set: {
|
|
75
|
+
options: {
|
|
76
|
+
allowMapOverlap: false,
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
/** The default `picopilot.json` serialized as it is written to disk (trailing newline). */
|
|
84
|
+
export function defaultConfigFile() {
|
|
85
|
+
return `${JSON.stringify(defaultConfig, null, 2)}\n`;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Reads `allowMapOverlap` out of a parsed `picopilot.json` tree, tolerating a
|
|
89
|
+
* partially-shaped or absent config. Returns `false` when the key is missing or
|
|
90
|
+
* the file is malformed enough that the value cannot be found, the SAFE default
|
|
91
|
+
* (the smart-refuse still guards the genuine data-loss corner).
|
|
92
|
+
*
|
|
93
|
+
* `gfx set` normally gets this value through incur's config → option-default
|
|
94
|
+
* layer; this helper exists for callers that hold a raw config object (and to
|
|
95
|
+
* keep the "where allowMapOverlap lives" knowledge in one place).
|
|
96
|
+
*/
|
|
97
|
+
export function readAllowMapOverlap(config) {
|
|
98
|
+
const parsed = PicopilotConfig.safeParse(config);
|
|
99
|
+
if (!parsed.success)
|
|
100
|
+
return false;
|
|
101
|
+
return (parsed.data.commands?.gfx?.commands?.set?.options?.allowMapOverlap ?? false);
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/engine/config/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,CAAC,EAAC,MAAM,OAAO,CAAC;AAExB;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC,eAAe,EAAE,CAAC;SAChB,OAAO,EAAE;SACT,OAAO,CAAC,KAAK,CAAC;SACd,QAAQ,CACR,uIAAuI,CACvI;CACF,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;IAC5E,QAAQ,EAAE,CAAC;SACT,MAAM,CAAC;QACP,GAAG,EAAE,CAAC;aACJ,MAAM,CAAC;YACP,QAAQ,EAAE,CAAC;iBACT,MAAM,CAAC;gBACP,GAAG,EAAE,CAAC;qBACJ,MAAM,CAAC;oBACP,OAAO,EAAE,aAAa,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;iBAC3C,CAAC;qBACD,QAAQ,EAAE;aACZ,CAAC;iBACD,QAAQ,EAAE;SACZ,CAAC;aACD,QAAQ,EAAE;KACZ,CAAC;SACD,QAAQ,EAAE;SACV,QAAQ,CACR,2EAA2E,CAC3E;CACF,CAAC,CAAC;AAIH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,aAAa,GAAoB;IAC7C,OAAO,EAAE,yBAAyB;IAClC,QAAQ,EAAE;QACT,GAAG,EAAE;YACJ,QAAQ,EAAE;gBACT,GAAG,EAAE;oBACJ,OAAO,EAAE;wBACR,eAAe,EAAE,KAAK;qBACtB;iBACD;aACD;SACD;KACD;CACD,CAAC;AAEF,2FAA2F;AAC3F,MAAM,UAAU,iBAAiB;IAChC,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;AACtD,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAe;IAClD,MAAM,MAAM,GAAG,eAAe,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACjD,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAClC,OAAO,CACN,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,eAAe,IAAI,KAAK,CAC3E,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The per-cart `picopilot.json` config model: the schema `init` scaffolds from
|
|
3
|
+
* and the later `gfx set` reads `allowMapOverlap` through (via incur's config
|
|
4
|
+
* layer). See `config.ts` for why the shape lives here as one source of truth.
|
|
5
|
+
*/
|
|
6
|
+
export { defaultConfig, defaultConfigFile, GfxSetOptions, PicopilotConfig, readAllowMapOverlap, } from './config.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/engine/config/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACN,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,mBAAmB,GACnB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The per-cart `picopilot.json` config model: the schema `init` scaffolds from
|
|
3
|
+
* and the later `gfx set` reads `allowMapOverlap` through (via incur's config
|
|
4
|
+
* layer). See `config.ts` for why the shape lives here as one source of truth.
|
|
5
|
+
*/
|
|
6
|
+
export { defaultConfig, defaultConfigFile, GfxSetOptions, PicopilotConfig, readAllowMapOverlap, } from './config.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/engine/config/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACN,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,mBAAmB,GACnB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shrinko-free char-grid codec: converts a sprite's per-pixel colour
|
|
3
|
+
* nibbles (as {@link import('../cart/index.js').GfxSheet} reads/writes them)
|
|
4
|
+
* to and from a readable CHAR GRID, and back, as an IDENTITY.
|
|
5
|
+
*
|
|
6
|
+
* The char grid is the "SVG for pixels" (CONTEXT.md `char grid`): the EDIT
|
|
7
|
+
* surface an agent reads with `gfx show` and writes with `gfx set`. Each pixel
|
|
8
|
+
* is one character:
|
|
9
|
+
*
|
|
10
|
+
* - `.` = transparent = colour index 0 (PICO-8's index-0 doubles as the default
|
|
11
|
+
* transparent colour; the grid renders it as `.` so an agent SEES the empty
|
|
12
|
+
* pixels rather than a wall of `0`s).
|
|
13
|
+
* - `0`..`f` (lowercase hex) = colour indices 1..15 (`__gfx__` stores nibbles
|
|
14
|
+
* lowercase, so decode is case-insensitive but encode is lowercase to match
|
|
15
|
+
* what PICO-8 writes).
|
|
16
|
+
*
|
|
17
|
+
* The grid is 8 lines of 8 characters (one 8x8 sprite). The round-trip
|
|
18
|
+
* `nibbles → grid → nibbles` is an identity for every valid sprite (asserted in
|
|
19
|
+
* the tests), because `.` maps to 0 and 0 maps to `.` with no other collision.
|
|
20
|
+
*
|
|
21
|
+
* This codec is deliberately SEPARABLE from the cart model and the commands: it
|
|
22
|
+
* only knows nibble grids and strings, so the later `gfx render` task can reuse
|
|
23
|
+
* it and a test can round-trip it without a cart.
|
|
24
|
+
*/
|
|
25
|
+
/** The width/height (in pixels) of one sprite; a char grid is this square. */
|
|
26
|
+
export declare const GRID_SIZE = 8;
|
|
27
|
+
/** The character that renders colour index 0 (transparent) in a char grid. */
|
|
28
|
+
export declare const TRANSPARENT_CHAR = ".";
|
|
29
|
+
/**
|
|
30
|
+
* Encodes an 8x8 grid of colour nibbles (0..15) into a char-grid string: 8
|
|
31
|
+
* lines of 8 chars, `\n`-joined, no trailing newline. Index 0 → `.`; 1..15 →
|
|
32
|
+
* the lowercase hex digit.
|
|
33
|
+
*
|
|
34
|
+
* @throws {GfxGridError} if the grid is not 8x8 or a cell is out of 0..15.
|
|
35
|
+
*/
|
|
36
|
+
export declare function nibblesToGrid(grid: number[][]): string;
|
|
37
|
+
/**
|
|
38
|
+
* Decodes a char-grid string back into an 8x8 grid of colour nibbles (0..15),
|
|
39
|
+
* the inverse of {@link nibblesToGrid}. Accepts `.` (→ 0) and hex digits
|
|
40
|
+
* (case-insensitive). Blank lines / trailing whitespace-only content are
|
|
41
|
+
* tolerated so an agent may paste a grid with a trailing newline; the parsed
|
|
42
|
+
* content must still be exactly 8 rows of 8 cells.
|
|
43
|
+
*
|
|
44
|
+
* @throws {GfxGridError} if the parsed grid is not 8x8 or a char is invalid.
|
|
45
|
+
*/
|
|
46
|
+
export declare function gridToNibbles(text: string): number[][];
|
|
47
|
+
/** A malformed char grid or nibble grid (wrong shape or an invalid cell/char). */
|
|
48
|
+
export declare class GfxGridError extends Error {
|
|
49
|
+
constructor(message: string);
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=grid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../../../src/engine/gfx/grid.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,8EAA8E;AAC9E,eAAO,MAAM,SAAS,IAAc,CAAC;AAErC,8EAA8E;AAC9E,eAAO,MAAM,gBAAgB,MAAM,CAAC;AAEpC;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,CAStD;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,CA4BtD;AAED,kFAAkF;AAClF,qBAAa,YAAa,SAAQ,KAAK;gBAC1B,OAAO,EAAE,MAAM;CAI3B"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { SPRITE_SIZE } from '../cart/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* The shrinko-free char-grid codec: converts a sprite's per-pixel colour
|
|
4
|
+
* nibbles (as {@link import('../cart/index.js').GfxSheet} reads/writes them)
|
|
5
|
+
* to and from a readable CHAR GRID, and back, as an IDENTITY.
|
|
6
|
+
*
|
|
7
|
+
* The char grid is the "SVG for pixels" (CONTEXT.md `char grid`): the EDIT
|
|
8
|
+
* surface an agent reads with `gfx show` and writes with `gfx set`. Each pixel
|
|
9
|
+
* is one character:
|
|
10
|
+
*
|
|
11
|
+
* - `.` = transparent = colour index 0 (PICO-8's index-0 doubles as the default
|
|
12
|
+
* transparent colour; the grid renders it as `.` so an agent SEES the empty
|
|
13
|
+
* pixels rather than a wall of `0`s).
|
|
14
|
+
* - `0`..`f` (lowercase hex) = colour indices 1..15 (`__gfx__` stores nibbles
|
|
15
|
+
* lowercase, so decode is case-insensitive but encode is lowercase to match
|
|
16
|
+
* what PICO-8 writes).
|
|
17
|
+
*
|
|
18
|
+
* The grid is 8 lines of 8 characters (one 8x8 sprite). The round-trip
|
|
19
|
+
* `nibbles → grid → nibbles` is an identity for every valid sprite (asserted in
|
|
20
|
+
* the tests), because `.` maps to 0 and 0 maps to `.` with no other collision.
|
|
21
|
+
*
|
|
22
|
+
* This codec is deliberately SEPARABLE from the cart model and the commands: it
|
|
23
|
+
* only knows nibble grids and strings, so the later `gfx render` task can reuse
|
|
24
|
+
* it and a test can round-trip it without a cart.
|
|
25
|
+
*/
|
|
26
|
+
/** The width/height (in pixels) of one sprite; a char grid is this square. */
|
|
27
|
+
export const GRID_SIZE = SPRITE_SIZE;
|
|
28
|
+
/** The character that renders colour index 0 (transparent) in a char grid. */
|
|
29
|
+
export const TRANSPARENT_CHAR = '.';
|
|
30
|
+
/**
|
|
31
|
+
* Encodes an 8x8 grid of colour nibbles (0..15) into a char-grid string: 8
|
|
32
|
+
* lines of 8 chars, `\n`-joined, no trailing newline. Index 0 → `.`; 1..15 →
|
|
33
|
+
* the lowercase hex digit.
|
|
34
|
+
*
|
|
35
|
+
* @throws {GfxGridError} if the grid is not 8x8 or a cell is out of 0..15.
|
|
36
|
+
*/
|
|
37
|
+
export function nibblesToGrid(grid) {
|
|
38
|
+
assertNibbleGrid(grid);
|
|
39
|
+
const lines = [];
|
|
40
|
+
for (let r = 0; r < GRID_SIZE; r++) {
|
|
41
|
+
let line = '';
|
|
42
|
+
for (let c = 0; c < GRID_SIZE; c++)
|
|
43
|
+
line += nibbleToChar(grid[r]?.[c] ?? 0);
|
|
44
|
+
lines.push(line);
|
|
45
|
+
}
|
|
46
|
+
return lines.join('\n');
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Decodes a char-grid string back into an 8x8 grid of colour nibbles (0..15),
|
|
50
|
+
* the inverse of {@link nibblesToGrid}. Accepts `.` (→ 0) and hex digits
|
|
51
|
+
* (case-insensitive). Blank lines / trailing whitespace-only content are
|
|
52
|
+
* tolerated so an agent may paste a grid with a trailing newline; the parsed
|
|
53
|
+
* content must still be exactly 8 rows of 8 cells.
|
|
54
|
+
*
|
|
55
|
+
* @throws {GfxGridError} if the parsed grid is not 8x8 or a char is invalid.
|
|
56
|
+
*/
|
|
57
|
+
export function gridToNibbles(text) {
|
|
58
|
+
// Split on either newline style; drop a single trailing empty line (a paste
|
|
59
|
+
// with a final newline) but keep interior blank lines so a genuine malformed
|
|
60
|
+
// grid (too few rows) is caught rather than silently accepted.
|
|
61
|
+
const rawLines = text.split(/\r?\n/);
|
|
62
|
+
while (rawLines.length > 0 && rawLines[rawLines.length - 1] === '')
|
|
63
|
+
rawLines.pop();
|
|
64
|
+
if (rawLines.length !== GRID_SIZE) {
|
|
65
|
+
throw new GfxGridError(`char grid must have ${GRID_SIZE} rows, got ${rawLines.length}`);
|
|
66
|
+
}
|
|
67
|
+
const grid = [];
|
|
68
|
+
for (let r = 0; r < GRID_SIZE; r++) {
|
|
69
|
+
const line = rawLines[r] ?? '';
|
|
70
|
+
if (line.length !== GRID_SIZE) {
|
|
71
|
+
throw new GfxGridError(`char grid row ${r} must have ${GRID_SIZE} cells, got ${line.length}`);
|
|
72
|
+
}
|
|
73
|
+
const row = [];
|
|
74
|
+
for (let c = 0; c < GRID_SIZE; c++)
|
|
75
|
+
row.push(charToNibble(line[c], r, c));
|
|
76
|
+
grid.push(row);
|
|
77
|
+
}
|
|
78
|
+
return grid;
|
|
79
|
+
}
|
|
80
|
+
/** A malformed char grid or nibble grid (wrong shape or an invalid cell/char). */
|
|
81
|
+
export class GfxGridError extends Error {
|
|
82
|
+
constructor(message) {
|
|
83
|
+
super(message);
|
|
84
|
+
this.name = 'GfxGridError';
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function nibbleToChar(n) {
|
|
88
|
+
return n === 0 ? TRANSPARENT_CHAR : n.toString(16);
|
|
89
|
+
}
|
|
90
|
+
function charToNibble(ch, r, c) {
|
|
91
|
+
if (ch === TRANSPARENT_CHAR)
|
|
92
|
+
return 0;
|
|
93
|
+
const v = Number.parseInt(ch, 16);
|
|
94
|
+
if (Number.isNaN(v) || v < 0 || v > 15) {
|
|
95
|
+
throw new GfxGridError(`invalid char "${ch}" at (${c}, ${r}); expected "${TRANSPARENT_CHAR}" or a hex digit 0-f`);
|
|
96
|
+
}
|
|
97
|
+
return v;
|
|
98
|
+
}
|
|
99
|
+
function assertNibbleGrid(grid) {
|
|
100
|
+
if (grid.length !== GRID_SIZE) {
|
|
101
|
+
throw new GfxGridError(`nibble grid must have ${GRID_SIZE} rows, got ${grid.length}`);
|
|
102
|
+
}
|
|
103
|
+
for (let r = 0; r < GRID_SIZE; r++) {
|
|
104
|
+
const row = grid[r];
|
|
105
|
+
if (row === undefined || row.length !== GRID_SIZE) {
|
|
106
|
+
throw new GfxGridError(`nibble grid row ${r} must have ${GRID_SIZE} cells`);
|
|
107
|
+
}
|
|
108
|
+
for (let c = 0; c < GRID_SIZE; c++) {
|
|
109
|
+
const v = row[c] ?? 0;
|
|
110
|
+
if (!Number.isInteger(v) || v < 0 || v > 15) {
|
|
111
|
+
throw new GfxGridError(`nibble grid cell (${c}, ${r}) = ${v} out of range 0..15`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=grid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grid.js","sourceRoot":"","sources":["../../../src/engine/gfx/grid.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `engine/gfx` — the shrinko-free char-grid codec (`__gfx__` nibbles ↔ char
|
|
3
|
+
* grid) plus the gfx/map overlap smart-refuse decision.
|
|
4
|
+
*
|
|
5
|
+
* This module OWNS the char-grid representation (the "SVG for pixels" EDIT
|
|
6
|
+
* surface), the overlap safety logic, and the palette-accurate PNG render (the
|
|
7
|
+
* JUDGE surface). The `gfx show`/`gfx set`/`gfx render` commands are thin wiring
|
|
8
|
+
* over it. It is separable from the cart model (it only speaks nibble grids,
|
|
9
|
+
* strings, and RGB buffers) so it round-trips in isolation.
|
|
10
|
+
*/
|
|
11
|
+
export { GRID_SIZE, GfxGridError, gridToNibbles, nibblesToGrid, TRANSPARENT_CHAR, } from './grid.js';
|
|
12
|
+
export { LABEL_SIZE, LabelError, labelHexFromPng, nearestPaletteIndex, } from './label.js';
|
|
13
|
+
export { decideOverlap, type OverlapDecision, spriteHasData } from './overlap.js';
|
|
14
|
+
export { PICO8_PALETTE, type PaletteColor, paletteColor } from './palette.js';
|
|
15
|
+
export { encodePng, type RgbImage } from './png.js';
|
|
16
|
+
export { RENDER_TARGET_PX, renderSheetPng, renderSpritePng, SHEET_RENDER_SCALE, SPRITE_RENDER_SCALE, upscale, } from './render.js';
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/engine/gfx/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACN,SAAS,EACT,YAAY,EACZ,aAAa,EACb,aAAa,EACb,gBAAgB,GAChB,MAAM,WAAW,CAAC;AACnB,OAAO,EACN,UAAU,EACV,UAAU,EACV,eAAe,EACf,mBAAmB,GACnB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAC,aAAa,EAAE,KAAK,eAAe,EAAE,aAAa,EAAC,MAAM,cAAc,CAAC;AAChF,OAAO,EAAC,aAAa,EAAE,KAAK,YAAY,EAAE,YAAY,EAAC,MAAM,cAAc,CAAC;AAC5E,OAAO,EAAC,SAAS,EAAE,KAAK,QAAQ,EAAC,MAAM,UAAU,CAAC;AAClD,OAAO,EACN,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,OAAO,GACP,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `engine/gfx` — the shrinko-free char-grid codec (`__gfx__` nibbles ↔ char
|
|
3
|
+
* grid) plus the gfx/map overlap smart-refuse decision.
|
|
4
|
+
*
|
|
5
|
+
* This module OWNS the char-grid representation (the "SVG for pixels" EDIT
|
|
6
|
+
* surface), the overlap safety logic, and the palette-accurate PNG render (the
|
|
7
|
+
* JUDGE surface). The `gfx show`/`gfx set`/`gfx render` commands are thin wiring
|
|
8
|
+
* over it. It is separable from the cart model (it only speaks nibble grids,
|
|
9
|
+
* strings, and RGB buffers) so it round-trips in isolation.
|
|
10
|
+
*/
|
|
11
|
+
export { GRID_SIZE, GfxGridError, gridToNibbles, nibblesToGrid, TRANSPARENT_CHAR, } from './grid.js';
|
|
12
|
+
export { LABEL_SIZE, LabelError, labelHexFromPng, nearestPaletteIndex, } from './label.js';
|
|
13
|
+
export { decideOverlap, spriteHasData } from './overlap.js';
|
|
14
|
+
export { PICO8_PALETTE, paletteColor } from './palette.js';
|
|
15
|
+
export { encodePng } from './png.js';
|
|
16
|
+
export { RENDER_TARGET_PX, renderSheetPng, renderSpritePng, SHEET_RENDER_SCALE, SPRITE_RENDER_SCALE, upscale, } from './render.js';
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/engine/gfx/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACN,SAAS,EACT,YAAY,EACZ,aAAa,EACb,aAAa,EACb,gBAAgB,GAChB,MAAM,WAAW,CAAC;AACnB,OAAO,EACN,UAAU,EACV,UAAU,EACV,eAAe,EACf,mBAAmB,GACnB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAC,aAAa,EAAwB,aAAa,EAAC,MAAM,cAAc,CAAC;AAChF,OAAO,EAAC,aAAa,EAAqB,YAAY,EAAC,MAAM,cAAc,CAAC;AAC5E,OAAO,EAAC,SAAS,EAAgB,MAAM,UAAU,CAAC;AAClD,OAAO,EACN,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,OAAO,GACP,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `__label__` builder: turn a 128x128 image into the hex a `.p8` cart's
|
|
3
|
+
* label section holds, so `picopilot export --label <png>` can give a labelless
|
|
4
|
+
* cart a loading splash WITHOUT an interactive PICO-8 (F7) capture.
|
|
5
|
+
*
|
|
6
|
+
* A PICO-8 label is a 128x128 grid of palette indices (0..15), serialised as 128
|
|
7
|
+
* rows of 128 hex nibbles. This module decodes a PNG to RGB (via Node's stdlib
|
|
8
|
+
* `zlib` inflate, no npm dependency), maps each pixel to the NEAREST PICO-8
|
|
9
|
+
* palette colour, and emits that hex. It is the inverse direction of the
|
|
10
|
+
* palette-accurate PNG RENDER in `render.ts`/`png.ts` (which goes indices -> RGB).
|
|
11
|
+
*
|
|
12
|
+
* It intentionally supports only the PNG subset a caller realistically produces
|
|
13
|
+
* for a 128x128 label: 8-bit, non-interlaced, colour types 2 (RGB) and 6 (RGBA),
|
|
14
|
+
* and (via the palette map) 0/3 are rejected with a clear error rather than
|
|
15
|
+
* guessed at. Anything else fails loud with a structured {@link LabelError}.
|
|
16
|
+
*/
|
|
17
|
+
/** The fixed PICO-8 label dimensions: a 128x128 image. */
|
|
18
|
+
export declare const LABEL_SIZE = 128;
|
|
19
|
+
/** A structured label-build failure (bad PNG, wrong size, unsupported format). */
|
|
20
|
+
export declare class LabelError extends Error {
|
|
21
|
+
readonly code: 'not-a-png' | 'unsupported-png' | 'wrong-size' | 'truncated-png';
|
|
22
|
+
constructor(code: 'not-a-png' | 'unsupported-png' | 'wrong-size' | 'truncated-png', message: string);
|
|
23
|
+
}
|
|
24
|
+
/** The nearest PICO-8 palette index (by squared RGB distance) for an RGB triple. */
|
|
25
|
+
export declare function nearestPaletteIndex(r: number, g: number, b: number): number;
|
|
26
|
+
/**
|
|
27
|
+
* Builds the `__label__` hex body (128 rows of 128 nibbles, newline-joined, with
|
|
28
|
+
* a trailing newline) from a 128x128 PNG. Each pixel is mapped to its nearest
|
|
29
|
+
* PICO-8 palette colour. The PNG MUST be exactly 128x128 ({@link LABEL_SIZE});
|
|
30
|
+
* anything else is a {@link LabelError} (`wrong-size`) so a mis-sized image fails
|
|
31
|
+
* loud instead of being silently cropped or stretched.
|
|
32
|
+
*/
|
|
33
|
+
export declare function labelHexFromPng(pngBytes: Uint8Array): string;
|
|
34
|
+
//# sourceMappingURL=label.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"label.d.ts","sourceRoot":"","sources":["../../../src/engine/gfx/label.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,0DAA0D;AAC1D,eAAO,MAAM,UAAU,MAAM,CAAC;AAE9B,kFAAkF;AAClF,qBAAa,UAAW,SAAQ,KAAK;IAEnC,QAAQ,CAAC,IAAI,EACZ,WAAW,GAAG,iBAAiB,GAAG,YAAY,GAAG,eAAe;gBADxD,IAAI,EACZ,WAAW,GAAG,iBAAiB,GAAG,YAAY,GAAG,eAAe,EACjE,OAAO,EAAE,MAAM;CAKhB;AAsJD,oFAAoF;AACpF,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAe3E;AAID;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,UAAU,GAAG,MAAM,CAkB5D"}
|