← back to Only CSS: Joint Animationcompare with ground truth →
model output
GPT-5.4
Only CSS: Joint Animation
A 0.84T 0.65
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>Linked Bars Rotation</title>
7<style>
8 html, body {
9 margin: 0;
10 width: 100%;
11 height: 100%;
12 background: #fff;
13 overflow: hidden;
14 font-family: sans-serif;
15 }
16
17 .stage {
18 position: relative;
19 width: 100vw;
20 height: 100vh;
21 }
22
23 /* overall placement roughly matching the frames */
24 .rig {
25 position: absolute;
26 left: 35.3vw;
27 top: 34.3vh;
28 width: 0;
29 height: 0;
30 }
31
32 .arm {
33 position: absolute;
34 transform-origin: 0 50%;
35 }
36
37 .bar {
38 position: absolute;
39 left: 0;
40 top: -38px;
41 width: 300px;
42 height: 76px;
43 box-sizing: border-box;
44 }
45
46 .bar.gray {
47 background: rgba(140,140,140,.78);
48 }
49
50 .bar.blue {
51 background: rgba(54,157,210,.78);
52 }
53
54 /* faint construction / previous-position outlines visible in frames */
55 .ghost {
56 position: absolute;
57 left: 0;
58 top: -38px;
59 width: 300px;
60 height: 76px;
61 box-sizing: border-box;
62 border: 1px dashed rgba(0,0,0,.35);
63 background: transparent;
64 pointer-events: none;
65 }
66
67 .pivot {
68 position: absolute;
69 width: 20px;
70 height: 20px;
71 border-radius: 50%;
72 background: #f2cf12;
73 border: 4px solid rgba(255,255,255,.95);
74 box-sizing: border-box;
75 box-shadow: 0 0 0 1px rgba(180,180,180,.45);
76 }
77
78 /* pivot positions inside each bar */
79 .gray .pivot {
80 left: 30px;
81 top: 28px;
82 }
83
84 .blue .pivot {
85 left: 30px;
86 top: 28px;
87 }
88
89 /* gray arm rotates around its left yellow point */
90 .gray-arm {
91 animation: graySwing 3.2s ease-in-out infinite;
92 }
93
94 /* blue arm is attached near the right side of gray bar */
95 .blue-arm {
96 left: 220px;
97 top: 0;
98 animation: blueCounter 3.2s ease-in-out infinite;
99 }
100
101 /* subtle outlined snapshots seen during motion */
102 .gray-arm .ghost {
103 animation: grayGhost 3.2s ease-in-out infinite;
104 }
105
106 .blue-arm .ghost {
107 animation: blueGhost 3.2s ease-in-out infinite;
108 }
109
110 @keyframes graySwing {
111 0%, 100% { transform: rotate(0deg); }
112 25% { transform: rotate(22deg); }
113 50% { transform: rotate(78deg); }
114 75% { transform: rotate(18deg); }
115 }
116
117 /* relative rotation so blue remains mostly horizontal while gray swings up,
118 then slightly dips as in the later frames */
119 @keyframes blueCounter {
120 0%, 100% { transform: rotate(0deg); }
121 25% { transform: rotate(-22deg); }
122 50% { transform: rotate(-78deg); }
123 75% { transform: rotate(-30deg); }
124 }
125
126 @keyframes grayGhost {
127 0%, 12% { transform: rotate(0deg); opacity: 0; }
128 20%, 38% { transform: rotate(22deg); opacity: .55; }
129 45%, 62% { transform: rotate(78deg); opacity: .55; }
130 70%, 88% { transform: rotate(18deg); opacity: .45; }
131 100% { transform: rotate(0deg); opacity: 0; }
132 }
133
134 @keyframes blueGhost {
135 0%, 12% { transform: rotate(0deg); opacity: 0; }
136 20%, 38% { transform: rotate(-22deg); opacity: .55; }
137 45%, 62% { transform: rotate(-78deg); opacity: .55; }
138 70%, 88% { transform: rotate(-30deg); opacity: .45; }
139 100% { transform: rotate(0deg); opacity: 0; }
140 }
141</style>
142</head>
143<body>
144 <div class="stage">
145 <div class="rig">
146 <div class="arm gray-arm">
147 <div class="ghost"></div>
148 <div class="bar gray">
149 <div class="pivot"></div>
150 </div>
151
152 <div class="arm blue-arm">
153 <div class="ghost"></div>
154 <div class="bar blue">
155 <div class="pivot"></div>
156 </div>
157 </div>
158 </div>
159 </div>
160 </div>
161</body>
162</html>