Tjaz' design system
The roles, components and rules every page of Tjaz is built with, from the front page to the quiz, the 3D game, the big screen and the editor. Tjaz is for people who can read: school children from about 6, when they learn to read, their teachers, grown-ups and seniors, in 161 languages, seven of them read from right to left.
Principles
Six rules that every design on Tjaz follows, by a person or by Claude.
Roles, not values
Choose text-ink-soft, bg-action and rounded-card, never a colour as a number, or a size or a corner of its own in square brackets. The roles are worked out and tested once, so their contrast comes along.
Components, not recipes
A button is +button, a field +field, a dialog +dialog, with the focus ring, the states, accessibility and right to left built in, as the behaviour is what goes wrong.
Short guidance, long tests
What a script can check is a test, not a line in a guide: values outside the system, contrast, things to tap, text size and axe.
Tjaz' own values
The logo's four colours and the button blue, Raleway, and the public pages' corners and shadows, so nothing falls back to what every site looks like.
Alike works alike
What works alike looks alike, and the other way round: an answer in a quiz never looks like a button that takes you somewhere.
Derived from what's there
The public pages' design became the system's, so moving a page into it changes nothing anyone sees, except faults fixed.
Two surfaces
Tjaz has two surfaces, and every page is on one of them. There's no dark theme, also not on the big screen.
Play
The public pages, the quiz in 2D and 3D, the big screen and the players' phones: squared paper, white cards, the logo's colours as fills, stickers, the colour stripe, big tactile buttons whose edge sinks when pressed, and 18 px text where children read.
Tool
The editor, the account, /home, the admin pages and the research: a calm cream surface, ink and the button blue, 16 px text and flat buttons. No stickers or coloured fills; a colour stripe on the main card is fine.
Never decoration around a question that's being answered: the warmth is in the answer buttons, the feedback and the screens between the questions. In quizzes whose youngest players are 6–8, questions and answers are one step bigger in the 2D quiz. The TV page (tjaz.com/tv), the big screen and the players' phones keep their own carefully made design.
Colour
Tjaz' own colours are the logo's four, in the order of its letters, with their shades, ink, the cream canvas and paper, and the button blue. A role says what a colour is for and points to one of them; pages use the roles.
Roles
page
#f8f7f2
surface
#ffffff
surface-muted
#f3f4f5
ink-soft
#575e71
line
#e3e4e7
line-strong
#8b909d
action
#2f3f65
action-hover
#3f5588
action-edge
#1f2942
on-action
#ffffff
focus
#3f5588
danger
#ab0002
danger-fill
#da2d23
on-danger-fill
#ffffff
success
#386805
success-fill
#73cd00
on-success-fill
#193300
warning
#7d4d02
warning-fill
#e79301
on-warning-fill
#3f2501
info
#255e89
info-fill
#7bc3fe
on-info-fill
#012e4c
Contrast
Every pair of text and background a role is used in, with WCAG's contrast: at least 4.5:1 for text and 3:1 for a field's edge. A test holds every pair to it.
| Sample | Text | On | Contrast |
|---|---|---|---|
| Aa | ink | surface | 16.1:1 ✓ ≥ 4.5 |
| Aa | ink | page | 15:1 ✓ ≥ 4.5 |
| Aa | ink | canvas | 14.5:1 ✓ ≥ 4.5 |
| Aa | ink | surface-muted | 14.6:1 ✓ ≥ 4.5 |
| Aa | ink-soft | surface | 6.4:1 ✓ ≥ 4.5 |
| Aa | ink-soft | page | 6:1 ✓ ≥ 4.5 |
| Aa | ink-soft | canvas | 5.8:1 ✓ ≥ 4.5 |
| Aa | ink-soft | surface-muted | 5.8:1 ✓ ≥ 4.5 |
| line-strong | surface | 3.1:1 ✓ ≥ 3 | |
| Aa | action | surface | 10.3:1 ✓ ≥ 4.5 |
| Aa | action | page | 9.6:1 ✓ ≥ 4.5 |
| Aa | action | canvas | 9.3:1 ✓ ≥ 4.5 |
| Aa | on-action | action | 10.3:1 ✓ ≥ 4.5 |
| Aa | on-action | action-edge | 14.4:1 ✓ ≥ 4.5 |
| Aa | danger | surface | 7.6:1 ✓ ≥ 4.5 |
| Aa | danger | page | 7.1:1 ✓ ≥ 4.5 |
| Aa | danger | canvas | 6.9:1 ✓ ≥ 4.5 |
| Aa | success | surface | 6.6:1 ✓ ≥ 4.5 |
| Aa | success | page | 6.2:1 ✓ ≥ 4.5 |
| Aa | success | canvas | 5.9:1 ✓ ≥ 4.5 |
| Aa | warning | surface | 7.1:1 ✓ ≥ 4.5 |
| Aa | warning | page | 6.6:1 ✓ ≥ 4.5 |
| Aa | warning | canvas | 6.4:1 ✓ ≥ 4.5 |
| Aa | info | surface | 6.9:1 ✓ ≥ 4.5 |
| Aa | info | page | 6.4:1 ✓ ≥ 4.5 |
| Aa | info | canvas | 6.2:1 ✓ ≥ 4.5 |
| Aa | on-danger-fill | danger-fill | 4.7:1 ✓ ≥ 4.5 |
| Aa | on-success-fill | success-fill | 6.9:1 ✓ ≥ 4.5 |
| Aa | on-warning-fill | warning-fill | 5.8:1 ✓ ≥ 4.5 |
| Aa | on-info-fill | info-fill | 7.4:1 ✓ ≥ 4.5 |
Tjaz' own colours
The logo's orange
tj-orange
#e79301
50
#fff5ea
100
#ffebd5
200
#fed8ae
300
#fec078
400
#f6a63b
500
#e19011
600
#bf7903
700
#9d6301
800
#7d4d02
900
#613b01
950
#3f2501
The logo's green
tj-green
#73cd00
50
#e9ffdc
100
#d1ffb4
200
#acf975
300
#96e856
400
#7cd427
500
#6cbe15
600
#5aa008
700
#488405
800
#386805
900
#2a5102
950
#193300
The logo's red
tj-red
#da2d23
50
#fff4f2
100
#ffe9e5
200
#ffd4cd
300
#febab0
400
#ff998a
500
#fd7464
600
#e94c3e
700
#cf231b
800
#ab0002
900
#850504
950
#580001
The logo's blue
tj-blue
#7bc3fe
50
#f0f8ff
100
#e1f1ff
200
#c5e4ff
300
#a2d4fe
400
#79c1fb
500
#67ace3
600
#5191c4
700
#3b77a6
800
#255e89
900
#114970
950
#012e4c
The button blue
500
#3f5588
600
#2f3f65
700
#1f2942
800
#0e141f
Blue
100
#eef0f7
200
#b6c2dd
300
#93a4cd
400
#7087bd
500
#4f6aab
600
#3f5588
700
#2f3f65
800
#1f2942
900
#0e141f
Ink, canvas and paper
ink
#16203a
canvas
#f4f3ec
paper
#f8f7f2
In a script in the browser, e.g. three.js or a canvas, the same colours are named imports fromshared/designTokens.js, so only the colours used end up in its bundle:import { inkSoft, tjOrange, numberOf, withAlpha } from "shared/designTokens.js". On the server, colour("ink-soft") and colourNumber("tj-orange") look one up by its name.
Type
One scale with roles, from 13 to 56 px, in Raleway with lining numbers. 13 px only for small print, else at least 14; 16 px in tools and 18 px where children read; lines of 55–70 characters.
- text-caption
13 px / 18 pxMake a quiz - text-small
14 px / 20 pxMake a quiz - text-body
16 px / 24 pxMake a quiz - text-body-lg
18 px / 28 pxMake a quiz - text-lead
20 px / 28 pxMake a quiz - text-title
24 px / 32 pxMake a quiz - text-headline
36 px / 40 pxMake a quiz - text-display
56 px / 1.05Make a quiz
Corners and shadows
Three corners and the shadows of the public pages: cards and tiles float, and tactile buttons have an edge in a darker shade that sinks when they're pressed.
rounded-control
16 px
rounded-tile
24 px
rounded-card
32 px
shadow-card
shadow-card-lg
shadow-tile
shadow-sticker
shadow-press
shadow-press-soft
shadow-press-danger
Components
Pug mixins in views/mixins/ui/, one file each, all of them included by include ../mixins/ui.pug. Attributes after the call go on the element, and a class is added to the component's.
Button
The one main thing on a screen is primary; secondary beside it, quiet for Cancel and the like, danger for what can't be undone. md is at least 44 px high, lg is the main action of a page. On the play surface it's tactile, with an edge that sinks when it's pressed, as the front page's Make a quiz; on the tool surface it's flat, as the editor's. With href it's a link that looks like a button.
+button({ kind: "primary"|"secondary"|"quiet"|"danger", size: "md"|"lg", surface: "play"|"tool", href, type, wide }) Make a quiz
+button({ kind: "secondary", surface: "tool" })(class="mt-4" id="save") SaveIcon button
A button with only a picture, 44 × 44 px and round. Its label says what it does, for screen readers and as a tip, as a picture alone isn't enough.
+iconButton({ label: t.close, kind: "quiet"|"primary", href })
svg(class="h-5 w-5" …)Panel
A white card on the page: card for wide content with 2rem corners, tile for something small with 1.5rem corners. stripe puts the logo's four colours along its top, for what's Tjaz' own, e.g. a quiz that's ready.
Play surface
Your quiz is ready
Quiz title
Quizzes
Answers
Tool surface
Your quiz is ready
Quiz title
Quizzes
Answers
+panel({ size: "card"|"tile", stripe: false })
p …Heading
The heading of a page (1), a part of it (2) or a part of that (3), with a sentence under it if lead is given. Long words, as in German or Finnish, break rather than leave the page.
Play surface
Find a quiz
You haven't made any quizzes yet. Make your first one!
Quizzes
We only use it to answer you.
Quiz title
Tool surface
Find a quiz
You haven't made any quizzes yet. Make your first one!
Quizzes
We only use it to answer you.
Quiz title
+heading({ level: 1|2|3, lead }) Find a quizField
A field with its label above it, and a help text or an error under it, tied to it for screen readers. Its edge is line-strong, 3:1 on white. An email, a password or a number is written from the left in every language. type can be textarea, or select with its options as the block.
Play surface
We only use it to answer you.
Please enter a valid email address.
Tool surface
We only use it to answer you.
Please enter a valid email address.
+field({ id, name, label, help, error, type: "text"|"email"|"password"|…|"textarea"|"select", value, placeholder, required, rows })(autocomplete="email")Switch
A setting that's on or off: its label, its help, and a switch at the end of the line, where the whole row can be tapped. A real checkbox with role="switch", so a form sends it and a script reads .checked. switchControl is the switch alone, 44 px high to tap.
Play surface
Tool surface
+switchRow({ id, name, label, help, checked })
+switchControl({ id, name, checked })(aria-label=t.shuffled)Chip
A choice among a few, as a pill 44 px high: a link or a button. The chosen one is said with aria-current or aria-pressed, which is also what shows it, so a script that moves the choice only moves the attribute.
+chip({ href, selected }) All agesBadge
A small label on something, e.g. who a quiz is for, or New. White, or one of the logo's colours with its own dark text, and white only on red and the button blue.
Play surface
Tool surface
+badge({ tone: "plain"|"orange"|"green"|"red"|"blue"|"action" }) 7–9Notice
A message on the page: white with an edge at the start in its tone's colour, a title, its text and room for a button. Danger is said to screen readers as an alert, the others as a status.
Play surface
Your quiz is ready
We only use it to answer you.
Saved
We only use it to answer you.
Link copied
We only use it to answer you.
Something went wrong. Please try again.
Tool surface
Your quiz is ready
We only use it to answer you.
Saved
We only use it to answer you.
Link copied
We only use it to answer you.
Something went wrong. Please try again.
+notice({ tone: "info"|"success"|"warning"|"danger", title }) TextDialog
A dialog over the page, the browser's own <dialog>, so the focus stays in it and Escape closes it; open it with dialog.showModal(). Its buttons in +actions: at the end of the line with the main one last, and on a phone each the whole width with the main one on top. Here it's shown in the page.
Play surface
Tool surface
+dialog({ id: "deleteQuiz", title: t.delete })
p= t.confirmDelete
+actions
+button({ kind: "secondary" }) Cancel
+button({ kind: "danger" }) DeleteEmpty state
When there's nothing to show yet: faces of kids from the 3D game, a title, a sentence and what to do.
+emptyState({ title, text, faces: 3 })
+button({ href: "/" }) Make a quizStat
A number with what it is, and a note under it. The number and the note are isolated, so +12 % stays +12 % from right to left.
Play surface
Answers
1,284
+12 %
Right answer
7/10
Tool surface
Answers
1,284
+12 %
Right answer
7/10
+stat({ label, value, note })Progress
How far something has come, as a bar in the button blue, said to screen readers by its label.
Play surface
Tool surface
+progress({ value, max, label })Right to left
Seven of Tjaz' 161 languages are read from right to left. The components turn by themselves: every class says start and end, not left and right, every lang has its dir, arrows turn with rtl:-scale-x-100, a name in a sentence is isolated, and a number beside a sign is in a bdi. Here they are in Arabic, with Tjaz' own words.
Button
Play surface
Tool surface
Panel
Play surface
الاختبار جاهز
عنوان الاختبار
الاختبارات
الإجابات
Tool surface
الاختبار جاهز
عنوان الاختبار
الاختبارات
الإجابات
Heading
Play surface
البحث عن اختبار
لا توجد اختبارات بعد. حان وقت إنشاء أول اختبار!
الاختبارات
لا نستخدمه إلا للرد عليك.
عنوان الاختبار
Tool surface
البحث عن اختبار
لا توجد اختبارات بعد. حان وقت إنشاء أول اختبار!
الاختبارات
لا نستخدمه إلا للرد عليك.
عنوان الاختبار
Field
Play surface
لا نستخدمه إلا للرد عليك.
يُرجى إدخال عنوان بريد إلكتروني صحيح.
Tool surface
لا نستخدمه إلا للرد عليك.
يُرجى إدخال عنوان بريد إلكتروني صحيح.
Switch
Play surface
Tool surface
Chip
Play surface
Tool surface
Badge
Play surface
Tool surface
Notice
Play surface
الاختبار جاهز
لا نستخدمه إلا للرد عليك.
تم الحفظ
لا نستخدمه إلا للرد عليك.
تم نسخ الرابط
لا نستخدمه إلا للرد عليك.
حدث خطأ ما. يُرجى المحاولة مرة أخرى.
Tool surface
الاختبار جاهز
لا نستخدمه إلا للرد عليك.
تم الحفظ
لا نستخدمه إلا للرد عليك.
تم نسخ الرابط
لا نستخدمه إلا للرد عليك.
حدث خطأ ما. يُرجى المحاولة مرة أخرى.
Dialog
Play surface
Tool surface
Empty state
Stat
Play surface
الإجابات
1,284
+12 %
الإجابة الصحيحة
7/10
Tool surface
الإجابات
1,284
+12 %
الإجابة الصحيحة
7/10
Progress
Play surface
Tool surface
Decorations
Only decoration, so screen readers skip them, on the play surface: stickers of what a quiz has, the colour stripe, the logo's tile and faces of kids made in the 3D game. The logo itself never changes.
Accessibility
WCAG 2.2 AA, and stricter where children use it.
44 × 44 px
Everything that can be tapped, also in the editor, where WCAG asks only for 24 px.
13 px
No text is smaller, and only small print is that small.
Contrast
At least 4.5:1 for text, 3:1 for a field's edge and the parts of a control, from the roles.
Focus
What can be used shows a 4 px ring in the focus colour from the keyboard, with a gap of the surface round it: the focus-ring utility.
Motion
Movement with motion-safe:, transitions with motion-reduce:transition-none, and nothing moves more than 5 seconds without a way to stop it.
Never colour alone
Right and wrong are also said with an icon and a word.
No sideways scroll
Every page fits a 320 px phone, also in German's long words and in Arabic.
Checked
axe-core finds no WCAG 2.2 AA fault on any page, in English and in Arabic.
How it's kept
Tests, so the system doesn't drift, and a skill that tells Claude to use it.
test/server/designTokens.test.jsthe colours in shared/designTokens.js are the theme's, and every pair has its contrasttest/server/designClasses.test.jscounts per file what's outside the system, with scripts/designClasses.js; a file's number may only go downtest/server/logicalClasses.test.jsstart and end, never left and righttest/ui/design.test.jsevery page on a phone and a laptop: axe, 44 px, 13 px and no sideways scrolltest/ui/designCatalogue.test.jsthis page, with the same checks, and the look of every component as the browser computes it, so a change of a role or a component is seen before it goes live.claude/skills/tjaz-design/SKILL.mdhow Claude designs with it
Outside the system today
What test/server/designBaseline.json still allows, summed over its 195 files. It may only go down.
Values in [ ] or ( )
2,578
Tailwind's own colours
188
Colours as numbers
1,784
Buttons written by hand
164





