๐ How Websites Work
Before learning cloud computing, itโs important to understand how a website actually works.
<div class="infographic-rrflow">
<style>
.infographic-rrflow {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
--body-font: 'Inter', sans-serif;
}
.infographic-rrflow[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--accent: #5b8def;
--accent-soft:#202942;
--line: #2c313d;
}
.infographic-rrflow {
background: var(--paper);
color: var(--ink);
font-family: var(--body-font);
max-width: 880px;
margin: 0 auto;
padding: clamp(1.5rem, 5vw, 3rem);
border-radius: 20px;
box-sizing: border-box;
}
.infographic-rrflow * { box-sizing: border-box; }
.rr-status {
text-align: center;
font-size: 0.95rem;
font-weight: 600;
color: var(--accent);
min-height: 1.5em;
margin-bottom: 1.5rem;
}
/* --- Stage diagram: client / network / server with animated dot --- */
.rr-stage {
display: grid;
grid-template-columns: auto 1fr auto 1fr auto;
align-items: center;
padding: 0.5rem 0.5rem 1rem;
}
.rr-node {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.6rem;
}
.rr-node-icon {
width: 56px;
height: 56px;
display: flex;
align-items: center;
justify-content: center;
color: var(--ink);
background: var(--paper-alt);
border-radius: 16px;
padding: 12px;
transition: background 0.2s ease, color 0.2s ease;
}
.rr-node-icon svg { width: 100%; height: 100%; }
.rr-node-label {
font-size: 0.85rem;
font-weight: 600;
color: var(--ink-soft);
}
.rr-node.is-active .rr-node-icon { background: var(--accent-soft); color: var(--accent); }
.rr-node.is-active .rr-node-label { color: var(--accent); }
.rr-track {
position: relative;
height: 3px;
background: var(--line);
margin: 0 0.75rem;
min-width: 40px;
border-radius: 3px;
align-self: center;
}
.rr-packet {
position: absolute;
top: 50%;
left: 0;
width: 10px;
height: 10px;
border-radius: 50%;
background: var(--accent);
transform: translate(-50%, -50%);
opacity: 0;
}
.rr-packet.is-moving {
opacity: 1;
transition: left 1.8s ease;
}
.rr-controls {
display: flex;
justify-content: center;
margin-top: 1.75rem;
}
.rr-play-btn {
font: inherit;
font-size: 0.85rem;
font-weight: 600;
background: var(--accent);
color: var(--paper);
border: none;
padding: 0.65rem 1.3rem;
border-radius: 999px;
cursor: pointer;
}
.rr-play-btn:hover:not(:disabled) { opacity: 0.9; }
.rr-play-btn:disabled { opacity: 0.5; cursor: default; }
@media (max-width: 620px) {
.rr-stage { overflow-x: auto; }
}
@media (prefers-reduced-motion: reduce) {
.rr-packet.is-moving { transition-duration: 0.001ms !important; }
}
</style>
<div class="rr-status" id="statusText"></div>
<div class="rr-stage">
<div class="rr-node" data-node="client">
<div class="rr-node-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6">
<rect x="3" y="4" width="18" height="12" rx="1.5"/>
<line x1="8" y1="20" x2="16" y2="20"/>
<line x1="12" y1="16" x2="12" y2="20"/>
</svg>
</div>
<div class="rr-node-label">Client</div>
</div>
<div class="rr-track" id="trackOut">
<div class="rr-packet" id="packetOut"></div>
</div>
<div class="rr-node" data-node="network">
<div class="rr-node-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6">
<circle cx="12" cy="12" r="9"/>
<ellipse cx="12" cy="12" rx="4" ry="9"/>
<line x1="3" y1="12" x2="21" y2="12"/>
</svg>
</div>
<div class="rr-node-label">Network</div>
</div>
<div class="rr-track" id="trackIn">
<div class="rr-packet" id="packetIn"></div>
</div>
<div class="rr-node" data-node="server">
<div class="rr-node-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6">
<rect x="4" y="3" width="16" height="5" rx="1"/>
<rect x="4" y="9.5" width="16" height="5" rx="1"/>
<rect x="4" y="16" width="16" height="5" rx="1"/>
<circle cx="17.2" cy="5.5" r="0.7" fill="currentColor" stroke="none"/>
<circle cx="17.2" cy="12" r="0.7" fill="currentColor" stroke="none"/>
<circle cx="17.2" cy="18.5" r="0.7" fill="currentColor" stroke="none"/>
</svg>
</div>
<div class="rr-node-label">Server</div>
</div>
</div>
<div class="rr-controls">
<button class="rr-play-btn" id="playBtn">โถ Play the round trip</button>
</div>
</div>
<script>
(function () {
const wrapper = document.currentScript.closest('.infographic-rrflow')
|| document.querySelector('.infographic-rrflow');
const bodyAttr = document.body.getAttribute('data-darkmode');
let dark;
if (bodyAttr === 'true') {
dark = true;
} else if (bodyAttr === 'false') {
dark = false;
} else {
const match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) wrapper.setAttribute('data-theme', 'dark');
const nodes = wrapper.querySelectorAll('.rr-node');
const statusText = wrapper.querySelector('#statusText');
const packetOut = wrapper.querySelector('#packetOut');
const packetIn = wrapper.querySelector('#packetIn');
const playBtn = wrapper.querySelector('#playBtn');
function setActive(name, text) {
nodes.forEach(n => n.classList.toggle('is-active', n.dataset.node === name));
statusText.textContent = text;
}
function wait(ms) { return new Promise(res => setTimeout(res, ms)); }
function travel(packet, dir) {
packet.classList.remove('is-moving');
packet.style.left = dir === 'forward' ? '0%' : '100%';
void packet.offsetWidth;
packet.classList.add('is-moving');
requestAnimationFrame(() => {
packet.style.left = dir === 'forward' ? '100%' : '0%';
});
}
async function playSequence() {
playBtn.disabled = true;
packetOut.classList.remove('is-moving');
packetOut.style.left = '0%';
packetIn.classList.remove('is-moving');
packetIn.style.left = '0%';
void packetOut.offsetWidth;
setActive('client', 'Browser sends a request');
await wait(1500);
setActive('network', 'Request travels as packets');
travel(packetOut, 'forward');
await wait(1800);
setActive('server', 'Packets reach the server');
travel(packetIn, 'forward');
await wait(1800);
setActive('server', 'Server processes it');
await wait(1500);
setActive('network', 'Response travels back');
travel(packetIn, 'reverse');
await wait(1800);
setActive('client', 'Response arrives');
travel(packetOut, 'reverse');
await wait(1800);
setActive('client', 'Browser renders the page');
await wait(1500);
nodes.forEach(n => n.classList.remove('is-active'));
statusText.textContent = '';
playBtn.disabled = false;
}
playBtn.addEventListener('click', playSequence);
})();
</script>
</div>.demo {
font-family: system-ui, sans-serif;
padding: 16px;
}
.demo h1 {
color: #2563eb;
margin: 0 0 8px;
}
.demo p {
color: #4b5563;
margin: 0;
}document.querySelector('.demo h1')?.addEventListener('click', () => {
alert('Hello from live preview!');
});๐ Enter a website URL.
๐ค Your browser instantly sends a request.
๐ฆ The request races across the internet as data packets.
๐ฅ๏ธ It reaches the server hosting the website.
โ๏ธ The server processes your request.
๐ฅ A response is sent back to your browser.
โจ Your browser renders the websiteโready for you to explore!
๐ IP Address & DNS
<div class="infographic-dns">
<style>
.infographic-dns {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
--body-font: 'Inter', sans-serif;
--mono-font: 'IBM Plex Mono', monospace;
}
.infographic-dns[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--accent: #5b8def;
--accent-soft:#202942;
--line: #2c313d;
}
.infographic-dns {
background: var(--paper);
color: var(--ink);
font-family: var(--body-font);
max-width: 880px;
margin: 0 auto;
padding: clamp(1.5rem, 5vw, 3rem);
border-radius: 20px;
box-sizing: border-box;
}
.infographic-dns * { box-sizing: border-box; }
/* --- Note block --- */
.dns-note {
background: var(--paper-alt);
border-radius: 14px;
padding: 1.1rem 1.3rem;
margin-bottom: 2rem;
font-size: 0.92rem;
line-height: 1.6;
color: var(--ink);
}
.dns-note strong { color: var(--accent); }
.dns-note code {
font-family: var(--mono-font);
background: var(--accent-soft);
color: var(--accent);
padding: 0.1rem 0.35rem;
border-radius: 6px;
font-size: 0.85em;
}
.dns-note ul {
margin: 0;
padding-left: 1.2rem;
}
.dns-note li {
margin-bottom: 0.45rem;
}
.dns-note li:last-child { margin-bottom: 0; }
.dns-note .dns-note-arrow {
margin-top: 0.7rem;
padding-top: 0.7rem;
border-top: 1px solid var(--line);
display: flex;
align-items: center;
gap: 0.5rem;
flex-wrap: wrap;
font-weight: 600;
}
.dns-note .dns-note-arrow svg { flex: 0 0 auto; color: var(--accent); }
/* --- Status line --- */
.dns-status {
text-align: center;
font-size: 0.95rem;
font-weight: 600;
color: var(--accent);
min-height: 1.5em;
margin-bottom: 1.5rem;
}
/* --- Stage diagram --- */
.dns-stage {
display: grid;
grid-template-columns: auto 1fr auto 1fr auto 1fr auto;
align-items: center;
padding: 0.5rem 0.5rem 1rem;
}
.dns-node {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.6rem;
}
.dns-node-icon {
width: 56px;
height: 56px;
display: flex;
align-items: center;
justify-content: center;
color: var(--ink);
background: var(--paper-alt);
border-radius: 16px;
padding: 12px;
transition: background 0.2s ease, color 0.2s ease;
}
.dns-node-icon svg { width: 100%; height: 100%; }
.dns-node-label {
font-size: 0.82rem;
font-weight: 600;
color: var(--ink-soft);
text-align: center;
}
.dns-node-value {
font-family: var(--mono-font);
font-size: 0.72rem;
color: var(--ink-soft);
text-align: center;
min-height: 1.2em;
}
.dns-node.is-active .dns-node-icon { background: var(--accent-soft); color: var(--accent); }
.dns-node.is-active .dns-node-label { color: var(--accent); }
.dns-node.is-resolved .dns-node-value { color: var(--accent); font-weight: 600; }
.dns-track {
position: relative;
height: 3px;
background: var(--line);
margin: 0 0.6rem;
min-width: 28px;
border-radius: 3px;
align-self: center;
top: -14px;
}
.dns-packet {
position: absolute;
top: 50%;
left: 0;
width: 10px;
height: 10px;
border-radius: 50%;
background: var(--accent);
transform: translate(-50%, -50%);
opacity: 0;
}
.dns-packet.is-moving {
opacity: 1;
transition: left 1.4s ease;
}
/* --- Controls --- */
.dns-controls {
display: flex;
justify-content: center;
align-items: center;
gap: 0.6rem;
margin-top: 1.75rem;
flex-wrap: wrap;
}
.dns-input {
font: inherit;
font-size: 0.85rem;
font-family: var(--mono-font);
color: var(--ink);
background: var(--paper-alt);
border: 1px solid var(--line);
border-radius: 999px;
padding: 0.6rem 1rem;
min-width: 200px;
text-align: center;
}
.dns-input:focus { outline: none; border-color: var(--accent); }
.dns-play-btn {
font: inherit;
font-size: 0.85rem;
font-weight: 600;
background: var(--accent);
color: var(--paper);
border: none;
padding: 0.65rem 1.3rem;
border-radius: 999px;
cursor: pointer;
}
.dns-play-btn:hover:not(:disabled) { opacity: 0.9; }
.dns-play-btn:disabled { opacity: 0.5; cursor: default; }
@media (max-width: 680px) {
.dns-stage { overflow-x: auto; }
.dns-node-label { font-size: 0.74rem; }
}
@media (prefers-reduced-motion: reduce) {
.dns-packet.is-moving { transition-duration: 0.001ms !important; }
}
</style>
<div class="dns-note">
<ul>
<li>Every device on a network has an <strong>IP address</strong> โ a unique identifier.</li>
<li>IP addresses let systems locate and communicate with each other.</li>
<li>Since people find names easier to remember than numbers, <strong>DNS (Domain Name System)</strong> steps in.</li>
</ul>
<div class="dns-note-arrow">
<code>www.example.com</code>
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>
<code id="noteIp">93.184.216.34</code>
<span style="font-weight: 400; color: var(--ink-soft); font-size: 0.85em;">โ the browser now knows exactly which server to reach.</span>
</div>
</div>
<div class="dns-status" id="dnsStatus"></div>
<div class="dns-stage">
<div class="dns-node" data-node="browser">
<div class="dns-node-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6">
<rect x="3" y="4" width="18" height="12" rx="1.5"/>
<line x1="8" y1="20" x2="16" y2="20"/>
<line x1="12" y1="16" x2="12" y2="20"/>
</svg>
</div>
<div class="dns-node-label">Browser</div>
<div class="dns-node-value" id="valBrowser"></div>
</div>
<div class="dns-track"><div class="dns-packet" id="p1"></div></div>
<div class="dns-node" data-node="dns">
<div class="dns-node-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6">
<circle cx="12" cy="12" r="9"/>
<path d="M12 3a13 13 0 0 1 0 18"/>
<path d="M12 3a13 13 0 0 0 0 18"/>
<line x1="3" y1="12" x2="21" y2="12"/>
</svg>
</div>
<div class="dns-node-label">DNS</div>
<div class="dns-node-value" id="valDns"></div>
</div>
<div class="dns-track"><div class="dns-packet" id="p2"></div></div>
<div class="dns-node" data-node="ip">
<div class="dns-node-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6">
<path d="M20.59 13.41 11 3.83 4 4l-.17 7L13.4 20.6a2 2 0 0 0 2.83 0l4.36-4.36a2 2 0 0 0 0-2.83Z"/>
<circle cx="8.5" cy="8.5" r="1.2" fill="currentColor" stroke="none"/>
</svg>
</div>
<div class="dns-node-label">IP Address</div>
<div class="dns-node-value" id="valIp">โ</div>
</div>
<div class="dns-track"><div class="dns-packet" id="p3"></div></div>
<div class="dns-node" data-node="server">
<div class="dns-node-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6">
<rect x="4" y="3" width="16" height="5" rx="1"/>
<rect x="4" y="9.5" width="16" height="5" rx="1"/>
<rect x="4" y="16" width="16" height="5" rx="1"/>
<circle cx="17.2" cy="5.5" r="0.7" fill="currentColor" stroke="none"/>
<circle cx="17.2" cy="12" r="0.7" fill="currentColor" stroke="none"/>
<circle cx="17.2" cy="18.5" r="0.7" fill="currentColor" stroke="none"/>
</svg>
</div>
<div class="dns-node-label">Server</div>
<div class="dns-node-value" id="valServer"></div>
</div>
</div>
<div class="dns-controls">
<input class="dns-input" id="domainInput" type="text" value="www.example.com" spellcheck="false" />
<button class="dns-play-btn" id="resolveBtn">โถ Resolve</button>
</div>
</div>
<script>
(function () {
const wrapper = document.currentScript.closest('.infographic-dns')
|| document.querySelector('.infographic-dns');
const bodyAttr = document.body.getAttribute('data-darkmode');
let dark;
if (bodyAttr === 'true') {
dark = true;
} else if (bodyAttr === 'false') {
dark = false;
} else {
const match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) wrapper.setAttribute('data-theme', 'dark');
const nodes = wrapper.querySelectorAll('.dns-node');
const statusText = wrapper.querySelector('#dnsStatus');
const domainInput = wrapper.querySelector('#domainInput');
const resolveBtn = wrapper.querySelector('#resolveBtn');
const p1 = wrapper.querySelector('#p1');
const p2 = wrapper.querySelector('#p2');
const p3 = wrapper.querySelector('#p3');
const valBrowser = wrapper.querySelector('#valBrowser');
const valDns = wrapper.querySelector('#valDns');
const valIp = wrapper.querySelector('#valIp');
const valServer = wrapper.querySelector('#valServer');
function setActive(name, text) {
nodes.forEach(n => n.classList.toggle('is-active', n.dataset.node === name));
statusText.textContent = text;
}
function wait(ms) { return new Promise(res => setTimeout(res, ms)); }
function travel(packet, dir) {
packet.classList.remove('is-moving');
packet.style.left = dir === 'forward' ? '0%' : '100%';
void packet.offsetWidth;
packet.classList.add('is-moving');
requestAnimationFrame(() => {
packet.style.left = dir === 'forward' ? '100%' : '0%';
});
}
// Deterministic fake IP so the same domain always "resolves" the same way.
function fakeIp(domain) {
let hash = 0;
for (let i = 0; i < domain.length; i++) {
hash = (hash * 31 + domain.charCodeAt(i)) >>> 0;
}
const a = 20 + (hash % 220);
const b = (hash >> 8) % 256;
const c = (hash >> 16) % 256;
const d = 1 + ((hash >> 24) % 254);
return `${a}.${b}.${c}.${d}`;
}
async function playSequence() {
resolveBtn.disabled = true;
domainInput.disabled = true;
const domain = (domainInput.value || 'www.example.com').trim();
const ip = fakeIp(domain);
nodes.forEach(n => n.classList.remove('is-resolved'));
valBrowser.textContent = '';
valDns.textContent = '';
valIp.textContent = 'โ';
valServer.textContent = '';
[p1, p2, p3].forEach(p => { p.classList.remove('is-moving'); p.style.left = '0%'; });
void p1.offsetWidth;
setActive('browser', `Browser asks: what's the IP for ${domain}?`);
valBrowser.textContent = domain;
await wait(1300);
setActive('dns', 'DNS looks up the domain');
travel(p1, 'forward');
await wait(1400);
setActive('ip', 'DNS returns the matching IP address');
valDns.textContent = domain;
travel(p2, 'forward');
await wait(1400);
valIp.textContent = ip;
wrapper.querySelector('[data-node="ip"]').classList.add('is-resolved');
setActive('server', 'Browser connects using the IP');
travel(p3, 'forward');
await wait(1400);
valServer.textContent = ip;
setActive('server', 'Connected to the right server');
await wait(1400);
nodes.forEach(n => n.classList.remove('is-active'));
statusText.textContent = '';
resolveBtn.disabled = false;
domainInput.disabled = false;
}
resolveBtn.addEventListener('click', playSequence);
domainInput.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && !resolveBtn.disabled) playSequence();
});
})();
</script>
</div>.demo {
font-family: system-ui, sans-serif;
padding: 16px;
}
.demo h1 {
color: #2563eb;
margin: 0 0 8px;
}
.demo p {
color: #4b5563;
margin: 0;
}document.querySelector('.demo h1')?.addEventListener('click', () => {
alert('Hello from live preview!');
});๐ฝ๏ธ Simple Analogy (Restaurant)
Element | IT Equivalent | Role |
|---|---|---|
Customer | Client (Browser) | Sends request |
Order | Data Packet | Contains request |
Waiter | Network | Transfers data |
Kitchen | Server | Processes request |
Food | Response | Returns result |
๐ฅ๏ธ Traditional Server Components

