From 3e3497aaead79213f56f5fe69dee0cf2601b4aed Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 11 Oct 2026 15:23:34 +0000 Subject: [PATCH] =?UTF-8?q?=E6=89=A9=E5=85=85=20Kenney=20CC0=20=E5=AE=98?= =?UTF-8?q?=E6=96=B9=E7=B4=A0=E6=9D=90=E5=BA=93=EF=BC=88#14=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 按主题精选平台跳跃、迷宫地牢、太空射击、竞速、益智、界面和音效,写入版本化 manifest。地图、动画和声音编辑器可以按需使用这些副本。 Co-authored-by: Jett Wang --- docs/asset-credits.md | 26 + docs/roadmap.md | 15 +- docs/runtime.md | 4 +- public/asset-packs/index.json | 84 +++ .../kenney-dungeon/effects/flower.png | Bin 0 -> 107 bytes .../asset-packs/kenney-dungeon/manifest.json | 217 ++++++ .../kenney-dungeon/props/crate.png | Bin 0 -> 120 bytes .../asset-packs/kenney-dungeon/props/door.png | Bin 0 -> 163 bytes .../asset-packs/kenney-dungeon/props/flag.png | Bin 0 -> 150 bytes .../kenney-dungeon/sounds/door.ogg | Bin 0 -> 22848 bytes .../kenney-dungeon/sounds/step.ogg | Bin 0 -> 9475 bytes .../kenney-dungeon/tilesets/rooms.png | Bin 0 -> 956 bytes .../characters/walker-blue.png | Bin 0 -> 321 bytes .../kenney-platform/characters/walker.png | Bin 0 -> 330 bytes .../kenney-platform/effects/dust.png | Bin 0 -> 162 bytes .../asset-packs/kenney-platform/manifest.json | 354 +++++++++ .../kenney-platform/props/pebble.png | Bin 0 -> 183 bytes .../kenney-platform/sounds/jump.ogg | Bin 0 -> 6733 bytes .../kenney-platform/sounds/step.ogg | Bin 0 -> 8290 bytes .../kenney-platform/terrain/dirt.png | Bin 0 -> 142 bytes .../kenney-platform/terrain/grass-edge.png | Bin 0 -> 178 bytes .../kenney-platform/terrain/grass.png | Bin 0 -> 198 bytes .../kenney-platform/terrain/stone.png | Bin 0 -> 190 bytes .../kenney-platform/terrain/water.png | Bin 0 -> 169 bytes .../kenney-puzzle/characters/player.png | Bin 0 -> 2429 bytes .../asset-packs/kenney-puzzle/manifest.json | 184 +++++ .../asset-packs/kenney-puzzle/sounds/ok.ogg | Bin 0 -> 8968 bytes .../kenney-puzzle/sounds/place.ogg | Bin 0 -> 6019 bytes .../kenney-puzzle/tilesets/blocks.png | Bin 0 -> 4848 bytes .../kenney-racing/characters/driver.png | Bin 0 -> 296 bytes .../kenney-racing/effects/light.png | Bin 0 -> 128 bytes .../asset-packs/kenney-racing/manifest.json | 330 +++++++++ .../kenney-racing/props/barrier.png | Bin 0 -> 145 bytes .../asset-packs/kenney-racing/props/bus.png | Bin 0 -> 289 bytes .../kenney-racing/props/car-green.png | Bin 0 -> 239 bytes .../kenney-racing/props/car-red.png | Bin 0 -> 232 bytes .../asset-packs/kenney-racing/props/sign.png | Bin 0 -> 134 bytes .../asset-packs/kenney-racing/props/taxi.png | Bin 0 -> 251 bytes .../kenney-racing/sounds/clank.ogg | Bin 0 -> 10474 bytes .../kenney-racing/sounds/crash.ogg | Bin 0 -> 7651 bytes .../kenney-racing/terrain/road.png | Bin 0 -> 208 bytes public/asset-packs/kenney-sfx/manifest.json | 378 ++++++++++ public/asset-packs/kenney-sfx/sounds/back.ogg | Bin 0 -> 6997 bytes public/asset-packs/kenney-sfx/sounds/boom.ogg | Bin 0 -> 9408 bytes .../asset-packs/kenney-sfx/sounds/click.ogg | Bin 0 -> 4876 bytes public/asset-packs/kenney-sfx/sounds/coin.ogg | Bin 0 -> 6019 bytes .../asset-packs/kenney-sfx/sounds/confirm.ogg | Bin 0 -> 8968 bytes public/asset-packs/kenney-sfx/sounds/door.ogg | Bin 0 -> 22848 bytes public/asset-packs/kenney-sfx/sounds/hit.ogg | Bin 0 -> 5351 bytes .../kenney-sfx/sounds/jump-soft.ogg | Bin 0 -> 6342 bytes public/asset-packs/kenney-sfx/sounds/jump.ogg | Bin 0 -> 6733 bytes .../kenney-sfx/sounds/laser-small.ogg | Bin 0 -> 7286 bytes .../asset-packs/kenney-sfx/sounds/laser.ogg | Bin 0 -> 9315 bytes .../asset-packs/kenney-sfx/sounds/power.ogg | Bin 0 -> 9011 bytes .../asset-packs/kenney-sfx/sounds/punch.ogg | Bin 0 -> 8800 bytes .../kenney-sfx/sounds/step-stone.ogg | Bin 0 -> 9475 bytes public/asset-packs/kenney-sfx/sounds/step.ogg | Bin 0 -> 8290 bytes .../kenney-space/characters/enemy-2.png | Bin 0 -> 296 bytes .../kenney-space/characters/enemy.png | Bin 0 -> 238 bytes .../kenney-space/characters/ship.png | Bin 0 -> 296 bytes .../kenney-space/effects/flare.png | Bin 0 -> 129 bytes .../kenney-space/effects/spark.png | Bin 0 -> 95 bytes .../asset-packs/kenney-space/effects/star.png | Bin 0 -> 102 bytes public/asset-packs/kenney-space/manifest.json | 288 ++++++++ .../asset-packs/kenney-space/sounds/hit.ogg | Bin 0 -> 5351 bytes .../asset-packs/kenney-space/sounds/laser.ogg | Bin 0 -> 9315 bytes .../kenney-space/tilesets/ground.png | Bin 0 -> 934 bytes .../asset-packs/kenney-ui/icons/box-check.png | Bin 0 -> 559 bytes public/asset-packs/kenney-ui/icons/box.png | Bin 0 -> 280 bytes public/asset-packs/kenney-ui/icons/check.png | Bin 0 -> 377 bytes public/asset-packs/kenney-ui/icons/circle.png | Bin 0 -> 312 bytes public/asset-packs/kenney-ui/icons/cross.png | Bin 0 -> 350 bytes public/asset-packs/kenney-ui/icons/down.png | Bin 0 -> 414 bytes public/asset-packs/kenney-ui/icons/left.png | Bin 0 -> 402 bytes public/asset-packs/kenney-ui/icons/right.png | Bin 0 -> 422 bytes public/asset-packs/kenney-ui/icons/square.png | Bin 0 -> 142 bytes public/asset-packs/kenney-ui/icons/star.png | Bin 0 -> 1507 bytes public/asset-packs/kenney-ui/icons/up.png | Bin 0 -> 391 bytes public/asset-packs/kenney-ui/manifest.json | 342 +++++++++ public/asset-packs/kenney-ui/sounds/back.ogg | Bin 0 -> 6997 bytes public/asset-packs/kenney-ui/sounds/click.ogg | Bin 0 -> 4876 bytes scripts/build-kenney-packs.py | 680 ++++++++++++++++++ scripts/write-forest-pack.ts | 19 +- src/lib/assets/forest.ts | 4 +- src/lib/assets/kenney.test.ts | 83 +++ src/lib/assets/schema.ts | 13 + src/lib/assets/sprite-note.ts | 20 + src/lib/assets/tileset.ts | 30 + src/lib/assets/validate.test.ts | 8 +- src/lib/assets/validate.ts | 29 + src/lib/recipes/catalog.ts | 21 +- src/studio/store.tsx | 62 +- src/ui/LibraryDialog.tsx | 50 +- src/ui/MapEditor.tsx | 12 +- src/ui/MapNewDialog.tsx | 84 ++- src/ui/SoundEditor.tsx | 37 + src/ui/sound-editor.css | 8 + src/ui/text.ts | 6 + tests/e2e/kenney.spec.ts | 98 +++ 99 files changed, 3449 insertions(+), 37 deletions(-) create mode 100644 docs/asset-credits.md create mode 100644 public/asset-packs/kenney-dungeon/effects/flower.png create mode 100644 public/asset-packs/kenney-dungeon/manifest.json create mode 100644 public/asset-packs/kenney-dungeon/props/crate.png create mode 100644 public/asset-packs/kenney-dungeon/props/door.png create mode 100644 public/asset-packs/kenney-dungeon/props/flag.png create mode 100644 public/asset-packs/kenney-dungeon/sounds/door.ogg create mode 100644 public/asset-packs/kenney-dungeon/sounds/step.ogg create mode 100644 public/asset-packs/kenney-dungeon/tilesets/rooms.png create mode 100644 public/asset-packs/kenney-platform/characters/walker-blue.png create mode 100644 public/asset-packs/kenney-platform/characters/walker.png create mode 100644 public/asset-packs/kenney-platform/effects/dust.png create mode 100644 public/asset-packs/kenney-platform/manifest.json create mode 100644 public/asset-packs/kenney-platform/props/pebble.png create mode 100644 public/asset-packs/kenney-platform/sounds/jump.ogg create mode 100644 public/asset-packs/kenney-platform/sounds/step.ogg create mode 100644 public/asset-packs/kenney-platform/terrain/dirt.png create mode 100644 public/asset-packs/kenney-platform/terrain/grass-edge.png create mode 100644 public/asset-packs/kenney-platform/terrain/grass.png create mode 100644 public/asset-packs/kenney-platform/terrain/stone.png create mode 100644 public/asset-packs/kenney-platform/terrain/water.png create mode 100644 public/asset-packs/kenney-puzzle/characters/player.png create mode 100644 public/asset-packs/kenney-puzzle/manifest.json create mode 100644 public/asset-packs/kenney-puzzle/sounds/ok.ogg create mode 100644 public/asset-packs/kenney-puzzle/sounds/place.ogg create mode 100644 public/asset-packs/kenney-puzzle/tilesets/blocks.png create mode 100644 public/asset-packs/kenney-racing/characters/driver.png create mode 100644 public/asset-packs/kenney-racing/effects/light.png create mode 100644 public/asset-packs/kenney-racing/manifest.json create mode 100644 public/asset-packs/kenney-racing/props/barrier.png create mode 100644 public/asset-packs/kenney-racing/props/bus.png create mode 100644 public/asset-packs/kenney-racing/props/car-green.png create mode 100644 public/asset-packs/kenney-racing/props/car-red.png create mode 100644 public/asset-packs/kenney-racing/props/sign.png create mode 100644 public/asset-packs/kenney-racing/props/taxi.png create mode 100644 public/asset-packs/kenney-racing/sounds/clank.ogg create mode 100644 public/asset-packs/kenney-racing/sounds/crash.ogg create mode 100644 public/asset-packs/kenney-racing/terrain/road.png create mode 100644 public/asset-packs/kenney-sfx/manifest.json create mode 100644 public/asset-packs/kenney-sfx/sounds/back.ogg create mode 100644 public/asset-packs/kenney-sfx/sounds/boom.ogg create mode 100644 public/asset-packs/kenney-sfx/sounds/click.ogg create mode 100644 public/asset-packs/kenney-sfx/sounds/coin.ogg create mode 100644 public/asset-packs/kenney-sfx/sounds/confirm.ogg create mode 100644 public/asset-packs/kenney-sfx/sounds/door.ogg create mode 100644 public/asset-packs/kenney-sfx/sounds/hit.ogg create mode 100644 public/asset-packs/kenney-sfx/sounds/jump-soft.ogg create mode 100644 public/asset-packs/kenney-sfx/sounds/jump.ogg create mode 100644 public/asset-packs/kenney-sfx/sounds/laser-small.ogg create mode 100644 public/asset-packs/kenney-sfx/sounds/laser.ogg create mode 100644 public/asset-packs/kenney-sfx/sounds/power.ogg create mode 100644 public/asset-packs/kenney-sfx/sounds/punch.ogg create mode 100644 public/asset-packs/kenney-sfx/sounds/step-stone.ogg create mode 100644 public/asset-packs/kenney-sfx/sounds/step.ogg create mode 100644 public/asset-packs/kenney-space/characters/enemy-2.png create mode 100644 public/asset-packs/kenney-space/characters/enemy.png create mode 100644 public/asset-packs/kenney-space/characters/ship.png create mode 100644 public/asset-packs/kenney-space/effects/flare.png create mode 100644 public/asset-packs/kenney-space/effects/spark.png create mode 100644 public/asset-packs/kenney-space/effects/star.png create mode 100644 public/asset-packs/kenney-space/manifest.json create mode 100644 public/asset-packs/kenney-space/sounds/hit.ogg create mode 100644 public/asset-packs/kenney-space/sounds/laser.ogg create mode 100644 public/asset-packs/kenney-space/tilesets/ground.png create mode 100644 public/asset-packs/kenney-ui/icons/box-check.png create mode 100644 public/asset-packs/kenney-ui/icons/box.png create mode 100644 public/asset-packs/kenney-ui/icons/check.png create mode 100644 public/asset-packs/kenney-ui/icons/circle.png create mode 100644 public/asset-packs/kenney-ui/icons/cross.png create mode 100644 public/asset-packs/kenney-ui/icons/down.png create mode 100644 public/asset-packs/kenney-ui/icons/left.png create mode 100644 public/asset-packs/kenney-ui/icons/right.png create mode 100644 public/asset-packs/kenney-ui/icons/square.png create mode 100644 public/asset-packs/kenney-ui/icons/star.png create mode 100644 public/asset-packs/kenney-ui/icons/up.png create mode 100644 public/asset-packs/kenney-ui/manifest.json create mode 100644 public/asset-packs/kenney-ui/sounds/back.ogg create mode 100644 public/asset-packs/kenney-ui/sounds/click.ogg create mode 100644 scripts/build-kenney-packs.py create mode 100644 src/lib/assets/kenney.test.ts create mode 100644 src/lib/assets/sprite-note.ts create mode 100644 src/lib/assets/tileset.ts create mode 100644 tests/e2e/kenney.spec.ts diff --git a/docs/asset-credits.md b/docs/asset-credits.md new file mode 100644 index 0000000..826ca16 --- /dev/null +++ b/docs/asset-credits.md @@ -0,0 +1,26 @@ +# 素材来源 + +内置素材库里的官方精选,除了 GameKit 自己画的森林,都来自 [Kenney](https://kenney.nl/assets)。Kenney 这些包以 [CC0 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode) 贡献到公共领域。使用时不要求署名。GameKit 仍然记下作者、原包链接和内容 hash,缺了许可或来源就不能构建。 + +每个主题只收了原包里风格协调的一小部分:角色、地形或瓦片、道具、特效、短音效。没有整包搬进来,也没有热链接到 kenney.nl。复制进项目的是文件本身,运行和导出都不访问外网。 + +| 包 | 主题 | 文件数 | 原包 | +| --- | --- | --- | --- | +| `kenney-platform` | 平台跳跃 | 11 | [Pixel Platformer](https://kenney.nl/assets/pixel-platformer) | +| `kenney-dungeon` | 迷宫地牢 | 7 | [Tiny Dungeon](https://kenney.nl/assets/tiny-dungeon) | +| `kenney-space` | 太空射击 | 9 | [Pixel Shmup](https://kenney.nl/assets/pixel-shmup) | +| `kenney-racing` | 竞速 | 11 | [Pixel Vehicle Pack](https://kenney.nl/assets/pixel-vehicle-pack) | +| `kenney-puzzle` | 益智 | 4 | [Sokoban](https://kenney.nl/assets/sokoban) | +| `kenney-ui` | 界面 | 13 | [UI Pack](https://kenney.nl/assets/ui-pack)(只要蓝色默认样式) | +| `kenney-sfx` | 音效 | 15 | [Kenney 素材](https://kenney.nl/assets) 里的短声音。每条声音的来源指向它自己的原包:Digital Audio、Impact Sounds、Interface Sounds、RPG Audio、Sci-fi Sounds | + +音效是原来的 OGG Vorbis,没有转码。文件头里要能认出 Vorbis,构建才会通过。 + +有三处为了接上现有编辑器,动过像素,说明写在包的署名里: + +- 平台跳跃的地形是原来的 18 像素单张图。地图编辑器只收 8、16、32 像素的方格,所以这些地形不进地图调色板。 +- 迷宫地牢和太空射击的图块是原来的 16 像素,排成 4×4,地图编辑器可以直接用。地牢包没有单独的角色图。 +- 益智图块从 Sokoban 的 64 像素用最近邻缩到 32 像素。推箱子的人仍是 64 像素,四帧排成精灵表。 +- 竞速的人原来每帧宽窄不一样,这里放进同样的 16×16 透明格子,脚对齐到底边,动画编辑器才能打开。车还是原来的大小。 + +GameKit 自己的「森林冒险」和「森林声音」不是 Kenney 的图,作者是 GameKit,许可同样是 CC0。 diff --git a/docs/roadmap.md b/docs/roadmap.md index d60fcad..31acd5d 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -232,7 +232,7 @@ Worker 对每个 `/api/*` 请求校验 Access JWT(签名、aud、iss、过期 「看代码」的文件栏和素材区都能「画地图」。先选关卡名、文件名(`maps/level-1.map.json`)、大小(10×8、20×12、32×18)和格子(8/16/32)。编辑器里有瓦片调色板、点绘、矩形、填充、擦除,最多四层,可以藏起来或上下移动。背景是天空、夜晚、洞穴或沙滩。碰撞是单独的一层标注(0 能走,1 不能走)。出生点只有一个。物件标记是金币、敌人、门或标记,点同一格再拿掉。画面上可以叠上碰撞和标记,当作简单预览。撤销和重做只在编辑器里,不写文件。 -保存写一组普通文件,路径都由文件名算出来,说明里的路径不能指到别的文件:`maps/<名字>.map.json`(格式 `gamekit.map`)、每一层一个 CSV、`maps/<名字>.collision.csv`、`maps/<名字>.tileset.png`。新地图自带一张 8 格的瓦片图。格子里的 0 是空的,1 是瓦片图上从左往右的第一格。孩子可以在「看代码」里改这些数字,再打开编辑器就是改过的样子。导出一份地图包(JSON,里面是同样的文件),再导入会回到同一张图,先不写入项目;存的时候才写,并且可以撤销。 +保存写一组普通文件,路径都由文件名算出来,说明里的路径不能指到别的文件:`maps/<名字>.map.json`(格式 `gamekit.map`)、每一层一个 CSV、`maps/<名字>.collision.csv`、`maps/<名字>.tileset.png`。新地图可以选纯色方块,也可以选素材库里格子是 8、16 或 32 像素、不超过 32 格的图块。选中的图会复制进项目里的瓦片图,不连到素材库。格子里的 0 是空的,1 是瓦片图上从左往右的第一格。孩子可以在「看代码」里改这些数字,再打开编辑器就是改过的样子。导出一份地图包(JSON,里面是同样的文件),再导入会回到同一张图,先不写入项目;存的时候才写,并且可以撤销。 读取是普通 pygame。「把读取代码放进项目」写入可见的 `map_loader.py`(`load_map`、`solid_at`、`draw_map`),项目里已有不同内容时不盖掉。「在舞台上看这一关」先确认,再把 `main.py` 换成一段带 `await asyncio.sleep(0)` 的代码,打出出生点像素、碰撞格数和瓦片图上的一个像素。工作室撤销可以回到原来的代码。不引入 GameKit 运行库,`runtime/player.tmpl` 没有改。 @@ -246,7 +246,7 @@ Worker 对每个 `/api/*` 请求校验 Access JWT(签名、aud、iss、过期 「看代码」的素材区能打开声音。预设有跳跃、轻跳、金币、碰到蘑菇和一段走路音乐,不登录也能用。滑杆改波形、音高、包络、音量,也能截取一头一尾。勾上循环时,首尾会接上,免得 `play(-1)` 爆音。音乐能改速度和小节,主旋律、低音、踩镲可以单独听。画面上的包络和波形就是正在听的那一份。点保存,写进项目的 WAV 和刚才试听的字节相同,可以撤销。写入失败时项目不变,声音还留在编辑器里。 -「在舞台上听听」会先给看 `main.py` 变成什么样,确认后才写。那段代码是普通 pygame:点一下画面再 `mixer.init()` 和 `Sound.play`,并且 `await asyncio.sleep(0)`。官方音效在素材库的「森林声音」包里,和森林的图用同一套标签连着(跳跃对角色,金币对金币,蘑菇对蘑菇)。轻跳是跳跃的一种变体,改参数就行,不用重新画图。孩子收录的声音存在这台电脑上,清单字段和官方包一样(许可、作者、来源、署名、hash),格式不对的不会收。复制进项目之后,游戏读的是项目里的文件。 +「在舞台上听听」会先给看 `main.py` 变成什么样,确认后才写。那段代码是普通 pygame:点一下画面再 `mixer.init()` 和 `Sound.play`,并且 `await asyncio.sleep(0)`。官方音效在素材库里:GameKit 合成的「森林声音」,以及 Kenney CC0 的 OGG Vorbis。声音编辑器打开后可以试听这些声音,试听不写入项目;要放进游戏仍从素材库复制。森林的图和声音用同一套标签连着(跳跃对角色,金币对金币,蘑菇对蘑菇)。轻跳是跳跃的一种变体,改参数就行,不用重新画图。孩子收录的声音存在这台电脑上,清单字段和官方包一样(许可、作者、来源、署名、hash),格式不对的不会收。复制进项目之后,游戏读的是项目里的文件。 浏览器能播的是 16-bit PCM WAV,和通过检查的 OGG Vorbis。MP3、AIFF、坏 WAV、Opus 会在问题里说明。小助手和 WebMCP 不能改这些音频文件,也不能改素材库记录。 @@ -254,9 +254,10 @@ Worker 对每个 `/api/*` 请求校验 Access JWT(签名、aud、iss、过期 - 内置素材库(阶段 A,不登录可用) -顶栏和「看代码」的素材区都能打开素材库。包的说明是版本化的 `asset-pack` manifest(稳定 id、版本、路径、媒体类型、像素尺寸、动画帧和碰撞、中文标签、主题、预览、许可/作者/来源/署名、内容 hash),语义不靠文件名猜。现在收录一套 GameKit 原创、CC0 的「森林冒险」(角色、地形、道具、界面)。缩略图和包说明在打开素材库之后才加载,不进首屏脚本。 -复制进项目的是文件本身,记在 `assets/library/<包>/…`,版本写在 `assets/library.json`。运行和导出用的是这份副本,不访问素材库。同名、重复、更新和替换都会先说明,不会静默盖掉;盖掉之后可以撤销。加载示例是普通的 `pygame.image.load`。小助手和 WebMCP 可以检索目录、把某一份点名为候选;采用时才按同一套复制规则写入。它们不能在文件里直接写二进制,也不能盖掉已经不一样的那一份,也不能改孩子手写的 `assets/library.json`。 -入口 `src/ui/LibraryDialog.tsx`、`src/lib/assets/`、`public/asset-packs/`。还没做:更多主题包、孩子自己跨项目的图片。动画编辑器已在阶段 B 交付,地图编辑器已在阶段 C 交付。官方音效和孩子收录的声音已在阶段 D 放进同一套清单。配方和检索已在阶段 E 交付。 +顶栏和「看代码」的素材区都能打开素材库。包的说明是版本化的 `asset-pack` manifest(稳定 id、版本、路径、媒体类型、像素尺寸、动画帧、瓦片网格和碰撞、中文标签、主题、预览、许可/作者/来源/署名、内容 hash),语义不靠文件名猜。现在有 GameKit 原创、CC0 的「森林冒险」和「森林声音」,再加上 Kenney CC0 精选:平台跳跃、迷宫地牢、太空射击、竞速、益智、界面、音效。每个主题只收协调的一小套,不整包搬入。来源和许可写在 [docs/asset-credits.md](asset-credits.md)。缩略图和包说明在打开素材库、地图新建或声音编辑器之后才加载,不进首屏脚本。 +带动画说明的角色可以「在动画里打开」:先按同样的规则复制进项目,再写下旁边的 `.anim.json`,然后打开动画编辑器。同名冲突时,保留原来的不会打开编辑器。 +复制进项目的是文件本身,记在 `assets/library/<包>/…`,版本写在 `assets/library.json`。运行和导出用的是这份副本,不访问素材库,也不访问 kenney.nl。同名、重复、更新和替换都会先说明,不会静默盖掉;盖掉之后可以撤销。加载示例是普通的 `pygame.image.load`。小助手和 WebMCP 可以检索目录、把某一份点名为候选;采用时才按同一套复制规则写入。它们不能在文件里直接写二进制,也不能盖掉已经不一样的那一份,也不能改孩子手写的 `assets/library.json`。 +入口 `src/ui/LibraryDialog.tsx`、`src/lib/assets/`、`public/asset-packs/`。还没做:孩子自己跨项目的图片。动画编辑器已在阶段 B 交付,地图编辑器已在阶段 C 交付。官方音效和孩子收录的声音已在阶段 D 放进同一套清单。配方和检索已在阶段 E 交付。平台跳跃、迷宫和卡通射击的说明里提到了可以用的 Kenney 包,检查仍只看原来的源码和舞台标记。 - 游戏配方与分步挑战(阶段 E,不登录可用) @@ -289,7 +290,7 @@ Worker 对每个 `/api/*` 请求校验 Access JWT(签名、aud、iss、过期 | 阶段 | 状态 | 范围 | | --- | --- | --- | -| A. 统一内置资产库闭环 | 已交付 | 版本化 manifest、一个 CC0 主题包、匿名浏览/预览、复制进项目并固定版本、pygame 示例、离线导出。见上「内置素材库」 | +| A. 统一内置资产库闭环 | 已交付 | 版本化 manifest、森林冒险,以及 Kenney CC0 的平台跳跃、迷宫地牢、太空射击、竞速、益智、界面和音效。匿名浏览/预览、复制进项目并固定版本、pygame 示例、离线导出。见上「内置素材库」 | | B. 精灵与动画编辑器 | 已交付 | 帧时间轴、精灵表、多动作、选区与图层。产物是 PNG + 可读 JSON,播放是普通 pygame。见上「精灵与动画编辑器」 | | C. 可视化瓦片地图 | 已交付 | 瓦片调色板、点绘/矩形/填充/擦除、图层、背景、出生点、物件标记、碰撞标注和预览。产物是 JSON + CSV + PNG,并附可读的 pygame 加载示例。见上「瓦片地图编辑器」 | | D. 音效与音乐编辑 | 已交付 | 预设、包络和波形、裁剪、音量、循环、音乐的节奏和声部。官方音效与收录的声音走同一套清单。导出的 WAV 离线可播。见上「音效编辑器」 | @@ -434,7 +435,7 @@ PNG/OGG/数据文件,代码用标准 pygame 读取。不依赖 AI,未登录 | PWA 与离线 | 未实现 | 中 | ❌ 缺口 | ❌ 缺口 | 不适用 | ❌ 缺口(更新失败回到旧版本) | 无 | | MCP / WebMCP 外部协作 | 已有 | 高(外部写入、权限) | ✅(开启协作、显示状态与 MCP URL、外部提案生成候选、采用写入并支持撤销;授权用户检索素材目录、提议一份素材成为候选) | ✅(未登录拒绝开启、丢弃提案后项目不变、无效 Token 拒绝;没有令牌不能检索;不存在的素材 id 不产生候选;项目里已有同路径时不能盖掉) | ✅ 匿名页面可检索和做候选但不调 `/api/`;MCP 通道要令牌。已登录未授权沿用身份门拒绝 | ✅(丢弃提案项目不变;采用后可撤销;冲突的素材提议不写入) | `tests/e2e/collab.spec.ts`(4 条)、`tests/e2e/recipes.spec.ts`、`worker/mcp.test.ts` | | 游戏配方与教程 | 已有(阶段 E) | 中(覆盖旧项目) | ✅(匿名从平台跳跃配方新建项目,舞台打出 `RECIPE-OK platform`;旧项目还在) | ✅(未改之前检查失败;改高了但控制台仍是旧标记也失败;`time.sleep` 失败) | ✅ 匿名可用,不发 `/api/`。已登录未授权仍可做配方。小助手对话仍要授权 | ✅(挑战候选在采用前不改 `JUMP`;丢掉后仍是 -9;采用后检查通过;撤销后再次失败) | `tests/e2e/recipes.spec.ts`;`src/lib/recipes/recipes.test.ts` | -| 内置素材库 | 已有(阶段 A:一个「森林冒险」包。更多主题、跨项目个人图片未做;动画见阶段 B,地图见阶段 C,检索见阶段 E) | 高(覆盖作品、版权) | ✅(匿名浏览、筛选、预览许可与来源 → 复制进项目 → pygame 在舞台加载 → 源码包和网页包里都有这份文件;加入时没有 `/api/` 请求;做成候选再采用也会复制) | ✅(同名先问再保留/另存/替换;重复复制不写第二份;hash 不符或许可/来源为空则校验失败,构建会被挡住;候选遇到不同字节则拒绝) | ✅ 匿名可用。小助手和 WebMCP 不能在文件里写二进制,也不能改孩子手写的 `assets/library.json`;点名素材只进候选 | ✅(替换后撤销回到旧文件;复制后撤销去掉这份;删进回收站可以恢复;丢掉候选不留下文件) | `tests/e2e/library.spec.ts`;`tests/e2e/recipes.spec.ts`;`src/lib/assets/*.test.ts`;构建时 `vite.config.ts` 的素材包检查 | +| 内置素材库 | 已有(阶段 A:森林冒险,以及 Kenney CC0 的平台跳跃、迷宫地牢、太空射击、竞速、益智、界面、音效。跨项目个人图片未做;动画见阶段 B,地图见阶段 C,检索见阶段 E) | 高(覆盖作品、版权) | ✅(匿名浏览、筛选、预览许可与来源 → 复制进项目 → pygame 在舞台加载 → 源码包和网页包里都有这份文件;Kenney 地牢图块同样走这条路;加入时没有 `/api/` 请求;做成候选再采用也会复制;图块可开始画地图,角色帧可打开动画编辑器,音效可在声音编辑器试听) | ✅(同名先问再保留/另存/替换;重复复制不写第二份;hash 不符或许可/来源为空则校验失败,构建会被挡住;候选遇到不同字节则拒绝;瓦片网格对不上编辑器尺寸也不能构建) | ✅ 匿名可用。小助手和 WebMCP 不能在文件里写二进制,也不能改孩子手写的 `assets/library.json`;点名素材只进候选 | ✅(替换后撤销回到旧文件;复制后撤销去掉这份;删进回收站可以恢复;丢掉候选不留下文件) | `tests/e2e/library.spec.ts`;`tests/e2e/kenney.spec.ts`;`tests/e2e/recipes.spec.ts`;`src/lib/assets/*.test.ts`;构建时 `vite.config.ts` 的素材包检查 | | 像素编辑器 / 新建图片 | 已有(单张图片的画笔、保存和撤销;多帧见下一行) | 高(覆盖孩子已有素材、作品丢失) | ✅(新建 → 画 → 保存 → 项目里出现 PNG、预览里 pygame 加载;打开已有 PNG → 改 → 保存 → 撤销还原;另存为新图片;触控与笔;导出包字节一致;生成素材继续改像素) | ✅(非法尺寸被拒;同名不覆盖、自动加序号;未保存关闭先问、继续画/不保存/保存;写入失败后画布保留、可重试;缓冲区/填充越界与死循环、PNG 往返逐字节、alpha 保持、解压体积受表头限制、撤销占用有上限的单元测试;生成素材里「保存并关闭」不会再弹出空的生成面板) | ✅ 匿名可用(不发任何 `/api/` 请求;不新增 AI 工具,小助手与 WebMCP 没有改 assets/ 的能力) | ✅(写入失败不留半成品,重试成功;覆盖可用工作室撤销还原;新图保存后可撤销) | `tests/e2e/pixel.spec.ts`(14 条);`src/lib/pixel/*.test.ts`(单张图画笔仍由 `buffer`、`png`、`rules`、`history`、`session`、`save`、`export` 覆盖;多帧见下一行) | | 精灵与动画编辑器 | 已有(阶段 B) | 高(覆盖已有素材、帧和说明对不上) | ✅(匿名:画多帧 → 设时长和动作 → 保存 → 重新打开后帧序和时长还在 → PNG 与 JSON 的像素、alpha、帧序可比对 → 源码包里两份文件都在 → pygame 在舞台打出 `ANIM-OK` 和 `ANIM-PIXEL`) | ✅(坏的动画说明按整张图打开且不改文件;写入失败时 PNG 和 JSON 都不留下,画布还在,重试成功;选区移动、图层显隐、洋葱皮、复制/删除帧、精灵表导入可撤销) | ✅ 匿名可用,不发 `/api/`。小助手和 WebMCP 不能改写 `*.anim.json` | ✅(失败写入不留半成品,重试成功;试播先确认,工作室撤销回到试播前的代码,精灵表还在) | `tests/e2e/anim.spec.ts`;`src/lib/pixel/anim.test.ts`、`film.test.ts`、`save.test.ts`;`src/lib/ai.test.ts`;`worker/mcp.test.ts` | | 瓦片地图编辑器 | 已有(阶段 C) | 高(覆盖已有关卡、半截文件) | ✅(匿名:画关 → 碰撞、出生点、物件 → 保存 → 重新打开还原 → 导出地图包再导入一致 → 源码包里有 JSON/CSV/PNG → pygame 打出 `MAP-OK` 碰撞和出生点;加入时没有 `/api/` 请求) | ✅(非法地图说明原因且原文件不变;写入失败时不留半截文件,画面还在,重试成功) | ✅ 匿名可用,不发 `/api/`。小助手和 WebMCP 不能改写 `*.map.json`、`maps/*.csv`、`*.tileset.png` | ✅(失败写入不留半成品,重试成功;试玩先确认,工作室撤销回到试玩前的代码,地图文件还在) | `tests/e2e/map.spec.ts`;`src/lib/map/*.test.ts`;`src/lib/ai.test.ts`;`worker/mcp.test.ts` | diff --git a/docs/runtime.md b/docs/runtime.md index 0a9742b..cffaffc 100644 --- a/docs/runtime.md +++ b/docs/runtime.md @@ -35,13 +35,13 @@ await asyncio.sleep(0) ## 素材库 -内置素材放在站点的 `public/asset-packs/`,打开素材库才请求说明文件和缩略图,不打进页面脚本。复制进项目的是文件字节,路径像 `assets/library/forest-adventure/characters/hero.png`,用普通 `pygame.image.load`。`assets/library.json` 只记下复制时的包版本、hash 和许可来源,游戏不要读它。 +内置素材放在站点的 `public/asset-packs/`,打开素材库、新建地图或声音编辑器才请求说明文件和缩略图,不打进页面脚本。除了 GameKit 画的森林,还有 Kenney 的 CC0 精选(见 [docs/asset-credits.md](asset-credits.md))。复制进项目的是文件字节,路径像 `assets/library/forest-adventure/characters/hero.png`,用普通 `pygame.image.load`。地图如果从素材库的图块开始,瓦片图也会存进项目里的 `maps/*.tileset.png`。`assets/library.json` 只记下复制时的包版本、hash 和许可来源,游戏不要读它。 预览和导出都打包项目里的这份副本(和别的 `assets/` 文件一样)。成品不请求素材库目录,也不请求 GameKit 站点。素材库以后升级,不会改掉已经复制进项目、或已经导出的那一份。模板本身没有为素材库改过。 ## 声音 -声音编辑器把参数合成成 16-bit 单声道 22.05 kHz WAV。试听播放的字节和保存进 `assets/` 的字节是同一份,所以导出的游戏不调用生成接口。pygame-web 能播这种 PCM WAV,也能播通过文件头检查的 OGG Vorbis。MP3、AIFF、坏掉的 WAV、以及 Ogg 里的 Opus 会在问题面板里说明,不会假装能播。官方音效在素材库里,复制进项目之后和别的 `assets/` 文件一样打包。播放用普通 `pygame.mixer.Sound`。模板没有为声音改过。声音要等孩子点一下画面才会响。 +声音编辑器把参数合成成 16-bit 单声道 22.05 kHz WAV。试听播放的字节和保存进 `assets/` 的字节是同一份,所以导出的游戏不调用生成接口。pygame-web 能播这种 PCM WAV,也能播通过文件头检查的 OGG Vorbis。MP3、AIFF、坏掉的 WAV、以及 Ogg 里的 Opus 会在问题面板里说明,不会假装能播。官方音效在素材库里,包括 Kenney 原来的 OGG Vorbis。复制进项目之后和别的 `assets/` 文件一样打包。播放用普通 `pygame.mixer.Sound`。模板没有为声音改过。声音要等孩子点一下画面才会响。 ## 精灵动画 diff --git a/public/asset-packs/index.json b/public/asset-packs/index.json index 989b859..b337cd2 100644 --- a/public/asset-packs/index.json +++ b/public/asset-packs/index.json @@ -25,6 +25,90 @@ "source": "https://github.com/talkincode/GameKit", "attribution": "这些声音由 GameKit 用参数合成,以 CC0 1.0 贡献到公共领域。使用时无需署名。不是从第三方素材站搬运的,也不是调用生成接口做的。", "assetCount": 5 + }, + { + "id": "kenney-dungeon", + "version": "1.0.0", + "title": "迷宫地牢", + "theme": "迷宫地牢", + "summary": "16 像素的地砖、墙、门、箱子和旗帜,可以放进地图编辑器。来自 Kenney 的 Tiny Dungeon,CC0。", + "license": "CC0-1.0", + "author": "Kenney", + "source": "https://kenney.nl/assets/tiny-dungeon", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。图块按 4×4 排好,每格 16 像素,地图编辑器的调色板可以直接用。原始包:https://kenney.nl/assets/tiny-dungeon", + "assetCount": 7 + }, + { + "id": "kenney-platform", + "version": "1.0.0", + "title": "平台跳跃", + "theme": "平台跳跃", + "summary": "绿色和蓝色小人、草地、泥土、石砖和水面,加上跳跃和脚步声。来自 Kenney 的 Pixel Platformer,CC0。", + "license": "CC0-1.0", + "author": "Kenney", + "source": "https://kenney.nl/assets/pixel-platformer", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。小人的两帧排成了一张精灵表,动画编辑器可以直接打开。地形保持原来的 18 像素。原始包:https://kenney.nl/assets/pixel-platformer", + "assetCount": 11 + }, + { + "id": "kenney-puzzle", + "version": "1.0.0", + "title": "益智", + "theme": "益智", + "summary": "推箱子的人和 32 像素的地面、方块、箱子。来自 Kenney 的 Sokoban,CC0。", + "license": "CC0-1.0", + "author": "Kenney", + "source": "https://kenney.nl/assets/sokoban", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。地图格子从原来的 64 像素缩小到 32 像素,好放进地图编辑器。人还是 64 像素,四帧排成精灵表。原始包:https://kenney.nl/assets/sokoban", + "assetCount": 4 + }, + { + "id": "kenney-racing", + "version": "1.0.0", + "title": "竞速", + "theme": "竞速", + "summary": "赛车、走路的人、路障和一段公路,加上撞击声。来自 Kenney 的 Pixel Vehicle Pack,CC0。", + "license": "CC0-1.0", + "author": "Kenney", + "source": "https://kenney.nl/assets/pixel-vehicle-pack", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。人的三帧原来宽窄不一样,这里放在同样的 16×16 透明格子里,动画编辑器才能打开。车还是原来的大小。原始包:https://kenney.nl/assets/pixel-vehicle-pack", + "assetCount": 11 + }, + { + "id": "kenney-sfx", + "version": "1.0.0", + "title": "音效", + "theme": "音效", + "summary": "跳跃、金币、激光、脚步、开门和点击。来自 Kenney 的几套 CC0 音效,都是原来的 OGG Vorbis。", + "license": "CC0-1.0", + "author": "Kenney", + "source": "https://kenney.nl/assets", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。这一套把 Digital Audio、Impact Sounds、Interface Sounds、RPG Audio 和 Sci-fi Sounds 里的短声音放在一起。每条声音的来源链到它自己的原包。原始包:https://kenney.nl/assets", + "assetCount": 15 + }, + { + "id": "kenney-space", + "version": "1.0.0", + "title": "太空射击", + "theme": "太空射击", + "summary": "飞船、敌机、地面图块和闪光,加上激光声。来自 Kenney 的 Pixel Shmup,CC0。", + "license": "CC0-1.0", + "author": "Kenney", + "source": "https://kenney.nl/assets/pixel-shmup", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。地面图块按 4×4 排好,每格 16 像素,地图编辑器可以直接用。飞船是原来的 32 像素。原始包:https://kenney.nl/assets/pixel-shmup", + "assetCount": 9 + }, + { + "id": "kenney-ui", + "version": "1.0.0", + "title": "界面", + "theme": "界面", + "summary": "箭头、勾、叉、星星和点击声。来自 Kenney 的 UI Pack,只要蓝色的一小套,CC0。", + "license": "CC0-1.0", + "author": "Kenney", + "source": "https://kenney.nl/assets/ui-pack", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。只收了蓝色默认样式里的小图标,没有把整套颜色都放进来。原始包:https://kenney.nl/assets/ui-pack", + "assetCount": 13 } ] } diff --git a/public/asset-packs/kenney-dungeon/effects/flower.png b/public/asset-packs/kenney-dungeon/effects/flower.png new file mode 100644 index 0000000000000000000000000000000000000000..c3b451c3328caf41144925ab043776586c335b38 GIT binary patch literal 107 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`MxHK?Ar-fh6Bda5=x6ho^uM1~ zz=*+>SI@U4#=3)Nf#iZ4%MQN2;y8!zgx@KVbTuyq2C1z7jN&`nn}NC+JYD@<);T3K F0RX^PAF==d literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-dungeon/manifest.json b/public/asset-packs/kenney-dungeon/manifest.json new file mode 100644 index 0000000..fd46a83 --- /dev/null +++ b/public/asset-packs/kenney-dungeon/manifest.json @@ -0,0 +1,217 @@ +{ + "format": "gamekit.asset-pack", + "formatVersion": 1, + "id": "kenney-dungeon", + "version": "1.0.0", + "title": "迷宫地牢", + "theme": "迷宫地牢", + "summary": "16 像素的地砖、墙、门、箱子和旗帜,可以放进地图编辑器。来自 Kenney 的 Tiny Dungeon,CC0。", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/tiny-dungeon", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。图块按 4×4 排好,每格 16 像素,地图编辑器的调色板可以直接用。原始包:https://kenney.nl/assets/tiny-dungeon", + "assets": [ + { + "id": "dungeon-tiles", + "version": "1.0.0", + "title": "地牢图块", + "path": "tilesets/rooms.png", + "mediaType": "image/png", + "tags": [ + "图块", + "地形", + "地牢" + ], + "theme": "迷宫地牢", + "category": "tileset", + "preview": "tilesets/rooms.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/tiny-dungeon", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。图块按 4×4 排好,每格 16 像素,地图编辑器的调色板可以直接用。原始包:https://kenney.nl/assets/tiny-dungeon", + "sha256": "41511ff2c66d33e65a506c70da6d82ad0e610bb2b349c9e0082a386e41a820fa", + "width": 64, + "height": 64, + "tileset": { + "tileWidth": 16, + "tileHeight": 16, + "columns": 4, + "rows": 4, + "names": [ + "棕色地砖", + "深色地砖", + "灰色地砖", + "蓝灰地砖", + "暗色地砖", + "砖墙", + "石墙", + "蓝砖", + "木地板", + "白花", + "石碑", + "木桶", + "木箱", + "木门", + "旗帜", + "木箱盖" + ] + } + }, + { + "id": "dungeon-flower", + "version": "1.0.0", + "title": "白花", + "path": "effects/flower.png", + "mediaType": "image/png", + "tags": [ + "特效", + "花" + ], + "theme": "迷宫地牢", + "category": "effect", + "preview": "effects/flower.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/tiny-dungeon", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。图块按 4×4 排好,每格 16 像素,地图编辑器的调色板可以直接用。原始包:https://kenney.nl/assets/tiny-dungeon", + "sha256": "a4cda9571f99b9d4f597bb5a99d3b419a7d54756567d8204e9b291e60019bfe6", + "width": 16, + "height": 16 + }, + { + "id": "dungeon-door", + "version": "1.0.0", + "title": "木门", + "path": "props/door.png", + "mediaType": "image/png", + "tags": [ + "道具", + "门" + ], + "theme": "迷宫地牢", + "category": "prop", + "preview": "props/door.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/tiny-dungeon", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。图块按 4×4 排好,每格 16 像素,地图编辑器的调色板可以直接用。原始包:https://kenney.nl/assets/tiny-dungeon", + "sha256": "ba976d7810eb6096c163158c0ffd171356aa9efa805bedf270e198744cc75c2d", + "width": 16, + "height": 16 + }, + { + "id": "dungeon-crate", + "version": "1.0.0", + "title": "木箱", + "path": "props/crate.png", + "mediaType": "image/png", + "tags": [ + "道具", + "箱子" + ], + "theme": "迷宫地牢", + "category": "prop", + "preview": "props/crate.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/tiny-dungeon", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。图块按 4×4 排好,每格 16 像素,地图编辑器的调色板可以直接用。原始包:https://kenney.nl/assets/tiny-dungeon", + "sha256": "25afdd367cb93441e72fa9a70699f8c0b2df6e09ef4ff124fa196f7e76247339", + "width": 16, + "height": 16 + }, + { + "id": "dungeon-flag", + "version": "1.0.0", + "title": "旗帜", + "path": "props/flag.png", + "mediaType": "image/png", + "tags": [ + "道具", + "旗帜" + ], + "theme": "迷宫地牢", + "category": "prop", + "preview": "props/flag.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/tiny-dungeon", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。图块按 4×4 排好,每格 16 像素,地图编辑器的调色板可以直接用。原始包:https://kenney.nl/assets/tiny-dungeon", + "sha256": "6cee741dcc6bf96b37a1a72dc4e99f3309358cd1f572a7093159f388ff2fecf3", + "width": 16, + "height": 16 + }, + { + "id": "dungeon-door-sfx", + "version": "1.0.0", + "title": "开门", + "path": "sounds/door.ogg", + "mediaType": "audio/ogg", + "tags": [ + "音效", + "门", + "地牢" + ], + "theme": "迷宫地牢", + "category": "sfx", + "preview": "sounds/door.ogg", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/rpg-audio", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。声音是 Kenney 原来的 OGG Vorbis,没有转码。原始包:https://kenney.nl/assets/rpg-audio", + "sha256": "4ab93bab96522d8eb109ff96dc57cb6765deb02448fe14c10472084be5bb2a0b" + }, + { + "id": "dungeon-step", + "version": "1.0.0", + "title": "石地脚步", + "path": "sounds/step.ogg", + "mediaType": "audio/ogg", + "tags": [ + "音效", + "走路", + "地牢" + ], + "theme": "迷宫地牢", + "category": "sfx", + "preview": "sounds/step.ogg", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/rpg-audio", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。声音是 Kenney 原来的 OGG Vorbis,没有转码。原始包:https://kenney.nl/assets/rpg-audio", + "sha256": "6fe61ef1fc3bcf0e253bf2eb64759db6cb69e2fe452f4d88cc597ecf78a3d601" + } + ] +} diff --git a/public/asset-packs/kenney-dungeon/props/crate.png b/public/asset-packs/kenney-dungeon/props/crate.png new file mode 100644 index 0000000000000000000000000000000000000000..12c6f526f657953a48ff3760d4cee7d868e39ec0 GIT binary patch literal 120 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`_MR?|Ar-fh6C~me#GUkKLCheVXKUCbC(D;jWKT^VV?%WyK$ zl;LK|48|J;l8gb{#+UgF9OdWlF&#^(WNhJ|vyb_hi*&=93qK#GiTF%WG+tvigPD&#^9D($Foz&p%gZW{85x{sU9?>{ac?xxA_h-aKbLh*2~7YgX*3N0 literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-dungeon/sounds/door.ogg b/public/asset-packs/kenney-dungeon/sounds/door.ogg new file mode 100644 index 0000000000000000000000000000000000000000..7df28265312494fc053380002e551b001dea89ad GIT binary patch literal 22848 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 GY#ji~`&^L# literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-dungeon/sounds/step.ogg b/public/asset-packs/kenney-dungeon/sounds/step.ogg new file mode 100644 index 0000000000000000000000000000000000000000..ca5dd2b6aa45f73f53685988aacec0a88f31887b GIT binary patch literal 9475 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 literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-dungeon/tilesets/rooms.png b/public/asset-packs/kenney-dungeon/tilesets/rooms.png new file mode 100644 index 0000000000000000000000000000000000000000..847d55dab36248737c5385f8201dca3a96fea769 GIT binary patch literal 956 zcmV;t14I0YP)?e1uAu3oxEZMnUB|9Qxk8306_*X;i5chQ=2k-E(R zaA$u0`lDJF0QR3AfOOL6fVN+9p10@wo*e*O(^uDTkA?tf|8yEa0IW4jqvipM0Kk5` z0$|m1CoKR}H{BAb1R!Zc+c!OcQR5DBV6-jiz_L}yL&I>_+DoI1$CPG(_j{8l;3YH} z06*?-kG4wy7|tvJ5z_#8OJFkqT80+^KqF71-%Qc~6grFon`l4<0LipGK(o#A0Cbc_ zrg913R7aCE^uMwD2ug5Xp}8Q z9f|#@@Vt*Fdd)Zh?H+)20d*8XEp}=EP-r3mFnO_@^Z;lxp!=4XmMwWongPJ$cQbU7 zM$;R0oK+gnhJm>bhz!scT4oN88D;)qav6A5J_-) z0F-M$b3)pdG{6Ip33Uj-OOi^K06IkulQVpu1z>Fr7y+Qws~UjGi!rL&&7Ur@S2Q)&S|5d&ZW%mnr}UDEL3wdaq0cAaa6Mn?q-r4nXujH2}T+dGW44 zb^*YeCD#8%U#poKfVV^<0JPgj;5T)6JeGvdnd7J^ft{ebAIRYRV2VfmXI)(;MdoYUtw1>Cu^vg^`I#C=o z?u4ZU9DrmN0CG}tmP5g)P!fk{0MHW#)A>L&3Gt#pbSX*Bd;Nx!p{f)(Dq_`{WJM~y e`)i3yNtFNg#4htUi*w@u0000Nfk6N|+-Chyu_Wtv6;=7bzN0^1eUTs!ELXZ2;#l zc~gctfG42jf4;q{>JH!q;QS?TP;&rJfaJg39X<*R&C3wZ;kKaEa*AAo`Pj8=J$`Zg8~fPbyyWfAvR zu7Ubw1z7ul#h?3vR5)N$05Ad7o>}hOIDmA|XbMnz3$W!~cuRe?b?OkM c>(sG50im3H^Q{=VEC2ui07*qoM6N<$f_Nm1nE(I) literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-platform/effects/dust.png b/public/asset-packs/kenney-platform/effects/dust.png new file mode 100644 index 0000000000000000000000000000000000000000..e472129a3dad398410c3bf184c5ce4e602d088d1 GIT binary patch literal 162 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh<3?#J|q#XfLEa{HEjtmSN`?>!lvI6-$0X`wF zK>Ev?w9}1o`F75?rZ1ZWLb^O`RG4bISi~%^|n`Gfw;?Um(rFu%lft2p00i_>zopr E0PGbtA^-pY literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-platform/manifest.json b/public/asset-packs/kenney-platform/manifest.json new file mode 100644 index 0000000..ce34b73 --- /dev/null +++ b/public/asset-packs/kenney-platform/manifest.json @@ -0,0 +1,354 @@ +{ + "format": "gamekit.asset-pack", + "formatVersion": 1, + "id": "kenney-platform", + "version": "1.0.0", + "title": "平台跳跃", + "theme": "平台跳跃", + "summary": "绿色和蓝色小人、草地、泥土、石砖和水面,加上跳跃和脚步声。来自 Kenney 的 Pixel Platformer,CC0。", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/pixel-platformer", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。小人的两帧排成了一张精灵表,动画编辑器可以直接打开。地形保持原来的 18 像素。原始包:https://kenney.nl/assets/pixel-platformer", + "assets": [ + { + "id": "platform-walker", + "version": "1.0.0", + "title": "绿色小人", + "path": "characters/walker.png", + "mediaType": "image/png", + "tags": [ + "角色", + "主角", + "跳跃" + ], + "theme": "平台跳跃", + "category": "character", + "preview": "characters/walker.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/pixel-platformer", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。小人的两帧排成了一张精灵表,动画编辑器可以直接打开。地形保持原来的 18 像素。原始包:https://kenney.nl/assets/pixel-platformer", + "sha256": "8d6cc222ff669cc8ba51bbe23bfa28c9cf85aca2049b30adec8bfbdca8e33459", + "width": 48, + "height": 24, + "animation": { + "frameWidth": 24, + "frameHeight": 24, + "frames": [ + { + "index": 0, + "durationMs": 240, + "name": "站立" + }, + { + "index": 1, + "durationMs": 120, + "name": "走路" + } + ], + "states": { + "站立": [ + 0 + ], + "走路": [ + 1 + ] + } + }, + "collision": { + "x": 6, + "y": 4, + "width": 12, + "height": 18 + } + }, + { + "id": "platform-walker-blue", + "version": "1.0.0", + "title": "蓝色小人", + "path": "characters/walker-blue.png", + "mediaType": "image/png", + "tags": [ + "角色", + "跳跃", + "变体" + ], + "theme": "平台跳跃", + "category": "character", + "preview": "characters/walker-blue.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/pixel-platformer", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。小人的两帧排成了一张精灵表,动画编辑器可以直接打开。地形保持原来的 18 像素。原始包:https://kenney.nl/assets/pixel-platformer", + "sha256": "8d83952f01b5162c213ab43370d7a06f315b4efd7bfd4291da6e27f42efbfb5e", + "width": 48, + "height": 24, + "animation": { + "frameWidth": 24, + "frameHeight": 24, + "frames": [ + { + "index": 0, + "durationMs": 240, + "name": "站立" + }, + { + "index": 1, + "durationMs": 120, + "name": "走路" + } + ], + "states": { + "站立": [ + 0 + ], + "走路": [ + 1 + ] + } + }, + "collision": { + "x": 6, + "y": 4, + "width": 12, + "height": 18 + } + }, + { + "id": "platform-grass", + "version": "1.0.0", + "title": "草地", + "path": "terrain/grass.png", + "mediaType": "image/png", + "tags": [ + "地形", + "草地" + ], + "theme": "平台跳跃", + "category": "terrain", + "preview": "terrain/grass.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/pixel-platformer", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。小人的两帧排成了一张精灵表,动画编辑器可以直接打开。地形保持原来的 18 像素。原始包:https://kenney.nl/assets/pixel-platformer", + "sha256": "a677f7d9da75c6f3f32d08d9e2b44e48f03afcba678170a9aca99cb697fcafb8", + "width": 18, + "height": 18 + }, + { + "id": "platform-grass-edge", + "version": "1.0.0", + "title": "草地边", + "path": "terrain/grass-edge.png", + "mediaType": "image/png", + "tags": [ + "地形", + "草地" + ], + "theme": "平台跳跃", + "category": "terrain", + "preview": "terrain/grass-edge.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/pixel-platformer", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。小人的两帧排成了一张精灵表,动画编辑器可以直接打开。地形保持原来的 18 像素。原始包:https://kenney.nl/assets/pixel-platformer", + "sha256": "d48e9fe1197c99b7bac2c6f465160f89a8082d8059bd709e5de8fa83bfa81f7b", + "width": 18, + "height": 18 + }, + { + "id": "platform-dirt", + "version": "1.0.0", + "title": "泥土", + "path": "terrain/dirt.png", + "mediaType": "image/png", + "tags": [ + "地形", + "泥土" + ], + "theme": "平台跳跃", + "category": "terrain", + "preview": "terrain/dirt.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/pixel-platformer", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。小人的两帧排成了一张精灵表,动画编辑器可以直接打开。地形保持原来的 18 像素。原始包:https://kenney.nl/assets/pixel-platformer", + "sha256": "c82caa64467a4f8bbb5524e627aca73797731b3403d43e8a729d894578beafaa", + "width": 18, + "height": 18 + }, + { + "id": "platform-stone", + "version": "1.0.0", + "title": "石砖", + "path": "terrain/stone.png", + "mediaType": "image/png", + "tags": [ + "地形", + "石头" + ], + "theme": "平台跳跃", + "category": "terrain", + "preview": "terrain/stone.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/pixel-platformer", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。小人的两帧排成了一张精灵表,动画编辑器可以直接打开。地形保持原来的 18 像素。原始包:https://kenney.nl/assets/pixel-platformer", + "sha256": "d7d12bf435f5b5fc2c12a93a86495a0e6e6afdccdb90f77436f08cf20a7f0c95", + "width": 18, + "height": 18 + }, + { + "id": "platform-water", + "version": "1.0.0", + "title": "水面", + "path": "terrain/water.png", + "mediaType": "image/png", + "tags": [ + "地形", + "水面" + ], + "theme": "平台跳跃", + "category": "terrain", + "preview": "terrain/water.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/pixel-platformer", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。小人的两帧排成了一张精灵表,动画编辑器可以直接打开。地形保持原来的 18 像素。原始包:https://kenney.nl/assets/pixel-platformer", + "sha256": "51ff60a7a1a9c690f9a4ec7d8b00acfba7b7e726a35ef278d3adfb61b0f91bf0", + "width": 18, + "height": 18 + }, + { + "id": "platform-pebble", + "version": "1.0.0", + "title": "小石块", + "path": "props/pebble.png", + "mediaType": "image/png", + "tags": [ + "道具", + "石头" + ], + "theme": "平台跳跃", + "category": "prop", + "preview": "props/pebble.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/pixel-platformer", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。小人的两帧排成了一张精灵表,动画编辑器可以直接打开。地形保持原来的 18 像素。原始包:https://kenney.nl/assets/pixel-platformer", + "sha256": "0647aab90ffff15e94560f34e4063dc77d5037852e3c7c8005632c3bc8196ae4", + "width": 18, + "height": 18 + }, + { + "id": "platform-dust", + "version": "1.0.0", + "title": "尘土", + "path": "effects/dust.png", + "mediaType": "image/png", + "tags": [ + "特效", + "尘土" + ], + "theme": "平台跳跃", + "category": "effect", + "preview": "effects/dust.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/pixel-platformer", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。小人的两帧排成了一张精灵表,动画编辑器可以直接打开。地形保持原来的 18 像素。原始包:https://kenney.nl/assets/pixel-platformer", + "sha256": "b1fa9ae1eb841985464b732030ae7cfb5fccce61b4b3a8221932a478652ac312", + "width": 18, + "height": 18 + }, + { + "id": "platform-jump", + "version": "1.0.0", + "title": "跳跃", + "path": "sounds/jump.ogg", + "mediaType": "audio/ogg", + "tags": [ + "音效", + "跳跃", + "角色" + ], + "theme": "平台跳跃", + "category": "sfx", + "preview": "sounds/jump.ogg", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/digital-audio", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。声音是 Kenney 原来的 OGG Vorbis,没有转码。原始包:https://kenney.nl/assets/digital-audio", + "sha256": "c60069ed7108678dd6a1306404d168a93cc2575cda37b06add9dd6c4d46352a3" + }, + { + "id": "platform-step", + "version": "1.0.0", + "title": "脚步", + "path": "sounds/step.ogg", + "mediaType": "audio/ogg", + "tags": [ + "音效", + "走路", + "角色" + ], + "theme": "平台跳跃", + "category": "sfx", + "preview": "sounds/step.ogg", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/impact-sounds", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。声音是 Kenney 原来的 OGG Vorbis,没有转码。原始包:https://kenney.nl/assets/impact-sounds", + "sha256": "9d49497777405d78d7cf7f2888e28277f3a23192300cfd1d79d54876b20f479f" + } + ] +} diff --git a/public/asset-packs/kenney-platform/props/pebble.png b/public/asset-packs/kenney-platform/props/pebble.png new file mode 100644 index 0000000000000000000000000000000000000000..b59506c573cf9bc2082544248921d0f3bbf03cf7 GIT binary patch literal 183 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh<3?#J|q#XfLEa{HEjtmSN`?>!lvI6-$0X`wF zK>Ev?w9}1o`F75?rZ1ZWL9Uev}6kT0aC9qRSJQ%i68b0 br1%&n_ee?hE@(OpG?c;9)z4*}Q$iB}^}atV literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-platform/sounds/jump.ogg b/public/asset-packs/kenney-platform/sounds/jump.ogg new file mode 100644 index 0000000000000000000000000000000000000000..9461fd74e20d7af87bb9f3a9650f8c3239239871 GIT binary patch literal 6733 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 VdiFM2xV;{Gv5i$y(1Lw{{u}%#P>uiq literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-platform/sounds/step.ogg b/public/asset-packs/kenney-platform/sounds/step.ogg new file mode 100644 index 0000000000000000000000000000000000000000..5b5ec879a5ca457d18ad01a81af805409e35207f GIT binary patch literal 8290 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 TW%wyqlQZSd3&u_>T}S*E3mi$F literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-platform/terrain/dirt.png b/public/asset-packs/kenney-platform/terrain/dirt.png new file mode 100644 index 0000000000000000000000000000000000000000..2579b01ed0812b371a043033d775d78646c33ea1 GIT binary patch literal 142 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh<3?#J|q#XfLEa{HEjtmSN`?>!lvI6-$0X`wF zCZT~})}+mk3Od~wm+!dz7f@W+)5S4_<9hNBeinI&geUeEzwhgB;Amk9a`^OJUuCMr mi62!4oPs~OMeP~XBpGV;Lg%iG*_i~?$l&Sf=d#Wzp$Py1oGFF? literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-platform/terrain/grass-edge.png b/public/asset-packs/kenney-platform/terrain/grass-edge.png new file mode 100644 index 0000000000000000000000000000000000000000..c4ba0668f8d3dc40e92a46b668b88db809fb44e0 GIT binary patch literal 178 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh<3?#J|q#XfLEa{HEjtmSN`?>!lvI6-$0X`wF zK-%naxk+fC-iD^uXpRCPpRpv!FPOpM*^M+H$HmjdF@)oKazaAFg{*`JQCqXFGO?`< zU42bI;Q}9TFMq-X9$sG7Nnii}uTO~h`~UxUeje}t%{RQ?JG(Y4F^dTMZ9h?kq3N`} V9K+wAe}LvOc)I$ztaD0e0swjbI#U1u literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-platform/terrain/grass.png b/public/asset-packs/kenney-platform/terrain/grass.png new file mode 100644 index 0000000000000000000000000000000000000000..805508c64e1f54c64af743e394875bad9991ccf4 GIT binary patch literal 198 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh<3?#J|q#XfLEa{HEjtmSN`?>!lvI6-$0X`wF zK-%naxk+fC-iD^uXpRCPpRpv!FPOpM*^M+HC&JUkF@)o~@0o>y4F&=(7q6B$1^F+K zE(%?cY%sm9iMc<$Ao5+BK*#?p=a?kAmacNRP{o-vi~rz^ODSn)j!!SMO23?!r1V&DdLL+}GjC=>@cd!PC{xWt~$(695LoK->TT literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-platform/terrain/stone.png b/public/asset-packs/kenney-platform/terrain/stone.png new file mode 100644 index 0000000000000000000000000000000000000000..a5ed8ca478aa5a16b8d5f75295c63381c5b097e7 GIT binary patch literal 190 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh-3?!F4n4AKnSkfJR9T^xl_H+M9WCij?1AIbU zf%KO(X=abh=SKzUZD=~(80YL2zsl?TGoS=xNswPKgTu2MX+Vy!lvI6-$0X`wF zK-%Z&UuUm)oul6*jH4d{`HUq&e!&b5&u*jvIo6&ojv*Y^lP_dNExdYQ0~d#wfljRG z))L0USI%r$$;q?OLEylLul0Yf^Yi>)|Nrm*#)tpD{&)EFzkZV^!^8hxKN#*TYXTa> N;OXk;vd$@?2>^*!JVgKi literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-puzzle/characters/player.png b/public/asset-packs/kenney-puzzle/characters/player.png new file mode 100644 index 0000000000000000000000000000000000000000..2e6b075cef4a2616f58dda76f7ac6d68ed75dd23 GIT binary patch literal 2429 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 R3}4fbJY>2i$P(fQ{TJe+&CUP- literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-puzzle/sounds/place.ogg b/public/asset-packs/kenney-puzzle/sounds/place.ogg new file mode 100644 index 0000000000000000000000000000000000000000..58ed005178c61dcc4bbe563540b89ee18c4679d6 GIT binary patch literal 6019 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 T0Bm;wI00N4l0Je-fH(LX_bN&@ literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-puzzle/tilesets/blocks.png b/public/asset-packs/kenney-puzzle/tilesets/blocks.png new file mode 100644 index 0000000000000000000000000000000000000000..dd66959f2ffa7701d2dce983923a5e5143a902a3 GIT binary patch literal 4848 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 Wyl-E!EvW}8VDNPHb6Mw<&;$UpTO)-4 literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-racing/manifest.json b/public/asset-packs/kenney-racing/manifest.json new file mode 100644 index 0000000..5e2a33f --- /dev/null +++ b/public/asset-packs/kenney-racing/manifest.json @@ -0,0 +1,330 @@ +{ + "format": "gamekit.asset-pack", + "formatVersion": 1, + "id": "kenney-racing", + "version": "1.0.0", + "title": "竞速", + "theme": "竞速", + "summary": "赛车、走路的人、路障和一段公路,加上撞击声。来自 Kenney 的 Pixel Vehicle Pack,CC0。", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/pixel-vehicle-pack", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。人的三帧原来宽窄不一样,这里放在同样的 16×16 透明格子里,动画编辑器才能打开。车还是原来的大小。原始包:https://kenney.nl/assets/pixel-vehicle-pack", + "assets": [ + { + "id": "racing-driver", + "version": "1.0.0", + "title": "车手", + "path": "characters/driver.png", + "mediaType": "image/png", + "tags": [ + "角色", + "车手", + "走路" + ], + "theme": "竞速", + "category": "character", + "preview": "characters/driver.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/pixel-vehicle-pack", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。人的三帧原来宽窄不一样,这里放在同样的 16×16 透明格子里,动画编辑器才能打开。车还是原来的大小。原始包:https://kenney.nl/assets/pixel-vehicle-pack", + "sha256": "e2fabbfcb3ef0d873ee65407306612cf2f01ae08c5f191babd57097902638c01", + "width": 48, + "height": 16, + "animation": { + "frameWidth": 16, + "frameHeight": 16, + "frames": [ + { + "index": 0, + "durationMs": 200, + "name": "站立" + }, + { + "index": 1, + "durationMs": 120, + "name": "迈步" + }, + { + "index": 2, + "durationMs": 120, + "name": "再迈" + } + ], + "states": { + "站立": [ + 0 + ], + "走路": [ + 1, + 2 + ] + } + }, + "collision": { + "x": 4, + "y": 1, + "width": 8, + "height": 14 + } + }, + { + "id": "racing-car-green", + "version": "1.0.0", + "title": "绿色跑车", + "path": "props/car-green.png", + "mediaType": "image/png", + "tags": [ + "道具", + "赛车" + ], + "theme": "竞速", + "category": "prop", + "preview": "props/car-green.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/pixel-vehicle-pack", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。人的三帧原来宽窄不一样,这里放在同样的 16×16 透明格子里,动画编辑器才能打开。车还是原来的大小。原始包:https://kenney.nl/assets/pixel-vehicle-pack", + "sha256": "7ee6636fe8cf687b0d62cc7366ff722f8a840528f9d93482a93c24da5c62c39d", + "width": 29, + "height": 11 + }, + { + "id": "racing-taxi", + "version": "1.0.0", + "title": "出租车", + "path": "props/taxi.png", + "mediaType": "image/png", + "tags": [ + "道具", + "赛车" + ], + "theme": "竞速", + "category": "prop", + "preview": "props/taxi.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/pixel-vehicle-pack", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。人的三帧原来宽窄不一样,这里放在同样的 16×16 透明格子里,动画编辑器才能打开。车还是原来的大小。原始包:https://kenney.nl/assets/pixel-vehicle-pack", + "sha256": "0f39c03adcfd54066512eafd1a35c75dbb01b367b778880ec6c2e567e4eabd28", + "width": 33, + "height": 14 + }, + { + "id": "racing-bus", + "version": "1.0.0", + "title": "巴士", + "path": "props/bus.png", + "mediaType": "image/png", + "tags": [ + "道具", + "赛车" + ], + "theme": "竞速", + "category": "prop", + "preview": "props/bus.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/pixel-vehicle-pack", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。人的三帧原来宽窄不一样,这里放在同样的 16×16 透明格子里,动画编辑器才能打开。车还是原来的大小。原始包:https://kenney.nl/assets/pixel-vehicle-pack", + "sha256": "237460909a5d648639e58ebd10ed0ea93b74f22ed4b9dcdfb40fbbd97a612d4d", + "width": 45, + "height": 21 + }, + { + "id": "racing-car-red", + "version": "1.0.0", + "title": "红色跑车", + "path": "props/car-red.png", + "mediaType": "image/png", + "tags": [ + "道具", + "赛车", + "变体" + ], + "theme": "竞速", + "category": "prop", + "preview": "props/car-red.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/pixel-vehicle-pack", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。人的三帧原来宽窄不一样,这里放在同样的 16×16 透明格子里,动画编辑器才能打开。车还是原来的大小。原始包:https://kenney.nl/assets/pixel-vehicle-pack", + "sha256": "8ad2db0c825644db82219a2dc754dd16d7feadfc79c97b17d62f74357827a853", + "width": 34, + "height": 12 + }, + { + "id": "racing-road", + "version": "1.0.0", + "title": "公路", + "path": "terrain/road.png", + "mediaType": "image/png", + "tags": [ + "地形", + "公路" + ], + "theme": "竞速", + "category": "terrain", + "preview": "terrain/road.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/pixel-vehicle-pack", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。人的三帧原来宽窄不一样,这里放在同样的 16×16 透明格子里,动画编辑器才能打开。车还是原来的大小。原始包:https://kenney.nl/assets/pixel-vehicle-pack", + "sha256": "0a217e56d57c183ce31ea44996a3a1d7afc62ce9b70d993acd2e0bc84df7e5ed", + "width": 32, + "height": 31 + }, + { + "id": "racing-barrier", + "version": "1.0.0", + "title": "路障", + "path": "props/barrier.png", + "mediaType": "image/png", + "tags": [ + "道具", + "路障" + ], + "theme": "竞速", + "category": "prop", + "preview": "props/barrier.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/pixel-vehicle-pack", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。人的三帧原来宽窄不一样,这里放在同样的 16×16 透明格子里,动画编辑器才能打开。车还是原来的大小。原始包:https://kenney.nl/assets/pixel-vehicle-pack", + "sha256": "7a9c64c35f66d661f9a8ee8ed48bc85a799700b5c4b5be4f0909f058721b3954", + "width": 25, + "height": 7 + }, + { + "id": "racing-sign", + "version": "1.0.0", + "title": "路牌", + "path": "props/sign.png", + "mediaType": "image/png", + "tags": [ + "道具", + "路牌" + ], + "theme": "竞速", + "category": "prop", + "preview": "props/sign.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/pixel-vehicle-pack", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。人的三帧原来宽窄不一样,这里放在同样的 16×16 透明格子里,动画编辑器才能打开。车还是原来的大小。原始包:https://kenney.nl/assets/pixel-vehicle-pack", + "sha256": "2c37315d9b1f797589d5c495d33202f65139e5beef499e157efd474c94461431", + "width": 7, + "height": 21 + }, + { + "id": "racing-light", + "version": "1.0.0", + "title": "路灯", + "path": "effects/light.png", + "mediaType": "image/png", + "tags": [ + "特效", + "灯光" + ], + "theme": "竞速", + "category": "effect", + "preview": "effects/light.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/pixel-vehicle-pack", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。人的三帧原来宽窄不一样,这里放在同样的 16×16 透明格子里,动画编辑器才能打开。车还是原来的大小。原始包:https://kenney.nl/assets/pixel-vehicle-pack", + "sha256": "d4290d719cfe12455b047da5c27fc26049e8de028e598378940ff2d13d3e7369", + "width": 7, + "height": 27 + }, + { + "id": "racing-crash", + "version": "1.0.0", + "title": "撞击", + "path": "sounds/crash.ogg", + "mediaType": "audio/ogg", + "tags": [ + "音效", + "撞击", + "赛车" + ], + "theme": "竞速", + "category": "sfx", + "preview": "sounds/crash.ogg", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/impact-sounds", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。声音是 Kenney 原来的 OGG Vorbis,没有转码。原始包:https://kenney.nl/assets/impact-sounds", + "sha256": "33b5e6e37c6e9d54e07bf5a89b12c76e879f40c1ea83cdd82714df1d6f9fec6d" + }, + { + "id": "racing-clank", + "version": "1.0.0", + "title": "金属声", + "path": "sounds/clank.ogg", + "mediaType": "audio/ogg", + "tags": [ + "音效", + "撞击", + "变体" + ], + "theme": "竞速", + "category": "sfx", + "preview": "sounds/clank.ogg", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/impact-sounds", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。声音是 Kenney 原来的 OGG Vorbis,没有转码。原始包:https://kenney.nl/assets/impact-sounds", + "sha256": "6e797cf8a5bfc52d7ed5eb47c227974c1cf2a674954fec5b539cea7d62c7282c" + } + ] +} diff --git a/public/asset-packs/kenney-racing/props/barrier.png b/public/asset-packs/kenney-racing/props/barrier.png new file mode 100644 index 0000000000000000000000000000000000000000..86f449c6fb4121f986f7e7b9830c874df3945573 GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0vp^l0eMP!VDz&rGM`RQY`6?zK#qG8~eHcB(j2p1AIbU zf%MmynE(I(AFy*g@!)?w|Les-A;yv*zhDN3XE)M-90gAo#}JO|$q8m=Wrc-of_`2+ mJXaoaa?R3M*}$o)%E}PaDR6M{_k)~3wG5uFelF{r5}E)|hA9pJ literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-racing/props/bus.png b/public/asset-packs/kenney-racing/props/bus.png new file mode 100644 index 0000000000000000000000000000000000000000..48d2e7cfe671fdf18e16d2167e4e2744aa99890d GIT binary patch literal 289 zcmeAS@N?(olHy`uVBq!ia0vp^xUox6FT+q-*v?{X)^KE7(-CjTT{u)Hwu jMW5bB=2zmmezlB||LYnbU-SC{bTxygtDnm{r-UW|b2E2Y literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-racing/props/car-green.png b/public/asset-packs/kenney-racing/props/car-green.png new file mode 100644 index 0000000000000000000000000000000000000000..4e127021859c5fe95eef26197983338abd816343 GIT binary patch literal 239 zcmeAS@N?(olHy`uVBq!ia0vp^vOvtu!VDw}jb`rxQY`6?zK#qG8~eHcB(eheq5(c3 zu0Yz(J@Ehk|2oE2Q4ecQJoxXjDRxq7d^u2pu_VYZn8D%MjWi&q!qdeugyVW>uOnBB z0gvl`kGtM4Az2jyXo9X?yW9=x1?!EUG;prRap1HTbCyX9h1|}t^9D} jj@`MQiH1jb&i!EQTBs7CuebOW&Nn{1`MFV_7 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 XpN4LH*nH^3%^QdAo!InKZP5P%>Jo5A literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-racing/sounds/crash.ogg b/public/asset-packs/kenney-racing/sounds/crash.ogg new file mode 100644 index 0000000000000000000000000000000000000000..7d49262cc9f69eb517cf644f61940ace16714f22 GIT binary patch literal 7651 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 literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-racing/terrain/road.png b/public/asset-packs/kenney-racing/terrain/road.png new file mode 100644 index 0000000000000000000000000000000000000000..c74fed9f83e9ed4780bdb4ea1298aec5f016e6f4 GIT binary patch literal 208 zcmeAS@N?(olHy`uVBq!ia0vp^3P3E+!VDx!DlY8@QY`6?zK#qG8~eHcB(ehe`~f~8 zu0T5KVa@;l|4%&l@3u1`v+RljP>8W4$S;_|;n|HeASd3_#W6(Vd~$-B8=D&sk3$Q~ z3{i=mh!_V41|KUX)*j!O7?+rsmPQ)|BevBAA}m16xSD~BgR6^yRfd%{kx4<}R>@?rH0chr3wL7H&z77i?ozUb7g%BmaKjku0F4@#$&$E)~Xqe|ooV zSvmp~%$+@)jv9G7O8o9@Ys$1Qp(mkm9I0?z;rIy&StD0BXAe&Yyn`D70UKxe?dMP} zZBrJA1N0#ECF%n@V=hAw9|T>MLhwAku7@BIGi7fl5_REP{qYBh#0T|4b`i*iUoQzo zdqD_dg92nZqq0Z!T-s5NLNZaF87ODN(|Ho?4=??R;(WJs$j&XdG#BUAj*#ZqY4IBb zfYH#E3>Lt^FWWH55Fzji74vM8%uDs;I-H+zpG%=hB2ZspJm;~Y@_2rBl=6gZX{Xi> z`Oyk2>m%FrEsq4f!V-thR;PJ9DyXnw()2r{MuSH_8VMf6g#Js zIXx?LZFwoz@{*gW0-VYQuLjC+PR{)w<+??@!~b10oSF_p8UV}28)A(&q|RZa8a?IM znFu#Qz^57*xq44U9lT;AUKJD_!r5k`e%qox?=L67ZU>=-6sx}>)(p_V$oF_Enc>y? z@CJPV3K)_9{M=*43)qO{lk4#=0URe{t}$T=0A__UIkdUAW&#RfnSV(ncP1~ip?H$N zWfTac^!)L_Bt@p8ATfpM!Qb13zXD$(J|xv=By}d^+x57UNn5qs{3+~31>K-en3l@Z zAbbtzId>B`j0+P9skM|Rzc^+pVn-DqsBcslv3j!}Gu5Gf5JX==lMW2Uzh>$IVK0?Aq7$kJ2$Gc8Oma zlr9B%;}dF^O)i_=bhSwE8Y~aC>i44d`BM8LZT5!zdtm*|90-smh{;K!Z3MD0HPBFt zbIZZMm~%s*@sU{bBdH57r3|{|+U6CF78JX7pSz@JU@U0WCFs?&$HDldRgaQG&t-?+ zn+^kI4wmJ<7G*yPvqc+fpVvQ_15@MxD(b6lEZe`BlOY@R<#g0Ry;v!W*h9DD9UmkY zB&CfPWO4l)bDSRLB|gjxdq@k5l6?^G{2=*hMb_^hiYMRvpXG1n=y*zj0+@5oQ|ceg zd5aX&25fpMXRxrfN3|{hDB;}Re>wny-o|iWVCIoa82Mg|QZGjSvWeP%W(<(_DjM`C z0$}4HNEm{~>H+F}vDxuhz8bR+C|RWyYvgr-_ai=}M9nDA*(6&uN|v10jwFRWx?*|c z(Si5Zc$6<2BJwq96g>`kc98bipi6*mT4BidLbef_O%i7#kQ~B6VaV;0ft{Kh(!oRp z4#~I}%zGiwY?cTjYUv3RV=%fT2nvAM!EZ-qXN(|=Mk)l|kHLo_IRx$alsO6re3+*~ zfiWl^FR+_|zMgxHYP0GGqk5f8F0IgRL7=w`|kuIWL5F{aEwERsz3>OIqoDpOJ zOSF8$LnKEM9-~0Z3Bq83ARZ+{0wdTniLn?QDTe|CgigJ22_gpLTtNJYm6av~fpi=N zi$ms8Y`K}HigG^Mx**CZ*h1#yIq>ALKu;cTh-R0JYu7}85nwG2?XanCO<7V-H&%~C zzKFgcO`>QaipUgO{Q|NGS`V1Q>J^YbVvCB%LMj}HV0cxf@z{q*(jGfm5_57An4DY& zPhM(*afU~@6g7a!3%~|($TEscB(g!wt_?*Juya8)e8fh`mxuj2+yO{0BY!FxQ5sl#1H$0 z4~;;8WBKBr;4HrynEU<<6dY2>25GTELP12^RuoMF_#h|-6M>?M1z|7``7jTWwA8?h zXmlJ#A2|y5xfEc~$OdL#fkOn`#|JEv!O@=@$ft!skSSm+0nA1s^(%w1U`l{D7T5!N zBof7TlBp+6`iKpe48oxGq)G9%;Yd&edPHnEGTsD(E&zJrB@Gxf$a@sf*N_b61rCcS zX}}tzVYoma76>^$Jga=ugVeB8Nyr+2~Z8O)Fs07!A$aw9`h@q7v#kMP`D?2?`! z5OVA>TF#OreYCE0&K?wqGmHWvlXMYtNIJ&^3$8!k0leSeYRM|vOG7d2;PlE70GFB& zB7mVmOdAbQwu=BU4f<$A4A^oa9=ycBc>(S{06j6gRsa`13Sa^H8est~)o$xF;e?>W z9^mkOamgNk|4{~@Co5C{P6;HMiK|Gk5YXlzDe59e!J^RxTTLQntBH_?rINrquv81s z4sHU_&`;oICXuMc0gefPTrdEfL^Q!3CIMvtmFX6)E=3SD%f=36u!@@MoJNT3kYnzV z1$qm(thrs%4!#)$ffrb(5WLRgncM;*FZm%|a4X{m`)3F2V#XF)4*^F794T<9!Os8L z#DTTIO(7Mg6o(AiYT9wb3&$ZTSf&)$O8(izp#kG?MM^Xxpf&}IZ~qOFP&^FidHP{MyG}Q;dkf?eZ(va>yU5D6DBrOa8V0E0wdU&PL~Y2i2fzuN6V6kzf6%}Uj9_! zhXV_vycH%}cakkr%!tFFIk)tfmlYyEyvVH)AOK;#%q;;1&5T>v6l@O!ujDTQn20$! zQ-IOpkp5dh0tUdUwgh0JUp3eY1a&g~xhrmuZJw~%{(A?xgb!`;>oYk1e(AbM{ThD| zM$Q$8ZL^C**pdjR9=678ZiWdMz_xWxMxwZ?LC zy3xOvD4{iBurPoo6os*TVk{b6RKLeAA}J7qISeu=$cGdjEwns&k7antC>F<_nFBH? z9AL%OfiY-Y(KjKx7bw~%O<4rF-!?+259`BIPznr?m#^U3P+=g$BPk;IHl>xJ3&3(R zu2_jZ9nY6b>UW7$qNV!qDX)ISMplgOCv=4@l$6@z@yUmKWV&qDF7| z?t%Qm1%-hFEdnH)+KHQ@EKgbL|5)PdP7jW}Gid(y%Mt;dPoX_HAP4C>5@<=iP zgM7SOGy3Dj@VKj?rXGQN1DFRI_{!l61Bl?G_=ptSsR|P`%B6%xl)Rr>ntGv`ThkDW zlece@l|hyXCr zaqZyVS9eZBC>M>WJYF#L{l@2O(x)Z;P2``0SW`qfvlvYuVb^T5a%vo zNdyw5sdovaWAI2os~`!Q2820XA3d$CdPYO*?0H?ZzTriT$=`n^1Ox;ybv3{{Ab|O2 z0UOH>W)}qiSpX}#H~5zCC0r-quX*9!ZW-V87x(eLdDq7GE`uQ*G2hR|Dkijfe%xrj zPTYFgeNj$uNB#V_d8(>M^~&gS3cZg`tE7b{g#PGruc`RD=39)smT7K&)Mi?apk8_8 zJNJ-GXY8;iyMC!R4?0b|-*7OvS(Q$XPmsQ|crD9fQ$=iNPxvEcgNIgCuDIcPib(;~ z+WSrgrT=7a{Dyg7PkzdsqeSe4MHjxe`l*fK`81wxoRO$^rJLp86_b8j{omEAL@d(p zw)c6T#^r>}R(<8)HdAD@lhiiVIv#h4&+L#_zwvN)d(Im#-Qsr>jQNSlWa}%t19n4l zA3C`p!K&%$8tXz?|A*;!p3%mH^p zkE(i2@AGK!-#2KCPtO@6Bd<0H79j^qUhelzv|d?|IQ_Dl=2{ofXq!1r4V}}eWcB)>PJ%q-KLJ@ zDnx1@`DJC0 zT4OhNt!25gQFLi;eO#n=Xl;|h?!><)GHQ`+2n%#u-E=Kg7F^6Tigt7l({ zzdBaYqMP+eWyPaH^Fzt0e9vKg`6t=4g>uVlHtWg+8J@a{9cMTFiVGgGsWxjs{6jCk zHwy4PbMGjw!<4N5*u3p6=p(Z_P4^$VQq(e7>*wX2y0I|Q+&HgA_qaep4a3vlYV7vp=iAR;FRr!>FL9|EiCeEcyf8y2 zRM?)F9v7TJoq6MS+wCA$v}!U&L$T_&Ok4XZ-jDIQN%}V0ov&2Q8!i>O9ZG(4#3f}3 zYhN`Nofx1i8qMn$?}m=L&brv&t#wWdOCx!*3j+Q(=t;*|P&-OOFO&#@=YYs)^hm5uv- zzH8(m)#=NXGc`Upu0QA#c1*o-UV`ln{RHbdi%7rkx>=hM#vFUYSI-(2qLgAAIJ|gQ zs#?!uyt4-!9rCTM+hy20D|OO0M9Hye?TxvsOscf$l8@b3Db~@K)Q0qRnjT~jLJ7Pp!PK>3n`M%t;W3u){b^6t18n|m z;Qt1`NT2{TYaP{tfn9RA9w>V038eUr0J`t?dfQYl6t64Qsts2i@$XTarG1(D+D0dN zkHpmu?7KBJ{jFxfN9I{=+@0y}(E-ywnS+%JPF6l+uaOlK*olhp97oHq&K)`nR(o}9 zDIFEE*S;I@zDgSweRc))*B4xK}Y%oR7Ec3h6KO+TW$^{ z)QP__deul1we09QXme4DsR^$dYpZkFb6x02!| zvnHi@QtA9C-bZqu!04*2cG^|nwMiS*M;%MEZt>#I?i;rkPF_6T_bw~B^u(VRB8FDG zn#(r`Ttu=WJDBzY-O>*`*G}JTW0v_1;sQf;jwC)<>*GMHd^T4zGBDX9HL^LdTpijz zlbX6hnZNMd)w(|=sOQ?d10jEvr4L4^y0rJ+d{~sA{`&Dk9=A%k87@=siFlfR@&tdT zOXk#Z?mS)+b6V& zz;niN?d?~WnY3y8&B1{kgL#w9MwKU~-QJ}IejB|(Un0Hg8%(Rb>ctvi!Xb^1*fu(4 zelo84LKCji1HI-Eo3&Y(*f|{YRopBh$kalZs|<>$&$k{y%ksX_6RsnXaVjT!lX7W3`*3>)6F+#L5xdBzKA~38 zGJkb)T4iv!VydIEba{T9mTO&$`kh&1t%K=x9p{ESpLRFD1NKrqHSWlN2Z2WYUR_`7fQy<8-ub zJvA9)qcctV&Ej+DNC%k!1K00_>Dt_aGn;1{8II+`$C@dH@6gx2^?&>v!t%a^OAg9o z)$})0U({A#j4Cf4xieW*?pC!#;oayQndsArR^MFxgLkOJ@ob(^ZSxF+%J3Zoi)B5xcJL@w&%Vm1@7RMy z%$-RV+b>QVC@0;#zPd9xDCPaZOFR**?M5k4?$t}DHfyQt47#QNd&^U{<%}fi>_Ga) z0DI4^A7EwL>V#}{H7`b&;~BvH4MhVZDp;uK#*0C!|N7j<$;fBV%17?FU9mbhc;?Rf zT%-6*S(KR>NDfK{ZEc9vC_gqD zxRod6pYT0tU0sC*v~>URq+@E8&h^Wf-OctZ@oGNH`TA?C-kY`ai{m|xWs)@;%i^n* z{vEu&jh4eL6&v(g#>PzcnsyRCo9*~gceimzs^91$#&vCRIaHjn+PKpGgC{tsVti`2 tvfMcR(&bQX`Iz7iMmyDlqou{-aqw?LYpde^s6Bi3cudR|y4(2g{4e#9ld=E+ literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-sfx/sounds/boom.ogg b/public/asset-packs/kenney-sfx/sounds/boom.ogg new file mode 100644 index 0000000000000000000000000000000000000000..a59f17869064eaf4eae14c722c60f55cef3f2e4e GIT binary patch literal 9408 zcmeHscUY6jzW*el1PB-)U?^fhkdBnVf~yjc79dC$f@lc6BgNHYAs`?GP(Z{`MI;D; zxPlaQS5FjzQlv-`aaXW+#dUYp72(bsaNXbj&U4Rwp7Y%Q?l2kVo%a3C=Ue7G@4F>3 z(g&cyatd-?su(sJA3|xMb|oe=qf?M3v_s4Ckey3|&!e^=GyhD;OcZ>Y8`ZN@IKKF| zRE$|#$`FnSh)#+!*^(Sdii>9YiwKaYBy&?Ub5nCu3zFWJ_=M=Bx6o*g9=<*seG=0W!bp+f3E{~hso`NH<{pxBNPM`@o`lpW zQbclMJjpjDEi#&<_uY5jnWQ3B&XzR-zjiBmtOHb81^ZNtOX9rDX2fxn_A?7US5Bq1{BU!X{5(?C= zu_=3?U#F#7ci*NClaR2D zN0h~|uogujB3M{(S>j3TX511bI3V}rLsG>^#k(6eauttin+TO-SMq!-buTn=Dn$~E z8&Y`yWvSm^F03sdsYn^3;wrdHwLJ=zlKiHduubJjm0Yh%2pkuEvqG}zb^x3kI8yPr z@d5$X@=7apJ1+Pxt+%WeP1~!6uGrjzGxDY@V=qVr!`jENs@FH9khZ_84+Y9CWQy2Z zok`k%Sb|B=Y|uQak$Ob#Xsy|G{d$eU!%nVE2R*%2bh)XSqMeff$ij=X_)8&D>zx}kA233SmhPeTFV1%3H{;Bp78_YYEiUYMT$6If#wC{9F-bS%mU_GDbC)a% z3Y8RAWGA5_GLjrla=-p*Xcd1I+?@8X{HoEvSh99cS!7;CQ+ds^raI}rSxyxDG>3gU zm;EI7uwGtSbY2DTLS0<{nHLxTZT{18oRhU-hL+=)to;|u5tylOhSt<(M0>Zi$Bm;9 z&{W5je-!`#f+C!o$d7n=8&7y!PIw#p`ELC0Ee7^ZkZEIN2<$NcQ~-Eb-!T3UIR$2s zO`cs8mfE8(+_wH%)v0X-hl&V(0_uh$axlRp7$s8_H&PTGmmdGK5)vYNiNU_(}Gk47LF7$JW2lZ^e>G3LJVsDIrnk$gI%7xedEj-4$m8lsBxXkR1DB9q@qtg}hs1!-@u}BJzqF z$>D?1e+Hd^v#^&i(eQYIu!|$GTSd7V$$3UycLgMEAh>5;_GnL?9vj9_ zy#Ad=1MeKX2s9tR;NuSh%AVxa=~XoFE}B3>!=fV!26s^ve>Rh81n7mKHx6D|@i-4z zfyX-|14oXLX>jB%@w%vrh9(|7NhqR$6KTOKbCEV4JYCSpAiv;S$HH0BaNfl;Mi}3v zXO&tW@A<_uh64ZwP`8hT2TIH$Pi;m3%nDF|B*3okYiz@+(az5Sf@+%<$c4I45aMda z#f2)^OP>sJw|CJD^Y%8-=Stff=p6I5bK%x|o4Xow%e=)kkCnJKk?Os@^~C{el{NeY zV6$^t#K12w+6ygZ4%$4?ws$pqT$Q4r$tA+@ril=W#5koTW-w0naP8y3HeGHQ99MPJ zdp&HEg8@e>98zEEZU3|?1;!uMa0m)eme6L$d6+8rir`iPf>}gdHM$UPYDvSM8eJH- z#+1}AwNz{vUPgaU%`(Qx!B83qP&xyMjGA~nY4|h-fyzeWT^{en)lLNeTWKM85b$4I z6hPe5!d1>A$G4FT09%p(FgP2MmUXnQRR9k*LtCD?zjh@c2GCG@YpKFHY){oQU%#??1Bv00t(%Jf*_o0Ab8{7(gn~Wy6 zl%8+gNvw?1gi?!zZJ`#f9k2~YToV+;q!LS0xBR@l@_hl(Q=UQlQ} zQJOL&4k#O~0Y!&sr>o+p9CAu(r3OnRm<#X@301Eb(J(}>yz7Z6P|ZkL$W5#sE9$U= z;U$!rO6Zr4lUXI+{cr}-0mij8qyGTxWX$d!Cq>qqqGE$<1TkVLU8@%4oCr=zcMX_giCN+~Z+!W&_%pVD3&4*(|)F;U!z! zC+W=v$^BF+f3uV7a?zU`=r;LIY_T+^TLz3dKb8l%O`r-CDQW3cg0j9mMD5 z3Q1-sRrL%SFf5^X&OUH`WXk1-^DGn0wh>{lq&?OipBbP|K}lI#-^`{d@8IO( z>h9qQ-5W}D5>fyPi(R^KBF|Xt(n}Odg=juNUZNn!Vy5@;Z}p7#x!J9!ZL+s@aIvFo zWCYPe!sAo2zdOPz*ncoHGd(>$`#?s4WRU+N?3sf zt2ki_VhmG+A8dw#ytxIxfmfYzDY`;gZSyRZy^~u{#rqQqIAUvljWX0LYSW&RBmKDJ z{SD2BPs#sC*rfhSHP=ppX8JaI-+K#*%^`Pl^a@a>Nv5nMF|hsl{9?lKQ~Sh{JoVES z(z^z{HleK>fAU_fAONVNO9;Rqy*DPZf|yes(%RLfxHpd0(b2)10KNs>m%f1WWBRw8 z=_v)Uso=Bi@JGgK)Tmu3@l$%uyDOW}bq9O1{Z}x*tOH-)w6w3beO*BUZ>H>Mq%5O0?%?R9gc)D3 zM}y0T3p?Jg-?P$Pow0TPpRdz?G2vJXjsu|o7s?|zF_t|+LBYF7!oLE$ISW6kUppG( z(7d@Nh7csc1_-7nJl513>4D3*g%d%xZ8EbGWmgtcUO4YU{Uoq74A6#s`lWN+bPWbYZRE2~G=mpSuVWKhk4sibN!HAN{-;U!86Se;X>`dy7jJO~ z)7Z@Wz5?z{XC@Jz5X*^zQ)~7cABu_Obnncw8WPc0I-bbcQ(-ZzyF?7?H6xsJZ{Qo2+#KUy17%2l;XkV zA3mplA6}P__V7FVwK^xwZA&OOH<$X$Ivq}q{3`|qT2l-m!O~scRB6FlDFAb~`Saqs zXGIktp?2%1#T_>_Euk=Fy!cJ*Ts^6huUxQ%s-cc%Y%i}?a*JA~mR4h97)n}0?Q{B2 z*Q4FvpyEhYe=Jrd4!li3PYE0isU9ms@gj3XR-nYa4ax0Zlbvb)R}Psx(sRF`9r!_BTJ zE6cIm?C9&+4k#3GR~53J@aRJ-O1;(+vi@`b+h=HNLHNPWDb80t_A$z=7P1S4F`w#p^grwccycy2}LaQ-RIC*nIKHdjeM;p zJ(Id)F65L`zwmvwt0O>ZubR@gEjhI@Q;c(5Ziqpn=6a<#GXrd=BdTx|tsLi&BpLM_ z?Y}171t|W|b4l+s?f_8$4ooB7@X?%=c-(CJ$Hi?s`tQX{L)7-ry)R$2D)v+~`O7xv81Q&Gbm3KU3#n|fr838HBF4*@l*^kxT^u+|y3%cpCWzy2 z0zGkQu+TT3o^Z!}V=zkXL)e0CSA2QR8J6si{q}*rO+gCgRuK^q=w(W*0G!hmUTaKG zgb%GJ!f=unORQC99Hi%B8|a*dY>8%ip;N~c-RPrLY+T_!vfMhUhAO@Ohi|W8*KzPf zqHYn`esMni^|1L4NK7wy!S;P*`S+06wzZ18%pxMzeh~*VlGJIniy7L?RPD4f@aNNg zIwC^OWe2diN^0XgdLuVFrOZ~Swae|%Ht zS(VE8=%z`$n_FyyQuj?|2HnDxrqn!zjX4@Eyvl3js2WPw1;}Wz@9!h-&Nv)En*KwL zDX6*LKKm;2k4|IfOYaZOI%`k2x&Mkq+ej-s%Sdv`n9D&Q$b(Eome0^`pUrT4xcF}U zz1V9$fa~t{_bnU^aKH7Jq85+?9;e@}nBA|`H1aQoM= z9GZJUc{x=A8Y~`x!j#rZr{xz`t9EuOx87>%m|PDWo4wlULGnSl(Lx7fS`SZ$UFWlA zlEjO*t93SY-+KsqP2GigN6q6yCTZv0HR6m6z+XFOa@tH%>fvkmki#sDi2mL8<{L#) zfM{Gk{wx|wVVn2fVm2qBK$uG{k)kM=qC|Qa06ke^XsBgePfTN7S)-pDrW>thYRora zdl)jR>zNR&k`89~Sqm3;(?qLgAxQ9H^E}k~*DlW?^A* z6o*C^A#jiw;{h_gjSQt#(*AaYd|ob}-qr3Y4>^V`|o!MHA`42&j9G6}@!VTi71N8qBjsRo8wkob&O!W5$V?QmOtvw44ge}LJCgM=G8S8Y@u%QvbDKq5v7;83JlP@RcF z;lKjIf^+$$#?Lvys3X0LPxhAH&Yw=4QcChzdyn!`FgPgYPN7gr+>z}AW^Cw`+Ajb6 z>Q&6x3Td`-507}(c4cw-?%9hjzU_(eKD{~H8EWEPpIDRa zN4{~qcsK+*_fCjPW64$(ffBT|7(ivAHbD*!oOp(X9<>%?u)krA9s~0oeXSiycqOB} zyj+T6j=Z4(pe3ie@KRy5rq!;7>S|_gwBZz|fj@OS7sZYd8_kq&R3Kq@t0|V3^?D7= z9|Pri0h?@11vF@Uxa+Ud^TT!QfTGiC2Z#pJfXI-g9mXoL_ zF=p{Z3V2!vh#~-Nqve(X_*`!T$!|??t+%$uTUel=@+ko1RrT5FscDtYhQjJsccpz6tJr=)^Ms$ydEyv`KHkK=M0KpofEikL9pfVIueq zTu8H0rW-=!(Nq)E7S(%n0s(inT8C6NAZN1+QkBZy%|;b~OEjQ_Atp5f8dg zU>@eJR6Q_AUTwRP=@fXqG+*aO2?}d13WxC&mlH!<1C-|hNZw<|BZ@v0I#j=3{p3o~ zR&z>##o?60G=mU85Vei~by z3=X|Naen56!6{wxOLbB zQ0gg=L7M`!)T}FoZ3n+SiXd41h|(l$m4u+NR7Ef-4{$FCET9$v4iaRuqyb)DLHWVk zM*J2IduJ0VlD5fo<4}1aZEKA!^)1-GLa1&Ajf!j z=SmY_n8@oL`QPwsH9$3X<7W6SJtO3YpyfVGMMMH zwSYpFqO1WVoSg~_$X$jk*bb-@&SqFXSo{?DxRxcmPaGuSlSpeL)-upV&&Cb`a(eX+;y@4BNpSN*dkPe0RTyX@>7-;Wc#JAT ztGXK~Fhp+}#GG0XtbyoF1LAtTT8R(D_h;@sa|B^@hY#ktWE|(x-}9}q);wBx?;Yy&EzA&*RFT0*UE@#rHSS&{b^(tax*?b3_X% z^b+U*eiC7N@AFsB+-6s1c>U2YA7RkmmGHBZT73JclN$d{)Xx{wULb8T6EJ*eE-P!` za=HG^6EPihJ}(CO8q4SL=*a&G9xvWc=-D?%yST~ux>JIV zjg0lC7F2;qL1586)IL?tRAsX{OnLzPYfZRu(elM)OVGIl+G)A!^{LNCnl?9&#j literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-sfx/sounds/click.ogg b/public/asset-packs/kenney-sfx/sounds/click.ogg new file mode 100644 index 0000000000000000000000000000000000000000..7ca77c7186126ce177640aad0c7ccc4c59bf4446 GIT binary patch literal 4876 zcmai230PBC)4q{4h%`X3K_lM

