Sync config from arch

- hypr/apps.lua
- hypr/autostart.lua
- hypr/envs.lua
- hypr/hyprland.lua
- hypr/hyprsunset.conf
- hypr/input.lua
- hypr/looknfeel.lua
- hypr/omasettings.lua
- hypr/xdph.conf
- omarchy/branding/about.txt
- omarchy/branding/screensaver.txt
- omarchy/extensions/omarchy-menu.jsonc
- omarchy/hooks/battery-low.d/play-warning-sound.sample
- omarchy/hooks/font-set.d/show-font-notification.sample
- omarchy/hooks/post-boot.d/weather.sample
- omarchy/hooks/post-update.d/install-voxtype.hook
- omarchy/hooks/post-update.d/setup-agent.hook
- omarchy/hooks/post-update.d/setup-fingerprint.hook
- omarchy/hooks/post-update.d/show-update-notification.sample
- omarchy/hooks/pre-refresh-pacman.d/add-custom-repo.sample
- omarchy/hooks/theme-set.d/show-theme-notification.sample
- omarchy/shell.json
- omarchy/shell.toml
- omarchy/theme.name
- omarchy/themes/azure-glow/README.md
- omarchy/themes/azure-glow/alacritty.toml
- omarchy/themes/azure-glow/btop.theme
- omarchy/themes/azure-glow/hyprland.conf
- omarchy/themes/azure-glow/hyprlock.conf
- omarchy/themes/azure-glow/icons.theme
- … 269 more
This commit is contained in:
asepharyana
2026-09-23 15:19:12 +07:00
commit 1cdb82a76f
300 changed files with 78143 additions and 0 deletions
@@ -0,0 +1,171 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap">
<style>
body { margin: 0; background: #0e0e14; font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; }
a { color: #7aa2f7; } a:hover { color: #b4bee6; }
.band { border: 1px solid rgba(169,177,214,0.22); background: rgba(169,177,214,0.025); padding: 16px; box-sizing: border-box; }
.bandcap { font-size: 10px; letter-spacing: 0.14em; color: #565f89; margin-bottom: 13px; }
.box { border: 1px solid rgba(169,177,214,0.28); background: #1a1b26; padding: 12px 13px; box-sizing: border-box; display: flex; flex-direction: column; gap: 5px; }
.bt { font-size: 12px; color: #c0caf5; font-weight: 500; }
.bs { font-size: 10px; letter-spacing: 0.08em; color: #7aa2f7; }
.bb { font-size: 10px; color: #565f89; line-height: 1.65; }
.flow { display: flex; align-items: center; justify-content: center; gap: 11px; padding: 11px 0; }
.flowt { font-size: 10px; color: #565f89; letter-spacing: 0.04em; }
.g3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; }
.g2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
</style>
</helmet>
<div style="display: flex; flex-direction: column; gap: 0; width: 1120px; padding: 28px; box-sizing: border-box; color: #a9b1d6;">
<div style="display: flex; flex-direction: column; gap: 5px; margin-bottom: 20px;">
<div style="font-size: 15px; color: #c0caf5; font-weight: 700;">Architecture</div>
<div style="font-size: 11px; color: #565f89; line-height: 1.65; max-width: 720px;">Plugins run unsandboxed inside the single long-lived <span style="color: #a9b1d6;">omarchy-shell</span> process, so nothing that samples twice a second belongs in QML. The shell side stays a thin reader; a small daemon owns every measurement, and three files are the whole contract between them.</div>
</div>
<div class="band">
<div class="bandcap">INSIDE OMARCHY-SHELL &middot; QML, LOADED BY THE PLUGIN REGISTRY</div>
<div class="g3">
<div class="box">
<div class="bt">BarWidget.qml</div>
<div class="bs">kind: bar-widget</div>
<div class="bb">Index, latency or live sparkline. Colour carries the state. Click opens the panel, middle-click runs a peak test.</div>
</div>
<div class="box">
<div class="bt">Panel.qml</div>
<div class="bs">five tab Loaders</div>
<div class="bb">Only the selected tab is alive, so a hidden tab costs nothing per sample. Charts are Canvas, same technique as the UniFi plugin.</div>
</div>
<div class="box">
<div class="bt">Service.qml</div>
<div class="bs">kind: service</div>
<div class="bb">Starts at shell startup, spawns the daemon if no lock is held, restarts it if it dies, raises outage notifications.</div>
</div>
</div>
</div>
<div class="flow">
<svg width="13" height="30" viewBox="0 0 13 30"><path d="M6.5 0v22" stroke="#565f89" stroke-width="1"></path><path d="M2.5 19l4 5 4-5" fill="none" stroke="#565f89" stroke-width="1"></path></svg>
<div class="flowt">One <span style="color: #a9b1d6;">nexthop stream</span> reader for live state &mdash; bounded, no-follow, regular-file-only, so the shell never opens a state path itself &nbsp;&middot;&nbsp; one Process call to <span style="color: #a9b1d6;">nexthop query</span> when you open a longer window</div>
<svg width="13" height="30" viewBox="0 0 13 30"><path d="M6.5 30V8" stroke="#565f89" stroke-width="1"></path><path d="M2.5 11l4-5 4 5" fill="none" stroke="#565f89" stroke-width="1"></path></svg>
</div>
<div class="band">
<div class="bandcap">THE CONTRACT &middot; ~/.LOCAL/STATE/NEXTHOP</div>
<div class="g3">
<div class="box">
<div class="bt">live.json</div>
<div class="bs">rewritten 2&times; / sec</div>
<div class="bb">Both legs, lag, loss, rates, signal, the three component scores and the index. Under 1 KB, atomic rename. This is all the bar widget ever reads.</div>
</div>
<div class="box">
<div class="bt">recent.json</div>
<div class="bs">rewritten every 5 sec</div>
<div class="bb">A 30-minute ring buffer, pre-downsampled to ~360 points. The panel's default graphs paint from it with no subprocess at all.</div>
</div>
<div class="box">
<div class="bt">history.db</div>
<div class="bs">sqlite, stdlib</div>
<div class="bb">1-minute rows for 7 days, 1-hour rows for a year, every speed test and every event kept. QML never speaks SQL &mdash; the CLI answers in JSON.</div>
</div>
</div>
</div>
<div class="flow">
<svg width="13" height="30" viewBox="0 0 13 30"><path d="M6.5 30V8" stroke="#565f89" stroke-width="1"></path><path d="M2.5 11l4-5 4 5" fill="none" stroke="#565f89" stroke-width="1"></path></svg>
<div class="flowt">writes only &nbsp;&middot;&nbsp; the daemon never talks to the shell, so either side can restart without the other noticing</div>
</div>
<div class="band">
<div class="bandcap">NEXTHOPD &middot; PYTHON 3, STANDARD LIBRARY ONLY, NO PIP</div>
<div class="g3" style="margin-bottom: 14px;">
<div class="box">
<div class="bt">Local leg</div>
<div class="bs">2 Hz</div>
<div class="bb">One persistent <span style="color: #a9b1d6;">ping -D -i 0.5</span> to the default gateway, parsed line by line. No process spawn per sample.</div>
</div>
<div class="box">
<div class="bt">Wan leg</div>
<div class="bs">2 Hz</div>
<div class="bb">Same again to an anchor. Wan latency is the anchor minus the gateway, which is what separates your Wi-Fi from your ISP.</div>
</div>
<div class="box">
<div class="bt">Link + counters</div>
<div class="bs">1 Hz / 5 sec</div>
<div class="bb"><span style="color: #a9b1d6;">/sys/class/net</span> byte counters for throughput; <span style="color: #a9b1d6;">iw station dump</span> for signal, bitrate, retries and roams.</div>
</div>
</div>
<div class="g3" style="margin-bottom: 14px;">
<div class="box">
<div class="bt">Application path</div>
<div class="bs">1 Hz + 5 min</div>
<div class="bb">A TCP handshake to the anchor on 443, and one HTTPS request every five minutes. Routers answer pings from hardware and rate-limit them under load, so ICMP alone is not what applications get.</div>
</div>
<div class="box">
<div class="bt">Content speed</div>
<div class="bs">hourly, ~14 MB</div>
<div class="bb">A short ranged fetch, enough to score Speed honestly without moving real data. This is what feeds the index.</div>
</div>
<div class="box">
<div class="bt">Scorer</div>
<div class="bs">continuous</div>
<div class="bb">Lag from latency, jitter and loss &rarr; Responsiveness. Downtime &rarr; Reliability. Content speed &rarr; Speed. Weakest-link, 0&ndash;100: you feel the bottleneck, not the average.</div>
</div>
</div>
<div class="box">
<div class="bt">Roll-up and retention</div>
<div class="bb" style="line-height: 1.7;">Raw 2 Hz samples never hit the disk. The daemon folds them into 1-second aggregates in memory, 1-minute rows on the way to sqlite, and 1-hour rows after a week. A month of continuous monitoring lands under 12 MB.</div>
</div>
</div>
<div class="flow">
<svg width="13" height="30" viewBox="0 0 13 30"><path d="M6.5 0v22" stroke="#565f89" stroke-width="1"></path><path d="M2.5 19l4 5 4-5" fill="none" stroke="#565f89" stroke-width="1"></path></svg>
<div class="flowt">only when you ask, or when a schedule you turned on says so</div>
</div>
<div class="band">
<div class="bandcap">ON DEMAND</div>
<div class="g2">
<div class="box">
<div class="bt">Peak speed test</div>
<div class="bs">ookla &rarr; cloudflare &rarr; fast.com</div>
<div class="bb">Uses the official <span style="color: #a9b1d6;">speedtest</span> CLI when it is on the machine, for server choice and a shareable result. Falls back to a Cloudflare or fast.com run that needs nothing installed &mdash; the same method Omarchy's own speed test uses. Idle and loaded latency are captured on every run.</div>
</div>
<div class="box">
<div class="bt">Notifications and report</div>
<div class="bs">omarchy-notification-send</div>
<div class="bb">One notification when a disruption starts and one when it clears, naming the leg that failed. "Copy report" renders the visible window as plain text with timestamps, both legs and loss.</div>
</div>
</div>
</div>
<div style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 22px; margin-top: 24px; padding-top: 20px; border-top: 1px solid rgba(169,177,214,0.14);">
<div style="display: flex; flex-direction: column; gap: 7px;">
<div style="font-size: 10px; letter-spacing: 0.14em; color: #565f89;">WHY A DAEMON AND NOT QML TIMERS</div>
<div style="font-size: 11px; color: #a9b1d6; line-height: 1.7;">History has to survive a shell restart, and you restart the shell every time you change a theme. Sampling twice a second from QML would also mean a subprocess per probe inside the process that draws your desktop. And the panel must open already full of data, not start collecting when you look at it.</div>
</div>
<div style="display: flex; flex-direction: column; gap: 7px;">
<div style="font-size: 10px; letter-spacing: 0.14em; color: #565f89;">TWO WAYS TO RUN IT</div>
<div style="font-size: 11px; color: #a9b1d6; line-height: 1.7;">By default the shell service starts the daemon, so installing the plugin is still just a clone and an enable &mdash; the marketplace installer never runs code. Anyone who wants monitoring while the shell is down installs a <span style="color: #c0caf5;">systemd --user</span> unit with one command; the service sees the lock is held and simply attaches.</div>
</div>
</div>
</div>
</x-dc>
<script data-dc-script data-props='{"$preview":{"width":1120,"height":1180}}'>
class Component extends DCLogic {}
</script>
</body>
</html>
@@ -0,0 +1,164 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap">
<style>
body { margin: 0; background: #0e0e14; font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; }
a { color: #7aa2f7; } a:hover { color: #b4bee6; }
.bar { display: flex; align-items: center; justify-content: space-between; height: 26px; background: #1a1b26; padding: 0 8px; box-sizing: border-box; flex-grow: 1; }
.grp { display: flex; align-items: center; gap: 10px; }
.lbl { font-size: 10px; letter-spacing: 0.1em; color: #565f89; width: 176px; flex-shrink: 0; line-height: 1.5; }
.row { display: flex; align-items: center; gap: 18px; }
.me { display: flex; align-items: center; gap: 5px; padding: 0 6px; height: 21px; }
</style>
</helmet>
<div style="display: flex; flex-direction: column; gap: 18px; width: 900px; padding: 26px; box-sizing: border-box;">
<div style="display: flex; flex-direction: column; gap: 4px;">
<div style="font-size: 13px; color: #c0caf5; letter-spacing: 0.02em;">Bar widget &mdash; the only always-visible surface</div>
<div style="font-size: 11px; color: #565f89; line-height: 1.6;">26 px tall, drawn in the shell's bar font. Four display modes, all six states. Colour is the whole message: you should know your connection went bad without reading a number.</div>
</div>
<div style="height: 1px; background: rgba(169,177,214,0.12);"></div>
<div class="row">
<div class="lbl">MODE A<br>INDEX &middot; DEFAULT</div>
<div class="bar">
<div class="grp">
<div style="display: flex; gap: 5px;"><div style="width: 7px; height: 7px; background: #7aa2f7;"></div><div style="width: 7px; height: 7px; background: rgba(169,177,214,0.28);"></div><div style="width: 7px; height: 7px; background: rgba(169,177,214,0.28);"></div></div>
</div>
<div class="grp">
<div class="me" style="background: rgba(169,177,214,0.04);">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#9ece6a" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 13h4l3-8 4 16 3-8h6"></path></svg>
<span style="font-size: 11px; color: #9ece6a; font-weight: 500;">94</span>
</div>
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#a9b1d6" stroke-width="1.6" stroke-linecap="round"><path d="M2 8.5a15 15 0 0 1 20 0"></path><path d="M5.5 12.4a10 10 0 0 1 13 0"></path><circle cx="12" cy="18" r="1.2" fill="#a9b1d6" stroke="none"></circle></svg>
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#a9b1d6" stroke-width="1.6" stroke-linejoin="round"><path d="M4 9v6h4l5 4V5L8 9H4z"></path></svg>
<span style="font-size: 11px; color: #a9b1d6;">14:32</span>
</div>
</div>
</div>
<div class="row">
<div class="lbl">MODE B<br>LIVE LATENCY</div>
<div class="bar">
<div class="grp">
<div style="display: flex; gap: 5px;"><div style="width: 7px; height: 7px; background: #7aa2f7;"></div><div style="width: 7px; height: 7px; background: rgba(169,177,214,0.28);"></div><div style="width: 7px; height: 7px; background: rgba(169,177,214,0.28);"></div></div>
</div>
<div class="grp">
<div class="me">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#a9b1d6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 13h4l3-8 4 16 3-8h6"></path></svg>
<span style="font-size: 11px; color: #a9b1d6;">9 ms</span>
</div>
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#a9b1d6" stroke-width="1.6" stroke-linecap="round"><path d="M2 8.5a15 15 0 0 1 20 0"></path><path d="M5.5 12.4a10 10 0 0 1 13 0"></path><circle cx="12" cy="18" r="1.2" fill="#a9b1d6" stroke="none"></circle></svg>
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#a9b1d6" stroke-width="1.6" stroke-linejoin="round"><path d="M4 9v6h4l5 4V5L8 9H4z"></path></svg>
<span style="font-size: 11px; color: #a9b1d6;">14:32</span>
</div>
</div>
</div>
<div class="row">
<div class="lbl">MODE C<br>LIVE SPARKLINE</div>
<div class="bar">
<div class="grp">
<div style="display: flex; gap: 5px;"><div style="width: 7px; height: 7px; background: #7aa2f7;"></div><div style="width: 7px; height: 7px; background: rgba(169,177,214,0.28);"></div><div style="width: 7px; height: 7px; background: rgba(169,177,214,0.28);"></div></div>
</div>
<div class="grp">
<div class="me">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#9ece6a" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 13h4l3-8 4 16 3-8h6"></path></svg>
<svg width="38" height="12" viewBox="0 0 38 12"><polyline points="0,9 3,8 6,10 9,6 12,8 15,4 18,9 21,7 24,10 27,5 30,8 33,6 36,7" fill="none" stroke="#7aa2f7" stroke-width="1.2" stroke-linejoin="round"></polyline></svg>
</div>
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#a9b1d6" stroke-width="1.6" stroke-linecap="round"><path d="M2 8.5a15 15 0 0 1 20 0"></path><path d="M5.5 12.4a10 10 0 0 1 13 0"></path><circle cx="12" cy="18" r="1.2" fill="#a9b1d6" stroke="none"></circle></svg>
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#a9b1d6" stroke-width="1.6" stroke-linejoin="round"><path d="M4 9v6h4l5 4V5L8 9H4z"></path></svg>
<span style="font-size: 11px; color: #a9b1d6;">14:32</span>
</div>
</div>
</div>
<div class="row">
<div class="lbl">DEGRADED<br>WAN LEG SLOW</div>
<div class="bar">
<div class="grp">
<div style="display: flex; gap: 5px;"><div style="width: 7px; height: 7px; background: #7aa2f7;"></div><div style="width: 7px; height: 7px; background: rgba(169,177,214,0.28);"></div><div style="width: 7px; height: 7px; background: rgba(169,177,214,0.28);"></div></div>
</div>
<div class="grp">
<div class="me" style="background: rgba(224,175,104,0.10);">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#e0af68" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 13h4l3-8 4 16 3-8h6"></path></svg>
<span style="font-size: 11px; color: #e0af68; font-weight: 500;">61</span>
</div>
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#a9b1d6" stroke-width="1.6" stroke-linecap="round"><path d="M2 8.5a15 15 0 0 1 20 0"></path><path d="M5.5 12.4a10 10 0 0 1 13 0"></path><circle cx="12" cy="18" r="1.2" fill="#a9b1d6" stroke="none"></circle></svg>
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#a9b1d6" stroke-width="1.6" stroke-linejoin="round"><path d="M4 9v6h4l5 4V5L8 9H4z"></path></svg>
<span style="font-size: 11px; color: #a9b1d6;">14:32</span>
</div>
</div>
</div>
<div class="row">
<div class="lbl">OUTAGE<br>ROUTER OK, WAN DEAD</div>
<div class="bar">
<div class="grp">
<div style="display: flex; gap: 5px;"><div style="width: 7px; height: 7px; background: #7aa2f7;"></div><div style="width: 7px; height: 7px; background: rgba(169,177,214,0.28);"></div><div style="width: 7px; height: 7px; background: rgba(169,177,214,0.28);"></div></div>
</div>
<div class="grp">
<div class="me" style="background: rgba(247,118,142,0.14);">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#f7768e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 13h6l4 0"></path><path d="M16 13h6"></path><path d="M12.5 8.5 15 13l-2.5 4.5"></path></svg>
<span style="font-size: 11px; color: #f7768e; font-weight: 500;">2m 14s</span>
</div>
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#a9b1d6" stroke-width="1.6" stroke-linecap="round"><path d="M2 8.5a15 15 0 0 1 20 0"></path><path d="M5.5 12.4a10 10 0 0 1 13 0"></path><circle cx="12" cy="18" r="1.2" fill="#a9b1d6" stroke="none"></circle></svg>
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#a9b1d6" stroke-width="1.6" stroke-linejoin="round"><path d="M4 9v6h4l5 4V5L8 9H4z"></path></svg>
<span style="font-size: 11px; color: #a9b1d6;">14:32</span>
</div>
</div>
</div>
<div class="row">
<div class="lbl">SPEED TEST RUNNING<br>PROGRESS ON THE WIDGET</div>
<div class="bar" style="position: relative;">
<div class="grp">
<div style="display: flex; gap: 5px;"><div style="width: 7px; height: 7px; background: #7aa2f7;"></div><div style="width: 7px; height: 7px; background: rgba(169,177,214,0.28);"></div><div style="width: 7px; height: 7px; background: rgba(169,177,214,0.28);"></div></div>
</div>
<div class="grp">
<div class="me" style="background: rgba(122,162,247,0.12); position: relative;">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#7aa2f7" stroke-width="1.7" stroke-linecap="round"><path d="M4 18a9 9 0 1 1 16 0"></path><path d="M12 14.5 16.5 9"></path></svg>
<span style="font-size: 11px; color: #7aa2f7;">386 &darr;</span>
<div style="position: absolute; left: 0; bottom: 0; width: 62%; height: 2px; background: #7aa2f7;"></div>
</div>
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#a9b1d6" stroke-width="1.6" stroke-linecap="round"><path d="M2 8.5a15 15 0 0 1 20 0"></path><path d="M5.5 12.4a10 10 0 0 1 13 0"></path><circle cx="12" cy="18" r="1.2" fill="#a9b1d6" stroke="none"></circle></svg>
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#a9b1d6" stroke-width="1.6" stroke-linejoin="round"><path d="M4 9v6h4l5 4V5L8 9H4z"></path></svg>
<span style="font-size: 11px; color: #a9b1d6;">14:32</span>
</div>
</div>
</div>
<div style="height: 1px; background: rgba(169,177,214,0.12);"></div>
<div style="display: flex; gap: 26px;">
<div style="display: flex; flex-direction: column; gap: 4px; flex-grow: 1;">
<div style="font-size: 10px; letter-spacing: 0.1em; color: #565f89;">TOOLTIP ON HOVER</div>
<div style="font-size: 11px; color: #a9b1d6; line-height: 1.6;">Excitel &middot; 94 excellent<br>local 1.2 ms &middot; wan 8.4 ms &middot; 0.0% loss</div>
</div>
<div style="display: flex; flex-direction: column; gap: 4px; flex-grow: 1;">
<div style="font-size: 10px; letter-spacing: 0.1em; color: #565f89;">CLICK</div>
<div style="font-size: 11px; color: #a9b1d6; line-height: 1.6;">Opens the panel.<br>Middle-click runs a speed test.</div>
</div>
<div style="display: flex; flex-direction: column; gap: 4px; flex-grow: 1;">
<div style="font-size: 10px; letter-spacing: 0.1em; color: #565f89;">NOTIFICATION</div>
<div style="font-size: 11px; color: #a9b1d6; line-height: 1.6;">Fires on outage start and recovery,<br>with the leg that failed named.</div>
</div>
</div>
</div>
</x-dc>
<script data-dc-script data-props='{"$preview":{"width":900,"height":520}}'>
class Component extends DCLogic {}
</script>
</body>
</html>
@@ -0,0 +1,164 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap">
<style>
body { margin: 0; background: #0e0e14; font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; }
a { color: #7aa2f7; } a:hover { color: #b4bee6; }
.cap { font-size: 10px; letter-spacing: 0.12em; color: #565f89; }
.tab { flex-grow: 1; height: 26px; display: flex; align-items: center; justify-content: center; font-size: 11px; color: #a9b1d6; background: rgba(169,177,214,0.04); border: 1px solid rgba(169,177,214,0.4); }
.tabon { flex-grow: 1; height: 26px; display: flex; align-items: center; justify-content: center; font-size: 11px; color: #c0caf5; background: rgba(169,177,214,0.18); border: 1px solid transparent; }
.sep { height: 1px; background: rgba(169,177,214,0.12); }
.ev { display: flex; align-items: flex-start; gap: 10px; }
.evt { font-size: 10px; color: #565f89; width: 60px; flex-shrink: 0; padding-top: 1px; }
.evb { font-size: 11px; color: #a9b1d6; line-height: 1.55; flex-grow: 1; }
.evd { font-size: 10px; color: #565f89; flex-shrink: 0; padding-top: 1px; }
.dot { width: 5px; height: 5px; flex-shrink: 0; margin-top: 5px; }
</style>
</helmet>
<div style="display: flex; flex-direction: column; width: 560px; background: #1a1b26; border: 2px solid #7aa2f7; box-sizing: border-box; padding: 18px; color: #a9b1d6;">
<div style="display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;">
<div style="display: flex; align-items: flex-start; gap: 10px;">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#9ece6a" stroke-width="1.6" stroke-linecap="round" style="margin-top: 2px;">
<path d="M2 8.5a15 15 0 0 1 20 0"></path><path d="M5 12.2a10.5 10.5 0 0 1 14 0"></path><path d="M8.2 15.9a6 6 0 0 1 7.6 0"></path><circle cx="12" cy="19.3" r="1.1" fill="#9ece6a" stroke="none"></circle>
</svg>
<div style="display: flex; flex-direction: column; gap: 3px;">
<div style="font-size: 16px; font-weight: 700; color: #c0caf5;">Excitel</div>
<div class="cap" style="letter-spacing: 0.1em;">EXCELLENT &middot; ONLINE 4H 12M</div>
</div>
</div>
<div style="display: flex; flex-direction: column; align-items: flex-end; gap: 1px;">
<div style="font-size: 30px; font-weight: 700; line-height: 1; color: #9ece6a;">94</div>
<div class="cap">EXPERIENCE</div>
</div>
</div>
<div style="display: flex; gap: 6px; margin-top: 16px;">
<div class="tab">Overview</div><div class="tab">Latency</div><div class="tab">Speed</div><div class="tab">Wi-Fi</div><div class="tabon">Events</div>
</div>
<div class="sep" style="margin: 16px 0 14px 0;"></div>
<div style="display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 10px;">
<div class="cap">EXPERIENCE, LAST 24 HOURS</div>
<div style="font-size: 10px; color: #565f89;">1-minute buckets</div>
</div>
<svg width="524" height="26" viewBox="0 0 524 26" style="display: block;">
<sc-for list="{{c.ribbon}}" as="r" hint-placeholder-count="24">
<rect x="{{r.x}}" y="0" width="{{r.w}}" height="26" fill="{{r.fill}}"></rect>
</sc-for>
</svg>
<div style="display: flex; justify-content: space-between; margin-top: 5px;">
<div style="font-size: 9px; color: #414868;">14:30 yest.</div>
<div style="font-size: 9px; color: #414868;">00:00</div>
<div style="font-size: 9px; color: #414868;">08:00</div>
<div style="font-size: 9px; color: #414868;">now</div>
</div>
<div style="display: flex; gap: 12px; margin-top: 10px; flex-wrap: wrap;">
<div style="display: flex; align-items: center; gap: 5px;"><div style="width: 9px; height: 9px; background: #9ece6a;"></div><div style="font-size: 10px; color: #565f89;">90+ excellent</div></div>
<div style="display: flex; align-items: center; gap: 5px;"><div style="width: 9px; height: 9px; background: #b9f27c;"></div><div style="font-size: 10px; color: #565f89;">80 good</div></div>
<div style="display: flex; align-items: center; gap: 5px;"><div style="width: 9px; height: 9px; background: #e0af68;"></div><div style="font-size: 10px; color: #565f89;">70 okay</div></div>
<div style="display: flex; align-items: center; gap: 5px;"><div style="width: 9px; height: 9px; background: #eb927b;"></div><div style="font-size: 10px; color: #565f89;">50 fair</div></div>
<div style="display: flex; align-items: center; gap: 5px;"><div style="width: 9px; height: 9px; background: #f7768e;"></div><div style="font-size: 10px; color: #565f89;">under 50 poor</div></div>
</div>
<div class="sep" style="margin: 16px 0 12px 0;"></div>
<div class="cap" style="margin-bottom: 11px;">LAST 7 DAYS</div>
<div style="display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 8px; align-items: end;">
<div style="display: flex; flex-direction: column; align-items: center; gap: 5px;"><div style="font-size: 10px; color: #c0caf5;">91</div><div style="width: 100%; height: 44px; background: rgba(169,177,214,0.08); display: flex; align-items: flex-end;"><div style="width: 100%; height: 40px; background: #9ece6a;"></div></div><div style="font-size: 9px; color: #414868;">Mon</div></div>
<div style="display: flex; flex-direction: column; align-items: center; gap: 5px;"><div style="font-size: 10px; color: #c0caf5;">93</div><div style="width: 100%; height: 44px; background: rgba(169,177,214,0.08); display: flex; align-items: flex-end;"><div style="width: 100%; height: 41px; background: #9ece6a;"></div></div><div style="font-size: 9px; color: #414868;">Tue</div></div>
<div style="display: flex; flex-direction: column; align-items: center; gap: 5px;"><div style="font-size: 10px; color: #c0caf5;">67</div><div style="width: 100%; height: 44px; background: rgba(169,177,214,0.08); display: flex; align-items: flex-end;"><div style="width: 100%; height: 29px; background: #eb927b;"></div></div><div style="font-size: 9px; color: #414868;">Wed</div></div>
<div style="display: flex; flex-direction: column; align-items: center; gap: 5px;"><div style="font-size: 10px; color: #c0caf5;">88</div><div style="width: 100%; height: 44px; background: rgba(169,177,214,0.08); display: flex; align-items: flex-end;"><div style="width: 100%; height: 39px; background: #b9f27c;"></div></div><div style="font-size: 9px; color: #414868;">Thu</div></div>
<div style="display: flex; flex-direction: column; align-items: center; gap: 5px;"><div style="font-size: 10px; color: #c0caf5;">94</div><div style="width: 100%; height: 44px; background: rgba(169,177,214,0.08); display: flex; align-items: flex-end;"><div style="width: 100%; height: 41px; background: #9ece6a;"></div></div><div style="font-size: 9px; color: #414868;">Fri</div></div>
<div style="display: flex; flex-direction: column; align-items: center; gap: 5px;"><div style="font-size: 10px; color: #c0caf5;">95</div><div style="width: 100%; height: 44px; background: rgba(169,177,214,0.08); display: flex; align-items: flex-end;"><div style="width: 100%; height: 42px; background: #9ece6a;"></div></div><div style="font-size: 9px; color: #414868;">Sat</div></div>
<div style="display: flex; flex-direction: column; align-items: center; gap: 5px;"><div style="font-size: 10px; color: #c0caf5;">94</div><div style="width: 100%; height: 44px; background: rgba(169,177,214,0.08); display: flex; align-items: flex-end;"><div style="width: 100%; height: 41px; background: #9ece6a;"></div></div><div style="font-size: 9px; color: #414868;">Sun</div></div>
</div>
<div class="sep" style="margin: 16px 0 12px 0;"></div>
<div style="display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 12px;">
<div class="cap">WHAT HAPPENED</div>
<div style="font-size: 10px; color: #565f89;">3 disruptions this week</div>
</div>
<div style="display: flex; flex-direction: column; gap: 11px;">
<div class="ev">
<div class="evt">Wed 19:14</div>
<div class="dot" style="background: #f7768e;"></div>
<div class="evb">No internet. Router still answered in 2 ms, so the fault was upstream of your line.</div>
<div class="evd">7m 41s</div>
</div>
<div class="ev">
<div class="evt">Wed 20:02</div>
<div class="dot" style="background: #eb927b;"></div>
<div class="evb">Lag above 120 ms on the wan leg. Speed unaffected.</div>
<div class="evd">52m</div>
</div>
<div class="ev">
<div class="evt">Thu 09:30</div>
<div class="dot" style="background: #7aa2f7;"></div>
<div class="evb">Public address changed, 49.36.x.x &rarr; 49.37.x.x. Same ISP, same AS.</div>
<div class="evd">&mdash;</div>
</div>
<div class="ev">
<div class="evt">Fri 12:04</div>
<div class="dot" style="background: #bb9af7;"></div>
<div class="evb">Roamed 3&times; between &hellip;25:fe &harr; &hellip;25:fa &harr; &hellip;25:b4</div>
<div class="evd">2m</div>
</div>
<div class="ev">
<div class="evt">Sat 03:00</div>
<div class="dot" style="background: #565f89;"></div>
<div class="evb">DNS resolver stopped answering for 90 s. Fell back to the secondary.</div>
<div class="evd">1m 30s</div>
</div>
</div>
<div class="sep" style="margin: 16px 0 12px 0;"></div>
<div style="display: flex; align-items: center; justify-content: space-between; gap: 12px;">
<div style="font-size: 10px; color: #565f89; line-height: 1.6; flex-grow: 1;">Builds a plain-text summary of the window you are looking at, with timestamps, both legs and loss &mdash; the thing an ISP actually asks for.</div>
<div style="display: flex; align-items: center; gap: 7px; height: 28px; padding: 0 12px; background: rgba(169,177,214,0.04); border: 1px solid rgba(169,177,214,0.4); color: #c0caf5; font-size: 11px; flex-shrink: 0;">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#c0caf5" stroke-width="1.6" stroke-linejoin="round"><rect x="9" y="4" width="11" height="14"></rect><path d="M15 20H4V7"></path></svg>
Copy report
</div>
</div>
</div>
</x-dc>
<script data-dc-script data-props='{"$preview":{"width":560,"height":840}}'>
class Component extends DCLogic {
rng(seed) { let s = seed >>> 0; return function () { s = (s * 1664525 + 1013904223) >>> 0; return s / 4294967296 } }
renderVals() {
var N = 96, W = 524, rand = this.rng(31337)
var seg = W / N
var out = []
for (var i = 0; i < N; i++) {
var score = 92 + rand() * 7
if (i > 18 && i < 23) score = 41 + rand() * 8
if (i >= 23 && i < 31) score = 62 + rand() * 9
if (i > 54 && i < 58) score = 76 + rand() * 6
var fill = score >= 90 ? '#9ece6a' : score >= 80 ? '#b9f27c' : score >= 70 ? '#e0af68' : score >= 50 ? '#eb927b' : '#f7768e'
out.push({ x: (i * seg).toFixed(2), w: (seg + 0.4).toFixed(2), fill: fill })
}
return { c: { ribbon: out } }
}
}
</script>
</body>
</html>
@@ -0,0 +1,215 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap">
<style>
body { margin: 0; background: #0e0e14; font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; }
a { color: #7aa2f7; } a:hover { color: #b4bee6; }
.cap { font-size: 10px; letter-spacing: 0.12em; color: #565f89; }
.tab { flex-grow: 1; height: 26px; display: flex; align-items: center; justify-content: center; font-size: 11px; color: #a9b1d6; background: rgba(169,177,214,0.04); border: 1px solid rgba(169,177,214,0.4); }
.tabon { flex-grow: 1; height: 26px; display: flex; align-items: center; justify-content: center; font-size: 11px; color: #c0caf5; background: rgba(169,177,214,0.18); border: 1px solid transparent; }
.pill { height: 22px; padding: 0 11px; display: flex; align-items: center; font-size: 10px; letter-spacing: 0.06em; color: #a9b1d6; background: rgba(169,177,214,0.04); border: 1px solid rgba(169,177,214,0.4); }
.pillon { height: 22px; padding: 0 11px; display: flex; align-items: center; font-size: 10px; letter-spacing: 0.06em; color: #c0caf5; background: rgba(169,177,214,0.18); border: 1px solid transparent; }
.sep { height: 1px; background: rgba(169,177,214,0.12); }
.num { font-size: 11px; color: #c0caf5; text-align: right; }
</style>
</helmet>
<div style="display: flex; flex-direction: column; width: 560px; background: #1a1b26; border: 2px solid #7aa2f7; box-sizing: border-box; padding: 18px; color: #a9b1d6;">
<div style="display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;">
<div style="display: flex; align-items: flex-start; gap: 10px;">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#9ece6a" stroke-width="1.6" stroke-linecap="round" style="margin-top: 2px;">
<path d="M2 8.5a15 15 0 0 1 20 0"></path><path d="M5 12.2a10.5 10.5 0 0 1 14 0"></path><path d="M8.2 15.9a6 6 0 0 1 7.6 0"></path><circle cx="12" cy="19.3" r="1.1" fill="#9ece6a" stroke="none"></circle>
</svg>
<div style="display: flex; flex-direction: column; gap: 3px;">
<div style="font-size: 16px; font-weight: 700; color: #c0caf5;">Excitel</div>
<div class="cap" style="letter-spacing: 0.1em;">EXCELLENT &middot; ONLINE 4H 12M</div>
</div>
</div>
<div style="display: flex; flex-direction: column; align-items: flex-end; gap: 1px;">
<div style="font-size: 30px; font-weight: 700; line-height: 1; color: #9ece6a;">94</div>
<div class="cap">EXPERIENCE</div>
</div>
</div>
<div style="display: flex; gap: 6px; margin-top: 16px;">
<div class="tab">Overview</div><div class="tabon">Latency</div><div class="tab">Speed</div><div class="tab">Wi-Fi</div><div class="tab">Events</div>
</div>
<div class="sep" style="margin: 16px 0 14px 0;"></div>
<div style="display: flex; align-items: center; justify-content: space-between;">
<div style="display: flex; gap: 5px;">
<div class="pill">5M</div><div class="pillon">30M</div><div class="pill">6H</div><div class="pill">24H</div><div class="pill">7D</div>
</div>
<div class="cap">1 SAMPLE / SEC</div>
</div>
<div style="display: flex; align-items: baseline; justify-content: space-between; margin: 16px 0 6px 0;">
<div class="cap">ROUND-TRIP LATENCY, BY LEG</div>
<div style="font-size: 10px; color: #565f89;">peak 41 ms</div>
</div>
<div style="display: flex; gap: 8px;">
<div style="display: flex; flex-direction: column; justify-content: space-between; height: 140px; padding-bottom: 2px;">
<div style="font-size: 9px; color: #414868;">45</div>
<div style="font-size: 9px; color: #414868;">30</div>
<div style="font-size: 9px; color: #414868;">15</div>
<div style="font-size: 9px; color: #414868;">0</div>
</div>
<svg width="496" height="140" viewBox="0 0 496 140" style="display: block;">
<line x1="0" y1="0.5" x2="496" y2="0.5" stroke="rgba(169,177,214,0.07)"></line>
<line x1="0" y1="45.5" x2="496" y2="45.5" stroke="rgba(169,177,214,0.07)"></line>
<line x1="0" y1="90.5" x2="496" y2="90.5" stroke="rgba(169,177,214,0.07)"></line>
<line x1="0" y1="135.5" x2="496" y2="135.5" stroke="rgba(169,177,214,0.16)"></line>
<path d="{{c.wanArea}}" fill="rgba(122,162,247,0.20)"></path>
<path d="{{c.wanLine}}" fill="none" stroke="#7aa2f7" stroke-width="1.5" stroke-linejoin="round"></path>
<path d="{{c.localArea}}" fill="rgba(86,95,137,0.6)"></path>
<path d="{{c.localLine}}" fill="none" stroke="#565f89" stroke-width="1" stroke-linejoin="round"></path>
</svg>
</div>
<div style="display: flex; align-items: center; gap: 16px; margin-top: 7px; padding-left: 26px;">
<div style="display: flex; align-items: center; gap: 6px;"><div style="width: 10px; height: 2px; background: #7aa2f7;"></div><div style="font-size: 10px; color: #565f89;">wan leg (router &rarr; 1.1.1.1)</div></div>
<div style="display: flex; align-items: center; gap: 6px;"><div style="width: 10px; height: 2px; background: #565f89;"></div><div style="font-size: 10px; color: #565f89;">local leg (laptop &rarr; router)</div></div>
</div>
<div class="sep" style="margin: 16px 0 12px 0;"></div>
<div class="cap" style="margin-bottom: 7px;">JITTER</div>
<svg width="524" height="40" viewBox="0 0 524 40" style="display: block;">
<line x1="0" y1="39.5" x2="524" y2="39.5" stroke="rgba(169,177,214,0.16)"></line>
<path d="{{c.jitterArea}}" fill="rgba(187,154,247,0.22)"></path>
<path d="{{c.jitterLine}}" fill="none" stroke="#bb9af7" stroke-width="1.2" stroke-linejoin="round"></path>
</svg>
<div style="display: flex; justify-content: space-between; margin-top: 5px;">
<div style="font-size: 10px; color: #565f89;">mean 1.8 ms</div>
<div style="font-size: 10px; color: #565f89;">peak 9.4 ms</div>
</div>
<div class="sep" style="margin: 14px 0 12px 0;"></div>
<div class="cap" style="margin-bottom: 7px;">PACKET LOSS</div>
<svg width="524" height="26" viewBox="0 0 524 26" style="display: block;">
<line x1="0" y1="25.5" x2="524" y2="25.5" stroke="rgba(169,177,214,0.16)"></line>
<sc-for list="{{c.lossBars}}" as="b" hint-placeholder-count="3">
<rect x="{{b.x}}" y="{{b.y}}" width="3" height="{{b.h}}" fill="#f7768e"></rect>
</sc-for>
</svg>
<div style="font-size: 10px; color: #565f89; margin-top: 5px;">2 lost of 1800 probes &middot; 0.11% &middot; all on the wan leg</div>
<div class="sep" style="margin: 14px 0 12px 0;"></div>
<div style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 7px 14px;">
<div class="cap"></div>
<div class="cap" style="text-align: right;">LOCAL LEG</div>
<div class="cap" style="text-align: right;">WAN LEG</div>
<div style="font-size: 11px; color: #565f89;">median</div><div class="num">1.2 ms</div><div class="num">8.4 ms</div>
<div style="font-size: 11px; color: #565f89;">p95</div><div class="num">2.1 ms</div><div class="num">14.0 ms</div>
<div style="font-size: 11px; color: #565f89;">p99</div><div class="num">3.4 ms</div><div class="num">27.0 ms</div>
<div style="font-size: 11px; color: #565f89;">worst</div><div class="num">6.8 ms</div><div class="num">41.0 ms</div>
<div style="font-size: 11px; color: #565f89;">jitter</div><div class="num">0.4 ms</div><div class="num">1.8 ms</div>
<div style="font-size: 11px; color: #565f89;">loss</div><div class="num">0.00 %</div><div class="num" style="color: #e0af68;">0.11 %</div>
</div>
<div class="sep" style="margin: 14px 0 12px 0;"></div>
<div style="display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 9px;">
<div class="cap">LATENCY UNDER LOAD</div>
<div style="font-size: 10px; color: #565f89;">measured during the last speed test</div>
</div>
<div style="display: flex; align-items: center; gap: 12px;">
<div style="flex-grow: 1; display: flex; flex-direction: column; gap: 6px;">
<div style="display: flex; align-items: center; gap: 9px;">
<div style="width: 46px; font-size: 10px; color: #565f89;">idle</div>
<div style="flex-grow: 1; height: 8px; background: rgba(169,177,214,0.10);"><div style="height: 8px; width: 12%; background: #9ece6a;"></div></div>
<div style="width: 52px; font-size: 11px; color: #c0caf5; text-align: right;">9 ms</div>
</div>
<div style="display: flex; align-items: center; gap: 9px;">
<div style="width: 46px; font-size: 10px; color: #565f89;">loaded</div>
<div style="flex-grow: 1; height: 8px; background: rgba(169,177,214,0.10);"><div style="height: 8px; width: 45%; background: #e0af68;"></div></div>
<div style="width: 52px; font-size: 11px; color: #c0caf5; text-align: right;">34 ms</div>
</div>
</div>
<div style="display: flex; flex-direction: column; align-items: center; gap: 2px; width: 78px; padding-left: 12px; border-left: 1px solid rgba(169,177,214,0.12);">
<div style="font-size: 20px; font-weight: 700; line-height: 1.1; color: #9ece6a;">A&minus;</div>
<div class="cap" style="letter-spacing: 0.08em;">BUFFERBLOAT</div>
</div>
</div>
<div style="font-size: 10px; color: #565f89; margin-top: 9px; line-height: 1.6;">+25 ms added under full load. Below 30 ms a video call stays clean while someone else is downloading.</div>
</div>
</x-dc>
<script data-dc-script data-props='{"$preview":{"width":560,"height":880}}'>
class Component extends DCLogic {
rng(seed) { let s = seed >>> 0; return function () { s = (s * 1664525 + 1013904223) >>> 0; return s / 4294967296 } }
renderVals() {
var N = 110, rand = this.rng(77003)
var local = [], wan = [], jit = []
for (var i = 0; i < N; i++) {
var l = 1.2 + rand() * 0.9
var w = 8.4 * (0.8 + rand() * 0.4)
if (i === 38 || i === 39) w = 33
if (i === 71) w = 24
if (i === 90 || i === 91 || i === 92) w = 30 + rand() * 8
local.push(l); wan.push(w)
jit.push(0.7 + rand() * 2.4 + (i > 88 && i < 94 ? 6 : 0))
}
var W = 496, H = 140, peak = 45
var xAt = function (i) { return (i * (W - 1) / (N - 1)).toFixed(1) }
var yAt = function (v) { return (H - (H - 4) * v / peak).toFixed(1) }
var lp = [], tp = [], localLine = '', wanLine = ''
for (var j = 0; j < N; j++) {
var a = xAt(j) + ',' + yAt(local[j])
var b = xAt(j) + ',' + yAt(local[j] + wan[j])
lp.push(a); tp.push(b)
localLine += (j === 0 ? 'M' : 'L') + a
wanLine += (j === 0 ? 'M' : 'L') + b
}
var JW = 524, JH = 40, jpeak = 11
var jx = function (i) { return (i * (JW - 1) / (N - 1)).toFixed(1) }
var jy = function (v) { return (JH - (JH - 3) * v / jpeak).toFixed(1) }
var jp = [], jitterLine = ''
for (var k = 0; k < N; k++) {
var p = jx(k) + ',' + jy(jit[k])
jp.push(p)
jitterLine += (k === 0 ? 'M' : 'L') + p
}
var lossIdx = [39, 90, 91]
var lossBars = lossIdx.map(function (i) {
var h = i === 39 ? 12 : 20
return { x: jx(i), y: (26 - h).toFixed(1), h: h }
})
return {
c: {
localLine: localLine,
wanLine: wanLine,
localArea: 'M0,' + H + 'L' + lp.join('L') + 'L' + W + ',' + H + 'Z',
wanArea: 'M' + tp.join('L') + 'L' + lp.slice().reverse().join('L') + 'Z',
jitterLine: jitterLine,
jitterArea: 'M0,' + JH + 'L' + jp.join('L') + 'L' + JW + ',' + JH + 'Z',
lossBars: lossBars
}
}
}
}
</script>
</body>
</html>
@@ -0,0 +1,298 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap">
<style>
body { margin: 0; background: #0e0e14; font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; }
a { color: #7aa2f7; } a:hover { color: #b4bee6; }
</style>
</helmet>
<div style="display: flex; flex-direction: column; gap: 0; width: 560px; background: #1a1b26; border: 2px solid #7aa2f7; box-sizing: border-box; padding: 18px; color: #a9b1d6;">
<div style="display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;">
<div style="display: flex; align-items: flex-start; gap: 10px;">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="{{d.tone}}" stroke-width="1.6" stroke-linecap="round" style="margin-top: 2px;">
<path d="M2 8.5a15 15 0 0 1 20 0"></path>
<path d="M5 12.2a10.5 10.5 0 0 1 14 0"></path>
<path d="M8.2 15.9a6 6 0 0 1 7.6 0"></path>
<circle cx="12" cy="19.3" r="1.1" fill="{{d.tone}}" stroke="none"></circle>
</svg>
<div style="display: flex; flex-direction: column; gap: 3px;">
<div style="font-size: 16px; font-weight: 700; color: #c0caf5; letter-spacing: 0.01em;">Excitel</div>
<div style="font-size: 10px; letter-spacing: 0.1em; color: #565f89;">{{d.verdict}} &middot; {{d.uptime}}</div>
</div>
</div>
<div style="display: flex; flex-direction: column; align-items: flex-end; gap: 1px;">
<div style="font-size: 30px; font-weight: 700; line-height: 1; color: {{d.tone}};">{{d.index}}</div>
<div style="font-size: 10px; letter-spacing: 0.12em; color: #565f89;">EXPERIENCE</div>
</div>
</div>
<div style="display: flex; gap: 6px; margin-top: 16px;">
<div style="flex-grow: 1; height: 26px; display: flex; align-items: center; justify-content: center; font-size: 11px; color: #c0caf5; background: rgba(169,177,214,0.18); border: 1px solid transparent;">Overview</div>
<div style="flex-grow: 1; height: 26px; display: flex; align-items: center; justify-content: center; font-size: 11px; color: #a9b1d6; background: rgba(169,177,214,0.04); border: 1px solid rgba(169,177,214,0.4);">Latency</div>
<div style="flex-grow: 1; height: 26px; display: flex; align-items: center; justify-content: center; font-size: 11px; color: #a9b1d6; background: rgba(169,177,214,0.04); border: 1px solid rgba(169,177,214,0.4);">Speed</div>
<div style="flex-grow: 1; height: 26px; display: flex; align-items: center; justify-content: center; font-size: 11px; color: #a9b1d6; background: rgba(169,177,214,0.04); border: 1px solid rgba(169,177,214,0.4);">Wi-Fi</div>
<div style="flex-grow: 1; height: 26px; display: flex; align-items: center; justify-content: center; font-size: 11px; color: #a9b1d6; background: rgba(169,177,214,0.04); border: 1px solid rgba(169,177,214,0.4);">Events</div>
</div>
<div style="height: 1px; background: rgba(169,177,214,0.12); margin: 16px 0 14px 0;"></div>
<div style="font-size: 10px; letter-spacing: 0.12em; color: #565f89; margin-bottom: 12px;">PATH</div>
<div style="display: flex; align-items: center; gap: 0;">
<div style="display: flex; flex-direction: column; align-items: center; gap: 5px; width: 96px;">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#c0caf5" stroke-width="1.5" stroke-linejoin="round">
<rect x="4" y="5" width="16" height="11" rx="1"></rect>
<path d="M2 19h20"></path>
</svg>
<div style="font-size: 10px; color: #c0caf5;">This laptop</div>
<div style="font-size: 10px; color: #565f89;">wlan0</div>
</div>
<div style="flex-grow: 1; display: flex; flex-direction: column; align-items: center; gap: 5px; padding-bottom: 26px;">
<div style="font-size: 11px; color: {{d.localTone}}; font-weight: 500;">{{d.localMs}} ms</div>
<div style="width: 100%; height: 2px; background: {{d.localTone}};"></div>
<div style="font-size: 10px; letter-spacing: 0.1em; color: #565f89;">LOCAL LEG</div>
</div>
<div style="display: flex; flex-direction: column; align-items: center; gap: 5px; width: 96px;">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#c0caf5" stroke-width="1.5" stroke-linejoin="round">
<rect x="3" y="13" width="18" height="7" rx="1"></rect>
<path d="M7.5 16.5h.01M11 16.5h.01"></path>
<path d="M12 13V9"></path>
<path d="M8.5 6.5a5 5 0 0 1 7 0"></path>
</svg>
<div style="font-size: 10px; color: #c0caf5;">Router</div>
<div style="font-size: 10px; color: #565f89;">10.10.0.1</div>
</div>
<div style="flex-grow: 1; display: flex; flex-direction: column; align-items: center; gap: 5px; padding-bottom: 26px;">
<div style="font-size: 11px; color: {{d.wanTone}}; font-weight: 500;">{{d.wanMs}} ms</div>
<div style="width: 100%; height: 2px; background: {{d.wanTone}};"></div>
<div style="font-size: 10px; letter-spacing: 0.1em; color: #565f89;">WAN LEG</div>
</div>
<div style="display: flex; flex-direction: column; align-items: center; gap: 5px; width: 96px;">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="{{d.tone}}" stroke-width="1.5">
<circle cx="12" cy="12" r="8.5"></circle>
<path d="M3.5 12h17"></path>
<path d="M12 3.5c2.6 2.6 2.6 14.4 0 17c-2.6-2.6-2.6-14.4 0-17z"></path>
</svg>
<div style="font-size: 10px; color: #c0caf5;">Internet</div>
<div style="font-size: 10px; color: #565f89;">AS17754</div>
</div>
</div>
<div style="display: flex; align-items: baseline; justify-content: space-between; margin-top: 14px; padding-top: 12px; border-top: 1px solid rgba(169,177,214,0.12);">
<div class="capx" style="font-size: 10px; letter-spacing: 0.12em; color: #565f89;">LAG</div>
<div style="font-size: 10px; color: #565f89;">best {{d.lagBest}} ms &nbsp;&middot;&nbsp; typical <span style="color: #c0caf5; font-size: 11px;">{{d.lagTypical}} ms</span> &nbsp;&middot;&nbsp; worst {{d.lagWorst}} ms</div>
</div>
<div style="height: 1px; background: rgba(169,177,214,0.12); margin: 14px 0 14px 0;"></div>
<div style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px;">
<div style="display: flex; flex-direction: column; gap: 6px;">
<div style="font-size: 10px; letter-spacing: 0.1em; color: #565f89;">RESPONSIVENESS</div>
<div style="font-size: 22px; font-weight: 700; line-height: 1; color: {{d.respTone}};">{{d.resp}}</div>
<div style="height: 3px; background: rgba(169,177,214,0.12);">
<div style="height: 3px; width: {{d.respPct}}; background: {{d.respTone}};"></div>
</div>
<div style="font-size: 10px; color: #565f89;">{{d.respNote}}</div>
</div>
<div style="display: flex; flex-direction: column; gap: 6px;">
<div style="font-size: 10px; letter-spacing: 0.1em; color: #565f89;">RELIABILITY</div>
<div style="font-size: 22px; font-weight: 700; line-height: 1; color: {{d.relTone}};">{{d.rel}}</div>
<div style="height: 3px; background: rgba(169,177,214,0.12);">
<div style="height: 3px; width: {{d.relPct}}; background: {{d.relTone}};"></div>
</div>
<div style="font-size: 10px; color: #565f89;">{{d.relNote}}</div>
</div>
<div style="display: flex; flex-direction: column; gap: 6px;">
<div style="font-size: 10px; letter-spacing: 0.1em; color: #565f89;">SPEED</div>
<div style="font-size: 22px; font-weight: 700; line-height: 1; color: {{d.spdTone}};">{{d.spd}}</div>
<div style="height: 3px; background: rgba(169,177,214,0.12);">
<div style="height: 3px; width: {{d.spdPct}}; background: {{d.spdTone}};"></div>
</div>
<div style="font-size: 10px; color: #565f89;">{{d.spdNote}}</div>
</div>
</div>
<sc-if value="{{d.hasRec}}" hint-placeholder-val="{{ true }}">
<div style="display: flex; align-items: flex-start; gap: 9px; margin-top: 14px; padding: 10px 12px; background: rgba(224,175,104,0.07); border: 1px solid rgba(224,175,104,0.35); box-sizing: border-box;">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#e0af68" stroke-width="1.7" stroke-linecap="round" style="flex-shrink: 0; margin-top: 1px;">
<circle cx="12" cy="12" r="9"></circle><path d="M12 8.2v4.6"></path><circle cx="12" cy="16" r="0.9" fill="#e0af68" stroke="none"></circle>
</svg>
<div style="font-size: 11px; color: #a9b1d6; line-height: 1.65;">{{d.rec}}</div>
</div>
</sc-if>
<div style="height: 1px; background: rgba(169,177,214,0.12); margin: 16px 0 12px 0;"></div>
<div style="display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 6px;">
<div style="font-size: 10px; letter-spacing: 0.12em; color: #565f89;">LATENCY &middot; LAST 30 MIN</div>
<div style="font-size: 10px; color: #565f89;">{{d.stats}}</div>
</div>
<svg width="524" height="104" viewBox="0 0 524 104" style="display: block;">
<line x1="0" y1="95.5" x2="524" y2="95.5" stroke="rgba(169,177,214,0.15)" stroke-width="1"></line>
<path d="{{chart.wanArea}}" fill="rgba(122,162,247,0.20)"></path>
<path d="{{chart.wanLine}}" fill="none" stroke="#7aa2f7" stroke-width="1.5" stroke-linejoin="round"></path>
<path d="{{chart.localArea}}" fill="rgba(86,95,137,0.55)"></path>
<path d="{{chart.localLine}}" fill="none" stroke="#565f89" stroke-width="1" stroke-linejoin="round"></path>
<sc-for list="{{chart.loss}}" as="tick" hint-placeholder-count="2">
<rect x="{{tick.x}}" y="88" width="2" height="8" fill="#f7768e"></rect>
</sc-for>
</svg>
<div style="display: flex; align-items: center; gap: 16px; margin-top: 6px;">
<div style="display: flex; align-items: center; gap: 6px;">
<div style="width: 10px; height: 2px; background: #7aa2f7;"></div>
<div style="font-size: 10px; color: #565f89;">wan leg</div>
</div>
<div style="display: flex; align-items: center; gap: 6px;">
<div style="width: 10px; height: 2px; background: #565f89;"></div>
<div style="font-size: 10px; color: #565f89;">local leg</div>
</div>
<div style="display: flex; align-items: center; gap: 6px;">
<div style="width: 2px; height: 8px; background: #f7768e;"></div>
<div style="font-size: 10px; color: #565f89;">packet loss</div>
</div>
</div>
<div style="height: 1px; background: rgba(169,177,214,0.12); margin: 14px 0 12px 0;"></div>
<div style="display: flex; align-items: center; justify-content: space-between; gap: 12px;">
<div style="display: flex; flex-direction: column; gap: 4px;">
<div style="font-size: 10px; letter-spacing: 0.1em; color: #565f89;">LAST SPEED TEST &middot; {{d.testAge}}</div>
<div style="display: flex; align-items: baseline; gap: 12px;">
<div style="display: flex; align-items: baseline; gap: 5px;">
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="#7aa2f7" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" style="transform: translateY(1px);"><path d="M12 4v14M6 13l6 6 6-6"></path></svg>
<span style="font-size: 15px; font-weight: 700; color: #c0caf5;">{{d.down}}</span>
<span style="font-size: 10px; color: #565f89;">Mbps</span>
</div>
<div style="display: flex; align-items: baseline; gap: 5px;">
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="#f7cf7a" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" style="transform: translateY(1px);"><path d="M12 20V6M6 11l6-6 6 6"></path></svg>
<span style="font-size: 15px; font-weight: 700; color: #c0caf5;">{{d.up}}</span>
<span style="font-size: 10px; color: #565f89;">Mbps</span>
</div>
</div>
</div>
<div style="display: flex; align-items: center; gap: 7px; height: 28px; padding: 0 12px; background: rgba(169,177,214,0.04); border: 1px solid rgba(169,177,214,0.4); color: #c0caf5; font-size: 11px;">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#c0caf5" stroke-width="1.6" stroke-linecap="round">
<path d="M4 18a9 9 0 1 1 16 0"></path>
<path d="M12 14.5 16.5 9"></path>
</svg>
Run test
</div>
</div>
<div style="height: 1px; background: rgba(169,177,214,0.12); margin: 14px 0 10px 0;"></div>
<div style="display: flex; align-items: center; justify-content: space-between;">
<div style="font-size: 10px; color: #565f89;">{{d.outages}}</div>
<div style="font-size: 10px; color: #565f89;">monitoring used 3.1 MB today</div>
</div>
</div>
</x-dc>
<script data-dc-script data-props='{"state":{"editor":"enum","options":["healthy","degraded","outage"],"default":"healthy","section":"Data"},"accent":{"editor":"color","default":"#7aa2f7","options":["#7aa2f7","#9ece6a","#e0af68","#bb9af7"],"section":"Theme"},"$preview":{"width":560,"height":720}}'>
class Component extends DCLogic {
rng(seed) {
let s = seed >>> 0
return function () { s = (s * 1664525 + 1013904223) >>> 0; return s / 4294967296 }
}
series(state) {
var N = 72, rand = this.rng(20260824)
var localBase = state === 'outage' ? 2.4 : (state === 'degraded' ? 2.1 : 1.2)
var wanBase = state === 'outage' ? 120 : (state === 'degraded' ? 46 : 8.4)
var local = [], wan = [], loss = []
for (var i = 0; i < N; i++) {
var l = localBase + rand() * localBase * 0.5
var w = wanBase * (0.82 + rand() * 0.36)
if (state === 'healthy' && (i === 23 || i === 24)) w = wanBase * 4.6
if (state === 'degraded' && i % 11 === 4) w = wanBase * 2.2
if (state === 'outage' && i > 46 && i < 60) { w = wanBase * 2.4; loss.push(i) }
if (state === 'degraded' && (i === 31 || i === 52)) loss.push(i)
local.push(l); wan.push(w)
}
return { local: local, wan: wan, loss: loss, N: N }
}
chartFor(state) {
var s = this.series(state)
var W = 524, H = 96, top = 4
var peak = 0
for (var i = 0; i < s.N; i++) peak = Math.max(peak, s.local[i] + s.wan[i])
peak = peak * 1.12
var xAt = function (i) { return (i * (W - 1) / (s.N - 1)).toFixed(1) }
var yAt = function (v) { return (H - (H - top) * v / peak).toFixed(1) }
var localLine = '', wanLine = '', totalPts = [], localPts = []
for (var j = 0; j < s.N; j++) {
var lp = xAt(j) + ',' + yAt(s.local[j])
var tp = xAt(j) + ',' + yAt(s.local[j] + s.wan[j])
localPts.push(lp); totalPts.push(tp)
localLine += (j === 0 ? 'M' : 'L') + lp
wanLine += (j === 0 ? 'M' : 'L') + tp
}
var localArea = 'M0,' + H + 'L' + localPts.join('L') + 'L' + W + ',' + H + 'Z'
var wanArea = 'M' + totalPts.join('L') + 'L' + localPts.slice().reverse().join('L') + 'Z'
var ticks = s.loss.map(function (i) { return { x: xAt(i) } })
return { localLine: localLine, wanLine: wanLine, localArea: localArea, wanArea: wanArea, loss: ticks }
}
renderVals() {
var accent = this.props.accent ?? '#7aa2f7'
var state = this.props.state ?? 'healthy'
var GOOD = '#9ece6a', WARN = '#e0af68', BAD = '#f7768e'
var table = {
healthy: {
index: 94, verdict: 'EXCELLENT', tone: GOOD, uptime: 'ONLINE 4H 12M',
localMs: '1.2', wanMs: '8.4', localTone: GOOD, wanTone: GOOD,
lagBest: '7', lagTypical: '11', lagWorst: '41', hasRec: false, rec: '',
resp: 96, respTone: GOOD, respPct: '96%', respNote: 'lag 11 ms typical',
rel: 99, relTone: GOOD, relPct: '99%', relNote: 'no disruptions in 24 h',
spd: 88, spdTone: GOOD, spdPct: '88%', spdNote: '92% of your 450/50 plan',
stats: 'p50 9 ms · p95 14 ms · jitter 1.8 ms',
down: '412', up: '48', testAge: '2 H AGO', outages: 'no outages today'
},
degraded: {
index: 61, verdict: 'DEGRADED', tone: WARN, uptime: 'ONLINE 41M',
localMs: '2.1', wanMs: '46', localTone: GOOD, wanTone: WARN,
lagBest: '34', lagTypical: '58', lagWorst: '210', hasRec: true,
rec: 'Your local leg is clean at 2 ms \u2014 the 46 ms is upstream of the router, so moving the laptop or changing channel will not help. Lag has been above 40 ms for 26 minutes; this is worth raising with Excitel.',
resp: 44, respTone: BAD, respPct: '44%', respNote: 'lag 58 ms typical',
rel: 82, relTone: WARN, relPct: '82%', relNote: '2 disruptions today',
spd: 71, spdTone: WARN, spdPct: '71%', spdNote: '318 Mbps, below plan',
stats: 'p50 48 ms · p95 121 ms · jitter 19 ms',
down: '318', up: '41', testAge: '18 MIN AGO', outages: '2 brief outages today'
},
outage: {
index: 12, verdict: 'NO INTERNET', tone: BAD, uptime: 'WAN DOWN 2M 14S',
localMs: '2.4', wanMs: '--', localTone: GOOD, wanTone: BAD,
lagBest: '--', lagTypical: '--', lagWorst: '--', hasRec: true,
rec: 'The router answers in 2.4 ms but nothing past it replies. Your Wi-Fi is fine \u2014 the fault is on the Excitel side or the line itself. Started 2 min 14 s ago.',
resp: 0, respTone: BAD, respPct: '4%', respNote: 'no reply past the router',
rel: 21, relTone: BAD, relPct: '21%', relNote: 'outage in progress',
spd: 0, spdTone: BAD, spdPct: '3%', spdNote: 'last known 412 Mbps',
stats: 'router reachable · wan unreachable',
down: '412', up: '48', testAge: '3 H AGO', outages: '1 outage today, ongoing'
}
}
var d = table[state] || table.healthy
return { d: d, accent: accent, chart: this.chartFor(state) }
}
}
</script>
</body>
</html>
@@ -0,0 +1,183 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap">
<style>
body { margin: 0; background: #0e0e14; font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; }
a { color: #7aa2f7; } a:hover { color: #b4bee6; }
.cap { font-size: 10px; letter-spacing: 0.12em; color: #565f89; }
.tab { flex-grow: 1; height: 26px; display: flex; align-items: center; justify-content: center; font-size: 11px; color: #a9b1d6; background: rgba(169,177,214,0.04); border: 1px solid rgba(169,177,214,0.4); }
.tabon { flex-grow: 1; height: 26px; display: flex; align-items: center; justify-content: center; font-size: 11px; color: #c0caf5; background: rgba(169,177,214,0.18); border: 1px solid transparent; }
.sep { height: 1px; background: rgba(169,177,214,0.12); }
</style>
</helmet>
<div style="display: flex; flex-direction: column; width: 560px; background: #1a1b26; border: 2px solid #7aa2f7; box-sizing: border-box; padding: 18px; color: #a9b1d6;">
<div style="display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;">
<div style="display: flex; align-items: flex-start; gap: 10px;">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#9ece6a" stroke-width="1.6" stroke-linecap="round" style="margin-top: 2px;">
<path d="M2 8.5a15 15 0 0 1 20 0"></path><path d="M5 12.2a10.5 10.5 0 0 1 14 0"></path><path d="M8.2 15.9a6 6 0 0 1 7.6 0"></path><circle cx="12" cy="19.3" r="1.1" fill="#9ece6a" stroke="none"></circle>
</svg>
<div style="display: flex; flex-direction: column; gap: 3px;">
<div style="font-size: 16px; font-weight: 700; color: #c0caf5;">Excitel</div>
<div class="cap" style="letter-spacing: 0.1em;">EXCELLENT &middot; ONLINE 4H 12M</div>
</div>
</div>
<div style="display: flex; flex-direction: column; align-items: flex-end; gap: 1px;">
<div style="font-size: 30px; font-weight: 700; line-height: 1; color: #9ece6a;">94</div>
<div class="cap">EXPERIENCE</div>
</div>
</div>
<div style="display: flex; gap: 6px; margin-top: 16px;">
<div class="tab">Overview</div><div class="tab">Latency</div><div class="tabon">Speed</div><div class="tab">Wi-Fi</div><div class="tab">Events</div>
</div>
<div class="sep" style="margin: 16px 0 14px 0;"></div>
<div class="cap" style="margin-bottom: 9px;">LIVE THROUGHPUT &middot; LAST 3 MIN</div>
<svg width="524" height="118" viewBox="0 0 524 118" style="display: block;">
<path d="{{c.rxArea}}" fill="rgba(122,162,247,0.20)"></path>
<path d="{{c.rxLine}}" fill="none" stroke="#7aa2f7" stroke-width="1.4" stroke-linejoin="round"></path>
<path d="{{c.txArea}}" fill="rgba(247,207,122,0.18)"></path>
<path d="{{c.txLine}}" fill="none" stroke="#f7cf7a" stroke-width="1.4" stroke-linejoin="round"></path>
<line x1="0" y1="59" x2="524" y2="59" stroke="rgba(169,177,214,0.22)" stroke-width="1"></line>
</svg>
<div style="display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px 14px; margin-top: 14px;">
<div class="cap">RECEIVING</div>
<div class="cap">SENDING</div>
<div class="cap">DOWNLOADED</div>
<div class="cap">UPLOADED</div>
<div style="font-size: 15px; color: #7aa2f7; font-weight: 500;">4.0 <span style="font-size: 10px; color: #565f89;">MB/s</span></div>
<div style="font-size: 15px; color: #f7cf7a; font-weight: 500;">2.2 <span style="font-size: 10px; color: #565f89;">MB/s</span></div>
<div style="font-size: 15px; color: #c0caf5; font-weight: 500;">1.05 <span style="font-size: 10px; color: #565f89;">GB</span></div>
<div style="font-size: 15px; color: #c0caf5; font-weight: 500;">416 <span style="font-size: 10px; color: #565f89;">MB</span></div>
</div>
<div class="sep" style="margin: 16px 0 12px 0;"></div>
<div style="display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 9px;">
<div class="cap">CONTENT SPEED &middot; FEEDS YOUR SCORE</div>
<div style="font-size: 10px; color: #565f89;">hourly &middot; ~15 MB per check</div>
</div>
<svg width="524" height="86" viewBox="0 0 524 86" style="display: block;">
<line x1="0" y1="21.5" x2="524" y2="21.5" stroke="rgba(169,177,214,0.07)"></line>
<line x1="0" y1="47.5" x2="524" y2="47.5" stroke="rgba(169,177,214,0.07)"></line>
<line x1="0" y1="73.5" x2="524" y2="73.5" stroke="rgba(169,177,214,0.16)"></line>
<sc-for list="{{c.tests}}" as="t" hint-placeholder-count="12">
<rect x="{{t.dx}}" y="{{t.dy}}" width="14" height="{{t.dh}}" fill="#7aa2f7"></rect>
<rect x="{{t.ux}}" y="{{t.uy}}" width="8" height="{{t.uh}}" fill="#f7cf7a"></rect>
</sc-for>
</svg>
<div style="display: flex; align-items: center; justify-content: space-between; margin-top: 6px;">
<div style="display: flex; align-items: center; gap: 14px;">
<div style="display: flex; align-items: center; gap: 6px;"><div style="width: 9px; height: 9px; background: #7aa2f7;"></div><div style="font-size: 10px; color: #565f89;">download</div></div>
<div style="display: flex; align-items: center; gap: 6px;"><div style="width: 9px; height: 9px; background: #f7cf7a;"></div><div style="font-size: 10px; color: #565f89;">upload</div></div>
</div>
<div style="font-size: 10px; color: #565f89;">plan 450 / 50 Mbps</div>
</div>
<div class="sep" style="margin: 16px 0 12px 0;"></div>
<div style="display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 10px;">
<div class="cap">PEAK SPEED &middot; LAST RUN 24 AUG 12:04</div>
<div style="font-size: 10px; color: #565f89;">informational, not scored</div>
</div>
<div style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 24px;">
<div style="display: flex; align-items: baseline; justify-content: space-between;"><span style="font-size: 11px; color: #565f89;">Download</span><span style="font-size: 11px; color: #c0caf5;">412.3 Mbps</span></div>
<div style="display: flex; align-items: baseline; justify-content: space-between;"><span style="font-size: 11px; color: #565f89;">Upload</span><span style="font-size: 11px; color: #c0caf5;">48.1 Mbps</span></div>
<div style="display: flex; align-items: baseline; justify-content: space-between;"><span style="font-size: 11px; color: #565f89;">Idle ping</span><span style="font-size: 11px; color: #c0caf5;">9 ms</span></div>
<div style="display: flex; align-items: baseline; justify-content: space-between;"><span style="font-size: 11px; color: #565f89;">Loaded ping</span><span style="font-size: 11px; color: #e0af68;">34 ms</span></div>
<div style="display: flex; align-items: baseline; justify-content: space-between;"><span style="font-size: 11px; color: #565f89;">Jitter</span><span style="font-size: 11px; color: #c0caf5;">1.8 ms</span></div>
<div style="display: flex; align-items: baseline; justify-content: space-between;"><span style="font-size: 11px; color: #565f89;">Data used</span><span style="font-size: 11px; color: #c0caf5;">287 MB</span></div>
<div style="display: flex; align-items: baseline; justify-content: space-between;"><span style="font-size: 11px; color: #565f89;">Server</span><span style="font-size: 11px; color: #c0caf5;">Delhi &middot; 18 km</span></div>
<div style="display: flex; align-items: baseline; justify-content: space-between;"><span style="font-size: 11px; color: #565f89;">Engine</span><span style="font-size: 11px; color: #c0caf5;">Ookla</span></div>
</div>
<div class="sep" style="margin: 14px 0 12px 0;"></div>
<div style="display: flex; align-items: center; justify-content: space-between; gap: 12px;">
<div style="display: flex; flex-direction: column; gap: 5px;">
<div class="cap">PEAK TEST ENGINE</div>
<div style="display: flex; gap: 5px;">
<div style="height: 22px; padding: 0 10px; display: flex; align-items: center; font-size: 10px; color: #c0caf5; background: rgba(169,177,214,0.18);">Ookla</div>
<div style="height: 22px; padding: 0 10px; display: flex; align-items: center; font-size: 10px; color: #a9b1d6; background: rgba(169,177,214,0.04); border: 1px solid rgba(169,177,214,0.4);">Cloudflare</div>
<div style="height: 22px; padding: 0 10px; display: flex; align-items: center; font-size: 10px; color: #a9b1d6; background: rgba(169,177,214,0.04); border: 1px solid rgba(169,177,214,0.4);">fast.com</div>
</div>
</div>
<div style="display: flex; align-items: center; gap: 7px; height: 28px; padding: 0 12px; background: rgba(169,177,214,0.04); border: 1px solid rgba(169,177,214,0.4); color: #c0caf5; font-size: 11px;">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#c0caf5" stroke-width="1.6" stroke-linecap="round"><path d="M4 18a9 9 0 1 1 16 0"></path><path d="M12 14.5 16.5 9"></path></svg>
Run test
</div>
</div>
<div style="font-size: 10px; color: #565f89; margin-top: 11px; line-height: 1.6;">A peak test sizes itself to saturate the line for about 10 s each way &mdash; up to ~600 MB on a fast one, far less on a slow one &mdash; so it only ever runs when you ask for it. The hourly content check above is what keeps the score honest, at a fraction of the data.</div>
</div>
</x-dc>
<script data-dc-script data-props='{"$preview":{"width":560,"height":800}}'>
class Component extends DCLogic {
rng(seed) { let s = seed >>> 0; return function () { s = (s * 1664525 + 1013904223) >>> 0; return s / 4294967296 } }
renderVals() {
var N = 90, rand = this.rng(4242)
var W = 524, mid = 59, up = 55, down = 55
var rx = [], tx = []
for (var i = 0; i < N; i++) {
var r = 0.25 + rand() * 0.3
if (i > 20 && i < 46) r = 0.55 + rand() * 0.42
if (i === 33 || i === 34) r = 1
rx.push(r)
tx.push(0.12 + rand() * 0.22 + (i > 58 && i < 70 ? 0.45 : 0))
}
var xAt = function (i) { return (i * (W - 1) / (N - 1)).toFixed(1) }
var rxPts = [], txPts = [], rxLine = '', txLine = ''
for (var j = 0; j < N; j++) {
var a = xAt(j) + ',' + (mid - up * rx[j]).toFixed(1)
var b = xAt(j) + ',' + (mid + down * tx[j]).toFixed(1)
rxPts.push(a); txPts.push(b)
rxLine += (j === 0 ? 'M' : 'L') + a
txLine += (j === 0 ? 'M' : 'L') + b
}
var vals = [
[412, 48], [404, 47], [388, 46], [412, 48], [318, 41], [396, 47],
[421, 49], [402, 48], [255, 38], [408, 47], [415, 49], [412, 48]
]
var maxV = 450, base = 73, plot = 66, slot = W / vals.length
var tests = vals.map(function (v, i) {
var dh = Math.max(2, Math.round(plot * v[0] / maxV))
var uh = Math.max(2, Math.round(plot * v[1] / maxV * 3.2))
var left = i * slot + (slot - 26) / 2
return {
dx: left.toFixed(1), dy: (base - dh).toFixed(1), dh: dh,
ux: (left + 17).toFixed(1), uy: (base - uh).toFixed(1), uh: uh
}
})
return {
c: {
rxLine: rxLine, txLine: txLine,
rxArea: 'M0,' + mid + 'L' + rxPts.join('L') + 'L' + W + ',' + mid + 'Z',
txArea: 'M0,' + mid + 'L' + txPts.join('L') + 'L' + W + ',' + mid + 'Z',
tests: tests
}
}
}
}
</script>
</body>
</html>
@@ -0,0 +1,137 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap">
<style>
body { margin: 0; background: #0a0a0d; font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; }
a { color: #7aa2f7; } a:hover { color: #b4bee6; }
</style>
</helmet>
<div style="position: relative; width: 1000px; height: 560px; background: #000000; overflow: hidden;">
<div style="position: absolute; inset: 0; background: rgba(10,10,14,0.78);"></div>
<div style="position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; gap: 0;">
<div style="font-size: 11px; letter-spacing: 0.42em; color: rgba(255,255,255,0.55); margin-bottom: 22px;">EXCITEL</div>
<div style="display: flex; align-items: flex-start; gap: 78px;">
<div style="display: flex; flex-direction: column; align-items: center; gap: 14px;">
<svg width="300" height="300" viewBox="0 0 300 300" style="display: block;">
<defs>
<linearGradient id="ndl-down" gradientUnits="userSpaceOnUse" x1="{{g.down.nx1}}" y1="{{g.down.ny1}}" x2="{{g.down.nx2}}" y2="{{g.down.ny2}}">
<stop offset="0" stop-color="rgba(255,255,255,0.10)"></stop>
<stop offset="1" stop-color="#7aa2f7"></stop>
</linearGradient>
</defs>
<path d="{{g.arc}}" fill="none" stroke="rgba(255,255,255,0.13)" stroke-width="2" stroke-linecap="round"></path>
<sc-for list="{{g.ticks}}" as="t" hint-placeholder-count="41">
<line x1="{{t.x1}}" y1="{{t.y1}}" x2="{{t.x2}}" y2="{{t.y2}}" stroke="{{t.stroke}}" stroke-width="{{t.w}}"></line>
</sc-for>
<line x1="{{g.down.nx1}}" y1="{{g.down.ny1}}" x2="{{g.down.nx2}}" y2="{{g.down.ny2}}" stroke="url(#ndl-down)" stroke-width="3.2" stroke-linecap="round"></line>
<text x="150" y="164" text-anchor="middle" font-family="JetBrains Mono, monospace" font-size="42" font-weight="700" fill="#ffffff">412.3</text>
<text x="150" y="184" text-anchor="middle" font-family="JetBrains Mono, monospace" font-size="12" fill="rgba(255,255,255,0.55)">Mbps</text>
</svg>
<div style="font-size: 11px; letter-spacing: 0.3em; color: rgba(255,255,255,0.9);">DOWNLOAD</div>
</div>
<div style="display: flex; flex-direction: column; align-items: center; gap: 14px;">
<svg width="300" height="300" viewBox="0 0 300 300" style="display: block;">
<defs>
<linearGradient id="ndl-up" gradientUnits="userSpaceOnUse" x1="{{g.up.nx1}}" y1="{{g.up.ny1}}" x2="{{g.up.nx2}}" y2="{{g.up.ny2}}">
<stop offset="0" stop-color="rgba(255,255,255,0.10)"></stop>
<stop offset="1" stop-color="#7aa2f7"></stop>
</linearGradient>
</defs>
<path d="{{g.arc}}" fill="none" stroke="rgba(255,255,255,0.13)" stroke-width="2" stroke-linecap="round"></path>
<sc-for list="{{g.ticks}}" as="t" hint-placeholder-count="41">
<line x1="{{t.x1}}" y1="{{t.y1}}" x2="{{t.x2}}" y2="{{t.y2}}" stroke="{{t.stroke}}" stroke-width="{{t.w}}"></line>
</sc-for>
<line x1="{{g.up.nx1}}" y1="{{g.up.ny1}}" x2="{{g.up.nx2}}" y2="{{g.up.ny2}}" stroke="url(#ndl-up)" stroke-width="3.2" stroke-linecap="round"></line>
<text x="150" y="164" text-anchor="middle" font-family="JetBrains Mono, monospace" font-size="42" font-weight="700" fill="#ffffff">48.1</text>
<text x="150" y="184" text-anchor="middle" font-family="JetBrains Mono, monospace" font-size="12" fill="rgba(255,255,255,0.55)">Mbps</text>
</svg>
<div style="font-size: 11px; letter-spacing: 0.3em; color: rgba(255,255,255,0.55);">UPLOAD</div>
</div>
</div>
<div style="display: flex; align-items: center; gap: 26px; margin-top: 30px; padding-top: 18px; border-top: 1px solid rgba(255,255,255,0.10);">
<div style="display: flex; align-items: baseline; gap: 8px;">
<span style="font-size: 10px; letter-spacing: 0.16em; color: rgba(255,255,255,0.4);">IDLE</span>
<span style="font-size: 14px; color: rgba(255,255,255,0.9);">9 ms</span>
</div>
<div style="width: 26px; height: 1px; background: rgba(255,255,255,0.2);"></div>
<div style="display: flex; align-items: baseline; gap: 8px;">
<span style="font-size: 10px; letter-spacing: 0.16em; color: rgba(255,255,255,0.4);">UNDER LOAD</span>
<span style="font-size: 14px; color: #ffc678;">34 ms</span>
</div>
<div style="width: 26px; height: 1px; background: rgba(255,255,255,0.2);"></div>
<div style="display: flex; align-items: baseline; gap: 8px;">
<span style="font-size: 10px; letter-spacing: 0.16em; color: rgba(255,255,255,0.4);">BUFFERBLOAT</span>
<span style="font-size: 14px; color: #a9e88a;">A&minus;</span>
</div>
</div>
</div>
<div style="position: absolute; left: 26px; bottom: 22px; font-size: 10px; letter-spacing: 0.14em; color: rgba(255,255,255,0.28);">SCALE 500 Mbps &middot; OOKLA &middot; DELHI</div>
<div style="position: absolute; right: 26px; bottom: 22px; font-size: 10px; letter-spacing: 0.14em; color: rgba(255,255,255,0.28);">ENTER TO RUN AGAIN &middot; ESC TO CLOSE</div>
</div>
</x-dc>
<script data-dc-script data-props='{"$preview":{"width":1000,"height":560}}'>
class Component extends DCLogic {
polar(cx, cy, r, deg) {
var t = deg * Math.PI / 180
return { x: cx + r * Math.cos(t), y: cy + r * Math.sin(t) }
}
renderVals() {
var cx = 150, cy = 152, R = 120
var START = 135, SWEEP = 270
var a0 = this.polar(cx, cy, R, START)
var a1 = this.polar(cx, cy, R, START + SWEEP)
var arc = 'M' + a0.x.toFixed(2) + ',' + a0.y.toFixed(2) +
'A' + R + ',' + R + ' 0 1 1 ' + a1.x.toFixed(2) + ',' + a1.y.toFixed(2)
var ticks = []
for (var i = 0; i <= 40; i++) {
var deg = START + SWEEP * i / 40
var major = i % 5 === 0
var inner = major ? R - 17 : R - 9
var p1 = this.polar(cx, cy, R - 3, deg)
var p2 = this.polar(cx, cy, inner, deg)
ticks.push({
x1: p1.x.toFixed(2), y1: p1.y.toFixed(2),
x2: p2.x.toFixed(2), y2: p2.y.toFixed(2),
stroke: major ? 'rgba(255,255,255,0.42)' : 'rgba(255,255,255,0.16)',
w: major ? 2 : 1
})
}
var self = this
function needle(value, scale) {
var frac = Math.max(0, Math.min(1, value / scale))
var deg = START + SWEEP * frac
var hub = self.polar(cx, cy, 24, deg)
var tip = self.polar(cx, cy, R - 26, deg)
return {
nx1: hub.x.toFixed(2), ny1: hub.y.toFixed(2),
nx2: tip.x.toFixed(2), ny2: tip.y.toFixed(2)
}
}
return { g: { arc: arc, ticks: ticks, down: needle(412.3, 500), up: needle(48.1, 500) } }
}
}
</script>
</body>
</html>
@@ -0,0 +1,188 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap">
<style>
body { margin: 0; background: #0e0e14; font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; }
a { color: #7aa2f7; } a:hover { color: #b4bee6; }
.cap { font-size: 10px; letter-spacing: 0.12em; color: #565f89; }
.tab { flex-grow: 1; height: 26px; display: flex; align-items: center; justify-content: center; font-size: 11px; color: #a9b1d6; background: rgba(169,177,214,0.04); border: 1px solid rgba(169,177,214,0.4); }
.tabon { flex-grow: 1; height: 26px; display: flex; align-items: center; justify-content: center; font-size: 11px; color: #c0caf5; background: rgba(169,177,214,0.18); border: 1px solid transparent; }
.sep { height: 1px; background: rgba(169,177,214,0.12); }
.kv { display: flex; align-items: baseline; justify-content: space-between; }
.k { font-size: 11px; color: #565f89; }
.v { font-size: 11px; color: #c0caf5; }
</style>
</helmet>
<div style="display: flex; flex-direction: column; width: 560px; background: #1a1b26; border: 2px solid #7aa2f7; box-sizing: border-box; padding: 18px; color: #a9b1d6;">
<div style="display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;">
<div style="display: flex; align-items: flex-start; gap: 10px;">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#9ece6a" stroke-width="1.6" stroke-linecap="round" style="margin-top: 2px;">
<path d="M2 8.5a15 15 0 0 1 20 0"></path><path d="M5 12.2a10.5 10.5 0 0 1 14 0"></path><path d="M8.2 15.9a6 6 0 0 1 7.6 0"></path><circle cx="12" cy="19.3" r="1.1" fill="#9ece6a" stroke="none"></circle>
</svg>
<div style="display: flex; flex-direction: column; gap: 3px;">
<div style="font-size: 16px; font-weight: 700; color: #c0caf5;">Excitel</div>
<div class="cap" style="letter-spacing: 0.1em;">EXCELLENT &middot; ONLINE 4H 12M</div>
</div>
</div>
<div style="display: flex; flex-direction: column; align-items: flex-end; gap: 1px;">
<div style="font-size: 30px; font-weight: 700; line-height: 1; color: #9ece6a;">94</div>
<div class="cap">EXPERIENCE</div>
</div>
</div>
<div style="display: flex; gap: 6px; margin-top: 16px;">
<div class="tab">Overview</div><div class="tab">Latency</div><div class="tab">Speed</div><div class="tabon">Wi-Fi</div><div class="tab">Events</div>
</div>
<div class="sep" style="margin: 16px 0 14px 0;"></div>
<div class="cap" style="margin-bottom: 11px;">THE LOCAL LEG &middot; LAPTOP TO ROUTER</div>
<div style="display: flex; align-items: flex-end; gap: 22px;">
<div style="display: flex; flex-direction: column; gap: 2px;">
<div style="font-size: 28px; font-weight: 700; line-height: 1; color: #9ece6a;">&minus;47<span style="font-size: 12px; color: #565f89; font-weight: 400;"> dBm</span></div>
<div class="cap" style="letter-spacing: 0.1em;">SIGNAL</div>
</div>
<div style="flex-grow: 1; display: flex; flex-direction: column; gap: 6px; padding-bottom: 3px;">
<div style="position: relative; height: 8px; background: rgba(169,177,214,0.10);">
<div style="height: 8px; width: 78%; background: #9ece6a;"></div>
<div style="position: absolute; left: 55%; top: -3px; width: 1px; height: 14px; background: rgba(169,177,214,0.35);"></div>
</div>
<div style="display: flex; justify-content: space-between;">
<div style="font-size: 9px; color: #414868;">&minus;90 unusable</div>
<div style="font-size: 9px; color: #414868;">&minus;67 marginal</div>
<div style="font-size: 9px; color: #414868;">&minus;30 max</div>
</div>
</div>
</div>
<div style="display: flex; align-items: baseline; justify-content: space-between; margin: 16px 0 6px 0;">
<div class="cap">SIGNAL &amp; LOCAL LAG &middot; LAST 30 MIN</div>
<div style="font-size: 10px; color: #565f89;">one roam</div>
</div>
<svg width="524" height="82" viewBox="0 0 524 82" style="display: block;">
<line x1="0" y1="81.5" x2="524" y2="81.5" stroke="rgba(169,177,214,0.16)"></line>
<line x1="{{c.roamX}}" y1="0" x2="{{c.roamX}}" y2="82" stroke="rgba(187,154,247,0.5)" stroke-width="1" stroke-dasharray="2 3"></line>
<path d="{{c.sigArea}}" fill="rgba(158,206,106,0.16)"></path>
<path d="{{c.sigLine}}" fill="none" stroke="#9ece6a" stroke-width="1.4" stroke-linejoin="round"></path>
<path d="{{c.lagLine}}" fill="none" stroke="#565f89" stroke-width="1" stroke-linejoin="round"></path>
</svg>
<div style="display: flex; align-items: center; gap: 16px; margin-top: 6px;">
<div style="display: flex; align-items: center; gap: 6px;"><div style="width: 10px; height: 2px; background: #9ece6a;"></div><div style="font-size: 10px; color: #565f89;">signal</div></div>
<div style="display: flex; align-items: center; gap: 6px;"><div style="width: 10px; height: 2px; background: #565f89;"></div><div style="font-size: 10px; color: #565f89;">local lag</div></div>
<div style="display: flex; align-items: center; gap: 6px;"><div style="width: 1px; height: 9px; background: #bb9af7;"></div><div style="font-size: 10px; color: #565f89;">roamed to a stronger AP</div></div>
</div>
<div class="sep" style="margin: 16px 0 12px 0;"></div>
<div style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 24px;">
<div class="kv"><span class="k">Band</span><span class="v">5 GHz</span></div>
<div class="kv"><span class="k">Channel</span><span class="v">44 &middot; 80 MHz</span></div>
<div class="kv"><span class="k">Tx rate</span><span class="v">866 Mbps</span></div>
<div class="kv"><span class="k">Rx rate</span><span class="v">780 Mbps</span></div>
<div class="kv"><span class="k">Standard</span><span class="v">802.11ax</span></div>
<div class="kv"><span class="k">Security</span><span class="v">WPA2</span></div>
<div class="kv"><span class="k">BSSID</span><span class="v">c8:3a:35:4f:12:80</span></div>
<div class="kv"><span class="k">Interface</span><span class="v">wlan0</span></div>
</div>
<div class="sep" style="margin: 14px 0 12px 0;"></div>
<div class="cap" style="margin-bottom: 10px;">AIRTIME HEALTH &middot; WHY WI-FI FEELS SLOW WHEN SIGNAL LOOKS FINE</div>
<div style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px;">
<div style="display: flex; flex-direction: column; gap: 5px;">
<div style="font-size: 18px; font-weight: 700; line-height: 1; color: #9ece6a;">1.2 %</div>
<div class="cap" style="letter-spacing: 0.08em;">TX RETRIES</div>
<div style="height: 3px; background: rgba(169,177,214,0.12);"><div style="height: 3px; width: 12%; background: #9ece6a;"></div></div>
</div>
<div style="display: flex; flex-direction: column; gap: 5px;">
<div style="font-size: 18px; font-weight: 700; line-height: 1; color: #e0af68;">7</div>
<div class="cap" style="letter-spacing: 0.08em;">TX FAILED</div>
<div style="height: 3px; background: rgba(169,177,214,0.12);"><div style="height: 3px; width: 26%; background: #e0af68;"></div></div>
</div>
<div style="display: flex; flex-direction: column; gap: 5px;">
<div style="font-size: 18px; font-weight: 700; line-height: 1; color: #9ece6a;">0</div>
<div class="cap" style="letter-spacing: 0.08em;">BEACON LOSS</div>
<div style="height: 3px; background: rgba(169,177,214,0.12);"><div style="height: 3px; width: 3%; background: #9ece6a;"></div></div>
</div>
</div>
<div class="sep" style="margin: 14px 0 12px 0;"></div>
<div class="cap" style="margin-bottom: 10px;">LINK EVENTS</div>
<div style="display: flex; flex-direction: column; gap: 8px;">
<div style="display: flex; align-items: baseline; gap: 10px;">
<div style="font-size: 10px; color: #565f89; width: 46px; flex-shrink: 0;">12:41</div>
<div style="width: 5px; height: 5px; background: #bb9af7; flex-shrink: 0; transform: translateY(-1px);"></div>
<div style="font-size: 11px; color: #a9b1d6; flex-grow: 1;">Roamed to c8:3a:35:4f:12:80, channel 149 &rarr; 44</div>
<div style="font-size: 10px; color: #565f89;">&minus;61 &rarr; &minus;47 dBm</div>
</div>
<div style="display: flex; align-items: baseline; gap: 10px;">
<div style="font-size: 10px; color: #565f89; width: 46px; flex-shrink: 0;">11:58</div>
<div style="width: 5px; height: 5px; background: #e0af68; flex-shrink: 0; transform: translateY(-1px);"></div>
<div style="font-size: 11px; color: #a9b1d6; flex-grow: 1;">Rate dropped to 173 Mbps for 40 s</div>
<div style="font-size: 10px; color: #565f89;">microwave band</div>
</div>
<div style="display: flex; align-items: baseline; gap: 10px;">
<div style="font-size: 10px; color: #565f89; width: 46px; flex-shrink: 0;">08:32</div>
<div style="width: 5px; height: 5px; background: #9ece6a; flex-shrink: 0; transform: translateY(-1px);"></div>
<div style="font-size: 11px; color: #a9b1d6; flex-grow: 1;">Associated with Excitel after wake</div>
<div style="font-size: 10px; color: #565f89;">1.4 s to online</div>
</div>
</div>
</div>
</x-dc>
<script data-dc-script data-props='{"$preview":{"width":560,"height":800}}'>
class Component extends DCLogic {
rng(seed) { let s = seed >>> 0; return function () { s = (s * 1664525 + 1013904223) >>> 0; return s / 4294967296 } }
renderVals() {
var N = 100, rand = this.rng(9111), W = 524, H = 82
var roam = 62
var sig = [], lag = []
for (var i = 0; i < N; i++) {
var base = i < roam ? -61 : -47
sig.push(base + (rand() - 0.5) * 4)
lag.push(1.2 + rand() * 1.1 + (i < roam ? 0.8 : 0))
}
var lo = -80, hi = -35
var xAt = function (i) { return (i * (W - 1) / (N - 1)).toFixed(1) }
var sy = function (v) { return (H - (H - 6) * (v - lo) / (hi - lo)).toFixed(1) }
var ly = function (v) { return (H - (H - 6) * v / 8).toFixed(1) }
var sp = [], sigLine = '', lagLine = ''
for (var j = 0; j < N; j++) {
var a = xAt(j) + ',' + sy(sig[j])
sp.push(a)
sigLine += (j === 0 ? 'M' : 'L') + a
lagLine += (j === 0 ? 'M' : 'L') + xAt(j) + ',' + ly(lag[j])
}
return {
c: {
sigLine: sigLine,
sigArea: 'M0,' + H + 'L' + sp.join('L') + 'L' + W + ',' + H + 'Z',
lagLine: lagLine,
roamX: xAt(roam)
}
}
}
}
</script>
</body>
</html>
File diff suppressed because one or more lines are too long