animation2code benchmark
For best compatibility, please view this dashboard in a Chrome browser.
← back to Only CSS: Joint Animation

model output

GPT-5.4

Only CSS: Joint Animation

A 0.82T 0.50
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.0" />
6<title>Pivoting Bars Animation</title>
7<style>
8  html, body {
9    margin: 0;
10    width: 100%;
11    height: 100%;
12    overflow: hidden;
13    background: #fff;
14    font-family: sans-serif;
15  }
16
17  .stage {
18    position: relative;
19    width: 100vw;
20    height: 100vh;
21    background: #ffffff;
22  }
23
24  /* overall placement roughly centered like the frames */
25  .rig {
26    position: absolute;
27    left: 50%;
28    top: 50%;
29    width: 420px;
30    height: 260px;
31    transform: translate(-50%, -50%);
32  }
33
34  .bar {
35    position: absolute;
36    width: 300px;
37    height: 70px;
38    transform-origin: 50px 35px;
39    opacity: .82;
40  }
41
42  .bar::before {
43    content: "";
44    position: absolute;
45    width: 14px;
46    height: 14px;
47    left: 33px;
48    top: 28px;
49    border-radius: 50%;
50    background: #ffd400;
51    box-shadow: 0 0 0 4px rgba(255,255,255,.95);
52  }
53
54  .gray {
55    background: #8f8f8f;
56    animation: grayMove 2.8s ease-in-out infinite;
57    z-index: 2;
58  }
59
60  .blue {
61    background: #3ea0d4;
62    animation: blueMove 2.8s ease-in-out infinite;
63    z-index: 1;
64  }
65
66  /* faint dashed "ghost" rectangles visible in intermediate frames */
67  .ghost {
68    position: absolute;
69    width: 300px;
70    height: 70px;
71    border: 1.5px dashed rgba(0,0,0,.28);
72    box-sizing: border-box;
73    pointer-events: none;
74    opacity: 0;
75  }
76
77  .ghost.grayGhost {
78    transform-origin: 50px 35px;
79    animation: grayGhost 2.8s ease-in-out infinite;
80    z-index: 0;
81  }
82
83  .ghost.blueGhost {
84    transform-origin: 50px 35px;
85    animation: blueGhost 2.8s ease-in-out infinite;
86    z-index: 0;
87  }
88
89  /*
90    Motion approximates the sequence:
91    - start horizontal overlap
92    - gray rotates up around its left pivot while blue slides/settles below
93    - both pass near vertical
94    - continue to opposite diagonal
95    - return
96  */
97  @keyframes grayMove {
98    0% {
99      transform: translate(40px, 40px) rotate(0deg);
100    }
101    18% {
102      transform: translate(34px, 52px) rotate(0deg);
103    }
104    38% {
105      transform: translate(30px, 58px) rotate(22deg);
106    }
107    52% {
108      transform: translate(28px, 62px) rotate(72deg);
109    }
110    68% {
111      transform: translate(18px, 72px) rotate(82deg);
112    }
113    84% {
114      transform: translate(26px, 60px) rotate(28deg);
115    }
116    100% {
117      transform: translate(40px, 40px) rotate(0deg);
118    }
119  }
120
121  @keyframes blueMove {
122    0% {
123      transform: translate(265px, 45px) rotate(0deg);
124    }
125    18% {
126      transform: translate(245px, 95px) rotate(0deg);
127    }
128    38% {
129      transform: translate(230px, 160px) rotate(0deg);
130    }
131    52% {
132      transform: translate(210px, 175px) rotate(0deg);
133    }
134    68% {
135      transform: translate(175px, 182px) rotate(0deg);
136    }
137    84% {
138      transform: translate(215px, 150px) rotate(0deg);
139    }
140    100% {
141      transform: translate(265px, 45px) rotate(0deg);
142    }
143  }
144
145  @keyframes grayGhost {
146    0%, 20%, 100% {
147      opacity: 0;
148      transform: translate(40px, 40px) rotate(0deg);
149    }
150    30% {
151      opacity: .9;
152      transform: translate(34px, 52px) rotate(22deg);
153    }
154    48% {
155      opacity: .9;
156      transform: translate(28px, 62px) rotate(72deg);
157    }
158    62% {
159      opacity: .9;
160      transform: translate(18px, 72px) rotate(82deg);
161    }
162    80% {
163      opacity: .9;
164      transform: translate(26px, 60px) rotate(28deg);
165    }
166  }
167
168  @keyframes blueGhost {
169    0%, 20%, 100% {
170      opacity: 0;
171      transform: translate(265px, 45px) rotate(0deg);
172    }
173    30% {
174      opacity: .9;
175      transform: translate(245px, 95px) rotate(-22deg);
176    }
177    48% {
178      opacity: .9;
179      transform: translate(210px, 175px) rotate(-78deg);
180    }
181    62% {
182      opacity: .9;
183      transform: translate(175px, 182px) rotate(-82deg);
184    }
185    80% {
186      opacity: .9;
187      transform: translate(215px, 150px) rotate(-28deg);
188    }
189  }
190</style>
191</head>
192<body>
193  <div class="stage">
194    <div class="rig">
195      <div class="ghost grayGhost"></div>
196      <div class="ghost blueGhost"></div>
197      <div class="bar blue"></div>
198      <div class="bar gray"></div>
199    </div>
200  </div>
201</body>
202</html>