80 lines
3.1 KiB
HTML
80 lines
3.1 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<title>Motion fixture — CSS keyframes</title>
|
|
<style>
|
|
:root { --bg: #0b0b10; --fg: #f5f5f7; --muted: #9aa0aa; --accent: #6d6aff; }
|
|
* { box-sizing: border-box; }
|
|
html, body { margin: 0; }
|
|
body {
|
|
background: var(--bg); color: var(--fg);
|
|
font-family: -apple-system, system-ui, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
|
|
-webkit-font-smoothing: antialiased;
|
|
}
|
|
.wrap { max-width: 920px; margin: 0 auto; padding: 64px 24px 96px; }
|
|
|
|
/* 1) Finite entrance: fade + slide up, ends at rest (fill forwards). */
|
|
@keyframes fadeUp {
|
|
from { opacity: 0; transform: translateY(28px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
.hero h1 {
|
|
font-size: 56px; font-weight: 700; line-height: 1.05; letter-spacing: -0.02em; margin: 0 0 16px;
|
|
animation: fadeUp 700ms cubic-bezier(0.22, 1, 0.36, 1) both;
|
|
}
|
|
.hero p {
|
|
font-size: 20px; line-height: 1.5; color: var(--muted); margin: 0; max-width: 560px;
|
|
animation: fadeUp 700ms cubic-bezier(0.22, 1, 0.36, 1) 120ms both;
|
|
}
|
|
|
|
/* 2) Infinite spinner. */
|
|
@keyframes spin { to { transform: rotate(360deg); } }
|
|
.spinner {
|
|
width: 48px; height: 48px; margin: 56px 0 0; border-radius: 9999px;
|
|
border: 4px solid rgba(255,255,255,0.15); border-top-color: var(--accent);
|
|
animation: spin 1s linear infinite;
|
|
}
|
|
|
|
/* 3) Infinite pulse (opacity + scale). */
|
|
@keyframes pulse {
|
|
0%, 100% { opacity: 1; transform: scale(1); }
|
|
50% { opacity: 0.55; transform: scale(1.08); }
|
|
}
|
|
.badge {
|
|
display: inline-block; margin-top: 40px; padding: 8px 16px; border-radius: 9999px;
|
|
background: var(--accent); color: #fff; font-size: 14px; font-weight: 600;
|
|
animation: pulse 1.8s ease-in-out infinite;
|
|
}
|
|
|
|
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; margin-top: 64px; }
|
|
.card {
|
|
background: #15151d; border: 1px solid #23232e; border-radius: 14px; padding: 20px;
|
|
animation: fadeUp 600ms ease-out both;
|
|
}
|
|
.card h3 { margin: 0 0 8px; font-size: 18px; font-weight: 600; }
|
|
.card p { margin: 0; font-size: 15px; line-height: 1.5; color: var(--muted); }
|
|
.footer { margin-top: 80px; color: var(--muted); font-size: 14px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<main class="wrap">
|
|
<section class="hero">
|
|
<h1>Motion that replays</h1>
|
|
<p>A deterministic fixture: heading and subtext animate in, the loader spins forever, and the badge pulses.</p>
|
|
<div class="spinner" aria-label="Loading"></div>
|
|
<span class="badge">Live</span>
|
|
</section>
|
|
|
|
<section class="grid">
|
|
<div class="card"><h3>Entrance</h3><p>Cards fade and slide up on load via a CSS keyframes animation.</p></div>
|
|
<div class="card"><h3>Looping</h3><p>The spinner uses an infinite linear rotation that never settles.</p></div>
|
|
<div class="card"><h3>Pulsing</h3><p>The badge eases between two opacity and scale states forever.</p></div>
|
|
</section>
|
|
|
|
<p class="footer">Reconstructed deterministically — the clone should replay each of these.</p>
|
|
</main>
|
|
</body>
|
|
</html>
|