Publish RoleRouteBench trajectory explorer
Browse filesAdd the static trajectory viewer, JEV reference results, public/private isolation design, and router-submission links. The Space runs entirely in the browser and executes no model.
- README.md +11 -5
- app.js +89 -0
- benchmark.json +0 -0
- index.html +154 -17
- robots.txt +4 -0
- sitemap.xml +9 -0
- styles.css +123 -0
README.md
CHANGED
|
@@ -1,12 +1,18 @@
|
|
| 1 |
---
|
| 2 |
title: RoleRouteBench Explorer
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: static
|
|
|
|
| 7 |
pinned: false
|
| 8 |
license: apache-2.0
|
| 9 |
-
|
|
|
|
| 10 |
---
|
| 11 |
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
title: RoleRouteBench Explorer
|
| 3 |
+
emoji: 🧭
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: indigo
|
| 6 |
sdk: static
|
| 7 |
+
app_file: index.html
|
| 8 |
pinned: false
|
| 9 |
license: apache-2.0
|
| 10 |
+
datasets:
|
| 11 |
+
- TrangBui/RoleRouteBench
|
| 12 |
---
|
| 13 |
|
| 14 |
+
# RoleRouteBench Explorer
|
| 15 |
+
|
| 16 |
+
Static trajectory explorer and reference-results dashboard for
|
| 17 |
+
[RoleRouteBench](https://huggingface.co/datasets/TrangBui/RoleRouteBench).
|
| 18 |
+
It runs entirely in the browser and does not execute a router or model.
|
app.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const state = { data: null, packet: null };
|
| 2 |
+
const byId = (id) => document.getElementById(id);
|
| 3 |
+
const esc = (value) => String(value ?? "").replace(/[&<>'"]/g, (char) => ({"&":"&","<":"<",">":">","'":"'",'"':"""}[char]));
|
| 4 |
+
const percent = (part, total) => total ? `${Math.round(part * 100 / total)}%` : "—";
|
| 5 |
+
|
| 6 |
+
async function loadData() {
|
| 7 |
+
const response = await fetch("benchmark.json");
|
| 8 |
+
if (!response.ok) throw new Error(`data request failed (${response.status})`);
|
| 9 |
+
return response.json();
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
function renderResults(runs) {
|
| 13 |
+
byId("results-body").innerHTML = runs.map((run) => `
|
| 14 |
+
<tr>
|
| 15 |
+
<td><strong>${esc(run.domain_label)}</strong></td>
|
| 16 |
+
<td>${run.packet_count}</td>
|
| 17 |
+
<td>${run.trajectory_passed}/${run.packet_count} <span class="badge">${percent(run.trajectory_passed, run.packet_count)}</span></td>
|
| 18 |
+
<td>${run.independent_end_task_passed}/${run.packet_count} <span class="badge">${percent(run.independent_end_task_passed, run.packet_count)}</span></td>
|
| 19 |
+
<td>${run.primary_routing_decisions}</td>
|
| 20 |
+
<td>${run.suppressed_by_budget}</td>
|
| 21 |
+
</tr>`).join("");
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
function unique(values) { return [...new Set(values.filter(Boolean))].sort(); }
|
| 25 |
+
function fillSelect(select, values, label) {
|
| 26 |
+
select.innerHTML = `<option value="">${label}</option>` + values.map((value) => `<option value="${esc(value)}">${esc(value)}</option>`).join("");
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
function availablePackets() {
|
| 30 |
+
const domain = byId("domain-filter").value;
|
| 31 |
+
return state.data.packets.filter((packet) => !domain || packet.domain === domain);
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
function updatePacketOptions(keepSelection = true) {
|
| 35 |
+
const select = byId("packet-filter");
|
| 36 |
+
const previous = keepSelection ? select.value : "";
|
| 37 |
+
const packets = availablePackets();
|
| 38 |
+
select.innerHTML = packets.map((packet) => `<option value="${esc(packet.packet_id)}">${esc(packet.packet_id)}</option>`).join("");
|
| 39 |
+
if (packets.some((packet) => packet.packet_id === previous)) select.value = previous;
|
| 40 |
+
renderPacket();
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
function renderPacket() {
|
| 44 |
+
const id = byId("packet-filter").value;
|
| 45 |
+
state.packet = state.data.packets.find((packet) => packet.packet_id === id) || availablePackets()[0];
|
| 46 |
+
if (!state.packet) return;
|
| 47 |
+
byId("packet-filter").value = state.packet.packet_id;
|
| 48 |
+
const p = state.packet;
|
| 49 |
+
byId("packet-summary").innerHTML = `
|
| 50 |
+
<div class="packet-summary-head">
|
| 51 |
+
<div><h3>${esc(p.packet_id)}</h3><div class="badges"><span class="badge">${esc(p.domain_label)}</span><span class="badge">${esc(p.executor_model)}</span><span class="badge">${p.primary_routing_decisions} primary decisions</span></div></div>
|
| 52 |
+
<div class="badges"><span class="status ${p.trajectory_passed ? "success" : "failed"}">trajectory ${p.trajectory_passed ? "pass" : "fail"}</span><span class="status ${p.independent_end_task_passed ? "success" : "failed"}">trusted ${p.independent_end_task_passed ? "pass" : "fail"}</span></div>
|
| 53 |
+
</div><p>${esc(p.task)}</p>`;
|
| 54 |
+
renderSteps();
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
function renderSteps() {
|
| 58 |
+
const role = byId("role-filter").value;
|
| 59 |
+
const status = byId("status-filter").value;
|
| 60 |
+
const rows = state.packet.steps.filter((step) => (!role || step.role === role) && (!status || step.event_status === status));
|
| 61 |
+
byId("trajectory").innerHTML = rows.length ? rows.map((step) => `
|
| 62 |
+
<article class="trajectory-step">
|
| 63 |
+
<div class="step-number">#${String(step.index).padStart(2,"0")}</div>
|
| 64 |
+
<div class="step-role"><strong>${esc(step.role)}</strong><small>budget before: ${esc(step.budget_before)} · confidence: ${step.confidence == null ? "—" : Number(step.confidence).toFixed(2)}</small><span class="event-pill">${esc(step.event_status)} · ${esc(step.semantic_delta)}</span></div>
|
| 65 |
+
<div class="state-change"><small>state before → after</small><code>${esc(step.state_before || "not executed")}</code><code>→ ${esc(step.state_after || "not executed")}</code></div>
|
| 66 |
+
<div class="choice-list">top choices<br>${step.top_choices.map((choice) => `${esc(choice.role)} ${(choice.probability * 100).toFixed(0)}%`).join(" · ") || "not recorded"}</div>
|
| 67 |
+
</article>`).join("") : `<p class="error">No step matches the active role and status filters.</p>`;
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
async function init() {
|
| 71 |
+
try {
|
| 72 |
+
state.data = await loadData();
|
| 73 |
+
renderResults(state.data.runs);
|
| 74 |
+
const domains = state.data.runs.map((run) => run.domain);
|
| 75 |
+
byId("domain-filter").innerHTML += domains.map((domain) => `<option value="${esc(domain)}">${esc(state.data.runs.find((run) => run.domain === domain).domain_label)}</option>`).join("");
|
| 76 |
+
fillSelect(byId("role-filter"), unique(state.data.packets.flatMap((packet) => packet.steps.map((step) => step.role))), "All roles");
|
| 77 |
+
fillSelect(byId("status-filter"), unique(state.data.packets.flatMap((packet) => packet.steps.map((step) => step.event_status))), "All statuses");
|
| 78 |
+
updatePacketOptions(false);
|
| 79 |
+
byId("domain-filter").addEventListener("change", () => updatePacketOptions(false));
|
| 80 |
+
byId("packet-filter").addEventListener("change", renderPacket);
|
| 81 |
+
byId("role-filter").addEventListener("change", renderSteps);
|
| 82 |
+
byId("status-filter").addEventListener("change", renderSteps);
|
| 83 |
+
} catch (error) {
|
| 84 |
+
byId("results-body").innerHTML = `<tr><td colspan="6" class="error">Could not load explorer data: ${esc(error.message)}</td></tr>`;
|
| 85 |
+
byId("trajectory").innerHTML = `<p class="error">Explorer data is unavailable.</p>`;
|
| 86 |
+
}
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
document.addEventListener("DOMContentLoaded", init);
|
benchmark.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
index.html
CHANGED
|
@@ -1,19 +1,156 @@
|
|
| 1 |
<!doctype html>
|
| 2 |
-
<html>
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
</html>
|
|
|
|
| 1 |
<!doctype html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="utf-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
| 6 |
+
<meta name="description" content="Explore RoleRouteBench live multi-agent routing trajectories, JEV reference results, and the public/private isolation protocol.">
|
| 7 |
+
<meta name="theme-color" content="#08111f">
|
| 8 |
+
<title>RoleRouteBench — Dynamic role routing, made inspectable</title>
|
| 9 |
+
<link rel="stylesheet" href="styles.css">
|
| 10 |
+
<script type="application/ld+json">
|
| 11 |
+
{
|
| 12 |
+
"@context": "https://schema.org",
|
| 13 |
+
"@type": "Dataset",
|
| 14 |
+
"name": "RoleRouteBench",
|
| 15 |
+
"alternateName": "RoutingBench V4-beta",
|
| 16 |
+
"description": "A reproducible multi-domain benchmark for dynamic role routing in multi-agent systems, with 82 live trajectories across four domains.",
|
| 17 |
+
"identifier": "https://doi.org/10.57967/hf/11430",
|
| 18 |
+
"url": "https://huggingface.co/datasets/TrangBui/RoleRouteBench",
|
| 19 |
+
"version": "4.0.0-beta.2",
|
| 20 |
+
"creator": {"@type": "Person", "name": "Trang Bui"},
|
| 21 |
+
"license": "https://huggingface.co/datasets/TrangBui/RoleRouteBench/blob/main/LICENSE_DATA",
|
| 22 |
+
"sameAs": [
|
| 23 |
+
"https://doi.org/10.57967/hf/11430",
|
| 24 |
+
"https://huggingface.co/datasets/TrangBui/RoleRouteBench",
|
| 25 |
+
"https://github.com/BuiThiThanhTrang/RACO_MAS"
|
| 26 |
+
],
|
| 27 |
+
"keywords": ["multi-agent systems", "dynamic routing", "agent orchestration", "tool use", "benchmark", "live trajectories"]
|
| 28 |
+
}
|
| 29 |
+
</script>
|
| 30 |
+
</head>
|
| 31 |
+
<body>
|
| 32 |
+
<a class="skip-link" href="#main">Skip to content</a>
|
| 33 |
+
<header class="site-header">
|
| 34 |
+
<a class="brand" href="#top" aria-label="RoleRouteBench home">
|
| 35 |
+
<span class="brand-mark">RR</span>
|
| 36 |
+
<span>RoleRouteBench</span>
|
| 37 |
+
</a>
|
| 38 |
+
<nav aria-label="Primary navigation">
|
| 39 |
+
<a href="#results">Results</a>
|
| 40 |
+
<a href="#explorer">Explorer</a>
|
| 41 |
+
<a href="#isolation">Isolation</a>
|
| 42 |
+
<a href="#submit">Submit</a>
|
| 43 |
+
</nav>
|
| 44 |
+
<a class="header-link" href="https://huggingface.co/datasets/TrangBui/RoleRouteBench">Dataset ↗</a>
|
| 45 |
+
</header>
|
| 46 |
+
|
| 47 |
+
<main id="main">
|
| 48 |
+
<section class="hero" id="top">
|
| 49 |
+
<div class="hero-copy">
|
| 50 |
+
<p class="eyebrow">Frozen environment · live consequences · multi-step tasks</p>
|
| 51 |
+
<h1>Dynamic role routing,<br><span>made inspectable.</span></h1>
|
| 52 |
+
<p class="hero-lede">RoleRouteBench evaluates whether a decision model can coordinate specialized executors across evolving task states—not merely whether the final answer happens to be correct.</p>
|
| 53 |
+
<div class="hero-actions">
|
| 54 |
+
<a class="button primary" href="#explorer">Explore trajectories</a>
|
| 55 |
+
<a class="button secondary" href="https://doi.org/10.57967/hf/11430">DOI 10.57967/hf/11430 ↗</a>
|
| 56 |
+
</div>
|
| 57 |
+
</div>
|
| 58 |
+
<div class="route-card" aria-label="Illustrative routing trajectory">
|
| 59 |
+
<div class="route-card-head"><span>packet / live state</span><span class="live-dot">LIVE</span></div>
|
| 60 |
+
<div class="route-step"><span class="step-index">01</span><div><strong>Inspect evidence</strong><small>state changed</small></div><span class="status success">success</span></div>
|
| 61 |
+
<div class="route-line"></div>
|
| 62 |
+
<div class="route-step"><span class="step-index">02</span><div><strong>Author candidate</strong><small>artifact created</small></div><span class="status success">success</span></div>
|
| 63 |
+
<div class="route-line warning"></div>
|
| 64 |
+
<div class="route-step"><span class="step-index">03</span><div><strong>Execute candidate</strong><small>failure preserved</small></div><span class="status failed">failed</span></div>
|
| 65 |
+
<div class="route-line"></div>
|
| 66 |
+
<div class="route-step"><span class="step-index">04</span><div><strong>Diagnose & repair</strong><small>new routed action</small></div><span class="status success">success</span></div>
|
| 67 |
+
</div>
|
| 68 |
+
</section>
|
| 69 |
+
|
| 70 |
+
<section class="stats" aria-label="Benchmark summary">
|
| 71 |
+
<div><strong>82</strong><span>live trajectories</span></div>
|
| 72 |
+
<div><strong>4</strong><span>task domains</span></div>
|
| 73 |
+
<div><strong>568</strong><span>primary decisions</span></div>
|
| 74 |
+
<div><strong>33</strong><span>specialized roles</span></div>
|
| 75 |
+
</section>
|
| 76 |
+
|
| 77 |
+
<section class="section why">
|
| 78 |
+
<div class="section-kicker">Why RoleRouteBench?</div>
|
| 79 |
+
<div class="why-grid">
|
| 80 |
+
<h2>Final task success cannot tell you whether a router coordinated well.</h2>
|
| 81 |
+
<div class="why-copy">
|
| 82 |
+
<p>Outcome quality also depends on the frozen executor. RoleRouteBench therefore retains every routing decision, failed action, state transition, budget event, and independent evaluator result.</p>
|
| 83 |
+
<p>Competing routers see the same public state, role pool, adapters, executors, budgets, and evaluator. The environment stays fixed; only the routing policy changes.</p>
|
| 84 |
+
</div>
|
| 85 |
+
</div>
|
| 86 |
+
</section>
|
| 87 |
+
|
| 88 |
+
<section class="section" id="results">
|
| 89 |
+
<div class="section-heading">
|
| 90 |
+
<div><div class="section-kicker">Reference system</div><h2>JEV 1.13 results</h2></div>
|
| 91 |
+
<p>Reference signals for environment validation—not an oracle and not a composite leaderboard score.</p>
|
| 92 |
+
</div>
|
| 93 |
+
<div class="table-wrap">
|
| 94 |
+
<table>
|
| 95 |
+
<thead><tr><th>Domain</th><th>Packets</th><th>Trajectory pass</th><th>Trusted task pass</th><th>Primary decisions</th><th>Budget-suppressed</th></tr></thead>
|
| 96 |
+
<tbody id="results-body"><tr><td colspan="6">Loading reference results…</td></tr></tbody>
|
| 97 |
+
</table>
|
| 98 |
+
</div>
|
| 99 |
+
</section>
|
| 100 |
+
|
| 101 |
+
<section class="section explorer-section" id="explorer">
|
| 102 |
+
<div class="section-heading">
|
| 103 |
+
<div><div class="section-kicker">Trajectory explorer</div><h2>Follow each routed consequence</h2></div>
|
| 104 |
+
<p>Filter public compact traces. Raw prompts and executor outputs are not included.</p>
|
| 105 |
+
</div>
|
| 106 |
+
<div class="filters" aria-label="Trajectory filters">
|
| 107 |
+
<label>Domain<select id="domain-filter"><option value="">All domains</option></select></label>
|
| 108 |
+
<label>Packet<select id="packet-filter"></select></label>
|
| 109 |
+
<label>Role<select id="role-filter"><option value="">All roles</option></select></label>
|
| 110 |
+
<label>Event status<select id="status-filter"><option value="">All statuses</option></select></label>
|
| 111 |
+
</div>
|
| 112 |
+
<div class="packet-summary" id="packet-summary" aria-live="polite"></div>
|
| 113 |
+
<div class="trajectory" id="trajectory" aria-live="polite"></div>
|
| 114 |
+
</section>
|
| 115 |
+
|
| 116 |
+
<section class="section isolation-section" id="isolation">
|
| 117 |
+
<div class="section-heading">
|
| 118 |
+
<div><div class="section-kicker">Evaluation boundary</div><h2>Public/private isolation by construction</h2></div>
|
| 119 |
+
<p>“Private” means evaluator-only under the benchmark protocol; the artifacts remain downloadable for transparent reproduction.</p>
|
| 120 |
+
</div>
|
| 121 |
+
<div class="isolation-grid">
|
| 122 |
+
<div class="boundary public-boundary">
|
| 123 |
+
<span class="boundary-label">ROUTER + EXECUTOR VISIBLE</span>
|
| 124 |
+
<h3>Public state</h3>
|
| 125 |
+
<ul><li>Task and public artifacts</li><li>Full role pool plus STOP</li><li>Prior observable consequences</li><li>Remaining call budget</li></ul>
|
| 126 |
+
</div>
|
| 127 |
+
<div class="boundary-flow" aria-hidden="true"><span>route</span><b>→</b><span>execute</span><b>→</b><span>observe</span></div>
|
| 128 |
+
<div class="boundary private-boundary">
|
| 129 |
+
<span class="boundary-label">EVALUATOR ONLY</span>
|
| 130 |
+
<h3>Reference state</h3>
|
| 131 |
+
<ul><li>Gold patches and proofs</li><li>Answer workbooks and oracles</li><li>Trusted evaluator results</li><li>Track A labels</li></ul>
|
| 132 |
+
</div>
|
| 133 |
+
</div>
|
| 134 |
+
<p class="boundary-note">The evaluator runs only after termination. It does not feed private artifacts back into the trajectory.</p>
|
| 135 |
+
</section>
|
| 136 |
+
|
| 137 |
+
<section class="section submit-section" id="submit">
|
| 138 |
+
<div>
|
| 139 |
+
<div class="section-kicker">Community evaluation</div>
|
| 140 |
+
<h2>Bring your own router.</h2>
|
| 141 |
+
<p>JEV is the reference system. Submit reproducible results from another decision model under the frozen environment—without sending us your model.</p>
|
| 142 |
+
</div>
|
| 143 |
+
<div class="submit-actions">
|
| 144 |
+
<a class="button primary" href="https://github.com/BuiThiThanhTrang/RACO_MAS/issues/new?template=router-result.yml">Submit router results ↗</a>
|
| 145 |
+
<a class="button secondary" href="https://github.com/BuiThiThanhTrang/RACO_MAS/blob/main/puppeteer/CONTRIBUTING_ROUTER_RESULTS.md">Read the protocol ↗</a>
|
| 146 |
+
</div>
|
| 147 |
+
</section>
|
| 148 |
+
</main>
|
| 149 |
+
|
| 150 |
+
<footer>
|
| 151 |
+
<div><strong>RoleRouteBench</strong><span>Version 4.0.0-beta.2 · DOI 10.57967/hf/11430</span></div>
|
| 152 |
+
<div class="footer-links"><a href="https://huggingface.co/datasets/TrangBui/RoleRouteBench">Dataset</a><a href="https://github.com/BuiThiThanhTrang/RACO_MAS">Code</a><a href="https://doi.org/10.57967/hf/11430">DOI</a></div>
|
| 153 |
+
</footer>
|
| 154 |
+
<script src="app.js" defer></script>
|
| 155 |
+
</body>
|
| 156 |
</html>
|
robots.txt
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
User-agent: *
|
| 2 |
+
Allow: /
|
| 3 |
+
|
| 4 |
+
Sitemap: https://buithithanhtrang.github.io/RACO_MAS/sitemap.xml
|
sitemap.xml
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
| 2 |
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
| 3 |
+
<url>
|
| 4 |
+
<loc>https://buithithanhtrang.github.io/RACO_MAS/</loc>
|
| 5 |
+
<lastmod>2026-11-04</lastmod>
|
| 6 |
+
<changefreq>monthly</changefreq>
|
| 7 |
+
<priority>1.0</priority>
|
| 8 |
+
</url>
|
| 9 |
+
</urlset>
|
styles.css
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
:root {
|
| 2 |
+
--bg: #07101d;
|
| 3 |
+
--panel: #0d1929;
|
| 4 |
+
--panel-2: #112238;
|
| 5 |
+
--text: #edf5ff;
|
| 6 |
+
--muted: #9cb0c9;
|
| 7 |
+
--line: #233b58;
|
| 8 |
+
--cyan: #53dddb;
|
| 9 |
+
--blue: #71a7ff;
|
| 10 |
+
--green: #59d391;
|
| 11 |
+
--red: #ff7f7f;
|
| 12 |
+
--amber: #f1c76d;
|
| 13 |
+
--max: 1180px;
|
| 14 |
+
}
|
| 15 |
+
* { box-sizing: border-box; }
|
| 16 |
+
html { scroll-behavior: smooth; }
|
| 17 |
+
body { margin: 0; color: var(--text); background: var(--bg); font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; line-height: 1.55; }
|
| 18 |
+
a { color: inherit; }
|
| 19 |
+
.skip-link { position: absolute; left: -9999px; top: 1rem; z-index: 20; background: white; color: black; padding: .7rem 1rem; }
|
| 20 |
+
.skip-link:focus { left: 1rem; }
|
| 21 |
+
.site-header { position: sticky; top: 0; z-index: 10; display: flex; align-items: center; gap: 2rem; padding: 1rem max(1.25rem, calc((100vw - var(--max))/2)); border-bottom: 1px solid rgba(113,167,255,.18); background: rgba(7,16,29,.9); backdrop-filter: blur(16px); }
|
| 22 |
+
.brand { display: flex; align-items: center; gap: .75rem; text-decoration: none; font-weight: 740; letter-spacing: -.02em; }
|
| 23 |
+
.brand-mark { display: grid; place-items: center; width: 2.1rem; height: 2.1rem; border-radius: .65rem; color: #07101d; background: linear-gradient(135deg,var(--cyan),var(--blue)); font-size: .72rem; letter-spacing: .04em; }
|
| 24 |
+
nav { display: flex; gap: 1.4rem; margin-left: auto; }
|
| 25 |
+
nav a, .header-link { color: var(--muted); text-decoration: none; font-size: .9rem; }
|
| 26 |
+
nav a:hover, .header-link:hover { color: var(--text); }
|
| 27 |
+
.header-link { padding-left: 1.5rem; border-left: 1px solid var(--line); }
|
| 28 |
+
.hero { max-width: var(--max); margin: 0 auto; padding: 7rem 1.25rem 5rem; display: grid; grid-template-columns: 1.12fr .88fr; gap: 4rem; align-items: center; }
|
| 29 |
+
.hero::before { content: ""; position: absolute; inset: 4rem 0 auto; height: 34rem; pointer-events: none; background: radial-gradient(circle at 22% 40%, rgba(42,125,187,.24), transparent 34%), radial-gradient(circle at 82% 18%, rgba(83,221,219,.13), transparent 30%); }
|
| 30 |
+
.hero-copy, .route-card { position: relative; }
|
| 31 |
+
.eyebrow, .section-kicker { color: var(--cyan); text-transform: uppercase; letter-spacing: .14em; font-size: .72rem; font-weight: 760; }
|
| 32 |
+
h1 { margin: 1rem 0 1.4rem; max-width: 13ch; font-size: clamp(3rem, 6vw, 5.8rem); line-height: .97; letter-spacing: -.065em; }
|
| 33 |
+
h1 span { color: transparent; background: linear-gradient(90deg,var(--cyan),var(--blue)); background-clip: text; -webkit-background-clip: text; }
|
| 34 |
+
.hero-lede { max-width: 63ch; color: #b7c8da; font-size: 1.1rem; }
|
| 35 |
+
.hero-actions, .submit-actions { display: flex; flex-wrap: wrap; gap: .8rem; margin-top: 2rem; }
|
| 36 |
+
.button { display: inline-flex; justify-content: center; align-items: center; min-height: 2.8rem; padding: .72rem 1.05rem; border-radius: .65rem; text-decoration: none; font-weight: 700; font-size: .9rem; }
|
| 37 |
+
.button.primary { color: #06101b; background: var(--cyan); }
|
| 38 |
+
.button.primary:hover { background: #78ece9; }
|
| 39 |
+
.button.secondary { color: var(--text); border: 1px solid var(--line); background: rgba(16,31,51,.58); }
|
| 40 |
+
.button.secondary:hover { border-color: var(--blue); }
|
| 41 |
+
.route-card { padding: 1.2rem; border: 1px solid var(--line); border-radius: 1rem; background: linear-gradient(160deg,rgba(17,34,56,.98),rgba(8,20,34,.95)); box-shadow: 0 28px 80px rgba(0,0,0,.36); }
|
| 42 |
+
.route-card-head { display: flex; justify-content: space-between; padding-bottom: 1rem; border-bottom: 1px solid var(--line); color: var(--muted); font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: .72rem; }
|
| 43 |
+
.live-dot { color: var(--green); }
|
| 44 |
+
.route-step { display: grid; grid-template-columns: 2.2rem 1fr auto; align-items: center; gap: .85rem; padding: .9rem .3rem; }
|
| 45 |
+
.step-index { display: grid; place-items: center; width: 2rem; height: 2rem; border: 1px solid var(--line); border-radius: 50%; color: var(--muted); font: .72rem ui-monospace, monospace; }
|
| 46 |
+
.route-step div { display: flex; flex-direction: column; }
|
| 47 |
+
.route-step small { color: var(--muted); }
|
| 48 |
+
.status { border-radius: 999px; padding: .25rem .5rem; font: .67rem ui-monospace, monospace; }
|
| 49 |
+
.status.success { color: var(--green); background: rgba(89,211,145,.1); }
|
| 50 |
+
.status.failed { color: var(--red); background: rgba(255,127,127,.1); }
|
| 51 |
+
.route-line { width: 1px; height: .75rem; margin: -.4rem 0 -.4rem 1.28rem; background: var(--green); }
|
| 52 |
+
.route-line.warning { background: var(--red); }
|
| 53 |
+
.stats { max-width: var(--max); margin: 0 auto; padding: 0 1.25rem 5rem; display: grid; grid-template-columns: repeat(4,1fr); }
|
| 54 |
+
.stats div { padding: 1.4rem 1.6rem; border-block: 1px solid var(--line); border-right: 1px solid var(--line); }
|
| 55 |
+
.stats div:first-child { border-left: 1px solid var(--line); }
|
| 56 |
+
.stats strong { display: block; font-size: 2rem; letter-spacing: -.04em; }
|
| 57 |
+
.stats span { color: var(--muted); font-size: .84rem; }
|
| 58 |
+
.section { max-width: var(--max); margin: 0 auto; padding: 5.5rem 1.25rem; border-top: 1px solid var(--line); }
|
| 59 |
+
.why-grid { display: grid; grid-template-columns: 1.08fr .92fr; gap: 5rem; margin-top: 1rem; }
|
| 60 |
+
h2 { margin: .65rem 0 1rem; font-size: clamp(2rem,4vw,3.3rem); line-height: 1.08; letter-spacing: -.045em; }
|
| 61 |
+
.why-copy, .section-heading > p, .boundary-note { color: var(--muted); }
|
| 62 |
+
.section-heading { display: flex; align-items: end; justify-content: space-between; gap: 3rem; margin-bottom: 2rem; }
|
| 63 |
+
.section-heading > p { max-width: 48ch; }
|
| 64 |
+
.table-wrap { overflow-x: auto; border: 1px solid var(--line); border-radius: .8rem; }
|
| 65 |
+
table { width: 100%; border-collapse: collapse; min-width: 760px; background: rgba(13,25,41,.72); }
|
| 66 |
+
th, td { padding: 1rem 1.1rem; border-bottom: 1px solid var(--line); text-align: left; }
|
| 67 |
+
th { color: var(--muted); font-size: .72rem; text-transform: uppercase; letter-spacing: .08em; }
|
| 68 |
+
tbody tr:last-child td { border-bottom: 0; }
|
| 69 |
+
.filters { display: grid; grid-template-columns: 1.15fr 1.55fr 1.15fr 1fr; gap: .8rem; }
|
| 70 |
+
label { color: var(--muted); font-size: .72rem; text-transform: uppercase; letter-spacing: .08em; }
|
| 71 |
+
select { width: 100%; margin-top: .45rem; padding: .72rem .8rem; border: 1px solid var(--line); border-radius: .55rem; color: var(--text); background: var(--panel); font: inherit; text-transform: none; letter-spacing: 0; }
|
| 72 |
+
.packet-summary { margin: 1.3rem 0; padding: 1.2rem; border: 1px solid var(--line); border-radius: .75rem; background: var(--panel); }
|
| 73 |
+
.packet-summary-head { display: flex; justify-content: space-between; gap: 1rem; }
|
| 74 |
+
.packet-summary h3 { margin: 0 0 .5rem; font: 700 1rem ui-monospace, monospace; }
|
| 75 |
+
.packet-summary p { margin: .7rem 0 0; color: var(--muted); }
|
| 76 |
+
.badges { display: flex; flex-wrap: wrap; gap: .4rem; }
|
| 77 |
+
.badge { padding: .25rem .5rem; border: 1px solid var(--line); border-radius: 999px; color: var(--muted); font-size: .7rem; }
|
| 78 |
+
.trajectory { display: grid; gap: .7rem; }
|
| 79 |
+
.trajectory-step { display: grid; grid-template-columns: 3rem minmax(11rem,1.1fr) minmax(12rem,.9fr) minmax(13rem,1.2fr); gap: 1rem; align-items: center; padding: .9rem 1rem; border: 1px solid var(--line); border-radius: .7rem; background: rgba(13,25,41,.72); }
|
| 80 |
+
.trajectory-step.hidden { display: none; }
|
| 81 |
+
.step-number { color: var(--muted); font: .75rem ui-monospace, monospace; }
|
| 82 |
+
.step-role strong { display: block; }
|
| 83 |
+
.step-role small, .state-change small { color: var(--muted); }
|
| 84 |
+
.state-change code { display: block; overflow: hidden; text-overflow: ellipsis; color: var(--blue); font-size: .72rem; }
|
| 85 |
+
.choice-list { color: var(--muted); font-size: .76rem; }
|
| 86 |
+
.event-pill { display: inline-block; width: fit-content; margin-top: .35rem; padding: .18rem .45rem; border-radius: 999px; background: rgba(113,167,255,.1); color: var(--blue); font-size: .68rem; }
|
| 87 |
+
.isolation-grid { display: grid; grid-template-columns: 1fr auto 1fr; gap: 1rem; align-items: stretch; }
|
| 88 |
+
.boundary { padding: 1.6rem; border: 1px solid var(--line); border-radius: .8rem; background: var(--panel); }
|
| 89 |
+
.public-boundary { border-top: 3px solid var(--cyan); }
|
| 90 |
+
.private-boundary { border-top: 3px solid var(--amber); }
|
| 91 |
+
.boundary h3 { margin: .65rem 0; font-size: 1.55rem; }
|
| 92 |
+
.boundary-label { color: var(--muted); font: .68rem ui-monospace, monospace; letter-spacing: .08em; }
|
| 93 |
+
.boundary ul { margin: .8rem 0 0; padding-left: 1.15rem; color: var(--muted); }
|
| 94 |
+
.boundary-flow { display: flex; align-items: center; gap: .45rem; color: var(--muted); font: .68rem ui-monospace, monospace; writing-mode: vertical-rl; }
|
| 95 |
+
.boundary-note { text-align: center; }
|
| 96 |
+
.submit-section { display: flex; justify-content: space-between; align-items: center; gap: 3rem; margin-bottom: 5rem; padding: 3rem; border: 1px solid var(--line); border-radius: 1rem; background: linear-gradient(120deg,rgba(19,55,75,.78),rgba(14,29,49,.85)); }
|
| 97 |
+
.submit-section p { max-width: 60ch; color: var(--muted); }
|
| 98 |
+
footer { max-width: var(--max); margin: 0 auto; padding: 2rem 1.25rem 3rem; border-top: 1px solid var(--line); display: flex; justify-content: space-between; color: var(--muted); }
|
| 99 |
+
footer div:first-child { display: flex; flex-direction: column; }
|
| 100 |
+
.footer-links { display: flex; gap: 1rem; }
|
| 101 |
+
.error { color: var(--red); }
|
| 102 |
+
@media (max-width: 900px) {
|
| 103 |
+
nav { display: none; }
|
| 104 |
+
.header-link { margin-left: auto; }
|
| 105 |
+
.hero, .why-grid { grid-template-columns: 1fr; }
|
| 106 |
+
.hero { padding-top: 4.5rem; }
|
| 107 |
+
.stats { grid-template-columns: repeat(2,1fr); }
|
| 108 |
+
.filters { grid-template-columns: 1fr 1fr; }
|
| 109 |
+
.trajectory-step { grid-template-columns: 2.5rem 1fr; }
|
| 110 |
+
.state-change, .choice-list { grid-column: 2; }
|
| 111 |
+
.isolation-grid { grid-template-columns: 1fr; }
|
| 112 |
+
.boundary-flow { writing-mode: initial; justify-content: center; padding: .5rem; }
|
| 113 |
+
.submit-section, .section-heading { align-items: flex-start; flex-direction: column; }
|
| 114 |
+
}
|
| 115 |
+
@media (max-width: 560px) {
|
| 116 |
+
.site-header { gap: .5rem; }
|
| 117 |
+
.header-link { display: none; }
|
| 118 |
+
h1 { font-size: 3.25rem; }
|
| 119 |
+
.stats, .filters { grid-template-columns: 1fr; }
|
| 120 |
+
.stats div { border-left: 1px solid var(--line); }
|
| 121 |
+
.packet-summary-head, footer { flex-direction: column; }
|
| 122 |
+
.submit-section { padding: 2rem 1.2rem; margin-inline: 1rem; }
|
| 123 |
+
}
|