A complete, reusable design system extracted from first-party CODECAVE source —
the CodeCavePro/brand repository and the production codecave.pro codebase.
Every token, component rule, asset and font file in this package was read out of
captured source, not inferred from a screenshot or a marketing page.
Link one stylesheet and the system is live:
<link rel="stylesheet" href="colors_and_type.css">There is no build step, no package to install, no theme provider and no
component bundle. colors_and_type.css declares the tokens on :root and ships
a component class layer on top of them.
CODECAVE is a software delivery studio. The captured surface is its marketing and lead-generation site: a dark, high-contrast presentation whose entire job is to turn a visitor into one booked consultation.
Six services, and the site titles every one of them by the outcome it
produces rather than the technology it uses — read straight from
source_examples/header/menu.ts:
| Service | Outcome line, verbatim |
|---|---|
| Cloud & DevOps | Optimize costs. Protect your Data |
| E-Commerce | Maximize revenue, dominate Markets |
| Autodesk plugins | 10x efficiency with custom Plugins |
| Automation & AI | Leverage virtual Workforce |
| HubSpot | Aggregate data from all your Tools |
| AR & VR | Stunning visualisations for your business |
Production stack. Astro 7 + Vue 3 + Tailwind 4, GSAP 3.13 with ScrollTrigger,
Lenis 1.3.11 smooth scroll, vue3-carousel, Strapi as the content backend. 61
.astro files, 45 .vue components, zero React, no Storybook. The Tailwind 4
@theme block in src/styles/global.css is the authoritative token source; the
brand repository's docs/tokens/*.css publish the same ramp independently.
Conversion shape. Exactly one primary action per page — a violet glow button reading "Get a free consultation" — supported by a consultation form that asks for one required field (e-mail) and treats everything else as optional. The voice is plain, specific and non-promotional: "Scope, milestones and outcomes upfront." / "We are ready to sign an NDA — your idea stays yours."
What defines the visual system (the long version is DESIGN.md):
- Depth without contrast. The page is
#0A0A0Band a card is#0F0F15— one hair apart. Separation comes from radius and a 1px#2B2848border, never from a lighter fill. - Enormous radii. 24px is the default card corner. Feature cards take 44px; section panels reach 64px, and 120px above 768px. Nothing in the system has a small corner.
- The inverted glow. Section panels cast violet light upward — every Y
offset in
--shadow-sectionis negative. It is physically wrong and instantly recognizable, and it is the single most important thing not to normalize. - Violet is rationed.
#5F20FElives on edges, links and marks and never fills a large area. When a violet field is genuinely needed the system switches to#9980FFwith#1B0D4Etext — the only dark-on-light text anywhere in the system.
| Source | Where the evidence lives | Read method |
|---|---|---|
CodeCavePro/brand (GitHub, main) |
context/github/CodeCavePro-brand/ + files/ snapshots |
git-clone |
CodeCavePro/brand (GitHub, development) |
context/github/CodeCavePro-brand-development.md — tokens, DESIGN.md, ds-bundle/ |
git-clone |
CodeCavePro/brand working clone — the binary logo/icon/favicon trees |
context/local-code/brand/ + files/logos/, files/icons/, files/favicons/, files/build.sh |
local-folder |
codecave.pro production codebase |
context/local-code/codecave.pro/ + files/ snapshots |
local-folder |
| https://codecavepro.github.io/brand | reviewed; structural confirmation only | fetched |
| https://codecave.gay | live site, named in .design-sync/config.json as the measurement source |
measured |
| Figma design file | linked but not decoded — no snapshot captured, contributed nothing | — |
The context/ intake tree is not published in this repository. It is the
capture workspace's raw evidence — full snapshots of the codecave.pro and
brand-repo working trees — and the table above cites it so each claim stays
traceable to where it was read, not because the folder ships here. The
high-signal originals are preserved in source_examples/ instead, so the
evidence behind the rules can be read without re-running intake: 21 files — the
brand repository's token CSS in source_examples/brand-repo-tokens/, the
production global.css, and every Vue/Astro component this system documents.
tokens/ is the one derived artefact rather than a copy: colors.ts,
layout.ts and typography.ts mirror colors_and_type.css as typed modules
for consumers that cannot read a stylesheet — design tooling, canvas renderers,
PDF and email builders, native apps. The CSS remains the source of truth.
├── index.html dark front door — start here
├── DESIGN.md THE rules — canonical source of truth
├── colors_and_type.css THE deliverable: tokens + component class layer
├── brand-kit.html the brand page: lockups, palette, type scale, glow CTA
├── README.md this file — package guide and preview manifest
├── SKILL.md agent-facing entry point
├── guide.md short orientation note
├── tokens/ the same tokens as typed TS modules, for non-CSS consumers
├── brand.json machine-readable palette, type and voice summary
├── assets/ brand marks, raster lockups, UI icons, font originals
├── build/ runtime assets, original filenames, byte-for-byte
├── fonts/ 6 Satoshi cuts (woff2 + woff) + fonts.css
├── imagery/ decorative line-and-glow art, on its #050505 ground
│ └── source/ the same 8 SVGs untouched, byte-for-byte
├── source_examples/ high-signal source files, the evidence behind the rules
├── preview/ 12 focused review cards + index — layer 1, foundations
├── storybook/ 13 component stories + index — layer 2, components
│ ├── ports/ interfaces + docs-build adapters for what a
│ │ component depends on outside itself
│ └── placeholders.js local stand-ins for the CMS-hosted media the
│ captured components ask for
└── artifacts/ 6 whole surfaces + index — layer 3, compositions
The three browsable layers answer three different questions. preview/ asks
whether a token is right, storybook/ whether a component is right, and
artifacts/ whether the two compose into something a client receives.
DESIGN.md and colors_and_type.css sit underneath all three as the rules and
their machine-readable half.
build/ is the runtime asset directory. It holds the marks a packager or
runtime consumes, under their original source filenames, copied byte-for-byte
from the captured snapshots. Nothing in build/ was redrawn, re-encoded or
optimized.
imagery/source/ is the same contract for the decorative art — eight SVGs
copied byte-for-byte out of codecave.pro/src/assets/images/. The seven files
one level up in imagery/ are the presentation copies: identical artwork
with a single #050505 ground rect added, because the originals are
stroke-only on a transparent root and therefore do not render on a light
canvas. Ship from imagery/source/; review from imagery/.
| Group | Files | Source |
|---|---|---|
| Vectors | codecave-wide.svg, codecave-tall.svg, codecave.svg |
brand repo src/ |
| Site marks | logo.svg |
codecave.pro production |
| Raster lockups | logo.png, logo-tall.png, icon.png (1024²) |
brand repo logos/ |
| Icon ramp | icons/16x16.png … icons/512x512.png (7 sizes) |
brand repo icons/ |
| Web runtime | favicon.ico, favicon.svg, favicon-96x96.png, apple-touch-icon.png, web-app-manifest-192x192.png, web-app-manifest-512x512.png, site.webmanifest |
brand repo favicons/ |
The production site's own public/favicon.svg is not shipped here. As
captured, codecave.pro still serves the Astro starter's default favicon — a
stock framework glyph, not a CODECAVE mark. It is left in the evidence snapshot
(context/local-code/codecave.pro/files/public/favicon.svg) and deliberately
kept out of build/. Use build/favicon.svg, which is the real brand mark.
assets/ holds the wider brand kit: the 1024px raster lockups plus the 256px
review cuts in all four finishes, the square 256px and 1024px app marks, the
chevron and stacked vectors, the checkbox tick, and the original font uploads.
Every lockup exists in eight sizes × four finishes. The brand repo's
build.sh renders src/codecave.svg, src/codecave-wide.svg and
src/codecave-tall.svg at 96/128/256/300/350/500/600/1024 into
codecave-{wide|tall}-{size}-{text-white|text-black|all-white|all-black}.png.
text-white is the default on dark; text-black is for genuinely light
surfaces; the two all-* finishes are one-ink print. This package preserves a
representative subset — regenerate any other size from the vectors rather than
upscaling a PNG.
Fonts are real and bound. colors_and_type.css opens with six @font-face
blocks pointing at ./fonts/Satoshi-*.woff2 with .woff fallbacks. Nothing is
described in prose only.
Twelve cards, one concern each. All are static HTML — open preview/index.html
and work down, or open any card directly. Every card links
../colors_and_type.css and renders live tokens, live components and real
preserved files: there are no screenshots and no redrawn marks anywhere in the
set.
| Card | What to inspect | What it demonstrates |
|---|---|---|
preview/index.html |
Launcher. Confirm all eleven cards open and the lockup renders. | build/codecave.svg, .divider, .eyebrow |
preview/colors-primary.html |
That #5F20FE never fills a large area, and that cyan appears nowhere as a UI color. |
--color-action, --color-hovered, --color-glow-25, --gradient-brand, the 12-step brand ramp, the 13-step gray ramp, the single-use accents, the technology wash, the 4-step error ramp. Source: source_examples/styles/global.css, tokens/colors.css |
preview/colors-theme-dark.html |
Four surfaces one hair apart — check they still separate. Read the contrast ratios on the foreground ramp. | --color-surface-primary/-secondary/-tertiary/-quaternary, --color-body-*, .card in situ |
preview/colors-theme-light.html |
The three light surfaces that legitimately exist, and why no light theme may be derived from them. | gray-50 as ink vs. as a field, inverse lockup usage, error-100 rationale |
preview/typography-specimens.html |
Whether the six Satoshi cuts render distinctly. If they look identical, the @font-face binding is broken. |
fonts/Satoshi-*.woff2, the nine-step scale at true size, .eyebrow / .lead / .eyebrow-lead with a counter-example. Source: tokens/typography.css, homepage/expertise.astro |
preview/spacing-tokens.html |
The asymmetric section rhythm (200px above, 120px below) and bottom-heavy card padding. | --gutter-*, --section-padding-top/-bottom, --card-padding, --control-height, --input-height. Source: tokens/layout.css |
preview/spacing-radius.html |
Eight radii at true size, the measured homepage census, and the same card at 4px and 0px for comparison. | --radius-control → --radius-section-md, .card, live .section-container across the 768px breakpoint |
preview/spacing-shadows.html |
The space above the panel — that is where the violet has to appear. Then the conventional-shadow counter-example beside it. | --shadow-section (three negative-Y layers), --shadow-glow-button, --shadow-input-focus, --shadow-input-error |
preview/components-buttons.html |
Rest, hover, active, focus and disabled shown together; tab through the focus row. | .btn + -glow/-primary/-secondary/-tertiary/-ghost/-text/-link/:disabled, and the one sanctioned CTA pairing. Source: common/Button.vue, common/GlowButton.vue |
preview/components-inputs.html |
Click into the fields. The floating label must never collide with the value, and focus must be a halo rather than an outline. | .field, .field.is-error, .error-message, label .required, .checkbox, .chip, radios, the assembled consultation form. Source: common/InputText.vue, TextField.vue, Checkbox.vue, Radio.vue, common/forms/ContactUsForm.vue |
preview/components-progress.html |
That the bar is violet at 15% and near-white only at 100%. If early progress reads near-white, the gradient is being sized to the fill instead of the track. | .rule, .progress, .progress-value, .progress.is-indeterminate, --gradient-brand as a field, and three counter-examples: stretched full width, gradient sized to the fill, thickened to 16px. Source: the brand repository's previously published docs/index.html |
preview/brand-imagery.html |
Every plate must show visible strokes. A plate that reads as flat near-black means the #050505 ground rect is missing from that file, not that the art is subtle. |
The seven harvested section backgrounds on their required ground, the 0.8 / 0.65 / 0.55 / 0.45 opacity ladder that produces the falloff, the three gradient stops, and the two imagery-only literals recovered in the deep pass (#391398, #4C4759). Source: codecave.pro/src/assets/images/ |
preview/brand-assets.html |
Every frame must contain artwork. An empty frame means a missing file, not a styling bug. Check the 16px icon still reads as a chevron. | Real files from build/ and assets/ loaded via <img>, <object> and CSS url(...): both lockups, the chevron, all four raster finishes at 256px, the seven-step build/icons/ ramp at native size, the web runtime set (favicon.ico, apple-touch-icon.png, both PWA manifest icons), the production logo.svg, the 1024² app icon, and the six font specimens |
The launcher links onward to the two layers above these cards: storybook/index.html
and artifacts/index.html.
Thirteen components extracted from codecave.pro — twelve Vue islands and one
Astro component. Open storybook/index.html.
The stories mount the real components: tools/build-storybook.mjs
compiles each .vue source verbatim (vue/compiler-sfc + esbuild) into
storybook/compiled/, and generates storybook/tw-bridge.css — the site's
own Tailwind theme plus every utility the components use, scoped to the story
canvases with a preflight equivalent. Pages render them with the vendored Vue
and GSAP runtimes; no external network, no build step at view time. The one
.astro component cannot run in a browser, so storybook/components.css
survives only as its hand-translated port (.cc-chip). Where the storybook
deviates from production — Strapi-hosted images swapped for local
placeholders, positioning stages for absolutely-positioned cards — the gap is
written on the story page rather than silently papered over.
| Group | Components |
|---|---|
| Primitives | Button (7 variants), GlowButton, InputText, TextField, Checkbox (2×2), Radio (2 variants) |
| Content | ArticlePreview, Review, TechnologyCard, ProjectChip, TypingEffect, PainPointsItem |
| Compositions | LinkGroup |
Each story page carries the real defineProps signature, a variant/state
matrix rendered live, and a findings section. 55 findings were recorded — 30
defects and 25 design observations. The ones that change runtime behavior:
--default-transition-durationis not the project's variable.Checkbox.vue:75 andRadio.vue:61 both use it in atransitionshorthand. It appears nowhere in the project's own code — it resolves to 150ms from Tailwind's default theme, emitted becausetransition-colorsis in use. Inside a Tailwind build the indicators ease; lift either component out and the shorthand collapses and they snap.tailwind.config.tsis never loaded. Tailwind 4 is configured CSS-first via@theme; a JS config only applies when a stylesheet names it with@config, and none does.darkMode,contentandtheme.extendare inert — including the*.storiesexclusion in the content glob.Button'sisDisableddoes not disable. It sets opacity and cursor only; thedisabledattribute is never bound.Fixed upstream 2026-08-20 — the parse now runs throughPainPointsItemrenders unsanitized CMS markdown throughv-html.isomorphic-dompurify, and the specimen's third story re-checks it on every page load.TextFieldsyncs its model onchange, notinput— sov-modelupdates on blur whileInputTextin the same form updates per keystroke.
The storybook is static HTML and needs no build. It is not a Storybook
(@storybook/*) install: codecave.pro is linked read-only, so nothing was
written into that repo.
artifacts/email.html shipped its two CTAs as green buttons. The cause
is a single attribute:
<td align="center" bgcolor="var(--brand-color-primary)">bgcolor is a presentational attribute, parsed with the HTML legacy color
rules — a fixed-width algorithm that has no access to CSS at all, so it cannot
resolve a custom property. It does not fail and fall back; it substitutes 0
for every non-hex character and reads what is left as a color. For
var(--brand-color-primary) that yields #A0D000, a lime green. The
literal string is doing the choosing, not the token.
Both CTAs in email.html and both in newsletter.html are now the glow button,
written with literals end to end:
| Property | Value | Why a literal |
|---|---|---|
bgcolor / background |
#9980FF |
The one violet field in the system. |
color |
#1B0D4E |
The only dark-on-light text in the system — 5.67:1. |
border-radius |
9999px |
Pill, per the radius rules. |
box-shadow |
0 0 64px 0 #7A58FFA8, 0 0 16px 0 #4F22FFA6, 0 0 4px 2px #5B34FA |
The halo, verbatim from --shadow-glow-button. |
padding / font-size |
16px 32px / 18px |
Outlook's Word engine ignores var(); the button would collapse to zero padding. |
Never use var() inside bgcolor, and prefer literals over tokens anywhere
in an email artifact. Custom properties are unsupported in Outlook on Windows
and unreliable elsewhere; the design system's token layer stops at the inbox
boundary.
Known limits, not defects: Outlook squares the pill and drops the halo, leaving
the flat #9980FF field with #1B0D4E text. That degradation is intentional —
the fill and the text color are the parts that carry the brand.
The generator emits a placeholder postal address and the brand-guide host. The registered line, in both email artifacts, is:
CODECAVE · 8 The Green, STE B, 19901 Dover DE, US · codecave.pro
The other four artifacts — deck, landing, poster, form — name
codecave.pro in their footers too. The generated files pointed every one of
those at the brand-guide host instead; that host is not CODECAVE's website, so
all six artifacts now carry the company address.
- Copy
colors_and_type.css,fonts/andbuild/into the target project, keeping the relative layout — the stylesheet resolves fonts as./fonts/Satoshi-*.woff2. - Link it once, at the root of the document. The tokens land on
:rootand the baseline sets the page to#0A0A0Bwith#F4F4F6text. - Consume the semantic layer, never the raw ramp:
--color-surface-*,--color-body-*,--color-heading,--color-action,--color-hovered. Exactly three raw values are legitimate —glow-25(glow fill),shadow-0(the upward glow) andprogress-0(the gradient mid). Never hard-code a hex. - Use the component classes rather than re-deriving them:
.btn+ variant,.card,.card-article,.card-feature,.field,.checkbox,.chip,.eyebrow,.lead,.eyebrow-lead,.stat,.divider,.page-container,.section-container. These are the public API. - Read
DESIGN.md§9 before shipping. The twelve anti-patterns are the fastest way to catch work that has drifted off-system — a downward shadow, a small radius, a second glow button, a purple wash, or a light theme. - Check §10, Known divergences. Two rules here intentionally differ from
what
codecave.proships today (error text contrast, real vs. synthesized font weights). Each is documented with the production value if you need to match live exactly. Buttons are not among them: the.btn*layer is a transcription ofButton.vueandGlowButton.vue, down to the halo hex literals and the 150mstransition-colors— including the tertiary hover that darkens its border to#1B0D4E. The only addition is the:focus-visiblering, which production never implemented. - Start from
artifacts/when building a whole surface rather than a control. Those six files show the system carrying real page density, which is where the 200/120 rhythm and the one-primary-action rule actually get tested.
guide.md and the former system/ tree are artefacts of the original
/design-systems/create registration run, which read the palette from the brand
site's README rather than from source. That palette was wrong — it mapped
#aaccee to the page background and #5F20FE to body text; #aaccee appears in
no first-party file, and #5F20FE is the action color and is never body text.
DESIGN.md §1 documents the correction in full.
brand.json was then corrected to the source-backed values (#5F20FE action,
near-black canvas, near-white ink, 24px radius — re-seeded again after the
2026 palette rebuild) and the generator re-run against them. The seed is right; the generator's derivation is not. Feeding it
#5F20FE produced a ten-step palette whose primary is #7040da, and the
resulting token layer — system/variables*.css, system/tokens.*.json,
system/theme.json, system/kit*.html and system/index.html — contained
zero occurrences of #5F20FE. It also shipped a light theme, which this
brand does not have. That layer has been removed rather than corrected: a second
set of custom properties on a different primary is worse than none, because a
consumer who links it gets a brand that is not CODECAVE and no error to tell
them so.
What survived the removal is artifacts/, promoted to the top level and re-based
on colors_and_type.css. brand.json and guide.md stay — both are on the real
palette — though guide.md remains a short generated orientation note and lags
this package in detail.
This package — colors_and_type.css, DESIGN.md, tokens/, preview/,
storybook/, artifacts/ — is the source of truth.
One check, and it needs nothing but node. Run it from the repository root:
node docs/tools/check-tw-bridge.mjsIt proves storybook/tw-bridge.css is still in step with source_examples/,
comparing a SHA-256 recorded in the generated header against the sources on
disk. A stale bridge does not announce itself: it compiles, it loads, and the
storybook goes on documenting an older site than the sources sitting beside it.
The same check runs on every push in .github/workflows/static.yml, ahead of
the deploy, and it is the one guarantee that always runs.
That check proves the bridge matches the captures. It cannot prove the
captures still match the site — nothing in a checkout of this repository
can, because the answer lives in another repository. With a codecave.pro
checkout beside this one:
npm run check:capturesIt compares all 30 site-derived captures against their origins and names any
that have drifted. The comparison normalises line endings, because the site
checkout does not pin them and a Windows clone of it is CRLF throughout — raw
bytes would mark all 30 as drifted on any Windows machine and never on CI,
which tells you about the reader's core.autocrlf and nothing about the site. Deliberately outside npm run check and outside
CI: codecave.pro is private, and with no checkout the command fails loudly
rather than reporting a success it did not earn. Run it before trusting any
claim of the form "production does X" — every such claim in this package rests
on those files. Last measured clean 2026-08-21; it found thirteen drifted files
the day before.
Regenerating the bridge is the other half, and it needs the codecave.pro
checkout — the storybook compiles the real components with the same
vue/esbuild/tailwind versions the site builds with, which is the whole point:
node docs/tools/build-storybook.mjs ../codecave.proThat checkout must have its dependencies installed, and it uses pnpm — its
lockfile is pnpm-lock.yaml and there is no package-lock.json:
pnpm install --frozen-lockfileReaching for npm install there instead produces an ERESOLVE failure on an
unrelated peer conflict, which looks like a broken dependency graph and is
really just the wrong package manager. --frozen-lockfile is what keeps a build
of this package from quietly rewriting the site's lockfile.
Some captured components import something a static docs page cannot resolve the
way production does: helpers/image-url.ts wants the Strapi base URL out of a
module that otherwise constructs an authenticated client, and
project/pain-points-item.vue sanitises its markdown with isomorphic-dompurify,
whose job is to pair DOMPurify with jsdom so the call also works during SSR.
Those dependencies are inverted, not stubbed. storybook/ports/ports.d.ts
declares the narrow interface the component actually needs; an adapter beside it
implements that interface for a static build; the PORTS table in
tools/build-storybook.mjs is the only place a specifier is wired to an
adapter. Everything else still compiles from the real source.
An adapter substitutes the environment, never the behaviour. The sanitiser
port really sanitises — it is plain dompurify at the version the isomorphic
wrapper resolves to, minus the jsdom half that only matters on a server. The
third story on the PainPointsItem page proves it rather than asserting it:
hostile markdown goes in, and the verdict under it is generated after mount from
the DOM the real component produced. It was an identity function for about a day
in August 2026, which was wrong — it made that page the one place in the
storybook where the component on screen was not the component in production, in
exactly the behaviour anyone visits that page to check.
Where an adapter genuinely cannot reach production, the specimen says so on its
face. StrapiPort can give a media URL its host but not the private token
behind it, so every page swaps in a local placeholder after mount — via
storybook/placeholders.js, which knows that LazyImage reads data-src and
that assigning .src to one of those loses a race with its
IntersectionObserver.
The distinction is not vocabulary. A stub is unchecked — it fails as an
undefined in someone's browser, at the one moment the specimen was supposed to
be proving something. An adapter is typechecked against its interface, so it
fails at build time instead:
npm run check:portswhich npm run check runs for you. The bar for adding a port is narrow, and
ports.d.ts states it: if swapping the implementation would change what the
specimen looks like, it is not a port — it belongs in the bundle.