/* === CSS VARIABLES === */
:root {
--bg-base: #3d566e;
--bg-surface: #3d5a7a;
--bg-elevated: #486a8f;
--bg-border: rgba(255,255,255,0.08);
--bg-subtle: #2d4059;
--border-strong: rgba(255,255,255,0.14);
--pillar-1: #8b96e8;
--pillar-1-soft: rgba(139,150,232,0.18);
--pillar-2: #4dbac4;
--pillar-2-soft: rgba(77,186,196,0.18);
--pillar-3: #e0993a;
--pillar-3-soft: rgba(224,153,58,0.18);
--text-primary: #e2e8f0;
--text-body: #e2e8f0;
--text-muted: #a8b8cc;
--font-display: 'Space Grotesk', system-ui, -apple-system, 'Segoe UI', sans-serif;
--font-ui: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
--font-body: 'Crimson Pro', Georgia, 'Times New Roman', serif;
--font-mono: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace;
--text-xs: 0.75rem;
--text-sm: 0.875rem;
--text-base: 1.05rem;
--text-body: 1.15rem;
--text-md: 1.25rem;
--text-lg: 1.5rem;
--text-xl: clamp(1.8rem, 3vw, 2.75rem);
--text-2xl: clamp(2rem, 4vw, 3.5rem);
--text-3xl: clamp(2.5rem, 5vw, 4rem);
--text-hero: clamp(2.4rem, 5vw, 4.4rem);
--glow-indigo: rgba(139,150,232,0.22);
--glow-cyan: rgba(77,186,196,0.18);
--hover-subtle: rgba(255,255,255,0.04);
--nav-separator: rgba(120,144,168,0.30);
}
[data-theme="light"] {
--bg-base: #DDEAF7;
--bg-surface: #F4F7FB;
--bg-elevated: #FFFFFF;
--bg-border: rgba(30,48,72,0.10);
--bg-subtle: #a8c4e0;
--border-strong: rgba(30,48,72,0.18);
--text-primary: #1e3048;
--text-body: #2d4a66;
--text-muted: #4a6080;
--hover-subtle: rgba(30,48,72,0.04);
--nav-separator: rgba(30,48,72,0.18);
--glow-indigo: rgba(101,112,200,0.10);
--glow-cyan: rgba(58,157,166,0.10);
--pillar-1: #6570c8;
--pillar-1-soft: rgba(101,112,200,0.18);
--pillar-2: #3a9da6;
--pillar-2-soft: rgba(58,157,166,0.18);
--pillar-3: #c07a28;
--pillar-3-soft: rgba(192,122,40,0.18);
--text-muted: #4a6080;
}
body, .nav-mobile-overlay,
h1, h2, h3, p, li, span, a {
transition:
background-color 0.25s ease,
color 0.20s ease,
border-color 0.20s ease;
}
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
background: var(--bg-base);
color: var(--text-body);
font-family: var(--font-body);
line-height: 1.9;
overflow-x: hidden;
}
/* === NAV === */
.site-nav {
position: fixed; top: 0; left: 0; right: 0; z-index: 1000;
display: flex; align-items: center; justify-content: space-between;
padding: 0 64px; height: 54px;
background: rgba(61,86,110,0.85);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-bottom: 1px solid rgba(255,255,255,0.06);
transition: background 0.4s ease, backdrop-filter 0.4s ease, border-color 0.4s ease;
}
[data-theme="light"] .site-nav { background: rgba(255,255,255,0.55); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); border-bottom: 1px solid rgba(255,255,255,0.65); box-shadow: 0 2px 16px rgba(30,48,72,0.08); }
[data-theme="light"] .site-nav.scrolled { background: rgba(255,255,255,0.70); backdrop-filter: blur(24px); -webkit-backdrop-filter: blur(24px); box-shadow: 0 4px 24px rgba(30,48,72,0.12); }
[data-theme="dark"] .site-nav { background: rgba(35,52,72,0.75); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); border-bottom: 1px solid rgba(255,255,255,0.08); box-shadow: 0 2px 16px rgba(0,0,0,0.30); }
[data-theme="dark"] .site-nav.scrolled { background: rgba(30,45,65,0.88); backdrop-filter: blur(24px); -webkit-backdrop-filter: blur(24px); box-shadow: 0 4px 24px rgba(0,0,0,0.40); }
.site-nav.scrolled { background: rgba(61,86,110,0.75); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); border-bottom-color: rgba(255,255,255,0.10); }
.nav-brand { text-decoration: none; display: flex; flex-direction: column; gap: 2px; }
.nav-brand-name { font-family: var(--font-display); font-size: var(--text-md); font-weight: 700; color: var(--text-primary); letter-spacing: 0.18em; text-transform: uppercase; }
.nav-brand-sub { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--text-muted); letter-spacing: 0.1em; text-transform: uppercase; }
.nav-links { display: flex; align-items: center; gap: 40px; list-style: none; margin: 0; padding: 0; }
.nav-link { font-family: var(--font-display); font-size: var(--text-sm); font-weight: 600; color: var(--text-body); text-decoration: none; letter-spacing: 0.04em; transition: color 0.2s; position: relative; }
.nav-link:hover, .nav-link.active { color: var(--text-primary); }
.nav-link.active::after { content: ''; position: absolute; bottom: -4px; left: 0; right: 0; height: 3px; background: var(--pillar-2); border-radius: 1px; }
.nav-hamburger { display: none; flex-direction: column; gap: 5px; background: none; border: none; cursor: pointer; padding: 8px; }
.nav-hamburger span { display: block; width: 22px; height: 2px; background: var(--text-primary); transition: transform 0.3s ease, opacity 0.3s ease; }
.nav-hamburger.open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-hamburger.open span:nth-child(2) { opacity: 0; transform: scaleX(0); }
.nav-hamburger.open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
.nav-mobile-overlay {
position: fixed; inset: 0; z-index: 999;
background: var(--bg-base); display: flex; align-items: center; justify-content: center;
opacity: 0; pointer-events: none; transform: translateY(-12px); transition: opacity 0.3s ease, transform 0.3s ease;
}
.nav-mobile-overlay.open { opacity: 1; pointer-events: all; transform: translateY(0); }
.nav-mobile-links { list-style: none; text-align: center; padding: 0; }
.nav-mobile-links li { margin: 24px 0; }
.nav-mobile-links a { font-family: var(--font-display); font-size: 2rem; font-weight: 700; color: var(--text-muted); text-decoration: none; transition: color 0.2s; }
.nav-mobile-links a:hover { color: var(--text-primary); }
.mobile-cta { color: var(--pillar-2) !important; }
@media (max-width: 768px) {
.site-nav { padding: 0 24px; }
.nav-links, .nav-cta { display: none; }
.nav-hamburger { display: flex; }
}
/* Nav pipe separators */
.nav-links { gap: 40px !important; }
.nav-brand-sub { display: none !important; }
/* === REVEAL === */
.reveal { opacity: 0; transform: translateY(24px); transition: opacity 0.5s ease, transform 0.5s ease; }
.reveal.visible { opacity: 1; transform: none; }
/* === PAGE HERO === */
.page-hero {
position: relative;
padding: 96px 80px 72px;
overflow: hidden;
border-bottom: 1px solid rgba(255,255,255,0.08);
background: var(--bg-subtle) !important;
}
.hero-lines {
position: absolute; inset: 0; pointer-events: none; overflow: hidden;
}
.hero-line {
position: absolute; height: 1px;
background: linear-gradient(90deg, transparent, rgba(58,157,166,0.18), rgba(101,112,200,0.18), transparent);
animation: lineSweep linear infinite;
}
@keyframes lineSweep {
0% { transform: translateX(-100%); }
100% { transform: translateX(100vw); }
}
.hero-glow {
position: absolute; top: -60px; right: 10%;
width: 500px; height: 500px;
background: radial-gradient(ellipse, rgba(6,182,212,0.07) 0%, transparent 70%);
pointer-events: none;
}
.hero-eyebrow {
font-family: var(--font-mono); font-size: var(--text-sm);
color: var(--pillar-2); letter-spacing: 0.22em;
text-transform: uppercase; margin-bottom: 20px;
display: block;
opacity: 0;
animation: fadeUp 0.7s cubic-bezier(0.16,1,0.3,1) 0.1s both;
}
.page-hero h1 {
font-family: var(--font-display);
font-size: clamp(2.2rem, 4.5vw, 4rem);
font-weight: 600;
color: var(--text-primary);
line-height: 1.1;
letter-spacing: 0.01em;
max-width: 800px;
margin-bottom: 20px;
opacity: 0;
animation: fadeUp 0.7s cubic-bezier(0.16,1,0.3,1) 0.2s both;
}
.page-hero-sub {
font-family: var(--font-body); font-size: var(--text-md);
color: var(--text-body); max-width: 640px;
line-height: 1.9; margin-bottom: 48px;
opacity: 0;
animation: fadeUp 0.7s cubic-bezier(0.16,1,0.3,1) 0.32s both;
}
.hero-metrics {
display: flex; gap: 48px; flex-wrap: wrap;
opacity: 0;
animation: fadeUp 0.7s cubic-bezier(0.16,1,0.3,1) 0.44s both;
}
.hero-metric {
display: flex; flex-direction: column; gap: 4px;
}
.hero-metric-val {
font-family: var(--font-mono); font-size: var(--text-lg);
font-weight: 500; color: var(--pillar-2); letter-spacing: 0;
}
.hero-metric-label {
font-family: var(--font-mono); font-size: var(--text-sm);
color: var(--text-muted); letter-spacing: 0.1em; text-transform: uppercase;
}
.hero-tags {
display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 32px;
opacity: 0;
animation: fadeUp 0.7s cubic-bezier(0.16,1,0.3,1) 0.38s both;
}
.hero-tag {
font-family: var(--font-mono); font-size: var(--text-sm);
padding: 4px 12px; border: 1px solid var(--bg-border);
color: var(--text-muted); letter-spacing: 0.04em;
}
.hero-status {
display: inline-flex; align-items: center; gap: 8px;
font-family: var(--font-mono); font-size: var(--text-sm);
color: #fbbf24; background: rgba(251,191,36,0.10);
border: 1px solid rgba(251,191,36,0.25);
padding: 6px 14px; margin-bottom: 28px; letter-spacing: 0.08em;
text-transform: uppercase;
}
.hero-status::before {
content: ''; width: 7px; height: 7px; border-radius: 50%;
background: #fbbf24; flex-shrink: 0;
animation: pulseDot 2s ease-in-out infinite;
}
@keyframes pulseDot {
0%, 100% { opacity: 1; }
50% { opacity: 0.3; }
}
@keyframes fadeUp {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.hero-parallels {
font-family: var(--font-mono); font-size: var(--text-sm);
color: var(--text-muted); letter-spacing: 0.04em;
margin-top: 24px; line-height: 1.8;
}
@media (max-width: 768px) {
.page-hero { padding: 64px 24px 48px; }
.hero-metrics { gap: 28px; }
}
/* === CASE STUDY CONTENT === */
.cs-section {
padding: 80px 80px;
border-bottom: 1px solid var(--bg-border);
}
.cs-section:last-of-type { border-bottom: none; }
.cs-section-dark { background: var(--bg-surface); }
.cs-inner {
max-width: 1000px;
margin: 0 auto;
}
.cs-label {
font-family: var(--font-mono); font-size: var(--text-sm);
color: var(--pillar-2); letter-spacing: 0.22em;
text-transform: uppercase; margin-bottom: 16px; display: block;
}
.cs-heading {
font-family: var(--font-display);
font-size: var(--text-xl);
font-weight: 700;
color: var(--text-primary);
margin-bottom: 32px;
letter-spacing: 0.04em;
text-transform: uppercase;
}
.cs-body {
font-family: var(--font-body);
font-size: var(--text-base);
color: var(--text-body);
line-height: 1.9;
max-width: 800px;
}
.cs-body p { margin-bottom: 20px; }
.cs-body strong { color: var(--text-primary); font-weight: 600; }
.cs-body code {
font-family: var(--font-mono);
font-size: 0.85rem;
background: rgba(255,255,255,0.06);
padding: 2px 8px;
border: 1px solid var(--bg-border);
color: var(--pillar-2);
}
/* === TECH STACK === */
.stack-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
margin-top: 32px;
}
.stack-category {
background: var(--bg-surface);
border: 1px solid var(--bg-border);
padding: 24px 28px;
}
.stack-cat-label {
font-family: var(--font-mono); font-size: var(--text-xs);
color: var(--pillar-2); letter-spacing: 0.2em;
text-transform: uppercase; margin-bottom: 16px;
}
.stack-tags {
display: flex; flex-wrap: wrap; gap: 8px;
}
.stack-tag {
font-family: var(--font-mono); font-size: var(--text-sm);
color: var(--text-muted); background: var(--bg-elevated);
border: 1px solid var(--bg-border);
padding: 5px 12px; letter-spacing: 0.04em;
}
@media (max-width: 768px) {
.stack-grid { grid-template-columns: 1fr; }
.cs-section { padding: 48px 24px; }
}
/* === ADR CARDS === */
.adr-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 24px;
margin-top: 32px;
}
.adr-card {
background: var(--bg-surface);
border: 1px solid var(--bg-border);
border-left: 4px solid var(--pillar-2);
padding: 28px 28px;
transition: transform 0.3s, box-shadow 0.3s;
}
.adr-card:hover {
transform: translateY(-4px);
box-shadow: 2px 16px 40px rgba(58,157,166,0.15);
}
.adr-card:nth-child(2) { border-left-color: var(--pillar-1); }
.adr-card:nth-child(3) { border-left-color: var(--pillar-3); }
.adr-card:nth-child(4) { border-left-color: var(--pillar-2); }
.adr-card:nth-child(2):hover { box-shadow: 2px 16px 40px rgba(101,112,200,0.15); }
.adr-card:nth-child(3):hover { box-shadow: 2px 16px 40px rgba(192,122,40,0.15); }
.adr-card:nth-child(4):hover { box-shadow: 2px 16px 40px rgba(58,157,166,0.15); }
.adr-decision {
font-family: var(--font-mono); font-size: var(--text-xs);
color: var(--text-muted); letter-spacing: 0.15em;
text-transform: uppercase; margin-bottom: 8px;
}
.adr-title {
font-family: var(--font-display); font-size: var(--text-md);
font-weight: 700; color: var(--text-primary);
margin-bottom: 12px; line-height: 1.3;
}
.adr-desc {
font-family: var(--font-body); font-size: var(--text-base);
color: var(--text-body); line-height: 1.7;
}
.adr-desc strong { color: var(--text-primary); }
@media (max-width: 768px) {
.adr-grid { grid-template-columns: 1fr; }
}
/* === TIMELINE === */
.timeline {
margin-top: 40px;
position: relative;
}
.timeline::before {
content: '';
position: absolute; left: 0; top: 0; bottom: 0;
width: 1px;
background: linear-gradient(to bottom, var(--pillar-2), var(--pillar-1), var(--pillar-3), transparent);
}
.timeline-item {
padding-left: 32px;
margin-bottom: 40px;
position: relative;
}
.timeline-item::before {
content: '';
position: absolute; left: -5px; top: 6px;
width: 11px; height: 11px;
border-radius: 50%;
background: var(--pillar-2);
border: 2px solid var(--bg-base);
}
.timeline-item:nth-child(2)::before { background: var(--pillar-1); }
.timeline-item:nth-child(3)::before { background: var(--pillar-3); }
.timeline-item:nth-child(4)::before { background: var(--pillar-2); }
.tl-label {
font-family: var(--font-mono); font-size: var(--text-sm);
color: var(--text-muted); letter-spacing: 0.12em;
text-transform: uppercase; margin-bottom: 4px;
}
.tl-title {
font-family: var(--font-display); font-size: var(--text-lg);
font-weight: 700; color: var(--text-primary);
margin-bottom: 4px;
}
.tl-meta {
font-family: var(--font-mono); font-size: var(--text-xs);
color: var(--pillar-2); letter-spacing: 0.1em; margin-bottom: 12px;
}
.tl-desc {
font-family: var(--font-body); font-size: var(--text-base);
color: var(--text-body); line-height: 1.7;
}
/* === OUTCOME === */
.outcome-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
margin-top: 32px;
}
.outcome-card {
background: var(--bg-surface);
border: 1px solid var(--bg-border);
padding: 28px 28px;
text-align: center;
}
.outcome-val {
font-family: var(--font-display);
font-size: clamp(2rem, 3vw, 2.8rem);
font-weight: 800;
color: var(--pillar-2);
line-height: 1;
margin-bottom: 8px;
}
.outcome-card:nth-child(2) .outcome-val { color: var(--pillar-1); }
.outcome-card:nth-child(3) .outcome-val { color: var(--pillar-3); }
.outcome-label {
font-family: var(--font-mono); font-size: var(--text-xs);
color: var(--text-muted); letter-spacing: 0.15em;
text-transform: uppercase;
}
.outcome-list {
margin-top: 32px;
list-style: none;
}
.outcome-list li {
font-family: var(--font-body); font-size: var(--text-base);
color: var(--text-body);
padding: 12px 0;
border-bottom: 1px solid var(--bg-border);
display: flex; align-items: center; gap: 12px;
}
.outcome-list li::before {
content: '◆';
color: var(--pillar-2);
font-size: 0.6rem;
flex-shrink: 0;
}
.outcome-list li:last-child { border-bottom: none; }
@media (max-width: 768px) {
.outcome-grid { grid-template-columns: 1fr; }
}
/* === RELATED PROJECTS === */
.related-section {
padding: 80px 80px 120px;
background: var(--bg-base);
}
.related-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 24px;
margin-top: 32px;
max-width: 1000px;
margin-left: auto;
margin-right: auto;
}
.related-card {
background: var(--bg-surface);
border: 1px solid var(--bg-border);
padding: 32px;
text-decoration: none;
display: flex;
flex-direction: column;
transition: border-color 0.3s, transform 0.3s, box-shadow 0.3s;
}
.related-card:hover {
border-color: var(--pillar-2);
transform: translateY(-4px);
box-shadow: 2px 16px 40px rgba(58,157,166,0.12);
}
.related-direction {
font-family: var(--font-mono); font-size: var(--text-xs);
color: var(--text-muted); letter-spacing: 0.15em;
text-transform: uppercase; margin-bottom: 8px;
}
.related-title {
font-family: var(--font-display); font-size: var(--text-md);
font-weight: 700; color: var(--text-primary);
margin-bottom: 8px;
}
.related-desc {
font-family: var(--font-body); font-size: var(--text-base);
color: var(--text-body); line-height: 1.6;
}
.related-arrow {
font-family: var(--font-mono); font-size: var(--text-sm);
color: var(--pillar-2); margin-top: auto; padding-top: 16px;
letter-spacing: 0.08em;
}
@media (max-width: 768px) {
.related-grid { grid-template-columns: 1fr; }
.related-section { padding: 48px 24px 80px; }
}
/* === FOOTER === */
.site-footer {
background: var(--bg-surface);
border-top: 1px solid var(--bg-border);
padding: 64px 80px 32px;
}
.footer-inner {
display: grid; grid-template-columns: 1.5fr 2fr 0.5fr;
gap: 64px; align-items: start;
padding-bottom: 48px; border-bottom: 1px solid var(--bg-border);
margin-bottom: 32px;
}
.footer-brand { display: flex; flex-direction: column; gap: 6px; }
.footer-name { font-family: var(--font-display); font-size: var(--text-lg); font-weight: 700; color: var(--text-primary); }
.footer-title { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--pillar-2); text-transform: uppercase; letter-spacing: 0.12em; }
.footer-location { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--text-body); margin-top: 8px; }
.footer-nav { display: flex; gap: 48px; }
.footer-nav-col { display: flex; flex-direction: column; gap: 12px; }
.footer-nav-heading { font-family: var(--font-ui); font-size: var(--text-sm); font-weight: 700; color: var(--text-body); text-transform: uppercase; letter-spacing: 0.12em; margin-bottom: 4px; }
.footer-nav-col a { font-family: var(--font-body); font-size: var(--text-base); color: var(--text-muted); text-decoration: none; transition: color 0.2s; }
.footer-nav-col a:hover { color: var(--text-primary); }
.footer-social { display: flex; flex-direction: column; gap: 12px; align-items: flex-end; }
.footer-social-link {
width: 36px; height: 36px; border: 1px solid var(--bg-border);
display: flex; align-items: center; justify-content: center;
font-family: var(--font-mono); font-size: var(--text-sm); color: var(--text-muted);
text-decoration: none; text-transform: lowercase;
transition: border-color 0.2s, color 0.2s;
}
.footer-social-link:hover { border-color: var(--pillar-2); color: var(--pillar-2); }
.footer-bottom {
display: flex; justify-content: space-between; align-items: center;
font-family: var(--font-mono); font-size: var(--text-sm); color: var(--text-body);
}
.footer-tagline { font-style: italic; opacity: 0.85; }
@media (max-width: 768px) {
.site-footer { padding: 48px 24px 24px; }
.footer-inner { grid-template-columns: 1fr; gap: 32px; }
.footer-nav { flex-direction: column; gap: 32px; }
.footer-social { flex-direction: row; align-items: flex-start; }
.footer-bottom { flex-direction: column; gap: 8px; text-align: center; }
}
p, li { font-size: var(--text-body); letter-spacing: 0.01em; }
h2, h3, h4, .cs-heading, .card-title, .page-title {
text-transform: uppercase;
letter-spacing: 0.05em !important;
}
h1 { text-transform: uppercase; }
.btn-primary, .btn-outline, .nav-cta,
a.btn-primary, a.btn-outline,
input, textarea, select {
border-radius: 0 !important;
}
.nav-cta {
background: transparent !important;
border: 1px solid var(--pillar-2) !important;
color: var(--pillar-2) !important;
}
.nav-cta:hover {
background: var(--pillar-2) !important;
color: var(--bg-base) !important;
transform: none !important;
}
/* === SVG DIAGRAM === */
.diagram-wrap {
position: relative;
margin: 48px auto;
max-width: 960px;
background: var(--bg-surface);
border: 1px solid var(--bg-border);
padding: 24px;
}
.diagram-svg {
width: 100%;
height: auto;
display: block;
}
.diagram-svg text {
font-family: 'JetBrains Mono', monospace;
}
/* Pulsing hub / brain */
@keyframes brainPulse {
0%, 100% { r: 28; opacity: 0.35; }
50% { r: 40; opacity: 0.08; }
}
@keyframes brainGlow {
0%, 100% { opacity: 0.3; filter: drop-shadow(0 0 6px var(--pillar-2)); }
50% { opacity: 0.7; filter: drop-shadow(0 0 16px var(--pillar-2)); }
}
@keyframes dataFlow {
0% { offset-distance: 0%; opacity: 0; }
10% { opacity: 1; }
90% { opacity: 1; }
100% { offset-distance: 100%; opacity: 0; }
}
@keyframes floatNode {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-3px); }
}
@keyframes transcribePulse {
0%, 100% { opacity: 0.4; }
50% { opacity: 0.8; }
}
@keyframes progressFill {
from { width: 0%; }
to { width: 100%; }
}
@keyframes gearSpin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.diagram-caption {
font-family: var(--font-mono);
font-size: var(--text-sm);
color: var(--text-muted);
text-align: center;
padding: 16px 0 0;
letter-spacing: 0.04em;
}
/* === DARK THEME FIXES === */
[data-theme="dark"] .adr-card,
[data-theme="dark"] .outcome-card,
[data-theme="dark"] .stack-category,
[data-theme="dark"] .related-card,
[data-theme="dark"] .diagram-wrap {
box-shadow: 2px 6px 28px rgba(0,0,0,0.40), 0 1px 0 rgba(255,255,255,0.06) inset;
}
.cs-section-dark {
box-shadow: 0 8px 32px rgba(0,0,0,0.25);
}
/* === DIAGRAM ANIMATIONS (ENHANCED) === */
@keyframes seqStep {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
@keyframes seqArrow {
to { stroke-dashoffset: -30; }
}
@keyframes glowPulse {
0%, 100% { filter: drop-shadow(0 0 3px rgba(77,186,196,0.4)); }
50% { filter: drop-shadow(0 0 12px rgba(77,186,196,0.9)); }
}
@keyframes floatUp {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(-5px); }
}
@keyframes nodeGlow {
0%, 100% { stroke-opacity: 0.3; }
50% { stroke-opacity: 1; }
}
@keyframes fadeSlideIn {
from { opacity: 0; transform: translateX(-10px); }
to { opacity: 1; transform: translateX(0); }
}
@keyframes progressFill {
from { width: 0%; }
to { width: 100%; }
}
@keyframes spinSlow {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
@keyframes dashFlowRev {
to { stroke-dashoffset: 60; }
}
.diag-label {
font-family: 'JetBrains Mono', monospace;
font-size: 8px;
fill: var(--text-muted);
text-anchor: middle;
letter-spacing: 0.08em;
}
.diag-title {
font-family: 'Space Grotesk', sans-serif;
font-size: 10px;
fill: var(--text-primary);
text-anchor: middle;
font-weight: 700;
}
.diag-step {
font-family: 'JetBrains Mono', monospace;
font-size: 7px;
fill: var(--pillar-2);
text-anchor: middle;
}
.seq-arrow {
stroke-dasharray: 6 4;
animation: seqArrow 1s linear infinite;
}
.seq-dashed {
stroke-dasharray: 4 5;
animation: dashFlowRev 1.5s linear infinite;
}
.deploy-node {
animation: floatUp 3s ease-in-out infinite;
}
.glow-node {
animation: glowPulse 2.5s ease-in-out infinite;
}
.step-circle {
animation: seqStep 2s ease-in-out infinite;
}
.node-pulse {
animation: nodeGlow 2s ease-in-out infinite;
}
Vikram
Builder Case Study
Complete (1 month stale)
LLM Video Pipeline
Local LLM-friendly video editing pipeline — transcribes footage, LLM authors an EDL, renders final video with cuts, overlays, color grading, subtitles. Zero cloud APIs.
Python
faster-whisper
HyperFrames
FFmpeg
Industry parallels: LLM-as-compiler (emerging) · AI-assisted creative (Runway ML)
12
Sessions
5
Linear Videos
20s
Render Length
0
Cloud APIs
Problem Statement
The Manual Video Editing Tax
Traditional video editing is manual — watch footage, decide cuts, create timeline, render. For AI-generated narration videos (product launches, explainers), the pattern is formulaic: given source footage and a script, the computer should edit automatically. Yet every video still requires a human to scrub through clips, place cuts, sync voiceover, add overlays, and adjust color — a repetitive, hours-long process that resists automation because creative tools lack programmable decision-making.
The core insight: video editing for structured content is a compilation problem, not a creative one. A product launch has a known arc — hook, problem, solution, features, CTA. The source footage is deterministic (screen recordings, talking head, b-roll). The script is written in advance. The only missing piece is an automated director that can watch the footage, understand what each clip contains, and decide how to assemble them.
Existing tools — Premiere Pro, DaVinci Resolve, Final Cut — provide scripting (AppleScript, Python bindings) but no autonomous decision layer. Cloud AI services (Runway ML, Descript) offer AI-assisted editing but require uploading content to external servers, incur per-minute costs, and cannot operate offline or with sensitive material.
The goal: an LLM authoring a video the way a compiler generates code. You write the DESIGN.md, SCRIPT.md, STORYBOARD.md in natural language, and the pipeline transcribes the footage, has the LLM analyze narrative structure, write an Edit Decision List (EDL), and renders the final video — all locally, with zero cloud APIs.
Approach & Architecture
LLM-as-Director Pipeline
The pipeline is a sequence of stages: Capture raw footage (screen recording, webcam), Transcribe via faster-whisper, Analyze with a local LLM to understand narrative structure, Author an EDL (Edit Decision List) describing every cut, transition, overlay, and color grade, Render compositions through HyperFrames, and Assemble the final MP4 via FFmpeg. The LLM acts as the director: it views transcripts, understands the narrative arc, decides what footage to use, where to cut, and what overlays to apply — all without a human touching a timeline.
{
"tracks": [
{"src": "intro.mp4", "cut": "0:12-0:45", "overlay": "title.png"},
{"src": "demo.mp4", "cut": "1:05-2:30", "transition": "crossfade"},
{"src": "outro.mp4", "cut": "0:00-0:20", "color_grade": "warm"}
]
}
# HyperFrames renders the EDL
renderer = HyperFrames(width=1920, height=1080, fps=30)
renderer.compose_from_edl("output.edl")
renderer.render("final.mp4")
RAW
FOOTAGE
📷
faster-whisper
TRANSCRIPTION
🧠
LLM
Narrative Analysis
EDL Authoring
📄
EDL
Edit Decision List
Cuts · Overlays · Grading
HyperFrames
COMPOSITION ENGINE
FFmpeg
FINAL ASSEMBLY
width
0;70;70
6s
indefinite
▶ MP4
CAPTURE
TRANSCRIBE
ANALYZE
AUTHOR
RENDER
Data flow
Render pipeline
Data packet
LLM pulse
Left-to-right pipeline: Raw footage is captured, transcribed via faster-whisper (animated bubbles), analyzed by the LLM (pulsing brain node), EDL document authored, compositions rendered through HyperFrames, assembled via FFmpeg (rotating gear + progress bar), and output as final MP4. Dashed line = render pipeline; animated dots = in-flight data.
Sequence Diagram
Capture → Transcribe → LLM → Render Pipeline
VIDEO RENDER PIPELINE
CAPTURE
Screen / Camera
Raw Footage
1
TRANSCRIBE
whisper.cpp
Audio → Text
2
LLM EDL
Author Edit Decision
Cuts + Effects
3
RENDER
FFmpeg · HyperFrames
Output Video
4
Final Video File
RENDER TIMELINE
Intro
xfade
Main Segment
cut
Demo
Subtitle
Outro
0:00
0:04
0:12
0:18
0:24
Edit Decision List (JSON)
{ cuts: [{src: "clip1.mp4", in: 0, out: 4, fx: "crossfade"}, ...] }
N
Step
Flow
Timeline Clip
Component Interaction
HyperFrames Pipeline Architecture
PIPELINE COMPONENT MAP
Solid = sync call · Dashed = async file I/O
CAPTURE / INPUT
Screen Capture
metal / avfoundation
Microphone
Audio Capture
Source Media
.mp4 · .mov · .wav
PROCESSING
whisper.cpp
Speech → Text
LLM Orchestrator
EDL Generation
Frame Analysis
Scene Detection
RENDER
HyperFrames
Frame Assembly
FFmpeg
Encoding · Muxing
Color Grade
Filters · Overlays
OUTPUT
Final Video
.mp4 · .mov
Subtitles
.srt · .vtt
Thumbnail
Poster Frame
file
event
sync
async
pipe
All components run locally on macOS • No cloud API calls • Apple Silicon optimized
Technology Stack
Languages, AI & Rendering
Languages
Python 3.11
TypeScript (tooling)
AI & Transcription
faster-whisper
local LLM (Ollama)
Sentence embeddings
Rendering
HyperFrames
FFmpeg
Pillow
NumPy
EDL Format
Custom JSON EDL
CMX3600 export
Timecode spec
Capture & Input
Screen recording
Webcam capture
Audio extraction
Format & Delivery
H.264 MP4
SRT subtitles
Color grading LUT
Architecture Decisions
Key Design Records
ADR-001
HyperFrames over After Effects
Free, scriptable, headless. HyperFrames is a Python compositing engine designed for programmatic composition generation — no GUI, no licensing, no GPU dependencies. After Effects would require a Windows/Mac license, manual workflow via ExtendScript, and a display server. HyperFrames accepts frames as NumPy arrays, applies transforms via compositing operations, and outputs directly to FFmpeg pipes. Perfect for LLM-generated composition descriptions where every element (text overlay, image position, color grade) is computed at runtime.
ADR-002
faster-whisper over OpenAI Whisper
4x faster on Apple Silicon; MIT license; zero API costs. faster-whisper uses CTranslate2 to run the Whisper model with integer quantization and optimized inference on Apple Silicon (CoreML) and CUDA. On an M1 Max, a 10-minute audio file transcribes in ~45 seconds vs ~3 minutes for the reference implementation. Both produce word-level timestamps needed for subtitle generation and narrative analysis. The MIT license allows commercial use without restrictions, and running entirely locally means no per-minute transcription costs or data leaving the machine.
ADR-003
faster-whisper over OpenAI API — 4x faster on Apple Silicon, MIT license, zero API costs, privacy-preserving
4x faster on Apple Silicon; MIT license; zero API costs. faster-whisper uses CTranslate2 with integer quantization and CoreML optimizations to achieve ~45s transcription for a 10-minute audio file on M1 Max, versus ~3 minutes for the reference Whisper implementation and ~2 minutes for OpenAI's API (including network round-trip). The MIT license permits commercial use without restrictions. Running entirely locally means no per-minute transcription costs and zero data leaving the machine — critical for processing sensitive screen recordings and internal demos. Word-level timestamps are preserved for subtitle generation and narrative analysis, matching API output quality without ongoing API expense.
Session Timeline
Development Journey
Session 1
linear-video — Pipeline Architecture
Project setup · 20s target
Designed the full pipeline: Capture from product website (screen recording + voiceover), transcribe with faster-whisper, analyze transcript via local LLM to understand narrative beats, author EDL in JSON format, render compositions with HyperFrames, assemble final MP4 with FFmpeg. Defined the DESIGN.md / SCRIPT.md / STORYBOARD.md workflow that anchors every video generation.
Session 2
linear-video — First Render
End-to-end pipeline test
First end-to-end execution: captured 30s of screen recording from a product website, ran faster-whisper transcription, fed transcript to Ollama (Mistral 7B) for EDL authoring, applied cuts, generated text overlays via HyperFrames, produced final MP4. First render had timing alignment issues between voiceover and cuts — refined the timecode generation in the EDL format.
Session 3
linear-video — Quality Improvements
Overlays, color grading, subtitles
Added color grading via HyperFrames compositing LUTs, embedded SRT subtitle generation from whisper word-level timestamps, improved text overlay alignment. The LLM now specified overlay positions (top-left, center, bottom banner) and transitions (crossfade, cut) in the EDL. Refined the prompt template for the LLM to produce consistent EDL JSON output.
Session 4
linear-video — Second Product Video
New product · refined workflow
Produced a second 20s product launch video using the refined pipeline. The LLM correctly identified narrative beats (hook → problem → solution → features → CTA) from the transcript, selected appropriate footage segments, and generated a well-paced EDL. Added scene detection to faster-whisper output for better cut points.
Session 5
linear-video — Final Polish & Documentation
Pipeline hardening
Hardened the pipeline with error handling for missing footage, fallback composition templates when the LLM returned malformed EDL, and a validation pass that checks timecode continuity. Documented the full workflow with example DESIGN.md, SCRIPT.md, and STORYBOARD.md files. Published the pipeline as a reusable CLI entry point.
Outcome & Impact
Results & Industry Alignment
Complete LLM-driven video pipeline — from raw footage capture to final rendered MP4, zero manual timeline editing
End-to-end from product website capture to final 20s render — tested across two different product launches
Industry alignment: LLM-as-compiler (emerging pattern) — the LLM authors an EDL the way a compiler generates code from source, treating DESIGN.md as source and video as compiled output
Industry alignment: AI-assisted creative (Runway ML, Descript) — but fully local, no cloud dependency, no per-minute AI costs, no data leaving the machine
DESIGN.md → SCRIPT.md → STORYBOARD.md → HyperFrames workflow establishes a repeatable template for AI-generated video production