Back to the library
Token stream, bursty
Variant: Bursty
The same model on the same 175ms beat, but delivery runs through a four-slot buffer: tokens queue, the buffer flushes, four words land at once. Production never pauses — the queue filling underneath is the proof — so the stall you feel is transport, not the model. Use it to explain chunked transfer, batched SSE flushes, or why a proxy makes a fast model feel jerky.
diagramllminfrastructure
The source
A complete HTML document. Paste it into an empty .html file and it plays — no stylesheet, script, font, or image to fetch.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Token stream, bursty</title>
<style>
:root {
--ivory: #faf9f5;
--slate: #141413;
--clay: #d97757;
--oat: #e3dacc;
--text: rgba(20, 20, 19, 0.34);
/* Same 4.2s loop and same 175ms token period as the steady variant —
production is identical. Four tokens per chunk, so the buffer cycles
every 700ms and fits the loop exactly six times. */
--loop: 4.2s;
--tok: 175ms;
--chunk: 700ms;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
min-height: 100vh;
display: grid;
place-items: center;
background: var(--ivory);
font-family:
system-ui,
-apple-system,
'Segoe UI',
Roboto,
sans-serif;
color: var(--slate);
}
.sys {
width: 192px;
display: grid;
justify-items: start;
}
/* --- prompt ------------------------------------------------------ */
.prompt {
position: relative;
width: 192px;
height: 30px;
display: grid;
align-content: center;
gap: 5px;
padding: 0 10px;
border-radius: 7px;
background: var(--oat);
}
.prompt b {
display: block;
height: 4px;
border-radius: 2px;
background: var(--text);
}
.prompt b:nth-of-type(1) {
width: 128px;
}
.prompt b:nth-of-type(2) {
width: 86px;
}
.prompt .ring {
border-radius: 7px;
animation: sent var(--loop) infinite;
}
.ring {
position: absolute;
inset: -1.5px;
border: 1.5px solid var(--clay);
opacity: 0;
pointer-events: none;
}
/* --- channels ---------------------------------------------------- */
.chan {
position: relative;
width: 192px;
}
.chan.a {
height: 16px;
}
.chan.b {
height: 26px;
}
.rail {
position: absolute;
top: 0;
bottom: 0;
left: 50%;
width: 1.5px;
margin-left: -0.75px;
background: var(--oat);
}
.pkt {
position: absolute;
top: 0;
left: 50%;
width: 7px;
height: 7px;
margin-left: -3.5px;
border-radius: 50%;
background: var(--clay);
opacity: 0;
animation: send var(--loop) infinite;
}
/* --- buffer ------------------------------------------------------ */
.bufgate {
position: absolute;
inset: 0;
opacity: 0;
animation: gate var(--loop) steps(1, end) infinite;
}
/* Four slots at 17px rather than 11px: this is the element that explains
the whole variant, so it has to survive being shrunk to a card. */
.slots,
.fill {
position: absolute;
top: 3px;
left: 50%;
width: 72px;
height: 6px;
margin-left: -36px;
background: repeating-linear-gradient(90deg, currentColor 0 17px, transparent 17px 18px);
}
.slots {
color: var(--oat);
}
/* Four slots fill on the same 175ms beat the steady variant emits on —
the queue is what clumps, not the model. */
.fill {
color: var(--clay);
animation: buffer var(--chunk) infinite;
}
.flush {
position: absolute;
top: 12px;
left: 50%;
width: 7px;
height: 7px;
margin-left: -3.5px;
border-radius: 50%;
background: var(--clay);
opacity: 0;
animation: deliver var(--chunk) infinite;
}
/* --- model ------------------------------------------------------- */
.model {
position: relative;
width: 192px;
height: 36px;
border: 1.5px solid var(--oat);
border-radius: 9px;
animation: receive var(--loop) infinite;
}
.model .ring {
border-radius: 9px;
animation: live var(--loop) infinite;
}
.beat {
position: absolute;
inset: 0;
display: grid;
place-items: center;
opacity: 0;
animation: gate var(--loop) steps(1, end) infinite;
}
.core {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--clay);
animation: tick var(--tok) infinite;
}
/* --- completion -------------------------------------------------- */
.out {
width: 192px;
display: grid;
gap: 9px;
overflow: hidden;
animation: hold var(--loop) infinite;
}
.line {
position: relative;
height: 7px;
}
.l1 {
width: 288px;
}
.l2 {
width: 192px;
}
.row {
position: absolute;
inset: 0;
display: flex;
}
.row span {
flex: 0 0 24px;
}
.row span::before {
content: '';
display: block;
height: 7px;
border-radius: 3.5px;
background: currentColor;
}
.ink {
color: var(--text);
}
.hot {
color: var(--clay);
}
.l1 span:nth-child(1)::before {
width: 18px;
}
.l1 span:nth-child(2)::before {
width: 12px;
}
.l1 span:nth-child(3)::before {
width: 20px;
}
.l1 span:nth-child(4)::before {
width: 14px;
}
.l1 span:nth-child(5)::before {
width: 16px;
}
.l1 span:nth-child(6)::before {
width: 12px;
}
.l1 span:nth-child(7)::before {
width: 19px;
}
.l1 span:nth-child(8)::before {
width: 15px;
}
.l1 span:nth-child(n + 9)::before {
display: none;
}
.l2 span:nth-child(1)::before {
width: 13px;
}
.l2 span:nth-child(2)::before {
width: 20px;
}
.l2 span:nth-child(3)::before {
width: 16px;
}
.l2 span:nth-child(4)::before {
width: 11px;
}
.l2 span:nth-child(n + 5)::before {
display: none;
}
.l1 .ink {
animation: ink-a var(--loop) infinite;
}
.l1 .hot {
animation: hot-a var(--loop) infinite;
}
.l2 .ink {
animation: ink-b var(--loop) infinite;
}
.l2 .hot {
animation: hot-b var(--loop) infinite;
}
/* --- timeline ---------------------------------------------------- */
@keyframes sent {
0%,
1% {
opacity: 0;
animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
}
4% {
opacity: 1;
}
11%,
100% {
opacity: 0;
}
}
@keyframes send {
0%,
4% {
opacity: 0;
transform: translateY(-4px);
}
5% {
opacity: 1;
transform: translateY(-4px);
animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
}
11.5% {
opacity: 1;
transform: translateY(14px);
}
12%,
100% {
opacity: 0;
transform: translateY(14px);
}
}
@keyframes receive {
0%,
11.4% {
transform: scale(1);
}
11.5% {
transform: scale(0.99);
animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
}
15%,
100% {
transform: scale(1);
}
}
@keyframes live {
0%,
11.5% {
opacity: 0;
animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
}
15%,
66.667% {
opacity: 1;
}
71%,
100% {
opacity: 0;
}
}
@keyframes gate {
0% {
opacity: 0;
}
16.667%,
66.6% {
opacity: 1;
}
66.667%,
100% {
opacity: 0;
}
}
@keyframes tick {
0% {
transform: scale(1.3);
opacity: 0.95;
animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
}
55%,
100% {
transform: scale(1);
opacity: 0.5;
}
}
/* Discrete steps, not a slide: a queue holds whole tokens. It empties the
instant the chunk leaves, then starts refilling — production never stops. */
@keyframes buffer {
0% {
clip-path: inset(0 75% 0 0);
animation-timing-function: steps(1, end);
}
25% {
clip-path: inset(0 50% 0 0);
animation-timing-function: steps(1, end);
}
50% {
clip-path: inset(0 25% 0 0);
animation-timing-function: steps(1, end);
}
75% {
clip-path: inset(0 0 0 0);
animation-timing-function: steps(1, end);
}
76%,
100% {
clip-path: inset(0 100% 0 0);
}
}
@keyframes deliver {
0%,
75% {
opacity: 0;
transform: translateY(0);
}
76% {
opacity: 1;
transform: translateY(0);
animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
}
90% {
opacity: 1;
transform: translateY(12px);
}
90.5%,
100% {
opacity: 0;
transform: translateY(12px);
}
}
/* Two steps across the first line instead of eight: four tokens land
together, then nothing for 700ms. Same total, worse to read. */
@keyframes ink-a {
0%,
31.667% {
clip-path: inset(0 288px 0 0);
animation-timing-function: steps(2, end);
}
65%,
100% {
clip-path: inset(0 96px 0 0);
}
}
@keyframes hot-a {
0% {
clip-path: inset(0 192px 0 0);
opacity: 0;
animation-timing-function: steps(1, end);
}
31.667% {
clip-path: inset(0 192px 0 0);
opacity: 1;
animation-timing-function: steps(2, end);
}
65%,
100% {
clip-path: inset(0 0 0 192px);
opacity: 1;
}
}
@keyframes ink-b {
0%,
65% {
clip-path: inset(0 192px 0 0);
animation-timing-function: steps(1, end);
}
81.667%,
100% {
clip-path: inset(0 96px 0 0);
}
}
@keyframes hot-b {
0% {
clip-path: inset(0 96px 0 0);
opacity: 0;
animation-timing-function: steps(1, end);
}
65% {
clip-path: inset(0 96px 0 0);
opacity: 1;
animation-timing-function: steps(1, end);
}
81.667%,
100% {
clip-path: inset(0 0 0 96px);
opacity: 1;
}
}
@keyframes hold {
0%,
88% {
opacity: 1;
animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
}
94%,
100% {
opacity: 0;
}
}
@media (prefers-reduced-motion: reduce) {
.pkt,
.flush {
animation: none;
opacity: 0;
}
.model {
animation: none;
}
.core {
animation: none;
opacity: 0.75;
}
/* The buffer is what makes this variant different from the steady one,
so it stays — held full, which is the state a bursty consumer sits in
between flushes. Nothing about it travels. */
.bufgate {
animation: none;
opacity: 1;
}
.fill {
animation: none;
clip-path: inset(0 0 0 0);
}
}
</style>
</head>
<body>
<div
class="sys"
role="img"
aria-label="A prompt enters a model; tokens queue in a four-slot buffer and are delivered to the completion four at a time"
>
<div class="prompt">
<b></b><b></b>
<i class="ring"></i>
</div>
<div class="chan a">
<i class="rail"></i>
<i class="pkt"></i>
</div>
<div class="model">
<i class="ring"></i>
<div class="beat"><i class="core"></i></div>
</div>
<div class="chan b">
<i class="rail"></i>
<div class="bufgate">
<i class="slots"></i>
<i class="fill"></i>
<i class="flush"></i>
</div>
</div>
<div class="out">
<div class="line l1">
<div class="row ink">
<span></span><span></span><span></span><span></span><span></span><span></span
><span></span><span></span><span></span><span></span><span></span><span></span>
</div>
<div class="row hot">
<span></span><span></span><span></span><span></span><span></span><span></span
><span></span><span></span><span></span><span></span><span></span><span></span>
</div>
</div>
<div class="line l2">
<div class="row ink">
<span></span><span></span><span></span><span></span><span></span><span></span
><span></span><span></span>
</div>
<div class="row hot">
<span></span><span></span><span></span><span></span><span></span><span></span
><span></span><span></span>
</div>
</div>
</div>
</div>
</body>
</html>
The variant family
Same idea, one axis moved. Compare them side by side before you commit.