-- gen_npcs.lua — named NPC sprites (each 48x24: 3 frames = smile / flat / off) -- plus npc_bird.png (32x24: 2 frames = beak closed / open) local ROOT = "/Users/leidianyayi/Documents/GitHub/ModelTest20260714/Kimi-K3/" local H = dofile(ROOT .. "tools/aseprite/helpers.lua") -- ---- shared expression core ------------------------------------------------ -- eyes at (lx,ly)/(rx,ry); mouth baseline my. ex in {"smile","flat","off"}. -- "off" = smile mouth but the right eye sits 1px lower (a 1-2px difference). local function expr(t, ex, lx, ly, rx, ry, my, eyeCol, mouthCol) eyeCol = eyeCol or "ink"; mouthCol = mouthCol or "brown_d" if ex == "off" then ry = ry + 1 end t.pn(lx, ly, eyeCol); t.pn(rx, ry, eyeCol) if ex == "flat" then t.hln(lx + 1, my, rx - lx - 1, mouthCol) else t.pn(lx + 1, my, mouthCol); t.pn(lx + 2, my + 1, mouthCol) t.pn(rx - 2, my + 1, mouthCol); t.pn(rx - 1, my, mouthCol) end end local function arms(t, c) t.rectn(2, 12, 2, 5, c); t.rectn(12, 12, 2, 5, c) end local function feet(t, c) t.rectn(5, 20, 2, 3, c); t.rectn(9, 20, 2, 3, c) end -- ---- species bodies (face forward, 16x24 local) --------------------------- local function afu(t, ex) -- 狗村长 dog village head t.rectn(1, 3, 3, 6, "brown_d"); t.rectn(12, 3, 3, 6, "brown_d") -- floppy ears t.rectn(1, 3, 3, 2, "brown"); t.rectn(12, 3, 3, 2, "brown") t.rectn(3, 3, 10, 9, "brown"); t.rectn(3, 3, 10, 1, "brown_l") t.rectn(6, 8, 4, 4, "cream"); t.pn(7, 8, "ink") -- muzzle + nose t.rectn(4, 12, 8, 7, "brown"); t.rectn(4, 12, 8, 3, "honey") -- vest t.pn(7, 13, "honey_d"); t.pn(8, 13, "honey_d") arms(t, "brown"); feet(t, "brown_d") expr(t, ex, 5, 6, 10, 6, 10) end local function yuanyuan(t, ex) -- 兔面包师 rabbit baker t.rectn(4, 0, 2, 5, "cream"); t.rectn(10, 0, 2, 5, "cream") -- long ears t.rectn(5, 1, 1, 3, "pink"); t.rectn(10, 1, 1, 3, "pink") -- inner ear t.rectn(3, 4, 10, 8, "cream"); t.rectn(3, 4, 10, 1, "white") t.pn(7, 9, "pink_d") -- bunny nose t.rectn(4, 12, 8, 7, "pink") -- dress t.rectn(4, 12, 8, 5, "white") -- apron t.rectn(4, 12, 8, 1, "cream_d") t.pn(6, 14, "cream_d"); t.pn(9, 14, "cream_d") arms(t, "cream"); feet(t, "cream_d") expr(t, ex, 5, 7, 10, 7, 10) end local function dabao(t, ex) -- 熊邮差 bear postman t.discn(4, 3, 2, "brown"); t.discn(11, 3, 2, "brown") -- round ears t.discn(4, 3, 1, "brown_d"); t.discn(11, 3, 1, "brown_d") t.rectn(2, 3, 12, 9, "brown"); t.rectn(2, 3, 12, 1, "brown_l") -- big head t.rectn(6, 8, 4, 4, "cream"); t.pn(7, 8, "ink") t.rectn(3, 12, 10, 7, "brown") -- big body t.pn(4, 12, "brown_d"); t.pn(5, 13, "brown_d"); t.pn(6, 14, "brown_d") t.pn(7, 15, "brown_d"); t.pn(8, 16, "brown_d") -- satchel strap t.rectn(9, 15, 4, 4, "yellow_d"); t.framen(9, 15, 4, 4, "brown_d"); t.rectn(9, 15, 4, 1, "yellow") t.rectn(1, 12, 2, 5, "brown"); t.rectn(13, 12, 2, 5, "brown") -- arms (wider) feet(t, "brown_d") expr(t, ex, 5, 6, 10, 6, 10) end local function mimi(t, ex) -- 猫店主 cat shopkeeper t.rectn(3, 2, 2, 3, "honey"); t.rectn(11, 2, 2, 3, "honey") -- pointy ears t.pn(3, 2, "honey_d"); t.pn(12, 2, "honey_d") t.pn(3, 3, "pink"); t.pn(12, 3, "pink") t.rectn(3, 4, 10, 8, "honey"); t.rectn(3, 4, 10, 1, "honey_l") t.pn(4, 4, "honey_d"); t.pn(7, 4, "honey_d"); t.pn(10, 4, "honey_d") -- stripes t.pn(7, 9, "pink_d") -- nose t.rectn(4, 12, 8, 7, "cream") t.rectn(4, 12, 8, 4, "sky"); t.rectn(4, 12, 8, 1, "sky_d") -- apron arms(t, "honey"); feet(t, "honey_d") t.pn(1, 8, "honey_d"); t.pn(14, 8, "honey_d") -- whiskers expr(t, ex, 5, 7, 10, 7, 10) end local function fuyisheng(t, ex) -- 鹿医生 deer doctor t.vln(4, 0, 3, "brown_d"); t.pn(3, 1, "brown_d"); t.pn(5, 1, "brown_d") -- antlers t.vln(11, 0, 3, "brown_d"); t.pn(10, 1, "brown_d"); t.pn(12, 1, "brown_d") t.rectn(2, 4, 2, 3, "cream_d"); t.rectn(12, 4, 2, 3, "cream_d") -- ears t.rectn(3, 3, 10, 9, "cream_d"); t.rectn(3, 3, 10, 1, "skin") t.rectn(6, 8, 4, 4, "cream"); t.pn(7, 8, "ink") -- muzzle t.rectn(3, 12, 10, 7, "white"); t.framen(3, 12, 10, 7, "w_lo") -- white coat t.vln(8, 12, 7, "w_lo") t.rectn(5, 12, 6, 2, "skin") t.pn(11, 14, "red"); t.pn(11, 15, "red") -- red cross hint arms(t, "white"); feet(t, "brown_d") expr(t, ex, 5, 6, 10, 6, 10) end local function guiyeye(t, ex) -- 龟老者 turtle elder t.rectn(6, 4, 6, 5, "leaf_l"); t.rectn(6, 4, 6, 1, "cream") -- head t.rectn(6, 8, 6, 2, "white") -- beard t.discn(8, 14, 6, "leaf_d") -- shell t.discn(8, 13, 5, "leaf") t.discn(6, 12, 2, "leaf_l") t.pn(8, 12, "leaf_dd"); t.pn(6, 14, "leaf_dd"); t.pn(10, 14, "leaf_dd"); t.pn(8, 16, "leaf_dd") t.rectn(4, 20, 3, 3, "leaf_d"); t.rectn(9, 20, 3, 3, "leaf_d") -- feet t.vln(13, 12, 9, "brown_d"); t.pn(13, 11, "brown") -- cane expr(t, ex, 7, 6, 10, 6, 8, "ink", "brown_d") end -- ---- build the 6 three-frame NPC sprites ---------------------------------- local npcs = { { "afu", afu }, { "yuanyuan", yuanyuan }, { "dabao", dabao }, { "mimi", mimi }, { "fuyisheng", fuyisheng }, { "guiyeye", guiyeye }, } for _, n in ipairs(npcs) do local spr, img = H.new(48, 24) for i, ex in ipairs({ "smile", "flat", "off" }) do n[2](H.at(img, (i - 1) * 16, 0), ex) end spr:saveAs(ROOT .. "public/assets/sprites/npc_" .. n[1] .. ".png") print("npc_" .. n[1] .. ".png done") end -- ---- twin birds (32x24, 2 frames = beak closed / open) --------------------- local function bird(t, open) t.rectn(0, 18, 16, 2, "brown_d") -- branch -- bird A (faces right) t.discn(4, 11, 4, "blue"); t.discn(4, 8, 3, "blue") t.discn(3, 10, 2, "blue_l") t.discn(5, 11, 2, "blue_d") -- wing t.pn(1, 12, "blue_d"); t.pn(0, 13, "blue_d") -- tail t.pn(3, 7, "ink") -- eye if open then t.pn(6, 8, "yellow"); t.pn(6, 9, "yellow_d") else t.pn(6, 8, "yellow") end t.vln(3, 15, 3, "honey_d"); t.vln(5, 15, 3, "honey_d") -- bird B (faces left), slightly lower t.discn(11, 13, 4, "blue"); t.discn(11, 10, 3, "blue") t.discn(12, 12, 2, "blue_l") t.discn(10, 13, 2, "blue_d") t.pn(14, 14, "blue_d"); t.pn(15, 15, "blue_d") t.pn(12, 9, "ink") if open then t.pn(9, 10, "yellow"); t.pn(9, 11, "yellow_d") else t.pn(9, 10, "yellow") end t.vln(10, 16, 2, "honey_d"); t.vln(12, 16, 2, "honey_d") end local bspr, bimg = H.new(32, 24) bird(H.at(bimg, 0, 0), false) bird(H.at(bimg, 16, 0), true) bspr:saveAs(ROOT .. "public/assets/sprites/npc_bird.png") print("npc_bird.png done")