Meta Description" name="description" />

Share this result

Previews are deleted daily. Get a permanent share link sent to your inbox:
Script
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> <title>AR Burger</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { background: #111; overflow: hidden; font-family: 'Georgia', serif; } #overlay { position: fixed; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; background: linear-gradient(135deg, #1a0a00, #111); z-index: 10; } #overlay h1 { color: #f5c842; font-size: clamp(28px, 6vw, 48px); letter-spacing: 4px; text-transform: uppercase; text-shadow: 0 0 30px #f5c84260; margin-bottom: 8px; } #overlay p { color: #ffffff70; font-size: 14px; letter-spacing: 2px; margin-bottom: 40px; } #preview-canvas { border-radius: 20px; margin-bottom: 32px; box-shadow: 0 0 60px #f5c84230; } .btn { padding: 16px 44px; border: none; border-radius: 50px; font-size: 16px; font-weight: bold; letter-spacing: 2px; cursor: pointer; text-transform: uppercase; transition: all 0.2s; } #ar-btn { background: #f5c842; color: #1a0a00; box-shadow: 0 0 30px #f5c84250; } #ar-btn:hover { transform: scale(1.05); box-shadow: 0 0 50px #f5c84280; } #ar-btn:disabled { background: #555; color: #999; box-shadow: none; cursor: not-allowed; } #not-supported { margin-top: 14px; color: #ff6b6b; font-size: 13px; letter-spacing: 1px; display: none; } /* AR UI overlay (shown during AR session) */ #ar-ui { position: fixed; inset: 0; pointer-events: none; z-index: 20; display: none; } #ar-ui.active { display: block; } #ar-hint { position: absolute; bottom: 130px; left: 50%; transform: translateX(-50%); background: #00000099; color: #fff; padding: 10px 22px; border-radius: 30px; font-size: 14px; letter-spacing: 1px; white-space: nowrap; } #ar-hint.placed { display: none; } #exit-btn { position: absolute; top: 30px; right: 20px; background: #00000088; color: #fff; border: 1px solid #ffffff40; border-radius: 30px; padding: 10px 20px; font-size: 13px; cursor: pointer; pointer-events: all; letter-spacing: 1px; } #tap-hint { position: absolute; bottom: 60px; left: 50%; transform: translateX(-50%); color: #f5c842; font-size: 13px; letter-spacing: 2px; text-align: center; pointer-events: none; } #scale-btns { position: absolute; bottom: 50px; right: 20px; display: flex; flex-direction: column; gap: 10px; pointer-events: all; } #scale-btns button { width: 44px; height: 44px; border-radius: 50%; border: none; background: #00000099; color: #fff; font-size: 22px; cursor: pointer; border: 1px solid #ffffff30; } </style> </head> <body> <!-- Landing screen with 3D preview --> <div id="overlay"> <h1>Cheeseburger</h1> <p>AR Menu Experience</p> <canvas id="preview-canvas" width="280" height="200"></canvas> <button class="btn" id="ar-btn">πŸ“± Launch AR</button> <div id="not-supported">WebXR AR not supported on this device/browser</div> <p style="margin-top:16px;color:#ffffff40;font-size:11px;">Best on Android Chrome Β· Requires camera permission</p> </div> <!-- AR session UI --> <div id="ar-ui"> <div id="ar-hint">πŸ” Move camera slowly over a flat surface</div> <div id="tap-hint">Tap to place burger</div> <div id="scale-btns"> <button id="scale-up">οΌ‹</button> <button id="scale-down">-</button> </div> <button id="exit-btn">βœ• Exit AR</button> </div> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> <script> // ─── BURGER BUILDER ─────────────────────────────────────────────── function buildBurger(scene) { const group = new THREE.Group(); function ellipsoid(rx, ry, rz, color, rough = 0.65, metal = 0) { const g = new THREE.SphereGeometry(1, 48, 48); g.applyMatrix4(new THREE.Matrix4().makeScale(rx, ry, rz)); const m = new THREE.MeshStandardMaterial({ color, roughness: rough, metalness: metal }); const mesh = new THREE.Mesh(g, m); mesh.castShadow = mesh.receiveShadow = true; return mesh; } function pattyDisk(rx, ry, color) { const g = new THREE.CylinderGeometry(rx, rx * 1.06, ry, 48, 4); const pos = g.attributes.position; for (let i = 0; i < pos.count; i++) { const y = pos.getY(i); if (Math.abs(y) < ry * 0.45) { pos.setX(i, pos.getX(i) + (Math.random() - 0.5) * 0.015); pos.setZ(i, pos.getZ(i) + (Math.random() - 0.5) * 0.015); } pos.setY(i, y + (Math.random() - 0.5) * 0.008); } g.computeVertexNormals(); const m = new THREE.MeshStandardMaterial({ color, roughness: 0.92 }); const mesh = new THREE.Mesh(g, m); mesh.castShadow = true; return mesh; } function cheeseDrape(yPos) { const shape = new THREE.Shape(); const s = 0.285; shape.moveTo(-s, -s); shape.lineTo(s, -s); shape.lineTo(s, s); shape.lineTo(-s, s); shape.closePath(); const g = new THREE.ShapeGeometry(shape, 6); g.applyMatrix4(new THREE.Matrix4().makeRotationX(-Math.PI / 2)); const pos = g.attributes.position; for (let i = 0; i < pos.count; i++) { const x = pos.getX(i), z = pos.getZ(i); const d = Math.sqrt(x * x + z * z); pos.setY(i, pos.getY(i) - Math.max(0, d - 0.13) * 0.45); } g.computeVertexNormals(); const m = new THREE.MeshStandardMaterial({ color: 0xf5b800, roughness: 0.28, metalness: 0.04, side: THREE.DoubleSide }); const mesh = new THREE.Mesh(g, m); mesh.position.y = yPos; mesh.castShadow = true; return mesh; } // Scale: real burger ~11cm tall β†’ 0.11 in meters const S = 0.2; // 20cm for good AR visibility let y = 0; // Bottom bun const bbun = ellipsoid(S * 1.4, S * 0.4, S * 1.3, 0xcc7a18); bbun.position.y = y + S * 0.4; group.add(bbun); y += S * 0.65; // Bottom bun crown const bbc = ellipsoid(S * 1.38, S * 0.1, S * 1.28, 0xe09030, 0.55); bbc.position.y = y; group.add(bbc); y += S * 0.08; // Cheese bottom group.add(cheeseDrape(y + S * 0.06)); y += S * 0.08; // Patty const pat = pattyDisk(S * 1.28, S * 0.35, 0x1e0d04); pat.position.y = y + S * 0.175; group.add(pat); y += S * 0.38; // Char marks for (let i = -1; i <= 1; i++) { const cg = new THREE.BoxGeometry(S * 2.4, S * 0.02, S * 0.1); const cm = new THREE.MeshStandardMaterial({ color: 0x080301, roughness: 1 }); const ch = new THREE.Mesh(cg, cm); ch.position.set(0, y - S * 0.03, i * S * 0.35); ch.rotation.y = 0.12; group.add(ch); } // Cheese top group.add(cheeseDrape(y + S * 0.02)); y += S * 0.14; // Top bun base const tbbase = ellipsoid(S * 1.38, S * 0.18, S * 1.28, 0xc07010); tbbase.position.y = y + S * 0.12; group.add(tbbase); y += S * 0.18; // Top bun dome const tdome = ellipsoid(S * 1.36, S * 0.82, S * 1.26, 0xd4872a, 0.52, 0.02); tdome.position.y = y + S * 0.72; group.add(tdome); // Glaze const gg = new THREE.SphereGeometry(1, 32, 32); gg.applyMatrix4(new THREE.Matrix4().makeScale(S * 1.12, S * 0.55, S * 1.08)); const gm = new THREE.MeshStandardMaterial({ color: 0xe8a030, roughness: 0.2, metalness: 0.1, transparent: true, opacity: 0.55 }); const glaze = new THREE.Mesh(gg, gm); glaze.position.y = y + S * 1.08; group.add(glaze); const topY = y + S * 1.28; // Sesame seeds const seedPositions = [[0,0],[0.55,0.3],[-0.5,0.35],[0.2,-0.6],[-0.3,-0.55],[0.65,-0.2],[-0.65,-0.1],[0,0.7]]; seedPositions.forEach(([sx, sz]) => { const sg = new THREE.SphereGeometry(S * 0.045, 8, 8); sg.applyMatrix4(new THREE.Matrix4().makeScale(1.4, 0.65, 1)); const sm = new THREE.MeshStandardMaterial({ color: 0xf0e0a0, roughness: 0.8 }); const seed = new THREE.Mesh(sg, sm); seed.position.set(sx * S, topY, sz * S); group.add(seed); }); // Lift so base sits at y=0 group.position.y = 0; scene.add(group); return group; } // ─── PREVIEW (landing screen) ────────────────────────────────────── (function initPreview() { const canvas = document.getElementById('preview-canvas'); const scene = new THREE.Scene(); scene.background = new THREE.Color(0x1a0a00); const camera = new THREE.PerspectiveCamera(40, 280 / 200, 0.01, 50); camera.position.set(0, 0.18, 0.7); camera.lookAt(0, 0.1, 0); const renderer = new THREE.WebGLRenderer({ canvas, antialias: true }); renderer.setSize(280, 200); renderer.shadowMap.enabled = true; scene.add(new THREE.AmbientLight(0xfff5e0, 0.6)); const dl = new THREE.DirectionalLight(0xfff5cc, 2.5); dl.position.set(2, 4, 2); dl.castShadow = true; scene.add(dl); scene.add(new THREE.PointLight(0xffaa44, 1.0, 10)).position.set(-2, 1.5, 2); const burger = buildBurger(scene); burger.position.y = 0; let t = 0; function loop() { requestAnimationFrame(loop); t += 0.016; burger.rotation.y = t * 0.5; burger.position.y = Math.sin(t * 0.8) * 0.008; renderer.render(scene, camera); } loop(); })(); // ─── WebXR AR SESSION ───────────────────────────────────────────── const arBtn = document.getElementById('ar-btn'); const arUI = document.getElementById('ar-ui'); const arHint = document.getElementById('ar-hint'); const tapHint = document.getElementById('tap-hint'); const exitBtn = document.getElementById('exit-btn'); const notSupported = document.getElementById('not-supported'); // Check WebXR support if (!('xr' in navigator)) { arBtn.disabled = true; notSupported.style.display = 'block'; notSupported.textContent = 'WebXR not available. Use Android Chrome.'; } else { navigator.xr.isSessionSupported('immersive-ar').then(supported => { if (!supported) { arBtn.disabled = true; notSupported.style.display = 'block'; notSupported.textContent = 'AR not supported on this device/browser.'; } }); } let xrSession = null; let hitTestSource = null; let hitTestSourceRequested = false; let burgerPlaced = false; let arBurger = null; let burgerScale = 1; arBtn.addEventListener('click', startAR); exitBtn.addEventListener('click', () => { if (xrSession) xrSession.end(); }); document.getElementById('scale-up').addEventListener('click', () => { if (arBurger) { burgerScale = Math.min(3, burgerScale + 0.2); arBurger.scale.setScalar(burgerScale); } }); document.getElementById('scale-down').addEventListener('click', () => { if (arBurger) { burgerScale = Math.max(0.3, burgerScale - 0.2); arBurger.scale.setScalar(burgerScale); } }); async function startAR() { const sessionInit = { requiredFeatures: ['hit-test'], optionalFeatures: ['dom-overlay', 'light-estimation'], domOverlay: { root: document.body } }; try { const session = await navigator.xr.requestSession('immersive-ar', sessionInit); onSessionStarted(session); } catch (e) { notSupported.style.display = 'block'; notSupported.textContent = 'Could not start AR: ' + e.message; } } // AR Three.js setup const arScene = new THREE.Scene(); const arCamera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 20); const arRenderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); arRenderer.setPixelRatio(window.devicePixelRatio); arRenderer.setSize(window.innerWidth, window.innerHeight); arRenderer.xr.enabled = true; arRenderer.outputEncoding = THREE.sRGBEncoding; arRenderer.shadowMap.enabled = true; document.body.appendChild(arRenderer.domElement); arRenderer.domElement.style.display = 'none'; arRenderer.domElement.style.position = 'fixed'; arRenderer.domElement.style.inset = '0'; arRenderer.domElement.style.zIndex = '5'; // Lighting for AR (will blend with real world) arScene.add(new THREE.AmbientLight(0xffffff, 1.2)); const arDirLight = new THREE.DirectionalLight(0xfff8ee, 1.5); arDirLight.position.set(1, 3, 1); arDirLight.castShadow = true; arScene.add(arDirLight); // Reticle (placement ring) const reticleGeo = new THREE.RingGeometry(0.08, 0.11, 32); reticleGeo.applyMatrix4(new THREE.Matrix4().makeRotationX(-Math.PI / 2)); const reticle = new THREE.Mesh(reticleGeo, new THREE.MeshBasicMaterial({ color: 0xf5c842 })); reticle.visible = false; reticle.matrixAutoUpdate = false; arScene.add(reticle); // Shadow receiver plane const shadowGeo = new THREE.CircleGeometry(0.5, 32); shadowGeo.applyMatrix4(new THREE.Matrix4().makeRotationX(-Math.PI / 2)); const shadowMat = new THREE.ShadowMaterial({ opacity: 0.4 }); const shadowPlane = new THREE.Mesh(shadowGeo, shadowMat); shadowPlane.receiveShadow = true; shadowPlane.visible = false; arScene.add(shadowPlane); // Tap to place arRenderer.domElement.addEventListener('click', () => { if (reticle.visible && !burgerPlaced) { placeBurger(); } }); function placeBurger() { if (!arBurger) { arBurger = buildBurger(arScene); arBurger.visible = false; } const pos = new THREE.Vector3(); pos.setFromMatrixPosition(reticle.matrix); arBurger.position.copy(pos); arBurger.visible = true; shadowPlane.position.copy(pos); shadowPlane.visible = true; burgerPlaced = true; reticle.visible = false; arHint.classList.add('placed'); tapHint.style.display = 'none'; } async function onSessionStarted(session) { xrSession = session; burgerPlaced = false; burgerScale = 1; hitTestSourceRequested = false; hitTestSource = null; arRenderer.xr.setReferenceSpaceType('local'); await arRenderer.xr.setSession(session); // Show AR UI document.getElementById('overlay').style.display = 'none'; arRenderer.domElement.style.display = 'block'; arUI.classList.add('active'); arHint.classList.remove('placed'); tapHint.style.display = 'block'; session.addEventListener('end', onSessionEnded); arRenderer.setAnimationLoop(renderAR); } function onSessionEnded() { xrSession = null; hitTestSource = null; hitTestSourceRequested = false; arRenderer.domElement.style.display = 'none'; arUI.classList.remove('active'); document.getElementById('overlay').style.display = 'flex'; arRenderer.setAnimationLoop(null); // Remove burger from scene so it resets next time if (arBurger) { arScene.remove(arBurger); arBurger = null; } } const clock = new THREE.Clock(); function renderAR(timestamp, frame) { if (frame) { const refSpace = arRenderer.xr.getReferenceSpace(); const session = arRenderer.xr.getSession(); // Init hit test if (!hitTestSourceRequested) { session.requestReferenceSpace('viewer').then(viewerSpace => { session.requestHitTestSource({ space: viewerSpace }).then(src => { hitTestSource = src; }); }); hitTestSourceRequested = true; session.addEventListener('end', () => { hitTestSourceRequested = false; hitTestSource = null; }); } if (hitTestSource && !burgerPlaced) { const results = frame.getHitTestResults(hitTestSource); if (results.length > 0) { const pose = results[0].getPose(refSpace); reticle.visible = true; reticle.matrix.fromArray(pose.transform.matrix); } else { reticle.visible = false; } } } // Gentle burger animation const t = clock.getElapsedTime(); if (arBurger && burgerPlaced) { arBurger.rotation.y = t * 0.4; } arRenderer.render(arScene, arCamera); } window.addEventListener('resize', () => { arCamera.aspect = window.innerWidth / window.innerHeight; arCamera.updateProjectionMatrix(); arRenderer.setSize(window.innerWidth, window.innerHeight); }); </script> </body> </html>
Landing Page
This ad does not have a landing page available
Network Timeline
Performance Summary

2

Requests

2

Domains

135KB

Transfer Size

606KB

Content Size

894.0ms

Dom Content Loaded

308.0ms

First Paint

894.0ms

Load Time
Domain Breakdown
Transfer Size (bytes)
Loading...
Content Size (bytes)
Loading...
Header Size (bytes)
Loading...
Requests
Loading...
Timings (ms)
Loading...
Total Time
Loading...
Content Breakdown
Transfer Size (bytes)
Loading...
Content Size (bytes)
Loading...
Header Size (bytes)
Loading...
Requests
Loading...