-- Minor native-pixel motion pass on four existing key drawings. Head, torso, -- limbs and equipment translate together; only the planted sole rolls 1px. local function numbers(value) local out={} for n in string.gmatch(value,'[^,]+') do table.insert(out,tonumber(n)) end return out end local keys=numbers(app.params.keys) local drops=numbers(app.params.drops) local weights=numbers(app.params.weights) local cycle=tonumber(app.params.cycle) local src=app.open(app.params.source) local original=Image(src.cels[1].image) local atlas=Image(#keys*48,256,ColorMode.RGB) local names={'south','west','east','north'} for row=0,3 do local gif=Sprite(48,64,ColorMode.RGB) for index,col in ipairs(keys) do local base=Image(48,64,ColorMode.RGB) base:drawImage(original,Point(-col*48,-row*64)) local floor=-1 for p in base:pixels() do if app.pixelColor.rgbaA(p())>0 then floor=math.max(floor,p.y) end end local frame=Image(48,64,ColorMode.RGB) local drop=drops[index] frame:drawImage(base,Point(0,drop)) if drop~=0 then -- Keep the authored planted sole on the floor. This changes one boot -- edge rather than stretching the shin, neck, or a torso band. for y=floor+1,63 do for x=0,47 do frame:putPixel(x,y,0) end end for x=0,47 do frame:putPixel(x,floor,base:getPixel(x,floor)) end end atlas:drawImage(frame,Point((index-1)*48,row*64)) if index>1 then gif:newFrame() end gif.cels[index].image=Image(frame) gif.frames[index].duration=cycle*weights[index]/#keys end app.command.SpriteSize{ui=false,width=144,height=192,method='nearest-neighbor'} gif:saveAs(app.params.preview..'_'..names[row+1]..'.gif');gif:close() end src:close() local sheet=Sprite(#keys*48,256,ColorMode.RGB) sheet.cels[1].image=atlas;sheet:saveAs(app.params.output) app.command.SpriteSize{ui=false,width=#keys*144,height=768,method='nearest-neighbor'} sheet:saveAs(app.params.preview..'_sheet_3x.png');sheet:close() print('Exported eight timed weight phases from four key drawings; soles anchored.')