<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PROJECT_TITLE — codevibing session</title>
<meta property="og:title" content="PROJECT_TITLE — SUBTITLE">
<meta property="og:description" content="Watch DESCRIPTION get built with AI">
<meta name="twitter:card" content="summary_large_image">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { background: #08080c; display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh; font-family: -apple-system, sans-serif; color: white; }
canvas { border-radius: 12px; max-width: 100%; height: auto; cursor: pointer; }
.back { position: fixed; top: 20px; left: 20px; color: #6a6a80; text-decoration: none; font-size: 14px; z-index: 10; }
.back:hover { color: #f0ece4; }
</style>
</head>
<body>
<a href="/sessions" class="back">← all sessions</a>
<canvas id="canvas" width="1280" height="720"></canvas>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const W = 1280, H = 720;
const C = {
bg: '#08080c',
surface: '#101018',
border: '#1c1c2c',
text: '#f0ece4',
dim: '#7a7068',
prompt: '#6ee7b7',
ai: '#93c5fd',
code: '#fbbf24',
accent: '#c4956a',
violet: '#a78bfa',
rust: '#c67b5c',
lapis: '#4a7bbd',
gold: '#C4A35A',
};
const images = {};
const imageSources = {
img1: '/<slug>/image1.png',
img2: '/<slug>/image2.png',
};
let imagesLoaded = 0;
Object.entries(imageSources).( {
img = ();
img. = { imagesLoaded++; };
img. = { imagesLoaded++; };
img. = src;
images[key] = img;
});
events = [
{ : , : , : , : , : , : },
{ : , : },
{ : , : , : },
{ : , : , : },
{ : , : , : },
{ : , : , : , : },
{ : , : },
{ : , : , : },
{ : , : , : [, , , ] },
{ : , : , : , : , : , : },
{ : , : },
];
startTime = ;
animFrame = ;
currentElapsed = ;
animRunning = ;
zoom = , zoomTarget = , panY = , panYTarget = ;
() { a + (b - a) * .(.(t, ), ); }
() { - .( - .(t, ), ); }
() {
ctx.();
ctx.(x + r, y); ctx.(x + w - r, y);
ctx.(x + w, y, x + w, y + r); ctx.(x + w, y + h - r);
ctx.(x + w, y + h, x + w - r, y + h); ctx.(x + r, y + h);
ctx.(x, y + h, x, y + h - r); ctx.(x, y + r);
ctx.(x, y, x + r, y); ctx.();
}
() {
(!img || !img. || !img.) ;
imgR = img. / img., boxR = w / h;
sx = , sy = , sw = img., sh = img.;
(imgR > boxR) { sw = sh * boxR; sx = (img. - sw) / ; }
{ sh = sw / boxR; sy = (img. - sh) / ; }
ctx.(img, sx, sy, sw, sh, x, y, w, h);
}
() {
visible = events.( e. <= elapsed);
( i = visible. - ; i >= ; i--) {
t = visible[i].;
(t === ) ;
(t === ) ;
(t === ) ;
(t === || t === ) ;
([,,].(t)) ;
}
;
}
() {
cards = events.( e. <= elapsed && e. === );
card = cards[cards. - ];
(!card) ;
age = elapsed - card.;
img = images[card.];
(img && img. && img.) {
ctx. = (.(age / , ));
(img, , , W, H);
ov = ctx.(, , , H);
ov.(, );
ov.(, );
ov.(, );
ov.(, );
ctx. = ov; ctx.(, , W, H);
ctx. = ;
}
ctx. = .((.((age - ) / , )), );
tx = , ty = H - ;
ctx. = ; ctx. = ;
ctx. = ;
ctx. = ; ctx. = ;
ctx.(card., tx, ty);
ctx. = ;
ctx. = C.; ctx. = ;
ctx.(card., tx, ty + );
(card.) {
ctx. = ;
ctx. = ; ctx. = ;
ctx.(card., tx, ty + );
}
ctx. = ; ctx. = ;
}
() {
zoom = (zoom, zoomTarget, );
panY = (panY, panYTarget, );
ctx.();
ctx.(W/, H/); ctx.(zoom, zoom); ctx.(-W/, -H/ + panY);
tX = , tY = , tW = W - , tH = H - ;
(tX, tY, tW, tH, ); ctx. = C.; ctx.();
ctx. = C.; ctx. = ; ctx.();
(tX, tY, tW, , ); ctx. = ; ctx.();
ctx. = C.; ctx.(tX + , tY + , tW - , );
dY = tY + ;
[[tX+,],[tX+,],[tX+,]].( {
ctx.(); ctx.(dx, dY, , , .*);
ctx. = c; ctx. = ; ctx.(); ctx. = ;
});
ctx. = ; ctx. = C.;
ctx.(, tX + , dY + );
secs = .(elapsed / );
ctx. = ; ctx. = ;
ctx.(, tX + tW - , dY + );
ctx. = ;
content = events.( e. <= elapsed && [,,].(e.));
lH = , sY = tY + , sX = tX + ;
maxL = .((tH - ) / lH);
content.(-maxL).( {
y = sY + i * lH, age = elapsed - ev.;
ctx. = (.(age / , ));
fs = ;
(ev. === ) {
ctx. = ; ctx. = C.;
ctx.(, sX, y);
pw = ctx.().;
ctx. = ; ctx. = C.;
ch = .(.(age / ), ev..);
ctx.(ev..(, ch), sX + pw, y);
(ch < ev.. && .(elapsed/)%===) {
ctx. = C.;
ctx.(sX + pw + ctx.(ev..(,ch)). + , y-, , );
}
} (ev. === ) {
ctx. = ; ctx. = C.;
ctx.(ev..(, .(.(age/), ev..)), sX+, y);
} (ev. === ) {
ctx. = ; ctx. = C.;
ctx.(ev..(, .(.(age/), ev..)), sX+, y);
}
ctx. = ;
});
pY = tY+tH-, pX = tX+, pW = tW-;
ctx. = C.; ctx.(pX, pY, pW, );
maxT = events[events.-].;
g = ctx.(pX,,pX+pW,);
g.(,C.); g.(,C.);
ctx. = g; ctx.(pX, pY, .((elapsed/maxT)*pW,), );
ctx.();
}
() {
reveals = events.( e.=== && e.<=elapsed);
cur = reveals[reveals.-]; (!cur) ;
age = elapsed - cur., img = images[cur.];
ctx. = C.; ctx.(,,W,H);
iW=, iH=, iX=W-iW-, iY=(H-iH)/;
ctx. = (.(age/,));
ctx.(); (iX,iY,iW,iH,); ctx.();
(img, iX, iY, iW, iH); ctx.();
ctx. = .((.((age-)/,)),);
lX=, lY=H/;
ctx.=; ctx.=C.;
ctx.(, lX, lY-);
parts = cur..();
ctx.=; ctx.=C.;
ctx.(parts[], lX, lY-);
(parts[]) { ctx.=; ctx.=C.; ctx.(parts[], lX, lY+); }
ctx. = ;
}
() {
grids = events.( e.=== && e.<=elapsed);
cur = grids[grids.-]; (!cur) ;
age = elapsed - cur.;
ctx. = C.; ctx.(,,W,H);
gap=, tW=W-, tH=H-, cW=(tW-gap)/, cH=(tH-gap)/;
cur..( {
col=i%, row=.(i/);
x=+col*(cW+gap), y=+row*(cH+gap), delay=i*, ca=age-delay;
(ca<) ;
fade=(.(ca/,)), scale=(,,(.(ca/,)));
ctx.=fade;
ctx.();
cx=x+cW/, cy=y+cH/;
ctx.(cx,cy); ctx.(scale,scale); ctx.(-cx,-cy);
(x,y,cW,cH,); ctx.();
(images[key], x, y, cW, cH);
ctx.(); ctx.=;
});
}
() {
ctx. = C.; ctx.(,,W,H);
mode = (elapsed);
(mode===) (elapsed);
(mode===) (elapsed);
(mode===) (elapsed);
(elapsed);
ctx.=; ctx.=;
ctx.=C.; ctx.=;
ctx.(, W-, H-);
ctx.=; ctx.=;
maxT=events[events.-].;
ctx.=; ctx.(,H-,W,);
g=ctx.(,,W,);
g.(,C.); g.(,C.);
ctx.=g; ctx.(,H-,.((elapsed/maxT)*W,),);
}
() {
(!startTime) startTime = ts;
currentElapsed = ts - startTime;
(currentElapsed);
maxT = events[events.-].;
(currentElapsed < maxT + ) {
animFrame = (animate);
} {
animRunning = ;
}
}
() {
startTime = ; zoom=; zoomTarget=; panY=; panYTarget=;
currentElapsed = ; animRunning = ;
(animFrame) (animFrame);
animFrame = (animate);
}
() {
startTime = performance.() - t;
currentElapsed = t;
(!animRunning) {
animRunning = ;
animFrame = (animate);
}
}
canvas.(, {
maxT = events[events. - ].;
(!animRunning || currentElapsed >= maxT) {
(); ;
}
next = events.( e. > currentElapsed + );
(next) {
(next.);
} {
(maxT);
}
});
() {
(imagesLoaded >= .(imageSources).) { (); ; }
(imagesLoaded > ) { (); ; }
(play, );
}
(autoplay, );
</script>
</body>
</html>