The Limina Labs marketing site. Ten marketing pages plus four utility pages, static, no framework, no runtime dependencies, and no external requests at all — not for fonts, not for analytics, not for anything.
node build.mjs # build every page
node bump-version.mjs 2.2 # bump the design system cache-busting versionThen serve the repo root. .claude/launch.json defines a local server on :8080.
src/
partials/ shell · nav · footer shared by every page
pages/ one file per URL, front matter in an HTML comment
site.css marketing patterns layered on the design system
site.js one thing: the Products menu
site.config.json shared URLs and contact, so ten pages cannot drift
placeholders.json what each {{PLACEHOLDER}} still needs
build.mjs expands partials → writes index.html, precepta/index.html, …
design-system/ Limen — tokens, components, both themes, self-hosted fonts
assets/ the brand kit: mark, lockups, favicons, app icons, social
Output is committed to the repo root, so /precepta is served from
precepta/index.html by GitHub Pages with no rewrite rules and no CI.
Never edit the built HTML at the repo root — it is regenerated. Edit
src/pages/ and rebuild.
build.mjs fails rather than emitting a page that breaks one. It checks for:
- the hard constraints —
beta,coming soon, Forge, and the slop material - every word on the never-use list —
enterprise-grade,seamless,leverage,unlock,AI-powered,10xand the rest - any external font CDN or analytics reference
It also writes LAUNCH.md from the built pages, listing every
{{PLACEHOLDER}} and where it appears. That file is generated, so it cannot
quietly disagree with the site.
Placeholders render on the page as amber dashed markers. A placeholder that blends in is a placeholder that ships.
These come from the build brief. Breaking one costs a deal, not a style point.
- Never fabricate an artifact. Any attestation, probe output or audit log shown on the site must be real output from a real environment. There is none in this repo, so the site shows none — it describes the architecture instead. A fabricated log line is the one thing a technical buyer never forgives.
- Never name a customer, claim a certification, funding, or a team size. None exist.
- Never publish a roadmap. The site covers the vision, the products and what is available today. No dates, no horizons, no "what isn't built yet" tables — and correspondingly, never imply something unbuilt is purchasable.
- Never offer a self-hosted download, and never offer a sandbox. There is no hosted tier — that is a positioning asset, not a gap. It means we operate no environment a customer's data could sit in, which is a stronger claim than any policy. Every route says request an evaluation or talk to us.
- Never present the three products as a pipeline. They are siblings of equal weight. Diagram A points arrows upward on purpose — a left-to-right row tells the buyer they need all three, which is both untrue and the strongest objection procurement can raise.
- Never make Cerebrio visually subordinate. Identical card, identical box, status in a chip. Never greyed, dimmed or dashed.
- Never assert what is true inside the reader's organisation. Not "your execution is ungoverned". Ask the question and let them answer it. An asserted problem invites an argument the reader wins.
- Never gate a security document.
- Never publish a price. Pricing is a conversation, not a page. Every
commercial route leads to
/contact. - No sign-in anywhere, for now. Limina Labs is a company, not an
application, so there is no company-wide sign-in — and product-level entry
points are parked too, pending a decision. Every route on the site leads to
/contact. Worth knowing when that decision is made: Precepta could never have one anyway. It is self-hosted, so a customer signs in to their own deployment, at their own URL, which we neither host nor link.
Voice: British spelling, sentence case headings, plain declarative sentences, concrete nouns. No emoji, no stock imagery, no manufactured social proof.
Two harnesses, both run in the browser against the built pages. Serve the repo and open them; each must report zero.
http://localhost:8080/src/responsive-harness.html layout at 375 / 768 / 1280
http://localhost:8080/src/contrast-harness.html WCAG AA, both themes
The responsive one walks every page at three widths and fails on horizontal overflow, on any element poking past the viewport, and on SVG text escaping its own viewBox — the three ways a page breaks that a screenshot at one width will not show you.
src/contrast-harness.html walks every page in an iframe, forces each theme,
composites translucent glass over its real backdrop and measures every
text/background pair against WCAG AA. Serve the repo and open:
http://localhost:8080/src/contrast-harness.html
It must report TOTAL FAILURES: 0. Two things it has already caught: the
amber --lim-warn sitting at 4.09:1 on its own wash, and decorative-only
--lim-text-faint used for numerals people are meant to read.
- Create
src/pages/<slug>.htmlstarting with the front-matter comment:<!-- title: Page title | Limina Labs description: One sentence for search and link previews. path: /slug nav: trust -->
navmarks the matching nav item current; usenonefor utility pages. - Write the body.
{{base}}resolves to the correct relative prefix. node build.mjs.
design-system/ is Limen — see its
README. It carries the tokens, components, both
themes and the self-hosted typefaces, and everything on this site is composed
from it. If a component does not fit, it needs a modifier, not a patch.
Its cache-busting version has to move on every file at once — the entry file,
its @imports, and the JS. bump-version.mjs does all of them together, which
matters: version only the entry file and a browser will serve cached copies of
everything it imports, which looks exactly like a CSS fix that did not work.