Make a quiz

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.

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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.

  6. 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.

SampleTextOnContrast
Aainksurface16.1:1 ✓ ≥ 4.5
Aainkpage15:1 ✓ ≥ 4.5
Aainkcanvas14.5:1 ✓ ≥ 4.5
Aainksurface-muted14.6:1 ✓ ≥ 4.5
Aaink-softsurface6.4:1 ✓ ≥ 4.5
Aaink-softpage6:1 ✓ ≥ 4.5
Aaink-softcanvas5.8:1 ✓ ≥ 4.5
Aaink-softsurface-muted5.8:1 ✓ ≥ 4.5
line-strongsurface3.1:1 ✓ ≥ 3
Aaactionsurface10.3:1 ✓ ≥ 4.5
Aaactionpage9.6:1 ✓ ≥ 4.5
Aaactioncanvas9.3:1 ✓ ≥ 4.5
Aaon-actionaction10.3:1 ✓ ≥ 4.5
Aaon-actionaction-edge14.4:1 ✓ ≥ 4.5
Aadangersurface7.6:1 ✓ ≥ 4.5
Aadangerpage7.1:1 ✓ ≥ 4.5
Aadangercanvas6.9:1 ✓ ≥ 4.5
Aasuccesssurface6.6:1 ✓ ≥ 4.5
Aasuccesspage6.2:1 ✓ ≥ 4.5
Aasuccesscanvas5.9:1 ✓ ≥ 4.5
Aawarningsurface7.1:1 ✓ ≥ 4.5
Aawarningpage6.6:1 ✓ ≥ 4.5
Aawarningcanvas6.4:1 ✓ ≥ 4.5
Aainfosurface6.9:1 ✓ ≥ 4.5
Aainfopage6.4:1 ✓ ≥ 4.5
Aainfocanvas6.2:1 ✓ ≥ 4.5
Aaon-danger-filldanger-fill4.7:1 ✓ ≥ 4.5
Aaon-success-fillsuccess-fill6.9:1 ✓ ≥ 4.5
Aaon-warning-fillwarning-fill5.8:1 ✓ ≥ 4.5
Aaon-info-fillinfo-fill7.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 px
    Make a quiz
  • text-small
    14 px / 20 px
    Make a quiz
  • text-body
    16 px / 24 px
    Make a quiz
  • text-body-lg
    18 px / 28 px
    Make a quiz
  • text-lead
    20 px / 28 px
    Make a quiz
  • text-title
    24 px / 32 px
    Make a quiz
  • text-headline
    36 px / 40 px
    Make a quiz
  • text-display
    56 px / 1.05
    Make 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.

Play surface

size: "md"

size: "lg"

Tool surface

size: "md"

size: "lg"

+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") Save

Icon 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.

Play surface

Tool surface

+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 quiz

Field

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.

Play surface

Tool surface

+chip({ href, selected }) All ages

Badge

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

NewChildrenChildrenChildrenChildrenChildren

Tool surface

NewChildrenChildrenChildrenChildrenChildren
+badge({ tone: "plain"|"orange"|"green"|"red"|"blue"|"action" }) 7–9

Notice

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.

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.

+notice({ tone: "info"|"success"|"warning"|"danger", title }) Text

Dialog

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

Delete

Are you sure you want to delete Volcanoes of the world? It can't be undone.

Tool surface

Delete

Are you sure you want to delete Volcanoes of the world? It can't be undone.

+dialog({ id: "deleteQuiz", title: t.delete })
    p= t.confirmDelete
    +actions
        +button({ kind: "secondary" }) Cancel
        +button({ kind: "danger" }) Delete

Empty state

When there's nothing to show yet: faces of kids from the 3D game, a title, a sentence and what to do.

Play surface

Quizzes

You haven't made any quizzes yet. Make your first one!

Make a quiz

Quizzes

Tool surface

Quizzes

You haven't made any quizzes yet. Make your first one!

Make a quiz

Quizzes

+emptyState({ title, text, faces: 3 })
    +button({ href: "/" }) Make a quiz

Stat

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

Icon 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

حذف

هل يُحذف «⁨Volcanoes of the world⁩» نهائيًا؟ لا يمكن التراجع عن ذلك.

Tool surface

حذف

هل يُحذف «⁨Volcanoes of the world⁩» نهائيًا؟ لا يمكن التراجع عن ذلك.

Empty state

Play surface

الاختبارات

لا توجد اختبارات بعد. حان وقت إنشاء أول اختبار!

إنشاء اختبار

الاختبارات

Tool surface

الاختبارات

لا توجد اختبارات بعد. حان وقت إنشاء أول اختبار!

إنشاء اختبار

الاختبارات

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.

+sticker(kind, css)

+logoTile

+colorStripe("h-2.5")

+kidFaces(6)

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 contrast
  • test/server/designClasses.test.jscounts per file what's outside the system, with scripts/designClasses.js; a file's number may only go down
  • test/server/logicalClasses.test.jsstart and end, never left and right
  • test/ui/design.test.jsevery page on a phone and a laptop: axe, 44 px, 13 px and no sideways scroll
  • test/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

Please turn on JavaScript