@liveloop · 5/17/2026, 11:52:13 AM
Initial version — all lines are new.
+<style>+ html,body{height:100%;margin:0;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;background:#0b1020;color:#f8fafc;overflow:hidden;}+ .wrap{display:flex;flex-direction:column;height:100%;box-sizing:border-box;padding:.8rem;gap:.5rem;}+ .top{display:flex;align-items:baseline;justify-content:space-between;gap:.5rem;}+ h1{margin:0;font-size:1rem;}+ #count{font-size:.78rem;color:#94a3b8;}+ #stage{flex:1;min-height:0;display:flex;align-items:center;justify-content:center;}+ #frame{position:relative;height:100%;aspect-ratio:3/4;max-width:100%;border-radius:1rem;border:4px solid #334155;background:#1e293b;background-size:cover;background-position:center;overflow:hidden;box-shadow:0 10px 30px rgba(0,0,0,.45);}+ #ph{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.4rem;color:#94a3b8;font-size:.78rem;text-align:center;padding:1rem;}+ #ph .big{font-size:3rem;}+ .sticker{position:absolute;transform:translate(-50%,-50%);line-height:1;cursor:grab;touch-action:none;user-select:none;-webkit-user-select:none;filter:drop-shadow(0 3px 7px rgba(0,0,0,.45));}+ .sticker.sel{outline:2px dashed #fbbf24;outline-offset:5px;border-radius:8px;}+ .palette{display:flex;gap:.35rem;overflow-x:auto;padding:.2rem;}+ .pal{flex:none;font:inherit;font-size:1.5rem;width:2.7rem;height:2.7rem;border:2px solid #334155;background:#1e293b;border-radius:.6rem;cursor:pointer;touch-action:manipulation;}+ .controls{display:flex;gap:.4rem;align-items:center;justify-content:center;flex-wrap:wrap;}+ .btn{font:inherit;font-size:.8rem;font-weight:600;border:0;border-radius:9999px;padding:.45rem .95rem;background:#3b82f6;color:#fff;cursor:pointer;touch-action:manipulation;display:inline-flex;align-items:center;gap:.3rem;}+ .ghost{background:transparent;border:1px solid #475569;color:#cbd5e1;}+ .sz{font:inherit;font-weight:800;font-size:1rem;border:1px solid #475569;background:transparent;color:#cbd5e1;width:2.1rem;height:2.1rem;border-radius:.5rem;cursor:pointer;touch-action:manipulation;}+ .hint{font-size:.68rem;color:#64748b;text-align:center;}+ .hidden{display:none;}+</style>+<div class="wrap">+ <div class="top"><h1>🧑🎤 Costume Studio</h1><span id="count"></span></div>+ <div id="stage">+ <div id="frame">+ <div id="ph"><div class="big">🙂</div><div>Add your photo, then tap accessories to dress it up</div></div>+ </div>+ </div>+ <div class="palette" id="palette"></div>+ <div class="controls">+ <label class="btn">📷 Photo<input type="file" accept="image/*" id="pick" class="hidden"></label>+ <button class="sz" id="minus" type="button">−</button>+ <button class="sz" id="plus" type="button">+</button>+ <button class="btn ghost" id="del" type="button">✕ Remove</button>+ <button class="btn ghost" id="clear" type="button">Clear all</button>+ </div>+ <div class="hint">Tap an accessory to add it · drag to place · tap a sticker to select</div>+</div>+<script>+(function(){+ var PALETTE=['🎩','🤠','👑','🧢','👒','🎓','⛑️','🪖','🕶️','👓','🥸','🧣','👔','🎀','💍','🌟'];+ var frame=document.getElementById('frame'),ph=document.getElementById('ph'),+ palette=document.getElementById('palette'),count=document.getElementById('count'),+ pick=document.getElementById('pick');+ var stickers=[],sel=null;++ function onTap(el,fn){+ var sx=0,sy=0,armed=false;+ el.addEventListener('pointerdown',function(e){ armed=true;sx=e.clientX;sy=e.clientY; });+ el.addEventListener('pointercancel',function(){ armed=false; });+ el.addEventListener('pointerup',function(e){+ if(!armed) return; armed=false;+ if(Math.abs(e.clientX-sx)<14&&Math.abs(e.clientY-sy)<14) fn();+ });+ }+ function updateCount(){+ count.textContent=stickers.length?stickers.length+(stickers.length===1?' piece':' pieces'):'';+ }+ function layout(s){+ s.el.style.left=(s.x*100)+'%';+ s.el.style.top=(s.y*100)+'%';+ s.el.style.fontSize=s.size+'px';+ }+ function select(s){+ sel=s;+ stickers.forEach(function(o){ o.el.classList.toggle('sel',o===s); });+ }+ function bindDrag(s){+ var dragging=false;+ s.el.addEventListener('pointerdown',function(e){+ dragging=true; select(s);+ try{ s.el.setPointerCapture(e.pointerId); }catch(_){}+ e.preventDefault();+ });+ s.el.addEventListener('pointermove',function(e){+ if(!dragging) return;+ var r=frame.getBoundingClientRect();+ s.x=Math.max(0,Math.min(1,(e.clientX-r.left)/r.width));+ s.y=Math.max(0,Math.min(1,(e.clientY-r.top)/r.height));+ layout(s);+ e.preventDefault();+ });+ function endDrag(e){ dragging=false; try{ s.el.releasePointerCapture(e.pointerId); }catch(_){} }+ s.el.addEventListener('pointerup',endDrag);+ s.el.addEventListener('pointercancel',endDrag);+ }+ function addSticker(emoji){+ var s={emoji:emoji,x:0.5,y:0.38,size:56,el:document.createElement('div')};+ s.el.className='sticker'; s.el.textContent=emoji;+ frame.appendChild(s.el);+ stickers.push(s);+ layout(s); bindDrag(s); select(s); updateCount();+ s.el.animate([{transform:'translate(-50%,-50%) scale(.4)'},{transform:'translate(-50%,-50%) scale(1.15)'},{transform:'translate(-50%,-50%) scale(1)'}],{duration:230,easing:'ease-out'});+ }+ PALETTE.forEach(function(emoji){+ var b=document.createElement('button');+ b.type='button'; b.className='pal'; b.textContent=emoji;+ onTap(b,function(){ addSticker(emoji); });+ palette.appendChild(b);+ });++ onTap(document.getElementById('minus'),function(){+ if(!sel) return; sel.size=Math.max(20,sel.size-12); layout(sel);+ });+ onTap(document.getElementById('plus'),function(){+ if(!sel) return; sel.size=Math.min(240,sel.size+12); layout(sel);+ });+ onTap(document.getElementById('del'),function(){+ if(!sel) return;+ var i=stickers.indexOf(sel);+ sel.el.remove(); stickers.splice(i,1);+ sel=stickers.length?stickers[stickers.length-1]:null;+ if(sel) select(sel);+ updateCount();+ });+ onTap(document.getElementById('clear'),function(){+ stickers.forEach(function(s){ s.el.remove(); });+ stickers=[]; sel=null; updateCount();+ });++ pick.addEventListener('change',function(e){+ var file=e.target.files&&e.target.files[0]; if(!file) return;+ var reader=new FileReader();+ reader.onload=function(){+ var img=new Image();+ img.onload=function(){+ try{+ var max=760,sc=Math.min(1,max/Math.max(img.width,img.height));+ var c=document.createElement('canvas');+ c.width=Math.round(img.width*sc); c.height=Math.round(img.height*sc);+ c.getContext('2d').drawImage(img,0,0,c.width,c.height);+ frame.style.backgroundImage='url("'+c.toDataURL('image/jpeg',0.85)+'")';+ }catch(err){ frame.style.backgroundImage='url("'+reader.result+'")'; }+ ph.style.display='none';+ };+ img.onerror=function(){ frame.style.backgroundImage='url("'+reader.result+'")'; ph.style.display='none'; };+ img.src=reader.result;+ };+ reader.readAsDataURL(file);+ });+})();+</script>