animation2code benchmark
For best compatibility, please view this dashboard in a Chrome browser.
← back to Only CSS: Responsive City Drone View Black

model output

GPT-5.4

Only CSS: Responsive City Drone View Black

A 0.50T 0.43
compare with ground truth →
1<!DOCTYPE html>
2<html lang="en">
3<head>
4<meta charset="UTF-8" />
5<meta name="viewport" content="width=device-width,initial-scale=1" />
6<title>Dark Pillar Flythrough</title>
7<style>
8  :root{
9    --bg:#000;
10    --face1:#141414;
11    --face2:#1d1d1d;
12    --face3:#262626;
13  }
14  html,body{
15    margin:0;
16    height:100%;
17    overflow:hidden;
18    background:var(--bg);
19  }
20  canvas{
21    display:block;
22    width:100vw;
23    height:100vh;
24    background:#000;
25  }
26</style>
27</head>
28<body>
29<canvas id="c"></canvas>
30<script>
31(() => {
32  const canvas = document.getElementById('c');
33  const ctx = canvas.getContext('2d');
34
35  let w = 0, h = 0, cx = 0, cy = 0;
36  function resize() {
37    const dpr = Math.min(devicePixelRatio || 1, 2);
38    w = canvas.width = Math.round(innerWidth * dpr);
39    h = canvas.height = Math.round(innerHeight * dpr);
40    canvas.style.width = innerWidth + 'px';
41    canvas.style.height = innerHeight + 'px';
42    ctx.setTransform(1,0,0,1,0,0);
43    ctx.scale(dpr, dpr);
44    w = innerWidth;
45    h = innerHeight;
46    cx = w / 2;
47    cy = h / 2;
48  }
49  addEventListener('resize', resize);
50  resize();
51
52  // Fixed sparse arrangement to match the stills:
53  // tall, dark rectangular prisms around a central void.
54  const pillars = [
55    {x:-8.8, z:18, bw:1.8, bd:1.8, h:18, yaw:-0.55},
56    {x:-5.8, z:10, bw:0.9, bd:0.9, h:14, yaw:-0.25},
57    {x:-1.2, z:8.5, bw:1.2, bd:1.2, h:22, yaw:0.02},
58    {x: 0.2, z:7.2, bw:0.7, bd:0.7, h:24, yaw:0.00},
59    {x: 1.8, z:8.8, bw:0.9, bd:0.9, h:20, yaw:0.03},
60    {x: 4.8, z:9.5, bw:0.9, bd:0.9, h:26, yaw:0.18},
61    {x: 7.2, z:12.5, bw:1.0, bd:1.0, h:13, yaw:0.45},
62    {x: 9.0, z:11.0, bw:1.3, bd:1.3, h:16, yaw:0.42},
63    {x: 6.8, z:6.0, bw:1.2, bd:1.2, h:28, yaw:0.22},
64    {x:-0.2, z:5.8, bw:0.55, bd:0.55, h:18, yaw:0.00},
65    {x: 3.2, z:5.2, bw:0.95, bd:0.95, h:21, yaw:0.08},
66    {x:-10.5,z:5.0, bw:2.2, bd:2.2, h:12, yaw:-0.65},
67    // central foreground pillar visible at start, then drops out of frame
68    {x:-0.6, z:2.2, bw:1.8, bd:1.8, h:8.5, yaw:-0.18}
69  ];
70
71  const cam = {
72    x: 0,
73    y: 7.8,
74    z: -1.2,
75    yaw: 0.0,
76    pitch: -0.92, // looking downward
77    fov: 760
78  };
79
80  const duration = 5200; // smooth single pass similar to frame sequence
81  let start = performance.now();
82
83  function rotY(x, z, a){
84    const c = Math.cos(a), s = Math.sin(a);
85    return [x*c - z*s, x*s + z*c];
86  }
87
88  function project(wx, wy, wz){
89    let x = wx - cam.x;
90    let y = wy - cam.y;
91    let z = wz - cam.z;
92
93    // camera yaw
94    let c = Math.cos(-cam.yaw), s = Math.sin(-cam.yaw);
95    let tx = x*c - z*s;
96    let tz = x*s + z*c;
97    x = tx; z = tz;
98
99    // camera pitch
100    c = Math.cos(-cam.pitch); s = Math.sin(-cam.pitch);
101    let ty = y*c - z*s;
102    tz = y*s + z*c;
103    y = ty; z = tz;
104
105    if (z <= 0.05) return null;
106    const scale = cam.fov / z;
107    return { x: cx + x * scale, y: cy + y * scale, z, scale };
108  }
109
110  function drawFace(points, fill){
111    ctx.beginPath();
112    ctx.moveTo(points[0].x, points[0].y);
113    for(let i=1;i<points.length;i++) ctx.lineTo(points[i].x, points[i].y);
114    ctx.closePath();
115    ctx.fillStyle = fill;
116    ctx.fill();
117  }
118
119  function drawPillar(p){
120    const hw = p.bw/2, hd = p.bd/2;
121    const y0 = 0, y1 = p.h;
122
123    const base = [
124      [-hw, y0, -hd], [ hw, y0, -hd], [ hw, y0, hd], [-hw, y0, hd],
125      [-hw, y1, -hd], [ hw, y1, -hd], [ hw, y1, hd], [-hw, y1, hd]
126    ].map(([x,y,z]) => {
127      const r = rotY(x,z,p.yaw);
128      return { x: r[0] + p.x, y, z: r[1] + p.z };
129    });
130
131    const pts = base.map(v => project(v.x, v.y, v.z));
132    if (pts.some(v => !v)) return;
133
134    const faces = [
135      { idx:[0,1,5,4], fill:getComputedStyle(document.documentElement).getPropertyValue('--face1').trim() }, // back-ish
136      { idx:[1,2,6,5], fill:getComputedStyle(document.documentElement).getPropertyValue('--face2').trim() }, // right
137      { idx:[2,3,7,6], fill:getComputedStyle(document.documentElement).getPropertyValue('--face1').trim() }, // front-ish
138      { idx:[3,0,4,7], fill:getComputedStyle(document.documentElement).getPropertyValue('--face2').trim() }, // left
139      { idx:[4,5,6,7], fill:getComputedStyle(document.documentElement).getPropertyValue('--face3').trim() }  // top
140    ];
141
142    // Painter's algorithm by average depth
143    faces.sort((a,b)=>{
144      const za = a.idx.reduce((s,i)=>s+pts[i].z,0)/a.idx.length;
145      const zb = b.idx.reduce((s,i)=>s+pts[i].z,0)/b.idx.length;
146      return zb - za;
147    });
148
149    for(const f of faces){
150      drawFace(f.idx.map(i => pts[i]), f.fill);
151    }
152  }
153
154  function frame(now){
155    const t = Math.min(1, (now - start) / duration);
156
157    // Smooth forward drift with slight rightward arc.
158    const ease = t*t*(3 - 2*t); // smoothstep
159    cam.z = -1.2 + ease * 10.8;
160    cam.x = ease * 1.35;
161    cam.y = 7.8 + ease * 0.35;
162    cam.yaw = ease * 0.16;
163    cam.pitch = -0.92 + ease * 0.06;
164
165    ctx.clearRect(0,0,w,h);
166
167    pillars
168      .slice()
169      .sort((a,b) => {
170        const da = (a.z - cam.z) ** 2 + (a.x - cam.x) ** 2;
171        const db = (b.z - cam.z) ** 2 + (b.x - cam.x) ** 2;
172        return db - da;
173      })
174      .forEach(drawPillar);
175
176    requestAnimationFrame(frame);
177  }
178
179  requestAnimationFrame(frame);
180})();
181</script>
182</body>
183</html>