Liveloop

Uma timeline interativa para redes sociais. Cada post é um app minúsculo que você pode jogar, salvar e remixar.

Produto

  • Feed
  • Jogos
  • Criar
  • Plugin do Claude Code
  • Blog

Jurídico

  • Política de Privacidade
  • Termos de Serviço
  • Política de Cookies
  • DMCA

Projeto

  • Templates
© 2026 Liveloop. Todos os direitos reservados.
LiveloopHistórico de versões

v2Atual

@joaobarrosfranca · 8/12/2026, 3:34:43 PM

Diferença em relação à v1.

<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
-<title>Open Wake</title>
+<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><title>Open Wake</title>
<style>
-*{box-sizing:border-box}html,body{margin:0;height:100%;overflow:hidden;background:#7bc9e3;font-family:system-ui,-apple-system,sans-serif;touch-action:none}canvas{display:block}#hud{position:fixed;z-index:4;inset:0 0 auto;padding:calc(17px + env(safe-area-inset-top)) 18px 0;display:flex;justify-content:space-between;color:#fff;text-shadow:0 2px 8px #164b6a;pointer-events:none}.label{font-size:10px;letter-spacing:1.7px;font-weight:900}.value{font-size:29px;line-height:1;font-weight:950}.right{text-align:right}#controls{position:fixed;z-index:6;left:0;right:0;bottom:max(20px,env(safe-area-inset-bottom));display:flex;justify-content:space-between;padding:0 22px}#controls button{width:65px;height:65px;border-radius:50%;border:2px solid #ffffffaa;background:#0a6d91a8;color:#fff;font-size:29px;font-weight:900;box-shadow:0 4px 12px #0b3d5a66;user-select:none}#controls button:active{background:#f7b84c;color:#174e68;transform:scale(.94)}#cover{position:fixed;z-index:10;inset:0;display:grid;place-items:center;padding:27px;text-align:center;background:linear-gradient(145deg,#e7cc89df 0%,#ef9a70cf 46%,#137a9acb 100%);color:#173f5b}#card{max-width:320px}.cap{font-size:11px;letter-spacing:4px;font-weight:900;color:#fff8d5}.title{font-family:Georgia,serif;font-weight:900;font-size:61px;line-height:.78;letter-spacing:-4px;margin:20px 0 21px;color:#fff9dd;text-shadow:0 4px 0 #3d7590}.title em{color:#075b79;font-style:italic}.copy{font-size:16px;line-height:1.5;color:#fffef4;margin:0 0 27px;font-weight:600}#start{border:3px solid #fff4d5;border-radius:4px;background:#075b79;color:#fff;padding:15px 27px;font-size:14px;font-weight:900;letter-spacing:1px;box-shadow:0 5px 0 #3c5160;cursor:pointer}#start:active{transform:translateY(3px);box-shadow:0 2px 0 #3c5160}.hint{font-size:12px;color:#fff9df;margin-top:18px}
-</style>
-</head>
-<body>
-<div id="hud"><div><div class="label">BUOYS FOUND</div><div id="score" class="value">0</div></div><div class="right"><div class="label">SPEED</div><div id="speed" class="value">FULL</div></div></div>
-<div id="controls"><button id="left" aria-label="Steer left">←</button><button id="right" aria-label="Steer right">→</button></div>
+*{box-sizing:border-box}html,body{margin:0;height:100%;overflow:hidden;background:#7bc9e3;font-family:system-ui,-apple-system,sans-serif;touch-action:none}canvas{display:block}#hud{position:fixed;z-index:4;top:0;left:0;right:0;padding:20px;display:flex;justify-content:space-between;color:#fff;text-shadow:0 2px 8px #164b6a;pointer-events:none}.label{font-size:10px;letter-spacing:1.7px;font-weight:900}.value{font-size:29px;line-height:1;font-weight:950}.right{text-align:right}#controls{position:fixed;z-index:6;left:0;right:0;bottom:22px;display:flex;justify-content:space-between;padding:0 22px}#controls button{width:65px;height:65px;border-radius:50%;border:2px solid #ffffffaa;background:#0a6d91a8;color:#fff;font-size:29px;font-weight:900;box-shadow:0 4px 12px #0b3d5a66;user-select:none}#controls button:active{background:#f7b84c;color:#174e68;transform:scale(.94)}#cover{position:fixed;z-index:10;inset:0;display:grid;place-items:center;padding:27px;text-align:center;background:linear-gradient(145deg,#e7cc89df,#ef9a70cf 46%,#137a9acb);color:#173f5b}#card{max-width:320px}.cap{font-size:11px;letter-spacing:4px;font-weight:900;color:#fff8d5}.title{font-family:Georgia,serif;font-weight:900;font-size:61px;line-height:.78;letter-spacing:-4px;margin:20px 0 21px;color:#fff9dd;text-shadow:0 4px 0 #3d7590}.title em{color:#075b79;font-style:italic}.copy{font-size:16px;line-height:1.5;color:#fffef4;margin:0 0 27px;font-weight:600}#start{border:3px solid #fff4d5;border-radius:4px;background:#075b79;color:#fff;padding:15px 27px;font-size:14px;font-weight:900;letter-spacing:1px;box-shadow:0 5px 0 #3c5160;cursor:pointer}#start:active{transform:translateY(3px);box-shadow:0 2px 0 #3c5160}.hint{font-size:12px;color:#fff9df;margin-top:18px}
+</style></head><body>
+<div id="hud"><div><div class="label">BUOYS FOUND</div><div id="score" class="value">0</div></div><div class="right"><div class="label">SPEED</div><div id="speed" class="value">FULL</div></div></div><div id="controls"><button id="left" aria-label="Steer left">←</button><button id="right" aria-label="Steer right">→</button></div>
<div id="cover"><div id="card"><div class="cap">AN OPEN WATER JOURNEY</div><div class="title">OPEN<br><em>WAKE</em></div><p class="copy">Sail the wide ocean, steer around islands, and pass through the glowing buoys.</p><button id="start" type="button">SET SAIL</button><div class="hint">Hold the wheel buttons to steer · Arrow keys also work</div></div></div>
<script type="module">
import * as THREE from "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js";
const scene=new THREE.Scene();scene.background=new THREE.Color(0x81cce3);scene.fog=new THREE.Fog(0x81cce3,27,100);
const camera=new THREE.PerspectiveCamera(59,innerWidth/innerHeight,.1,200);
-const renderer=new THREE.WebGLRenderer({antialias:true});renderer.setPixelRatio(Math.min(devicePixelRatio,2));renderer.setSize(innerWidth,innerHeight);renderer.outputColorSpace=THREE.SRGBColorSpace;renderer.shadowMap.enabled=true;document.body.appendChild(renderer.domElement);
-scene.add(new THREE.HemisphereLight(0xffffff,0x246b83,2.8));const sun=new THREE.DirectionalLight(0xffefc5,2.3);sun.position.set(-20,30,15);sun.castShadow=true;scene.add(sun);
-const seaGeo=new THREE.PlaneGeometry(220,220,80,80),base=[];const positions=seaGeo.attributes.position;for(let i=0;i<positions.count;i++)base.push([positions.getX(i),positions.getY(i)]);
-const sea=new THREE.Mesh(seaGeo,new THREE.MeshStandardMaterial({color:0x1489ad,roughness:.28,metalness:.12,flatShading:true}));sea.rotation.x=-Math.PI/2;sea.receiveShadow=true;scene.add(sea);
-const sparkle=new THREE.GridHelper(210,70,0x7ae1e8,0x237f9b);sparkle.position.y=.06;sparkle.material.opacity=.16;sparkle.material.transparent=true;scene.add(sparkle);
+const renderer=new THREE.WebGLRenderer({antialias:true});renderer.setPixelRatio(Math.min(devicePixelRatio,2));renderer.setSize(innerWidth,innerHeight);renderer.outputColorSpace=THREE.SRGBColorSpace;document.body.appendChild(renderer.domElement);
+scene.add(new THREE.HemisphereLight(0xffffff,0x246b83,2.8));const sun=new THREE.DirectionalLight(0xffefc5,2.3);sun.position.set(-20,30,15);scene.add(sun);
+const seaGeo=new THREE.PlaneGeometry(220,220,70,70),pos=seaGeo.attributes.position,base=[];
+for(let i=0;i<pos.count;i++)base.push([pos.getX(i),pos.getY(i)]);
+const sea=new THREE.Mesh(seaGeo,new THREE.MeshStandardMaterial({color:0x1489ad,roughness:.28,metalness:.12,flatShading:true}));sea.rotation.x=-Math.PI/2;scene.add(sea);
+const lines=new THREE.GridHelper(210,60,0x7ae1e8,0x237f9b);lines.position.y=.05;lines.material.opacity=.15;lines.material.transparent=true;scene.add(lines);
const boat=new THREE.Group();scene.add(boat);
-const hull=new THREE.Mesh(new THREE.BoxGeometry(1.25,.45,2.7),new THREE.MeshStandardMaterial({color:0xf7f1d1,roughness:.42,metalness:.05}));hull.position.y=.42;hull.scale.set(.82,1,1);hull.castShadow=true;boat.add(hull);
-const keel=new THREE.Mesh(new THREE.ConeGeometry(.69,1.45,4),new THREE.MeshStandardMaterial({color:0xd75b4b,roughness:.5}));keel.rotation.x=Math.PI;keel.position.set(0,.13,.18);keel.scale.z=1.55;boat.add(keel);
+const hull=new THREE.Mesh(new THREE.BoxGeometry(1.05,.45,2.6),new THREE.MeshStandardMaterial({color:0xf7f1d1,roughness:.42}));hull.position.y=.43;boat.add(hull);
+const keel=new THREE.Mesh(new THREE.ConeGeometry(.67,1.4,4),new THREE.MeshStandardMaterial({color:0xd75b4b,roughness:.5}));keel.rotation.x=Math.PI;keel.position.set(0,.13,.15);keel.scale.z=1.5;boat.add(keel);
const mast=new THREE.Mesh(new THREE.CylinderGeometry(.035,.045,2.8,8),new THREE.MeshStandardMaterial({color:0x6e402d}));mast.position.set(0,1.8,.05);boat.add(mast);
-const sailShape=new THREE.Shape();sailShape.moveTo(.08,0);sailShape.lineTo(.08,2.25);sailShape.lineTo(1.35,.18);sailShape.closePath();const sail=new THREE.Mesh(new THREE.ShapeGeometry(sailShape),new THREE.MeshStandardMaterial({color:0xffd365,side:THREE.DoubleSide,roughness:.75}));sail.position.set(0,1.15,.03);sail.rotation.y=.06;boat.add(sail);
-const flag=new THREE.Mesh(new THREE.PlaneGeometry(.55,.33),new THREE.MeshBasicMaterial({color:0xea6464,side:THREE.DoubleSide}));flag.position.set(.29,3.13,.05);boat.add(flag);
-boat.position.set(0,.45,0);
-function island(x,z,s){const g=new THREE.Group();const rock=new THREE.Mesh(new THREE.DodecahedronGeometry(s,1),new THREE.MeshStandardMaterial({color:0x88705b,roughness:1,flatShading:true}));rock.scale.y=.48;rock.position.y=s*.34;g.add(rock);for(let i=0;i<4;i++){const palm=new THREE.Group(),trunk=new THREE.Mesh(new THREE.CylinderGeometry(.045,.07,s*.9,6),new THREE.MeshStandardMaterial({color:0x70452d}));trunk.position.y=s*.72;palm.add(trunk);const leaves=new THREE.Mesh(new THREE.ConeGeometry(s*.34,s*.35,6),new THREE.MeshStandardMaterial({color:0x24845f,flatShading:true}));leaves.position.y=s*1.2;palm.add(leaves);palm.position.set((Math.random()-.5)*s*.8,0,(Math.random()-.5)*s*.8);g.add(palm)}g.position.set(x,0,z);scene.add(g)}
-for(let i=0;i<23;i++){let a=Math.random()*Math.PI*2,d=15+Math.random()*75;island(Math.sin(a)*d,Math.cos(a)*d,1.3+Math.random()*2.3)}
-const buoys=[];function makeBuoy(){const g=new THREE.Group(),ring=new THREE.Mesh(new THREE.TorusGeometry(1.05,.11,10,30),new THREE.MeshStandardMaterial({color:0xffe276,emissive:0xd17815,emissiveIntensity:2.1,roughness:.25}));ring.rotation.x=Math.PI/2;ring.position.y=1.45;g.add(ring);const post=new THREE.Mesh(new THREE.CylinderGeometry(.12,.12,1.2,10),new THREE.MeshStandardMaterial({color:0xff6b55,roughness:.5}));post.position.y=.6;g.add(post);const angle=Math.random()*Math.PI*2,dist=17+Math.random()*22;g.position.set(boat.position.x+Math.sin(angle)*dist,0,boat.position.z-Math.cos(angle)*dist);scene.add(g);buoys.push(g)}
+const shape=new THREE.Shape();shape.moveTo(.08,0);shape.lineTo(.08,2.25);shape.lineTo(1.35,.18);shape.closePath();
+const sail=new THREE.Mesh(new THREE.ShapeGeometry(shape),new THREE.MeshStandardMaterial({color:0xffd365,side:THREE.DoubleSide,roughness:.75}));sail.position.set(0,1.15,.03);sail.rotation.y=.06;boat.add(sail);boat.position.set(0,.48,0);
+function island(x,z,s){const g=new THREE.Group(),rock=new THREE.Mesh(new THREE.DodecahedronGeometry(s,1),new THREE.MeshStandardMaterial({color:0x88705b,roughness:1,flatShading:true}));rock.scale.y=.48;rock.position.y=s*.34;g.add(rock);for(let i=0;i<4;i++){const palm=new THREE.Group(),trunk=new THREE.Mesh(new THREE.CylinderGeometry(.045,.07,s*.9,6),new THREE.MeshStandardMaterial({color:0x70452d}));trunk.position.y=s*.72;palm.add(trunk);const leaves=new THREE.Mesh(new THREE.ConeGeometry(s*.34,s*.35,6),new THREE.MeshStandardMaterial({color:0x24845f,flatShading:true}));leaves.position.y=s*1.2;palm.add(leaves);palm.position.set((Math.random()-.5)*s*.8,0,(Math.random()-.5)*s*.8);g.add(palm)}g.position.set(x,0,z);scene.add(g)}
+for(let i=0;i<23;i++){const a=Math.random()*Math.PI*2,d=15+Math.random()*75;island(Math.sin(a)*d,Math.cos(a)*d,1.3+Math.random()*2.3)}
+const buoys=[];function addBuoy(){const g=new THREE.Group(),ring=new THREE.Mesh(new THREE.TorusGeometry(1.05,.11,10,30),new THREE.MeshStandardMaterial({color:0xffe276,emissive:0xd17815,emissiveIntensity:2.1,roughness:.25}));ring.rotation.x=Math.PI/2;ring.position.y=1.45;g.add(ring);const post=new THREE.Mesh(new THREE.CylinderGeometry(.12,.12,1.2,10),new THREE.MeshStandardMaterial({color:0xff6b55,roughness:.5}));post.position.y=.6;g.add(post);const a=Math.random()*Math.PI*2,d=17+Math.random()*22;g.position.set(boat.position.x+Math.sin(a)*d,0,boat.position.z-Math.cos(a)*d);scene.add(g);buoys.push(g)}
+for(let i=0;i<4;i++)addBuoy();
let turn=0,heading=0,running=false,score=0,last=0,boost=false;
const scoreEl=document.querySelector("#score"),speedEl=document.querySelector("#speed"),cover=document.querySelector("#cover");
-function setTurn(v){turn=v}function begin(){running=true;cover.style.display="none";last=0}
-function hold(el,value){el.addEventListener("pointerdown",e=>{e.preventDefault();setTurn(value);el.setPointerCapture&&el.setPointerCapture(e.pointerId)});["pointerup","pointercancel","pointerleave"].forEach(type=>el.addEventListener(type,()=>setTurn(0)))}
-hold(document.querySelector("#left"),1);hold(document.querySelector("#right"),-1);
-document.querySelector("#start").addEventListener("click",begin);
-addEventListener("keydown",e=>{let k=e.key.toLowerCase();if(k==="arrowleft"||k==="a"){e.preventDefault();turn=1}if(k==="arrowright"||k==="d"){e.preventDefault();turn=-1}if(k==="w"||k==="arrowup"){boost=true}if((k===" "||k==="enter")&&!running)begin()});addEventListener("keyup",e=>{let k=e.key.toLowerCase();if(k==="arrowleft"||k==="a"||k==="arrowright"||k==="d")turn=0;if(k==="w"||k==="arrowup")boost=false});
-function animate(t){requestAnimationFrame(animate);const dt=Math.min(40,last?t-last:16);last=t;
-for(let i=0;i<positions.count;i++){const x=base[i][0],z=base[i][1];positions.setZ(i,Math.sin(x*.13+t*.0018)*.18+Math.cos(z*.1+t*.0012)*.12)}positions.needsUpdate=true;
-if(running){const pace=(boost?.019:.0125)*dt;heading+=turn*dt*.00145;boat.position.x-=Math.sin(heading)*pace;boat.position.z-=Math.cos(heading)*pace;boat.rotation.y=heading;boat.position.y=.46+Math.sin(t*.003)*.06;boat.rotation.z=Math.sin(t*.0028)*.035;boat.rotation.x=Math.cos(t*.003)*.025;speedEl.textContent=boost?"FAST":"FULL";
-for(let i=buoys.length-1;i>=0;i--){const b=buoys[i];b.rotation.y+=dt*.0015;b.children[0].rotation.z+=dt*.001;const distance=boat.position.distanceTo(b.position);if(distance<1.35){scene.remove(b);buoys.splice(i,1);score++;scoreEl.textContent=score;makeBuoy()}}
+function begin(){running=true;cover.style.display="none";last=0}function steer(v){turn=v}
+function hold(el,v){el.addEventListener("pointerdown",e=>{e.preventDefault();steer(v)});["pointerup","pointercancel","pointerleave"].forEach(type=>el.addEventListener(type,()=>steer(0)))}
+hold(document.querySelector("#left"),1);hold(document.querySelector("#right"),-1);document.querySelector("#start").addEventListener("click",begin);
+addEventListener("keydown",e=>{const k=e.key.toLowerCase();if(k==="arrowleft"||k==="a"){e.preventDefault();turn=1}if(k==="arrowright"||k==="d"){e.preventDefault();turn=-1}if(k==="w"||k==="arrowup")boost=true;if((k===" "||k==="enter")&&!running)begin()});
+addEventListener("keyup",e=>{const k=e.key.toLowerCase();if(k==="arrowleft"||k==="a"||k==="arrowright"||k==="d")turn=0;if(k==="w"||k==="arrowup")boost=false});
+function loop(t){requestAnimationFrame(loop);const dt=Math.min(40,last?t-last:16);last=t;for(let i=0;i<pos.count;i++)pos.setZ(i,Math.sin(base[i][0]*.13+t*.0018)*.18+Math.cos(base[i][1]*.1+t*.0012)*.12);pos.needsUpdate=true;
+if(running){const pace=(boost ? .019 : .0125)*dt;heading+=turn*dt*.00145;boat.position.x-=Math.sin(heading)*pace;boat.position.z-=Math.cos(heading)*pace;boat.rotation.y=heading;boat.position.y=.48+Math.sin(t*.003)*.06;boat.rotation.z=Math.sin(t*.0028)*.035;boat.rotation.x=Math.cos(t*.003)*.025;speedEl.textContent=boost?"FAST":"FULL";
+for(let i=buoys.length-1;i>=0;i--){const b=buoys[i];b.rotation.y+=dt*.0015;b.children[0].rotation.z+=dt*.001;if(boat.position.distanceTo(b.position)<1.35){scene.remove(b);buoys.splice(i,1);score++;scoreEl.textContent=score;addBuoy()}}
const backX=boat.position.x+Math.sin(heading)*8,backZ=boat.position.z+Math.cos(heading)*8;camera.position.lerp(new THREE.Vector3(backX,5.5,backZ),.055);camera.lookAt(boat.position.x-Math.sin(heading)*4,.7,boat.position.z-Math.cos(heading)*4)}
renderer.render(scene,camera)}
-addEventListener("resize",()=>{camera.aspect=innerWidth/innerHeight;camera.updateProjectionMatrix();renderer.setSize(innerWidth,innerHeight)});animate(0);
+addEventListener("resize",()=>{camera.aspect=innerWidth/innerHeight;camera.updateProjectionMatrix();renderer.setSize(innerWidth,innerHeight)});loop(0);
</script></body></html>

v2Atual

@joaobarrosfranca · 8/12/2026, 3:34:43 PM

Diferença em relação à v1.

<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
-<title>Open Wake</title>
+<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><title>Open Wake</title>
<style>
-*{box-sizing:border-box}html,body{margin:0;height:100%;overflow:hidden;background:#7bc9e3;font-family:system-ui,-apple-system,sans-serif;touch-action:none}canvas{display:block}#hud{position:fixed;z-index:4;inset:0 0 auto;padding:calc(17px + env(safe-area-inset-top)) 18px 0;display:flex;justify-content:space-between;color:#fff;text-shadow:0 2px 8px #164b6a;pointer-events:none}.label{font-size:10px;letter-spacing:1.7px;font-weight:900}.value{font-size:29px;line-height:1;font-weight:950}.right{text-align:right}#controls{position:fixed;z-index:6;left:0;right:0;bottom:max(20px,env(safe-area-inset-bottom));display:flex;justify-content:space-between;padding:0 22px}#controls button{width:65px;height:65px;border-radius:50%;border:2px solid #ffffffaa;background:#0a6d91a8;color:#fff;font-size:29px;font-weight:900;box-shadow:0 4px 12px #0b3d5a66;user-select:none}#controls button:active{background:#f7b84c;color:#174e68;transform:scale(.94)}#cover{position:fixed;z-index:10;inset:0;display:grid;place-items:center;padding:27px;text-align:center;background:linear-gradient(145deg,#e7cc89df 0%,#ef9a70cf 46%,#137a9acb 100%);color:#173f5b}#card{max-width:320px}.cap{font-size:11px;letter-spacing:4px;font-weight:900;color:#fff8d5}.title{font-family:Georgia,serif;font-weight:900;font-size:61px;line-height:.78;letter-spacing:-4px;margin:20px 0 21px;color:#fff9dd;text-shadow:0 4px 0 #3d7590}.title em{color:#075b79;font-style:italic}.copy{font-size:16px;line-height:1.5;color:#fffef4;margin:0 0 27px;font-weight:600}#start{border:3px solid #fff4d5;border-radius:4px;background:#075b79;color:#fff;padding:15px 27px;font-size:14px;font-weight:900;letter-spacing:1px;box-shadow:0 5px 0 #3c5160;cursor:pointer}#start:active{transform:translateY(3px);box-shadow:0 2px 0 #3c5160}.hint{font-size:12px;color:#fff9df;margin-top:18px}
-</style>
-</head>
-<body>
-<div id="hud"><div><div class="label">BUOYS FOUND</div><div id="score" class="value">0</div></div><div class="right"><div class="label">SPEED</div><div id="speed" class="value">FULL</div></div></div>
-<div id="controls"><button id="left" aria-label="Steer left">←</button><button id="right" aria-label="Steer right">→</button></div>
+*{box-sizing:border-box}html,body{margin:0;height:100%;overflow:hidden;background:#7bc9e3;font-family:system-ui,-apple-system,sans-serif;touch-action:none}canvas{display:block}#hud{position:fixed;z-index:4;top:0;left:0;right:0;padding:20px;display:flex;justify-content:space-between;color:#fff;text-shadow:0 2px 8px #164b6a;pointer-events:none}.label{font-size:10px;letter-spacing:1.7px;font-weight:900}.value{font-size:29px;line-height:1;font-weight:950}.right{text-align:right}#controls{position:fixed;z-index:6;left:0;right:0;bottom:22px;display:flex;justify-content:space-between;padding:0 22px}#controls button{width:65px;height:65px;border-radius:50%;border:2px solid #ffffffaa;background:#0a6d91a8;color:#fff;font-size:29px;font-weight:900;box-shadow:0 4px 12px #0b3d5a66;user-select:none}#controls button:active{background:#f7b84c;color:#174e68;transform:scale(.94)}#cover{position:fixed;z-index:10;inset:0;display:grid;place-items:center;padding:27px;text-align:center;background:linear-gradient(145deg,#e7cc89df,#ef9a70cf 46%,#137a9acb);color:#173f5b}#card{max-width:320px}.cap{font-size:11px;letter-spacing:4px;font-weight:900;color:#fff8d5}.title{font-family:Georgia,serif;font-weight:900;font-size:61px;line-height:.78;letter-spacing:-4px;margin:20px 0 21px;color:#fff9dd;text-shadow:0 4px 0 #3d7590}.title em{color:#075b79;font-style:italic}.copy{font-size:16px;line-height:1.5;color:#fffef4;margin:0 0 27px;font-weight:600}#start{border:3px solid #fff4d5;border-radius:4px;background:#075b79;color:#fff;padding:15px 27px;font-size:14px;font-weight:900;letter-spacing:1px;box-shadow:0 5px 0 #3c5160;cursor:pointer}#start:active{transform:translateY(3px);box-shadow:0 2px 0 #3c5160}.hint{font-size:12px;color:#fff9df;margin-top:18px}
+</style></head><body>
+<div id="hud"><div><div class="label">BUOYS FOUND</div><div id="score" class="value">0</div></div><div class="right"><div class="label">SPEED</div><div id="speed" class="value">FULL</div></div></div><div id="controls"><button id="left" aria-label="Steer left">←</button><button id="right" aria-label="Steer right">→</button></div>
<div id="cover"><div id="card"><div class="cap">AN OPEN WATER JOURNEY</div><div class="title">OPEN<br><em>WAKE</em></div><p class="copy">Sail the wide ocean, steer around islands, and pass through the glowing buoys.</p><button id="start" type="button">SET SAIL</button><div class="hint">Hold the wheel buttons to steer · Arrow keys also work</div></div></div>
<script type="module">
import * as THREE from "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js";
const scene=new THREE.Scene();scene.background=new THREE.Color(0x81cce3);scene.fog=new THREE.Fog(0x81cce3,27,100);
const camera=new THREE.PerspectiveCamera(59,innerWidth/innerHeight,.1,200);
-const renderer=new THREE.WebGLRenderer({antialias:true});renderer.setPixelRatio(Math.min(devicePixelRatio,2));renderer.setSize(innerWidth,innerHeight);renderer.outputColorSpace=THREE.SRGBColorSpace;renderer.shadowMap.enabled=true;document.body.appendChild(renderer.domElement);
-scene.add(new THREE.HemisphereLight(0xffffff,0x246b83,2.8));const sun=new THREE.DirectionalLight(0xffefc5,2.3);sun.position.set(-20,30,15);sun.castShadow=true;scene.add(sun);
-const seaGeo=new THREE.PlaneGeometry(220,220,80,80),base=[];const positions=seaGeo.attributes.position;for(let i=0;i<positions.count;i++)base.push([positions.getX(i),positions.getY(i)]);
-const sea=new THREE.Mesh(seaGeo,new THREE.MeshStandardMaterial({color:0x1489ad,roughness:.28,metalness:.12,flatShading:true}));sea.rotation.x=-Math.PI/2;sea.receiveShadow=true;scene.add(sea);
-const sparkle=new THREE.GridHelper(210,70,0x7ae1e8,0x237f9b);sparkle.position.y=.06;sparkle.material.opacity=.16;sparkle.material.transparent=true;scene.add(sparkle);
+const renderer=new THREE.WebGLRenderer({antialias:true});renderer.setPixelRatio(Math.min(devicePixelRatio,2));renderer.setSize(innerWidth,innerHeight);renderer.outputColorSpace=THREE.SRGBColorSpace;document.body.appendChild(renderer.domElement);
+scene.add(new THREE.HemisphereLight(0xffffff,0x246b83,2.8));const sun=new THREE.DirectionalLight(0xffefc5,2.3);sun.position.set(-20,30,15);scene.add(sun);
+const seaGeo=new THREE.PlaneGeometry(220,220,70,70),pos=seaGeo.attributes.position,base=[];
+for(let i=0;i<pos.count;i++)base.push([pos.getX(i),pos.getY(i)]);
+const sea=new THREE.Mesh(seaGeo,new THREE.MeshStandardMaterial({color:0x1489ad,roughness:.28,metalness:.12,flatShading:true}));sea.rotation.x=-Math.PI/2;scene.add(sea);
+const lines=new THREE.GridHelper(210,60,0x7ae1e8,0x237f9b);lines.position.y=.05;lines.material.opacity=.15;lines.material.transparent=true;scene.add(lines);
const boat=new THREE.Group();scene.add(boat);
-const hull=new THREE.Mesh(new THREE.BoxGeometry(1.25,.45,2.7),new THREE.MeshStandardMaterial({color:0xf7f1d1,roughness:.42,metalness:.05}));hull.position.y=.42;hull.scale.set(.82,1,1);hull.castShadow=true;boat.add(hull);
-const keel=new THREE.Mesh(new THREE.ConeGeometry(.69,1.45,4),new THREE.MeshStandardMaterial({color:0xd75b4b,roughness:.5}));keel.rotation.x=Math.PI;keel.position.set(0,.13,.18);keel.scale.z=1.55;boat.add(keel);
+const hull=new THREE.Mesh(new THREE.BoxGeometry(1.05,.45,2.6),new THREE.MeshStandardMaterial({color:0xf7f1d1,roughness:.42}));hull.position.y=.43;boat.add(hull);
+const keel=new THREE.Mesh(new THREE.ConeGeometry(.67,1.4,4),new THREE.MeshStandardMaterial({color:0xd75b4b,roughness:.5}));keel.rotation.x=Math.PI;keel.position.set(0,.13,.15);keel.scale.z=1.5;boat.add(keel);
const mast=new THREE.Mesh(new THREE.CylinderGeometry(.035,.045,2.8,8),new THREE.MeshStandardMaterial({color:0x6e402d}));mast.position.set(0,1.8,.05);boat.add(mast);
-const sailShape=new THREE.Shape();sailShape.moveTo(.08,0);sailShape.lineTo(.08,2.25);sailShape.lineTo(1.35,.18);sailShape.closePath();const sail=new THREE.Mesh(new THREE.ShapeGeometry(sailShape),new THREE.MeshStandardMaterial({color:0xffd365,side:THREE.DoubleSide,roughness:.75}));sail.position.set(0,1.15,.03);sail.rotation.y=.06;boat.add(sail);
-const flag=new THREE.Mesh(new THREE.PlaneGeometry(.55,.33),new THREE.MeshBasicMaterial({color:0xea6464,side:THREE.DoubleSide}));flag.position.set(.29,3.13,.05);boat.add(flag);
-boat.position.set(0,.45,0);
-function island(x,z,s){const g=new THREE.Group();const rock=new THREE.Mesh(new THREE.DodecahedronGeometry(s,1),new THREE.MeshStandardMaterial({color:0x88705b,roughness:1,flatShading:true}));rock.scale.y=.48;rock.position.y=s*.34;g.add(rock);for(let i=0;i<4;i++){const palm=new THREE.Group(),trunk=new THREE.Mesh(new THREE.CylinderGeometry(.045,.07,s*.9,6),new THREE.MeshStandardMaterial({color:0x70452d}));trunk.position.y=s*.72;palm.add(trunk);const leaves=new THREE.Mesh(new THREE.ConeGeometry(s*.34,s*.35,6),new THREE.MeshStandardMaterial({color:0x24845f,flatShading:true}));leaves.position.y=s*1.2;palm.add(leaves);palm.position.set((Math.random()-.5)*s*.8,0,(Math.random()-.5)*s*.8);g.add(palm)}g.position.set(x,0,z);scene.add(g)}
-for(let i=0;i<23;i++){let a=Math.random()*Math.PI*2,d=15+Math.random()*75;island(Math.sin(a)*d,Math.cos(a)*d,1.3+Math.random()*2.3)}
-const buoys=[];function makeBuoy(){const g=new THREE.Group(),ring=new THREE.Mesh(new THREE.TorusGeometry(1.05,.11,10,30),new THREE.MeshStandardMaterial({color:0xffe276,emissive:0xd17815,emissiveIntensity:2.1,roughness:.25}));ring.rotation.x=Math.PI/2;ring.position.y=1.45;g.add(ring);const post=new THREE.Mesh(new THREE.CylinderGeometry(.12,.12,1.2,10),new THREE.MeshStandardMaterial({color:0xff6b55,roughness:.5}));post.position.y=.6;g.add(post);const angle=Math.random()*Math.PI*2,dist=17+Math.random()*22;g.position.set(boat.position.x+Math.sin(angle)*dist,0,boat.position.z-Math.cos(angle)*dist);scene.add(g);buoys.push(g)}
+const shape=new THREE.Shape();shape.moveTo(.08,0);shape.lineTo(.08,2.25);shape.lineTo(1.35,.18);shape.closePath();
+const sail=new THREE.Mesh(new THREE.ShapeGeometry(shape),new THREE.MeshStandardMaterial({color:0xffd365,side:THREE.DoubleSide,roughness:.75}));sail.position.set(0,1.15,.03);sail.rotation.y=.06;boat.add(sail);boat.position.set(0,.48,0);
+function island(x,z,s){const g=new THREE.Group(),rock=new THREE.Mesh(new THREE.DodecahedronGeometry(s,1),new THREE.MeshStandardMaterial({color:0x88705b,roughness:1,flatShading:true}));rock.scale.y=.48;rock.position.y=s*.34;g.add(rock);for(let i=0;i<4;i++){const palm=new THREE.Group(),trunk=new THREE.Mesh(new THREE.CylinderGeometry(.045,.07,s*.9,6),new THREE.MeshStandardMaterial({color:0x70452d}));trunk.position.y=s*.72;palm.add(trunk);const leaves=new THREE.Mesh(new THREE.ConeGeometry(s*.34,s*.35,6),new THREE.MeshStandardMaterial({color:0x24845f,flatShading:true}));leaves.position.y=s*1.2;palm.add(leaves);palm.position.set((Math.random()-.5)*s*.8,0,(Math.random()-.5)*s*.8);g.add(palm)}g.position.set(x,0,z);scene.add(g)}
+for(let i=0;i<23;i++){const a=Math.random()*Math.PI*2,d=15+Math.random()*75;island(Math.sin(a)*d,Math.cos(a)*d,1.3+Math.random()*2.3)}
+const buoys=[];function addBuoy(){const g=new THREE.Group(),ring=new THREE.Mesh(new THREE.TorusGeometry(1.05,.11,10,30),new THREE.MeshStandardMaterial({color:0xffe276,emissive:0xd17815,emissiveIntensity:2.1,roughness:.25}));ring.rotation.x=Math.PI/2;ring.position.y=1.45;g.add(ring);const post=new THREE.Mesh(new THREE.CylinderGeometry(.12,.12,1.2,10),new THREE.MeshStandardMaterial({color:0xff6b55,roughness:.5}));post.position.y=.6;g.add(post);const a=Math.random()*Math.PI*2,d=17+Math.random()*22;g.position.set(boat.position.x+Math.sin(a)*d,0,boat.position.z-Math.cos(a)*d);scene.add(g);buoys.push(g)}
+for(let i=0;i<4;i++)addBuoy();
let turn=0,heading=0,running=false,score=0,last=0,boost=false;
const scoreEl=document.querySelector("#score"),speedEl=document.querySelector("#speed"),cover=document.querySelector("#cover");
-function setTurn(v){turn=v}function begin(){running=true;cover.style.display="none";last=0}
-function hold(el,value){el.addEventListener("pointerdown",e=>{e.preventDefault();setTurn(value);el.setPointerCapture&&el.setPointerCapture(e.pointerId)});["pointerup","pointercancel","pointerleave"].forEach(type=>el.addEventListener(type,()=>setTurn(0)))}
-hold(document.querySelector("#left"),1);hold(document.querySelector("#right"),-1);
-document.querySelector("#start").addEventListener("click",begin);
-addEventListener("keydown",e=>{let k=e.key.toLowerCase();if(k==="arrowleft"||k==="a"){e.preventDefault();turn=1}if(k==="arrowright"||k==="d"){e.preventDefault();turn=-1}if(k==="w"||k==="arrowup"){boost=true}if((k===" "||k==="enter")&&!running)begin()});addEventListener("keyup",e=>{let k=e.key.toLowerCase();if(k==="arrowleft"||k==="a"||k==="arrowright"||k==="d")turn=0;if(k==="w"||k==="arrowup")boost=false});
-function animate(t){requestAnimationFrame(animate);const dt=Math.min(40,last?t-last:16);last=t;
-for(let i=0;i<positions.count;i++){const x=base[i][0],z=base[i][1];positions.setZ(i,Math.sin(x*.13+t*.0018)*.18+Math.cos(z*.1+t*.0012)*.12)}positions.needsUpdate=true;
-if(running){const pace=(boost?.019:.0125)*dt;heading+=turn*dt*.00145;boat.position.x-=Math.sin(heading)*pace;boat.position.z-=Math.cos(heading)*pace;boat.rotation.y=heading;boat.position.y=.46+Math.sin(t*.003)*.06;boat.rotation.z=Math.sin(t*.0028)*.035;boat.rotation.x=Math.cos(t*.003)*.025;speedEl.textContent=boost?"FAST":"FULL";
-for(let i=buoys.length-1;i>=0;i--){const b=buoys[i];b.rotation.y+=dt*.0015;b.children[0].rotation.z+=dt*.001;const distance=boat.position.distanceTo(b.position);if(distance<1.35){scene.remove(b);buoys.splice(i,1);score++;scoreEl.textContent=score;makeBuoy()}}
+function begin(){running=true;cover.style.display="none";last=0}function steer(v){turn=v}
+function hold(el,v){el.addEventListener("pointerdown",e=>{e.preventDefault();steer(v)});["pointerup","pointercancel","pointerleave"].forEach(type=>el.addEventListener(type,()=>steer(0)))}
+hold(document.querySelector("#left"),1);hold(document.querySelector("#right"),-1);document.querySelector("#start").addEventListener("click",begin);
+addEventListener("keydown",e=>{const k=e.key.toLowerCase();if(k==="arrowleft"||k==="a"){e.preventDefault();turn=1}if(k==="arrowright"||k==="d"){e.preventDefault();turn=-1}if(k==="w"||k==="arrowup")boost=true;if((k===" "||k==="enter")&&!running)begin()});
+addEventListener("keyup",e=>{const k=e.key.toLowerCase();if(k==="arrowleft"||k==="a"||k==="arrowright"||k==="d")turn=0;if(k==="w"||k==="arrowup")boost=false});
+function loop(t){requestAnimationFrame(loop);const dt=Math.min(40,last?t-last:16);last=t;for(let i=0;i<pos.count;i++)pos.setZ(i,Math.sin(base[i][0]*.13+t*.0018)*.18+Math.cos(base[i][1]*.1+t*.0012)*.12);pos.needsUpdate=true;
+if(running){const pace=(boost ? .019 : .0125)*dt;heading+=turn*dt*.00145;boat.position.x-=Math.sin(heading)*pace;boat.position.z-=Math.cos(heading)*pace;boat.rotation.y=heading;boat.position.y=.48+Math.sin(t*.003)*.06;boat.rotation.z=Math.sin(t*.0028)*.035;boat.rotation.x=Math.cos(t*.003)*.025;speedEl.textContent=boost?"FAST":"FULL";
+for(let i=buoys.length-1;i>=0;i--){const b=buoys[i];b.rotation.y+=dt*.0015;b.children[0].rotation.z+=dt*.001;if(boat.position.distanceTo(b.position)<1.35){scene.remove(b);buoys.splice(i,1);score++;scoreEl.textContent=score;addBuoy()}}
const backX=boat.position.x+Math.sin(heading)*8,backZ=boat.position.z+Math.cos(heading)*8;camera.position.lerp(new THREE.Vector3(backX,5.5,backZ),.055);camera.lookAt(boat.position.x-Math.sin(heading)*4,.7,boat.position.z-Math.cos(heading)*4)}
renderer.render(scene,camera)}
-addEventListener("resize",()=>{camera.aspect=innerWidth/innerHeight;camera.updateProjectionMatrix();renderer.setSize(innerWidth,innerHeight)});animate(0);
+addEventListener("resize",()=>{camera.aspect=innerWidth/innerHeight;camera.updateProjectionMatrix();renderer.setSize(innerWidth,innerHeight)});loop(0);
</script></body></html>
-
-
for(let i=0;i<4;i++)makeBuoy();
for(let i=0;i<4;i++)makeBuoy();
← Histórico de versões