Skip to content

Instantly share code, notes, and snippets.

@lassebenni
Created February 18, 2026 11:09
Show Gist options
  • Select an option

  • Save lassebenni/1849730eb5d448b866b4e0d26b8a1d2c to your computer and use it in GitHub Desktop.

Select an option

Save lassebenni/1849730eb5d448b866b4e0d26b8a1d2c to your computer and use it in GitHub Desktop.
Animation for: Separation of Concerns (I/O → Logic → Output)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Separation of Concerns — Data Pipeline Flow</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
background: #1a1a2e;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
}
svg { max-width: 700px; width: 100%; height: auto; }
/* ── Title ── */
.title {
fill: #e0e0e0;
font-size: 18px;
font-weight: 700;
text-anchor: middle;
opacity: 0;
animation: fadeIn 0.6s 0.2s forwards;
}
/* ── Boxes ── */
.box-input { fill: #16213e; stroke: #4fc3f7; stroke-width: 2; rx: 10; opacity: 0; animation: fadeSlideUp 0.5s 0.5s forwards; }
.box-logic { fill: #1a1a2e; stroke: #ffb74d; stroke-width: 2; rx: 10; opacity: 0; animation: fadeSlideUp 0.5s 0.8s forwards; }
.box-output { fill: #16213e; stroke: #81c784; stroke-width: 2; rx: 10; opacity: 0; animation: fadeSlideUp 0.5s 1.1s forwards; }
/* ── Headings ── */
.head-input { fill: #4fc3f7; font-size: 14px; font-weight: 700; text-anchor: middle; opacity: 0; animation: fadeIn 0.4s 0.8s forwards; }
.head-logic { fill: #ffb74d; font-size: 14px; font-weight: 700; text-anchor: middle; opacity: 0; animation: fadeIn 0.4s 1.1s forwards; }
.head-output { fill: #81c784; font-size: 14px; font-weight: 700; text-anchor: middle; opacity: 0; animation: fadeIn 0.4s 1.4s forwards; }
/* ── Subtitles ── */
.sub { fill: #b0b0b0; font-size: 11px; text-anchor: middle; opacity: 0; }
.sub-input { animation: fadeIn 0.4s 1.0s forwards; }
.sub-logic { animation: fadeIn 0.4s 1.3s forwards; }
.sub-output { animation: fadeIn 0.4s 1.6s forwards; }
/* ── Bullet items ── */
.item { fill: #d0d0d0; font-size: 10.5px; opacity: 0; }
.item-i1 { animation: fadeIn 0.3s 1.2s forwards; }
.item-i2 { animation: fadeIn 0.3s 1.3s forwards; }
.item-i3 { animation: fadeIn 0.3s 1.4s forwards; }
.item-l1 { animation: fadeIn 0.3s 1.5s forwards; }
.item-l2 { animation: fadeIn 0.3s 1.6s forwards; }
.item-l3 { animation: fadeIn 0.3s 1.7s forwards; }
.item-o1 { animation: fadeIn 0.3s 1.8s forwards; }
.item-o2 { animation: fadeIn 0.3s 1.9s forwards; }
.item-o3 { animation: fadeIn 0.3s 2.0s forwards; }
/* ── Arrows ── */
.arrow { stroke: #888; stroke-width: 2; fill: none; opacity: 0; }
.arrow-head { fill: #888; opacity: 0; }
.arrow1, .arrow-head1 { animation: fadeIn 0.3s 2.2s forwards; }
.arrow2, .arrow-head2 { animation: fadeIn 0.3s 2.5s forwards; }
/* ── Data dots ── */
.dot { r: 4; opacity: 0; }
.dot-1 { fill: #4fc3f7; animation: flowDot1 2.5s 3.0s infinite; }
.dot-2 { fill: #ffb74d; animation: flowDot2 2.5s 3.5s infinite; }
.dot-3 { fill: #81c784; animation: flowDot3 2.5s 4.0s infinite; }
/* ── Keyframes ── */
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes fadeSlideUp {
from { opacity: 0; transform: translateY(12px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes flowDot1 {
0% { cx: 50; cy: 185; opacity: 0; }
10% { opacity: 1; }
40% { cx: 220; cy: 185; opacity: 1; }
50% { opacity: 0; }
100% { opacity: 0; }
}
@keyframes flowDot2 {
0% { cx: 248; cy: 185; opacity: 0; }
10% { opacity: 1; }
40% { cx: 418; cy: 185; opacity: 1; }
50% { opacity: 0; }
100% { opacity: 0; }
}
@keyframes flowDot3 {
0% { cx: 448; cy: 185; opacity: 0; }
10% { opacity: 1; }
40% { cx: 618; cy: 185; opacity: 1; }
50% { opacity: 0; }
100% { opacity: 0; }
}
</style>
</head>
<body>
<svg viewBox="0 0 700 350" xmlns="http://www.w3.org/2000/svg">
<!-- Title -->
<text x="350" y="30" class="title">The Standard Data Pipeline Flow</text>
<!-- ─── INPUT BOX ─── -->
<rect x="30" y="60" width="175" height="250" class="box-input"/>
<text x="117" y="95" class="head-input">INPUT</text>
<text x="117" y="115" class="sub sub-input">Reading Data</text>
<text x="50" y="155" class="item item-i1">• Files (CSV, JSON)</text>
<text x="50" y="175" class="item item-i2">• Databases (SQL)</text>
<text x="50" y="195" class="item item-i3">• APIs &amp; Webhooks</text>
<!-- Arrow 1 -->
<line x1="210" y1="185" x2="245" y2="185" class="arrow arrow1"/>
<polygon points="245,180 255,185 245,190" class="arrow-head arrow-head1"/>
<!-- ─── BUSINESS LOGIC BOX ─── -->
<rect x="260" y="60" width="175" height="250" class="box-logic"/>
<text x="347" y="95" class="head-logic">BUSINESS LOGIC</text>
<text x="347" y="115" class="sub sub-logic">Processing Data</text>
<text x="280" y="155" class="item item-l1">• Transforming</text>
<text x="280" y="175" class="item item-l2">• Validating</text>
<text x="280" y="195" class="item item-l3">• Cleaning</text>
<!-- Arrow 2 -->
<line x1="440" y1="185" x2="475" y2="185" class="arrow arrow2"/>
<polygon points="475,180 485,185 475,190" class="arrow-head arrow-head2"/>
<!-- ─── OUTPUT BOX ─── -->
<rect x="490" y="60" width="175" height="250" class="box-output"/>
<text x="577" y="95" class="head-output">OUTPUT</text>
<text x="577" y="115" class="sub sub-output">Writing Data</text>
<text x="510" y="155" class="item item-o1">• Data Warehouses</text>
<text x="510" y="175" class="item item-o2">• Cloud Storage</text>
<text x="510" y="195" class="item item-o3">• Dashboards</text>
<!-- Flowing data dots -->
<circle class="dot dot-1"/>
<circle class="dot dot-2"/>
<circle class="dot dot-3"/>
</svg>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment