-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrender_map.py
More file actions
313 lines (257 loc) · 14.5 KB
/
Copy pathrender_map.py
File metadata and controls
313 lines (257 loc) · 14.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
#!/usr/bin/env python3
"""Deterministic SVG renderer for the roadmap path map.
The map is data, not a drawing: edit SECTIONS / EDGES below and re-run to
regenerate assets/roadmap.svg. No external dependencies, no randomness, no
timestamps — the same input always produces byte-identical output, so the
committed SVG and this script never drift.
python scripts/render_map.py # writes assets/roadmap.svg
python scripts/render_map.py --check # exit 1 if the SVG is stale
────────────────────────────────────────────────────────────────────────────
FIVE RULES THIS FILE MUST KEEP. Breaking any of them is silent — the SVG still
renders, and the site still builds green, while the map stops working.
1. NO <g transform> ANYWHERE, AND NO GROUPS AROUND NODES.
proofstone.dev inlines this SVG and appends its own clickable <rect> per
section, in the ROOT coordinate system, copied from the section box's own
x/y/width/height. A group transform would move the drawing but not the
hotspot, so the box would render in one place and be clickable in another —
with a green build, because the hotspot was still counted.
2. A SECTION'S <rect> AND ITS "§N" <text> ARE ADJACENT.
The site joins hotspots to README sections on the "§N" label, found by
looking for a <rect> immediately followed by a <text> starting with it.
Only <title>/<desc> may sit between. Anything else and that section
silently loses its link.
3. GEOMETRY IS PLAIN NUMBERS.
x/y/width/height are read with a regex that accepts digits and a dot and
nothing else. No units, no percentages, no negatives, no var().
4. COLOUR GOES THROUGH var(<token>, <fallback>).
Inlined on the site the SVG inherits the page's theme tokens; standalone on
GitHub var() does not resolve and the baked-in literal keeps it light. One
file, both places, no second copy to drift.
5. NO EMOJI.
Flagship sections carry a drawn FLAGSHIP stamp. The ⭐ in the README stays —
it is the data the site reads to decide what is flagship.
────────────────────────────────────────────────────────────────────────────
WHY THIS MAP IS SHAPED DIFFERENTLY FROM THE OTHERS IN THE SERIES
Because this roadmap is. The previous version drew one column, §1 through §10
in a line, and that contradicted the README it illustrates. "Order and
dependencies" states the real structure, and it is a fan, not a chain:
§1 ──► §2 ──► §2.6 ──► §2.8
│ └──► §8 (start M8.1 as soon as you have §2.6)
└──► §3 (parallel to §2 — Track B can run alongside)
after §2.6, three exits BY GOAL:
databases → §7
infra/platform → §4 + §5
P2P / web3 → §6 + §9
§10 last
So §4, §5 and §6 are not steps after §3 — they are alternatives chosen by what
the job needs, and the old map drew dependency arrows between them that its own
annotation ("§4–§6: independent — pick by job") then denied. Here the three
exits are dashed, because dashed already means "optional / your choice" across
this series, and only real dependencies stay solid.
"""
from __future__ import annotations
import argparse
import sys
from pathlib import Path
# --- data -------------------------------------------------------------------
# (id, short label for the map, lane, flagship?)
# `flagship` marks a section that CONTAINS a ⭐ milestone in the README:
# §2 (M2.5, M2.6, M2.8), §4 (M4.1), §8 (M8.1) — five starred milestones across
# three sections. Labels are short on purpose: the site names each hotspot from
# the README's own section heading, so this text only has to work as a picture.
SECTIONS = [
("§1", "Foundations", "root", False),
("§2", "Consensus", "trunk", True),
("§3", "Without consensus", "para", False),
("§8", "Testing & verifying", "para", True),
("§7", "Storage", "exit-a", False),
("§4", "Membership: SWIM", "exit-b", True),
("§5", "Partitioning", "exit-b", False),
("§6", "DHT & peer-to-peer", "exit-c", False),
("§9", "Byzantine", "exit-c", False),
("§10", "Where this leads", "last", False),
]
# Real dependencies, drawn solid.
EDGES = [("§1", "§2"), ("§1", "§3"), ("§2", "§8"), ("§4", "§5"), ("§6", "§9")]
# Choices, drawn dashed: after §2.6 you pick an exit by what you are building.
CHOICES = [("§2", "§7"), ("§2", "§4"), ("§2", "§6")]
# --- layout -----------------------------------------------------------------
W = 880
H = 780
NODE_H, FLAG_H = 56, 72
TRUNK_X, TRUNK_W = 40, 290
PARA_X, PARA_W = 380, 290
LANE_W = 250
LANE_X = {"exit-a": 40, "exit-b": 320, "exit-c": 600}
EXIT_TOP = 470
POS = {
"§1": (TRUNK_X, 108, TRUNK_W, NODE_H),
"§2": (TRUNK_X, 200, TRUNK_W, FLAG_H),
"§3": (PARA_X, 108, PARA_W, NODE_H),
"§8": (PARA_X, 200, PARA_W, FLAG_H),
"§7": (LANE_X["exit-a"], EXIT_TOP, LANE_W, NODE_H),
"§4": (LANE_X["exit-b"], EXIT_TOP, LANE_W, FLAG_H),
"§5": (LANE_X["exit-b"], EXIT_TOP + 104, LANE_W, NODE_H),
"§6": (LANE_X["exit-c"], EXIT_TOP, LANE_W, NODE_H),
"§9": (LANE_X["exit-c"], EXIT_TOP + 104, LANE_W, NODE_H),
"§10": (LANE_X["exit-b"], 664, LANE_W, NODE_H),
}
PAPER = "var(--map-paper, #fcfdfe)"
NODE = "var(--map-node, #f2f5f9)"
TRUNK_FILL = "var(--map-node-spine, #e8ecf1)"
INK = "var(--map-ink, #292e35)"
LINE = "var(--map-line, #575f67)"
ACCENT = "var(--accent, #005ab8)"
GOLD = "var(--gold, #181e23)"
# A label the corridors run behind. The three dashed choices drop from §2 to the
# three lanes, and they cross the band where this map names those lanes — so a
# vertical line went through the middle of a word. It already did on the shipped
# map ("THREE EXITS"), and raising the type to the floor made it worse by widening
# the labels into a second corridor ("INFRA / PLATFORM").
#
# The fix is the cartographers' one: paint a halo of paper around the glyphs
# first, then the ink on top. The line is interrupted exactly around the
# letterforms and nowhere else. No geometry moves, nothing is measured, and it
# follows the theme because the halo IS the paper token — on the site in dark
# theme it is dark, standalone on GitHub it is the fallback.
# paint-order is one attribute; a backing <rect> would have needed the text's
# width, which this renderer has no way to know.
HALO = f'stroke="{PAPER}" stroke-width="4" paint-order="stroke fill"'
SANS = ("'IBM Plex Sans',-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,"
"Helvetica,Arial,sans-serif")
MONO = "'IBM Plex Mono',ui-monospace,SFMono-Regular,Menlo,Consolas,monospace"
def esc(s: str) -> str:
return s.replace("&", "&").replace("<", "<").replace(">", ">")
def flagship_stamp(x: float, y: float) -> str:
"""Drawn stamp in place of ⭐ (rule 5). Rotation is on the elements
themselves, never on a wrapping group (rule 1)."""
cx, cy = x + 44, y - 5
return (
f'<rect x="{x}" y="{y - 13}" width="88" height="17" rx="2" fill="none" '
f'stroke="{GOLD}" stroke-width="1.2"/>'
f'<text x="{cx}" y="{y - 1}" '
f'text-anchor="middle" class="map-plate" font-family="{MONO}" font-size="9" letter-spacing="1.5" '
f'font-weight="600" fill="{GOLD}">FLAGSHIP</text>'
)
def connector(a_id: str, b_id: str, dashed: bool) -> str:
"""Manhattan connectors only — a line follows an axis or turns a right
angle. No diagonal sticks: this is a drawing, not a graph dump."""
ax, ay, aw, ah = POS[a_id]
bx, by, bw, bh = POS[b_id]
acx, bcx = ax + aw / 2, bx + bw / 2
dash = ' stroke-dasharray="5 4"' if dashed else ""
common = (f'fill="none" stroke="{LINE}" stroke-width="1.8"{dash} '
f'marker-end="url(#arw)"')
if abs(acx - bcx) < 1: # straight down
return (f'<line x1="{acx}" y1="{ay + ah}" x2="{bcx}" y2="{by}" '
f'stroke="{LINE}" stroke-width="1.8"{dash} marker-end="url(#arw)"/>')
if abs(ay - by) < 1: # side by side, straight across
return (f'<line x1="{ax + aw}" y1="{ay + ah / 2}" x2="{bx}" y2="{by + bh / 2}" '
f'stroke="{LINE}" stroke-width="1.8"{dash} marker-end="url(#arw)"/>')
if by > ay + ah: # down, across, then down again
mid = ay + ah + (by - ay - ah) / 2
return (f'<path d="M {acx} {ay + ah} L {acx} {mid} L {bcx} {mid} '
f'L {bcx} {by}" {common}/>')
return (f'<path d="M {ax + aw} {ay + ah / 2} L {bcx} {ay + ah / 2} '
f'L {bcx} {by}" {common}/>')
def build() -> str:
p: list[str] = []
a = p.append
a(f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 {W} {H}" '
f'width="{W}" height="{H}" font-family="{SANS}" '
f'role="img" aria-label="Distributed Systems Engineer roadmap path map">')
# Filled, not none: in dark theme the map has to BE dark, or it lands as a
# light rectangle on a dark page.
a(f'<rect width="{W}" height="{H}" fill="{PAPER}"/>')
a(f'<text x="{TRUNK_X}" y="46" font-size="23" font-weight="700" fill="{INK}">'
f'Working engineer → distributed systems engineer</text>')
a(f'<text x="{TRUNK_X}" y="72" font-size="15" fill="{LINE}">'
f'Every node is a milestone with an artifact.</text>')
a(f'<defs><marker id="arw" viewBox="0 0 10 10" refX="9" refY="5" '
f'markerWidth="6" markerHeight="6" orient="auto-start-reverse">'
f'<path d="M 0 0 L 10 5 L 0 10 z" fill="{LINE}"/></marker></defs>')
# The line the three exits hang from. Not a node and not an edge: it is
# where you stand after §2.6, before choosing which way to go.
a(f'<line x1="{TRUNK_X}" y1="{EXIT_TOP - 62}" x2="{W - 40}" y2="{EXIT_TOP - 62}" '
f'stroke="{LINE}" stroke-width="1" opacity="0.45"/>')
a(f'<text x="{TRUNK_X}" y="{EXIT_TOP - 40}" font-family="{MONO}" font-size="15" '
f'letter-spacing="1.2" {HALO} fill="{LINE}">'
f'AFTER §2.6 · THREE EXITS, PICK BY GOAL</text>')
for a_id, b_id in EDGES:
a(connector(a_id, b_id, dashed=False))
for a_id, b_id in CHOICES:
a(connector(a_id, b_id, dashed=True))
# Lane labels: what each exit is FOR.
for lane, label in (("exit-a", "DATABASES"), ("exit-b", "INFRA / PLATFORM"),
("exit-c", "P2P / WEB3")):
a(f'<text x="{LANE_X[lane]}" y="{EXIT_TOP - 12}" font-family="{MONO}" '
f'font-size="15" letter-spacing="1" {HALO} fill="{ACCENT}">{label}</text>')
for sid, title, lane, flag in SECTIONS:
x, y, w, h = POS[sid]
fill = TRUNK_FILL if lane in ("root", "trunk") else NODE
a(f'<rect x="{x}" y="{y}" width="{w}" height="{h}" rx="6" '
f'fill="{fill}" stroke="{INK}" stroke-width="1.6"/>')
# RULE 2: this <text> must stay immediately after the <rect> above.
ty = (y + 32) if flag else (y + h / 2 + 5)
a(f'<text x="{x + 16}" y="{ty}" font-family="{MONO}" font-size="15" '
f'font-weight="600" fill="{ACCENT}">{esc(sid)}</text>')
a(f'<text x="{x + 58}" y="{ty}" font-size="16" font-weight="600" '
f'fill="{INK}">{esc(title)}</text>')
if flag:
a(flagship_stamp(x + w - 104, y + h - 12))
# The one fork you choose up front, stated where you choose it.
x1, y1, w1, h1 = POS["§1"]
# Offset past the trunk's centre line: the §1->§2 arrow runs down x = the
# node's midpoint, and starting this text at the left edge put the arrow
# through the middle of the sentence.
a(f'<text x="{x1 + w1 / 2 + 24}" y="{y1 + h1 + 22}" font-size="15" fill="{LINE}">'
f'fork here: Track A (Go / 6.5840) or Track B (any language / Maelstrom)</text>')
x8, y8, w8, h8 = POS["§8"]
a(f'<text x="{x8 + 16}" y="{y8 + h8 + 22}" font-size="15" fill="{LINE}">'
f'start §8.1 as soon as you have §2.6</text>')
x10, y10, w10, h10 = POS["§10"]
a(f'<text x="{x10 + w10 + 20}" y="{y10 + h10 / 2 + 4}" font-size="15" fill="{LINE}">'
f'last, whichever exit you took</text>')
# legend
ly = H - 26
a(f'<line x1="{TRUNK_X}" y1="{ly - 24}" x2="{W - 40}" y2="{ly - 24}" '
f'stroke="{LINE}" stroke-width="1" opacity="0.4"/>')
a(f'<line x1="{TRUNK_X}" y1="{ly - 4}" x2="{TRUNK_X + 26}" y2="{ly - 4}" '
f'stroke="{LINE}" stroke-width="1.8" marker-end="url(#arw)"/>')
a(f'<text x="{TRUNK_X + 36}" y="{ly}" font-size="15" fill="{LINE}">depends on</text>')
a(f'<line x1="{TRUNK_X + 150}" y1="{ly - 4}" x2="{TRUNK_X + 176}" y2="{ly - 4}" '
f'stroke="{LINE}" stroke-width="1.8" stroke-dasharray="5 4" marker-end="url(#arw)"/>')
a(f'<text x="{TRUNK_X + 186}" y="{ly}" font-size="15" fill="{LINE}">'
f'your choice, by goal</text>')
a(flagship_stamp(TRUNK_X + 380, ly + 2))
# The README's own legend, not ai-safety's: "⭐ = a public artifact worth
# putting on your résumé (there are exactly five)". The phrase "public,
# cited artifact" belongs to the AI-safety map, where the flagship is a
# citation in a public register; here it is résumé-grade, which is what
# this repository says.
a(f'<text x="{TRUNK_X + 484}" y="{ly}" font-size="15" fill="{LINE}">'
f'section with a résumé-grade public artifact</text>')
a("</svg>")
return "\n".join(p) + "\n"
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("--check", action="store_true",
help="exit 1 if committed SVG differs from freshly rendered")
args = ap.parse_args()
out = Path(__file__).resolve().parent.parent / "assets" / "roadmap.svg"
svg = build()
if args.check:
if not out.exists() or out.read_text(encoding="utf-8") != svg:
print("roadmap.svg is stale — run: python scripts/render_map.py", file=sys.stderr)
return 1
print("roadmap.svg up to date.")
return 0
out.parent.mkdir(parents=True, exist_ok=True)
# newline="\n" is explicit: on Windows the default translates every "\n" to
# "\r\n", so the file stops matching the blob and every line of the map
# shows up as changed. .gitattributes pins the same thing from git's side.
out.write_text(svg, encoding="utf-8", newline="\n")
print(f"wrote {out}")
return 0
if __name__ == "__main__":
raise SystemExit(main())