93%
5%
2%
Tokens, components and the landing page formula for every Engine surface, published as @engineio/ui. Everything on this page is the shipped component. The rules ship with it as AGENTS.md, so the tools that build Engine surfaces read the same ones.
The rules every Engine surface follows: architecture, marks, colour, type, shape, space, motion, imagery and voice.
Engine is a B2B iGaming platform. The promise is speed. The platform is the product, not the player experience. Nothing here uses the visual language of a casino: no coins, no jackpots, no gold, no celebration.
Master brand
engine.io owns everything above the two products: marketing, the corporate story, recruitment, stationery. Master-brand surfaces carry the wordmark, never a sub-brand lockup.
Build and publish. Creators build games on Engine; Engine publishes them on Stake. Addresses creators and studios.
Distribution. Casinos integrate against Engine's docs, pull down Engine Studio games and run them on a revenue share. Addresses operators.
Magenta is the accent on both. One accent per surface, never two.
Naming
Write sub-brands in full on first use. Engine Studio, Engine Integration. Never abbreviate to ES or EI. Once a lockup has established which product is speaking, later references on the same surface may shorten to Studio or Integration. The master brand is Engine, never the Engine platform. Audiences do not mix: a Studio surface does not sell catalogue size, an Integration surface does not sell build tooling, and neither speaks to players.
Vector artwork from the brand team, in the only two colourways the brand sanctions. Pure White for dark surfaces, Off Black for print and inverted panels. The wordmark is a custom soft-rounded face, not DM Sans. It is artwork, never set in type and never approximated. The figure mark is the turbo — the wordmark's g is retired as a standalone mark and does not come back.
Wordmark, for master brand surfaces
Figure mark, the turbo
Secondary, on an inverted panel
Scale by height only, never both dimensions
Colour is a two-value variant and not currentColor. With currentColor, any ancestor's text colour silently becomes brand colour, and a magenta wordmark is one careless text-primary away. Size by height alone. The brand forbids distortion, and neither the turbo's 1001:1000 — square to the eye, not to the box — nor the wordmark's 2001:732.5 is a ratio anybody reproduces by hand.
The brand is three colours. Everything else is a neutral step between the outer two. One accent per surface, never two. No gradients, no coloured borders, no light theme.
Brand
Off Black
#0E0E0E
--color-background
Pure White
#FFFFFF
--color-foreground
Magenta
#FF006A
--color-primary
Magenta Press
#D60059
--color-primary-press
Neutral ramp
grey-950
grey-900
grey-850
grey-800
grey-700
grey-600
grey-500
grey-400
grey-300
grey-200
grey-100
grey-050
Status, functional only
Success
#00C46A
--color-success
Warning
#FFB020
--color-warning
Danger
#FF3B30
--color-danger
Status is functional colour. It reports state and nothing else. It is never decoration, never a second accent, and never a stand-in for magenta. Ink on a status fill is always Off Black, because white fails AA on all three. There is no info colour. Use the neutral ramp for informational states.
DM Sans only. Bold for display, Semibold for UI labels, Regular for body. Title Case for headlines, UPPERCASE only for small structural labels. No all-caps headlines, no italics, no other typefaces.
Display 1
Accelerate Growth.
Display 2
Accelerate Growth.
Headline
Accelerate Growth.
H1
Accelerate Growth.
H2
Accelerate Growth.
H3
Accelerate Growth.
Subtitle
Accelerate Growth.
Body
Accelerate Growth.
Caption
Accelerate Growth.
Mono
GAME_ID 7f3a91c2 · RTP 96.42% · 2300 live games
Condensed roles
2300 Games.
DM Sans has no condensed cut. --font-condensed and --font-extra-condensed remain as roles and resolve to the brand face, so big numbers and poster-scale words are set in DM Sans Black until the brand team assigns a condensed face. Display type is large: 92 to 104px on a 1480px page. Scaling Display 1 down to 48px does not produce a smaller display size. It produces an H1.
DM Sans is a variable Google Font under the Open Font Licence: weight 100 to 1000, and an optical-size axis from 9 to 40, so body sizes get the looser cut and display sizes the tight one. There is no substitute face. A machine that cannot reach Google renders a size-adjusted Helvetica Neue or Arial matched to DM Sans's width, which the package ships as "DM Sans Fallback". --font-mono resolves to the brand face; JetBrains Mono is retired, and a product that needs character-cell alignment binds its own monospace.
Radii by role, never mixed arbitrarily on one surface. The outer frame is always larger than the inner panel. Two border weights only: 1px hairline for structure, 1.5px for container rules.
Radii
Tag
6px
Field
10px
Media
14px
Card
18px
Frame
26px
Control
999px
Border weights
Hairline
1px · structure
Container rule
1.5px · cards and panels
Nesting, outer frame always larger
Depth comes from rules and nested panels, not shadow. The package holds two shadow tokens, --shadow-panel and --shadow-modal, and both are for product chrome and modals. Neither belongs on a brand surface. Neither is a substitute for the rule that should have been there.
1480px page, 40px gutters, and 920px for anything anyone has to read. Spacing is 4px-based, with large jumps at 56 / 72 / 96 / 128 for section rhythm and 12 to 20px within a group. Rhythm comes from the gap between groups being clearly larger than the gap inside one.
Widths
Page
1480px maximum, 40px gutters, 72px on large brand pages, for product surfaces. This page is not one: it sits on the 1180px marketing column described under Marketing.
Reading
920px, and this paragraph stops there. Body copy that runs the full 1480px is unreadable however correct the type scale is.
Brand page
1480 × 836. Slides and statement pages are drawn at that ratio.
Card
20px padding, 28px on the large variant.
Section rhythm, the large jumps
56px
72px
96px
128px
Within a group
2
4
6
8
12
16
20
24
32
40
Signature composition, big type flush to a bottom corner
Accelerate Growth.
The hairline sits 14px from the top, inset 24px each side, and the type is set flush to the bottom-left instead of centred. That is the deck's signature composition. Centring it is the most common way a page stops looking like Engine.
Fast and mechanical, to match the promise of speed. 140ms for control states, 220ms for surfaces, 360 to 640ms for reveals. Entrances ease out, exits accelerate, presses scale to 0.98. Never bounce, never spring, never parallax, never a looping decorative animation.
Durations
Instant
80ms
Anything that should not be seen moving at all.
Fast
140ms
Control states: hover, press, focus, the switch knob.
Base
220ms
Surfaces: dialogs, popovers, the tab marker.
Slow
360ms
Reveals on a product surface.
Reveal
640ms
The longest move the brand allows.
Easings, run side by side
ease-brand
cubic-bezier(.2,0,.2,1)
Control states, in and out.
ease-brand-out
cubic-bezier(.16,1,.3,1)
Entrances on surfaces and reveals.
ease-brand-accelerate
cubic-bezier(.6,0,.3,1)
Exits, and nothing else.
Reveal, 8px up with a fade and never further
Make Ambition Move Faster.
Motion is fast, but it is never mandatory. prefers-reduced-motion drops everything to fades, and the package's base layer already does that globally. A product importing @engineio/ui/styles gets it without writing a line. Turn the setting on and press Run again. The blocks jump, and nothing on this page breaks.
Black-and-white photographs and renders of machined objects: turbines, rigs, pipework, schematics, keycaps. Cool, hard, high-contrast, slightly clinical. Some frames read as technical drawings with faint annotation type. Occasionally one tiny point of magenta light in an otherwise monochrome frame, and no more than one.
Treatment: 14px crop, badge top-right, scrim under type
Rigs · Keycaps · Tooling
Pipework · Manifolds · Junctions
Never people. Never warm tones. Never stock-office imagery. No handshakes, no laptops, no meeting rooms. Always cropped into a rounded rectangle at the media radius or bled to the page edge, with the sub-brand badge top-right. Type over photography gets the bottom-up black scrim, not a capsule and not a box. Subject leans by sub-brand and the grade never does. Studio takes the machined and constructed, Integration the connective, both monochrome.
The two frames hold no photography. None ships in this package, and filling them with a stand-in would put an image into the design system that the brand never approved. The scrim under the type is the only gradient the brand permits. Backgrounds are one of three things, and photography is the third: flat Off Black, flat white for print and letterhead, or full-bleed monochrome. No patterns, no textures, no illustration, no noise.
Declarative, mechanical, confident. Short sentences that end in a full stop, headlines included. Second person for the customer, third person for Engine. Engine rarely says we. Register is plain and commercial: no showmanship, no exclamation marks.
Sentence shapes
Claim + mechanism
Accelerate Growth. The platform to build, publish and scale in the iGaming space.
Instruction + payoff
Integrate once with Engine to grow your casino catalogue with tested and proven games.
Question + answer
Thinking of growing your online casino offering? Engine Integration gives you access to over 2300 live games.
Numbers front-loaded
Over 2300 live games.
Engine writes, and does not
Written
Not written
Why
Accelerate Growth.
Accelerate growth!
Headlines end in a full stop. The stop lands the claim; an exclamation mark undoes it.
Build on Engine.
We will help you build.
Third person for Engine. Engine rarely says we.
Your catalogue, live on every operator.
The client catalogue, live on every operator.
Second person for the customer.
Colour, catalogue, favours, turbocharge.
Color, catalog, favors.
Spelling is British and Australian throughout.
Publish Game
PUBLISH GAME
Title Case for headlines and controls. Uppercase is for small structural labels only.
No emoji. Anywhere. Not in brand material, not in product UI, not in copy, and not in a commit message that ends up in release notes. The only non-alphanumeric glyphs the brand sanctions are the multiplication sign for a close control and the brand's asterisk for footnotes. This is the one voice rule with a grep behind it. CI scans the source and fails the build, because a design system that only asks nicely gets one eventually.
Twenty primitives from the package. Add a variant in your product by extending the exported variant map. Do not fork one.
One chip for every job, in the soft repository-label treatment: tinted fill, matching ink, 6px radius. Fills are translucent by design, so a chip reads the same on the page, on a card and on a table tile.
Brand and neutral
Status, functional only
The same chips on a card surface
There is no solid variant. An opaque fill can only be right on one surface, and these chips have to read on the page, on a card and in a table cell. The status variants are functional, not categorical. Reach for success when something has succeeded, never because green suited the row. The brand chip's ink is primary-300 and not pure magenta, because magenta on its own tint is 4.37:1 and the brand forbids magenta text below 15px bold.
The panel is always neutral. A 3px bar down the left edge is the only thing that says good, bad or warning. The fill, the rule and the type never change. A column of alerts reads as one surface with state down its side, not as four different components.
The bar is aria-hidden, so the title has to carry the message with the colour ignored entirely. "Upload failed." beats "Error." The neutral variant takes a grey bar instead of none, so a mixed stack keeps its left edge. Pass onDismiss to get the close control, and omit it for a static alert.
40px height, 10px radius, 1px hairline border on the grey ramp. Focus swaps the border to magenta and adds the ring. All three share the `field` utility, so the focus treatment is defined exactly once.
Checkbox at 18px with a 6px radius, radio as an 18px circle, switch as a 44 × 24 track. Magenta fill when on, knob travels in 140ms.
Switch
Checkbox
Radio
Progress
Off-black panel, 1.5px rule, 18px radius, with an inner panel at 10px holding artwork. Hover lifts the rule. Not a shadow, not a transform.
Monochrome machined objects. Never people, never warm tones.
Monochrome machined objects. Never people, never warm tones.
Monochrome machined objects. Never people, never warm tones.
Two flavours. Pill is the default. Underline is the section-level treatment: a hairline rule with a 2px magenta marker under the active tab. No pill-background tabs at section level.
Dialog scrim is rgba(10,10,10,.72) with an 18px blur. This and the sticky header are the only sanctioned uses of blur. Panels enter over 220ms and exit over 140ms.
Dialog, Popover, Tooltip
Responsive dialog
Ruled, not tiled. No frame, no fills, no gaps. The surface behind shows through, and a hairline under each row does all the structural work. Headings are Bold 13px in Pure White, Title Case, separated from the body by a rule one step stronger than the dividers.
| Game | Studio | RTP | Status |
|---|---|---|---|
| Turbine Rush | Northwind | 96.42% | live |
| Manifold | Grayscale | 95.18% | draft |
| Keycap Klondike | Northwind | 96.01% | live |
| Pipework | Grayscale | 94.87% | draft |
| 4 games | 2 studios | 95.87% |
Hover a row for the 6% white wash. The second row is data-state="selected", which takes the magenta tint. Never a coloured border or an edge accent, both of which the brand rules out. Because the cells carry no fill there are no fill collisions. A Badge, a Separator or an unchecked Switch reads correctly in any column, which the gapped-tile treatment could not promise.
Loading states stay on the grey ramp. A divider is a 1px hairline, never a coloured rule.
Below the rule.
The landing page formula: an 1180px column, four text sizes, a glass header, and motion that plays once and lands on its end state. This page uses it.
A logged-out landing is read once, top to bottom, by a stranger. It is narrower than a product page, breathes more and says less per screen. The two Engine landings settled this formula in September 2026 and calibrated it against stripe.com: an 1180px column, fluid gutters and rhythm, a glass header with no rules, a left-aligned hero with the art to its right, and a logo marquee before the first section.
Column and rhythm
--container-marketing
1180px
max-w-marketing — the column. Content starts at x=194 on 1440.
--spacing-gutter
clamp(20px, 5vw, 64px)
px-gutter — the side padding, fluid.
--spacing-section
clamp(88px, 12vw, 160px)
mt-section, pb-section — the gap before every h2.
--spacing-header / -sm
72px / 64px
h-header, -top-header — the glass bar, and where hero art starts.
--spacing-anchor / -sm
120px / 96px
scroll-mt-anchor — header plus breathing room for #links.
--blur-glass
20px
glass — 65% page colour over the blur, always on.
Banner, header, hero and marquee, as shipped
Thousands of publishers, one contract, one invoice, completely standardised behind one integration. Forget the negotiations and focus on what actually matters. Apply and go live today.
The header is `static` here only so the gallery can scroll past it. On a page it is sticky and the hero's art layer starts at its top edge, so the render shows through the glass at rest. The marquee takes real logos as images — white on transparent, fitted to one box — and this one renders text tiles through the `item` snippet.
Four sizes and a standfirst, each a whole spec on one utility: size, leading, tracking and weight together, so text-hero is the h1 and not a font size. Headings are capped in ch and balanced. Base text is white; grey is reserved for meaning.
text-hero
clamp(38px, 5vw, 64px) · 1.02 · −0.02em · 700
max-w-[18ch]
A Modern Take on the Traditional Aggregator.
text-section
clamp(28px, 3.2vw, 44px) · 1.06 · −0.02em · 700
max-w-[26ch]
Every operator and every creator is on the same simplified contract.
text-standfirst
clamp(18px, 1.5vw, 22px) · 1.5
max-w-[54ch]
One contract, one invoice, completely standardised behind one integration. Forget the negotiations and focus on what actually matters. Apply and go live today.
text-lead
clamp(17px, 1.4vw, 20px) · 1.5
max-w-[52ch]
You just need to pay the invoice, and we will settle with the creators.
text-card-title
17px · 1.35 · 600
max-w-[40ch]
Near real-time analytics, see exactly how the integration is performing.
text-stat
42px · 0.94 · 900 · tabular
9.7B+
text-small
13px · 1.5
Platform-wide totals, live from engine.io.
No uppercase, no mono and no eyebrows on a landing. The page has four sizes of type; a tracked label is a fifth. Inside a mock screen the scale drops again — 15px bold titles, 11 to 13px text, 10px tags — because a mock is a picture of a product, not the page.
A mock screen is a scene. Its elements rise in 140ms apart, fills sweep from the left, bars climb from the bottom, and three seconds in — once the reader has taken it in — the confirmation settles and a pending tag swaps to done. Every utility is global, honours prefers-reduced-motion by landing on its end state, and can be held paused by a motion-gate until the block is on screen.
Timings
--motion-reveal
700ms
rise — an element arriving on a scene.
--motion-stagger
140ms
Between siblings, multiplied by --i.
--motion-fill
1400ms
sweep — a gauge or split bar filling.
--motion-settle
3000ms
settle, swap — the confirmation, once the screen has been read.
--motion-swap
300ms
The outgoing half of a swap, and every fade-out.
--motion-pulse
2400ms
live-dot — one breath.
--motion-step
8000ms
One Tour step.
--motion-beat
3000ms
The bento metronome. One card moves per beat.
The scene, replayed
Exposure limits.
Unsaved Saved100,000.00 USD
500.00 USD
Rules learned the expensive way. Nothing plays until it is on screen. Rotating rows never use rise — the stagger leaves a hole — they use Svelte fly, flip and fade. A reveal is opacity only, because a translate on it makes every anchor scroll land short. And when several things on a page rotate they share one beat and take turns, so only one thing is ever moving.
The Stripe-style product walkthrough. A numbered step list beside a browser-frame mock, one screen per step, one callout hanging off the frame's corner, advancing on the progress bar's own animationend every eight seconds and paused while off screen. The shell is the component; the screens are yours, built from the motion grammar.
Choose a step
Application.
Your name, your website and a few lines on what you do.
Sign in / Apply for access
Clicking a step is the only control — no hover pause, no pause button, both tried and removed. The mock is decorative; the step list and the callout carry everything it shows. Under reduced motion the timer is off, not fast: a 0.01ms fill would advance every step in one frame.
Six columns from lg: a wide card spans three, a narrow one two. Each card is a cropped product mock over one sentence. The grid holds every scene paused until a quarter of it is on screen, then starts them together, and ticks one shared 3s beat so rotating cards take turns.
93%
5%
2%
INV-2026-07
Due in 20 days PaidThe screen runs off the card's bottom edge on purpose — design the mock to be cut. Two surfaces and no borders: card over page, page colour inside. One sentence per card, as an h3, with a full stop; the mock shows the thing and the sentence names it.
Four figures that count up on sight, each with a magenta plus. The plus is a promise — it says at least this — so floor the figures before passing them, never round up. The caption says where the numbers come from and when.
Proven and reliable at scale. Engine already powers Stake, the largest casino in the world.
Platform-wide totals as of September 2026. Games are released per operator.
SectionHead above it is the h2 and lead every section opens with, and mt-section is the rhythm between blocks — here overridden to zero because the gallery section already spaced it. Sentence case, a full stop, 26ch, balanced. No eyebrow above it; the landings removed every one.
The rules ship inside the package as AGENTS.md. Point your tools at it. This exists to help automation converge on one system, not to enforce a style.
Counted from the package this page imports.
Every rule on this page is in AGENTS.md. It ships inside the package at node_modules/@engineio/ui/AGENTS.md and versions with the components. The same file is served here at /AGENTS.md for a tool with nothing installed.
In a consumer's CLAUDE.md or AGENTS.md, one line does it
UI is built on `@engineio/ui`. Read `node_modules/@engineio/ui/AGENTS.md` before writing or reviewing any UI.
Point at the path. Do not copy the rules into a repo; the copy goes stale on the next version. The repo also carries a Claude Code skill that is only that pointer.
Tailwind 4 does not scan node_modules, so the @source line is required; without it the page half-styles with no error. The brand face is DM Sans from Google Fonts: the package names it and ships the fallback behind it, and you add the link to app.html. Skip that and the page renders in the fallback, also with no error.
app.css
@import "tailwindcss"; @import "@engineio/ui/styles"; @source "../node_modules/@engineio/ui/dist";
app.html
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000&display=swap" rel="stylesheet" />
Four greps fail the build. All four happened in the products first.
Raw hex literals
Every colour is a token. A literal is a colour nobody can find or change.
Tailwind's stock palette
The brand has three colours and a grey ramp. A stock green is a status colour someone invented.
Retired sub-brand colours
Originals Orange and Sportsbook Blue have no owner, so they are not available.
Emoji
None, anywhere. The only sanctioned glyphs beyond letters and numbers are the close sign and the footnote mark.
Engine surfaces are built by people and by agents. A rule written here once does not have to be rediscovered, and a component shipped here once does not have to be rebuilt. Where this page does not cover a case, choose the quieter option and flag the gap. Where it disagrees with the brand documents, the documents win.
The prohibitions in one list. Four are grep checks in CI and fail the build.
No gradients, glows or coloured shadows. The scrim over photography is the one exception.
No two accents on one surface.
No colour outside the three brand colours, the neutral ramp and the three status colours.
ciNo info colour. Use the neutral ramp for informational states.
ciNo raw hex literals in component source. Use a token.
ciNo body copy in magenta, and no magenta text below 15px bold.
No drop shadows on cards or brand surfaces.
No coloured left border to indicate category or ownership.
No setting the wordmark in a typeface, and no approximating it in a lookalike.
No all-caps headlines. No italics. No other typefaces.
No emoji, illustration, textures, patterns or noise.
ciNo photography of people, no warm tones, no stock office scenes.
No light-mode variant.
No casino iconography. No coins, chips, jackpots, gold or celebration.
No scaling display type down to 48px and calling it display.
When something is not covered here, choose the option that is quieter and more mechanical. That resolves most of what this list does not.