@v4/tokens
The generated Ghost 2.0 default tokens, the per-component contract slices and the generated icon set.
Overview
@v4/tokens is the Ghost 2.0 default token set — the generated source of
truth the theme contract derives from. It sits between the raw Token Studio
export and every component theme: tokens.json in, typed TypeScript and icons
out.
Nothing here is hand-written. tokens.json is a vendored Token Studio export
from stadionHQ/ghost-web-tokens-v2, and everything under src/__generated__/
is produced by the @v4/token-parser CLI. The
generated files are never edited by hand — to change a value you re-fetch the
export and commit, and the generated diff is the review surface. How the
pipeline works is on Token pipeline; the steps to
regenerate are on Generating tokens;
the generator catalogue is Code generation.
What it contains
packages/tokens/
├── tokens.json vendored Token Studio export (input)
└── src/
├── __generated__/
│ ├── tokens.ts the typed defaults — the token source of truth
│ ├── tokens.css the emitted --ph__* CSS variable layer
│ ├── tokens.flat.json flattened view
│ └── components/ per-component contract slices
└── icons/ 129 generated SVG icon components
The Token Studio sets it covers: Primitive · Semantic · Colour-Sets ·
Component/{Core, Content, Football, Video, Gamification, Hospitality}. Component/Hospitality
is an empty set in the export, so it emits no contract module — the five slices below are the
whole output.
Entry points
| Import | Contents |
|---|---|
@v4/tokens |
tokens (the full generated defaults object) and its Tokens type |
@v4/tokens/icons |
The 129 generated icon components (IconArrowRight, …) and the shared IconProps type |
@v4/tokens/components/<name> |
A per-component contract slice — core, content, football, video, gamification |
How it is consumed
@v4/ghost-coreimports the rawtokensobject in exactly one file,default.theme.ts, to build the global contract; every component then binds contract paths (g.components.*, colour-set paths) so Euro League's overrides flow through. No component imports@v4/tokensdirectly for theming.- Icons are imported from
@v4/tokens/iconsby components and stories — never re-drawn as inline SVG. See Icons. - Euro League's look comes from its own token layer,
@v4/tokens-euro-league, applied over these defaults — not from editing this package, which the template owns. (sync-tokensbelow refreshes THIS package's Ghost baseline; it is not how Euro League's tokens update — Token Studio pushes those straight into the repo.)
Commands
| Command | Purpose |
|---|---|
pnpm --filter @v4/tokens generate |
Regenerate src/__generated__/ from tokens.json |
pnpm --filter @v4/tokens check |
Validate the export without writing (CI gate) |
pnpm --filter @v4/tokens sync-tokens |
Re-fetch tokens.json from the upstream repo, then regenerate |
pnpm --filter @v4/tokens sync-icons |
Re-generate the icon set from Ghost – Core 2.0 and the ELB files (below) |
pnpm --filter @v4/tokens drift |
Design-drift report: Ghost – Core 2.0 against ghost-core/figma.json |
pnpm --filter @v4/tokens build |
generate, then compile dist/ |
sync-icons makes six v4-tokens icons runs into src/icons/, in order:
- Ghost – Core 2.0 (
67J5FrDZn5HzYzf5hJgoNA) — every icon master on its icons page. - ELB – Web – Core (
HIjezWNeRQSBGkxx8VqmjA) — every icon master on its icons page. - ELB – Web – Core, by node — the six plain social-media glyphs (Facebook, YouTube, X, Instagram, TikTok, WhatsApp), which are variants and so invisible to page discovery.
- ELB – Web – Content (
9iz5GeR9syO68cmPr1ppE1), by node —FeatureandShare-Plain. - Ghost – Core 2.0, by node —
Chevron-DownandChevron-Up. - ELB – Web – Content, by node — the three competition marks: EuroLeague, EuroCup and NextGen.
A later run writes over an earlier one's file of the same name.
Icons and component contracts
Beyond the defaults object, @v4/tokens ships two generated surfaces that the
component packages consume directly.
Icons — @v4/tokens/icons
The package generates 129 icon components from three Figma files: Ghost –
Core 2.0 (67J5FrDZn5HzYzf5hJgoNA), ELB – Web – Core (HIjezWNeRQSBGkxx8VqmjA)
and ELB – Web – Content (9iz5GeR9syO68cmPr1ppE1, which supplies Feature,
Share-Plain and the EuroLeague, EuroCup and NextGen competition marks). Each is
an SVG functional component with fill="currentColor", so it inherits its colour
from the text context it sits in. Most are drawn in a 24×24 viewBox; a handful
keep their own (12, 16, 20 or 25–26 units wide):
import { IconArrowRight, type IconProps } from "@v4/tokens/icons";
<IconArrowRight />;
Import the real icon — never hand-draw inline SVG demo shapes in stories or
slot demo content. How to consume one (colour inheritance, color: inherit on
anchor-rooted components) and how directional glyphs mirror under RTL through the
opt-in directionalIcon mechanism are on
Icons and the icon catalogue.
Regenerate with pnpm --filter @v4/tokens sync-icons. The output is generated —
do not hand-edit src/icons/.
Per-component contracts — @v4/tokens/components/*
The parser slices the Token Studio Component/* sets into per-namespace contract
modules, exposed at @v4/tokens/components/<name>:
| Subpath | Namespace |
|---|---|
@v4/tokens/components/core |
Component/Core |
@v4/tokens/components/content |
Component/Content |
@v4/tokens/components/football |
Component/Football |
@v4/tokens/components/video |
Component/Video |
@v4/tokens/components/gamification |
Component/Gamification |
These feed the global contract (components.core, components.content, …) that
@v4/ghost-core's default.theme.ts assembles. A component theme binds those
namespaces through the global-contract path (g.components.core.*), never by
importing a @v4/tokens/components/* module and freezing its literals — a raw
import puts the value beyond Euro League's overrides. Why is on
Binding through the global contract.