<div class="infographic-server">
<style>
.infographic-server {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
--body-font: 'Inter', sans-serif;
--mono-font: 'IBM Plex Mono', monospace;
}
.infographic-server[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--accent: #5b8def;
--accent-soft:#202942;
--line: #2c313d;
}
.infographic-server {
background: var(--paper);
color: var(--ink);
font-family: var(--body-font);
max-width: 880px;
margin: 0 auto;
padding: clamp(1.5rem, 5vw, 3rem);
border-radius: 20px;
box-sizing: border-box;
}
.infographic-server * { box-sizing: border-box; }
.srv-title {
font-size: 1.05rem;
font-weight: 700;
margin: 0 0 1.5rem;
text-align: center;
}
.srv-layout {
display: grid;
grid-template-columns: minmax(220px, 320px) 1fr;
gap: 2rem;
align-items: start;
}
/* --- Rack diagram --- */
.srv-rack {
display: flex;
flex-direction: column;
gap: 0.6rem;
}
.srv-unit {
display: flex;
align-items: center;
gap: 0.8rem;
background: var(--paper-alt);
border: none;
border-radius: 14px;
padding: 0.9rem 1rem;
cursor: pointer;
font: inherit;
text-align: left;
color: var(--ink);
transition: background 0.2s ease, color 0.2s ease;
}
.srv-unit-icon {
flex: 0 0 auto;
width: 34px;
height: 34px;
display: flex;
align-items: center;
justify-content: center;
}
.srv-unit-icon svg { width: 100%; height: 100%; }
.srv-unit-text {
display: flex;
flex-direction: column;
gap: 0.1rem;
}
.srv-unit-title {
font-weight: 700;
font-size: 0.92rem;
}
.srv-unit-sub {
font-size: 0.76rem;
color: var(--ink-soft);
}
.srv-unit.is-active {
background: var(--accent-soft);
color: var(--accent);
}
.srv-unit.is-active .srv-unit-sub { color: var(--accent); opacity: 0.8; }
/* --- Detail panel --- */
.srv-detail {
background: var(--paper-alt);
border-radius: 16px;
padding: 1.4rem 1.5rem;
min-height: 220px;
}
.srv-detail-heading {
font-size: 0.78rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--accent);
margin: 0 0 1rem;
}
.srv-part-row {
display: flex;
align-items: baseline;
gap: 0.6rem;
padding: 0.65rem 0;
border-bottom: 1px solid var(--line);
}
.srv-part-row:last-child { border-bottom: none; }
.srv-part-name {
font-family: var(--mono-font);
font-weight: 700;
font-size: 0.86rem;
color: var(--ink);
flex: 0 0 auto;
min-width: 92px;
}
.srv-part-arrow { color: var(--accent); flex: 0 0 auto; }
.srv-part-desc {
font-size: 0.86rem;
color: var(--ink-soft);
line-height: 1.4;
}
@media (max-width: 640px) {
.srv-layout { grid-template-columns: 1fr; }
}
</style>
<div class="srv-layout">
<div class="srv-rack" id="srvRack">
<button class="srv-unit" data-part="compute">
<div class="srv-unit-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6">
<rect x="7" y="7" width="10" height="10" rx="1"/>
<rect x="10" y="10" width="4" height="4" rx="0.5"/>
<line x1="7" y1="3" x2="7" y2="6"/>
<line x1="12" y1="3" x2="12" y2="6"/>
<line x1="17" y1="3" x2="17" y2="6"/>
<line x1="7" y1="18" x2="7" y2="21"/>
<line x1="12" y1="18" x2="12" y2="21"/>
<line x1="17" y1="18" x2="17" y2="21"/>
<line x1="3" y1="7" x2="6" y2="7"/>
<line x1="3" y1="12" x2="6" y2="12"/>
<line x1="3" y1="17" x2="6" y2="17"/>
<line x1="18" y1="7" x2="21" y2="7"/>
<line x1="18" y1="12" x2="21" y2="12"/>
<line x1="18" y1="17" x2="21" y2="17"/>
</svg>
</div>
<div class="srv-unit-text">
<div class="srv-unit-title">Compute & Memory</div>
<div class="srv-unit-sub">CPU, RAM</div>
</div>
</button>
<button class="srv-unit" data-part="storage">
<div class="srv-unit-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6">
<ellipse cx="12" cy="5.5" rx="8" ry="2.5"/>
<path d="M4 5.5v6c0 1.4 3.6 2.5 8 2.5s8-1.1 8-2.5v-6"/>
<path d="M4 11.5v6c0 1.4 3.6 2.5 8 2.5s8-1.1 8-2.5v-6"/>
</svg>
</div>
<div class="srv-unit-text">
<div class="srv-unit-title">Storage</div>
<div class="srv-unit-sub">HDD/SSD, Databases</div>
</div>
</button>
<button class="srv-unit" data-part="network">
<div class="srv-unit-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6">
<circle cx="5" cy="12" r="2.4"/>
<circle cx="19" cy="6" r="2.4"/>
<circle cx="19" cy="18" r="2.4"/>
<line x1="7.1" y1="11" x2="16.9" y2="6.9"/>
<line x1="7.1" y1="13" x2="16.9" y2="17.1"/>
</svg>
</div>
<div class="srv-unit-text">
<div class="srv-unit-title">Networking</div>
<div class="srv-unit-sub">Router, Switch, DNS</div>
</div>
</button>
</div>
<div class="srv-detail" id="srvDetail"></div>
</div>
</div>
<script>
(function () {
const wrapper = document.currentScript.closest('.infographic-server')
|| document.querySelector('.infographic-server');
const bodyAttr = document.body.getAttribute('data-darkmode');
let dark;
if (bodyAttr === 'true') {
dark = true;
} else if (bodyAttr === 'false') {
dark = false;
} else {
const match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) wrapper.setAttribute('data-theme', 'dark');
const DATA = {
compute: {
heading: 'Compute & Memory',
parts: [
{ name: 'CPU', desc: 'Processes instructions.' },
{ name: 'RAM', desc: 'Temporary working memory.' },
],
},
storage: {
heading: 'Storage',
parts: [
{ name: 'HDD/SSD', desc: 'Long-term data storage.' },
{ name: 'Databases', desc: 'Structured data storage.' },
],
},
network: {
heading: 'Networking',
parts: [
{ name: 'Router', desc: 'Connects different networks.' },
{ name: 'Switch', desc: 'Manages internal traffic.' },
{ name: 'DNS Server', desc: 'Resolves domain to IP.' },
],
},
};
const units = wrapper.querySelectorAll('.srv-unit');
const detail = wrapper.querySelector('#srvDetail');
function render(key) {
units.forEach(u => u.classList.toggle('is-active', u.dataset.part === key));
const d = DATA[key];
detail.innerHTML =
'<div class="srv-detail-heading">' + d.heading + '</div>' +
d.parts.map(p =>
'<div class="srv-part-row">' +
'<span class="srv-part-name">' + p.name + '</span>' +
'<span class="srv-part-arrow">โ</span>' +
'<span class="srv-part-desc">' + p.desc + '</span>' +
'</div>'
).join('');
}
units.forEach(u => {
u.addEventListener('click', () => render(u.dataset.part));
});
render('compute');
})();
</script>
</div>.demo {
font-family: system-ui, sans-serif;
padding: 16px;
}
.demo h1 {
color: #2563eb;
margin: 0 0 8px;
}
.demo p {
color: #4b5563;
margin: 0;
}document.querySelector('.demo h1')?.addEventListener('click', () => {
alert('Hello from live preview!');
});๐ Key IT Terminology
<div class="infographic-net">
<style>
.infographic-net {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
--body-font: 'Inter', sans-serif;
}
.infographic-net[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--accent: #5b8def;
--accent-soft:#202942;
--line: #2c313d;
}
.infographic-net {
background: var(--paper);
color: var(--ink);
font-family: var(--body-font);
max-width: 880px;
margin: 0 auto;
padding: clamp(1.5rem, 5vw, 3rem);
border-radius: 20px;
box-sizing: border-box;
}
.infographic-net * { box-sizing: border-box; }
.net-status {
text-align: center;
font-size: 0.95rem;
font-weight: 600;
color: var(--accent);
min-height: 1.5em;
margin-bottom: 0.75rem;
}
.net-svg-wrap { width: 100%; }
.net-svg { width: 100%; height: auto; display: block; overflow: visible; }
.net-line { stroke: var(--line); stroke-width: 2; }
.net-node { cursor: pointer; color: var(--ink-soft); }
.net-node:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
.net-node .net-icon { color: var(--ink); transition: color 0.2s ease; }
.net-node .net-label { fill: var(--ink-soft); font-size: 22px; font-weight: 700; transition: fill 0.2s ease; }
.net-node.is-active .net-icon { color: var(--accent); }
.net-node.is-active .net-label { fill: var(--accent); }
.net-node.is-static { cursor: default; }
.net-packet {
fill: var(--accent);
opacity: 0;
transition: cx 1.1s ease, cy 1.1s ease;
}
.net-packet.is-visible { opacity: 1; }
.net-detail {
min-height: 2.6em;
text-align: center;
font-size: 0.85rem;
color: var(--ink-soft);
margin-top: 0.5rem;
}
.net-detail strong { color: var(--ink); }
.net-controls {
display: flex;
justify-content: center;
margin-top: 1.5rem;
}
.net-play-btn {
font: inherit;
font-size: 0.85rem;
font-weight: 600;
background: var(--accent);
color: var(--paper);
border: none;
padding: 0.65rem 1.3rem;
border-radius: 999px;
cursor: pointer;
}
.net-play-btn:hover:not(:disabled) { opacity: 0.9; }
.net-play-btn:disabled { opacity: 0.5; cursor: default; }
@media (prefers-reduced-motion: reduce) {
.net-packet { transition-duration: 0.001ms !important; }
}
</style>
<div class="net-status" id="netStatus"> </div>
<div class="net-svg-wrap">
<svg class="net-svg" viewBox="0 0 1000 470" xmlns="http://www.w3.org/2000/svg">
<defs>
<symbol id="net-icon-monitor" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6">
<rect x="3" y="4" width="18" height="12" rx="1.5"/>
<line x1="8" y1="20" x2="16" y2="20"/>
<line x1="12" y1="16" x2="12" y2="20"/>
</symbol>
<symbol id="net-icon-router" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6">
<rect x="3" y="14" width="18" height="7" rx="1.5"/>
<rect x="6" y="17" width="2" height="1.4" fill="currentColor" stroke="none"/>
<line x1="10.5" y1="17" x2="10.5" y2="18.4"/>
<line x1="13.5" y1="17" x2="13.5" y2="18.4"/>
<line x1="16.5" y1="17" x2="16.5" y2="18.4"/>
<line x1="12" y1="14" x2="12" y2="8"/>
<path d="M9 8a4.2 4.2 0 0 1 6 0"/>
<path d="M7 6a7 7 0 0 1 10 0"/>
</symbol>
<symbol id="net-icon-switch" viewBox="0 0 34 24" fill="none" stroke="currentColor" stroke-width="1.6">
<path d="M4 9 8 5h18l4 4"/>
<rect x="2" y="9" width="30" height="9" rx="1.2"/>
<circle cx="6.5" cy="13.5" r="0.7" fill="currentColor" stroke="none"/>
<circle cx="10.5" cy="13.5" r="0.7" fill="currentColor" stroke="none"/>
<circle cx="14.5" cy="13.5" r="0.7" fill="currentColor" stroke="none"/>
<circle cx="18.5" cy="13.5" r="0.7" fill="currentColor" stroke="none"/>
<circle cx="22.5" cy="13.5" r="0.7" fill="currentColor" stroke="none"/>
<circle cx="26.5" cy="13.5" r="0.7" fill="currentColor" stroke="none"/>
</symbol>
</defs>
<!-- connecting lines -->
<line class="net-line" x1="112" y1="245" x2="255" y2="245"/>
<line class="net-line" x1="335" y1="245" x2="470" y2="245"/>
<line class="net-line" x1="580" y1="245" x2="850" y2="85"/>
<line class="net-line" x1="580" y1="245" x2="850" y2="245"/>
<line class="net-line" x1="580" y1="245" x2="850" y2="405"/>
<!-- client -->
<g class="net-node is-static" data-part="client">
<use class="net-icon" href="#net-icon-monitor" x="42" y="210" width="70" height="70"/>
</g>
<!-- router -->
<g class="net-node" data-part="router" tabindex="0" role="button" aria-label="Router">
<use class="net-icon" href="#net-icon-router" x="260" y="210" width="70" height="70"/>
<text class="net-label" x="295" y="312" text-anchor="middle">Router</text>
</g>
<!-- switch -->
<g class="net-node" data-part="switch" tabindex="0" role="button" aria-label="Switch">
<use class="net-icon" href="#net-icon-switch" x="470" y="222" width="110" height="46"/>
<text class="net-label" x="525" y="312" text-anchor="middle">Switch</text>
</g>
<!-- devices -->
<g class="net-node is-static" data-part="device1">
<use class="net-icon" href="#net-icon-monitor" x="815" y="50" width="70" height="70"/>
</g>
<g class="net-node is-static" data-part="device2">
<use class="net-icon" href="#net-icon-monitor" x="815" y="210" width="70" height="70"/>
</g>
<g class="net-node is-static" data-part="device3">
<use class="net-icon" href="#net-icon-monitor" x="815" y="370" width="70" height="70"/>
</g>
<!-- packets -->
<circle class="net-packet" id="pkt1" cx="112" cy="245" r="7"/>
<circle class="net-packet" id="pkt2" cx="580" cy="245" r="7"/>
<circle class="net-packet" id="pkt3" cx="580" cy="245" r="7"/>
</svg>
</div>
<div class="net-detail" id="netDetail">Click Router or Switch to see what it does.</div>
<div class="net-controls">
<button class="net-play-btn" id="playBtn">โถ Send data across the network</button>
</div>
</div>
<script>
(function () {
const wrapper = document.currentScript.closest('.infographic-net')
|| document.querySelector('.infographic-net');
const bodyAttr = document.body.getAttribute('data-darkmode');
let dark;
if (bodyAttr === 'true') {
dark = true;
} else if (bodyAttr === 'false') {
dark = false;
} else {
const match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) wrapper.setAttribute('data-theme', 'dark');
const DESCRIPTIONS = {
router: 'Router โ Connects different networks.',
switch: 'Switch โ Manages internal traffic.',
};
const nodes = wrapper.querySelectorAll('.net-node');
const clickable = wrapper.querySelectorAll('.net-node[data-part="router"], .net-node[data-part="switch"]');
const status = wrapper.querySelector('#netStatus');
const detail = wrapper.querySelector('#netDetail');
const playBtn = wrapper.querySelector('#playBtn');
const pkt1 = wrapper.querySelector('#pkt1');
const pkt2 = wrapper.querySelector('#pkt2');
const pkt3 = wrapper.querySelector('#pkt3');
function node(part) { return wrapper.querySelector('.net-node[data-part="' + part + '"]'); }
function setActive(parts) {
nodes.forEach(n => n.classList.toggle('is-active', parts.includes(n.dataset.part)));
}
function wait(ms) { return new Promise(res => setTimeout(res, ms)); }
// --- click a router/switch icon to read what it does ---
clickable.forEach(el => {
function toggle() {
const part = el.dataset.part;
const alreadyActive = el.classList.contains('is-active');
setActive(alreadyActive ? [] : [part]);
detail.innerHTML = alreadyActive
? 'Click Router or Switch to see what it does.'
: '<strong>' + DESCRIPTIONS[part] + '</strong>';
}
el.addEventListener('click', toggle);
el.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); toggle(); }
});
});
// --- play the full journey: client -> router -> switch -> all devices ---
async function playSequence() {
playBtn.disabled = true;
detail.textContent = 'Click Router or Switch to see what it does.';
[pkt1, pkt2, pkt3].forEach(p => p.classList.remove('is-visible'));
pkt1.setAttribute('cx', 112); pkt1.setAttribute('cy', 245);
pkt2.setAttribute('cx', 580); pkt2.setAttribute('cy', 245);
pkt3.setAttribute('cx', 580); pkt3.setAttribute('cy', 245);
setActive([]);
setActive(['client']);
status.textContent = 'Client sends data';
await wait(1000);
setActive(['router']);
pkt1.classList.add('is-visible');
pkt1.setAttribute('cx', 295); pkt1.setAttribute('cy', 245);
status.textContent = 'Router directs it toward the network';
await wait(1300);
setActive(['switch']);
pkt1.setAttribute('cx', 525); pkt1.setAttribute('cy', 245);
status.textContent = 'Switch receives the data';
await wait(1300);
setActive(['device1', 'device2', 'device3']);
pkt2.classList.add('is-visible');
pkt3.classList.add('is-visible');
pkt1.setAttribute('cx', 850); pkt1.setAttribute('cy', 245);
pkt2.setAttribute('cx', 850); pkt2.setAttribute('cy', 85);
pkt3.setAttribute('cx', 850); pkt3.setAttribute('cy', 405);
status.textContent = 'Switch forwards it to the right device';
await wait(1300);
status.textContent = 'Delivered';
await wait(1000);
setActive([]);
status.innerHTML = ' ';
playBtn.disabled = false;
}
playBtn.addEventListener('click', playSequence);
})();
</script>
</div>.demo {
font-family: system-ui, sans-serif;
padding: 16px;
}
.demo h1 {
color: #2563eb;
margin: 0 0 8px;
}
.demo p {
color: #4b5563;
margin: 0;
}document.querySelector('.demo h1')?.addEventListener('click', () => {
alert('Hello from live preview!');
});A collection of connected devices
Servers
Routers
Switches
Cables
That communicate with each other.
A device that forwards data packets between different networks and determines the best path on the internet.
A device that forwards packets to the correct server or client within a local network.
๐ข Traditional Infrastructure: How It Used to Work
<div class="infographic-infraevo2">
<style>
.infographic-infraevo2 {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
--radius: 10px;
--display-font: Georgia, 'Iowan Old Style', serif;
--mono-font: 'SFMono-Regular', Consolas, monospace;
position: relative;
background: var(--paper);
color: var(--ink);
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
padding: 3rem 1.75rem 2.5rem;
box-sizing: border-box;
overflow: hidden;
}
.infographic-infraevo2[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #13171F;
--paper-alt: #1c2129;
--accent: #5b8def;
--accent-soft:#202942;
--line: #2c313d;
}
.infographic-infraevo2 * { box-sizing: border-box; }
.ie2-bg-word {
position: absolute; top: -0.5rem; left: 50%; transform: translateX(-50%);
font-family: var(--display-font); font-size: clamp(4rem, 14vw, 9rem);
color: var(--ink); opacity: 0.035; font-weight: 700; white-space: nowrap;
pointer-events: none; letter-spacing: -0.02em; z-index: 0;
}
.ie2-head { position: relative; z-index: 1; text-align: center; margin-bottom: 2.75rem; }
.ie2-eyebrow {
font-size: 0.72rem; letter-spacing: 0.16em; text-transform: uppercase;
color: var(--accent); font-weight: 700; margin: 0 0 0.6rem;
}
.ie2-head h2 {
font-family: var(--display-font); font-size: clamp(1.6rem, 3.4vw, 2.15rem);
margin: 0 0 0.5rem; font-weight: 600; letter-spacing: -0.01em;
}
.ie2-head p {
color: var(--ink-soft); font-size: 0.92rem; margin: 0 auto; max-width: 42ch;
}
.ie2-road {
position: relative; z-index: 1; max-width: 960px; margin: 0 auto;
}
.ie2-path-svg { position: absolute; left: 0; top: 34px; width: 100%; height: 40px; z-index: 0; }
.ie2-path-svg path {
fill: none; stroke: var(--line); stroke-width: 2.5; stroke-dasharray: 1 10;
stroke-linecap: round;
}
.ie2-flow {
display: flex; gap: 1.25rem; align-items: flex-end; position: relative; z-index: 1;
}
.ie2-step {
flex: 1 1 0; background: var(--paper-alt); border: 1px solid var(--line);
border-radius: var(--radius); padding: 1.5rem 1.25rem 1.35rem; position: relative;
cursor: pointer; text-align: left; font: inherit; color: inherit;
transition: border-color 0.18s, background 0.18s, transform 0.18s;
overflow: hidden;
}
.ie2-step[data-step="1"] { flex-grow: 1; min-height: 190px; }
.ie2-step[data-step="2"] { flex-grow: 1.3; min-height: 225px; }
.ie2-step[data-step="3"] { flex-grow: 1.65; min-height: 265px; align-self: stretch; }
.ie2-step:hover { border-color: var(--accent); transform: translateY(-2px); }
.ie2-step.is-open { border-color: var(--accent); background: var(--accent-soft); }
.ie2-ghost-num {
position: absolute; right: -0.3rem; bottom: -0.9rem;
font-family: var(--display-font); font-size: 5.5rem; font-weight: 700;
color: var(--ink); opacity: 0.06; line-height: 1; pointer-events: none;
}
.ie2-step.is-open .ie2-ghost-num { color: var(--accent); opacity: 0.14; }
.ie2-step .ie2-icon { width: 46px; height: 46px; margin-bottom: 0.75rem; position: relative; z-index: 1; }
.ie2-step[data-step="2"] .ie2-icon { width: 52px; height: 52px; }
.ie2-step[data-step="3"] .ie2-icon { width: 60px; height: 60px; }
.ie2-step .ie2-icon svg { width: 100%; height: 100%; display: block; }
.ie2-step .ie2-icon [stroke] { stroke: var(--ink); transition: stroke 0.18s; }
.ie2-step.is-open .ie2-icon [stroke] { stroke: var(--accent); }
.ie2-step .ie2-tag {
font-size: 0.68rem; letter-spacing: 0.08em; text-transform: uppercase;
color: var(--accent); font-weight: 700; margin-bottom: 0.2rem; position: relative; z-index: 1;
}
.ie2-step h3 { margin: 0 0 0.3rem; font-size: 1.08rem; position: relative; z-index: 1; }
.ie2-scalebar { height: 4px; border-radius: 4px; background: var(--line); margin: 0.5rem 0 0.7rem;
overflow: hidden; position: relative; z-index: 1; max-width: 140px; }
.ie2-scalebar span { display: block; height: 100%; background: var(--accent); border-radius: 4px;
transition: width 0.5s ease; }
.ie2-detail {
display: none; margin-top: 0.6rem; padding-top: 0.7rem; position: relative; z-index: 1;
border-top: 1px dashed var(--line); font-size: 0.83rem; color: var(--ink-soft); line-height: 1.45;
}
.ie2-step.is-open .ie2-detail { display: block; }
.ie2-pills { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.6rem; }
.ie2-pill {
font-size: 0.7rem; background: var(--paper); border: 1px solid var(--line);
border-radius: var(--radius); padding: 0.2rem 0.5rem; color: var(--ink);
}
@media (max-width: 700px) {
.ie2-path-svg { display: none; }
.ie2-flow { flex-direction: column; align-items: stretch; }
.ie2-step[data-step="1"],
.ie2-step[data-step="2"],
.ie2-step[data-step="3"] { min-height: auto; }
}
.ie2-stats {
position: relative; z-index: 1; max-width: 960px; margin: 2.5rem auto 0;
border-top: 1px solid var(--line); padding-top: 1.5rem;
}
.ie2-stats-title { font-size: 0.72rem; letter-spacing: 0.1em; text-transform: uppercase;
color: var(--ink-soft); font-weight: 700; margin-bottom: 0.9rem; }
.ie2-stat-row { display: grid; grid-template-columns: 110px repeat(3, 1fr); gap: 0.75rem;
align-items: center; margin-bottom: 0.85rem; }
.ie2-stat-label { font-size: 0.82rem; color: var(--ink-soft); }
.ie2-stat-cell { font-size: 0.82rem; text-align: center; padding: 0.4rem 0.3rem;
border-radius: var(--radius); border: 1px solid transparent; transition: background 0.2s, border-color 0.2s; }
.ie2-stat-cell.is-synced { background: var(--accent-soft); border-color: var(--accent); font-weight: 600; }
@media (max-width: 560px) {
.ie2-stat-row { grid-template-columns: 1fr; gap: 0.2rem; text-align: center; }
.ie2-stat-label { font-weight: 700; margin-top: 0.6rem; }
}
.ie2-controls { text-align: center; margin-top: 2rem; position: relative; z-index: 1; }
.ie2-play {
font: inherit; font-size: 0.82rem; background: var(--paper); color: var(--accent);
border: 1px solid var(--accent); border-radius: var(--radius); padding: 0.5rem 1.15rem;
cursor: pointer; transition: background 0.15s, color 0.15s;
}
.ie2-play:hover { background: var(--accent); color: var(--paper); }
@media (prefers-reduced-motion: reduce) {
.infographic-infraevo2 *, .infographic-infraevo2 *::before, .infographic-infraevo2 *::after {
transition-duration: 0.001ms !important;
}
}
</style>
<div class="ie2-bg-word">SCALE</div>
<div class="ie2-head">
<p class="ie2-eyebrow">Infrastructure Evolution</p>
<h2>From Garage to Grid</h2>
<p>Every growing company outgrows its server closet. Click a stage to see how scale, redundancy, and uptime change along the way.</p>
</div>
<div class="ie2-road">
<svg class="ie2-path-svg" viewBox="0 0 960 40" preserveAspectRatio="none">
<path d="M40,20 C300,20 300,20 480,20 C660,20 660,20 920,20" />
</svg>
<div class="ie2-flow">
<button class="ie2-step" data-step="1" type="button">
<span class="ie2-ghost-num">01</span>
<div class="ie2-icon">
<svg viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 30 L32 10 L58 30" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
<rect x="22" y="8" width="7" height="9" stroke-width="3"/>
<path d="M12 28 V56 H52 V28" stroke-width="3" stroke-linejoin="round"/>
<rect x="20" y="32" width="24" height="20" rx="2" stroke-width="2.5"/>
<line x1="20" y1="38" x2="44" y2="38" stroke-width="2"/>
<line x1="20" y1="44" x2="44" y2="44" stroke-width="2"/>
<circle cx="24" cy="35" r="1.4" fill="currentColor" stroke="none"/>
<circle cx="24" cy="41" r="1.4" fill="currentColor" stroke="none"/>
<circle cx="24" cy="47" r="1.4" fill="currentColor" stroke="none"/>
</svg>
</div>
<div class="ie2-tag">Early stage</div>
<h3>Home or Garage</h3>
<div class="ie2-scalebar"><span style="width:15%"></span></div>
<div class="ie2-detail">One box, one outlet. Cheap to start, but a single power flicker takes everything down.</div>
</button>
<button class="ie2-step" data-step="2" type="button">
<span class="ie2-ghost-num">02</span>
<div class="ie2-icon">
<svg viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="14" y="10" width="24" height="46" stroke-width="3"/>
<rect x="38" y="26" width="16" height="30" stroke-width="3"/>
<circle cx="20" cy="18" r="1.6" fill="currentColor" stroke="none"/>
<circle cx="26" cy="18" r="1.6" fill="currentColor" stroke="none"/>
<circle cx="32" cy="18" r="1.6" fill="currentColor" stroke="none"/>
<circle cx="20" cy="26" r="1.6" fill="currentColor" stroke="none"/>
<circle cx="26" cy="26" r="1.6" fill="currentColor" stroke="none"/>
<circle cx="32" cy="26" r="1.6" fill="currentColor" stroke="none"/>
<circle cx="20" cy="34" r="1.6" fill="currentColor" stroke="none"/>
<circle cx="26" cy="34" r="1.6" fill="currentColor" stroke="none"/>
<circle cx="32" cy="34" r="1.6" fill="currentColor" stroke="none"/>
<rect x="19" y="46" width="6" height="10" stroke-width="2.5"/>
<rect x="43" y="46" width="6" height="10" stroke-width="2.5"/>
</svg>
</div>
<div class="ie2-tag">Office setup</div>
<h3>Dedicated Server Room</h3>
<div class="ie2-scalebar"><span style="width:50%"></span></div>
<div class="ie2-detail">A locked room, its own circuit, maybe a spare UPS. Room to grow, still bound by the building.</div>
</button>
<button class="ie2-step" data-step="3" type="button">
<span class="ie2-ghost-num">03</span>
<div class="ie2-icon">
<svg viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="6" y="14" width="52" height="38" rx="4" stroke-width="3"/>
<rect x="12" y="20" width="12" height="26" rx="1.5" stroke-width="2.2"/>
<rect x="26" y="20" width="12" height="26" rx="1.5" stroke-width="2.2"/>
<rect x="40" y="20" width="12" height="26" rx="1.5" stroke-width="2.2"/>
<line x1="14" y1="26" x2="22" y2="26" stroke-width="1.8"/>
<line x1="14" y1="32" x2="22" y2="32" stroke-width="1.8"/>
<line x1="14" y1="38" x2="22" y2="38" stroke-width="1.8"/>
<line x1="28" y1="26" x2="36" y2="26" stroke-width="1.8"/>
<line x1="28" y1="32" x2="36" y2="32" stroke-width="1.8"/>
<line x1="28" y1="38" x2="36" y2="38" stroke-width="1.8"/>
<line x1="42" y1="26" x2="50" y2="26" stroke-width="1.8"/>
<line x1="42" y1="32" x2="50" y2="32" stroke-width="1.8"/>
<line x1="42" y1="38" x2="50" y2="38" stroke-width="1.8"/>
</svg>
</div>
<div class="ie2-tag">Full scale</div>
<h3>Data Center</h3>
<div class="ie2-scalebar"><span style="width:100%"></span></div>
<div class="ie2-detail">
Purpose-built for uptime.
<div class="ie2-pills">
<span class="ie2-pill">Multiple servers</span>
<span class="ie2-pill">Cooling systems</span>
<span class="ie2-pill">Power management</span>
</div>
</div>
</button>
</div>
</div>
<div class="ie2-stats">
<div class="ie2-stats-title">The growth, side by side</div>
<div class="ie2-stat-row">
<div class="ie2-stat-label">Servers</div>
<div class="ie2-stat-cell" data-sync="1">1โ2</div>
<div class="ie2-stat-cell" data-sync="2">5โ15</div>
<div class="ie2-stat-cell" data-sync="3">100sโ1000s</div>
</div>
<div class="ie2-stat-row">
<div class="ie2-stat-label">Redundancy</div>
<div class="ie2-stat-cell" data-sync="1">None</div>
<div class="ie2-stat-cell" data-sync="2">Partial</div>
<div class="ie2-stat-cell" data-sync="3">Full</div>
</div>
<div class="ie2-stat-row">
<div class="ie2-stat-label">Uptime</div>
<div class="ie2-stat-cell" data-sync="1">Best-effort</div>
<div class="ie2-stat-cell" data-sync="2">~99%</div>
<div class="ie2-stat-cell" data-sync="3">99.99%+</div>
</div>
</div>
<div class="ie2-controls">
<button class="ie2-play" type="button">Play through โ</button>
</div>
<script>
(function () {
const wrapper = document.currentScript.closest('.infographic-infraevo2')
|| document.querySelector('.infographic-infraevo2');
const bodyAttr = document.body.getAttribute('data-darkmode');
let dark;
if (bodyAttr === 'true') {
dark = true;
} else if (bodyAttr === 'false') {
dark = false;
} else {
const match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) wrapper.setAttribute('data-theme', 'dark');
const steps = Array.from(wrapper.querySelectorAll('.ie2-step'));
const statCells = Array.from(wrapper.querySelectorAll('.ie2-stat-cell'));
function selectStep(step) {
const wasOpen = step.classList.contains('is-open');
steps.forEach(s => s.classList.remove('is-open'));
statCells.forEach(c => c.classList.remove('is-synced'));
if (!wasOpen) {
step.classList.add('is-open');
const n = step.dataset.step;
statCells.filter(c => c.dataset.sync === n).forEach(c => c.classList.add('is-synced'));
}
}
steps.forEach(step => step.addEventListener('click', () => selectStep(step)));
const playBtn = wrapper.querySelector('.ie2-play');
let playing = false;
playBtn.addEventListener('click', () => {
if (playing) return;
playing = true;
let i = 0;
steps.forEach(s => s.classList.remove('is-open'));
statCells.forEach(c => c.classList.remove('is-synced'));
const interval = setInterval(() => {
steps.forEach(s => s.classList.remove('is-open'));
statCells.forEach(c => c.classList.remove('is-synced'));
steps[i].classList.add('is-open');
const n = steps[i].dataset.step;
statCells.filter(c => c.dataset.sync === n).forEach(c => c.classList.add('is-synced'));
i++;
if (i >= steps.length) {
clearInterval(interval);
playing = false;
}
}, 1200);
});
})();
</script>
</div>.demo {
font-family: system-ui, sans-serif;
padding: 16px;
}
.demo h1 {
color: #2563eb;
margin: 0 0 8px;
}
.demo p {
color: #4b5563;
margin: 0;
}document.querySelector('.demo h1')?.addEventListener('click', () => {
alert('Hello from live preview!');
});๐ด Problems with Traditional Infrastructure
๐ธ Cost
Steep upfront investment
Ongoing maintenance overhead
Power and cooling bills
Hardware that needs periodic replacement
โ๏ธ Operations
Scaling takes time
Capacity is fixed, not flexible
Needs round-the-clock oversight
Exposed to outages and disasters
Hardware handled manually
โ๏ธ Enter Cloud Computing
Cloud computing removes these constraints entirely. Rather than owning physical hardware, you rent resources on demand โ infrastructure becomes virtual, and scaling happens instantly.
๐ What You Gain
Scale up or down instantly
Pay only for what you use
Zero hardware upkeep
Available anywhere in the world
Reliability and disaster recovery built in