47:51Ranking major U.S. Open-Weights Models. (Where does Ripple 65B fit in?)
Nov 6, 2026 · YouTube
38:58Testing Particle-1: a post-trained DeepSeek V4.1 Flash specializing in coding and efficiency
Oct 28, 2026 · YouTube
29:55Kimi K3.1 Pro Looked Incredible. Then I Kept Testing.
Oct 26, 2026 · YouTube
16:45DeepSeek V4.1 Flash Is Shockingly Good for the Price
Sep 10, 2026 · YouTube
17:14How much better is GPT-6 Astra over Claude Opus 5? Real Website and Coding Tests
Sep 5, 2026 · YouTube
29:13Implementing a multiplayer game with GPT-6 Astra (+ Gemini 3.8, Opus 5, Sol Pro)
Sep 5, 2026 · YouTube
19:42Meta Muse Spark 1.3 Review: A Huge Leap Forward
Sep 2, 2026 · YouTube
17:31Testing Gemini 3.8 Flash on Real Coding Challenges (vs. other models)
Sep 2, 2026 · YouTube
Build one self-contained HTML page for a museum armoury exhibit: a standing figure and a slider that re-equips that same figure across three periods of human history.
Choose any three periods from recorded human history, anywhere in the world. Put them in chronological order and keep adjacent choices at least 100 years apart. For each, name a specific year and place; if an exact year is impossible, give the tightest defensible date range and explain it in the label.
Choose periods you can depict accurately. You are judged on the drawing as well as the interface.
Math.random, clocks, or accumulated state.localStorage, sessionStorage, cookies, or indexedDB.One line per period: date, place, equipment, weapon, and one specific detail a non-specialist might miss.
One paragraph explaining the attachment points, layer order, and interpolation between periods.
One fenced html block containing the complete page.
Name the least certain historical choice and any accuracy compromise you made for legibility.
I will move the slider slowly in both directions, watch the feet and shoulders for drift, compare labels to drawings, inspect the SVG structure, and go straight to the final period before judging the rest.
1. c. 100–110 CE — Vindolanda, Roman Britain.
Equipment: lorica segmentata (Corbridge type A), Imperial Gallic helmet, balteus belt with studded apron.
Weapon: gladius Hispaniensis (sheathed at the right hip), pilum, curved scutum.
Detail a non-specialist might miss: the scutum is held by a single horizontal hand-grip behind the boss, not strapped to the forearm — so the legionary can punch it forward.
2. c. 900 CE — Hedeby, Denmark.
Equipment: riveted mail byrnie, spangenhelm with nasal, round limewood shield.
Weapon: spear (spjót) with a leaf-shaped iron head.
Detail a non-specialist might miss: the shield's iron boss covers the hand grip, and the shield is only about 7 mm of limewood — a shock absorber, not a wall.
3. c. 1450 CE — Beijing, Ming China.
Equipment: bùmiànjiǎ brigandine coat, conical iron helmet with brim, rattan shield (téngpái).
Weapon: yàndāo (willow-leaf saber).
Detail a non-specialist might miss: each brass rivet on the coat holds one small iron plate inside the cloth — the armour is a flexible matrix of plates, not a single breastplate.
The body is one fixed SVG group: head, neck, torso, hips, legs and feet never change size or position. Named attachment points are the shoulder pivots at (176,158) and (264,158), the elbow pivots at (176,234) and (264,234), the hand centres at (176,310) and (264,310), and the hip/knee/ankle anchors used by the leg layers. Each arm is a nested pair of groups — #armL/#armR rotate about the shoulder, and #foreL/#foreR rotate about the elbow inside them — so armour sleeves rotate with the limb. Held equipment lives in parallel #holdL/#holdR groups that receive the identical transform chain, which lets shields and weapons sit in front of the torso armour while still tracking the hands. Layer order is: ground shadow → body → leg equipment → arms → torso armour → helmets → held shields → held weapons. Interpolation is a three-way linear weight w = [1-t, t, 0] for t≤1 and [0, 2-t, t-1] for t≥1; the weights drive both the arm angles (a weighted sum of the three period poses) and the opacity of each period's equipment groups. The body itself is never faded, so the figure never jumps, rescales or drifts, and any slider value reproduces exactly the same drawing.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Three Warriors, One Body — Armoury Exhibit</title>
<style>
:root{
--bg:#0e1013;
--panel:#171a20;
--line:#2a2f38;
--ink:#e9e3d6;
--muted:#9b9486;
--gold:#c9a227;
}
*{box-sizing:border-box;}
html,body{height:100%;}
body{
margin:0;
background:radial-gradient(ellipse at 50% -10%, #232833 0%, #0e1013 60%), #0e1013;
color:var(--ink);
font-family:Georgia,"Times New Roman",serif;
display:flex;
flex-direction:column;
align-items:center;
padding:28px 16px 56px;
min-height:100%;
}
header{text-align:center;max-width:720px;margin-bottom:18px;}
h1{
font-size:clamp(20px,3.4vw,30px);
font-weight:400;
letter-spacing:.06em;
margin:0 0 6px;
text-transform:uppercase;
}
.sub{color:var(--muted);font-size:12px;letter-spacing:.16em;text-transform:uppercase;}
.stage{
width:100%;
max-width:520px;
background:linear-gradient(180deg,#1b1f26 0%,#12151a 100%);
border:1px solid var(--line);
border-radius:6px;
padding:8px 8px 0;
box-shadow:0 24px 60px rgba(0,0,0,.55), inset 0 1px 0 rgba(255,255,255,.04);
}
svg#fig{display:block;width:100%;height:auto;}
.controls{width:100%;max-width:520px;margin-top:18px;}
.slider-wrap{position:relative;padding:0 6px;}
input[type=range]{
-webkit-appearance:none;appearance:none;
width:100%;height:34px;background:transparent;cursor:pointer;margin:0;
}
input[type=range]::-webkit-slider-runnable-track{
height:4px;background:linear-gradient(90deg,#3a4250,#5a6474,#3a4250);border-radius:2px;
}
input[type=range]::-moz-range-track{
height:4px;background:linear-gradient(90deg,#3a4250,#5a6474,#3a4250);border-radius:2px;
}
input[type=range]::-webkit-slider-thumb{
-webkit-appearance:none;width:22px;height:22px;margin-top:-9px;border-radius:50%;
background:radial-gradient(circle at 35% 30%, #f0dfa0, #c9a227 60%, #7a6218);
border:1px solid #4a3a08;
box-shadow:0 0 0 4px rgba(201,162,39,.12), 0 2px 6px rgba(0,0,0,.6);
}
input[type=range]::-moz-range-thumb{
width:22px;height:22px;border-radius:50%;
background:radial-gradient(circle at 35% 30%, #f0dfa0, #c9a227 60%, #7a6218);
border:1px solid #4a3a08;
box-shadow:0 0 0 4px rgba(201,162,39,.12), 0 2px 6px rgba(0,0,0,.6);
}
.ticks{display:flex;justify-content:space-between;margin-top:2px;padding:0 2px;}
.ticks button{
background:none;border:none;color:var(--muted);font-family:inherit;
font-size:11px;letter-spacing:.1em;text-transform:uppercase;cursor:pointer;
padding:6px 4px;transition:color .2s;
}
.ticks button:hover,.ticks button.active{color:var(--gold);}
.label{
width:100%;max-width:520px;margin-top:20px;background:var(--panel);
border:1px solid var(--line);border-radius:6px;padding:16px 18px 18px;
}
.label .status{
font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:var(--gold);
margin-bottom:10px;display:flex;align-items:center;gap:8px;
}
.label .status::after{
content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--line),transparent);
}
dl{margin:0;display:grid;grid-template-columns:96px 1fr;gap:6px 14px;font-size:14px;line-height:1.45;}
dt{color:var(--muted);font-size:11px;letter-spacing:.12em;text-transform:uppercase;padding-top:3px;}
dd{margin:0;}
dd.note{color:var(--muted);font-size:12px;font-style:italic;}
dd.detail{color:#c8c0ae;font-style:italic;}
@media (max-width:520px){
dl{grid-template-columns:1fr;gap:2px 0;}
dt{padding-top:8px;}
}
</style>
</head>
<body>
<header>
<h1>Three Warriors, One Body</h1>
<div class="sub">Armoury · Comparative Equipment Study</div>
</header>
<div class="stage">
<svg id="fig" viewBox="0 0 440 600" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="A single standing figure re-equipped across three historical periods">
<defs>
<pattern id="mailPat" width="9" height="9" patternUnits="userSpaceOnUse">
<rect width="9" height="9" fill="#5f656d"/>
<circle cx="2.5" cy="2.5" r="2.3" fill="none" stroke="#a8aeb6" stroke-width="1.1"/>
<circle cx="7" cy="7" r="2.3" fill="none" stroke="#a8aeb6" stroke-width="1.1"/>
</pattern>
<pattern id="rivetPat" width="12" height="14" patternUnits="userSpaceOnUse">
<circle cx="6" cy="7" r="1.8" fill="#d8b64a"/>
<circle cx="6" cy="7" r="1.8" fill="none" stroke="#6a5418" stroke-width="0.6"/>
</pattern>
<linearGradient id="scutumGrad" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" stop-color="#5e1f1c"/>
<stop offset="0.45" stop-color="#a83a32"/>
<stop offset="1" stop-color="#5e1f1c"/>
</linearGradient>
<linearGradient id="ironGrad" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#c2c8d0"/>
<stop offset="1" stop-color="#7d838b"/>
</linearGradient>
<radialGradient id="bossGrad">
<stop offset="0" stop-color="#f0e0a8"/>
<stop offset="0.6" stop-color="#c9a227"/>
<stop offset="1" stop-color="#7a6218"/>
</radialGradient>
</defs>
<!-- ground -->
<ellipse cx="220" cy="578" rx="118" ry="13" fill="#000" opacity="0.40"/>
<ellipse cx="220" cy="578" rx="70" ry="7" fill="#000" opacity="0.35"/>
<!-- ================= BODY (fixed) ================= -->
<g id="body">
<path d="M 184 292 L 192 430 L 196 548 L 212 548 L 210 430 L 212 292 Z" fill="#c49a6c"/>
<path d="M 256 292 L 248 430 L 244 548 L 228 548 L 230 430 L 228 292 Z" fill="#c49a6c"/>
<rect x="186" y="542" width="28" height="28" rx="10" fill="#c49a6c"/>
<rect x="226" y="542" width="28" height="28" rx="10" fill="#c49a6c"/>
<path d="M 172 148 Q 166 200 184 264 L 184 306 L 256 306 L 256 264 Q 274 200 268 148 Z" fill="#c49a6c"/>
<rect x="208" y="118" width="24" height="36" rx="9" fill="#c49a6c"/>
<ellipse cx="220" cy="100" rx="23" ry="32" fill="#c49a6c"/>
<ellipse cx="197" cy="104" rx="4" ry="7" fill="#c49a6c"/>
<ellipse cx="243" cy="104" rx="4" ry="7" fill="#c49a6c"/>
<ellipse cx="211" cy="102" rx="3" ry="2.2" fill="#3a2a1e"/>
<ellipse cx="229" cy="102" rx="3" ry="2.2" fill="#3a2a1e"/>
<path d="M 220 106 L 218 113 L 222 113" fill="none" stroke="#a87a52" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M 214 121 Q 220 124 226 121" fill="none" stroke="#8a5a3a" stroke-width="1.6" stroke-linecap="round"/>
</g>
<!-- ================= LEG EQUIPMENT ================= -->
<g class="eq eq0" id="legs0">
<path d="M 182 284 L 258 284 L 264 352 Q 220 364 176 352 Z" fill="#d8d0c0" stroke="#b0a890" stroke-width="1.5"/>
<path d="M 184 560 L 216 560 L 216 572 L 184 572 Z" fill="#4a3b2e"/>
<path d="M 224 560 L 256 560 L 256 572 L 224 572 Z" fill="#4a3b2e"/>
<path d="M 188 546 L 212 546 M 188 554 L 212 554 M 188 562 L 212 562" stroke="#5a3f2a" stroke-width="2.5"/>
<path d="M 228 546 L 252 546 M 228 554 L 252 554 M 228 562 L 252 562" stroke="#5a3f2a" stroke-width="2.5"/>
</g>
<g class="eq eq1" id="legs1">
<path d="M 181 288 L 190 430 L 194 550 L 214 550 L 212 430 L 215 288 Z" fill="#6b6a5a" stroke="#4a4a3e" stroke-width="1.5"/>
<path d="M 259 288 L 250 430 L 246 550 L 226 550 L 228 430 L 225 288 Z" fill="#6b6a5a" stroke="#4a4a3e" stroke-width="1.5"/>
<rect x="184" y="540" width="30" height="30" rx="11" fill="#4a3b2e" stroke="#2a1f16" stroke-width="1.5"/>
<rect x="226" y="540" width="30" height="30" rx="11" fill="#4a3b2e" stroke="#2a1f16" stroke-width="1.5"/>
</g>
<g class="eq eq2" id="legs2">
<path d="M 181 288 L 190 430 L 194 550 L 214 550 L 212 430 L 215 288 Z" fill="#2e3a52" stroke="#1e2638" stroke-width="1.5"/>
<path d="M 259 288 L 250 430 L 246 550 L 226 550 L 228 430 L 225 288 Z" fill="#2e3a52" stroke="#1e2638" stroke-width="1.5"/>
<path d="M 184 536 L 216 536 L 216 570 L 184 570 Z" fill="#2a2a2a" stroke="#111" stroke-width="1.5"/>
<path d="M 224 536 L 256 536 L 256 570 L 224 570 Z" fill="#2a2a2a" stroke="#111" stroke-width="1.5"/>
<path d="M 184 566 L 216 566 L 216 572 L 184 572 Z" fill="#d8d0c0"/>
<path d="M 224 566 L 256 566 L 256 572 L 224 572 Z" fill="#d8d0c0"/>
</g>
<!-- ================= ARMS ================= -->
<g id="armL" transform="rotate(24 176 158)">
<line x1="176" y1="158" x2="176" y2="234" stroke="#c49a6c" stroke-width="24" stroke-linecap="round"/>
<g class="eq eq0"><rect x="163" y="150" width="26" height="32" rx="13" fill="#d8d0c0" stroke="#b0a890" stroke-width="1.5"/></g>
<g class="eq eq1"><rect x="162" y="148" width="28" height="88" rx="14" fill="url(#mailPat)" stroke="#3a3f45" stroke-width="1.5"/></g>
<g class="eq eq2"><rect x="161" y="146" width="30" height="96" rx="15" fill="#3d4a63" stroke="#26304a" stroke-width="1.5"/></g>
<g id="foreL" transform="rotate(0 176 234)">
<line x1="176" y1="234" x2="176" y2="304" stroke="#c49a6c" stroke-width="20" stroke-linecap="round"/>
<circle cx="176" cy="310" r="11" fill="#c49a6c"/>
</g>
</g>
<g id="armR" transform="rotate(0 264 158)">
<line x1="264" y1="158" x2="264" y2="234" stroke="#c49a6c" stroke-width="24" stroke-linecap="round"/>
<g class="eq eq0"><rect x="251" y="150" width="26" height="32" rx="13" fill="#d8d0c0" stroke="#b0a890" stroke-width="1.5"/></g>
<g class="eq eq1"><rect x="250" y="148" width="28" height="88" rx="14" fill="url(#mailPat)" stroke="#3a3f45" stroke-width="1.5"/></g>
<g class="eq eq2"><rect x="249" y="146" width="30" height="96" rx="15" fill="#3d4a63" stroke="#26304a" stroke-width="1.5"/></g>
<g id="foreR" transform="rotate(0 264 234)">
<line x1="264" y1="234" x2="264" y2="304" stroke="#c49a6c" stroke-width="20" stroke-linecap="round"/>
<circle cx="264" cy="310" r="11" fill="#c49a6c"/>
</g>
</g>
<!-- ================= TORSO ARMOUR ================= -->
<g class="eq eq0" id="torso0">
<path d="M 172 152 Q 220 146 268 152 L 268 168 Q 220 162 172 168 Z" fill="#9aa0a8" stroke="#4e545c" stroke-width="1.4"/>
<path d="M 170 168 Q 220 162 270 168 L 270 184 Q 220 178 170 184 Z" fill="#a8aeb6" stroke="#4e545c" stroke-width="1.4"/>
<path d="M 169 184 Q 220 178 271 184 L 271 200 Q 220 194 169 200 Z" fill="#9aa0a8" stroke="#4e545c" stroke-width="1.4"/>
<path d="M 170 200 Q 220 194 270 200 L 270 216 Q 220 210 170 216 Z" fill="#a8aeb6" stroke="#4e545c" stroke-width="1.4"/>
<path d="M 173 216 Q 220 210 267 216 L 267 232 Q 220 226 173 232 Z" fill="#9aa0a8" stroke="#4e545c" stroke-width="1.4"/>
<path d="M 177 232 Q 220 226 263 232 L 263 248 Q 220 242 177 248 Z" fill="#a8aeb6" stroke="#4e545c" stroke-width="1.4"/>
<path d="M 182 248 Q 220 242 258 248 L 258 266 Q 220 260 182 266 Z" fill="#9aa0a8" stroke="#4e545c" stroke-width="1.4"/>
<path d="M 206 140 Q 184 142 170 154 L 174 162 Q 190 150 208 148 Z" fill="#a8aeb6" stroke="#4e545c" stroke-width="1.4"/>
<path d="M 208 148 Q 188 150 174 162 L 178 170 Q 192 158 210 156 Z" fill="#9aa0a8" stroke="#4e545c" stroke-width="1.4"/>
<path d="M 210 156 Q 192 158 178 170 L 182 178 Q 194 166 212 164 Z" fill="#a8aeb6" stroke="#4e545c" stroke-width="1.4"/>
<path d="M 234 140 Q 256 142 270 154 L 266 162 Q 250 150 232 148 Z" fill="#a8aeb6" stroke="#4e545c" stroke-width="1.4"/>
<path d="M 232 148 Q 252 150 266 162 L 262 170 Q 248 158 230 156 Z" fill="#9aa0a8" stroke="#4e545c" stroke-width="1.4"/>
<path d="M 230 156 Q 248 158 262 170 L 258 178 Q 246 166 228 164 Z" fill="#a8aeb6" stroke="#4e545c" stroke-width="1.4"/>
<rect x="182" y="264" width="76" height="14" rx="3" fill="#5a3f2a" stroke="#3a2a1a" stroke-width="1.5"/>
<rect x="196" y="266" width="14" height="10" rx="2" fill="#b08d3a"/>
<rect x="230" y="266" width="14" height="10" rx="2" fill="#b08d3a"/>
<path d="M 188 278 L 196 278 L 198 330 L 190 330 Z" fill="#5a3f2a"/>
<path d="M 202 278 L 210 278 L 212 330 L 204 330 Z" fill="#5a3f2a"/>
<path d="M 216 278 L 224 278 L 226 330 L 218 330 Z" fill="#5a3f2a"/>
<path d="M 230 278 L 238 278 L 240 330 L 232 330 Z" fill="#5a3f2a"/>
<path d="M 244 278 L 252 278 L 254 330 L 246 330 Z" fill="#5a3f2a"/>
<circle cx="193" cy="292" r="2.2" fill="#b08d3a"/>
<circle cx="207" cy="292" r="2.2" fill="#b08d3a"/>
<circle cx="221" cy="292" r="2.2" fill="#b08d3a"/>
<circle cx="235" cy="292" r="2.2" fill="#b08d3a"/>
<circle cx="249" cy="292" r="2.2" fill="#b08d3a"/>
<path d="M 262 288 L 276 288 L 282 374 L 268 374 Z" fill="#6a4a2a" stroke="#3a2a1a" stroke-width="1.5"/>
<path d="M 262 288 L 276 288 L 276 298 L 262 298 Z" fill="#b08d3a"/>
<circle cx="269" cy="284" r="5" fill="#b08d3a"/>
</g>
<g class="eq eq1" id="torso1">
<path d="M 174 148 Q 166 200 182 268 L 178 378 Q 220 390 262 378 L 258 268 Q 274 200 266 148 Z" fill="url(#mailPat)" stroke="#3a3f45" stroke-width="2"/>
<path d="M 200 144 Q 220 156 240 144 L 242 154 Q 220 166 198 154 Z" fill="#5f656d" stroke="#3a3f45" stroke-width="1.5"/>
<rect x="180" y="262" width="80" height="12" rx="3" fill="#4a3b2e" stroke="#2a1f16" stroke-width="1.5"/>
<rect x="212" y="264" width="16" height="8" rx="2" fill="#b08d3a"/>
</g>
<g class="eq eq2" id="torso2">
<path d="M 174 148 Q 166 200 182 268 L 178 372 Q 220 384 262 372 L 258 268 Q 274 200 266 148 Z" fill="#3d4a63" stroke="#26304a" stroke-width="2"/>
<path d="M 174 148 Q 166 200 182 268 L 178 372 Q 220 384 262 372 L 258 268 Q 274 200 266 148 Z" fill="url(#rivetPat)"/>
<path d="M 198 142 Q 220 154 242 142 L 244 158 Q 220 170 196 158 Z" fill="#2e3a52" stroke="#1e2638" stroke-width="1.5"/>
<rect x="180" y="262" width="80" height="14" rx="3" fill="#2a2a2a" stroke="#111" stroke-width="1.5"/>
<rect x="210" y="264" width="20" height="10" rx="2" fill="#b08d3a"/>
</g>
<!-- ================= HELMETS ================= -->
<g class="eq eq0" id="helm0">
<path d="M 194 96 Q 220 118 246 96 L 250 112 Q 220 136 190 112 Z" fill="#8a8f96" stroke="#4e545c" stroke-width="1.5"/>
<path d="M 195 96 Q 195 62 220 60 Q 245 62 245 96 Z" fill="url(#ironGrad)" stroke="#4e545c" stroke-width="1.5"/>
<path d="M 193 92 Q 220 100 247 92 L 247 100 Q 220 108 193 100 Z" fill="#b08d3a" stroke="#6a5418" stroke-width="1"/>
<path d="M 195 96 L 195 126 Q 201 132 205 124 L 205 98 Z" fill="#9aa0a8" stroke="#4e545c" stroke-width="1.5"/>
<path d="M 245 96 L 245 126 Q 239 132 235 124 L 235 98 Z" fill="#9aa0a8" stroke="#4e545c" stroke-width="1.5"/>
<circle cx="220" cy="58" r="4" fill="#b08d3a"/>
</g>
<g class="eq eq1" id="helm1">
<path d="M 196 94 Q 196 64 220 58 Q 244 64 244 94 Z" fill="url(#ironGrad)" stroke="#3a3f45" stroke-width="1.5"/>
<path d="M 194 90 Q 220 98 246 90 L 246 98 Q 220 106 194 98 Z" fill="#8a8f96" stroke="#3a3f45" stroke-width="1"/>
<path d="M 216 96 L 224 96 L 223 120 L 220 124 L 217 120 Z" fill="#9aa0a8" stroke="#3a3f45" stroke-width="1"/>
<path d="M 208 66 Q 206 80 206 94 M 232 66 Q 234 80 234 94" stroke="#5a6068" stroke-width="1.2" fill="none"/>
<circle cx="200" cy="92" r="1.6" fill="#d8d8d8"/>
<circle cx="240" cy="92" r="1.6" fill="#d8d8d8"/>
<circle cx="220" cy="60" r="2" fill="#d8d8d8"/>
</g>
<g class="eq eq2" id="helm2">
<ellipse cx="220" cy="90" rx="32" ry="8" fill="#7d838b" stroke="#3a3f45" stroke-width="1.5"/>
<path d="M 196 90 Q 200 60 220 50 Q 240 60 244 90 Z" fill="url(#ironGrad)" stroke="#3a3f45" stroke-width="1.5"/>
<path d="M 218 52 L 222 52 L 221 38 L 219 38 Z" fill="#b08d3a"/>
<circle cx="220" cy="36" r="3.5" fill="#b08d3a"/>
<circle cx="198" cy="90" r="1.6" fill="#d8b64a"/>
<circle cx="209" cy="93" r="1.6" fill="#d8b64a"/>
<circle cx="231" cy="93" r="1.6" fill="#d8b64a"/>
<circle cx="242" cy="90" r="1.6" fill="#d8b64a"/>
</g>
<!-- ================= HELD: LEFT (shields) ================= -->
<g id="holdL" transform="rotate(24 176 158)">
<g id="holdLFore" transform="rotate(0 176 234)">
<g class="eq eq0">
<path d="M 128 200 Q 122 310 128 420 L 224 420 Q 230 310 224 200 Z" fill="url(#scutumGrad)" stroke="#3a1410" stroke-width="3"/>
<rect x="126" y="196" width="100" height="9" rx="3" fill="#b08d3a"/>
<rect x="126" y="415" width="100" height="9" rx="3" fill="#b08d3a"/>
<ellipse cx="176" cy="310" rx="18" ry="22" fill="url(#bossGrad)" stroke="#6a5418" stroke-width="2"/>
<path d="M 176 258 Q 154 246 138 260 Q 156 266 176 270 Z" fill="#d8b64a"/>
<path d="M 176 258 Q 198 246 214 260 Q 196 266 176 270 Z" fill="#d8b64a"/>
<path d="M 176 340 L 168 360 L 175 360 L 170 382 L 184 356 L 177 356 L 182 340 Z" fill="#d8b64a"/>
</g>
<g class="eq eq1">
<circle cx="176" cy="310" r="86" fill="#b08a52" stroke="#5a3f2a" stroke-width="4"/>
<path d="M 176 224 L 176 396 M 155 227 L 155 393 M 197 227 L 197 393 M 134 237 L 134 383 M 218 237 L 218 383" stroke="#8a6a3a" stroke-width="1.5"/>
<circle cx="176" cy="310" r="62" fill="none" stroke="#8c2f2a" stroke-width="10"/>
<circle cx="176" cy="310" r="24" fill="url(#bossGrad)" stroke="#5a3f2a" stroke-width="2"/>
<circle cx="176" cy="310" r="9" fill="#8a6f2a"/>
<circle cx="176" cy="310" r="86" fill="none" stroke="#4a3b2e" stroke-width="5"/>
</g>
<g class="eq eq2">
<circle cx="176" cy="310" r="76" fill="#c9a05a" stroke="#6a4a1a" stroke-width="4"/>
<circle cx="176" cy="310" r="62" fill="none" stroke="#a87f3a" stroke-width="2"/>
<circle cx="176" cy="310" r="50" fill="none" stroke="#a87f3a" stroke-width="2"/>
<circle cx="176" cy="310" r="38" fill="none" stroke="#a87f3a" stroke-width="2"/>
<circle cx="176" cy="310" r="26" fill="none" stroke="#a87f3a" stroke-width="2"/>
<path d="M 176 248 L 176 372 M 114 310 L 238 310 M 132 266 L 220 354 M 220 266 L 132 354" stroke="#a87f3a" stroke-width="1.5"/>
<circle cx="176" cy="310" r="16" fill="url(#bossGrad)" stroke="#6a4a1a" stroke-width="2"/>
<circle cx="176" cy="310" r="76" fill="none" stroke="#6a4a1a" stroke-width="5"/>
</g>
</g>
</g>
<!-- ================= HELD: RIGHT (weapons) ================= -->
<g id="holdR" transform="rotate(0 264 158)">
<g id="holdRFore" transform="rotate(0 264 234)">
<g class="eq eq0">
<rect x="261" y="200" width="6" height="352" fill="#8a6a44" stroke="#5a4028" stroke-width="1"/>
<rect x="262" y="90" width="4" height="112" fill="#9aa0a8" stroke="#4e545c" stroke-width="1"/>
<path d="M 264 58 L 270 92 L 258 92 Z" fill="#b9bfc7" stroke="#4e545c" stroke-width="1"/>
<path d="M 261 552 L 267 552 L 265 566 L 263 566 Z" fill="#9aa0a8"/>
<rect x="259" y="296" width="10" height="28" rx="2" fill="#5a3f2a"/>
</g>
<g class="eq eq1">
<rect x="261" y="120" width="6" height="432" fill="#9a7a4a" stroke="#5a4028" stroke-width="1"/>
<rect x="259" y="112" width="10" height="16" rx="2" fill="#7d838b"/>
<path d="M 264 56 Q 274 90 270 116 L 258 116 Q 254 90 264 56 Z" fill="#b9bfc7" stroke="#4e545c" stroke-width="1.5"/>
<rect x="259" y="296" width="10" height="28" rx="2" fill="#5a3f2a"/>
</g>
<g class="eq eq2">
<rect x="258" y="294" width="12" height="34" rx="3" fill="#3a2a1a" stroke="#1a1008" stroke-width="1"/>
<ellipse cx="264" cy="330" rx="12" ry="4" fill="#8a8f96" stroke="#4e545c" stroke-width="1"/>
<path d="M 258 332 C 260 380 270 420 290 444 L 296 436 C 278 412 270 374 270 332 Z" fill="#c8ced6" stroke="#6a7078" stroke-width="1.5"/>
<path d="M 262 338 C 264 378 272 410 288 434" fill="none" stroke="#9aa0a8" stroke-width="1.5"/>
<circle cx="264" cy="292" r="5" fill="#b08d3a"/>
</g>
</g>
</g>
</svg>
</div>
<div class="controls">
<div class="slider-wrap">
<input id="slider" type="range" min="0" max="200" step="1" value="0" aria-label="Historical period">
</div>
<div class="ticks">
<button data-t="0">c. 105 CE</button>
<button data-t="1">c. 900 CE</button>
<button data-t="2">c. 1450 CE</button>
</div>
</div>
<div class="label">
<div class="status" id="status">Exact stop</div>
<dl>
<dt>Date</dt><dd id="l-date"></dd>
<dt>Dating</dt><dd id="l-datenote" class="note"></dd>
<dt>Place</dt><dd id="l-place"></dd>
<dt>Equipment</dt><dd id="l-equip"></dd>
<dt>Materials</dt><dd id="l-mat"></dd>
<dt>Weapon</dt><dd id="l-weap"></dd>
<dt>Detail</dt><dd id="l-detail" class="detail"></dd>
</dl>
</div>
<script>
(function(){
"use strict";
var slider = document.getElementById('slider');
var armL = document.getElementById('armL');
var foreL = document.getElementById('foreL');
var armR = document.getElementById('armR');
var foreR = document.getElementById('foreR');
var holdL = document.getElementById('holdL');
var holdLFore = document.getElementById('holdLFore');
var holdR = document.getElementById('holdR');
var holdRFore = document.getElementById('holdRFore');
var eqGroups = [
Array.prototype.slice.call(document.querySelectorAll('.eq0')),
Array.prototype.slice.call(document.querySelectorAll('.eq1')),
Array.prototype.slice.call(document.querySelectorAll('.eq2'))
];
var SH_L = [24, 26, 22];
var EL_L = [0, -8, -4];
var SH_R = [0, 0, 6];
var EL_R = [0, 0, -20];
var P = [
{
date: "c. 100–110 CE",
dateNote: "Range from the Corbridge-type lorica segmentata finds and Vindolanda Period III (c. 105–120); no single year is documented.",
place: "Vindolanda, Roman Britain",
equip: "Lorica segmentata (Corbridge type A), Imperial Gallic helmet, balteus belt with studded apron",
short: "Lorica segmentata + Gallic helmet",
mat: "Iron bands, bronze hinges and buckles, leather lacing, wool tunic, hobnailed leather caligae",
matShort: "Iron, bronze, leather, wool",
weap: "Gladius Hispaniensis (sheathed at the right hip), pilum, curved scutum",
weapShort: "Gladius, pilum, scutum",
detail: "The scutum is held by a single horizontal hand-grip behind the boss, not strapped to the forearm — so the legionary can punch it forward."
},
{
date: "c. 900 CE",
dateNote: "Hedeby's Viking-Age occupation layers; riveted mail and the Gjermundbu-type helmet are dated to the 10th century.",
place: "Hedeby, Denmark",
equip: "Riveted mail byrnie, spangenhelm with nasal, round limewood shield",
short: "Mail byrnie + spangenhelm",
mat: "Riveted iron rings, iron helmet segments with brass rivets, limewood planks, leather, wool",
matShort: "Iron, limewood, leather, wool",
weap: "Spear (spjót) with a leaf-shaped iron head, round shield",
weapShort: "Spear, round shield",
detail: "The shield's iron boss covers the hand grip; the shield is only about 7 mm of limewood — a shock absorber, not a wall."
},
{
date: "c. 1450 CE",
dateNote: "Mid-Ming army lists; the brigandine (bùmiànjiǎ) and yàndāo are standard 15th-century issue.",
place: "Beijing, Ming China",
equip: "Bùmiànjiǎ brigandine coat, conical iron helmet with brim, rattan shield (téngpái)",
short: "Brigandine coat + conical helmet",
mat: "Iron plates riveted between layers of cotton cloth, brass rivets, lacquered rattan, cotton",
matShort: "Iron, brass, cotton, rattan",
weap: "Yàndāo (willow-leaf saber), rattan shield",
weapShort: "Yàndāo, rattan shield",
detail: "Each brass rivet on the coat holds one small iron plate inside the cloth — the armour is a flexible matrix of plates, not a single breastplate."
}
];
function weights(t){
if (t <= 1) return [1 - t, t, 0];
return [0, 2 - t, t - 1];
}
function lerp3(arr, w){
return arr[0] * w[0] + arr[1] * w[1] + arr[2] * w[2];
}
function setRot(el, angle, cx, cy){
el.setAttribute('transform', 'rotate(' + angle.toFixed(3) + ' ' + cx + ' ' + cy + ')');
}
function render(){
var t = slider.value / 100;
var w = weights(t);
var shL = lerp3(SH_L, w);
var elL = lerp3(EL_L, w);
var shR = lerp3(SH_R, w);
var elR = lerp3(EL_R, w);
setRot(armL, shL, 176, 158);
setRot(foreL, elL, 176, 234);
setRot(armR, shR, 264, 158);
setRot(foreR, elR, 264, 234);
setRot(holdL, shL, 176, 158);
setRot(holdLFore, elL, 176, 234);
setRot(holdR, shR, 264, 158);
setRot(holdRFore, elR, 264, 234);
for (var i = 0; i < 3; i++){
var o = Math.max(0, Math.min(1, w[i]));
var s = o.toFixed(3);
for (var j = 0; j < eqGroups[i].length; j++){
eqGroups[i][j].setAttribute('opacity', s);
}
}
updateLabel(t);
}
function updateLabel(t){
var nearest = Math.round(t);
var isStop = Math.abs(t - nearest) < 0.005;
var status = document.getElementById('status');
var dDate = document.getElementById('l-date');
var dNote = document.getElementById('l-datenote');
var dPlace = document.getElementById('l-place');
var dEquip = document.getElementById('l-equip');
var dMat = document.getElementById('l-mat');
var dWeap = document.getElementById('l-weap');
var dDetail = document.getElementById('l-detail');
if (isStop){
var p = P[nearest];
status.textContent = 'Exact stop · ' + (nearest + 1) + ' of 3';
dDate.textContent = p.date;
dNote.textContent = p.dateNote;
dPlace.textContent = p.place;
dEquip.textContent = p.equip;
dMat.textContent = p.mat;
dWeap.textContent = p.weap;
dDetail.textContent = p.detail;
} else {
var a = Math.floor(t);
var b = a + 1;
var pa = P[a], pb = P[b];
status.textContent = 'Between stops · ' + (a + 1) + ' → ' + (b + 1);
dDate.textContent = pa.date + ' → ' + pb.date;
dNote.textContent = '—';
dPlace.textContent = pa.place + ' → ' + pb.place;
dEquip.textContent = pa.short + ' ↔ ' + pb.short;
dMat.textContent = pa.matShort + ' ↔ ' + pb.matShort;
dWeap.textContent = pa.weapShort + ' ↔ ' + pb.weapShort;
dDetail.textContent = 'Mid-transition: both periods\' equipment is drawn at partial opacity. No single period is being depicted.';
}
var btns = document.querySelectorAll('.ticks button');
for (var k = 0; k < btns.length; k++){
btns[k].classList.toggle('active', isStop && k === nearest);
}
}
slider.addEventListener('input', render);
var tickBtns = document.querySelectorAll('.ticks button');
for (var i = 0; i < tickBtns.length; i++){
(function(btn){
btn.addEventListener('click', function(){
slider.value = parseInt(btn.getAttribute('data-t'), 10) * 100;
render();
});
})(tickBtns[i]);
}
render();
})();
</script>
</body>
</html>
The Ming stop is the least certain. The brigandine is reconstructed from later Ming and Qing finds and from military treatises rather than from a single excavated 1450 Beijing coat, and the exact plate layout inside the cloth is unknown. For legibility I drew the rivets as a regular grid and omitted the visible plate edge at the hem; real bùmiànjiǎ had irregular plate sizes and often a laced side opening. The conical helmet is a generic mid-Ming form — regional variants differ in brim width and finial shape. The face and body proportions are also idealized (about 7.9 heads tall) so that the same rig can carry all three equipments without rescaling.