animation2code benchmark
For best compatibility, please view this dashboard in a Chrome browser.
← back to Retro Sine Wave 〰

model output

GPT-5.4

Retro Sine Wave 〰

A 0.81T 0.24
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>Striped Morph Animation</title>
7<style>
8  :root{
9    --bg1:#2b2740;
10    --bg2:#4a4568;
11    --line:#ff7a5f;
12    --glow:rgba(255,122,95,.55);
13  }
14
15  html,body{
16    margin:0;
17    width:100%;
18    height:100%;
19    overflow:hidden;
20    background:
21      radial-gradient(1200px 900px at 100% 0%, #5a547b 0%, #433e5f 28%, #312c49 58%, #26223a 100%);
22  }
23
24  body{
25    display:grid;
26    place-items:center;
27    font-family:system-ui,sans-serif;
28  }
29
30  .scene{
31    position:relative;
32    width:min(62vmin,520px);
33    aspect-ratio:1/1;
34    filter: saturate(1.05);
35  }
36
37  .shape{
38    position:absolute;
39    inset:0;
40    display:block;
41    filter: drop-shadow(0 0 6px rgba(255,120,90,.18));
42  }
43
44  .line{
45    position:absolute;
46    left:50%;
47    top:50%;
48    height:2px;
49    border-radius:999px;
50    background:linear-gradient(90deg,
51      rgba(255,122,95,.18) 0%,
52      rgba(255,122,95,.95) 18%,
53      #ff7a5f 50%,
54      rgba(255,122,95,.95) 82%,
55      rgba(255,122,95,.18) 100%);
56    box-shadow:
57      0 0 6px var(--glow),
58      0 0 12px rgba(255,122,95,.18);
59    transform-origin:center center;
60    opacity:.96;
61    animation: morph 4.8s cubic-bezier(.55,.02,.35,1) infinite;
62    will-change: transform, width;
63  }
64
65  @keyframes morph{
66    0%,100%{
67      transform:translate(calc(var(--x0) * 1px), calc(var(--y) * 1px));
68      width:calc(var(--w0) * 1px);
69    }
70    50%{
71      transform:translate(calc(var(--x1) * 1px), calc(var(--y) * 1px));
72      width:calc(var(--w1) * 1px);
73    }
74  }
75
76  /* subtle overall breathing like the reference softness */
77  .shape{
78    animation: drift 4.8s cubic-bezier(.55,.02,.35,1) infinite;
79  }
80  @keyframes drift{
81    0%,100%{ transform:translateX(-8px); }
82    50%{ transform:translateX(10px); }
83  }
84</style>
85</head>
86<body>
87  <div class="scene">
88    <div class="shape" id="shape"></div>
89  </div>
90
91<script>
92(() => {
93  const shape = document.getElementById('shape');
94
95  // Horizontal scanlines approximating the striped morph seen in the frames:
96  // from a "b"-like silhouette to a "p"-like silhouette.
97  const count = 26;
98  const step = 11;
99  const ys = Array.from({length: count}, (_, i) => (i - (count - 1) / 2) * step);
100
101  function circleHalfWidth(y, r){
102    const v = r*r - y*y;
103    return v > 0 ? Math.sqrt(v) : 0;
104  }
105
106  // Left stem + right bowl (b)
107  function shapeB(y){
108    const stemLeft = -92, stemRight = -18;
109    const stemW = stemRight - stemLeft;
110
111    const cx = 28, cy = 0, r = 78;
112    const hw = circleHalfWidth(y - cy, r);
113    const bowlLeft = cx - hw;
114    const bowlRight = cx + hw;
115
116    const left = Math.min(stemLeft, bowlLeft);
117    const right = Math.max(stemRight, bowlRight);
118
119    // carve a slight waist / notch where stem meets bowl
120    let notch = 0;
121    if (Math.abs(y) < 18) notch = 10 - Math.abs(y) * 0.35;
122
123    return {
124      x: (left + right) / 2 + notch * 0.15,
125      w: Math.max(stemW, right - left - notch)
126    };
127  }
128
129  // Descender stem + upper bowl (p)
130  function shapeP(y){
131    const stemLeft = 8, stemRight = 82;
132    const stemW = stemRight - stemLeft;
133
134    const cx = -18, cy = -18, r = 82;
135    const hw = circleHalfWidth(y - cy, r);
136    const bowlLeft = cx - hw;
137    const bowlRight = cx + hw;
138
139    let left = Math.min(stemLeft, bowlLeft);
140    let right = Math.max(stemRight, bowlRight);
141
142    // lower descender extension
143    if (y > 34){
144      left = Math.min(left, -92);
145      right = Math.max(right, 18);
146    }
147
148    // slight narrowing near join
149    let notch = 0;
150    if (y > -6 && y < 28) notch = 12 - Math.abs(y - 11) * 0.45;
151
152    return {
153      x: (left + right) / 2 - notch * 0.12,
154      w: Math.max(stemW, right - left - notch)
155    };
156  }
157
158  ys.forEach((y, i) => {
159    const a = shapeB(y);
160    const b = shapeP(y);
161
162    const line = document.createElement('div');
163    line.className = 'line';
164
165    // small deterministic irregularity to mimic the uneven line lengths/offsets
166    const jitterX0 = Math.sin(i * 1.73) * 4;
167    const jitterX1 = Math.cos(i * 1.21) * 4;
168    const jitterW0 = Math.sin(i * 0.91) * 10;
169    const jitterW1 = Math.cos(i * 0.77) * 10;
170
171    line.style.setProperty('--y', y.toFixed(2));
172    line.style.setProperty('--x0', (a.x + jitterX0).toFixed(2));
173    line.style.setProperty('--w0', Math.max(18, a.w + jitterW0).toFixed(2));
174    line.style.setProperty('--x1', (b.x + jitterX1).toFixed(2));
175    line.style.setProperty('--w1', Math.max(18, b.w + jitterW1).toFixed(2));
176
177    // stagger slightly so the morph feels organic but still cohesive
178    line.style.animationDelay = `${(-i * 0.035).toFixed(3)}s`;
179    line.style.opacity = (0.72 + (1 - Math.abs(y)/150) * 0.28).toFixed(2);
180
181    shape.appendChild(line);
182  });
183})();
184</script>
185</body>
186</html>