Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions apps/website/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,9 @@ one line per edge, labelled with kind, name, source lines and inference label. T
`specs/t27f/spec_graph_export.t27` and the layout from `specs/t27f/spec_graph_view.t27`, both
compiled to `t27f.wasm`; `graph.js` is only the glue (loads the wasm, feeds the bytes, emits SVG).
A spec over the graph's cap (192 nodes, 254 edges) is refused with the verdict, never truncated.
The page is in the site's own style (the tokens of `src/index.css`, not `docs/BRAND-KIT.md`). The
colour of every box and line lives in `spec_graph_view.t27` (change it there, in gHashTag/t27, then
regenerate `t27f.wasm`); the CSS in `index.html` styles the page chrome only.
`PROVENANCE.txt` in that directory records the t27 commit, the compiler, the checksums and how to
rebuild. To add a spec to the picker, copy it from t27 into `specs/` there and add an `<option>`.

Expand Down
36 changes: 26 additions & 10 deletions apps/website/public/t27f/graph/PROVENANCE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,40 @@ of its own:
Both run as t27f.wasm. graph.js (39 lines, comments included) is the whole of the hand-written
JavaScript: it loads the wasm, writes the spec's bytes in, loops over nodes and edges and emits
SVG. The one number it computes is how many characters of "kind name" fit in a box's first line
(font size x 0.6); the full text is in the box's tooltip.
(font size x 0.6, the width of the JetBrains Mono the boxes are set in); the full text is in the
box's tooltip.

Colours
Every box fill, outline, dash and line colour comes from spec_graph_view.t27 (VIEW_LABEL_FILL,
VIEW_LABEL_STROKE, VIEW_LABEL_DASH, VIEW_TEXT, VIEW_BACKDROP), changed in gHashTag/t27#10215
(closes #10213). They are the t27.ai site's own tokens (apps/website/src/index.css :root and
src/lib/explorerTheme.ts in gHashTag/trinity), not docs/BRAND-KIT.md: exact is the site
green 00FF88, derived the golden FFD700, suggested the blue 58A6FF, unknown the muted
8B9490. The dash per label stays distinct (solid, 6, 3, 2) so a label survives a colour-blind
reader. The CSS in index.html styles the page chrome only (background, fonts, header,
picker); it never recolours a box or a line.