Pq@U{Hf%0a?t2h$I9gl!}3fY*7=UQiWm(2#OKm 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 T0Bm;wI00N4l0Je-fH(LX_bN&@ literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-sfx/sounds/confirm.ogg b/public/asset-packs/kenney-sfx/sounds/confirm.ogg new file mode 100644 index 0000000000000000000000000000000000000000..78f119c626bd8e9c18a19c0c9175d3e37d3a7a22 GIT binary patch literal 8968 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 R3}4fbJY>2i$P(fQ{TJe+&CUP- literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-sfx/sounds/door.ogg b/public/asset-packs/kenney-sfx/sounds/door.ogg new file mode 100644 index 0000000000000000000000000000000000000000..7df28265312494fc053380002e551b001dea89ad GIT binary patch literal 22848 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 GY#ji~`&^L# literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-sfx/sounds/hit.ogg b/public/asset-packs/kenney-sfx/sounds/hit.ogg new file mode 100644 index 0000000000000000000000000000000000000000..bf1027b541bfe16cc80af24807ca9bce271c267a GIT binary patch literal 5351 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 f{YM4K51%fl%$&G{k#42IjQcdt~&j8S9Nu~ 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 VdiFM2xV;{Gv5i$y(1Lw{{u}%#P>uiq literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-sfx/sounds/laser-small.ogg b/public/asset-packs/kenney-sfx/sounds/laser-small.ogg new file mode 100644 index 0000000000000000000000000000000000000000..73ef94a9fdd4a0dc5e5fbc9b9786b349da581d68 GIT binary patch literal 7286 zcmeG=c{~(a+h?pp5}Jh69U{BiFkH0Up~g;`F_$M+8D( zsW{m#b`m&a8xiXeQDNa;0W>~HXnW-n$^J#+ONbr(nSU1kOavS`YB&1Iomu!>NflmP zN(WN71?=Ce2nh|?7fz*7LnE~Ktd_&CIl_8X8KCwt|3dI~*MFj?Tm_#IVRvAG9Aelp5|CLG?jort;hqd{YRRskRa=$aDAMbB*ld8U2}8p+}L zrU8y7rD$=c)0nA5+w2DK(2}~6pirKcI&wK#6v`CftX1Mr1b*YiP>EN7%}M3(J1V6) z;gZ^A`7x3PchD#74PF+fJDR;LD@rzdrCE2+VwqlDpRGM+z{R`zs+jv>8qahxXQ`18 zoC6K_Vj-sJBV&Q&FVD~_$qI){EglOE=Pya~{`-pazoQLsP?op%E8pI)h9{`q4%ZbINcawbI>ixm+rzO|H0*8KW>~Evws)}X z?|!gf@k0rGwF7{|D7Wud?ts!D==Fyixze@_(Hw@LDEJcj*X6jtUf@Aga(y!c=}5yA zPk~tIa9M={_y9+6|XAqgD}O(9O+w%o{%n}k1bw4>;~tO@3EhkHKAZHfpu1+ zzR7uUy(P0K-;=|;Zu$hyNO*WQs7b;d_CEXMytymEhyC4ra8Pfa4-{_Y#-NWRi+Q0` zN>tLcS0~ZBiI$#kxk&ij(S}=h3Q7t%ErAgA^SOi(sq8S@bBVRJ2cuxtOBB zN#e7@JGDxoSNv6R(`r4kYkU7vd)_HK$*IHIYoJFo+(L3DxkiPM&qO|IjB|ewIXZM? zbSP=>>iEAK)}NjOpwq+(e3Iprh`F6}!qGxvQNcevXFuw8s&YrFnq94$L!a*5_t+gX z*xr?RC#(Z;m3!~1$bNY$(b&D;h}uu04n$Fh8>qV)kB}Rd9A?pNMu#H*;yHX5Q8i6| zW}PPT56{WhOnz#Tyxt~Fjhwb2I@2$KU7nryvb<38Z=U1NEX`t;GMJN$WX*)kfCM(T zsW7;+dg}7Ot$%usRk#|g&~xzNYJc&ZR*dpC=uNe{4l|2q+|mmL8i8N^R|Npjnj&Q< zh$Bt}y#a#J06~xByyahe48#s#9s03Quo(a-0x(`&a{r*ToL7ozg1JA^=B9G{ZnKv; zMY|JErmVNL`9p=+EhAE&b1Jmv})g zt%i6U7TzTPdHE;2oQx1V{=y4~b-+10{O6qhe}(^-z`vCMG;xG9{K{JtsOSjMO%UMZ zGh7RbTAKn2k*!S4q)@@!oyZPwqe89322ULLAV+%1+#$dn&S)1HdHB zhYa%z>oh6?(5d7+aRAb&(d+*CGXHz%-xwn3ngEZ&}yLdiAm-}bfG2_=1<(t{kmN<+nrDj zM3VcNXKtC335A;M67FSv$f!qfMZx6GpZzBo>wtn$7)E3F)$Hd9{1v#|>Sd6!AL{@q zheQkg*(K#%c$44+gaeW8s~LP47v3&Hd?J$jPzIGA0Owt<))jVM94qE?xvwr)>vRE_ zKn-V5$zo&tQLQcjW332)Zbh1Pl+_~FI9!?rD5Y9ez<{=p=xK}LNO{XyNEUe7TUe|3 z5D3~@97zjp^$dc!HK&+hV5`T;B#5eHq}i6EiwOiRQ9xg70>5s^xcEvD@E&G+-Ylwunw$zp0j4+QC~tm_!%D-zJlWBU3?vtbGedm)DHy}$Io}U+^Mz(zWj$GJsn;Oe z$36hGFL*}ArWe+qLbv9Q*POZo5SkD$XjbeW|WigBXnQg6TH zUtcZ%c)$E#_8w4zs_I>U0xwP&M~+Q0tW?Wgl`OVesa6gkC7{;L8JHJptTbEORThb+ zn(7&u6lRqL1B2ug-=_p))#3~r%_ zu*Z(wcxz6pWc%lHe#RTBg70fjh zN%EdW606tI1&V2cZ%Al*xA+#uw<|)i0u7oOI+p(uD@F=$u`mNX2yXk0Hy;;Z#WnhmJ_$+*($%xm~4N@u+!#izksTqd>l1|EmgS1D@E-)C>4k!uY9MqqTyBrw|1m;xnD?Gj;nyJ-Aj zaOd6w>*h;zec|2r+TF!1kQOpAZpt`>go(+Mc#X%?v1@YjiO#QZkPiUsz!(f)!$4KF zF#Fky=}$mHR#8O@V`?rdKyLz{0I(*|84UmDCT5$r;w-jXTHD$??u6kDA-D-~0D(j< zJ~;VfBvSAviinYxU_RjgiNe1YsW;^EW$noe1`F$64?X5RE$Ul9E=YC9m&Z#1r=_3Y z*<~&(?Glx}2{)CTPHB2o4aWFm2f3>L_1ZCksHB*YH>U%4l6vz=tCmx+qamfFy>($f zo!(*i<#0vg2WeK6QK{Mpvw8R48rO#dIcX6(Z^DnXKPGpS?Rr`)k4<7oRfq;wX)?XG zBSf7Yoceu(v^_jekhaO*Xv-|5a~v^@!fmAr!LndETHBZzE?v2;!U#X_PM@Kq6TZ1mxgpW3?yR4o$=Nm7}QbS872*-x!_NwlkK zc6s(ua=RL5r0uQZ*ZXO2sw2;QH|uC@bd8d}EyLdOnk({Cf#JyahNJ1bi{{7Q^HGh% zz=Lx)_;Ge5{?5pRltW0bf4^qTNN+QV=%C-u^-`?%7*u$hq+dyE6EmeYG!Ag^p>CP2q{(4MIa*#y@{$tPw4-a)-*s4`gZxCEB>i=Q@W;WyHRbJ0nL5u0Sg!atJeJT{OF#s zo75KGH{Hr#9$ox;h4+opQt|fCc-Xd?mj^4_4(f!?R49J!+*VLMGxfQ@=NxtFbZm@~ERsL5%f0(E#3`#ed zn8<7jM@ONfJbX87$QD5e!-NYr$X>plYgs8t*Y0x@14v<~WRz8mj!W=`4tZmR!H`=U z`ng6Gme=%#l>XQ=dd1sapQaya=eGN_ZZ2Uqm7=?0V(O`O7%lqck=eZS+x+ya)ramh z6Xi)xs|3}EoAzjEA}BaRd#Z9~-0*ft^r1r|kDp&TzrJ}LJ2>3^uEjMy8gJ;24DY>3 zcIQupoOyX4|w{AkO$Zs_nzPb`8ghUsh!8JwB^ny4~ymO%xT>7O5 z^?jlBGw$;O3e33z`rYf-&AYE(Kb}oa%+Ai{#||8;46zQ-HSq1xW44m-mV=vZ?B#69X@n6?BZLqE0Pu3omVI=&CL|`z2sv;wPOy2XXIXp z{1M@??s~rZ&gH=}SW&f`POFG3IO6e*b}{o33gqxz&8wLFq}=;P*z8sw>2= zexompT&*Rn<{I;*HGkE)^qTWQRDxl3@XG;%k26&%$1^@eU1QabYUC`C5|dJ`I?pHf zf%jG`T5({{)coys_4oLQ$I`k%xeJ#rZNJ9gJvu%?J($ve9TxM%wOQHO2?^QoWI(3o z0i~ViQq>T6BB?zyu!vG~p|{Sr$f3ljV(_M0sTjW0vMz?Zt<;hf5$G&R!Z5hgBayS! zgZYEn^%bP#U4g+xQTIfQ6l>mGUGx2E_gd`o--7t<=^*KJXvvd zIJnEFFQ`Yi1{9z9!>sQXUZyYVUersgmd9(pAUclSo2?C-RZ^Q$NIFeFz$~}ywFrz8 zQ~cl|aqZ#!G2UU7Lles`sqCsYUN~pC_s*WrLZNpu&!B2BXHT3svHmFvBaXpfe0{xq zVUVTg=CZxK&wrG!zgS=2C}jMIo@87W;8~;>jMc4F@){7EQZ1p!B^hVA1Sh#%XX5eB z2=!W!I&Y@-dneh(^{DpxQ>!}8yxMapG&On5GM`+hX(>ZO-Q@IG8eEB^$GB`1liePa zxt~*a{&YdG^!R~IjQX|Ml%ejgqE})(cn6Nii?G^^2F|}7|4nzqYD?Ml^g+`+E83)S z9e1o}%bTmR8(+*txO_x3$`eog>ZEKV2fj;uJC?kT%66nLKe^+@0_}rle}qu5$zf5z zj~+6#eI78dZt(Dh88s+F%hA`jg^Ly^*fHLjyUAn?2G_-K;>rv2+qO=;GA-YD4otMz zsfxD!)V5bR`n{`6WO1h5tvfTarq^t#V|~4NRhC+JfMR-ga_4jc_2U%-k!6|O*>{s~ zV_GjXIiWrTTPX=!i_hn{r_s~hl^it3^;GBxXK<}!{#f$k^`EO(jL~N{%q*B5JU!mL zl`hQNK~B%c%c?SvRzlM7qJ&qaJuL9Ll!BYR&Tw<8aoL{qLZ*Tn7)-*a6vjvIKg~tx zl@-QlDouV=Mi|G)OK~%5k2|OKi+r`Zx532t)iVcj~K*b^8BIh;*Q&~LcHAemfQC1!}gkE zheKl9Gnv`hWEj?h;GmJxBwAqyYweT&Y?#zs=>H{jf0l#qEvJZbAAcd(wv8U_%kKMf zO}5`O4yq-6F?5xZALECHLEnCkwKAv>cH=M1I zYwEsF*|cl+VsrM_+32g03&SI?<~x7?{mb{?hhNRV4h=nWEU)Uz@Cciao!#2yGU@u< fZ0=ih!z;f7hKs+$?616>s>8m-Q3J=_lHk7p*EO?0 literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-sfx/sounds/laser.ogg b/public/asset-packs/kenney-sfx/sounds/laser.ogg new file mode 100644 index 0000000000000000000000000000000000000000..56ad23de07f7704df9210eece99e8b682a879b87 GIT binary patch literal 9315 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 PP0ipUZi52I^D_P$PFBIY literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-sfx/sounds/punch.ogg b/public/asset-packs/kenney-sfx/sounds/punch.ogg new file mode 100644 index 0000000000000000000000000000000000000000..d8e0b890ae019533ec190dd2d1decce249ea556e GIT binary patch literal 8800 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 B{I382 literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-sfx/sounds/step-stone.ogg b/public/asset-packs/kenney-sfx/sounds/step-stone.ogg new file mode 100644 index 0000000000000000000000000000000000000000..ca5dd2b6aa45f73f53685988aacec0a88f31887b GIT binary patch literal 9475 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 literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-sfx/sounds/step.ogg b/public/asset-packs/kenney-sfx/sounds/step.ogg new file mode 100644 index 0000000000000000000000000000000000000000..5b5ec879a5ca457d18ad01a81af805409e35207f GIT binary patch literal 8290 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 TW%wyqlQZSd3&u_>T}S*E3mi$F literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-space/characters/enemy-2.png b/public/asset-packs/kenney-space/characters/enemy-2.png new file mode 100644 index 0000000000000000000000000000000000000000..a16147923f99cd2e052f5e5d0e36908e52c3b534 GIT binary patch literal 296 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvmUKs7M+SzC{oH>NS%G}f0G|+7 zApQUU|2q$#msZbOzxn9YSsR_b;$KucZ39X$mIV0)GdMiEkp|>!^mK6y(Kx?$;z8cS z3OugGr`RGJLU<-PuxsSK7c4#3A@<(hDK}$E#MG+H+Fx~_%s;%`^C{l16Gs~APjc;0MXsFn$IJcFmJpUXO@geCwo*mP+C literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-space/characters/enemy.png b/public/asset-packs/kenney-space/characters/enemy.png new file mode 100644 index 0000000000000000000000000000000000000000..9a02dbac9d018c4dbb39e68386ada626a6b802b9 GIT binary patch literal 238 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvmUKs7M+SzC{oH>NS%G|^0G|+7 zApQUU|EaS!PTDBC?W&ElSG@kE9U#?=B|(0{3=Yq3qyafqo-U3d8t0ErI4Ia)z`^o& z33Idudql(Gr{`7T{;%y=Y}om4s=L~of&v5I{cM)c8n+1MoNTMg>-2s4mE}f=qWe1I z;x!GDTpUWPnJ$!yh2J!F^jBEPG)E}p!P`E~f46d*QxnsV>|gZeI;U&N%f0&#UOarP g*oObpnf-mTT;3{WAGq5V0bRl1>FVdQ&MBb@0CBZiG5`Po literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-space/characters/ship.png b/public/asset-packs/kenney-space/characters/ship.png new file mode 100644 index 0000000000000000000000000000000000000000..b1b8a6470fe739daa123c0088d7adeca743ad730 GIT binary patch literal 296 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvmUKs7M+SzC{oH>NS%G}f0G|+7 zApQUU|2q$#3ogB)bM)KPSsR_b;x|eEvIR;omIV0)GdMiEkp|>!^mK6y(Kx?$;z8cS z3OugGr`RGJLU<-PuxsSK7c4#3A@<(hDK}$E#MG+H+Fx~_%s;%`^C{l16Gs~APjc;0MXsFn$IJcFmJpUXO@geCy6?sL=t literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-space/effects/flare.png b/public/asset-packs/kenney-space/effects/flare.png new file mode 100644 index 0000000000000000000000000000000000000000..ab3646d0040f4c8a3cdd271ec4d8e126a8a93eb6 GIT binary patch literal 129 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`9-c0aAr-fh6C^l3)UQ8OFQ68! z?8jW-xgh&UrnOn?4ugy5Sdt|aj=h(dHG$EUO+fmSh@?a9^I(}@OI#EUxj2_ObY1?@ b@Wh8<`&Y9f2~)jrpqUJwu6{1-oD!M<0ZAx$ literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-space/effects/spark.png b/public/asset-packs/kenney-space/effects/spark.png new file mode 100644 index 0000000000000000000000000000000000000000..5632767e16e5138126dc9ce19780aa20a5c74d34 GIT binary patch literal 95 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 f{YM4K51%fl%$&Gt2%|(7C5YZj1kr;8 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 IM6N<$f*L-bj{pDw literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-ui/icons/box-check.png b/public/asset-packs/kenney-ui/icons/box-check.png new file mode 100644 index 0000000000000000000000000000000000000000..25ef183b76a269849e56491ad60bb6ccf680c09c GIT binary patch literal 559 zcmV+~0?_@5P)CmZX-Jqm`ASm6fBFm7|uHqL!ATmX@QHm7)Lu03Lv;p00AdSL_t(I%dL~= za)U4sgyjk-#c{VW#Te5p;H2aI-z^ekNGNhQwnCFdo82Jj$$aLylnAoZfilh0Rxt@QZ|ur83*!KxyMMEMEiMF-eGe06-- z+~LZb1A=au^@s8`T$EqN5cL`b@LvDeFBRac8oR(A9OXEw0Di5z)CB^7+WQXJpG5?5 z+4x@p2gAymd~Lu1knZ8*XTagOWsg?8Yy*z$gQuF=1{_g?s5(ogE&xh^6wIkW%(002ovPDHLkV1l513=9AO literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-ui/icons/box.png b/public/asset-packs/kenney-ui/icons/box.png new file mode 100644 index 0000000000000000000000000000000000000000..774f00f492b991a88fb6ff44a7fe4d5444ae732a GIT binary patch literal 280 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyEa{HEjtmSN`?>!lvI6-|0X`wF zQ>HAOHf_nYX^W>$T{LwnkX$@%+9EIli2zmY-Fx)$lea&9{JePa+Q*NdpFDYS>eR(o zuRs3({~xI9)}7}{PG|jr>bOgS{DS@C*T2s{f8T!pe1_jT!JI(hEKe855R21qCwucX zD2Oo6?_&DOe5vUF>Q{^o*VWFIsl8mq_Cumcsztyyp`%LS5L@QinY=}DOAn^aeN&WW zmYIGtt9fm~^mh$wWKY=tXx3+&EaZJ#T+P?aPCng4U)Hw%4)^=#tamP5?q=5eC+)Ar T*||XnXe)!KtDnm{r-UW|5U+TZ literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-ui/icons/check.png b/public/asset-packs/kenney-ui/icons/check.png new file mode 100644 index 0000000000000000000000000000000000000000..2f60e31c7733e20eee837d702992fe2c65277237 GIT binary patch literal 377 zcmeAS@N?(olHy`uVBq!ia0vp^B0wy}!3-pG`1q876id3JuOkD)#(wTUiL5|=Y=BRQ zt3Yy#NNSr%N}F(MI|!w82q(9JMcM_^I)p(|?E*<1!YOS)9dZq;)TbR&>fT|v>7_)$ zRPBXVWU3ddPTa51wo$5dj#yTo=A5&}+dt^9c_fnBZnpP(vBT{bKyCabL4LvV_Wk$g z`^TTJ=U=~H|2@OMm$FqrsWqN1jv*44L(fNwH7oG22E014prpX1=H`DRZwB47;&+@Y zIya=Hd+0XL!;~+PZ#yYua>-NvTd-GuuW{a`mxx$ z$KnQGPxFcg+e+Q9CNI8nCrVJhMOn=3y~5!g2h`2p&MRzxCY!aUCfahwHUrCK?jyfN zg|=@MI;Y;P$a&buP`N!N#Pr_&2|YI7yKDG%8swav>Xf%-t)bifwEfSLq+Jg8K1c+* Oo59o7&t;ucLK6V-bCXyA literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-ui/icons/circle.png b/public/asset-packs/kenney-ui/icons/circle.png new file mode 100644 index 0000000000000000000000000000000000000000..89f8ca62f86e115bb1154e007046c55a5bd53c33 GIT binary patch literal 312 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$hZfKQ04 zKyr(4a+`2Uhj2=pNNSrvQipJAJCFe+1=Bi2Qrd-6+kk2%3Z_bx&QYIsOsRW^{+dUs z6Zh*bziqhbrC3&<@%9fQsqJQazn{PE*bG$4TN30KEFbUx{=EKu`}zF)*E4Kbw@n2o zQSa&E7$R{wwf`dDVFeD?o4cY!Z)Yu!`~TmY{aC4*wSR%o11HCbwc>A9nR>o9Ojv$M za>@^}q=TnB6W(kseZ|MOW#JMtj{|OE;k!FGY*F~{a>&VHHp9QxneIkBANPD=dVTZP z+w6&(h2BW0$xHbxejHNT_rmcSPfopG#h3cO!LRvmum~Nh4V^d%=oAJ|S3j3^P6QaFeOS+@4BLl<6e(pbstU$hZfKQ04 zaB917YMVfEi*RzANNSr%O1ofM2S_lbO(3ZQs7iI>e)Va`v=?5{U-QUt(@UA^#c~a+ zH0PXE>fRw$I!B>xqw)3+BB||Wd%sWJ*zydhfx9HgFL?fX`S|nu`R~8iXLxws@j6g= zxu=U`h{R>r36V@K3OvrQxvs=cDfmCxkL%T!s#moKaK{r|Fj?~gy1j!#M3 tWqf*0(3+Q#Y5%k?Ze#y-ZQqALd*833ul2dMeFHj~!PC{xWt~$(69CV+kYoS= literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-ui/icons/down.png b/public/asset-packs/kenney-ui/icons/down.png new file mode 100644 index 0000000000000000000000000000000000000000..0d04b368c6a99fc9038d01c26d15da12fbfe1359 GIT binary patch literal 414 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyEa{HEjtmSN`?>!lvI6^)nlb)_jNbFRakOYW8oEv#x-KKE6nzOmzjTkL#3rRP$y4GkYBL>`+j-;^Xuo= z+wW)aYX0U26u;%^;uvCay7ux*zGejhx4>Jw6t1kDZFTv3{kcUt=U!ZRufEe#MMWbz zBe-eDr5NtjYufBruibUfh)*N$1>+PWgQPOq5UvGBzlYyx(T#~Qc%Z_b?^5p0YFzi^ zLF4A#iyB!|4>59^oSG%Gk?Gi8=e`dO+(j+y*BsQCHn159Ht0_1;K*roaXG-AuEc0( zA^e@A<$=c@A%Q04k3J4O7LE-P1x*Z^3s_i#95}h&9P~3t;4f=pROw)0_YmOZyKq35 zy@Ac_&%%jJIt4D*zsoX5B)tBST-!lvI6-D0X`wF zqO~i;YE}r>tq`pNA+g#OKoKBAq;{2H`6{uRl|Y3C8((Oxf2p_jvD)183QO)vG_Fxy z_1I|VXOrDuHP=0tU2s#Xb)(YMqdFU3Yc0Jgzv#Bn*0*MRzXOeunSWifU3C}G2%eH4 zzu^A${^#@Wzu#}qU(c}iANO^j_)$+6#}JFtwU=)SH5u?YTs)<8VO0aShS|yg|CcIk zy{u}u{`(n`T^hlc!AhD!4tf;=|eVr>PVgy2S!}+^+|c;1K}tNc zRaV48?~?nQ{X6xHxR2z9-1azGeSV1LHKil sQ&ResLyzyCFiTy&mdKI;Vst0M-(yh5!Hn literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-ui/icons/right.png b/public/asset-packs/kenney-ui/icons/right.png new file mode 100644 index 0000000000000000000000000000000000000000..804ee888ea040ef1ce56cb774ede2d99a74e9aae GIT binary patch literal 422 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyEa{HEjtmSN`?>!lvI6-z0X`wF z!gVXeYF3ECkVx$+f$FuQwJSucR{}}F@>OEBKm{v7W=%YxHutVg@jBWQz`5(DXIlr)$AIhl(>l0JZ@jcr5~$9| zE1wp@kkFHOlD{Hl|I)_H`TY|Y_}e&4W?kUHkR;SNLEyl|%utq-_JD1n==Zs}I>(&*neU1~H1)i!ZY~nxhhrRgT zlOz7OH&t59S#2$&w)^zacZbrsPnB52sqKCpcIlbQ^K<{XXBnl~>K;4E0`wMxr>mdK II;Vst03Q6UQvd(} literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-ui/icons/square.png b/public/asset-packs/kenney-ui/icons/square.png new file mode 100644 index 0000000000000000000000000000000000000000..44666fdbb4500451536723306ca92c476b4b6a33 GIT binary patch literal 142 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!93?!50ihlx9Ea{HEjtmSN`?>!lvI6-$0X`wF zA}Q@6DQzOD?PhzwSF7h#0>zn1g8YK__h+1Z_z%dF_jGX#;kcgsA!=)u;$ba?goywD k|LYfVZeWaD9k!N*Atu!Hw3?vyexOnYPgg&ebxsLQ0LdXKVE_OC literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-ui/icons/star.png b/public/asset-packs/kenney-ui/icons/star.png new file mode 100644 index 0000000000000000000000000000000000000000..a179beef3092f9c671b56157fcc649b6ce49f1fa GIT binary patch literal 1507 zcmV<91swW`P)Y@B*dUR?9Ei3qvF9+g?I@zx6n38^namo4 zuo{N5EwJerf2u30;2@UAEw1Jqin$`1%o~Zg8HKYTl*S&B!8N<}7JH>DuI4AB*%f-E zA(X`;rrsKewi}DOA(_o3q}vpEqaKsQBcaz7d7~ny-xGD77lExOr`{r)&lrur7lpGJ zjJy+gq8pjd9gx5hbDI=>XbdZini(HDrg6n&{O zxbiW#@feA?8=BA?p4J@_FSYM3wC)&- zyBe0tF0<_|v+Np_$RnrV8kNZ`vg;X>#w)Sv7>vCuu<00$z8R3h8Ii;plEoyb;Tev< z8IQp#ujnMH;wi4@C92{ktK%rG<|nM=D6HiipVty{ns-d>UH||95Oh*bQ%{d?ug@>v ze;=P;55GU}0F0R8W&i*KiAh93R7l62m-k=OKp2P9l{VA8_a03500jiM-~eSRTR^B~ zIG`e?;>ImF>&W|;dY4?=Tyjar^8?Vkd!NsTd+)wYxJ6zlf-DP)=Mv6qQUqAM3_vVY zAgQoq`O;!gr2+*4z>1=xl>olN1PZ{an~2o_N+AM?hvK!j5Np;$un<8QVBKAV4FKW% z1tEZq_X%4-jpQu|LUj8B!d8Glz5+i$`QtR@09<~8hze!TGHfmbUdl@#1C&0uQ0lsm zYyk(b;}yjwfKcuNbcUlPuPI8RAm=VXXL#p38`}Ww`mc7KR3|Q`3ntvnnWYI6DmbbQ?FC z2Z!z;h6bB&*ysAp8Wff2AccsbLwC|TGSbQz?jZFc^CXJqN8C&Yw{J5BM@fO0x(n`x zskXK$&w6s1QmxSJ^>KvVprsmMy^R547@*h2#}RRQY=G1UsO!vbW@6GH!EPX(2NI(d z{j-FA%iulI0Lh+6q?yx}4VZmIn6+#}rh)cIQ_QK%()Oom+U){`m5CxPh`+QDrv)NA zRDEdbUiu$+OEG2L1D{*0TLs!13e75Ti*?B&7L`Y{t7;JSL)LPnkf)m1hR3G$7@~~T!lvI6miN-ZXTi?obZqr-)*l6cx&2`UB zc7Ih}^;mYnO~dUURaQJS+4)Ij<|(ti-+|g?=3k#4&O8IClcyxeFF1bw`St$w`upGW z_cQ#P%%uesKkVt^7-Dg{_QFZACIbPNi%Iij0vr{m{{Qdi$mcvOFMIlvxw|=LJ-)O= zW0J{^LmvY^Z@qu&HF-_2zq)MM6>O?+!6ZzE3OMEtHY;FVdzyBy86E c(yKL$hgAX_FKH>s0lmZE>FVdQ&MBb@0Bh)#1ONa4 literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-ui/manifest.json b/public/asset-packs/kenney-ui/manifest.json new file mode 100644 index 0000000..bc68fc6 --- /dev/null +++ b/public/asset-packs/kenney-ui/manifest.json @@ -0,0 +1,342 @@ +{ + "format": "gamekit.asset-pack", + "formatVersion": 1, + "id": "kenney-ui", + "version": "1.0.0", + "title": "界面", + "theme": "界面", + "summary": "箭头、勾、叉、星星和点击声。来自 Kenney 的 UI Pack,只要蓝色的一小套,CC0。", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/ui-pack", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。只收了蓝色默认样式里的小图标,没有把整套颜色都放进来。原始包:https://kenney.nl/assets/ui-pack", + "assets": [ + { + "id": "ui-check", + "version": "1.0.0", + "title": "打勾", + "path": "icons/check.png", + "mediaType": "image/png", + "tags": [ + "界面", + "勾" + ], + "theme": "界面", + "category": "ui", + "preview": "icons/check.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/ui-pack", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。只收了蓝色默认样式里的小图标,没有把整套颜色都放进来。原始包:https://kenney.nl/assets/ui-pack", + "sha256": "82a5c1c3dfe9a704e9f5f220c9510b622c77c2207c226b41728978c2335b1f3b", + "width": 20, + "height": 18 + }, + { + "id": "ui-cross", + "version": "1.0.0", + "title": "叉号", + "path": "icons/cross.png", + "mediaType": "image/png", + "tags": [ + "界面", + "叉" + ], + "theme": "界面", + "category": "ui", + "preview": "icons/cross.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/ui-pack", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。只收了蓝色默认样式里的小图标,没有把整套颜色都放进来。原始包:https://kenney.nl/assets/ui-pack", + "sha256": "32eea5ea58f44f15c82691cad35406b32dfad7c3c1152d633dcd74a25e430d48", + "width": 18, + "height": 18 + }, + { + "id": "ui-circle", + "version": "1.0.0", + "title": "圆点", + "path": "icons/circle.png", + "mediaType": "image/png", + "tags": [ + "界面", + "圆" + ], + "theme": "界面", + "category": "ui", + "preview": "icons/circle.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/ui-pack", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。只收了蓝色默认样式里的小图标,没有把整套颜色都放进来。原始包:https://kenney.nl/assets/ui-pack", + "sha256": "14ac9f54d1d165fa4b8da9dda962b60ab4786987af0eb7052460ede6c6ecd885", + "width": 16, + "height": 16 + }, + { + "id": "ui-square", + "version": "1.0.0", + "title": "方块", + "path": "icons/square.png", + "mediaType": "image/png", + "tags": [ + "界面", + "方块" + ], + "theme": "界面", + "category": "ui", + "preview": "icons/square.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/ui-pack", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。只收了蓝色默认样式里的小图标,没有把整套颜色都放进来。原始包:https://kenney.nl/assets/ui-pack", + "sha256": "43d8616b7a23e56753929bf723106053994b3cf5720d47abd04dbdc67b9d595b", + "width": 16, + "height": 16 + }, + { + "id": "ui-up", + "version": "1.0.0", + "title": "向上", + "path": "icons/up.png", + "mediaType": "image/png", + "tags": [ + "界面", + "箭头" + ], + "theme": "界面", + "category": "ui", + "preview": "icons/up.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/ui-pack", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。只收了蓝色默认样式里的小图标,没有把整套颜色都放进来。原始包:https://kenney.nl/assets/ui-pack", + "sha256": "8afaa9889de96dbc5ce2dd6623a3b95aad814b6419247d9f6b4af282c71f9c72", + "width": 32, + "height": 32 + }, + { + "id": "ui-right", + "version": "1.0.0", + "title": "向右", + "path": "icons/right.png", + "mediaType": "image/png", + "tags": [ + "界面", + "箭头" + ], + "theme": "界面", + "category": "ui", + "preview": "icons/right.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/ui-pack", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。只收了蓝色默认样式里的小图标,没有把整套颜色都放进来。原始包:https://kenney.nl/assets/ui-pack", + "sha256": "5517436e154ef58b64ae46ebac37ab1b8a8df8ef3e9220b4154e78acde0221da", + "width": 32, + "height": 32 + }, + { + "id": "ui-down", + "version": "1.0.0", + "title": "向下", + "path": "icons/down.png", + "mediaType": "image/png", + "tags": [ + "界面", + "箭头" + ], + "theme": "界面", + "category": "ui", + "preview": "icons/down.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/ui-pack", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。只收了蓝色默认样式里的小图标,没有把整套颜色都放进来。原始包:https://kenney.nl/assets/ui-pack", + "sha256": "94cee47dc0cc708320ecadc59795413a5ac59e0802d6f42a92163411f6ed43e2", + "width": 32, + "height": 32 + }, + { + "id": "ui-left", + "version": "1.0.0", + "title": "向左", + "path": "icons/left.png", + "mediaType": "image/png", + "tags": [ + "界面", + "箭头" + ], + "theme": "界面", + "category": "ui", + "preview": "icons/left.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/ui-pack", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。只收了蓝色默认样式里的小图标,没有把整套颜色都放进来。原始包:https://kenney.nl/assets/ui-pack", + "sha256": "576db7b4e55f6937306d0fa56ea4da000aeaf4f53891fa967d2bd7dc0a83950f", + "width": 32, + "height": 32 + }, + { + "id": "ui-box", + "version": "1.0.0", + "title": "方框", + "path": "icons/box.png", + "mediaType": "image/png", + "tags": [ + "界面", + "方框" + ], + "theme": "界面", + "category": "ui", + "preview": "icons/box.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/ui-pack", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。只收了蓝色默认样式里的小图标,没有把整套颜色都放进来。原始包:https://kenney.nl/assets/ui-pack", + "sha256": "e11648f1188535916da8645cde5532f90c806ff0d678a03b668957f0aea431df", + "width": 32, + "height": 32 + }, + { + "id": "ui-box-check", + "version": "1.0.0", + "title": "勾选", + "path": "icons/box-check.png", + "mediaType": "image/png", + "tags": [ + "界面", + "勾" + ], + "theme": "界面", + "category": "ui", + "preview": "icons/box-check.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/ui-pack", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。只收了蓝色默认样式里的小图标,没有把整套颜色都放进来。原始包:https://kenney.nl/assets/ui-pack", + "sha256": "dc8624ee930b125a1d2086b31df6c4db3c8a395b7be2c4f6e355694475bdcd96", + "width": 32, + "height": 32 + }, + { + "id": "ui-star", + "version": "1.0.0", + "title": "星星", + "path": "icons/star.png", + "mediaType": "image/png", + "tags": [ + "界面", + "星星" + ], + "theme": "界面", + "category": "ui", + "preview": "icons/star.png", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/ui-pack", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。只收了蓝色默认样式里的小图标,没有把整套颜色都放进来。原始包:https://kenney.nl/assets/ui-pack", + "sha256": "ba91a196117f8c324beac04ae426379d054e9497be901469eea5d333b369265c", + "width": 64, + "height": 60 + }, + { + "id": "ui-click", + "version": "1.0.0", + "title": "点击", + "path": "sounds/click.ogg", + "mediaType": "audio/ogg", + "tags": [ + "音效", + "界面", + "点击" + ], + "theme": "界面", + "category": "sfx", + "preview": "sounds/click.ogg", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/interface-sounds", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。声音是 Kenney 原来的 OGG Vorbis,没有转码。原始包:https://kenney.nl/assets/interface-sounds", + "sha256": "ccfb7fa0cccdd9faec0eb16033c732b1e308d139d80f799161495d58f7adcdb9" + }, + { + "id": "ui-back", + "version": "1.0.0", + "title": "返回", + "path": "sounds/back.ogg", + "mediaType": "audio/ogg", + "tags": [ + "音效", + "界面", + "返回" + ], + "theme": "界面", + "category": "sfx", + "preview": "sounds/back.ogg", + "license": { + "spdx": "CC0-1.0", + "name": "CC0 1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "author": "Kenney", + "source": "https://kenney.nl/assets/interface-sounds", + "attribution": "这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。GameKit 只收了原包里的一小部分。声音是 Kenney 原来的 OGG Vorbis,没有转码。原始包:https://kenney.nl/assets/interface-sounds", + "sha256": "07db973f79f6ae0f2edc34561e7592e24d0577455919fb602cb8ecc0da991dcf" + } + ] +} diff --git a/public/asset-packs/kenney-ui/sounds/back.ogg b/public/asset-packs/kenney-ui/sounds/back.ogg new file mode 100644 index 0000000000000000000000000000000000000000..06c5e72c4fd2773438de35ce26bd90caad730031 GIT binary patch literal 6997 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 literal 0 HcmV?d00001 diff --git a/public/asset-packs/kenney-ui/sounds/click.ogg b/public/asset-packs/kenney-ui/sounds/click.ogg new file mode 100644 index 0000000000000000000000000000000000000000..7ca77c7186126ce177640aad0c7ccc4c59bf4446 GIT binary patch literal 4876 zcmai230PBC)4q{4h%`X3K_lM

Pq@U{Hf%0a?t2h$I9gl!}3fY*7=UQiWm(2#OKm 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 str: + return ( + f"这些素材来自 Kenney(www.kenney.nl)的 CC0 包,使用时无需署名。" + f"GameKit 只收了原包里的一小部分。{extra}" + f"原始包:{page}" + ) + + +def sha256(data: bytes) -> str: + return hashlib.sha256(data).hexdigest() + + +def write_png(path: Path, width: int, height: int, rgba: bytes) -> None: + if len(rgba) != width * height * 4: + raise SystemExit(f"bad rgba {path}") + + def chunk(tag: bytes, data: bytes) -> bytes: + return struct.pack(">I", len(data)) + tag + data + struct.pack(">I", zlib.crc32(tag + data) & 0xFFFFFFFF) + + raw = bytearray() + stride = width * 4 + for y in range(height): + raw.append(0) + raw += rgba[y * stride : (y + 1) * stride] + ihdr = struct.pack(">IIBBBBB", width, height, 8, 6, 0, 0, 0) + png = b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", ihdr) + chunk(b"IDAT", zlib.compress(bytes(raw), 9)) + chunk(b"IEND", b"") + path.parent.mkdir(parents=True, exist_ok=True) + path.write_bytes(png) + + +def load_rgba(path: Path) -> tuple[int, int, bytes]: + probe = subprocess.check_output( + ["ffprobe", "-v", "error", "-select_streams", "v:0", "-show_entries", "stream=width,height", "-of", "csv=p=0", str(path)], + text=True, + ).strip() + width_s, height_s = probe.split(",") + width, height = int(width_s), int(height_s) + raw = subprocess.check_output(["ffmpeg", "-v", "error", "-i", str(path), "-f", "rawvideo", "-pix_fmt", "rgba", "pipe:1"]) + if len(raw) != width * height * 4: + raise SystemExit(f"ffmpeg size {path}") + return width, height, raw + + +def cell(image: tuple[int, int, bytes], tile: int, index: int, columns: int) -> bytes: + width, _height, pixels = image + column = index % columns + row = index // columns + out = bytearray(tile * tile * 4) + for y in range(tile): + src = ((row * tile + y) * width + column * tile) * 4 + dst = y * tile * 4 + out[dst : dst + tile * 4] = pixels[src : src + tile * 4] + return bytes(out) + + +def hstrip(frames: list[bytes], tile_w: int, tile_h: int) -> tuple[int, int, bytes]: + width = tile_w * len(frames) + height = tile_h + out = bytearray(width * height * 4) + for index, frame in enumerate(frames): + if len(frame) != tile_w * tile_h * 4: + raise SystemExit("frame size") + for y in range(tile_h): + src = y * tile_w * 4 + dst = (y * width + index * tile_w) * 4 + out[dst : dst + tile_w * 4] = frame[src : src + tile_w * 4] + return width, height, bytes(out) + + +def pad_frame(rgba: bytes, width: int, height: int, tile: int) -> bytes: + """Bottom-align and center a sprite on a square cell. Empty pixels stay transparent.""" + out = bytearray(tile * tile * 4) + ox = (tile - width) // 2 + oy = tile - height + for y in range(height): + for x in range(width): + src = (y * width + x) * 4 + dst = ((oy + y) * tile + ox + x) * 4 + out[dst : dst + 4] = rgba[src : src + 4] + return bytes(out) + + +def down2(rgba: bytes, width: int, height: int) -> tuple[int, int, bytes]: + """Nearest-neighbor half size. Each 2×2 block keeps its top-left pixel.""" + nw, nh = width // 2, height // 2 + out = bytearray(nw * nh * 4) + for y in range(nh): + for x in range(nw): + src = ((y * 2) * width + x * 2) * 4 + dst = (y * nw + x) * 4 + out[dst : dst + 4] = rgba[src : src + 4] + return nw, nh, bytes(out) + + +def grid(cells: list[bytes], columns: int, tile: int) -> tuple[int, int, bytes]: + rows = (len(cells) + columns - 1) // columns + width = columns * tile + height = rows * tile + out = bytearray(width * height * 4) + for index, frame in enumerate(cells): + column = index % columns + row = index // columns + for y in range(tile): + src = y * tile * 4 + dst = ((row * tile + y) * width + column * tile) * 4 + out[dst : dst + tile * 4] = frame[src : src + tile * 4] + return width, height, bytes(out) + + +class Pack: + def __init__(self, pack_id: str, title: str, theme: str, summary: str, page: str, note: str): + self.id = pack_id + self.title = title + self.theme = theme + self.summary = summary + self.page = page + self.attribution = credit(page, note) + self.assets: list[dict] = [] + self.dir = ROOT / pack_id + + def add( + self, + asset_id: str, + title: str, + rel: str, + data: bytes, + category: str, + tags: list[str], + media: str = "image/png", + width: int | None = None, + height: int | None = None, + animation: dict | None = None, + collision: dict | None = None, + tileset: dict | None = None, + ) -> None: + path = self.dir / rel + path.parent.mkdir(parents=True, exist_ok=True) + path.write_bytes(data) + entry = { + "id": asset_id, + "version": "1.0.0", + "title": title, + "path": rel, + "mediaType": media, + "tags": tags, + "theme": self.theme, + "category": category, + "preview": rel, + "license": LICENSE, + "author": AUTHOR, + "source": self.page, + "attribution": self.attribution, + "sha256": sha256(data), + } + if width and height: + entry["width"] = width + entry["height"] = height + if animation: + entry["animation"] = animation + if collision: + entry["collision"] = collision + if tileset: + entry["tileset"] = tileset + self.assets.append(entry) + + def manifest(self) -> dict: + return { + "format": "gamekit.asset-pack", + "formatVersion": 1, + "id": self.id, + "version": "1.0.0", + "title": self.title, + "theme": self.theme, + "summary": self.summary, + "license": LICENSE, + "author": AUTHOR, + "source": self.page, + "attribution": self.attribution, + "assets": self.assets, + } + + +def anim(frame_w: int, frame_h: int, frames: list[tuple[str, int]], states: dict[str, list[int]]) -> dict: + return { + "frameWidth": frame_w, + "frameHeight": frame_h, + "frames": [{"index": index, "durationMs": duration, "name": name} for index, (name, duration) in enumerate(frames)], + "states": states, + } + + +def copy_bytes(path: Path) -> bytes: + return path.read_bytes() + + +def write_hold(width: int, height: int, rgba: bytes) -> bytes: + # Encode without a path, then the pack writer stores the bytes. + raw_path = Path("/tmp/kenney/hold.png") + write_png(raw_path, width, height, rgba) + return raw_path.read_bytes() + + +def add_sound(pack: Pack, asset_id: str, title: str, rel: str, src: Path, tags: list[str], page: str) -> None: + data = copy_bytes(src) + # Per-file source stays the audio pack page, while the image pack page stays on the pack. + path = pack.dir / rel + path.parent.mkdir(parents=True, exist_ok=True) + path.write_bytes(data) + pack.assets.append( + { + "id": asset_id, + "version": "1.0.0", + "title": title, + "path": rel, + "mediaType": "audio/ogg", + "tags": tags, + "theme": pack.theme, + "category": "sfx", + "preview": rel, + "license": LICENSE, + "author": AUTHOR, + "source": page, + "attribution": credit(page, "声音是 Kenney 原来的 OGG Vorbis,没有转码。"), + "sha256": sha256(data), + } + ) + + +def save_pack(pack: Pack) -> None: + manifest = pack.manifest() + (pack.dir / "manifest.json").write_text(json.dumps(manifest, ensure_ascii=False, indent=2) + "\n") + + +def build_platform() -> None: + page = "https://kenney.nl/assets/pixel-platformer" + chars = load_rgba(SRC / "pixel-platformer/Tilemap/tilemap-characters_packed.png") + walk = anim(24, 24, [("站立", 240), ("走路", 120)], {"站立": [0], "走路": [1]}) + box = {"x": 6, "y": 4, "width": 12, "height": 18} + pack = Pack( + "kenney-platform", + "平台跳跃", + "平台跳跃", + "绿色和蓝色小人、草地、泥土、石砖和水面,加上跳跃和脚步声。来自 Kenney 的 Pixel Platformer,CC0。", + page, + "小人的两帧排成了一张精灵表,动画编辑器可以直接打开。地形保持原来的 18 像素。", + ) + for asset_id, title, rel, indices, tags in [ + ("platform-walker", "绿色小人", "characters/walker.png", (0, 1), ["角色", "主角", "跳跃"]), + ("platform-walker-blue", "蓝色小人", "characters/walker-blue.png", (2, 3), ["角色", "跳跃", "变体"]), + ]: + frames = [cell(chars, 24, index, 9) for index in indices] + width, height, rgba = hstrip(frames, 24, 24) + pack.add(asset_id, title, rel, write_hold(width, height, rgba), "character", tags, width=width, height=height, animation=walk, collision=box) + tiles = SRC / "pixel-platformer/Tiles" + for asset_id, title, rel, filename, category, tags in [ + ("platform-grass", "草地", "terrain/grass.png", "tile_0016.png", "terrain", ["地形", "草地"]), + ("platform-grass-edge", "草地边", "terrain/grass-edge.png", "tile_0017.png", "terrain", ["地形", "草地"]), + ("platform-dirt", "泥土", "terrain/dirt.png", "tile_0004.png", "terrain", ["地形", "泥土"]), + ("platform-stone", "石砖", "terrain/stone.png", "tile_0000.png", "terrain", ["地形", "石头"]), + ("platform-water", "水面", "terrain/water.png", "tile_0033.png", "terrain", ["地形", "水面"]), + ("platform-pebble", "小石块", "props/pebble.png", "tile_0007.png", "prop", ["道具", "石头"]), + ("platform-dust", "尘土", "effects/dust.png", "tile_0008.png", "effect", ["特效", "尘土"]), + ]: + data = copy_bytes(tiles / filename) + width, height, _ = load_rgba(tiles / filename) + pack.add(asset_id, title, rel, data, category, tags, width=width, height=height) + add_sound(pack, "platform-jump", "跳跃", "sounds/jump.ogg", SRC / "digital/Audio/phaseJump1.ogg", ["音效", "跳跃", "角色"], "https://kenney.nl/assets/digital-audio") + add_sound(pack, "platform-step", "脚步", "sounds/step.ogg", SRC / "impact/Audio/footstep_grass_000.ogg", ["音效", "走路", "角色"], "https://kenney.nl/assets/impact-sounds") + save_pack(pack) + print(pack.id, len(pack.assets)) + + +def build_dungeon() -> None: + page = "https://kenney.nl/assets/tiny-dungeon" + sheet = load_rgba(SRC / "tiny-dungeon/Tilemap/tilemap_packed.png") + picked = [ + (0, "棕色地砖"), + (1, "深色地砖"), + (4, "灰色地砖"), + (7, "蓝灰地砖"), + (9, "暗色地砖"), + (12, "砖墙"), + (24, "石墙"), + (36, "蓝砖"), + (48, "木地板"), + (60, "白花"), + (61, "石碑"), + (101, "木桶"), + (102, "木箱"), + (108, "木门"), + (114, "旗帜"), + (120, "木箱盖"), + ] + cells = [cell(sheet, 16, index, 12) for index, _name in picked] + names = [name for _index, name in picked] + width, height, rgba = grid(cells, 4, 16) + pack = Pack( + "kenney-dungeon", + "迷宫地牢", + "迷宫地牢", + "16 像素的地砖、墙、门、箱子和旗帜,可以放进地图编辑器。来自 Kenney 的 Tiny Dungeon,CC0。", + page, + "图块按 4×4 排好,每格 16 像素,地图编辑器的调色板可以直接用。", + ) + pack.add( + "dungeon-tiles", + "地牢图块", + "tilesets/rooms.png", + write_hold(width, height, rgba), + "tileset", + ["图块", "地形", "地牢"], + width=width, + height=height, + tileset={"tileWidth": 16, "tileHeight": 16, "columns": 4, "rows": 4, "names": names}, + ) + singles = [ + ("dungeon-flower", "白花", "effects/flower.png", 60, "effect", ["特效", "花"]), + ("dungeon-door", "木门", "props/door.png", 108, "prop", ["道具", "门"]), + ("dungeon-crate", "木箱", "props/crate.png", 102, "prop", ["道具", "箱子"]), + ("dungeon-flag", "旗帜", "props/flag.png", 114, "prop", ["道具", "旗帜"]), + ] + for asset_id, title, rel, index, category, tags in singles: + frame = cell(sheet, 16, index, 12) + pack.add(asset_id, title, rel, write_hold(16, 16, frame), category, tags, width=16, height=16) + add_sound(pack, "dungeon-door-sfx", "开门", "sounds/door.ogg", SRC / "rpg/Audio/doorOpen_1.ogg", ["音效", "门", "地牢"], "https://kenney.nl/assets/rpg-audio") + add_sound(pack, "dungeon-step", "石地脚步", "sounds/step.ogg", SRC / "rpg/Audio/footstep00.ogg", ["音效", "走路", "地牢"], "https://kenney.nl/assets/rpg-audio") + save_pack(pack) + print(pack.id, len(pack.assets)) + + +def build_space() -> None: + page = "https://kenney.nl/assets/pixel-shmup" + tiles = load_rgba(SRC / "pixel-shmup/Tilemap/tiles_packed.png") + picked = [ + (36, "草地"), + (37, "浅草"), + (38, "黄绿草地"), + (40, "绿草地"), + (42, "冰面"), + (43, "沙地"), + (44, "褐沙"), + (46, "泥土"), + (72, "木板"), + (73, "浅木板"), + (74, "木纹"), + (75, "深木板"), + (48, "黄草地"), + (54, "深草地"), + (66, "石地"), + (84, "泥地"), + ] + cells = [cell(tiles, 16, index, 12) for index, _name in picked] + names = [name for _index, name in picked] + width, height, rgba = grid(cells, 4, 16) + pack = Pack( + "kenney-space", + "太空射击", + "太空射击", + "飞船、敌机、地面图块和闪光,加上激光声。来自 Kenney 的 Pixel Shmup,CC0。", + page, + "地面图块按 4×4 排好,每格 16 像素,地图编辑器可以直接用。飞船是原来的 32 像素。", + ) + pack.add( + "space-tiles", + "空地图块", + "tilesets/ground.png", + write_hold(width, height, rgba), + "tileset", + ["图块", "地形", "射击"], + width=width, + height=height, + tileset={"tileWidth": 16, "tileHeight": 16, "columns": 4, "rows": 4, "names": names}, + ) + ships = SRC / "pixel-shmup/Ships" + for asset_id, title, rel, filename, tags in [ + ("space-ship", "飞船", "characters/ship.png", "ship_0000.png", ["角色", "飞船", "射击"]), + ("space-enemy", "敌机", "characters/enemy.png", "ship_0006.png", ["角色", "敌人", "射击"]), + ("space-enemy-2", "另一艘敌机", "characters/enemy-2.png", "ship_0012.png", ["角色", "敌人", "变体"]), + ]: + data = copy_bytes(ships / filename) + w, h, _ = load_rgba(ships / filename) + pack.add(asset_id, title, rel, data, "character", tags, width=w, height=h, collision={"x": 4, "y": 4, "width": 24, "height": 24}) + for asset_id, title, rel, index, tags in [ + ("space-star", "金星", "effects/star.png", 0, ["特效", "星星"]), + ("space-spark", "闪光", "effects/spark.png", 2, ["特效", "闪光"]), + ("space-flare", "火花", "effects/flare.png", 4, ["特效", "火花"]), + ]: + frame = cell(tiles, 16, index, 12) + pack.add(asset_id, title, rel, write_hold(16, 16, frame), "effect", tags, width=16, height=16) + add_sound(pack, "space-laser", "激光", "sounds/laser.ogg", SRC / "digital/Audio/laser1.ogg", ["音效", "射击", "激光"], "https://kenney.nl/assets/digital-audio") + add_sound(pack, "space-hit", "击中", "sounds/hit.ogg", SRC / "impact/Audio/impactSoft_medium_000.ogg", ["音效", "撞击", "射击"], "https://kenney.nl/assets/impact-sounds") + save_pack(pack) + print(pack.id, len(pack.assets)) + + +def build_racing() -> None: + page = "https://kenney.nl/assets/pixel-vehicle-pack" + people = SRC / "pixel-vehicle/PNG/Characters" + frames = [] + for name in ("man.png", "man_walk1.png", "man_walk2.png"): + w, h, rgba = load_rgba(people / name) + frames.append(pad_frame(rgba, w, h, 16)) + width, height, rgba = hstrip(frames, 16, 16) + walk = anim(16, 16, [("站立", 200), ("迈步", 120), ("再迈", 120)], {"站立": [0], "走路": [1, 2]}) + pack = Pack( + "kenney-racing", + "竞速", + "竞速", + "赛车、走路的人、路障和一段公路,加上撞击声。来自 Kenney 的 Pixel Vehicle Pack,CC0。", + page, + "人的三帧原来宽窄不一样,这里放在同样的 16×16 透明格子里,动画编辑器才能打开。车还是原来的大小。", + ) + pack.add( + "racing-driver", + "车手", + "characters/driver.png", + write_hold(width, height, rgba), + "character", + ["角色", "车手", "走路"], + width=width, + height=height, + animation=walk, + collision={"x": 4, "y": 1, "width": 8, "height": 14}, + ) + cars = SRC / "pixel-vehicle/PNG/Cars" + for asset_id, title, rel, filename, tags in [ + ("racing-car-green", "绿色跑车", "props/car-green.png", "sports_green.png", ["道具", "赛车"]), + ("racing-taxi", "出租车", "props/taxi.png", "taxi.png", ["道具", "赛车"]), + ("racing-bus", "巴士", "props/bus.png", "bus.png", ["道具", "赛车"]), + ("racing-car-red", "红色跑车", "props/car-red.png", "sports_race.png", ["道具", "赛车", "变体"]), + ]: + data = copy_bytes(cars / filename) + w, h, _ = load_rgba(cars / filename) + pack.add(asset_id, title, rel, data, "prop", tags, width=w, height=h) + props = SRC / "pixel-vehicle/PNG/Props" + for asset_id, title, rel, filename, category, tags in [ + ("racing-road", "公路", "terrain/road.png", "highway.png", "terrain", ["地形", "公路"]), + ("racing-barrier", "路障", "props/barrier.png", "barrier.png", "prop", ["道具", "路障"]), + ("racing-sign", "路牌", "props/sign.png", "sign_blue.png", "prop", ["道具", "路牌"]), + ("racing-light", "路灯", "effects/light.png", "light.png", "effect", ["特效", "灯光"]), + ]: + data = copy_bytes(props / filename) + w, h, _ = load_rgba(props / filename) + pack.add(asset_id, title, rel, data, category, tags, width=w, height=h) + add_sound(pack, "racing-crash", "撞击", "sounds/crash.ogg", SRC / "impact/Audio/impactMetal_light_000.ogg", ["音效", "撞击", "赛车"], "https://kenney.nl/assets/impact-sounds") + add_sound(pack, "racing-clank", "金属声", "sounds/clank.ogg", SRC / "impact/Audio/impactPlate_light_000.ogg", ["音效", "撞击", "变体"], "https://kenney.nl/assets/impact-sounds") + save_pack(pack) + print(pack.id, len(pack.assets)) + + +def build_puzzle() -> None: + page = "https://kenney.nl/assets/sokoban" + base = SRC / "sokoban/PNG/Default size" + frames = [] + for name in ("player_01.png", "player_02.png", "player_03.png", "player_04.png"): + w, h, rgba = load_rgba(base / "Player" / name) + if (w, h) != (64, 64): + raise SystemExit("player size") + frames.append(rgba) + width, height, rgba = hstrip(frames, 64, 64) + motion = anim(64, 64, [("站立", 200), ("迈步", 140), ("侧身", 140), ("回头", 140)], {"站立": [0], "走路": [1, 2, 3]}) + picked = [ + ("Ground/ground_01.png", "地面"), + ("Ground/ground_02.png", "深地面"), + ("Ground/ground_03.png", "石地面"), + ("Ground/ground_04.png", "木地面"), + ("Blocks/block_01.png", "方块"), + ("Blocks/block_02.png", "红方块"), + ("Blocks/block_03.png", "蓝方块"), + ("Blocks/block_04.png", "绿方块"), + ("Crates/crate_02.png", "木箱"), + ("Crates/crate_08.png", "铁箱"), + ("Environment/environment_02.png", "墙壁"), + ("Environment/environment_05.png", "石墙"), + ("Ground/ground_05.png", "草地"), + ("Ground/ground_06.png", "沙地"), + ("Blocks/block_05.png", "黄方块"), + ("Environment/environment_06.png", "标记"), + ] + cells = [] + names = [] + for rel, name in picked: + w, h, raw = load_rgba(base / rel) + nw, nh, small = down2(raw, w, h) + if (nw, nh) != (32, 32): + raise SystemExit(f"puzzle tile {rel} {nw}x{nh}") + cells.append(small) + names.append(name) + tw, th, grid_rgba = grid(cells, 4, 32) + pack = Pack( + "kenney-puzzle", + "益智", + "益智", + "推箱子的人和 32 像素的地面、方块、箱子。来自 Kenney 的 Sokoban,CC0。", + page, + "地图格子从原来的 64 像素缩小到 32 像素,好放进地图编辑器。人还是 64 像素,四帧排成精灵表。", + ) + pack.add( + "puzzle-player", + "推箱子的人", + "characters/player.png", + write_hold(width, height, rgba), + "character", + ["角色", "益智"], + width=width, + height=height, + animation=motion, + collision={"x": 16, "y": 8, "width": 32, "height": 48}, + ) + pack.add( + "puzzle-tiles", + "益智图块", + "tilesets/blocks.png", + write_hold(tw, th, grid_rgba), + "tileset", + ["图块", "地形", "益智"], + width=tw, + height=th, + tileset={"tileWidth": 32, "tileHeight": 32, "columns": 4, "rows": 4, "names": names}, + ) + add_sound(pack, "puzzle-place", "放好", "sounds/place.ogg", SRC / "digital/Audio/pepSound1.ogg", ["音效", "金币", "益智"], "https://kenney.nl/assets/digital-audio") + add_sound(pack, "puzzle-ok", "完成", "sounds/ok.ogg", SRC / "interface/Audio/confirmation_001.ogg", ["音效", "界面", "益智"], "https://kenney.nl/assets/interface-sounds") + save_pack(pack) + print(pack.id, len(pack.assets)) + + +def build_ui() -> None: + page = "https://kenney.nl/assets/ui-pack" + blue = SRC / "ui-pack/PNG/Blue/Default" + pack = Pack( + "kenney-ui", + "界面", + "界面", + "箭头、勾、叉、星星和点击声。来自 Kenney 的 UI Pack,只要蓝色的一小套,CC0。", + page, + "只收了蓝色默认样式里的小图标,没有把整套颜色都放进来。", + ) + for asset_id, title, rel, filename, tags in [ + ("ui-check", "打勾", "icons/check.png", "icon_checkmark.png", ["界面", "勾"]), + ("ui-cross", "叉号", "icons/cross.png", "icon_cross.png", ["界面", "叉"]), + ("ui-circle", "圆点", "icons/circle.png", "icon_circle.png", ["界面", "圆"]), + ("ui-square", "方块", "icons/square.png", "icon_square.png", ["界面", "方块"]), + ("ui-up", "向上", "icons/up.png", "arrow_basic_n.png", ["界面", "箭头"]), + ("ui-right", "向右", "icons/right.png", "arrow_basic_e.png", ["界面", "箭头"]), + ("ui-down", "向下", "icons/down.png", "arrow_basic_s.png", ["界面", "箭头"]), + ("ui-left", "向左", "icons/left.png", "arrow_basic_w.png", ["界面", "箭头"]), + ("ui-box", "方框", "icons/box.png", "check_square_grey.png", ["界面", "方框"]), + ("ui-box-check", "勾选", "icons/box-check.png", "check_square_grey_checkmark.png", ["界面", "勾"]), + ("ui-star", "星星", "icons/star.png", "star.png", ["界面", "星星"]), + ]: + data = copy_bytes(blue / filename) + w, h, _ = load_rgba(blue / filename) + pack.add(asset_id, title, rel, data, "ui", tags, width=w, height=h) + add_sound(pack, "ui-click", "点击", "sounds/click.ogg", SRC / "interface/Audio/click_001.ogg", ["音效", "界面", "点击"], "https://kenney.nl/assets/interface-sounds") + add_sound(pack, "ui-back", "返回", "sounds/back.ogg", SRC / "interface/Audio/back_001.ogg", ["音效", "界面", "返回"], "https://kenney.nl/assets/interface-sounds") + save_pack(pack) + print(pack.id, len(pack.assets)) + + +def build_sfx() -> None: + page = "https://kenney.nl/assets" + # The pack source is the Kenney assets home, and each file names its own pack page. + pack = Pack( + "kenney-sfx", + "音效", + "音效", + "跳跃、金币、激光、脚步、开门和点击。来自 Kenney 的几套 CC0 音效,都是原来的 OGG Vorbis。", + "https://kenney.nl/assets/digital-audio", + "这一套把几个音效包里的短声音放在一起。每条声音的来源链到它自己的原包。", + ) + # Pack.source is one page; per-file source is set in add_sound. + items = [ + ("sfx-jump", "跳跃", "sounds/jump.ogg", SRC / "digital/Audio/phaseJump1.ogg", ["音效", "跳跃", "平台跳跃"], "https://kenney.nl/assets/digital-audio"), + ("sfx-jump-soft", "轻跳", "sounds/jump-soft.ogg", SRC / "digital/Audio/phaseJump2.ogg", ["音效", "跳跃", "变体"], "https://kenney.nl/assets/digital-audio"), + ("sfx-coin", "金币", "sounds/coin.ogg", SRC / "digital/Audio/pepSound1.ogg", ["音效", "金币", "益智"], "https://kenney.nl/assets/digital-audio"), + ("sfx-laser", "激光", "sounds/laser.ogg", SRC / "digital/Audio/laser1.ogg", ["音效", "射击", "激光"], "https://kenney.nl/assets/digital-audio"), + ("sfx-power", "升级", "sounds/power.ogg", SRC / "digital/Audio/powerUp1.ogg", ["音效", "道具", "升级"], "https://kenney.nl/assets/digital-audio"), + ("sfx-step", "草地脚步", "sounds/step.ogg", SRC / "impact/Audio/footstep_grass_000.ogg", ["音效", "走路", "平台跳跃"], "https://kenney.nl/assets/impact-sounds"), + ("sfx-hit", "轻撞", "sounds/hit.ogg", SRC / "impact/Audio/impactSoft_medium_000.ogg", ["音效", "撞击"], "https://kenney.nl/assets/impact-sounds"), + ("sfx-punch", "拳击", "sounds/punch.ogg", SRC / "impact/Audio/impactPunch_medium_000.ogg", ["音效", "撞击", "地牢"], "https://kenney.nl/assets/impact-sounds"), + ("sfx-click", "点击", "sounds/click.ogg", SRC / "interface/Audio/click_001.ogg", ["音效", "界面", "点击"], "https://kenney.nl/assets/interface-sounds"), + ("sfx-confirm", "确认", "sounds/confirm.ogg", SRC / "interface/Audio/confirmation_001.ogg", ["音效", "界面", "确认"], "https://kenney.nl/assets/interface-sounds"), + ("sfx-back", "返回", "sounds/back.ogg", SRC / "interface/Audio/back_001.ogg", ["音效", "界面", "返回"], "https://kenney.nl/assets/interface-sounds"), + ("sfx-door", "开门", "sounds/door.ogg", SRC / "rpg/Audio/doorOpen_1.ogg", ["音效", "门", "迷宫地牢"], "https://kenney.nl/assets/rpg-audio"), + ("sfx-step-stone", "石地脚步", "sounds/step-stone.ogg", SRC / "rpg/Audio/footstep00.ogg", ["音效", "走路", "迷宫地牢"], "https://kenney.nl/assets/rpg-audio"), + ("sfx-laser-small", "小激光", "sounds/laser-small.ogg", SRC / "scifi/Audio/laserSmall_000.ogg", ["音效", "射击", "变体"], "https://kenney.nl/assets/sci-fi-sounds"), + ("sfx-boom", "爆炸", "sounds/boom.ogg", SRC / "scifi/Audio/lowFrequency_explosion_001.ogg", ["音效", "爆炸", "射击"], "https://kenney.nl/assets/sci-fi-sounds"), + ] + for asset_id, title, rel, src, tags, source in items: + add_sound(pack, asset_id, title, rel, src, tags, source) + # The pack-level source should name the collection, not only digital-audio. + pack.page = "https://kenney.nl/assets" + pack.attribution = credit( + "https://kenney.nl/assets", + "这一套把 Digital Audio、Impact Sounds、Interface Sounds、RPG Audio 和 Sci-fi Sounds 里的短声音放在一起。每条声音的来源链到它自己的原包。", + ) + for asset in pack.assets: + if asset["source"] == "https://kenney.nl/assets/digital-audio" and asset["id"] == "sfx-jump": + pass + # Refresh pack-level fields already copied into assets at add time. Pack attribution on the manifest uses pack.attribution at save. + save_pack(pack) + print(pack.id, len(pack.assets)) + + +def write_index() -> None: + packs = [] + for folder in sorted(p for p in ROOT.iterdir() if p.is_dir()): + manifest_path = folder / "manifest.json" + if not manifest_path.exists(): + continue + manifest = json.loads(manifest_path.read_text()) + packs.append( + { + "id": manifest["id"], + "version": manifest["version"], + "title": manifest["title"], + "theme": manifest["theme"], + "summary": manifest["summary"], + "license": manifest["license"]["spdx"], + "author": manifest["author"], + "source": manifest["source"], + "attribution": manifest["attribution"], + "assetCount": len(manifest["assets"]), + } + ) + order = {"forest-adventure": 0, "forest-sounds": 1} + packs.sort(key=lambda item: (order.get(item["id"], 2), item["id"])) + index = {"format": "gamekit.asset-catalog", "formatVersion": 1, "packs": packs} + (ROOT / "index.json").write_text(json.dumps(index, ensure_ascii=False, indent=2) + "\n") + total = sum(item["assetCount"] for item in packs) + print(f"index packs={len(packs)} assets={total}") + + +if __name__ == "__main__": + if not SRC.is_dir(): + raise SystemExit(f"Missing Kenney sources at {SRC}") + for name in ["kenney-platform", "kenney-dungeon", "kenney-space", "kenney-racing", "kenney-puzzle", "kenney-ui", "kenney-sfx"]: + folder = ROOT / name + if folder.exists(): + shutil.rmtree(folder) + build_platform() + build_dungeon() + build_space() + build_racing() + build_puzzle() + build_ui() + build_sfx() + write_index() diff --git a/scripts/write-forest-pack.ts b/scripts/write-forest-pack.ts index 9ad003c..e6a75fb 100644 --- a/scripts/write-forest-pack.ts +++ b/scripts/write-forest-pack.ts @@ -1,6 +1,7 @@ -import { mkdir, writeFile } from "node:fs/promises"; +import { mkdir, readdir, readFile, writeFile } from "node:fs/promises"; import { dirname, join } from "node:path"; import { buildForestPack, catalogIndex } from "../src/lib/assets/forest"; +import type { AssetPack } from "../src/lib/assets/schema"; import { buildSoundPack } from "../src/lib/assets/sounds"; /** Writes the committed packs under public/asset-packs. Run from the repo root after changing a drawing or a sound preset. */ @@ -21,4 +22,18 @@ const forest = await buildForestPack(); const sounds = await buildSoundPack(); await writePack(forest.manifest, forest.files); await writePack(sounds.manifest, sounds.files); -await writeFile(join(root, "index.json"), `${JSON.stringify(catalogIndex([forest.manifest, sounds.manifest]), null, 2)}\n`); + +const folders = await readdir(root, { withFileTypes: true }); +const packs: AssetPack[] = []; +for (const entry of folders) { + if (!entry.isDirectory()) continue; + packs.push(JSON.parse(await readFile(join(root, entry.name, "manifest.json"), "utf8")) as AssetPack); +} +const first = ["forest-adventure", "forest-sounds"]; +packs.sort((a, b) => { + const ai = first.indexOf(a.id); + const bi = first.indexOf(b.id); + if (ai !== -1 || bi !== -1) return (ai === -1 ? first.length : ai) - (bi === -1 ? first.length : bi); + return a.id.localeCompare(b.id); +}); +await writeFile(join(root, "index.json"), `${JSON.stringify(catalogIndex(packs), null, 2)}\n`); diff --git a/src/lib/assets/forest.ts b/src/lib/assets/forest.ts index 7b0138a..9d7130e 100644 --- a/src/lib/assets/forest.ts +++ b/src/lib/assets/forest.ts @@ -8,8 +8,8 @@ import { catalogIndexSchema, type AssetPack, type CatalogAsset, type CatalogInde * * Drawn for GameKit and released CC0. It is not a copy of a third-party pack: * every pixel, the license, the author, and the source are ours to stand behind. - * Later packs can add other CC0 sources (Kenney and similar) the same way, - * once each file has been reviewed and the provenance fields are filled in. + * Kenney CC0 packs live beside this one under public/asset-packs. + * Each of those files keeps its own author, source, and hash. */ const OUTLINE: Rgba = [43, 33, 24, 255]; diff --git a/src/lib/assets/kenney.test.ts b/src/lib/assets/kenney.test.ts new file mode 100644 index 0000000..7045b55 --- /dev/null +++ b/src/lib/assets/kenney.test.ts @@ -0,0 +1,83 @@ +import { readdirSync, readFileSync } from "node:fs"; +import { join } from "node:path"; +import { describe, expect, it } from "vitest"; +import { inspectAudio } from "../audio/format"; +import { framesFromDocument, parseSpriteAnim } from "../pixel/anim"; +import { decodePng } from "../pixel/png"; +import { checkAssetPacks } from "./check-disk"; +import type { AssetPack } from "./schema"; +import { librarySpriteNote } from "./sprite-note"; +import { editorTileset } from "./tileset"; + +const root = join(process.cwd(), "public", "asset-packs"); +const THEMES = [ + "kenney-dungeon", + "kenney-platform", + "kenney-puzzle", + "kenney-racing", + "kenney-sfx", + "kenney-space", + "kenney-ui", +]; + +function loadPack(id: string): AssetPack { + return JSON.parse(readFileSync(join(root, id, "manifest.json"), "utf8")) as AssetPack; +} + +describe("Kenney CC0 packs", () => { + const ids = readdirSync(root, { withFileTypes: true }) + .filter((entry) => entry.isDirectory() && entry.name.startsWith("kenney-")) + .map((entry) => entry.name) + .sort(); + + it("ships one pack for each theme and passes the ship gate", async () => { + expect(ids).toEqual(THEMES); + expect(await checkAssetPacks(root)).toEqual([]); + }); + + it("keeps the CC0 credit, a Chinese tag, and a playable ogg on every file", () => { + for (const id of ids) { + const pack = loadPack(id); + expect(pack.author).toBe("Kenney"); + expect(pack.license.spdx).toBe("CC0-1.0"); + expect(pack.source).toMatch(/^https:\/\/kenney\.nl\//); + expect(pack.attribution).toContain("Kenney"); + for (const asset of pack.assets) { + expect(asset.author).toBe("Kenney"); + expect(asset.license.spdx).toBe("CC0-1.0"); + expect(asset.license.name.length).toBeGreaterThan(0); + expect(asset.source).toMatch(/^https:\/\/kenney\.nl\//); + expect(asset.attribution.length).toBeGreaterThan(0); + expect(asset.tags.some((tag) => /[\u4e00-\u9fff]/.test(tag))).toBe(true); + const bytes = new Uint8Array(readFileSync(join(root, id, asset.path))); + if (asset.mediaType === "audio/ogg") expect(inspectAudio(asset.path, bytes)?.ok).toBe(true); + } + } + }); + + it("fits dungeon, space, and puzzle sheets into the map editor", () => { + const dungeon = loadPack("kenney-dungeon").assets.find((asset) => asset.id === "dungeon-tiles"); + const space = loadPack("kenney-space").assets.find((asset) => asset.id === "space-tiles"); + const puzzle = loadPack("kenney-puzzle").assets.find((asset) => asset.id === "puzzle-tiles"); + expect(dungeon && editorTileset(dungeon)).toMatchObject({ tileWidth: 16, names: expect.arrayContaining(["棕色地砖"]) }); + expect(space && editorTileset(space)?.tileWidth).toBe(16); + expect(puzzle && editorTileset(puzzle)?.tileWidth).toBe(32); + expect(loadPack("kenney-platform").assets.every((asset) => editorTileset(asset) === null)).toBe(true); + }); + + it("opens the walker sheet as two animation frames", () => { + const walker = loadPack("kenney-platform").assets.find((asset) => asset.id === "platform-walker"); + expect(walker?.animation?.frames).toHaveLength(2); + if (!walker?.animation) return; + const decoded = decodePng(new Uint8Array(readFileSync(join(root, "kenney-platform", walker.path)))); + expect(decoded.ok).toBe(true); + if (!decoded.ok) return; + const path = "assets/library/kenney-platform/characters/walker.png"; + const note = librarySpriteNote(path, walker.animation); + expect(note).toBeTruthy(); + const parsed = parseSpriteAnim(note ?? "", path); + expect(parsed.ok).toBe(true); + if (!parsed.ok) return; + expect(framesFromDocument(decoded.pixels, parsed.document)).toHaveLength(2); + }); +}); diff --git a/src/lib/assets/schema.ts b/src/lib/assets/schema.ts index 4c3dd16..5b23a69 100644 --- a/src/lib/assets/schema.ts +++ b/src/lib/assets/schema.ts @@ -44,6 +44,18 @@ export const collisionSchema = z.object({ height: z.number().int().positive(), }); +/** + * A tileset grid the map editor can paint from. + * `names[0]` is tile 1 (the top-left cell), then left to right, then the next row. + */ +export const tilesetSchema = z.object({ + tileWidth: z.number().int().positive(), + tileHeight: z.number().int().positive(), + columns: z.number().int().positive(), + rows: z.number().int().positive(), + names: z.array(nonEmpty).min(1), +}); + export const catalogAssetSchema = z.object({ id: idSchema, version: versionSchema, @@ -54,6 +66,7 @@ export const catalogAssetSchema = z.object({ height: z.number().int().positive().optional(), animation: animationSchema.optional(), collision: collisionSchema.optional(), + tileset: tilesetSchema.optional(), tags: z.array(nonEmpty).min(1), theme: nonEmpty, category: z.enum(ASSET_CATEGORIES), diff --git a/src/lib/assets/sprite-note.ts b/src/lib/assets/sprite-note.ts new file mode 100644 index 0000000..22363f5 --- /dev/null +++ b/src/lib/assets/sprite-note.ts @@ -0,0 +1,20 @@ +import { SPRITE_ANIM_FORMAT, parseSpriteAnim, type SpriteAnimation } from "../pixel/anim"; + +/** + * The animation note that sits next to a copied sprite sheet. + * The image path is the copy inside the project, never a library URL. + * Null when the note would not open in the animation editor. + */ +export function librarySpriteNote(imagePath: string, animation: SpriteAnimation): string | null { + const text = `${JSON.stringify( + { + format: SPRITE_ANIM_FORMAT, + formatVersion: 1, + image: imagePath, + animation, + }, + null, + 2, + )}\n`; + return parseSpriteAnim(text, imagePath).ok ? text : null; +} diff --git a/src/lib/assets/tileset.ts b/src/lib/assets/tileset.ts new file mode 100644 index 0000000..9a786b6 --- /dev/null +++ b/src/lib/assets/tileset.ts @@ -0,0 +1,30 @@ +import { MAX_TILES, isTileSize } from "../map/model"; +import type { CatalogAsset } from "./schema"; + +export type EditorTileset = { + tileWidth: number; + tileHeight: number; + columns: number; + rows: number; + names: string[]; +}; + +/** + * A library tileset the map editor can paint with. + * Null when the grid is missing, the cells are not 8/16/32, or there are too many. + */ +export function editorTileset(asset: CatalogAsset): EditorTileset | null { + const grid = asset.tileset; + if (!grid) return null; + if (grid.tileWidth !== grid.tileHeight || !isTileSize(grid.tileWidth)) return null; + const count = grid.columns * grid.rows; + if (count < 1 || count > MAX_TILES || grid.names.length !== count) return null; + if (asset.width !== grid.columns * grid.tileWidth || asset.height !== grid.rows * grid.tileHeight) return null; + return { + tileWidth: grid.tileWidth, + tileHeight: grid.tileHeight, + columns: grid.columns, + rows: grid.rows, + names: grid.names.slice(), + }; +} diff --git a/src/lib/assets/validate.test.ts b/src/lib/assets/validate.test.ts index 41069e7..a41fe64 100644 --- a/src/lib/assets/validate.test.ts +++ b/src/lib/assets/validate.test.ts @@ -13,9 +13,13 @@ describe("forest adventure pack", () => { const built = await buildForestPack(); const sounds = await buildSoundPack(); const manifest = JSON.parse(readFileSync(join(root, "forest-adventure", "manifest.json"), "utf8")); - const index = JSON.parse(readFileSync(join(root, "index.json"), "utf8")); + const index = JSON.parse(readFileSync(join(root, "index.json"), "utf8")) as { packs: { id: string }[] }; expect(manifest).toEqual(built.manifest); - expect(index).toEqual(catalogIndex([built.manifest, sounds.manifest])); + const forestIndex = catalogIndex([built.manifest, sounds.manifest]); + for (const pack of forestIndex.packs) { + expect(index.packs.find((item) => item.id === pack.id)).toEqual(pack); + } + expect(index.packs.length).toBeGreaterThan(forestIndex.packs.length); for (const asset of built.manifest.assets) { const bytes = readFileSync(join(root, "forest-adventure", asset.path)); expect(Buffer.from(bytes).equals(Buffer.from(built.files[asset.path]))).toBe(true); diff --git a/src/lib/assets/validate.ts b/src/lib/assets/validate.ts index d59935d..8834800 100644 --- a/src/lib/assets/validate.ts +++ b/src/lib/assets/validate.ts @@ -1,4 +1,5 @@ import { inspectAudio } from "../audio/format"; +import { MAX_TILES, isTileSize } from "../map/model"; import { sha256Hex } from "./hash"; import { assetPackSchema, type AssetPack, type CatalogAsset } from "./schema"; @@ -17,6 +18,7 @@ export type PackIssueCode = | "missing-size" | "animation" | "collision" + | "tileset" | "preview" | "tag-language" | "title-language" @@ -63,6 +65,32 @@ function checkAnimation(asset: CatalogAsset, issues: PackIssue[]): void { } } +function checkTileset(asset: CatalogAsset, issues: PackIssue[]): void { + const grid = asset.tileset; + if (asset.category === "tileset" && !grid) { + issues.push({ code: "tileset", path: asset.path, message: `${asset.id} is a tileset and needs a grid.` }); + return; + } + if (!grid) return; + if (!asset.width || !asset.height) { + issues.push({ code: "tileset", path: asset.path, message: `${asset.id} has a tileset grid but no pixel size.` }); + return; + } + if (grid.tileWidth * grid.columns !== asset.width || grid.tileHeight * grid.rows !== asset.height) { + issues.push({ code: "tileset", path: asset.path, message: `${asset.id} tileset grid does not match the image.` }); + } + if (grid.names.length !== grid.columns * grid.rows) { + issues.push({ code: "tileset", path: asset.path, message: `${asset.id} tileset names do not match the cell count.` }); + } + if (!grid.names.every((name) => hasCjk(name))) { + issues.push({ code: "tileset", path: asset.path, message: `${asset.id} tileset names need Chinese.` }); + } + // The map editor paints 8/16/32 cells and at most 32 of them. A shipped tileset has to fit. + if (grid.tileWidth !== grid.tileHeight || !isTileSize(grid.tileWidth) || grid.columns * grid.rows > MAX_TILES) { + issues.push({ code: "tileset", path: asset.path, message: `${asset.id} tileset cannot be used in the map editor.` }); + } +} + function checkCollision(asset: CatalogAsset, issues: PackIssue[]): void { const box = asset.collision; if (!box) return; @@ -134,6 +162,7 @@ export async function validateAssetPack( checkAnimation(asset, issues); checkCollision(asset, issues); + checkTileset(asset, issues); } if (issues.length) return { ok: false, issues }; diff --git a/src/lib/recipes/catalog.ts b/src/lib/recipes/catalog.ts index 272fd7a..eb8514d 100644 --- a/src/lib/recipes/catalog.ts +++ b/src/lib/recipes/catalog.ts @@ -58,7 +58,12 @@ const platform: Recipe = { id: "platform", title: "平台跳跃", summary: "一个小人在地面上跑和跳。", - knowledge: ["角色是一个矩形,每帧加上速度", "重力是往下加一点速度", "往上跳的速度是负数"], + knowledge: [ + "角色是一个矩形,每帧加上速度", + "重力是往下加一点速度", + "往上跳的速度是负数", + "素材库的「平台跳跃」里有小人、草地和跳跃声,可以复制进来", + ], design: { title: "平台跳跃", hero: "一个小探险家", @@ -91,7 +96,12 @@ const maze: Recipe = { id: "maze", title: "迷宫", summary: "一格一格走到金色的终点,有一扇可以打开的门。", - knowledge: ["地图是几行文字,1 是墙", "人一次只走一格", "开关 OPEN_GATE 决定那一格能不能走"], + knowledge: [ + "地图是几行文字,1 是墙", + "人一次只走一格", + "开关 OPEN_GATE 决定那一格能不能走", + "素材库的「迷宫地牢」里有地砖、门和箱子,可以放进地图", + ], design: { title: "迷宫", hero: "一个橙色方块", @@ -107,7 +117,12 @@ const shooter: Recipe = { id: "shooter", title: "卡通射击", summary: "左右移动飞船,向一块会飘的方块发射。没有受伤的画面。", - knowledge: ["飞船的位置每帧跟着按键变", "子弹是一组矩形,往上飞", "两发之间要等 COOLDOWN 帧"], + knowledge: [ + "飞船的位置每帧跟着按键变", + "子弹是一组矩形,往上飞", + "两发之间要等 COOLDOWN 帧", + "素材库的「太空射击」里有飞船、地面图块和激光声,可以复制进来", + ], design: { title: "卡通射击", hero: "一艘小飞船", diff --git a/src/studio/store.tsx b/src/studio/store.tsx index 524d646..594a249 100644 --- a/src/studio/store.tsx +++ b/src/studio/store.tsx @@ -68,7 +68,8 @@ import { } from "../lib/project"; import { parseHex } from "../lib/pixel/buffer"; import { canEditPixels, checkSize, imagePath } from "../lib/pixel/rules"; -import { animationSidecarPath } from "../lib/pixel/anim"; +import { animationSidecarPath, type SpriteAnimation } from "../lib/pixel/anim"; +import { decodePng } from "../lib/pixel/png"; import { planAnimExample, planPixelSave, type AnimExampleInput, type AnimExampleResult, type PixelSaveFailure, type PixelSaveInput } from "../lib/pixel/save"; import { collisionCsvPath, layerCsvPath, mapDocumentPath, slugFromDocumentPath, tilesetPath, type MapFileBlob } from "../lib/map/document"; import { cleanMapName, createMap, isMapSlug } from "../lib/map/model"; @@ -81,6 +82,7 @@ import { readSoundSpec, type SoundSpec } from "../lib/audio/spec"; import { prepareAsset } from "../lib/sprite"; import { createBlankProject, createStarterProject } from "../lib/starter"; import { applyLibraryCopy, type LibraryCopyRequest, type LibraryCopyResult } from "../lib/assets/copy"; +import { librarySpriteNote } from "../lib/assets/sprite-note"; import { deleteStoredProject, loadProjects, saveProject } from "../lib/storage"; import { text } from "../ui/text"; @@ -142,6 +144,11 @@ export type MapNewInput = { rows: number; tileWidth: number; tileHeight: number; + /** A library tileset copied into the editor. The map stores this PNG, not a link. */ + tilesetColumns?: number; + tilesetRows?: number; + tilesetPng?: Uint8Array; + tileNames?: string[]; }; export type MapOpen = ({ source: "new" } & MapNewInput) | { source: "file"; path: string; files: MapFileBlob[] }; @@ -264,6 +271,11 @@ type StudioValue = { */ proposeCatalogAsset: (packId: string, assetId: string) => Promise; copyLibraryAsset: (request: LibraryCopyRequest) => Promise; + /** + * Copies a sprite sheet, writes the animation note beside it, and opens the editor. + * A conflict returns needs-choice and does not open anything. + */ + openLibrarySprite: (copy: LibraryCopyRequest["copy"], animation: SpriteAnimation, choice: LibraryCopyRequest["choice"]) => Promise; pixelSession: PixelSession | null; /** Opens a blank canvas. False when the size or name is not allowed or the name is taken. */ startPixelNew: (input: PixelNewInput) => boolean; @@ -838,6 +850,12 @@ export function StudioProvider({ children }: { children: ReactNode }) { (input: MapNewInput) => { const current = projectRef.current; if (!current || !isMapSlug(input.slug) || !cleanMapName(input.name) || !createMap(input)) return false; + if (input.tilesetPng) { + const decoded = decodePng(input.tilesetPng); + const columns = input.tilesetColumns ?? 0; + const rows = input.tilesetRows ?? 0; + if (!decoded.ok || decoded.pixels.width !== input.tileWidth * columns || decoded.pixels.height !== input.tileHeight * rows) return false; + } const paths = [mapDocumentPath(input.slug), tilesetPath(input.slug), collisionCsvPath(input.slug), layerCsvPath(input.slug, "ground")]; if (paths.some((path) => !path || current.files.some((file) => file.path === path))) return false; openMapEditor({ source: "new", ...input }); @@ -2000,6 +2018,48 @@ export function StudioProvider({ children }: { children: ReactNode }) { setNotice(text.library.message(outcome)); return outcome; }, + openLibrarySprite: async (copy, animation, choice) => { + const current = projectRef.current; + if (!current) { + const missing: LibraryCopyResult = { + ok: false, + changed: false, + path: "", + code: "no-project", + pinsSkipped: false, + exampleSkipped: false, + project: { id: "", name: "", createdAt: 0, updatedAt: 0, files: [] }, + }; + setNotice(text.library.message(missing)); + return missing; + } + const outcome = await applyLibraryCopy(current, copy, choice, "none"); + if (!outcome.ok) { + setNotice(text.library.message(outcome)); + return outcome; + } + const side = animationSidecarPath(outcome.path); + const note = side ? librarySpriteNote(outcome.path, animation) : null; + let next = outcome.project; + let changed = outcome.changed; + if (side && note) { + const existing = next.files.find((file) => file.path === side); + if (existing?.text !== note) { + next = upsertFile(next, { path: side, text: note }); + changed = true; + } + } + if (changed) { + remember(current); + commit(next); + setPath(outcome.path); + } + projectRef.current = next; + setNotice(text.library.message(outcome)); + setLibraryOpen(false); + editPixelFile(outcome.path); + return { ...outcome, changed, project: next }; + }, pixelSession, startPixelNew, editPixelFile, diff --git a/src/ui/LibraryDialog.tsx b/src/ui/LibraryDialog.tsx index b3596d0..f3ac98d 100644 --- a/src/ui/LibraryDialog.tsx +++ b/src/ui/LibraryDialog.tsx @@ -22,7 +22,9 @@ import { text } from "./text"; */ type Row = { pack: AssetPack; asset: CatalogAsset }; -type Pending = { copy: LibraryAssetCopy; plan: LibraryPlan }; +type OpenIntent = "copy" | "sprite"; +type Prepared = { copy: LibraryAssetCopy; plan: LibraryPlan }; +type Pending = Prepared & { intent: OpenIntent }; function snippetOf(asset: CatalogAsset): SnippetAsset { return { @@ -127,10 +129,13 @@ export function LibraryDialog() { if (!open) return null; - const finish = async (copy: LibraryAssetCopy, choice: LibraryChoice, example: LibraryExample) => { + const finish = async (copy: LibraryAssetCopy, choice: LibraryChoice, example: LibraryExample, intent: OpenIntent = "copy") => { setBusy(true); try { - const outcome = await studio.copyLibraryAsset({ copy, choice, example }); + const animation = intent === "sprite" && choice !== "keep" ? selected?.asset.animation : undefined; + const outcome = animation + ? await studio.openLibrarySprite(copy, animation, choice) + : await studio.copyLibraryAsset({ copy, choice, example }); setStatus(text.library.message(outcome)); if (outcome.ok) { setPending(null); @@ -141,7 +146,7 @@ export function LibraryDialog() { } }; - const prepare = async (row: Row): Promise => { + const prepare = async (row: Row): Promise => { const bytes = row.pack.id === KEPT_PACK_ID ? localFiles[row.asset.path] : await loadAssetBytes(row.pack.id, row.asset.path); if (!bytes) throw new Error("Missing sound"); @@ -162,7 +167,7 @@ export function LibraryDialog() { const next = await prepare(selected); if (!next) return; if (next.plan.kind === "conflict" || next.plan.kind === "update") { - setPending(next); + setPending({ ...next, intent: "copy" }); setMainPreview(null); setStatus(""); return; @@ -182,7 +187,7 @@ export function LibraryDialog() { const next = await prepare(selected); if (!next) return; if (next.plan.kind === "conflict" || next.plan.kind === "update") { - setPending(next); + setPending({ ...next, intent: "copy" }); setMainPreview(null); return; } @@ -206,7 +211,7 @@ export function LibraryDialog() { const next = await prepare(selected); if (!next) return; if (next.plan.kind === "conflict" || next.plan.kind === "update") { - setPending(next); + setPending({ ...next, intent: "copy" }); return; } await finish(next.copy, next.plan.kind === "identical" ? "keep" : "add", "file"); @@ -217,6 +222,26 @@ export function LibraryDialog() { } }; + const onOpenSprite = async () => { + if (!selected?.asset.animation) return; + setBusy(true); + try { + const next = await prepare(selected); + if (!next) return; + if (next.plan.kind === "conflict" || next.plan.kind === "update") { + setPending({ ...next, intent: "sprite" }); + setMainPreview(null); + setStatus(""); + return; + } + await finish(next.copy, "add", "none", "sprite"); + } catch { + setError(text.library.failed); + } finally { + setBusy(false); + } + }; + const dest = selected ? libraryDest({ packId: selected.pack.id, assetPath: selected.asset.path }) : ""; const snippet = selected ? pygameSnippet(snippetOf(selected.asset), dest) : ""; const related = selected ? relatedAssets(rows.map((row) => row.asset), selected.asset).slice(0, 8) : []; @@ -409,13 +434,13 @@ export function LibraryDialog() { : text.library.conflictName}

- - -
@@ -469,6 +494,11 @@ export function LibraryDialog() { + {selected.asset.animation ? ( + + ) : null} ))} +
+ + {sheets + .filter((sheet) => sheet.fit.tileWidth === tile) + .map((sheet) => ( + + ))} +
+ {sheetProblem ?

{sheetProblem}

: null}
{preset?.tags.includes("变体") ?

{text.sounds.variant}

: null} + {librarySounds.length ? ( +
+

{text.sounds.library}

+

{text.sounds.libraryHint}

+ {librarySounds.map((sound) => ( + + ))} +
+ ) : null}