Spaces:
Sleeping
Sleeping
| const puppeteer = require('puppeteer'); | |
| const html = `<!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <title>Cinematic Motion Graphics</title> | |
| <style> | |
| html,body{margin:0;overflow:hidden;width:100%;height:100%;background:#050816;font-family:Arial,sans-serif;} | |
| canvas{position:fixed;inset:0;} | |
| .overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;pointer-events:none;} | |
| .title{color:white;font-size:clamp(2rem,6vw,6rem);letter-spacing:.4em;text-transform:uppercase;mix-blend-mode:screen;animation:pulse 6s ease-in-out infinite;} | |
| @keyframes pulse{0%,100%{transform:scale(1);opacity:.7}50%{transform:scale(1.08);opacity:1}} | |
| </style> | |
| </head> | |
| <body> | |
| <canvas id="c"></canvas> | |
| <div class="overlay"><div class="title">Motion</div></div> | |
| <script> | |
| const canvas=document.getElementById("c"); | |
| const ctx=canvas.getContext("2d"); | |
| let w,h,t=0; | |
| function resize(){ | |
| w=canvas.width=window.innerWidth; | |
| h=canvas.height=window.innerHeight; | |
| console.log("Resize called: w=", w, "h=", h); | |
| } | |
| window.addEventListener("resize",resize); | |
| resize(); | |
| const particles=[]; | |
| for(let i=0;i<1200;i++){ | |
| particles.push({ | |
| a:Math.random()*Math.PI*2, | |
| r:50+Math.random()*700, | |
| s:0.2+Math.random()*2, | |
| o:Math.random()*Math.PI*2 | |
| }); | |
| } | |
| function draw(){ | |
| try { | |
| t+=0.008; | |
| const g=ctx.createRadialGradient(w/2,h/2,0,w/2,h/2,Math.max(w,h)); | |
| g.addColorStop(0,"#101a45"); | |
| g.addColorStop(.5,"#070b1d"); | |
| g.addColorStop(1,"#020205"); | |
| ctx.fillStyle=g; | |
| ctx.fillRect(0,0,w,h); | |
| ctx.save(); | |
| ctx.translate(w/2,h/2); | |
| for(let ring=0; ring<8; ring++){ | |
| ctx.beginPath(); | |
| for(let i=0;i<360;i++){ | |
| const a=i*Math.PI/180; | |
| const r=140+ring*50+Math.sin(a*6+t*3+ring)*18; | |
| const x=Math.cos(a+t*0.2*ring)*r; | |
| const y=Math.sin(a+t*0.2*ring)*r; | |
| if(i===0) ctx.moveTo(x,y); | |
| else ctx.lineTo(x,y); | |
| } | |
| ctx.closePath(); | |
| ctx.strokeStyle=\`hsla(\${(ring*45+t*120)%360},90%,65%,0.18)\`; | |
| ctx.lineWidth=2; | |
| ctx.stroke(); | |
| } | |
| particles.forEach((p,i)=>{ | |
| const ang=p.a+t*p.s; | |
| const rr=p.r*(0.75+0.25*Math.sin(t+p.o)); | |
| const x=Math.cos(ang)*rr; | |
| const y=Math.sin(ang)*rr; | |
| const size=1.5+2*Math.sin(t*2+p.o); | |
| ctx.fillStyle=\`hsla(\${(ang*100+t*300)%360},100%,70%,0.8)\`; | |
| ctx.beginPath(); | |
| ctx.arc(x,y,Math.abs(size),0,Math.PI*2); | |
| ctx.fill(); | |
| if(i%18===0){ | |
| ctx.beginPath(); | |
| ctx.moveTo(x,y); | |
| ctx.lineTo( | |
| Math.cos(ang+0.25)*rr*0.9, | |
| Math.sin(ang+0.25)*rr*0.9 | |
| ); | |
| ctx.strokeStyle="rgba(255,255,255,.08)"; | |
| ctx.stroke(); | |
| } | |
| }); | |
| for(let k=0;k<6;k++){ | |
| ctx.save(); | |
| ctx.rotate(t*(k+1)*0.15); | |
| ctx.beginPath(); | |
| for(let i=0;i<200;i++){ | |
| const a=i/200*Math.PI*2; | |
| const r=260+Math.sin(a*12+t*4+k)*45; | |
| ctx.lineTo(Math.cos(a)*r,Math.sin(a)*r); | |
| } | |
| ctx.closePath(); | |
| ctx.strokeStyle=\`hsla(\${(k*60+t*100)%360},100%,60%,0.25)\`; | |
| ctx.stroke(); | |
| ctx.restore(); | |
| } | |
| ctx.restore(); | |
| requestAnimationFrame(draw); | |
| } catch(e) { | |
| console.error("DRAW ERROR", e); | |
| } | |
| } | |
| draw(); | |
| </script> | |
| </body> | |
| </html>`; | |
| const TIME_SHIM = ` | |
| window.__VTIME_INSTALLED__ = true; | |
| var vtime = 0; | |
| var _origRaf = window.requestAnimationFrame; | |
| var rafCallbacks = []; var rafId = 0; | |
| window.requestAnimationFrame = function(cb){ rafId++; rafCallbacks.push({id: rafId, cb: cb}); return rafId; }; | |
| window.__advanceVTime = function(target){ | |
| var STEP = 8; | |
| while (vtime < target) { | |
| vtime = Math.min(vtime + STEP, target); | |
| var cbs = rafCallbacks; rafCallbacks = []; | |
| for (var j = 0; j < cbs.length; j++) { try { cbs[j].cb(vtime); } catch(e){} } | |
| } | |
| }; | |
| window.__renderFrame = function(target) { | |
| return new Promise(function(resolve) { | |
| window.__advanceVTime(target); | |
| if (typeof _origRaf === 'function') { | |
| _origRaf(function() { _origRaf(resolve); }); | |
| } else { | |
| setTimeout(resolve, 0); | |
| } | |
| }); | |
| }; | |
| `; | |
| (async () => { | |
| const browser = await puppeteer.launch({ | |
| headless: 'new', | |
| args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-web-security', '--disable-features=IsolateOrigins,site-per-process', '--js-flags="--max-old-space-size=4096"'] | |
| }); | |
| const page = await browser.newPage(); | |
| await page.setViewport({ width: 1920, height: 1080 }); | |
| page.on('console', msg => console.log('PAGE LOG:', msg.text())); | |
| await page.goto('about:blank'); | |
| const processedHtml = html.replace(/<head[^>]*>/i, (m) => m + '<script>' + TIME_SHIM + '</script>'); | |
| await page.setContent(processedHtml, { waitUntil: 'networkidle0' }); | |
| // Advance time to 5000ms | |
| for (let i = 0; i <= 300; i++) { | |
| await page.evaluate((t) => window.__renderFrame(t), i * 16.666); | |
| await new Promise(r => setTimeout(r, 5)); | |
| } | |
| await new Promise(r => setTimeout(r, 100)); | |
| await page.screenshot({ path: 'test_motion.jpg', type: 'jpeg', quality: 100 }); | |
| await browser.close(); | |
| console.log("Done"); | |
| })(); | |