Spaces:
Sleeping
Sleeping
| const puppeteer = require('puppeteer'); | |
| const html = `<!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width,initial-scale=1"> | |
| <title>Cinematic Motion Graphics 30s</title> | |
| <style> | |
| html,body{margin:0;width:100%;height:100%;overflow:hidden;background:#050814} | |
| canvas{position:fixed;inset:0} | |
| #ui{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;pointer-events:none} | |
| .title{ | |
| position:absolute; | |
| font-family:Georgia,serif; | |
| font-weight:700; | |
| font-size:clamp(60px,9vw,180px); | |
| letter-spacing:.08em; | |
| color:white; | |
| opacity:0; | |
| transform:translateY(40px) scale(.9); | |
| text-transform:uppercase; | |
| text-shadow:0 0 30px rgba(255,255,255,.25); | |
| } | |
| .sub{ | |
| position:absolute; | |
| top:62%; | |
| font-family:Arial,sans-serif; | |
| letter-spacing:.6em; | |
| font-size:14px; | |
| color:rgba(255,255,255,.8); | |
| opacity:0; | |
| text-transform:uppercase; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <canvas id="c"></canvas> | |
| <div id="ui"> | |
| <div class="title" id="title">MOTION</div> | |
| <div class="sub" id="sub">DESIGN • RHYTHM • STORY</div> | |
| </div> | |
| <script> | |
| const canvas=document.getElementById('c'); | |
| const ctx=canvas.getContext('2d',{alpha:false,willReadFrequently:true}); | |
| canvas.width=1920; canvas.height=1080; | |
| const title=document.getElementById('title'); | |
| const sub=document.getElementById('sub'); | |
| const D=30000; | |
| function lerp(a,b,t){return a+(b-a)*t;} | |
| function clamp(x,a,b){return Math.max(a,Math.min(b,x));} | |
| function drawBackground(t){ | |
| ctx.fillStyle='#050814'; | |
| ctx.fillRect(0,0,1920,1080); | |
| for(let i=0;i<80;i++){ | |
| let y=i*14 + Math.sin(t*0.001+i*0.4)*25; | |
| ctx.strokeStyle='rgba(80,160,255,.08)'; | |
| ctx.beginPath(); | |
| ctx.moveTo(0,y*4); | |
| ctx.lineTo(1920,y*4); | |
| ctx.stroke(); | |
| } | |
| } | |
| function sceneLines(local){ | |
| for(let i=0;i<30;i++){ | |
| let p=clamp(local-i*0.03,0,1); | |
| let len=1200*p; | |
| let y=120+i*28; | |
| ctx.strokeStyle='rgba(180,220,255,'+(0.08+p*0.35)+')'; | |
| ctx.lineWidth=2; | |
| ctx.beginPath(); | |
| ctx.moveTo(960-len/2,y); | |
| ctx.lineTo(960+len/2,y); | |
| ctx.stroke(); | |
| } | |
| } | |
| function sceneNetwork(local){ | |
| const pts=[]; | |
| for(let i=0;i<24;i++){ | |
| let a=i/24*Math.PI*2+local*2; | |
| let r=260+Math.sin(a*3+local*4)*70; | |
| pts.push([960+Math.cos(a)*r,540+Math.sin(a)*r]); | |
| } | |
| ctx.strokeStyle='rgba(255,255,255,.15)'; | |
| for(let i=0;i<pts.length;i++){ | |
| let a=pts[i], b=pts[(i+1)%pts.length]; | |
| ctx.beginPath(); ctx.moveTo(a[0],a[1]); ctx.lineTo(b[0],b[1]); ctx.stroke(); | |
| } | |
| } | |
| function sceneRibbons(local){ | |
| for(let i=0;i<120;i++){ | |
| let p=(i/120+local*0.2)%1; | |
| let x=1920*(1-p); | |
| let y=540+Math.sin(p*10+local*8+i)*220; | |
| ctx.strokeStyle='rgba(220,120,255,.12)'; | |
| ctx.beginPath(); | |
| ctx.moveTo(x,y); | |
| ctx.lineTo(x+180,y+Math.cos(i)*30); | |
| ctx.stroke(); | |
| } | |
| } | |
| function sceneFinal(local){ | |
| ctx.save(); | |
| ctx.translate(960,540); | |
| ctx.rotate(local*0.5); | |
| for(let i=0;i<8;i++){ | |
| ctx.strokeStyle='rgba(255,220,120,.15)'; | |
| ctx.strokeRect(-260-i*18,-260-i*18,520+i*36,520+i*36); | |
| } | |
| ctx.restore(); | |
| } | |
| function animate(ms){ | |
| const t=ms%D; | |
| drawBackground(ms); | |
| title.style.opacity=0; | |
| sub.style.opacity=0; | |
| if(t<7000){ | |
| sceneLines(t/7000); | |
| if(t>1500){ | |
| let p=(t-1500)/2000; | |
| title.style.opacity=clamp(p,0,1); | |
| title.style.transform=\`translateY(\${40-40*clamp(p,0,1)}px) scale(\${0.9+0.1*clamp(p,0,1)})\`; | |
| } | |
| } | |
| else if(t<14000){ | |
| sceneNetwork((t-7000)/1000); | |
| title.innerText="KINETIC"; | |
| title.style.opacity=1; | |
| sub.style.opacity=.8; | |
| } | |
| else if(t<22000){ | |
| sceneRibbons((t-14000)/1000); | |
| title.innerText="STORY"; | |
| title.style.opacity=1; | |
| sub.style.opacity=.8; | |
| } | |
| else{ | |
| sceneFinal((t-22000)/8000); | |
| title.innerText="CREATE"; | |
| title.style.opacity=1; | |
| sub.style.opacity=.8; | |
| } | |
| requestAnimationFrame(animate); | |
| } | |
| requestAnimationFrame(animate); | |
| </script> | |
| </body> | |
| </html>`; | |
| (async () => { | |
| const browser = await puppeteer.launch({ headless: 'new', args: ['--no-sandbox', '--disable-gpu'] }); | |
| const page = await browser.newPage(); | |
| await page.setViewport({ width: 1920, height: 1080 }); | |
| await page.setContent(html); | |
| // Wait for 1 second of animation | |
| await new Promise(r => setTimeout(r, 1000)); | |
| // Simulate the injection | |
| await page.evaluate(() => { | |
| const c = document.querySelector('canvas'); | |
| const dataUrl = c.toDataURL('image/png'); | |
| let img = document.getElementById('test-img'); | |
| if(!img) { | |
| img = document.createElement('img'); | |
| img.id = 'test-img'; | |
| img.style.position = 'fixed'; | |
| img.style.pointerEvents = 'none'; | |
| const computedStyle = window.getComputedStyle(c); | |
| img.style.zIndex = computedStyle.zIndex || '0'; | |
| c.parentNode.insertBefore(img, c.nextSibling); | |
| } | |
| img.src = dataUrl; | |
| const rect = c.getBoundingClientRect(); | |
| img.style.left = rect.left + 'px'; | |
| img.style.top = rect.top + 'px'; | |
| img.style.width = rect.width + 'px'; | |
| img.style.height = rect.height + 'px'; | |
| c.style.visibility = 'hidden'; | |
| }); | |
| await page.screenshot({ path: 'test_html2.jpg' }); | |
| await browser.close(); | |
| })(); | |