/* Engine-neutral PNG atlas + named animation coordinates. No external packages. */
(function(){
 'use strict';
 const directions=['down','left','right','up'],actions=['idle','walk','attack'];
 const counts={eyes:4,face:4,hair:4,body:3,outfit:4,palette:4};
 function normalize(input={}){return Object.fromEntries(Object.entries(counts).map(([k,n])=>[k,Number.isFinite(Number(input[k]))?((Math.trunc(Number(input[k]))%n)+n)%n:0]));}
 function build(input={},options={}){
  if(!window.PixelMotion)throw new Error('PixelMotion 尚未載入');
  const config=normalize(input),meta=PixelMotion.metadata,size=meta.size,columns=8;
  const canvas=document.createElement('canvas');canvas.width=size*columns;canvas.height=size*12;
  const ctx=canvas.getContext('2d');ctx.imageSmoothingEnabled=false;
  const frameCanvas=document.createElement('canvas'),frames={},animations={},clips={};
  for(let a=0;a<actions.length;a++)for(let d=0;d<directions.length;d++){
   const action=actions[a],direction=directions[d],info=meta.actions[action],name=`${action}-${direction}`,ids=[];
   for(let f=0;f<info.frames;f++){
    PixelMotion.render(frameCanvas,config,{action,direction,frame:f,layer:options.layer||'composite'});
    const x=f*size,y=(a*4+d)*size,id=`${name}-${String(f).padStart(2,'0')}`;
    ctx.drawImage(frameCanvas,x,y);
    frames[id]={frame:{x,y,w:size,h:size},rotated:false,trimmed:false,spriteSourceSize:{x:0,y:0,w:size,h:size},sourceSize:{w:size,h:size},duration:Math.round(1000/info.fps),anchor:{x:meta.anchor[0],y:meta.anchor[1]}};
    ids.push(id);
   }
   animations[name]=ids;
   clips[name]={frames:ids,fps:info.fps,loop:info.loop,direction,action,...(action==='attack'?{suggestedImpactFrames:info.impactFrames||[3,4]}:{})};
  }
  const json={frames,animations,clips,meta:{app:'Doll Atelier PixelMotion',version:'1',image:options.image||'spritesheet.png',format:'RGBA8888',size:{w:canvas.width,h:canvas.height},scale:'1',cell:{w:size,h:size},columns,rows:12,anchor:{x:meta.anchor[0],y:meta.anchor[1]},rowOrder:actions.flatMap(a=>directions.map(d=>`${a}-${d}`)),nativeCharacterSize:64,config,layer:options.layer||'composite',layers:meta.layers,notes:['Idle uses four frames; the remaining four cells in each idle row are transparent.','Attack is a non-looping short-sword animation. Impact frames are timing hints; no gameplay hitboxes are included.','Character pixels are drawn at native size; the 96px cell reserves room for the weapon.']}};
  return {canvas,json};
 }
 function save(blob,name){const url=URL.createObjectURL(blob),a=document.createElement('a');a.href=url;a.download=name;document.body.append(a);a.click();a.remove();setTimeout(()=>URL.revokeObjectURL(url),1500);}
 async function download(input={}){
  const {canvas,json}=build(input),blob=await new Promise(resolve=>canvas.toBlob(resolve,'image/png'));
  if(!blob)throw new Error('無法匯出 PNG');
  save(blob,'spritesheet.png');save(new Blob([JSON.stringify(json,null,2)+'\n'],{type:'application/json'}),'animations.json');
 }
 window.PixelMotionExport={build,download,normalize};
})();
