<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>dbg — Agent Debug Toolkit</title>
<meta name="description" content="A universal debugger CLI that lets AI agents observe runtime state instead of guessing from source code.">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=DM+Mono:ital,wght@0,300;0,400;0,500;1,400&family=Instrument+Serif:ital@0;1&display=swap" rel="stylesheet">
<style>
*{margin:0;padding:0;box-sizing:border-box}
:root{
--void:#06080c;
--ink:#0b0e14;
--slab:#111620;
--rule:#1a2233;
--mute:#4a5568;
--read:#94a3b8;
--lit:#d1dce8;
--white:#f1f5f9;
--trace:#3dffa0;
--probe:#5eead4;
--signal:#38bdf8;
--fault:#ff5c5c;
--warn:#fbbf24;
--glow:rgba(61,255,160,.06);
--mono:"DM Mono",ui-monospace,"Cascadia Code","Fira Code",Menlo,Consolas,monospace;
--serif:"Instrument Serif",Georgia,"Times New Roman",serif;
}
html{scroll-behavior:smooth}
body{
background:var(--void);
color:var(--lit);
font-family:var(--mono);
font-weight:400;
font-size:15px;
line-height:1.65;
overflow-x:hidden;
-webkit-font-smoothing:antialiased;
}
body::after{
content:'';
position:fixed;
inset:0;
pointer-events:none;
z-index:9999;
background:repeating-linear-gradient(
0deg,
transparent,
transparent 2px,
rgba(0,0,0,.03) 2px,
rgba(0,0,0,.03) 4px
);
}
.grid-bg{
position:fixed;
inset:0;
z-index:-1;
background-image:
linear-gradient(var(--rule) 1px,transparent 1px),
linear-gradient(90deg,var(--rule) 1px,transparent 1px);
background-size:60px 60px;
opacity:.25;
mask-image:radial-gradient(ellipse 80% 70% at 50% 30%,black 20%,transparent 70%);
}
a{color:var(--probe);text-decoration:none;transition:color .2s}
a:hover{color:var(--trace)}
.top-nav{
display:flex;
justify-content:center;
gap:4px;
padding:16px 24px 0;
}
.top-nav a{
font-size:.75rem;
font-weight:500;
letter-spacing:.06em;
padding:6px 16px;
border-radius:4px;
color:var(--mute);
transition:all .2s;
}
.top-nav a:hover{color:var(--read)}
.top-nav a.active{
color:var(--trace);
background:rgba(61,255,160,.06);
}
.hero{
position:relative;
display:flex;
flex-direction:column;
align-items:center;
text-align:center;
padding:48px 24px 40px;
max-width:800px;
margin:0 auto;
}
.hero-glow{
position:absolute;
top:-120px;left:50%;
transform:translateX(-50%);
width:600px;height:400px;
background:radial-gradient(ellipse,rgba(61,255,160,.08) 0%,transparent 70%);
pointer-events:none;
}
.hero .logo{width:120px;filter:drop-shadow(0 0 40px rgba(61,255,160,.2));margin-bottom:24px}
.hero h1{
font-family:var(--serif);
font-weight:400;
font-size:clamp(2.2rem,5vw,3.4rem);
line-height:1.15;
color:var(--white);
margin-bottom:20px;
letter-spacing:-.02em;
}
.hero h1 em{
font-style:italic;
color:var(--trace);
text-shadow:0 0 30px rgba(61,255,160,.3);
}
.hero .sub{
font-size:.95rem;
color:var(--read);
max-width:500px;
margin-bottom:36px;
line-height:1.7;
}
.hero .actions{display:flex;gap:12px;flex-wrap:wrap;justify-content:center}
.btn{
display:inline-flex;align-items:center;gap:6px;
padding:10px 22px;
border-radius:4px;
font-family:var(--mono);font-size:.85rem;font-weight:500;
text-decoration:none !important;
transition:all .2s;
border:1px solid transparent;
}
.btn-g{
background:var(--trace);color:var(--void) !important;
box-shadow:0 0 20px rgba(61,255,160,.15);
}
.btn-g:hover{box-shadow:0 0 30px rgba(61,255,160,.3);transform:translateY(-1px)}
.btn-o{
background:transparent;color:var(--probe) !important;
border-color:var(--rule);
}
.btn-o:hover{border-color:var(--probe);background:rgba(94,234,212,.04)}
.wrap{max-width:820px;margin:0 auto;padding:0 24px}
section{padding:36px 0}
.sec-label{
font-size:.7rem;
font-weight:500;
letter-spacing:.15em;
text-transform:uppercase;
color:var(--mute);
margin-bottom:10px;
}
.sec-title{
font-family:var(--serif);
font-weight:400;
font-size:clamp(1.6rem,3vw,2.2rem);
color:var(--white);
margin-bottom:12px;
letter-spacing:-.01em;
}
.sec-desc{
color:var(--read);
font-size:.9rem;
margin-bottom:40px;
}
.versus{
display:grid;
grid-template-columns:1fr 1fr;
gap:2px;
background:var(--rule);
border-radius:6px;
overflow:hidden;
}
@media(max-width:640px){.versus{grid-template-columns:1fr}}
.versus-card{
background:var(--ink);
padding:32px 28px;
}
.versus-card .tag{
display:inline-block;
font-size:.65rem;
font-weight:500;
letter-spacing:.12em;
text-transform:uppercase;
padding:3px 8px;
border-radius:3px;
margin-bottom:14px;
}
.versus-card.before .tag{background:rgba(255,92,92,.12);color:var(--fault)}
.versus-card.after .tag{background:rgba(61,255,160,.1);color:var(--trace)}
.versus-card p{font-size:.88rem;color:var(--read);line-height:1.7}
.versus-card p strong{color:var(--lit);font-weight:500}
.demo-wrap{
background:var(--ink);
border:1px solid var(--rule);
border-radius:8px;
overflow:hidden;
position:relative;
}
.demo-chrome{
display:flex;align-items:center;justify-content:space-between;
padding:10px 16px;
background:var(--slab);
border-bottom:1px solid var(--rule);
}
.demo-dots{display:flex;gap:6px}
.demo-dots span{width:10px;height:10px;border-radius:50%;background:var(--rule)}
.demo-dots span:first-child{background:#ff5f57}
.demo-dots span:nth-child(2){background:#febc2e}
.demo-dots span:nth-child(3){background:#28c840}
.demo-title-bar{font-size:.7rem;color:var(--mute);letter-spacing:.05em}
.demo-replay{
font-family:var(--mono);font-size:.7rem;
color:var(--mute);background:none;border:1px solid var(--rule);
padding:3px 10px;border-radius:3px;cursor:pointer;
transition:all .2s;
}
.demo-replay:hover{color:var(--trace);border-color:var(--trace)}
#term{
padding:20px;
font-family:var(--mono);
font-size:12.5px;
line-height:1.55;
color:#c9d1d9;
white-space:pre-wrap;
word-break:break-word;
height:420px;
overflow-y:auto;
position:relative;
}
#term::-webkit-scrollbar{width:6px}
#term::-webkit-scrollbar-track{background:transparent}
#term::-webkit-scrollbar-thumb{background:var(--rule);border-radius:3px}
#term::-webkit-scrollbar-thumb:hover{background:var(--mute)}
#term::before{
content:'';position:absolute;inset:0;
background:radial-gradient(ellipse at 50% 0%,rgba(61,255,160,.03),transparent 60%);
pointer-events:none;
}
.c-bold{font-weight:500}
.c-dim{opacity:.5}
.c-fg-red{color:#ff6b6b}
.c-fg-green{color:#3dffa0}
.c-fg-yellow{color:#fbbf24}
.c-fg-blue{color:#5eead4}
.c-fg-magenta{color:#c084fc}
.c-fg-cyan{color:#38bdf8}
.c-fg-white{color:#e2e8f0}
.c-bold.c-fg-red{color:#ff8787}
.c-bold.c-fg-green{color:#6fffb8}
.c-bold.c-fg-magenta{color:#d8b4fe}
.c-bold.c-fg-cyan{color:#7dd3fc}
.install-steps{display:grid;gap:2px;background:var(--rule);border-radius:6px;overflow:hidden}
.install-step{
background:var(--ink);
padding:24px 28px;
display:grid;
grid-template-columns:32px 1fr;
gap:16px;
align-items:start;
}
.install-step .num{
font-family:var(--serif);
font-size:1.4rem;
color:var(--trace);
line-height:1;
padding-top:2px;
}
.install-step pre{
background:var(--slab);
border:1px solid var(--rule);
border-radius:4px;
padding:10px 14px;
font-family:var(--mono);
font-size:.82rem;
color:var(--trace);
overflow-x:auto;
margin-top:8px;
}
.install-step p{font-size:.85rem;color:var(--read)}
.install-step p strong{color:var(--lit);font-weight:500}
.lang-grid{
display:grid;
grid-template-columns:repeat(auto-fill,minmax(140px,1fr));
gap:2px;
background:var(--rule);
border-radius:6px;
overflow:hidden;
}
.lang-item{
background:var(--ink);
padding:18px 16px;
text-align:center;
}
.lang-item .name{
font-size:.85rem;
color:var(--lit);
font-weight:500;
margin-bottom:4px;
}
.lang-item .tool{
font-size:.7rem;
color:var(--mute);
letter-spacing:.03em;
}
.lang-divider{
grid-column:1/-1;
background:var(--slab);
padding:6px 16px;
font-size:.65rem;
font-weight:500;
letter-spacing:.12em;
text-transform:uppercase;
color:var(--mute);
}
.arch-list{display:grid;gap:0;counter-reset:arch}
.arch-item{
display:grid;
grid-template-columns:48px 1fr;
gap:0;
padding:20px 0;
border-bottom:1px solid var(--rule);
}
.arch-item:last-child{border-bottom:none}
.arch-item::before{
counter-increment:arch;
content:counter(arch,decimal-leading-zero);
font-family:var(--serif);
font-size:1.1rem;
color:var(--trace);
opacity:.6;
padding-top:1px;
}
.arch-item strong{color:var(--white);font-weight:500;display:block;margin-bottom:2px}
.arch-item span{color:var(--read);font-size:.85rem}
footer{
padding:60px 24px;
text-align:center;
border-top:1px solid var(--rule);
}
footer p{font-size:.78rem;color:var(--mute)}
footer a{color:var(--read)}
footer a:hover{color:var(--trace)}
footer .sig{margin-top:12px;font-size:.7rem;color:var(--rule);letter-spacing:.05em}
.reveal{opacity:0;transform:translateY(16px);transition:opacity .6s ease,transform .6s ease}
.reveal.visible{opacity:1;transform:translateY(0)}
@media(max-width:640px){
body{font-size:14px}
.hero{padding:48px 20px 32px}
.hero .logo{width:80px;margin-bottom:16px}
.hero h1{font-size:1.7rem;margin-bottom:14px}
.hero .sub{font-size:.82rem;margin-bottom:24px;line-height:1.6}
.btn{padding:9px 16px;font-size:.78rem}
section{padding:20px 0}
.wrap{padding:0 16px}
.sec-label{margin-bottom:6px}
.sec-title{font-size:1.3rem;margin-bottom:8px}
.sec-desc{font-size:.8rem;margin-bottom:28px}
.versus{grid-template-columns:1fr}
.versus-card{padding:20px 18px}
.versus-card p{font-size:.8rem;line-height:1.6}
.demo-wrap{margin:0 -16px;border-radius:0;border-left:none;border-right:none}
.demo-title-bar{font-size:.6rem}
.demo-chrome{padding:8px 12px}
#term{
padding:12px;
font-size:11px;
line-height:1.5;
height:360px;
word-break:break-word;
}
.install-step{grid-template-columns:1fr;padding:18px 16px}
.install-step .num{display:none}
.install-step pre{font-size:.73rem;padding:8px 10px}
.install-step p{font-size:.8rem}
.lang-grid{grid-template-columns:repeat(3,1fr)}
.lang-item{padding:12px 8px}
.lang-item .name{font-size:.78rem}
.lang-item .tool{font-size:.6rem}
.lang-divider{font-size:.6rem;padding:5px 12px}
.arch-item{grid-template-columns:36px 1fr;padding:14px 0}
.arch-item::before{font-size:.95rem}
.arch-item strong{font-size:.85rem}
.arch-item span{font-size:.78rem}
footer{padding:32px 16px}
}
@media(max-width:380px){
.hero{padding:40px 16px 28px}
.hero .logo{width:70px;margin-bottom:12px}
.hero h1{font-size:1.5rem}
.btn{padding:8px 14px;font-size:.75rem}
.lang-grid{grid-template-columns:repeat(2,1fr)}
#term{font-size:10px}
.sec-title{font-size:1.2rem}
}
</style>
</head>
<body>
<div class="grid-bg" aria-hidden="true"></div>
<nav class="top-nav">
<a href="index.html" class="active">dbg</a>
<a href="gdbg.html">gdbg</a>
</nav>
<header class="hero">
<div class="hero-glow" aria-hidden="true"></div>
<img class="logo" src="logo_t.png" alt="dbg" width="120" height="120">
<h1>Give your agent <em>eyes</em>, not guesses.</h1>
<p class="sub">One CLI. Many debuggers. Your AI agent stops guessing at runtime state and starts observing it.</p>
<div class="actions">
<a class="btn btn-g" href="https://github.com/redknightlois/dbg">View source</a>
<a class="btn btn-o" href="#demo">Watch demo ↓</a>
</div>
</header>
<section>
<div class="wrap">
<div class="sec-title">Agents guess. Debuggers observe.</div>
<p class="sec-desc">The bottleneck for agentic engineering is not generation. It is diagnosis.</p>
<div class="versus reveal">
<div class="versus-card before">
<div class="tag">Without dbg</div>
<p>The agent reads source code, <strong>builds a theory</strong>, rewrites something, and hopes. Wrong guess? It guesses again. Five cycles of guess-and-rebuild per bug. <strong>Tokens, time, and trust — burned.</strong></p>
</div>
<div class="versus-card after">
<div class="tag">With dbg</div>
<p>The agent sets a breakpoint, <strong>steps to the crash</strong>, inspects the variable, and reads the actual value. <strong>Root cause on the first pass.</strong> One cycle. Done.</p>
</div>
</div>
</div>
</section>
<section id="demo">
<div class="wrap">
<div class="sec-title">Observe. Reason. Fix.</div>
<p class="sec-desc">The agent receives a crash report. Instead of guessing, it launches a debug session, steps to the error, and reads the state.</p>
<div class="demo-wrap reveal">
<div class="demo-chrome">
<div class="demo-dots"><span></span><span></span><span></span></div>
<div class="demo-title-bar">claude — dbg session</div>
<button class="demo-replay" onclick="replay()">↻ replay</button>
</div>
<div id="term"><span></span></div>
</div>
</div>
</section>
<section>
<div class="wrap">
<div class="sec-title">Two commands. That's it.</div>
<p class="sec-desc">Install the binary, point it at your agent. No configuration, no wrappers, no adapters.</p>
<div class="install-steps reveal">
<div class="install-step">
<div class="num">1</div>
<div>
<p><strong>Install</strong></p>
<pre>curl -sSf https://raw.githubusercontent.com/redknightlois/dbg/main/install.sh | sh
# or, if you already have Rust:
cargo install dbg-cli</pre>
</div>
</div>
<div class="install-step">
<div class="num">2</div>
<div>
<p><strong>Connect to your agent</strong></p>
<pre>dbg --init claude # or: dbg --init codex</pre>
<p style="margin-top:10px">The agent now knows when and how to use dbg. It picks the right backend, sets breakpoints, and interprets debugger output on its own.</p>
</div>
</div>
</div>
</div>
</section>
<section>
<div class="wrap">
<div class="sec-title">Many languages, one interface.</div>
<p class="sec-desc">The agent learns <code style="background:var(--slab);padding:2px 7px;border-radius:3px;font-size:.85em;color:var(--trace)">dbg</code> once. It works everywhere.</p>
<div class="lang-grid reveal">
<div class="lang-divider">Debuggers</div>
<div class="lang-item"><div class="name">Rust</div><div class="tool">LLDB</div></div>
<div class="lang-item"><div class="name">C / C++</div><div class="tool">LLDB</div></div>
<div class="lang-item"><div class="name">Zig</div><div class="tool">LLDB</div></div>
<div class="lang-item"><div class="name">Python</div><div class="tool">PDB</div></div>
<div class="lang-item"><div class="name">Go</div><div class="tool">Delve</div></div>
<div class="lang-item"><div class="name">.NET / C#</div><div class="tool">NetCoreDbg</div></div>
<div class="lang-item"><div class="name">Java</div><div class="tool">JDB</div></div>
<div class="lang-item"><div class="name">Kotlin</div><div class="tool">JDB</div></div>
<div class="lang-item"><div class="name">JavaScript</div><div class="tool">node inspect</div></div>
<div class="lang-item"><div class="name">TypeScript</div><div class="tool">node inspect</div></div>
<div class="lang-item"><div class="name">PHP</div><div class="tool">phpdbg</div></div>
<div class="lang-item"><div class="name">Ruby</div><div class="tool">rdbg</div></div>
<div class="lang-item"><div class="name">D</div><div class="tool">LLDB</div></div>
<div class="lang-item"><div class="name">Nim</div><div class="tool">LLDB</div></div>
<div class="lang-item"><div class="name">Haskell</div><div class="tool">GHCi</div></div>
<div class="lang-item"><div class="name">OCaml</div><div class="tool">ocamldebug</div></div>
<div class="lang-divider">Profilers</div>
<div class="lang-item"><div class="name">Go</div><div class="tool">pprof</div></div>
<div class="lang-item"><div class="name">Linux</div><div class="tool">perf</div></div>
<div class="lang-item"><div class="name">C / C++</div><div class="tool">callgrind</div></div>
<div class="lang-item"><div class="name">Rust</div><div class="tool">callgrind</div></div>
<div class="lang-item"><div class="name">D</div><div class="tool">callgrind</div></div>
<div class="lang-item"><div class="name">Nim</div><div class="tool">callgrind</div></div>
<div class="lang-item"><div class="name">Zig</div><div class="tool">callgrind</div></div>
<div class="lang-item"><div class="name">Memory</div><div class="tool">massif / memcheck</div></div>
<div class="lang-item"><div class="name">Python</div><div class="tool">cProfile</div></div>
<div class="lang-item"><div class="name">.NET</div><div class="tool">dotnet-trace</div></div>
<div class="lang-item"><div class="name">Node.js</div><div class="tool">V8 --cpu-prof</div></div>
<div class="lang-item"><div class="name">PHP</div><div class="tool">Xdebug</div></div>
<div class="lang-item"><div class="name">Ruby</div><div class="tool">StackProf</div></div>
<div class="lang-item"><div class="name">Haskell</div><div class="tool">GHC profiler</div></div>
<div class="lang-divider">GPU Profilers — <a href="gdbg.html" style="color:var(--probe);text-decoration:none"><code style="font-size:.65rem;color:var(--probe)">gdbg</code></a></div>
<div class="lang-item"><div class="name">CUDA</div><div class="tool">nsys + ncu</div></div>
<div class="lang-item"><div class="name">PyTorch</div><div class="tool">torch.profiler</div></div>
<div class="lang-item"><div class="name">Triton</div><div class="tool">nsys + proton</div></div>
</div>
</div>
</section>
<section>
<div class="wrap">
<div class="sec-title">How it works.</div>
<div class="arch-list reveal">
<div class="arch-item"><div><strong>Daemon, not subprocess.</strong><span>The debugger stays alive across commands. No startup cost per interaction, no lost state between steps.</span></div></div>
<div class="arch-item"><div><strong>PTY, not pipes.</strong><span>The debugger thinks it's in a real terminal. No pipe-mode quirks, no missing output, no behavior differences from docs.</span></div></div>
<div class="arch-item"><div><strong>Output cleaning.</strong><span>Backends strip DWARF indexing, thread lifecycle, symbol loading noise. The agent gets clean, token-efficient output.</span></div></div>
<div class="arch-item"><div><strong>One interface, many languages.</strong><span>A backend trait maps each debugger's commands to a common CLI. The agent learns break, step, print once.</span></div></div>
</div>
</div>
</section>
<footer>
<p><a href="index.html">dbg</a>  ·  <a href="gdbg.html">gdbg</a>  ·  <a href="https://github.com/redknightlois/dbg">GitHub</a>  ·  MIT License  ·  Built by <a href="https://github.com/redknightlois">Federico Lois</a></p>
<div class="sig">dbg — agent debug toolkit</div>
</footer>
<script>
var CAST=[
[0.0,"o","\x1b[1;35m>\x1b[0m "],
[0.6,"o","T"],[0.65,"o","h"],[0.7,"o","e"],[0.73,"o"," "],
[0.78,"o","f"],[0.82,"o","u"],[0.85,"o","n"],[0.88,"o","c"],
[0.91,"o","t"],[0.94,"o","i"],[0.97,"o","o"],[1.0,"o","n"],
[1.03,"o"," "],[1.08,"o","i"],[1.11,"o","n"],[1.14,"o"," "],
[1.17,"o","/"],[1.2,"o","t"],[1.23,"o","m"],[1.26,"o","p"],
[1.29,"o","/"],[1.32,"o","c"],[1.35,"o","r"],[1.38,"o","a"],
[1.41,"o","s"],[1.44,"o","h"],[1.47,"o","."],[1.5,"o","p"],
[1.53,"o","y"],[1.56,"o"," "],[1.59,"o","c"],[1.62,"o","r"],
[1.65,"o","a"],[1.68,"o","s"],[1.71,"o","h"],[1.74,"o","e"],
[1.77,"o","s"],[1.8,"o","."],[1.83,"o"," "],[1.86,"o","D"],
[1.89,"o","e"],[1.92,"o","b"],[1.95,"o","u"],[1.98,"o","g"],
[2.01,"o"," "],[2.04,"o","i"],[2.07,"o","t"],[2.1,"o","."],
[2.5,"o","\r\n"],
[3.0,"o","\r\n"],
[3.1,"o","\x1b[2m \u2570\u2500 \x1b[0m\x1b[2mRead /tmp/crash.py\x1b[0m\r\n"],
[3.4,"o","\r\n"],
[3.5,"o"," The file accesses \x1b[1mx[5]\x1b[0m on a list. Let me start a debug session to inspect\r\n"],
[3.6,"o"," the runtime state and find the exact failure.\r\n"],
[4.0,"o","\r\n"],
[4.1,"o","\x1b[2m \u2570\u2500 \x1b[0m\x1b[1;36mBash\x1b[0m \x1b[2mdbg start python /tmp/crash.py\x1b[0m\r\n"],
[4.4,"o","\x1b[2m \x1b[0mtarget: /tmp/crash.py\r\n"],
[4.8,"o","\r\n"],
[4.9,"o","\x1b[2m \u2570\u2500 \x1b[0m\x1b[1;36mBash\x1b[0m \x1b[2mdbg break /tmp/crash.py:1\x1b[0m\r\n"],
[5.2,"o","\x1b[2m \x1b[0mBreakpoint 1 at /tmp/crash.py:1\r\n"],
[5.6,"o","\r\n"],
[5.7,"o","\x1b[2m \u2570\u2500 \x1b[0m\x1b[1;36mBash\x1b[0m \x1b[2mdbg run\x1b[0m\r\n"],
[6.0,"o","\x1b[2m \x1b[0m> /tmp/crash.py(1)<module>()\r\n"],
[6.1,"o","\x1b[2m \x1b[0m-> x = [1,2,3]; print(x[5])\r\n"],
[6.5,"o","\r\n"],
[6.6,"o"," Hit the breakpoint. Let me step into the crash.\r\n"],
[7.0,"o","\r\n"],
[7.1,"o","\x1b[2m \u2570\u2500 \x1b[0m\x1b[1;36mBash\x1b[0m \x1b[2mdbg step\x1b[0m\r\n"],
[7.4,"o","\x1b[2m \x1b[0m\x1b[1;31mIndexError: list index out of range\x1b[0m\r\n"],
[7.5,"o","\x1b[2m \x1b[0m> /tmp/crash.py(1)<module>()\r\n"],
[7.6,"o","\x1b[2m \x1b[0m-> x = [1,2,3]; print(x[5])\r\n"],
[8.0,"o","\r\n"],
[8.1,"o"," IndexError. Let me inspect the variable to confirm the root cause.\r\n"],
[8.5,"o","\r\n"],
[8.6,"o","\x1b[2m \u2570\u2500 \x1b[0m\x1b[1;36mBash\x1b[0m \x1b[2mdbg \"print(x)\"\x1b[0m\r\n"],
[8.9,"o","\x1b[2m \x1b[0m[1, 2, 3]\r\n"],
[9.3,"o","\r\n"],
[9.4,"o","\x1b[2m \u2570\u2500 \x1b[0m\x1b[1;36mBash\x1b[0m \x1b[2mdbg \"print(len(x))\"\x1b[0m\r\n"],
[9.7,"o","\x1b[2m \x1b[0m3\r\n"],
[10.1,"o","\r\n"],
[10.2,"o"," \x1b[1mRoot cause:\x1b[0m \x1b[33mx\x1b[0m has 3 elements (indices 0\u20132), but the code accesses \x1b[33mx[5]\x1b[0m.\r\n"],
[10.4,"o"," Fix: change \x1b[33mx[5]\x1b[0m to a valid index, or add a bounds check.\r\n"],
[10.8,"o","\r\n"],
[10.9,"o","\x1b[2m \u2570\u2500 \x1b[0m\x1b[1;36mBash\x1b[0m \x1b[2mdbg kill\x1b[0m\r\n"],
[11.2,"o","\x1b[2m \x1b[0mstopped\r\n"],
[11.6,"o","\r\n"],
[11.7,"o","\x1b[1;35m>\x1b[0m "],
[13.0,"o",""]
];
var FG={30:'',31:'red',32:'green',33:'yellow',34:'blue',35:'magenta',36:'cyan',37:'white'};
function ansi(s){
var r='',b=false,d=false,f='',i=0;
while(i<s.length){
if(s[i]==='\x1b'&&s[i+1]==='['){
var j=i+2;while(j<s.length&&s[j]!=='m')j++;
var cc=s.substring(i+2,j).split(';');
for(var k=0;k<cc.length;k++){var c=parseInt(cc[k]);if(c===0){b=d=false;f=''}else if(c===1)b=true;else if(c===2)d=true;else if(c>=30&&c<=37)f=FG[c]||''}
i=j+1;var cl=[];if(b)cl.push('c-bold');if(d)cl.push('c-dim');if(f)cl.push('c-fg-'+f);
r+='</span><span class="'+cl.join(' ')+'">';
}else if(s[i]==='\r'){i++}
else if(s[i]==='<'){r+='<';i++}
else if(s[i]==='>'){r+='>';i++}
else if(s[i]==='&'){r+='&';i++}
else{r+=s[i];i++}
}return r
}
var term=document.getElementById('term'),timers=[],restartTimer=null;
var isVisible=false,hasPlayed=false;
var CAST_DURATION=CAST[CAST.length-1][0]*1000;
var RESTART_DELAY=6000;
function replay(){
for(var i=0;i<timers.length;i++)clearTimeout(timers[i]);
if(restartTimer){clearTimeout(restartTimer);restartTimer=null}
timers=[];term.innerHTML='<span>';hasPlayed=true;
for(var i=0;i<CAST.length;i++){
(function(e){timers.push(setTimeout(function(){term.innerHTML+=ansi(e[2]);term.scrollTop=term.scrollHeight},e[0]*1000))})(CAST[i]);
}
restartTimer=setTimeout(function(){
if(isVisible)replay();
},CAST_DURATION+RESTART_DELAY);
}
var obs=new IntersectionObserver(function(entries){
var entry=entries[0];
isVisible=entry.isIntersecting;
if(isVisible&&!hasPlayed){
replay();
}else if(isVisible&&hasPlayed){
if(!restartTimer){
restartTimer=setTimeout(function(){if(isVisible)replay()},RESTART_DELAY);
}
}else{
if(restartTimer){clearTimeout(restartTimer);restartTimer=null}
}
},{threshold:.35});
obs.observe(term);
var rev=new IntersectionObserver(function(entries){
entries.forEach(function(e){if(e.isIntersecting){e.target.classList.add('visible');rev.unobserve(e.target)}})
},{threshold:.15,rootMargin:'0px 0px -40px 0px'});
document.querySelectorAll('.reveal').forEach(function(el){rev.observe(el)});
</script>
</body>
</html>