A mark, a voice, and an address — the flame becomes the brand, Thoughts goes live on LFM, and learnstart.vc gets a canonical URL
Four things landed in one day and none of them had a changelog until now. The flame stopped being a favicon and became the logo — one Python geometry module emitting both, so the tab icon and the header mark can never drift. The Thoughts stream shipped on @lossless-group/lfm with a Sveltia surface so Don can publish without ever seeing git. 62 portfolio companies got one asset convention. And the site finally got an address — plus a DNS zone that had to be snapshotted before anyone dared touch it.
Why Care?
The 2026-08-03 rebuild put a site on the internet. This is the day it became a brand — with a mark of its own, a place to say things, and an address that resolves.
Written retroactively: all four shipped on 2026-08-04 across five commits, and none of them got an entry at the time. The gap surfaced while writing up the OG share cards, which are built directly on the flame this day produced.
The flame becomes the brand
The flames were promoted to the favicon, and then the header still showed
SparkMark — a radial burst. A tab icon and a header logo of different shapes
reads as a mistake rather than a choice, so FlameMark now renders in the header
on the homepage, the team page, and the portfolio page.
The part worth stealing is how the mark is produced. scripts/lib/flame-geometry.py
generates eleven tapering tongues from a fixed seed (15). build-flame-assets.py
emits that geometry to the public SVGs and to FlameMark.astro; build-favicon-ico.py
bakes the .ico. One geometry module, three outputs — the browser-tab icon and the
in-page logo are the same curve data by construction, not by somebody remembering to
update both.
FlameMark renders inline rather than as an <img>, which is why it can
inherit --grad-from/--grad-to and the vibrant-mode glow. The static SVGs
hardcode their gradient and can't. That single decision is what later made the OG
share cards possible — they compose the same component and inherit the same tokens.
SparkMark is deliberately left in place, unreferenced. The radial spark is still
what context-v/narratives/LearnStart-Site-Narrative.md and the spec call the brand
mark, so the documents and the code now disagree. That's a known debt, not an
oversight — the narrative needs a pass before the component is deleted.
Thoughts — a stream system that configures itself
@lossless-group/lfm 0.3.0 (from JSR) now renders LearnStart's markdown, so the
site speaks the house flavor — GFM tables, Obsidian callouts, directives, hex-code
citations — exactly like every other Astro Knots site.
Streams are self-organising. An entry declares publish_to_streams: and the
/streams page builds its tabs from the union of every value it sees. A new stream
exists the moment someone types its name; there is nothing to configure and nothing
to deploy. An entry can live in several at once — the first piece, Why we back the
earliest stage, sits in both Venture-Notes and Founder-Letters.
The loader is lenient by mandate: it never throws. Bad YAML, a missing stream, a malformed date, an unparseable body — each is logged and the entry is skipped or degraded. That rule matters more here than elsewhere, because a non-technical editor publishes into this directory and a stray colon in a title must not take the site down.
Publishing without git
A Sveltia CMS surface at /admin means Don Burton signs in with GitHub once, edits
in forms, and saving commits markdown to this repo. Vercel redeploys and the piece
is live in about a minute. He never sees a branch or a merge conflict.
Content stays as plain markdown in src/content/streams/, so the CMS is an editor,
not a storage layer — delete public/admin/ and everything still builds. Worth
knowing before extending it: Sveltia is not Decap, and custom media-library plugins
are a no-op. We use native internal (git) media, which sidesteps the problem.
62 portfolio companies, one asset convention
Portfolio brand assets were reorganised into one shape: public/portco-assets/<Company>/
holding favicon__, appIcon__, and (where we have them) trademark__<Company>--Light.svg
and --Dark.svg. 62 company directories; 13 of them carry a real trademark (25 files
across light and dark variants).
The marquee on the homepage renders only companies with a genuine trademark asset, and grows as more are approved and wired. The rest stay off it rather than rendering as text beside real logos — a half-filled marquee of real marks reads better than a full one of placeholders.
The address, and a DNS zone nobody could reach
astro.config.mjs gained site: 'https://learnstart.vc' (plus base and
trailingSlash), which is what makes canonical URLs, sitemap entries, and absolute OG
image URLs resolve. No vercel.json — no sibling site carries one, so Vercel's Astro
auto-detection stays the fleet convention.
The domain was the hard part. learnstart.vc was served by Cloudflare through an
account nobody could get into, and the zone carried live Google Workspace email
(MX, SPF, DKIM, DMARC) sitting alongside dead records from the deleted Heroku site.
So the zone was snapshotted verbatim into
context-v/issues/LearnStart-VC-DNS-Stranded-In-Cloudflare.md before anything moved.
That snapshot earned its keep within hours. The cutover to Vercel DNS stood up a fresh,
empty zone — and every mail record vanished at once, breaking inbound mail to
@learnstart.vc. The DKIM key had already expired out of every public resolver cache;
the committed snapshot was the only surviving copy. All eight mail records were restored
from it on 2026-08-05. Snapshot first, cut over second is now the rule, and this file
is the receipt.
Also Included
"Thoughts" was added to the nav on every page. Two implementation notes worth keeping:
the streams loader uses import.meta.glob rather than fs.readdir, because during
astro build the module executes from dist/.prerender/ and any path resolved from
import.meta.url points at a directory that doesn't exist there. And js-yaml v5 is
ESM with named exports only — the default import that worked in v4 fails at prerender
time.
