brand: adopt the Oxagen house system — palette, marks, and the face - #6473
Merged
Merged
Conversation
Stella and Oxagen shipped two palettes and a reader crossing between the two sites watched the brand change hue. The house system (macanderson/oxagen-house-brand) is generated for both brands from one source and cuts both wordmarks out of one typeface; this is that table in this repo's token schema, with the guards updated to hold it. The change is structural, not two anchors. v5.0 was cool-dark and warm-light -- a blue-tipped ground, two cool silvers, a warm paper ramp, three neutral clamps. The house system is warm on ONE axis end to end, which is what lets a single gold read as metal against both the ink and the paper, so the three collapse into one warm-neutral clamp. The clamps got stronger, not looser, in the places that mattered: - The gold's green ratio moves 78 -> 70. The honest account is that 78 was never measured: it was the ratio v5.0's gold happened to sit at. 70 has an argument -- sRGB hue 30 deg is the orange the clause excludes, and g >= 0.70 r sits six degrees clear of it. - gold-shade is new, and is what the ratio was doing badly. gold-ink is a dark shade of the gold; darkening compresses channels unevenly, so a ratio measures that instead of hue, and holding a shade to a ratio is what drags the ratio down. It is anchored now, like the lift. - The lift tolerance moves 3 -> 4 deg, the figure the JSON already argued for. It was written as 3 while the only lift on file sat at 2.9. The 30 deg hue-separation law forced one more move, and it is the law working rather than an exception to it: the identity moved 16 deg toward the warning, so the warning moved away. amber, amber-ink and red-ink are re-cut at the hues that maximise their smallest gap. There is about two degrees of room in the whole arc. paper-text is folded into text -- the house system has one off-white, so the second name was dead. ink and paper-ground now declare shares_value_with, so a deliberate repeat is a statement a reader can disagree with while an accidental one still fails. check-tokens, check-hue-separation, check-contrast, check-css-vars: pass cargo test -p stella-tui-theme: 21 passed
Stella's mark is the ASTERISK, and it already lives inside the word: stella*, cut from Space Grotesk at the kit's logo weight with the asterisk in gold. That combined form IS the lockup and it is the only one, so nothing is set to the left of the word any more -- the nav, the OG card and the docs header all show the wordmark alone. The comet goes with it: the four-point star, its three trails, and the typing lockup that assembled them. So does its generator. docs/brand/ was Stella's own kit (build_marks.py drawing through cometkit.py, sync_site.py copying into the site, build_social.py composing banners, plus the spinner and wallpaper builders); it is now a vendored mirror of the house kit, written by scripts/sync-brand-assets.mjs. The mirror is kept rather than deleted because brand-parity.test.ts runs in CI, where the house kit is not checked out. The kit lands in docs/brand/ offline and the site is held to that copy, which is the guarantee that caught the site sitting a whole brand version behind. - scripts/sync-brand-assets.mjs replaces mirror-brand-icons.py and sync_site.py. It also generates brand-marks.generated.ts, so the React marks are the kit's own path data rather than a hand-copied string, and extracts the shimmer's timing from the kit's spinner so the landing page's motion and the kit's are one animation. - MARK_PATH_FLAT is the asterisk with its placing transform solved into the coordinates, for Satori, which has no group transform. The OG card's corner sweeps were re-solved for it: the house mark centres on (48,48) where the comet's star centred on (64,48), so the old numbers would have slid both sweeps ~850px off frame. - Space Grotesk becomes the brand face. JetBrains Mono stays for code and terminal transcripts only, where column alignment is load-bearing. It used to be both faces on the argument that a terminal product should speak in monospace end to end; the house system settles that the other way, and the split now falls where the kit puts it. - #10100f and #f2eee5 leave the parity test's retired list -- they are the house ink and off-white, live again. v5.0's own anchors join it. website tsc: clean · next build: clean brand-parity.test.ts: 9 passed check-tokens, check-hue-separation, check-contrast, check-css-vars: pass
Contributor
There was a problem hiding this comment.
Sorry @macanderson, your pull request is larger than the review limit of 150,000 diff characters
Contributor
|
SCR-003 DoD check waived by the |
make brand-check runs the sync in --check mode. The kit is a separate repository and CI checks out this one alone, so --check now SKIPS when it is absent instead of exiting 2 — a gate that fails on every machine without a second clone is a gate people learn to ignore. It skips loudly: the line names what was not verified. Little is lost by that. brand-parity.test.ts still holds the site to docs/brand/ on every run, offline, and that is the check that has actually caught this repo shipping a stale brand. This one adds the outer link -- that docs/brand/ is still the kit.
Three CI guards were reading the world as it was before the house system. - check-light-clamp.py resolved every light role to the 'warm-paper' family, which no longer exists: the three neutral clamps collapsed into warm-neutral. Repointed, and the ratchet retightens on 34 entries -- the light surfaces now clear clamps they used to sit outside, which is the change improving them rather than a bound being loosened. - docs-guards ran docs/brand/social/build_social.py --check, holding a banner's install line to README.md. The banners are no longer composed here; they are the kit's, vendored. The claim to check moved with them, so the step now runs the brand sync in --check mode. - One comment cited an issue number where the prose guard wants the fact. make light-clamp-update: 34 entries retightened check-light-clamp: 6 judged, none off its declared clamp
Four guards were reading the world as it stood before the house system. - check-light-clamp.py resolved every light role to the "warm-paper" family, which the three-into-one collapse removed. Repointed, and the ratchet retightens on 34 entries: the light surfaces clear clamps they used to sit outside. - docs-guards ran a builder for social art this repo no longer composes. The step now runs the brand sync in --check mode, which is the claim that replaced it: every vendored file still matches what the kit emits. - check-prose.py read #10100F as issue number 10100. The rule matched a hash and two digits, and the palette before this one hid the flaw: its ground broke after one digit, so the rule looked exact while resting on how one colour was spelled. The house ramp spells six stops digit-first and the rule started reporting the canvas as a ticket. Length separates them exactly -- every colour here is a six-digit hex, an issue number is two to five digits and then something that is not a hex digit -- so the two exemptions are #RRGGBB and #RRGGBBAA and nothing else. #629 is still a hit, which is right. The guard's own 92 self-tests still pass. - test-contrast.sh measured its fixtures against the cool ground. The repaint values were cool greys too, which the warm palette they now test cannot contain; re-cut warm at the same lightnesses, same cases. Reading the retired-value list from the palette's own ban list rather than restating it found stale art nobody had looked at: vision.html and investor-deck.html each carried the v4.0 comet on Obsidian as an inline data-URI favicon. Both now carry the house mark. The rest is prose. The vocabulary, reading-grade and header-length gates all hold this branch to the same bar as the tree, and the writing here was over it -- too much "used to", sentences too long, one header too big. cargo test -p stella-tui-theme: 21 passed brand-parity.test.ts: 9 passed · website tsc: clean check-tokens, hue-separation, contrast, css-vars, light-clamp, doc-links, gate-parity, brand-sync: pass test-contrast, test-prose-guard, test-tokens self-tests: pass
every_gray_token_is_neutral_or_blue_tipped and both_silvers_stay_cool are deleted, folded into every_neutral_token_is_warm_or_neutral. They existed because v5.0 had three neutral families: a blue-tipped dark ramp, and two silvers sitting off neutral that carried a weaker predicate of their own. The house system has one family, so one test walks every token carrying Clamp::WarmNeutral and fails if none do. Neither predicate they asserted still exists. scripts/check-prose.py sat three lines under the 1500-line ceiling, and the hex exemption pushed it over. The comment is cut to two lines and the pattern to two, which lands the file at exactly 1500. The rule and its 92 self-tests are unchanged. check-file-size: pass check-prose: pass, 92 guard self-tests pass
design_token_parity caught two drifts a hex sweep cannot see, both in surfaces the palette change had already reached everywhere else. The washes are written in decimal. rgba(224, 104, 122, .12) is the old red, rgba(231, 141, 84, ...) the old amber, rgba(150, 33, 60, ...) the old red ink -- nine of them across the Observatory's index.html and the transcript stylesheet, each a colour re-typed by channel rather than derived from its token, which is exactly why they outlive the recolours that should carry them. Re-cut against the verdict hues the 30 deg separation law moved. The Observatory's palette block argues from measured angles, and every one of them moved with the identity: --bad 12.8 deg -> 11.2 identity 90.8 deg -> 74.8 warn->identity 39.1 deg -> 31.8 warn->bad 38.9 deg -> 31.8 ok->identity 63.1 deg -> 79.0 bad->identity 78.0 deg -> 63.7 warn contrast 7.85 / 7.60 / 7.10 -> 7.51 / 7.06 / 6.50 The block now also states the reason the warning sits where it does: the house gold is 16 deg nearer --bad than the gold before it, so the arc between them is 63.7 deg wide and holds about two degrees of room for a warning 30 deg from both ends. The parity table's rows move with the prose, which is what holds the two together. cargo test -p stella-cli --test design_token_parity: 13 passed cargo test -p stella-tui-theme -p stella-observatory -p stella-transcript: pass cargo fmt --check: clean check-tokens, hue-separation, contrast, css-vars, light-clamp, prose, file-size, brand-sync: pass
The terminal's dark ramp aliases the token table, so it moved with the palette. Its PAPER ramp did not: those were hexes derived on their own, which the token JSON recorded as an open question -- the paper theme "not yet reconciled against this ramp". Half a palette warm and half cool is the one outcome neither argument permits, so this closes it. PAPER, SNOW, PAPER_RAISED, PAPER_HAIRLINE, INK_MUTED and HAIRLINE_STRONG now come from the token table. paper-ground, paper-raised, paper-row, paper-seam and ink-muted carry `rust` names to make that possible; five stops still have none, and the doc says which and why. INK_DIM and INK_EMPHASIS stay written out, because this ramp's name for the tier and the dark ramp's name for that value are different words. The neutral law inverts, and the reason is worth having in one place. It read "cool" while the accent was a lemon: a warm neutral beside that accent sits in its own family and the screen reads muddy on a cheap panel. The house gold is a deeper metal and the kit answers the same question the other way -- one warm axis end to end, which is what lets a single gold read as metal against both the ink and the paper. Ten RETIRED_WARM_* bans come off the list with it. The v2.0 warm ground, void, surface, raised, hairline, three text tiers, paper and snow are live again; a value leaves that list when a later kit restores it, and ten did at once. The neutral test needed a better instrument. A channel span cannot answer "does this have a hue" across a ramp from near-black to near-white -- the hairline on ink spends 7 levels of 41 and the seam on paper spends 27 of 216, and both are the same grey, so a span admitting one reads the other as a colour. oklch::chroma is lightness-independent and answers it: every neutral here sits at or under 0.026 and every chromatic one at or above 0.090. The visible-cast checks keep absolute spans, which is the right instrument for a different question. Every stated angle in palette.rs moved with the identity, and the parity table's rows moved with the prose: the brand hue 90.8 -> 74.8, warning 51.7 -> 43.0, danger 12.8 -> 11.2, and each separation and contrast figure they argue from. cargo test -p stella-tui --lib: 1524 passed cargo test -p stella-cli --test design_token_parity: 13 passed cargo fmt --check: clean check-tokens, hue-separation, contrast, css-vars, light-clamp, prose, file-size, brand-sync: pass
test-light-clamp's W2 case asserts the count --update reports, and the count moved when the ratchet retightened: the house system's light surfaces clear clamps the previous ones sat outside, so seven entries left the ledger. scripts/test-light-clamp.sh: 19 passed test-contrast, test-prose-guard, test-tokens: pass
Promoting paper-ground, paper-raised, paper-row, paper-seam and ink-muted to rust names put them in token::ALL, and every token there owes SPEC 3.5 a row saying what it becomes at sixteen colours. Without one, they reach a sixteen-colour terminal as truecolor through the match's catch-all. The paper ramp collapses hardest of all: at sixteen colours a paper ground IS white, and there is no lighter tier to tell a canvas from a panel, so the four light surfaces go to bright white together and the two seams take the one gray left. ink_muted is text on that white and goes to black with ink. cargo test -p stella-tui --test spec_palette: 5 passed cargo test -p stella-tui -p stella-tui-theme: all pass cargo fmt --check: clean every colour, doc, prose and size guard: pass
clippy -D warnings caught the arm as unreachable. Under the house system one off-white serves as the light page and as the ink on the dark canvas, so token::PAPER_GROUND and token::TEXT hold the same value and the earlier arm already matches it. Both land on white, which is what SPEC 3.5 says for each. Same shape as INK, which is BG. clippy --workspace --all-targets -D warnings: clean stella-tui + stella-tui-theme suites: pass design_token_parity: 13 passed cargo fmt --check: clean check-prose, check-file-size: pass
macanderson
added a commit
that referenced
this pull request
Sep 12, 2026
… Oxagen (#6509) docs(readme): fix the broken logo and state where Stella sits next to Oxagen The README header pointed at docs/brand/logo/svg/lockup-color-light.svg, which #6473 (the house-system adoption) deleted along with the rest of the comet kit, so GitHub rendered a broken image above the badges. It now uses the vendored stella-wordmark-{dark,light}.svg pair behind prefers-color-scheme sources, with the light file as the fallback. The copy is brought onto the same position the site and the Oxagen repo already state: - The tagline is the site's h1 ("a terminal coding agent that proves its work finished") in place of "Reference Grade Agent Loop". - A short "Stella and Oxagen" section states the split from ADR-043 and ADR-053 on the Oxagen side: Stella runs the agent, Oxagen governs the run; Stella is the coding agent and the CGP/trace reference implementation, Oxagen is the governance plane with no agent loop; the two meet at the opt-in evidence drain and at stella-serve, which Oxagen's in-app assistant runs on. It also names the shared house brand and the stella* mark. - The workspace-layout paragraph that called crates/stella-tui/src/palette.rs the hand-maintained palette mirrored by tokens.css is replaced with what is true since v5.0 and #6473: design/tokens/stella-tokens.json is normative, gen-tokens.py emits the terminal tokens and the CSS, and sync-brand-assets.mjs vendors the marks from the house kit. Verified: check-doc-links, check-invariants, check-command-docs, check-brand-case, check-line-citations, check-rendering-facts and make tokens all pass; every relative link and image path in the README resolves. ## Summary by Sourcery Update the README to restore the logo, accurately position Stella alongside Oxagen, and document the current branding workflow. Bug Fixes: - Fix the README logo rendering by using the vendored dark and light Stella wordmarks with a light-theme fallback. Enhancements: - Clarify Stella’s relationship with Oxagen, including their distinct responsibilities, integration points, and shared branding. - Update the workspace documentation to describe the normative token source and generated brand assets accurately. Documentation: - Refresh the README tagline, privacy wording, product positioning, and workspace layout guidance.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Brings Stella onto the Oxagen house brand system
(
macanderson/oxagen-house-brand), so the two products stop shipping twoidentities. Paired with macanderson/oxagen#2785, which does the same on
the Oxagen side.
The two repos had diverged into two golds, two grounds and two typefaces,
and a reader crossing between the sites watched the brand change hue —
the exact failure
docs/brand/'s own README has recorded three times.The house kit is generated for both brands from one source and cuts
both wordmarks out of one typeface, which is what ends it.
Stella's lockup is
stella*. Its mark is the asterisk and it alreadylives inside the word, so that combined form is the whole lockup and
nothing is ever set to its left. The comet — the four-point star with
three trails — is retired, along with
cometkit.pyand the typinganimation built around it.
The palette: v6.0, and why the clamps moved
design/tokens/stella-tokens.jsonadopts the house table. This is asupersession, not a tune: v5.0 was cool-dark and warm-light (a blue-tipped
ground, two cool silvers, a warm paper ramp, three neutral clamps) and the
house system is warm on one axis end to end, which is what lets a
single gold read as metal against both the ink and the paper. The three
neutral clamps collapse into one
warm-neutral.The gold clamp got stronger where it mattered, not weaker:
measured — it was the ratio v5.0's own gold happened to sit at. 70 has
an argument: sRGB hue 30° is the orange the clause excludes, and
g >= 0.70 rsits six degrees clear of it.gold-shadeis new, and is what the ratio was doing badly.gold-inkisa dark shade of the gold; darkening compresses channels unevenly, so a
ratio measures that rather than hue — and holding a shade to a ratio is
what drags the ratio down. It is anchored to the gold now, like the lift.
and had written as 3 only because the one lift on file sat at 2.9.
The 30° hue-separation law forced one more move. The identity shifted
16° toward the warning, so the warning moved away from it:
amber,amber-inkandred-inkare re-cut at the hues that maximise theirsmallest gap. There is about two degrees of room in the whole arc. That is
the law working, not an exception to it — a state colour exists to be
unlike the identity.
crates/stella-tui-themeis regenerated from the same JSON, so theterminal re-tints with the site.
The site
scripts/sync-brand-assets.mjs, whichreplaces
mirror-brand-icons.pyandsync_site.py.docs/brand/stopsbeing Stella's own kit and becomes a vendored mirror of the house one —
kept, not deleted, because
brand-parity.test.tsruns in CI where thehouse kit is not checked out.
(it is what the wordmark is cut from), JetBrains Mono stays for code and
terminal transcripts only, where column alignment is load-bearing. It
used to be both faces.
own spinner, so the landing page and every other surface the kit renders
run one animation.
#10100fand#f2eee5leave the parity test's retired list — they arethe house ink and off-white, live again. v5.0's anchors join it.
Verification
check-tokens,check-hue-separation,check-contrast,check-css-vars— all pass
cargo test -p stella-tui-theme— 21 passedbrand-parity.test.ts— 9 passednode scripts/sync-brand-assets.mjs --check— matches house kit 2.1.0website:tsc --noEmitclean,next buildcleanverifications/directory.Deleted tests
Two tests are gone, folded into one that covers both:
every_gray_token_is_neutral_or_blue_tippedboth_silvers_stay_coolThey existed because v5.0 had three neutral families — a blue-tipped dark
ramp and two cool silvers held to a weaker predicate of their own. The house
system has one family, so both are now
every_neutral_token_is_warm_or_neutral, which walks every token carryingClamp::WarmNeutraland asserts it fails if none do. Nothing lost coverage;the two predicates they tested no longer exist.