Source
gHashTag/t27 master 290ff17df, specs/t27f/ and specs/tutorial/08_modules_and_arrays.t27
(specs/*.t27 here are byte-identical to that commit)
gHashTag/t27 master 538df0750, specs/t27f/spec_graph_view.t27 (t27#10215)
gHashTag/t27 master 290ff17df, the other specs/t27f/ files and
specs/tutorial/08_modules_and_arrays.t27
(specs/*.t27 here are byte-identical to those commits)
Compiler
t27c 0.5.2 (built from gHashTag/t27 90fc25b3b), zig 0.16.0, on the Railway lab
Built in
gHashTag/t27-mcp wasm/ (export.zig is the hand glue: byte buffers and getters, no spec
knowledge), PR gHashTag/t27-mcp#13, commit 72ecc84. wasm/BUILD there has the full recipe.
knowledge; 138 lines), glue last changed in commit 95a9de52b69867c7b43c35727c6ae90ca76523bc
(PR gHashTag/t27-mcp#13). It is built with the reel, deck, spec_graph_view,
spec_graph_export and spec_graph_outline modules. wasm/BUILD there has the full recipe.

Checksums (sha256)
t27f.wasm eaa97ac361cb2b7ebadacf0c7a33f6daaabf7b547df1f00353900dfd3e7c44e1
spec_graph_view.mjs 739118fa01cf501bdb3eab925ef9404873230a82907faf5e6e44c006e206c962
t27f.wasm 7b2a0f0caf6eafbeefa8813e9880346fb03d99b190efc396d59d4146aafa1e60
spec_graph_view.mjs 6918f5075e815f182fe854b8beab0d0202f1d1a11dbb67e556e03a4875bac9d4
generated Zig the wasm is built from, not vendored:
spec_graph_view.zig 191d55d9bb54d57017943a1903790e4661dfd237dfe507804cef3fcdfab33c19
spec_graph_view.zig 59c2c14184759efaa1c4756d31f0c0b3b037d2d4c127eeed5be8e91bb6df5bab
spec_graph_export.zig 5297308f1d54c2688801995d56db402809fc794a7dbe5f28ad119c5b3593ede7
specs/spec_graph.t27 a3dbe0ec5110c48183ebea101109598e8542bb0ffdf9e061c672162d7da03fe7
specs/spec_graph_view.t27 22579bc98aecb3c4405991eef8b5060eb4151b17b200dfbae07a75d8b1e8547a
specs/spec_graph_view.t27 662df660969b2ebccaf99129ea8d9eb41f38ded82ff34e085cf5e07b629e3089
specs/spec_graph_export.t27 ef4ee24d5debc51be4a10835947c86a0211b867dd6ca97890a15198daa744728
specs/ui_plan.t27 383fdfb78aa13f2e48172a20e9863d91aa5147b63b1685be8e3a40667243a3f1

Expand All @@ -42,5 +57,6 @@ Reproduced on the Railway lab on 2026-10-18 from these vendored specs:
-femit-bin=t27f.wasm gives t27f.wasm byte for byte.
(Generate from a directory laid out as specs/t27f/, so that the `use t27f::...` lines resolve.)

Not here yet: derived edges (calls inferred beyond what the exporter reads exactly). Every edge
on the page is exact, and the page says so.
Not here yet: derived edges. t27 has the derive pass (spec_graph_derive.t27, t27#10198), but it
is a separate module that the wasm glue does not call, and wiring it in means more hand-written
glue. Until the wasm exports it, every edge on the page is exact, and the page says so.
2 changes: 1 addition & 1 deletion apps/website/public/t27f/graph/graph.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ async function show(path, file) {
return (status.textContent = `${path}: refused, ${nm('ERR_', v).replace(/_/g, ' ')} (${why}). No graph is drawn and none is truncated.`, status.className = 'refused')
}
if (R.gx_view_verdict() !== G.VIEW_OK) return (status.textContent = `${path}: the view refuses it, verdict ${R.gx_view_verdict()}.`, status.className = 'refused')
const W = R.gx_view_width(), H = R.gx_view_height(), svg = el('svg', { viewBox: `0 0 ${W} ${H}`, width: W, height: H, 'font-family': 'system-ui,sans-serif' }, el('rect', { width: W, height: H, fill: hex(G.VIEW_BACKDROP) }))
const W = R.gx_view_width(), H = R.gx_view_height(), svg = el('svg', { viewBox: `0 0 ${W} ${H}`, width: W, height: H, 'font-family': "'JetBrains Mono',ui-monospace,monospace" }, el('rect', { width: W, height: H, fill: hex(G.VIEW_BACKDROP) }))
for (let j = 0; j < R.gx_edge_count(); j++)
svg.append(el('line', { x1: R.gx_view_edge_x1(j), y1: R.gx_view_edge_y1(j), x2: R.gx_view_edge_x2(j), y2: R.gx_view_edge_y2(j), stroke: hex(R.gx_view_edge_stroke(j)), 'stroke-width': 1.5, ...dash(R.gx_view_edge_dash(j)) },
el('title', {}, `${nm('EDGE_', R.gx_edge_kind(j))}: ${name(R.gx_edge_from(j))} -> ${name(R.gx_edge_to(j))}, line ${R.gx_edge_line(j)}`)))
Expand Down
31 changes: 30 additions & 1 deletion apps/website/public/t27f/graph/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,42 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="color-scheme" content="dark">
<meta name="theme-color" content="#000000">
<title>T27F graph view of a .t27 spec &middot; Trinity S&sup3;AI</title>
<meta name="description" content="The T27F graph view: a box per node and a line per edge of a .t27 spec, placed and coloured by specs/t27f/spec_graph_view.t27, running as WebAssembly in your browser.">
<link rel="canonical" href="https://t27.ai/t27f/graph/">
<link rel="icon" href="../../favicon.svg" type="image/svg+xml">
<style>body{margin:0;font:15px/1.5 system-ui,sans-serif;background:#fff;color:#1a1a1a}main{padding:1rem 1.25rem}h1{font-size:1.3rem;margin:0 0 .25rem}p{max-width:62rem;margin:.25rem 0 .75rem}select{font:inherit;padding:.2rem}#status{margin:.75rem 0;font-weight:600}#status.refused{color:#a02020}#graph{overflow:auto;border:1px solid #ccc}a{color:#2459a8}</style>
<link rel="preload" as="font" type="font/woff2" href="../../fonts/outfit-latin.woff2" crossorigin>
<link rel="preload" as="font" type="font/woff2" href="../../fonts/jetbrains-mono-latin.woff2" crossorigin>
<style>
/* Page chrome only: the site's own tokens (src/index.css :root, src/lib/explorerTheme.ts). The colour of every box and line comes from spec_graph_view.t27 inside the wasm, not from here. */
@font-face{font-family:'Outfit';font-style:normal;font-weight:400 800;font-display:swap;src:url(../../fonts/outfit-latin.woff2) format('woff2')}
@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:400 500;font-display:swap;src:url(../../fonts/jetbrains-mono-latin.woff2) format('woff2')}
:root{--bg:#000;--panel:#0b0d0c;--raised:#121614;--line:rgba(0,255,136,.10);--line-hi:rgba(0,255,136,.34);--text:#fff;--muted:#8b9490;--accent:#00ff88;--warn:#f0a020}
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--text);font:400 16px/1.55 'Outfit',system-ui,-apple-system,sans-serif}
code{font-family:'JetBrains Mono',ui-monospace,monospace;font-size:.92em;color:var(--accent)}
a{color:var(--accent);text-underline-offset:3px}
a:hover{color:#fff}
a:focus-visible,select:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
header{display:flex;align-items:baseline;gap:1rem;padding:.9rem 1.25rem;border-bottom:1px solid var(--line)}
header a.home{font-weight:700;letter-spacing:.08em;color:#fff;text-decoration:none}
header a.home:hover{color:var(--accent)}
header span{color:var(--muted);font-size:.85rem;letter-spacing:.14em;text-transform:uppercase}
main{max-width:100%;padding:1.5rem 1.25rem 3rem}
h1{font-size:clamp(1.4rem,4vw,2rem);font-weight:700;line-height:1.2;margin:0 0 .5rem}
p{max-width:62rem;margin:.25rem 0 1rem;color:var(--muted)}
label{display:inline-flex;align-items:center;gap:.6rem;color:var(--text)}
select{font:inherit;color:var(--text);background:var(--raised);border:1px solid var(--line-hi);border-radius:6px;padding:.4rem .6rem;max-width:100%}
#status{margin:1rem 0 .75rem;font:500 .9rem/1.5 'JetBrains Mono',ui-monospace,monospace;color:var(--accent)}
#status.refused{color:var(--warn)}
#graph{overflow:auto;background:var(--panel);border:1px solid var(--line);border-radius:8px}
#graph svg{display:block}
</style>
</head>
<body>
<header><a class="home" href="../../">t27.ai</a><span>T27F</span></header>
<main>
<h1>T27F graph view</h1>
<p>One box per node, one line per edge of a <code>.t27</code> spec. The graph is read from the spec's bytes by <code>spec_graph_export.t27</code>; the placement, size and colour of every box come from <code>spec_graph_view.t27</code>. Both run here as WebAssembly. A box shows its kind, name, inference label (exact, derived, suggested, unknown) and source lines; dashed outlines mark labels weaker than exact. A spec over the graph's cap is refused, never drawn truncated. See <a href="./PROVENANCE.txt">PROVENANCE.txt</a> for the exact sources, compiler and checksums.</p>
Expand Down
8 changes: 4 additions & 4 deletions apps/website/public/t27f/graph/spec_graph_view.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ export const VIEW_BAND_GAP = 48;
export const VIEW_LABEL_W = [220, 220, 200, 200];
export const VIEW_LABEL_H = [44, 44, 36, 36];
export const VIEW_LABEL_INDENT = [0, 0, 10, 10];
export const VIEW_LABEL_FILL = [0xDCEFE0, 0xDDE8F7, 0xFFF1D0, 0xECECEC];
export const VIEW_LABEL_STROKE = [0x1B7F3B, 0x2459A8, 0xB7791F, 0x8A8A8A];
export const VIEW_LABEL_FILL = [0x0C2A1B, 0x2B2508, 0x0E2236, 0x1A1E1C];
export const VIEW_LABEL_STROKE = [0x00FF88, 0xFFD700, 0x58A6FF, 0x8B9490];
export const VIEW_LABEL_DASH = [0, 6, 3, 2];
export const VIEW_TEXT = 0x1A1A1A;
export const VIEW_BACKDROP = 0xFFFFFF;
export const VIEW_TEXT = 0xFFFFFF;
export const VIEW_BACKDROP = 0x0B0D0C;
export const VIEW_FONT_PX = 13;
export const VIEW_LANE_STEP = 4;
export const VIEW_LANE_HALF = 8;
Expand Down
24 changes: 14 additions & 10 deletions apps/website/public/t27f/graph/specs/spec_graph_view.t27
Original file line number Diff line number Diff line change
Expand Up @@ -80,16 +80,20 @@ pub const VIEW_BAND_GAP : u32 = 48;
/// Style by inference label (exact, derived, suggested, unknown). A guess and an unknown are
/// narrower and lower than a fact and sit centred in the column (indent * 2 + width = VIEW_COL_W);
/// only EXACT is drawn solid. Dash is the dash length in pixels, 0 for a solid line.
/// Colours are the t27.ai site tokens (apps/website/src/index.css): stroke is accent green for
/// exact, golden for derived, blue for suggested, muted grey for unknown; each fill is a dark tint
/// of its stroke, so white text clears 4.5:1 on every box. The dash stays distinct per label, so
/// the label survives a colour-blind reader.
pub const VIEW_LABEL_W : [4]u32 = [220, 220, 200, 200];
pub const VIEW_LABEL_H : [4]u32 = [44, 44, 36, 36];
pub const VIEW_LABEL_INDENT : [4]u32 = [0, 0, 10, 10];
pub const VIEW_LABEL_FILL : [4]u32 = [0xDCEFE0, 0xDDE8F7, 0xFFF1D0, 0xECECEC];
pub const VIEW_LABEL_STROKE : [4]u32 = [0x1B7F3B, 0x2459A8, 0xB7791F, 0x8A8A8A];
pub const VIEW_LABEL_FILL : [4]u32 = [0x0C2A1B, 0x2B2508, 0x0E2236, 0x1A1E1C];
pub const VIEW_LABEL_STROKE : [4]u32 = [0x00FF88, 0xFFD700, 0x58A6FF, 0x8B9490];
pub const VIEW_LABEL_DASH : [4]u32 = [0, 6, 3, 2];

/// Text and page colours, and the text size a host uses inside a box.
pub const VIEW_TEXT : u32 = 0x1A1A1A;
pub const VIEW_BACKDROP : u32 = 0xFFFFFF;
pub const VIEW_TEXT : u32 = 0xFFFFFF;
pub const VIEW_BACKDROP : u32 = 0x0B0D0C;
pub const VIEW_FONT_PX : u32 = 13;

/// Two edges between the same pair of nodes (uses and data_flow, calls and tested_by) would lie on
Expand Down Expand Up @@ -589,7 +593,7 @@ test label_sets_size_colour_and_order {
assert view_node_y(s, 15) == 40;
assert view_node_w(s, 15) == 200;
assert view_node_h(s, 15) == 36;
assert view_node_fill(s, 15) == 0xFFF1D0;
assert view_node_fill(s, 15) == 0x0E2236;
assert view_node_dash(s, 15) == 3;
assert view_overlap_count(s) == 0;
// its edge is a guess too, and points at line 67
Expand All @@ -605,7 +609,7 @@ test label_sets_size_colour_and_order {
assert view_verdict(d) == VIEW_OK;
assert view_node_y(d, 5) == 296;
assert view_node_y(d, 6) == 168;
assert view_node_fill(d, 5) == 0xDDE8F7;
assert view_node_fill(d, 5) == 0x2B2508;
assert view_node_dash(d, 5) == 6;
// the name moves nothing: the layout reads kind, label and node number only
var r : SpecGraph = tutorial_08_graph();
Expand All @@ -620,7 +624,7 @@ test unknown_node_is_drawn_alone {
assert view_node_x(g, 14) == 1610;
assert view_band_top(g) == 408;
assert view_node_y(g, 14) == 408;
assert view_node_fill(g, 14) == 0xECECEC;
assert view_node_fill(g, 14) == 0x1A1E1C;
assert view_node_widget(g, 14) == WIDGET_TEXT_BLOCK;
assert view_alone_below(g, 14);
// no edge end lands on it, while power_of_two (node 8) takes four
Expand Down Expand Up @@ -735,8 +739,8 @@ test host_entry_points_match_the_layout {
assert fx_node_line_start(0, 8) == 66;
assert fx_node_line_end(0, 8) == 68;
assert fx_node_widget(0, 8) == WIDGET_FORMULA_VIEW;
assert fx_node_fill(1, 15) == 0xFFF1D0;
assert fx_node_stroke(0, 0) == 0x1B7F3B;
assert fx_node_fill(1, 15) == 0x0E2236;
assert fx_node_stroke(0, 0) == 0x00FF88;
assert fx_node_dash(0, 0) == 0;
assert fx_node_w(0, 14) == 200;
assert fx_node_h(0, 0) == 44;
Expand All @@ -747,7 +751,7 @@ test host_entry_points_match_the_layout {
assert fx_edge_y1(0, 0) == 58;
assert fx_edge_x2(0, 0) == 300;
assert fx_edge_y2(1, 16) == 66;
assert fx_edge_stroke(0, 12) == 0x2459A8;
assert fx_edge_stroke(0, 12) == 0xFFD700;
assert fx_edge_dash(1, 16) == 3;
// past the graph, a host gets 0, not a neighbour's numbers
assert fx_node_x(0, 15) == 0;
Expand Down
Binary file modified apps/website/public/t27f/graph/t27f.wasm
Binary file not shown.
Loading