@ko_studio · 6/9/2026, 10:51:32 PM
Initial version — all lines are new.
+<style>+ html,body{height:100%;margin:0;overflow:hidden;background:#E8D9BD;}+ *{box-sizing:border-box;}+ #wrap{position:relative;height:100%;width:100%;display:flex;flex-direction:column;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;background:linear-gradient(160deg,#EFE2C8 0%,#E4D2B0 100%);-webkit-tap-highlight-color:transparent;touch-action:none;user-select:none;-webkit-user-select:none;}+ #head{padding:1.15rem 1.25rem .2rem;z-index:2;pointer-events:none;}+ #head h1{margin:0;font-family:"Instrument Serif",Georgia,"Times New Roman",serif;font-weight:400;font-size:2.35rem;line-height:1;color:#5a4630;}+ #head p{margin:.2rem 0 0;font-size:.8rem;color:#9b855f;font-weight:500;}+ #board{flex:1;position:relative;min-height:0;}+ .pol{position:absolute;width:152px;background:#FFFDF6;padding:8px 8px 0;box-shadow:0 10px 22px rgba(80,60,20,.28);cursor:grab;touch-action:none;}+ .pol img{display:block;width:100%;height:138px;object-fit:cover;background:#ddd;pointer-events:none;}+ .pol .tape{position:absolute;left:50%;top:-9px;transform:translateX(-50%) rotate(-3deg);width:54px;height:18px;background:rgba(124,92,255,.35);border-radius:2px;}+ .pol input{width:100%;border:0;background:transparent;text-align:center;font-family:"Instrument Serif",Georgia,serif;font-style:italic;font-size:16px;color:#5a4630;padding:.45rem 0 .55rem;outline:none;}+ .pol input::placeholder{color:#c4b291;}+ #hint{position:absolute;left:50%;top:46%;transform:translate(-50%,-50%);pointer-events:none;font-family:"Instrument Serif",Georgia,serif;font-size:1.2rem;color:#9b855f;opacity:.85;transition:opacity .5s;text-align:center;line-height:1.5;}+ #foot{display:flex;gap:10px;justify-content:center;padding:.6rem 1.1rem 1.15rem;z-index:2;}+ #foot button{border:0;border-radius:999px;font-weight:700;font-size:.85rem;padding:.7rem 1.2rem;cursor:pointer;}+ #add{background:linear-gradient(135deg,#7C5CFF,#FF5A1F);color:#fff;box-shadow:0 8px 20px rgba(124,92,255,.3);}+ #snap{background:#5a4630;color:#FFF6E4;display:none;}+ #clear{background:rgba(255,255,255,.65);color:#6a5440;border:1px solid rgba(120,90,50,.25);display:none;}+ #file{display:none;}+ #resWrap{position:absolute;inset:0;z-index:5;display:none;flex-direction:column;align-items:center;justify-content:center;background:rgba(60,45,20,.55);backdrop-filter:blur(5px);padding:1.2rem;}+ #res{max-width:92%;max-height:70%;border-radius:10px;box-shadow:0 18px 44px rgba(0,0,0,.4);}+ #resWrap p{color:#FFF3DC;font-size:.78rem;font-weight:600;margin:.8rem 0 .5rem;}+ #back{border:0;border-radius:999px;background:rgba(255,255,255,.92);color:#5a4630;font-weight:700;font-size:.85rem;padding:.65rem 1.3rem;cursor:pointer;}+</style>+<div id="wrap">+ <div id="head"><h1>Polaroid Wall</h1><p>Pin up to 4 photos. Drag them around. Caption each.</p></div>+ <div id="board"><div id="hint">add a photo to start<br>it never leaves your phone</div></div>+ <div id="foot">+ <button id="add">+ photo</button>+ <button id="snap">snapshot 📸</button>+ <button id="clear">clear</button>+ </div>+ <input id="file" type="file" accept="image/*">+ <div id="resWrap">+ <img id="res" alt="your wall">+ <p>press & hold to save your wall</p>+ <button id="back">back to the board</button>+ </div>+</div>+<script>+(function(){+ var LL=window.liveloop||null;+ var muted = LL ? LL.muted : true;+ if(LL && LL.onMute){ try{ LL.onMute(function(m){ muted=m; }); }catch(e){} }+ if(LL && LL.declareMedia){ try{ LL.declareMedia({sound:true}); }catch(e){} }+ var _ac=null;+ function actx(){ if(!_ac){ try{ _ac=new (window.AudioContext||window.webkitAudioContext)(); }catch(e){ _ac=null; } } return _ac; }+ function thunk(f){ // soft cork "pin" sound+ if(muted) return; var c=actx(); if(!c) return;+ var t=c.currentTime, o=c.createOscillator(), g=c.createGain();+ o.type='triangle'; o.frequency.setValueAtTime(f||240,t);+ o.frequency.exponentialRampToValueAtTime((f||240)*0.6,t+0.08);+ g.gain.setValueAtTime(0.0001,t); g.gain.exponentialRampToValueAtTime(0.16,t+0.008);+ g.gain.exponentialRampToValueAtTime(0.0001,t+0.16);+ o.connect(g); g.connect(c.destination); o.start(t); o.stop(t+0.18);+ }++ var board=document.getElementById('board');+ var hint=document.getElementById('hint');+ var addBtn=document.getElementById('add'), snapBtn=document.getElementById('snap'), clearBtn=document.getElementById('clear');+ var fileIn=document.getElementById('file');+ var resWrap=document.getElementById('resWrap'), resImg=document.getElementById('res'), backBtn=document.getElementById('back');+ var pols=[]; // {el, img(dataURL canvas), x, y, rot}+ var MAXP=4;++ function spot(i){+ var r=board.getBoundingClientRect();+ var cols=[[0.08,0.06],[0.5,0.12],[0.12,0.46],[0.46,0.5]];+ var p=cols[i%4];+ return { x:p[0]*r.width + (Math.random()*16-8), y:p[1]*r.height + (Math.random()*16-8) };+ }++ function addPol(srcCanvas){+ var i=pols.length, pos=spot(i), rot=(Math.random()*10-5);+ var el=document.createElement('div'); el.className='pol';+ el.style.left=pos.x+'px'; el.style.top=pos.y+'px';+ el.style.transform='rotate('+rot+'deg)';+ el.style.zIndex=String(10+i);+ var tape=document.createElement('span'); tape.className='tape';+ var hues=['rgba(124,92,255,.35)','rgba(255,90,31,.35)','rgba(225,76,143,.35)','rgba(246,169,59,.4)'];+ tape.style.background=hues[i%4];+ var im=document.createElement('img'); im.src=srcCanvas.toDataURL('image/jpeg',0.85); im.alt='';+ var cap=document.createElement('input'); cap.maxLength=28; cap.placeholder='caption…';+ el.appendChild(tape); el.appendChild(im); el.appendChild(cap);+ board.appendChild(el);+ var rec={el:el, x:pos.x, y:pos.y, rot:rot, cap:cap, img:srcCanvas};+ pols.push(rec);++ // drag (pointer events; taps on the input still focus it)+ var sx=0,sy=0,ox=0,oy=0,drag=false;+ el.addEventListener('pointerdown',function(e){+ if(e.target===cap) return;+ drag=true; sx=e.clientX; sy=e.clientY; ox=rec.x; oy=rec.y;+ el.style.zIndex=String(100+(++zTop));+ try{ el.setPointerCapture(e.pointerId); }catch(x){}+ e.preventDefault();+ });+ el.addEventListener('pointermove',function(e){+ if(!drag) return;+ rec.x=ox+(e.clientX-sx); rec.y=oy+(e.clientY-sy);+ el.style.left=rec.x+'px'; el.style.top=rec.y+'px';+ e.preventDefault();+ });+ el.addEventListener('pointerup',function(){ if(drag){ drag=false; thunk(200); } });+ el.addEventListener('pointercancel',function(){ drag=false; });++ hint.style.opacity='0';+ snapBtn.style.display='block'; clearBtn.style.display='block';+ if(pols.length>=MAXP) addBtn.style.display='none';+ thunk(280);+ }+ var zTop=0;++ function load(file){+ var rd=new FileReader();+ rd.onload=function(){+ var im=new Image();+ im.onload=function(){+ var S=600, sc=Math.max(S/im.width,S/im.height);+ var c2=document.createElement('canvas'); c2.width=S; c2.height=S;+ var cc=c2.getContext('2d');+ var w=im.width*sc, h=im.height*sc;+ cc.drawImage(im,(S-w)/2,(S-h)/2,w,h);+ addPol(c2);+ };+ im.src=rd.result;+ };+ rd.readAsDataURL(file);+ }+ addBtn.addEventListener('click',function(){ if(pols.length<MAXP) fileIn.click(); });+ fileIn.addEventListener('change',function(){ if(fileIn.files && fileIn.files[0]){ load(fileIn.files[0]); fileIn.value=''; } });++ clearBtn.addEventListener('click',function(){+ pols.forEach(function(p){ board.removeChild(p.el); });+ pols=[]; addBtn.style.display='block';+ snapBtn.style.display='none'; clearBtn.style.display='none';+ hint.style.opacity='.85';+ });++ snapBtn.addEventListener('click',function(){+ if(!pols.length) return;+ var br=board.getBoundingClientRect();+ var W=900, H=Math.round(W*br.height/br.width), k=W/br.width;+ var out=document.createElement('canvas'); out.width=W; out.height=H;+ var oc=out.getContext('2d');+ var bg=oc.createLinearGradient(0,0,W*0.3,H);+ bg.addColorStop(0,'#EFE2C8'); bg.addColorStop(1,'#E4D2B0');+ oc.fillStyle=bg; oc.fillRect(0,0,W,H);+ pols.forEach(function(p){+ var pw=152*k, ph=(138+8+36)*k+8*k;+ var cx=(p.x+76)*k, cy=(p.y+95)*k;+ oc.save(); oc.translate(cx,cy); oc.rotate(p.rot*Math.PI/180);+ oc.shadowColor='rgba(80,60,20,.3)'; oc.shadowBlur=18*k/1.5; oc.shadowOffsetY=8;+ oc.fillStyle='#FFFDF6'; oc.fillRect(-pw/2,-ph/2,pw,ph);+ oc.shadowColor='transparent';+ oc.drawImage(p.img,-pw/2+8*k,-ph/2+8*k,pw-16*k,138*k);+ var ctext=(p.cap.value||'').trim();+ if(ctext){+ oc.fillStyle='#5a4630'; oc.textAlign='center';+ oc.font='italic '+Math.round(15*k)+'px Georgia,"Times New Roman",serif';+ oc.fillText(ctext,0,ph/2-12*k,pw-20*k);+ }+ oc.restore();+ });+ oc.fillStyle='rgba(90,70,48,.55)'; oc.textAlign='right';+ oc.font='italic '+Math.round(13*k)+'px Georgia,serif';+ var d=new Date();+ oc.fillText(d.toLocaleDateString(undefined,{month:'short',day:'numeric',year:'numeric'}),W-18,H-16);+ resImg.src=out.toDataURL('image/jpeg',0.9);+ resWrap.style.display='flex';+ thunk(330);+ });+ backBtn.addEventListener('click',function(){ resWrap.style.display='none'; });+})();+</script>