diff --git a/packages/site/package.json b/packages/site/package.json index a4a0559..7357a43 100644 --- a/packages/site/package.json +++ b/packages/site/package.json @@ -4,11 +4,15 @@ "version": "0.1.0", "scripts": { "dev": "astro dev", - "build": "astro build", + "gen-skin-data": "node scripts/gen-skin-data.mjs", + "build": "node scripts/gen-skin-data.mjs && astro build", "preview": "astro preview" }, "dependencies": { "@astrojs/sitemap": "^3.7.2", "astro": "^6.1.3" + }, + "devDependencies": { + "tsx": "^4.22.1" } } diff --git a/packages/site/public/data/skins.json b/packages/site/public/data/skins.json new file mode 100644 index 0000000..4a07c94 --- /dev/null +++ b/packages/site/public/data/skins.json @@ -0,0 +1,716 @@ +[ + { + "id": "vita", + "name": "Vita", + "author": "arks", + "description": "像素风小恐龙 Vita", + "style": "pixel", + "states": ["idle", "walk", "run", "sprint"], + "pet": "/skins/vita/pet.png", + "animations": { + "idle": { + "file": "skin.png", + "frameWidth": 24, + "frameHeight": 24, + "frameCount": 4, + "columns": 24, + "fps": 6, + "startFrame": 0, + "sheetRows": 1 + }, + "walk": { + "file": "skin.png", + "frameWidth": 24, + "frameHeight": 24, + "frameCount": 6, + "columns": 24, + "fps": 6, + "startFrame": 5, + "sheetRows": 1 + }, + "run": { + "file": "skin.png", + "frameWidth": 24, + "frameHeight": 24, + "frameCount": 8, + "columns": 24, + "fps": 16, + "startFrame": 6, + "sheetRows": 1 + }, + "sprint": { + "file": "skin.png", + "frameWidth": 24, + "frameHeight": 24, + "frameCount": 6, + "columns": 24, + "fps": 16, + "startFrame": 17, + "sheetRows": 1 + } + } + }, + { + "id": "tard", + "name": "Tard", + "author": "arks", + "description": "像素风小恐龙 Tard", + "style": "pixel", + "states": ["idle", "walk", "run", "sprint"], + "pet": "/skins/tard/pet.png", + "animations": { + "idle": { + "file": "skin.png", + "frameWidth": 24, + "frameHeight": 24, + "frameCount": 4, + "columns": 24, + "fps": 6, + "startFrame": 0, + "sheetRows": 1 + }, + "walk": { + "file": "skin.png", + "frameWidth": 24, + "frameHeight": 24, + "frameCount": 6, + "columns": 24, + "fps": 6, + "startFrame": 5, + "sheetRows": 1 + }, + "run": { + "file": "skin.png", + "frameWidth": 24, + "frameHeight": 24, + "frameCount": 8, + "columns": 24, + "fps": 16, + "startFrame": 6, + "sheetRows": 1 + }, + "sprint": { + "file": "skin.png", + "frameWidth": 24, + "frameHeight": 24, + "frameCount": 6, + "columns": 24, + "fps": 16, + "startFrame": 17, + "sheetRows": 1 + } + } + }, + { + "id": "mort", + "name": "Mort", + "author": "arks", + "description": "像素风小恐龙 Mort", + "style": "pixel", + "states": ["idle", "walk", "run", "sprint"], + "pet": "/skins/mort/pet.png", + "animations": { + "idle": { + "file": "skin.png", + "frameWidth": 24, + "frameHeight": 24, + "frameCount": 4, + "columns": 24, + "fps": 6, + "startFrame": 0, + "sheetRows": 1 + }, + "walk": { + "file": "skin.png", + "frameWidth": 24, + "frameHeight": 24, + "frameCount": 6, + "columns": 24, + "fps": 6, + "startFrame": 5, + "sheetRows": 1 + }, + "run": { + "file": "skin.png", + "frameWidth": 24, + "frameHeight": 24, + "frameCount": 8, + "columns": 24, + "fps": 16, + "startFrame": 6, + "sheetRows": 1 + }, + "sprint": { + "file": "skin.png", + "frameWidth": 24, + "frameHeight": 24, + "frameCount": 6, + "columns": 24, + "fps": 16, + "startFrame": 17, + "sheetRows": 1 + } + } + }, + { + "id": "doux", + "name": "Doux", + "author": "arks", + "description": "像素风小恐龙 Doux", + "style": "pixel", + "states": ["idle", "walk", "run", "sprint"], + "pet": "/skins/doux/pet.png", + "animations": { + "idle": { + "file": "skin.png", + "frameWidth": 24, + "frameHeight": 24, + "frameCount": 4, + "columns": 24, + "fps": 6, + "startFrame": 0, + "sheetRows": 1 + }, + "walk": { + "file": "skin.png", + "frameWidth": 24, + "frameHeight": 24, + "frameCount": 6, + "columns": 24, + "fps": 6, + "startFrame": 5, + "sheetRows": 1 + }, + "run": { + "file": "skin.png", + "frameWidth": 24, + "frameHeight": 24, + "frameCount": 8, + "columns": 24, + "fps": 16, + "startFrame": 6, + "sheetRows": 1 + }, + "sprint": { + "file": "skin.png", + "frameWidth": 24, + "frameHeight": 24, + "frameCount": 6, + "columns": 24, + "fps": 16, + "startFrame": 17, + "sheetRows": 1 + } + } + }, + { + "id": "boy", + "name": "Boy", + "author": "pzuh", + "description": "Boy 角色皮肤", + "style": "pixel", + "states": ["idle", "walk", "run", "sprint"], + "pet": "/skins/boy/pet.png", + "animations": { + "idle": { + "file": "skin.png", + "frameWidth": 64, + "frameHeight": 98, + "frameCount": 10, + "columns": 40, + "fps": 6, + "startFrame": 0, + "sheetRows": 1 + }, + "walk": { + "file": "skin.png", + "frameWidth": 64, + "frameHeight": 98, + "frameCount": 10, + "columns": 40, + "fps": 3, + "startFrame": 20, + "sheetRows": 1 + }, + "run": { + "file": "skin.png", + "frameWidth": 64, + "frameHeight": 98, + "frameCount": 10, + "columns": 40, + "fps": 10, + "startFrame": 20, + "sheetRows": 1 + }, + "sprint": { + "file": "skin.png", + "frameWidth": 64, + "frameHeight": 98, + "frameCount": 10, + "columns": 40, + "fps": 24, + "startFrame": 20, + "sheetRows": 1 + } + } + }, + { + "id": "dinosaur", + "name": "Dinosaur", + "author": "voidcord54", + "description": "像素风小恐龙 Dinosaur", + "style": "pixel", + "states": ["idle", "walk", "run", "sprint"], + "pet": "/skins/dinosaur/pet.png", + "animations": { + "idle": { + "file": "skin.png", + "frameWidth": 128, + "frameHeight": 128, + "frameCount": 2, + "columns": 5, + "fps": 6, + "startFrame": 0, + "sheetRows": 1 + }, + "walk": { + "file": "skin.png", + "frameWidth": 128, + "frameHeight": 128, + "frameCount": 2, + "columns": 5, + "fps": 4, + "startFrame": 2, + "sheetRows": 1 + }, + "run": { + "file": "skin.png", + "frameWidth": 128, + "frameHeight": 128, + "frameCount": 2, + "columns": 5, + "fps": 8, + "startFrame": 2, + "sheetRows": 1 + }, + "sprint": { + "file": "skin.png", + "frameWidth": 128, + "frameHeight": 128, + "frameCount": 2, + "columns": 5, + "fps": 16, + "startFrame": 2, + "sheetRows": 1 + } + } + }, + { + "id": "glube", + "name": "Glube", + "author": "SketchesWithKevin", + "description": "像素风小怪兽 Glube", + "style": "pixel", + "states": ["idle", "walk", "run", "sprint"], + "pet": "/skins/glube/pet.png", + "animations": { + "idle": { + "file": "idle.png", + "frameWidth": 44, + "frameHeight": 31, + "frameCount": 6, + "columns": 6, + "fps": 6, + "startFrame": 0, + "sheetRows": 1 + }, + "walk": { + "file": "walk.png", + "frameWidth": 65, + "frameHeight": 32, + "frameCount": 8, + "columns": 8, + "fps": 6, + "startFrame": 0, + "sheetRows": 1 + }, + "run": { + "file": "run.png", + "frameWidth": 65, + "frameHeight": 32, + "frameCount": 8, + "columns": 8, + "fps": 12, + "startFrame": 0, + "sheetRows": 1 + }, + "sprint": { + "file": "run.png", + "frameWidth": 65, + "frameHeight": 32, + "frameCount": 8, + "columns": 8, + "fps": 24, + "startFrame": 0, + "sheetRows": 1 + } + } + }, + { + "id": "line", + "name": "Line", + "author": "itch.io", + "description": "Line 角色皮肤", + "style": "pixel", + "states": ["idle", "walk", "run", "sprint"], + "pet": "/skins/line/pet.png", + "animations": { + "idle": { + "file": "skin.png", + "frameWidth": 156, + "frameHeight": 185, + "frameCount": 4, + "columns": 28, + "fps": 6, + "startFrame": 0, + "sheetRows": 1 + }, + "walk": { + "file": "skin.png", + "frameWidth": 156, + "frameHeight": 185, + "frameCount": 8, + "columns": 28, + "fps": 6, + "startFrame": 4, + "sheetRows": 1 + }, + "run": { + "file": "skin.png", + "frameWidth": 156, + "frameHeight": 185, + "frameCount": 8, + "columns": 28, + "fps": 10, + "startFrame": 12, + "sheetRows": 1 + }, + "sprint": { + "file": "skin.png", + "frameWidth": 156, + "frameHeight": 185, + "frameCount": 8, + "columns": 28, + "fps": 24, + "startFrame": 12, + "sheetRows": 1 + } + } + }, + { + "id": "buddy", + "name": "Buddy", + "author": "ChatGPT Image", + "description": "卡通风橙色小人皮肤", + "style": "pixel", + "states": ["idle", "walk", "run", "sprint"], + "pet": "/skins/buddy/pet.png", + "animations": { + "idle": { + "file": "skin.png", + "frameWidth": 128, + "frameHeight": 128, + "frameCount": 8, + "columns": 8, + "fps": 6, + "startFrame": 0, + "sheetRows": 4 + }, + "walk": { + "file": "skin.png", + "frameWidth": 128, + "frameHeight": 128, + "frameCount": 8, + "columns": 8, + "fps": 6, + "startFrame": 8, + "sheetRows": 4 + }, + "run": { + "file": "skin.png", + "frameWidth": 128, + "frameHeight": 128, + "frameCount": 8, + "columns": 8, + "fps": 12, + "startFrame": 16, + "sheetRows": 4 + }, + "sprint": { + "file": "skin.png", + "frameWidth": 128, + "frameHeight": 128, + "frameCount": 8, + "columns": 8, + "fps": 20, + "startFrame": 24, + "sheetRows": 4 + } + } + }, + { + "id": "hoodie", + "name": "Hoodie", + "author": "ChatGPT Image", + "description": "红色卫衣少年皮肤", + "style": "pixel", + "states": ["idle", "walk", "run", "sprint"], + "pet": "/skins/hoodie/pet.png", + "animations": { + "idle": { + "file": "idle.png", + "frameWidth": 140, + "frameHeight": 176, + "frameCount": 8, + "columns": 8, + "fps": 6, + "startFrame": 0, + "sheetRows": 1 + }, + "walk": { + "file": "walk.png", + "frameWidth": 140, + "frameHeight": 176, + "frameCount": 8, + "columns": 8, + "fps": 6, + "startFrame": 0, + "sheetRows": 1 + }, + "run": { + "file": "run.png", + "frameWidth": 140, + "frameHeight": 176, + "frameCount": 8, + "columns": 8, + "fps": 12, + "startFrame": 0, + "sheetRows": 1 + }, + "sprint": { + "file": "sprint.png", + "frameWidth": 140, + "frameHeight": 176, + "frameCount": 8, + "columns": 8, + "fps": 20, + "startFrame": 0, + "sheetRows": 1 + } + } + }, + { + "id": "panda", + "name": "Panda", + "author": "AIbubu", + "description": "A cute panda desk-pet skin.", + "style": "ai-generated", + "states": ["idle", "walk", "run", "sprint"], + "pet": "/skins/panda/pet.png", + "animations": { + "idle": { + "file": "idle.png", + "frameWidth": 176, + "frameHeight": 176, + "frameCount": 8, + "columns": 8, + "fps": 6, + "startFrame": 0, + "sheetRows": 1 + }, + "walk": { + "file": "walk.png", + "frameWidth": 176, + "frameHeight": 176, + "frameCount": 8, + "columns": 8, + "fps": 6, + "startFrame": 0, + "sheetRows": 1 + }, + "run": { + "file": "run.png", + "frameWidth": 176, + "frameHeight": 176, + "frameCount": 8, + "columns": 8, + "fps": 12, + "startFrame": 0, + "sheetRows": 1 + }, + "sprint": { + "file": "sprint.png", + "frameWidth": 176, + "frameHeight": 176, + "frameCount": 8, + "columns": 8, + "fps": 20, + "startFrame": 0, + "sheetRows": 1 + } + } + }, + { + "id": "sketch-boy", + "name": "Sketch Boy", + "author": "AIbubu", + "description": "简笔画风格的小男孩皮肤", + "style": "ai-generated", + "states": ["idle", "walk", "run", "sprint"], + "pet": "/skins/sketch-boy/pet.png", + "animations": { + "idle": { + "file": "idle.png", + "frameWidth": 176, + "frameHeight": 176, + "frameCount": 8, + "columns": 8, + "fps": 6, + "startFrame": 0, + "sheetRows": 1 + }, + "walk": { + "file": "walk.png", + "frameWidth": 176, + "frameHeight": 176, + "frameCount": 8, + "columns": 8, + "fps": 6, + "startFrame": 0, + "sheetRows": 1 + }, + "run": { + "file": "run.png", + "frameWidth": 176, + "frameHeight": 176, + "frameCount": 8, + "columns": 8, + "fps": 12, + "startFrame": 0, + "sheetRows": 1 + }, + "sprint": { + "file": "sprint.png", + "frameWidth": 176, + "frameHeight": 176, + "frameCount": 8, + "columns": 8, + "fps": 20, + "startFrame": 0, + "sheetRows": 1 + } + } + }, + { + "id": "cartoon-horse", + "name": "Cartoon Horse", + "author": "AIbubu", + "description": "A cute cartoon horse desk-pet skin.", + "style": "ai-generated", + "states": ["idle", "walk", "run", "sprint"], + "pet": "/skins/cartoon-horse/pet.png", + "animations": { + "idle": { + "file": "idle.png", + "frameWidth": 176, + "frameHeight": 176, + "frameCount": 8, + "columns": 8, + "fps": 6, + "startFrame": 0, + "sheetRows": 1 + }, + "walk": { + "file": "walk.png", + "frameWidth": 176, + "frameHeight": 176, + "frameCount": 8, + "columns": 8, + "fps": 6, + "startFrame": 0, + "sheetRows": 1 + }, + "run": { + "file": "run.png", + "frameWidth": 176, + "frameHeight": 176, + "frameCount": 8, + "columns": 8, + "fps": 12, + "startFrame": 0, + "sheetRows": 1 + }, + "sprint": { + "file": "sprint.png", + "frameWidth": 176, + "frameHeight": 176, + "frameCount": 8, + "columns": 8, + "fps": 20, + "startFrame": 0, + "sheetRows": 1 + } + } + }, + { + "id": "cartoon-pig", + "name": "Cartoon Pig", + "author": "AIbubu", + "description": "A cute cartoon piglet desk-pet skin.", + "style": "ai-generated", + "states": ["idle", "walk", "run", "sprint"], + "pet": "/skins/cartoon-pig/pet.png", + "animations": { + "idle": { + "file": "idle.png", + "frameWidth": 176, + "frameHeight": 176, + "frameCount": 8, + "columns": 8, + "fps": 6, + "startFrame": 0, + "sheetRows": 1 + }, + "walk": { + "file": "walk.png", + "frameWidth": 176, + "frameHeight": 176, + "frameCount": 8, + "columns": 8, + "fps": 6, + "startFrame": 0, + "sheetRows": 1 + }, + "run": { + "file": "run.png", + "frameWidth": 176, + "frameHeight": 176, + "frameCount": 8, + "columns": 8, + "fps": 12, + "startFrame": 0, + "sheetRows": 1 + }, + "sprint": { + "file": "sprint.png", + "frameWidth": 176, + "frameHeight": 176, + "frameCount": 8, + "columns": 8, + "fps": 20, + "startFrame": 0, + "sheetRows": 1 + } + } + } +] diff --git a/packages/site/public/skins/boy/pet.png b/packages/site/public/skins/boy/pet.png new file mode 100644 index 0000000..506622d Binary files /dev/null and b/packages/site/public/skins/boy/pet.png differ diff --git a/packages/site/public/skins/boy/skin.png b/packages/site/public/skins/boy/skin.png new file mode 100644 index 0000000..02413f3 Binary files /dev/null and b/packages/site/public/skins/boy/skin.png differ diff --git a/packages/site/public/skins/buddy/pet.png b/packages/site/public/skins/buddy/pet.png new file mode 100644 index 0000000..c10924c Binary files /dev/null and b/packages/site/public/skins/buddy/pet.png differ diff --git a/packages/site/public/skins/buddy/skin.png b/packages/site/public/skins/buddy/skin.png new file mode 100644 index 0000000..38426d8 Binary files /dev/null and b/packages/site/public/skins/buddy/skin.png differ diff --git a/packages/site/public/skins/cartoon-horse/idle.png b/packages/site/public/skins/cartoon-horse/idle.png new file mode 100644 index 0000000..bb8ec6a Binary files /dev/null and b/packages/site/public/skins/cartoon-horse/idle.png differ diff --git a/packages/site/public/skins/cartoon-horse/pet.png b/packages/site/public/skins/cartoon-horse/pet.png new file mode 100644 index 0000000..aefe510 Binary files /dev/null and b/packages/site/public/skins/cartoon-horse/pet.png differ diff --git a/packages/site/public/skins/cartoon-horse/run.png b/packages/site/public/skins/cartoon-horse/run.png new file mode 100644 index 0000000..685da88 Binary files /dev/null and b/packages/site/public/skins/cartoon-horse/run.png differ diff --git a/packages/site/public/skins/cartoon-horse/sprint.png b/packages/site/public/skins/cartoon-horse/sprint.png new file mode 100644 index 0000000..dd600ea Binary files /dev/null and b/packages/site/public/skins/cartoon-horse/sprint.png differ diff --git a/packages/site/public/skins/cartoon-horse/walk.png b/packages/site/public/skins/cartoon-horse/walk.png new file mode 100644 index 0000000..5c5a554 Binary files /dev/null and b/packages/site/public/skins/cartoon-horse/walk.png differ diff --git a/packages/site/public/skins/cartoon-pig/idle.png b/packages/site/public/skins/cartoon-pig/idle.png new file mode 100644 index 0000000..d33b642 Binary files /dev/null and b/packages/site/public/skins/cartoon-pig/idle.png differ diff --git a/packages/site/public/skins/cartoon-pig/pet.png b/packages/site/public/skins/cartoon-pig/pet.png new file mode 100644 index 0000000..cf88435 Binary files /dev/null and b/packages/site/public/skins/cartoon-pig/pet.png differ diff --git a/packages/site/public/skins/cartoon-pig/run.png b/packages/site/public/skins/cartoon-pig/run.png new file mode 100644 index 0000000..40b1d1e Binary files /dev/null and b/packages/site/public/skins/cartoon-pig/run.png differ diff --git a/packages/site/public/skins/cartoon-pig/sprint.png b/packages/site/public/skins/cartoon-pig/sprint.png new file mode 100644 index 0000000..741123e Binary files /dev/null and b/packages/site/public/skins/cartoon-pig/sprint.png differ diff --git a/packages/site/public/skins/cartoon-pig/walk.png b/packages/site/public/skins/cartoon-pig/walk.png new file mode 100644 index 0000000..21f8bfc Binary files /dev/null and b/packages/site/public/skins/cartoon-pig/walk.png differ diff --git a/packages/site/public/skins/dinosaur/pet.png b/packages/site/public/skins/dinosaur/pet.png new file mode 100644 index 0000000..ee2f5b0 Binary files /dev/null and b/packages/site/public/skins/dinosaur/pet.png differ diff --git a/packages/site/public/skins/dinosaur/skin.png b/packages/site/public/skins/dinosaur/skin.png new file mode 100644 index 0000000..60a596a Binary files /dev/null and b/packages/site/public/skins/dinosaur/skin.png differ diff --git a/packages/site/public/skins/doux/pet.png b/packages/site/public/skins/doux/pet.png new file mode 100644 index 0000000..b4b17cc Binary files /dev/null and b/packages/site/public/skins/doux/pet.png differ diff --git a/packages/site/public/skins/doux/skin.png b/packages/site/public/skins/doux/skin.png new file mode 100644 index 0000000..8fb8734 Binary files /dev/null and b/packages/site/public/skins/doux/skin.png differ diff --git a/packages/site/public/skins/glube/idle.png b/packages/site/public/skins/glube/idle.png new file mode 100644 index 0000000..b2905cb Binary files /dev/null and b/packages/site/public/skins/glube/idle.png differ diff --git a/packages/site/public/skins/glube/pet.png b/packages/site/public/skins/glube/pet.png new file mode 100644 index 0000000..28fe801 Binary files /dev/null and b/packages/site/public/skins/glube/pet.png differ diff --git a/packages/site/public/skins/glube/run.png b/packages/site/public/skins/glube/run.png new file mode 100644 index 0000000..636ab8d Binary files /dev/null and b/packages/site/public/skins/glube/run.png differ diff --git a/packages/site/public/skins/glube/walk.png b/packages/site/public/skins/glube/walk.png new file mode 100644 index 0000000..636ab8d Binary files /dev/null and b/packages/site/public/skins/glube/walk.png differ diff --git a/packages/site/public/skins/hoodie/idle.png b/packages/site/public/skins/hoodie/idle.png new file mode 100644 index 0000000..aecc6fe Binary files /dev/null and b/packages/site/public/skins/hoodie/idle.png differ diff --git a/packages/site/public/skins/hoodie/pet.png b/packages/site/public/skins/hoodie/pet.png new file mode 100644 index 0000000..5fe87ff Binary files /dev/null and b/packages/site/public/skins/hoodie/pet.png differ diff --git a/packages/site/public/skins/hoodie/run.png b/packages/site/public/skins/hoodie/run.png new file mode 100644 index 0000000..9aa11a6 Binary files /dev/null and b/packages/site/public/skins/hoodie/run.png differ diff --git a/packages/site/public/skins/hoodie/sprint.png b/packages/site/public/skins/hoodie/sprint.png new file mode 100644 index 0000000..c6df2c4 Binary files /dev/null and b/packages/site/public/skins/hoodie/sprint.png differ diff --git a/packages/site/public/skins/hoodie/walk.png b/packages/site/public/skins/hoodie/walk.png new file mode 100644 index 0000000..30fdfd0 Binary files /dev/null and b/packages/site/public/skins/hoodie/walk.png differ diff --git a/packages/site/public/skins/line/pet.png b/packages/site/public/skins/line/pet.png new file mode 100644 index 0000000..4421167 Binary files /dev/null and b/packages/site/public/skins/line/pet.png differ diff --git a/packages/site/public/skins/line/skin.png b/packages/site/public/skins/line/skin.png new file mode 100644 index 0000000..41b102e Binary files /dev/null and b/packages/site/public/skins/line/skin.png differ diff --git a/packages/site/public/skins/mort/pet.png b/packages/site/public/skins/mort/pet.png new file mode 100644 index 0000000..1b4dcbe Binary files /dev/null and b/packages/site/public/skins/mort/pet.png differ diff --git a/packages/site/public/skins/mort/skin.png b/packages/site/public/skins/mort/skin.png new file mode 100644 index 0000000..9089923 Binary files /dev/null and b/packages/site/public/skins/mort/skin.png differ diff --git a/packages/site/public/skins/panda/idle.png b/packages/site/public/skins/panda/idle.png new file mode 100644 index 0000000..d612aaa Binary files /dev/null and b/packages/site/public/skins/panda/idle.png differ diff --git a/packages/site/public/skins/panda/pet.png b/packages/site/public/skins/panda/pet.png new file mode 100644 index 0000000..44f229d Binary files /dev/null and b/packages/site/public/skins/panda/pet.png differ diff --git a/packages/site/public/skins/panda/run.png b/packages/site/public/skins/panda/run.png new file mode 100644 index 0000000..ec3ae3d Binary files /dev/null and b/packages/site/public/skins/panda/run.png differ diff --git a/packages/site/public/skins/panda/sprint.png b/packages/site/public/skins/panda/sprint.png new file mode 100644 index 0000000..65e70f8 Binary files /dev/null and b/packages/site/public/skins/panda/sprint.png differ diff --git a/packages/site/public/skins/panda/walk.png b/packages/site/public/skins/panda/walk.png new file mode 100644 index 0000000..6679cf1 Binary files /dev/null and b/packages/site/public/skins/panda/walk.png differ diff --git a/packages/site/public/skins/sketch-boy/idle.png b/packages/site/public/skins/sketch-boy/idle.png new file mode 100644 index 0000000..b3f6063 Binary files /dev/null and b/packages/site/public/skins/sketch-boy/idle.png differ diff --git a/packages/site/public/skins/sketch-boy/pet.png b/packages/site/public/skins/sketch-boy/pet.png new file mode 100644 index 0000000..4245be9 Binary files /dev/null and b/packages/site/public/skins/sketch-boy/pet.png differ diff --git a/packages/site/public/skins/sketch-boy/run.png b/packages/site/public/skins/sketch-boy/run.png new file mode 100644 index 0000000..f821f3c Binary files /dev/null and b/packages/site/public/skins/sketch-boy/run.png differ diff --git a/packages/site/public/skins/sketch-boy/sprint.png b/packages/site/public/skins/sketch-boy/sprint.png new file mode 100644 index 0000000..69aaf84 Binary files /dev/null and b/packages/site/public/skins/sketch-boy/sprint.png differ diff --git a/packages/site/public/skins/sketch-boy/walk.png b/packages/site/public/skins/sketch-boy/walk.png new file mode 100644 index 0000000..83088aa Binary files /dev/null and b/packages/site/public/skins/sketch-boy/walk.png differ diff --git a/packages/site/public/skins/tard/pet.png b/packages/site/public/skins/tard/pet.png new file mode 100644 index 0000000..12c9aec Binary files /dev/null and b/packages/site/public/skins/tard/pet.png differ diff --git a/packages/site/public/skins/tard/skin.png b/packages/site/public/skins/tard/skin.png new file mode 100644 index 0000000..c99f59e Binary files /dev/null and b/packages/site/public/skins/tard/skin.png differ diff --git a/packages/site/public/skins/vita/pet.png b/packages/site/public/skins/vita/pet.png new file mode 100644 index 0000000..005dff5 Binary files /dev/null and b/packages/site/public/skins/vita/pet.png differ diff --git a/packages/site/public/skins/vita/skin.png b/packages/site/public/skins/vita/skin.png new file mode 100644 index 0000000..1ee6744 Binary files /dev/null and b/packages/site/public/skins/vita/skin.png differ diff --git a/packages/site/scripts/gen-skin-data.mjs b/packages/site/scripts/gen-skin-data.mjs new file mode 100644 index 0000000..bb5eccb --- /dev/null +++ b/packages/site/scripts/gen-skin-data.mjs @@ -0,0 +1,114 @@ +/** + * Scan skin directories from packages/app/public/skins/, + * generate a consolidated skins.json for the site gallery, + * and copy pet.png + sprite sheet assets into site/public/skins/{id}/. + * + * Run: node scripts/gen-skin-data.mjs + */ +import { readFileSync, readdirSync, mkdirSync, copyFileSync, writeFileSync, existsSync } from 'fs' +import { join, resolve, dirname } from 'path' +import { fileURLToPath } from 'url' + +const __dirname = dirname(fileURLToPath(import.meta.url)) +const SITE_ROOT = resolve(__dirname, '..') +const APP_SKINS_DIR = resolve(SITE_ROOT, '../app/public/skins') +const OUT_DIR = resolve(SITE_ROOT, 'public/data') +const SKINS_ASSET_DIR = resolve(SITE_ROOT, 'public/skins') + +const VALID_STATES = ['idle', 'walk', 'run', 'sprint'] + +let order = [] +try { + order = JSON.parse(readFileSync(join(APP_SKINS_DIR, 'order.json'), 'utf-8')) +} catch { + // fallback: no ordering +} + +const dirs = readdirSync(APP_SKINS_DIR, { withFileTypes: true }) + .filter((d) => d.isDirectory()) + .map((d) => d.name) + +const skins = [] + +for (const id of dirs) { + const skinJsonPath = join(APP_SKINS_DIR, id, 'skin.json') + const petPngPath = join(APP_SKINS_DIR, id, 'pet.png') + + if (!existsSync(skinJsonPath) || !existsSync(petPngPath)) continue + + try { + const manifest = JSON.parse(readFileSync(skinJsonPath, 'utf-8')) + const rawAnims = manifest.animations ?? {} + const states = Object.keys(rawAnims).filter((s) => VALID_STATES.includes(s)) + + const animations = {} + const spriteFiles = new Set() + const fileMaxFrame = {} + + for (const state of states) { + const anim = rawAnims[state] + const sprite = anim?.sprite + if (!sprite) continue + + const startFrame = sprite.startFrame ?? 0 + const endFrame = startFrame + sprite.frameCount + + animations[state] = { + file: anim.file, + frameWidth: sprite.frameWidth, + frameHeight: sprite.frameHeight, + frameCount: sprite.frameCount, + columns: sprite.columns, + fps: sprite.fps, + startFrame, + } + spriteFiles.add(anim.file) + fileMaxFrame[anim.file] = Math.max(fileMaxFrame[anim.file] || 0, endFrame) + } + + for (const state of Object.keys(animations)) { + const a = animations[state] + const maxFrame = fileMaxFrame[a.file] || a.startFrame + a.frameCount + a.sheetRows = Math.ceil(maxFrame / a.columns) + } + + skins.push({ + id, + name: manifest.name ?? id, + author: manifest.author ?? 'Unknown', + description: manifest.description, + style: manifest.style, + states, + pet: `/skins/${id}/pet.png`, + animations, + }) + + const destDir = join(SKINS_ASSET_DIR, id) + mkdirSync(destDir, { recursive: true }) + copyFileSync(petPngPath, join(destDir, 'pet.png')) + + for (const file of spriteFiles) { + const srcPath = join(APP_SKINS_DIR, id, file) + if (existsSync(srcPath)) { + copyFileSync(srcPath, join(destDir, file)) + } + } + } catch (e) { + console.warn(`Skipping skin "${id}": ${e.message}`) + } +} + +// Sort: order.json first, then alphabetically +skins.sort((a, b) => { + const ai = order.indexOf(a.id) + const bi = order.indexOf(b.id) + if (ai !== -1 && bi !== -1) return ai - bi + if (ai !== -1) return -1 + if (bi !== -1) return 1 + return a.id.localeCompare(b.id) +}) + +mkdirSync(OUT_DIR, { recursive: true }) +writeFileSync(join(OUT_DIR, 'skins.json'), JSON.stringify(skins, null, 2)) + +console.log(`Generated skins.json with ${skins.length} skins → ${join(OUT_DIR, 'skins.json')}`) diff --git a/packages/site/src/components/Nav.astro b/packages/site/src/components/Nav.astro new file mode 100644 index 0000000..935a38f --- /dev/null +++ b/packages/site/src/components/Nav.astro @@ -0,0 +1,187 @@ +--- +import { t, localePath, getLocale } from '../i18n' + +interface Props { + variant?: 'main' | 'sub' +} + +const { variant = 'main' } = Astro.props +const locale = getLocale(Astro.url) +const i18n = t(locale) +const GITHUB_REPO = 'https://github.com/funAgent/ai-bubu' +const isMain = variant === 'main' +--- + +{ + isMain ? ( + + ) : ( + + ) +} + + diff --git a/packages/site/src/i18n/en.ts b/packages/site/src/i18n/en.ts index 61d0c85..7c18cb8 100644 --- a/packages/site/src/i18n/en.ts +++ b/packages/site/src/i18n/en.ts @@ -6,6 +6,7 @@ export default { }, nav: { brand: 'AIbubu', + market: 'Pet Market', switchLang: '中', backHome: 'Back to Home', }, @@ -82,6 +83,24 @@ export default { chars: { title: 'Pick your companion', note: 'Custom skins supported · More on the way', + browseAll: 'Browse all characters →', + }, + market: { + pageTitle: 'Pet Market — AIbubu', + description: 'Browse all AIbubu character skins and pick your desktop companion.', + title: 'Pet Market', + subtitle: '{count} characters, more on the way', + filterAll: 'All', + filterPixel: 'Pixel Art', + filterAI: 'AI Generated', + searchPlaceholder: 'Search characters...', + stateIdle: 'Idle', + stateWalk: 'Walk', + stateRun: 'Run', + stateSprint: 'Sprint', + author: 'by', + cta: 'Download AIbubu to use more characters', + ctaBtn: 'Download Now', }, footer: { credits: 'Pixel art by', diff --git a/packages/site/src/i18n/zh.ts b/packages/site/src/i18n/zh.ts index 3c7e0db..4b5e17e 100644 --- a/packages/site/src/i18n/zh.ts +++ b/packages/site/src/i18n/zh.ts @@ -6,6 +6,7 @@ export default { }, nav: { brand: 'AI 步步', + market: '宠物市场', switchLang: 'EN', backHome: '返回首页', }, @@ -70,6 +71,24 @@ export default { chars: { title: '挑选你的伙伴', note: '支持自定义角色 · 更多角色持续更新中', + browseAll: '浏览全部角色 →', + }, + market: { + pageTitle: '宠物市场 — AI 步步', + description: '浏览 AI 步步的所有角色皮肤,挑选你的桌面伙伴。', + title: '宠物市场', + subtitle: '{count} 款角色,更多持续更新中', + filterAll: '全部', + filterPixel: '像素风', + filterAI: 'AI 生成', + searchPlaceholder: '搜索角色...', + stateIdle: '待机', + stateWalk: '走路', + stateRun: '跑步', + stateSprint: '冲刺', + author: '作者', + cta: '下载 AI 步步,使用更多角色', + ctaBtn: '立即下载', }, footer: { credits: '像素角色来自', diff --git a/packages/site/src/pages/[locale]/download.astro b/packages/site/src/pages/[locale]/download.astro index fe63a43..ddff775 100644 --- a/packages/site/src/pages/[locale]/download.astro +++ b/packages/site/src/pages/[locale]/download.astro @@ -1,6 +1,7 @@ --- import Base from '../../layouts/Base.astro' -import { t, localePath, type Locale } from '../../i18n' +import Nav from '../../components/Nav.astro' +import { t, type Locale } from '../../i18n' export function getStaticPaths() { return [{ params: { locale: 'zh' } }, { params: { locale: 'en' } }] @@ -75,28 +76,7 @@ const platforms = [ --- - +