<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<meta
http-equiv="Content-Security-Policy"
content="default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; base-uri 'none'; form-action 'none'"
/>
<title>Pipecircuit ยท Source map</title>
<style>
:root {
color-scheme: dark;
font-family:
system-ui,
-apple-system,
sans-serif;
background: #10151e;
color: #e7edf5;
--muted: #a5b4c8;
--line: #334258;
--mint: #7ce0c2;
--blue: #9cbcff;
--red: #ffadb0;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
}
button,
input,
select {
font: inherit;
}
button,
select,
input {
color: inherit;
background: #1a2331;
border: 1px solid var(--line);
border-radius: 7px;
padding: 0.6rem 0.8rem;
}
button {
cursor: pointer;
}
button:hover {
border-color: var(--mint);
}
:focus-visible {
outline: 3px solid var(--mint);
outline-offset: 3px;
}
header {
padding: 1.7rem 2rem 1.1rem;
border-bottom: 1px solid var(--line);
}
.eyebrow {
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 0.17em;
color: var(--mint);
font-weight: 750;
}
h1 {
font-size: 1.8rem;
margin: 0.5rem 0;
}
.muted,
small {
color: var(--muted);
}
p {
line-height: 1.6;
}
header p {
margin: 0.35rem 0;
}
.path {
font:
0.8rem/1.5 ui-monospace,
monospace;
overflow-wrap: anywhere;
color: var(--muted);
}
.status {
display: inline-block;
border-radius: 20px;
padding: 0.3rem 0.65rem;
background: #193a33;
color: var(--mint);
font-weight: 650;
font-size: 0.85rem;
}
.status.bad {
color: var(--red);
background: #43262f;
}
.toolbar {
display: flex;
flex-wrap: wrap;
align-items: end;
gap: 1rem;
padding: 1rem 2rem;
background: #151d29;
}
.toolbar label {
display: grid;
gap: 0.3rem;
font-size: 0.8rem;
color: var(--muted);
}
input {
min-width: 230px;
}
main {
display: grid;
grid-template-columns: minmax(0, 1fr) 370px;
min-height: 65vh;
}
.map-area {
padding: 1.5rem 2rem;
min-width: 0;
}
.legend {
font-size: 0.8rem;
color: var(--muted);
margin: 0 0 1.2rem;
}
.legend b {
color: var(--mint);
}
#map {
position: relative;
isolation: isolate;
min-height: 200px;
}
#groups {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 1.2rem;
align-items: start;
}
section.group {
border: 1px solid var(--line);
border-radius: 12px;
background: #141c28;
padding: 1rem;
}
.group h2 {
font-size: 1rem;
margin: 0 0 0.15rem;
}
.group small {
display: block;
font-size: 0.72rem;
margin-bottom: 1rem;
}
.node {
position: relative;
z-index: 2;
display: block;
text-align: left;
width: 100%;
margin: 0.6rem 0 0;
background: #1a2433;
transition:
border-color 0.15s,
opacity 0.15s;
}
.node .name {
display: block;
font-size: 0.86rem;
font-weight: 650;
overflow-wrap: anywhere;
margin: 0.35rem 0;
}
.node .path {
display: block;
font-size: 0.7rem;
}
.role {
font-size: 0.65rem;
text-transform: uppercase;
letter-spacing: 0.07em;
font-weight: 700;
color: var(--blue);
}
.node[data-role="core"] .role,
.node[data-role="pipes"] .role,
.node[data-role="switchboard"] .role {
color: var(--mint);
}
.node[aria-pressed="true"] {
border: 2px solid var(--mint);
background: #173c38;
}
.node.dependency {
border-color: var(--blue);
}
.node.dependent {
border-color: #d6b2ff;
}
.node.dim {
opacity: 0.55;
}
.node.has-finding:after {
content: "!";
position: absolute;
right: 0.6rem;
top: 0.45rem;
color: var(--red);
font-weight: 900;
}
#edges {
position: absolute;
inset: 0;
z-index: 1;
pointer-events: none;
overflow: visible;
}
aside {
padding: 1.5rem;
border-left: 1px solid var(--line);
background: #151d29;
min-width: 0;
}
#detail {
position: sticky;
top: 1.5rem;
}
#detail h2 {
font-size: 1.2rem;
overflow-wrap: anywhere;
margin: 0 0 0.6rem;
}
#detail h3 {
font-size: 0.85rem;
margin: 1.5rem 0 0.6rem;
}
#detail p {
font-size: 0.85rem;
}
.relations {
list-style: none;
padding: 0;
margin: 0;
display: grid;
gap: 0.6rem;
}
.relations button {
width: 100%;
text-align: left;
font-size: 0.8rem;
overflow-wrap: anywhere;
}
.relations small {
display: block;
margin: 0.3rem 0;
overflow-wrap: anywhere;
}
.source {
display: block;
color: var(--blue);
margin: 0.4rem 0;
font-size: 0.8rem;
overflow-wrap: anywhere;
}
details {
margin-top: 1.5rem;
font-size: 0.8rem;
}
summary {
cursor: pointer;
color: var(--muted);
}
.finding {
border-left: 3px solid var(--red);
padding: 0.5rem 0.8rem;
background: #30232b;
margin: 1rem 0;
}
.finding p {
margin: 0.3rem 0;
font-size: 0.85rem;
}
.finding code {
font-size: 0.75rem;
}
#findings {
padding: 0 2rem;
}
#empty {
color: var(--muted);
}
footer {
border-top: 1px solid var(--line);
padding: 1rem 2rem;
font-size: 0.8rem;
color: var(--muted);
}
[hidden] {
display: none !important;
}
@media (max-width: 900px) {
main {
grid-template-columns: 1fr;
}
aside {
border-left: 0;
border-top: 1px solid var(--line);
}
#detail {
position: static;
}
.map-area,
header,
.toolbar {
padding-left: 1rem;
padding-right: 1rem;
}
}
@media (prefers-reduced-motion: reduce) {
* {
transition: none !important;
}
}
</style>
</head>
<body>
<header>
<div class="eyebrow">Pipecircuit / Architecture</div>
<h1 id="title">Source map</h1>
<p class="path" id="root"></p>
<p><span class="status" id="status"></span></p>
<p class="muted">
Find an app. Follow its pipes and switchboard into core. Select a
package to explore its dependencies.
</p>
</header>
<div class="toolbar">
<label
>Focus on an app<select id="app">
<option value="">All apps and shared code</option>
</select></label
><label
>Find a package or path<input
id="search"
type="search"
placeholder="e.g. server, pipes, authentication" /></label
><button id="reset" type="button">Reset view</button
><span class="muted" id="visible" role="status"></span>
</div>
<div id="findings"></div>
<main>
<div class="map-area">
<p class="legend">
<b>Source ownership</b> ยท Groups are apps, not threads.<br />Links
show Cargo dependencies, not messages or execution crossings.
</p>
<div id="map">
<svg id="edges" aria-hidden="true">
<defs>
<marker
id="arrow"
viewBox="0 0 10 10"
refX="9"
refY="5"
markerWidth="6"
markerHeight="6"
orient="auto-start-reverse"
>
<path d="M 0 0 L 10 5 L 0 10 z" fill="context-stroke" />
</marker>
</defs>
<g id="lines"></g>
</svg>
<div id="groups"></div>
<p id="empty" hidden>
No packages match. Try another name or reset the view.
</p>
</div>
</div>
<aside>
<div id="detail" aria-live="polite">
<h2>Where do you want to work?</h2>
<p>
Select a package to see its source location, what it uses, and what
uses it.
</p>
<p>
<strong>Pipes</strong> describe the duplex contract.<br /><strong
>Switchboard</strong
>
chooses where messages go.<br /><strong>Core</strong> owns facts and
state machines.<br /><strong>Wiring</strong> connects the physical
world.
</p>
<p class="muted">
This first view maps source structure. Runtime placement and
semantic message routes need separate evidence and are not shown
here.
</p>
</div>
</aside>
</main>
<footer>
Local snapshot ยท No server, external scripts, or network requests. Rerun
<code>pipecircuit arch visualize</code> after code changes.
<details>
<summary>What these checks establish</summary>
<ul id="limitations"></ul>
</details>
</footer>
<script id="architecture" type="application/json">
__ARCHITECTURE_DATA__
</script>
<script>
"use strict";
const report = JSON.parse(
document.getElementById("architecture").textContent,
);
const $ = (id) => document.getElementById(id);
const el = (tag, text, cls) => {
const node = document.createElement(tag);
if (text !== undefined) node.textContent = text;
if (cls) node.className = cls;
return node;
};
const normalize = (path) =>
path
.replaceAll("\\", "/")
.replace(/^\/\/\?\/UNC\//, "//")
.replace(/^\/\/\?\//, "")
.replace(/\/$/, "");
const packages = Object.values(report.packages),
byPath = new Map(packages.map((p) => [normalize(p.manifest), p]));
const fileHref = (path) => {
const normalized = normalize(path);
const encoded = normalized
.split("/")
.map((part) =>
/^[A-Za-z]:$/.test(part) ? part : encodeURIComponent(part),
)
.join("/");
return normalized.startsWith("//")
? "file:" + encoded
: "file://" + (normalized.startsWith("/") ? "" : "/") + encoded;
};
const relative = (path) =>
normalize(path).startsWith(normalize(report.root) + "/")
? normalize(path).slice(normalize(report.root).length + 1)
: path;
const localTarget = (dependency) =>
dependency.path
? byPath.get(normalize(dependency.path) + "/Cargo.toml")
: undefined;
const role = (package_) => package_.declaration?.role ?? "unclassified";
const group = (package_) =>
package_.declaration?.app ??
(role(package_) === "core"
? "Shared core"
: role(package_) === "tooling"
? "Development and build tooling"
: role(package_) === "third-party"
? "Third-party dependencies (not audited as core)"
: package_.declaration?.scope === "shared"
? "Shared contracts & wiring"
: "Unclassified");
const findingPaths = new Set(
report.findings.map((finding) => finding.manifest),
);
const buttons = new Map(),
groups = new Map(),
outgoing = new Map(),
incoming = new Map();
for (const package_ of packages) {
outgoing.set(package_.manifest, []);
incoming.set(package_.manifest, []);
}
for (const package_ of packages) {
for (const dependency of package_.dependencies) {
const target = localTarget(dependency);
if (target && dependency.kind !== "dev") {
const edge = { from: package_, to: target, dependency };
outgoing.get(package_.manifest).push(edge);
incoming.get(target.manifest).push(edge);
}
}
}
let selected = null,
queued = false;
const rootName = normalize(report.root).split("/").at(-1);
$("title").textContent = rootName + " ยท Source map";
document.title = rootName + " ยท Pipecircuit";
$("root").textContent = report.root;
$("status").textContent = report.findings.length
? report.findings.length + " architectural violations"
: packages.length + " packages ยท Architecture checks pass";
$("status").classList.toggle("bad", report.findings.length > 0);
for (const limitation of report.limitations)
$("limitations").append(el("li", limitation));
for (const finding of report.findings) {
const box = el("div", undefined, "finding");
box.append(
el("code", finding.code),
el("p", finding.subject),
el("p", relative(finding.manifest), "path"),
el("p", finding.explanation),
el("p", finding.guidance),
);
$("findings").append(box);
}
const roleOrder = [
"application",
"pipes",
"switchboard",
"wiring",
"core",
"tooling",
"third-party",
"unclassified",
];
packages.sort(
(a, b) =>
group(a).localeCompare(group(b)) ||
roleOrder.indexOf(role(a)) - roleOrder.indexOf(role(b)) ||
a.name.localeCompare(b.name),
);
for (const package_ of packages) {
const key = group(package_);
if (!groups.has(key)) {
const section = el("section", undefined, "group");
section.append(
el("h2", key),
el(
"small",
package_.declaration?.app
? "Application source"
: "Shared source",
),
);
groups.set(key, section);
$("groups").append(section);
const option = el("option", key);
option.value = key;
$("app").append(option);
}
const button = el("button", undefined, "node");
button.type = "button";
button.dataset.role = role(package_);
button.dataset.package = package_.name;
button.setAttribute("aria-pressed", "false");
button.append(
el("span", role(package_), "role"),
el("span", package_.name, "name"),
el("span", relative(package_.manifest), "path"),
);
button.classList.toggle(
"has-finding",
findingPaths.has(package_.manifest),
);
button.addEventListener("click", () => select(package_));
buttons.set(package_.manifest, button);
groups.get(key).append(button);
}
const tags = (dependency) =>
[
dependency.kind === "normal" ? null : dependency.kind,
dependency.optional ? "optional" : null,
dependency.target,
dependency.alias ? "alias: " + dependency.alias : null,
]
.filter(Boolean)
.join(" ยท ");
function relations(title, edges, direction) {
const section = el("section");
section.append(el("h3", title));
const list = el("ul", undefined, "relations");
for (const edge of edges) {
const package_ = direction === "out" ? edge.to : edge.from;
const item = el("li");
const button = el("button", package_.name);
button.type = "button";
button.addEventListener("click", () => {
if (buttons.get(package_.manifest).hidden) {
$("app").value = "";
$("search").value = "";
filter();
}
select(package_);
buttons.get(package_.manifest).scrollIntoView({ block: "nearest" });
});
item.append(button);
const condition = tags(edge.dependency);
if (condition) item.append(el("small", condition));
list.append(item);
}
if (edges.length === 0) section.append(el("p", "None.", "muted"));
else section.append(list);
return section;
}
function select(package_) {
selected = package_;
const detail = $("detail");
detail.replaceChildren(
el("h2", package_.name),
el("span", role(package_), "role"),
);
detail.append(
el("h3", "Start here"),
el("p", relative(package_.manifest), "path"),
);
const link = el("a", "Open Cargo.toml", "source");
link.href = fileHref(package_.manifest);
link.target = "_blank";
link.rel = "noopener";
detail.append(link);
const copy = el("button", "Copy manifest path");
copy.type = "button";
copy.addEventListener("click", async () => {
try {
await navigator.clipboard.writeText(package_.manifest);
copy.textContent = "Copied";
} catch {
copy.textContent =
"Copy unavailable โ select this path: ' + package_.manifest + '";
}
});
detail.append(copy);
detail.append(
relations("Uses โ", outgoing.get(package_.manifest), "out"),
relations("โ Used by", incoming.get(package_.manifest), "in"),
);
const other = package_.dependencies.filter(
(dep) => dep.kind === "dev" || !localTarget(dep),
);
if (other.length) {
const disclosure = el("details");
disclosure.append(
el(
"summary",
"External and dev dependencies (" + other.length + ")",
),
);
const list = el("ul");
for (const dependency of other) {
const item = el("li", dependency.name);
const condition = tags(dependency);
if (condition) item.append(el("small", condition));
list.append(item);
}
disclosure.append(list);
detail.append(disclosure);
}
detail.append(
el(
"p",
"Dependency direction is โuses.โ Optional and target-specific links describe possible builds, not active runtime paths.",
"muted",
),
);
const dependencies = new Set(
outgoing.get(package_.manifest).map((edge) => edge.to.manifest),
),
dependents = new Set(
incoming.get(package_.manifest).map((edge) => edge.from.manifest),
);
for (const [path, button] of buttons) {
button.setAttribute(
"aria-pressed",
String(path === package_.manifest),
);
button.classList.toggle("dependency", dependencies.has(path));
button.classList.toggle("dependent", dependents.has(path));
button.classList.toggle(
"dim",
path !== package_.manifest &&
!dependencies.has(path) &&
!dependents.has(path),
);
}
scheduleEdges();
}
function filter() {
const query = $("search").value.toLocaleLowerCase(),
app = $("app").value;
let visible = 0;
const visibleGroups = new Set();
for (const package_ of packages) {
const show =
(!app || group(package_) === app) &&
(!query ||
(
package_.name +
" " +
relative(package_.manifest) +
" " +
role(package_)
)
.toLocaleLowerCase()
.includes(query));
buttons.get(package_.manifest).hidden = !show;
if (show) {
visible++;
visibleGroups.add(group(package_));
}
}
for (const [key, section] of groups)
section.hidden = !visibleGroups.has(key);
$("visible").textContent =
visible + " / " + packages.length + " packages";
$("empty").hidden = visible !== 0;
scheduleEdges();
}
function scheduleEdges() {
if (queued) return;
queued = true;
requestAnimationFrame(() => {
queued = false;
drawEdges();
});
}
function drawEdges() {
$("lines").replaceChildren();
if (!selected || buttons.get(selected.manifest).hidden) return;
const origin = $("map").getBoundingClientRect();
const edges = [
...outgoing.get(selected.manifest),
...incoming.get(selected.manifest),
];
const seen = new Set();
for (const edge of edges) {
const key = edge.from.manifest + "\n" + edge.to.manifest;
if (seen.has(key)) continue;
seen.add(key);
const source = buttons.get(edge.from.manifest),
target = buttons.get(edge.to.manifest);
if (source.hidden || target.hidden) continue;
const a = source.getBoundingClientRect(),
b = target.getBoundingClientRect();
const sameColumn = Math.abs(b.left - a.left) < 1;
const forward = b.left > a.left;
const x1 = (forward ? a.right : a.left) - origin.left,
x2 = (sameColumn || forward ? b.left : b.right) - origin.left,
y1 = a.top + a.height / 2 - origin.top,
y2 = b.top + b.height / 2 - origin.top;
const curve = document.createElementNS(
"http://www.w3.org/2000/svg",
"path",
);
const bend = Math.max(35, Math.abs(x2 - x1) * 0.35);
curve.setAttribute(
"d",
`M ${x1} ${y1} C ${x1 + (forward ? bend : -bend)} ${y1}, ${x2 + (sameColumn || forward ? -bend : bend)} ${y2}, ${x2} ${y2}`,
);
curve.setAttribute("fill", "none");
curve.setAttribute(
"stroke",
edge.from === selected ? "#9cbcff" : "#d6b2ff",
);
curve.setAttribute("stroke-width", "2");
curve.setAttribute("opacity", ".8");
curve.setAttribute("marker-end", "url(#arrow)");
if (edge.dependency.optional || edge.dependency.target)
curve.setAttribute("stroke-dasharray", "5 4");
$("lines").append(curve);
}
}
$("search").addEventListener("input", filter);
$("app").addEventListener("change", filter);
const initialDetail = $("detail").cloneNode(true);
$("reset").addEventListener("click", () => {
$("app").value = "";
$("search").value = "";
selected = null;
$("detail").replaceChildren(
...Array.from(initialDetail.childNodes).map((n) => n.cloneNode(true)),
);
for (const button of buttons.values()) {
button.classList.remove("dim", "dependency", "dependent");
button.setAttribute("aria-pressed", "false");
}
filter();
});
new ResizeObserver(scheduleEdges).observe($("groups"));
filter();
</script>
</body>
</html>