-- gen_portraits.lua — dialogue portraits (each 32x32) -- player_smile / player_real + afu yuanyuan dabao mimi fuyisheng guiyeye bird (all smile) local ROOT = "/Users/leidianyayi/Documents/GitHub/ModelTest20260714/Kimi-K3/" local H = dofile(ROOT .. "tools/aseprite/helpers.lua") local function smileArc(t, cx, y, w, c) local half = math.floor(w / 2) t.pn(cx - half, y, c); t.pn(cx + half, y, c) t.pn(cx - half + 1, y + 1, c); t.pn(cx + half - 1, y + 1, c) for i = -half + 2, half - 2 do t.pn(cx + i, y + 2, c) end end local function eyes(t, lx, rx, y, c) t.rectn(lx, y, 3, 4, c); t.rectn(rx, y, 3, 4, c) end -- ---- player --------------------------------------------------------------- local function playerSmile(t) t.rectn(6, 2, 20, 6, "hair"); t.rectn(6, 2, 20, 2, "hair_l") t.rectn(4, 4, 4, 14, "hair"); t.rectn(24, 4, 4, 14, "hair") t.rectn(6, 7, 20, 18, "skin") eyes(t, 9, 20, 13, "ink") t.pn(8, 18, "pink"); t.pn(9, 18, "pink"); t.pn(23, 18, "pink"); t.pn(24, 18, "pink") smileArc(t, 16, 20, 8, "brown_d") t.rectn(12, 25, 8, 4, "honey"); t.rectn(12, 25, 8, 1, "honey_l") end -- E3 "real face": the smile is gone — a plain, tired, honest face. local function playerReal(t) t.rectn(6, 2, 20, 6, "hair"); t.rectn(6, 2, 20, 2, "hair_l") t.rectn(4, 4, 4, 14, "hair"); t.rectn(24, 4, 4, 14, "hair") t.rectn(6, 7, 20, 18, "skin") t.rectn(9, 15, 3, 2, "ink"); t.rectn(20, 15, 3, 2, "ink") -- half-closed eyes t.rectn(9, 14, 3, 1, "skin_d"); t.rectn(20, 14, 3, 1, "skin_d") -- heavy lids t.pn(9, 18, "skin_d"); t.pn(10, 18, "skin_d") -- bags t.pn(21, 18, "skin_d"); t.pn(22, 18, "skin_d") t.pn(10, 19, "cream_d"); t.pn(21, 19, "cream_d") t.pn(9, 12, "hair_d"); t.pn(10, 12, "hair_d"); t.pn(11, 13, "hair_d") -- weary brows t.pn(22, 12, "hair_d"); t.pn(21, 12, "hair_d"); t.pn(20, 13, "hair_d") t.hln(13, 21, 6, "brown_d") -- flat mouth t.rectn(12, 25, 8, 4, "honey"); t.rectn(12, 25, 8, 1, "honey_d") end -- ---- NPC smile portraits --------------------------------------------------- local function afuP(t) t.rectn(2, 6, 6, 15, "brown_d"); t.rectn(24, 6, 6, 15, "brown_d") t.rectn(2, 6, 6, 5, "brown"); t.rectn(24, 6, 6, 5, "brown") t.rectn(6, 4, 20, 23, "brown"); t.rectn(6, 4, 20, 3, "brown_l") eyes(t, 9, 20, 11, "ink") t.rectn(11, 16, 10, 8, "cream"); t.rectn(14, 16, 4, 3, "ink") smileArc(t, 16, 20, 7, "brown_d") t.rectn(12, 27, 8, 3, "honey") end local function yuanyuanP(t) t.rectn(8, 0, 4, 9, "cream"); t.rectn(20, 0, 4, 9, "cream") t.rectn(9, 1, 2, 7, "pink"); t.rectn(21, 1, 2, 7, "pink") t.rectn(6, 8, 20, 19, "cream"); t.rectn(6, 8, 20, 2, "white") eyes(t, 10, 20, 14, "ink") t.pn(15, 18, "pink_d"); t.pn(16, 18, "pink_d") smileArc(t, 16, 20, 6, "brown_d") t.rectn(12, 27, 8, 3, "pink") end local function dabaoP(t) t.discn(7, 6, 4, "brown"); t.discn(25, 6, 4, "brown") t.discn(7, 6, 2, "brown_d"); t.discn(25, 6, 2, "brown_d") t.rectn(4, 4, 24, 23, "brown"); t.rectn(4, 4, 24, 3, "brown_l") eyes(t, 9, 21, 11, "ink") t.rectn(11, 16, 10, 8, "cream"); t.rectn(14, 16, 4, 3, "ink") smileArc(t, 16, 20, 7, "brown_d") t.rectn(11, 27, 10, 3, "yellow_d") end local function mimiP(t) t.pn(7, 2, "honey"); t.rectn(6, 3, 4, 6, "honey") -- left ear t.pn(24, 2, "honey"); t.rectn(22, 3, 4, 6, "honey") -- right ear t.rectn(7, 4, 2, 4, "pink"); t.rectn(23, 4, 2, 4, "pink") -- inner t.rectn(6, 8, 20, 19, "honey"); t.rectn(6, 8, 20, 2, "honey_l") t.pn(9, 8, "honey_d"); t.pn(13, 8, "honey_d"); t.pn(17, 8, "honey_d"); t.pn(21, 8, "honey_d") eyes(t, 10, 20, 14, "ink") t.pn(15, 18, "pink_d"); t.pn(16, 18, "pink_d") smileArc(t, 16, 20, 6, "brown_d") t.hln(3, 17, 3, "honey_d"); t.hln(3, 19, 3, "honey_d") t.hln(26, 17, 3, "honey_d"); t.hln(26, 19, 3, "honey_d") t.rectn(12, 27, 8, 3, "sky") end local function fuyishengP(t) t.vln(8, 0, 5, "brown_d"); t.pn(6, 2, "brown_d"); t.pn(7, 3, "brown_d"); t.pn(10, 1, "brown_d") t.vln(23, 0, 5, "brown_d"); t.pn(25, 2, "brown_d"); t.pn(24, 3, "brown_d"); t.pn(21, 1, "brown_d") t.rectn(2, 10, 4, 6, "cream_d"); t.rectn(26, 10, 4, 6, "cream_d") t.rectn(6, 5, 20, 22, "cream_d"); t.rectn(6, 5, 20, 2, "skin") eyes(t, 10, 20, 13, "ink") t.rectn(11, 17, 10, 7, "cream"); t.rectn(14, 17, 4, 3, "ink") smileArc(t, 16, 21, 6, "brown_d") t.rectn(12, 27, 8, 3, "white"); t.pn(12, 28, "red") end local function guiyeyeP(t) t.rectn(7, 5, 18, 20, "leaf_l"); t.rectn(7, 5, 18, 2, "cream") -- bald cream top t.rectn(9, 12, 5, 2, "white"); t.rectn(18, 12, 5, 2, "white") -- bushy brows eyes(t, 10, 20, 14, "ink") t.rectn(10, 20, 12, 8, "white"); t.rectn(12, 26, 8, 3, "white") -- beard smileArc(t, 16, 19, 6, "brown_d") t.rectn(4, 28, 24, 3, "leaf_d"); t.rectn(4, 28, 24, 1, "leaf") -- shell hint end local function birdP(t) t.discn(10, 15, 8, "blue"); t.discn(9, 12, 4, "blue_l") -- left bird t.discn(11, 16, 3, "blue_d") t.pn(7, 12, "ink") t.pn(4, 15, "yellow"); t.pn(3, 16, "yellow_d") t.discn(22, 17, 7, "blue"); t.discn(23, 14, 3, "blue_l") -- right bird t.discn(21, 18, 3, "blue_d") t.pn(24, 14, "ink") t.pn(28, 16, "yellow"); t.pn(29, 17, "yellow_d") t.rectn(6, 25, 20, 2, "brown_d") -- branch end local portraits = { { "player_smile", playerSmile }, { "player_real", playerReal }, { "afu", afuP }, { "yuanyuan", yuanyuanP }, { "dabao", dabaoP }, { "mimi", mimiP }, { "fuyisheng", fuyishengP }, { "guiyeye", guiyeyeP }, { "bird", birdP }, } for _, n in ipairs(portraits) do local spr, img = H.new(32, 32) n[2](H.at(img, 0, 0)) spr:saveAs(ROOT .. "public/assets/portraits/" .. n[1] .. ".png") print(n[1] .. ".png done") end