Kaki
Kaki design system · v2 · 2026-09-23

Design guide

One system for the website, admin, owner portal, POS and app. It is built from the Kaki icon: an ivory tile with a gold edge, a green k and a red square. Everything here maps 1:1 to the tokens in @kaki/design-tokens and the components in @kaki/ui-web / @kaki/ui-native.

Principles

Apple’s surfaces, not a theme

Warm paper (the current site’s off-white) or true black ground, white cards, grouped lists, glass bars. It should feel native, but still like Kaki.

One object with personality

The tile. Ivory face, gold edge. Seats, ranks, venue marks and primary buttons are tiles; they press down 3px like a tile on felt.

Three colours, one job each

Green = act. Red = live / needs you now. Gold = only the tile’s edge. Nothing else is coloured.

Show the table

Wherever a game appears, show seats and winds the way a player sees them, never “3/4 players”.

Colour

Every token has a light and dark value and every surface follows the device setting. Components only ever read tokens, never literal hex values; a lint guard enforces it.

--ground
#FBF8F1 · #000000
--card
#FFFFFF · #1C1C1E
--card-2
#F4EEE3 · #232326
Aa
--ink / --muted
#0C100E / #6B7470
act
--felt / --felt-deep / --felt-tint
#1C9E5C / #0C6B3B / #E3F5EB
live
--dragon / --dragon-tint
#E5402A / #FCE7E1
--gold / --gold-deep
#F2B82E / #C98F12 · tile edge only
--ivory / --ivory-edge
#FBF8EF / #E6DFCB · tile face
panel
--deep
#0B4A2C · live panels, tickets
Do
  • White text only on --felt, --deep or --dragon fills.
  • Tinted chips: tint background + the matching strong colour for text.
  • Semantic states (paid, due, refunded) use the .st pills.
Don’t
  • Use gold as a label, button or text colour.
  • Bring back blue or violet, or use grey #F2F2F7 for the page. Light pages are warm paper #FBF8F1.
  • Hard-code a hex value in an app. Add a token instead.

Type

The Archivo brand family everywhere, loaded with next/font on web and @expo-google-fonts in the apps. Kanji uses the device’s own Chinese font in bold, never a serif.

Display · Archivo Black 400
--display · 44–88px · -0.04em
Mejanya siap
Title · Archivo Black 400
28–34px
Papan peringkat
Headline · Archivo 700
17–20px
Balai Mahjong Tiga Naga
Body · Archivo 500
15–18px · 1.5
Pesan meja di tempat mahjong dekatmu, temukan pemain keempat, dan catat skor tanpa kertas.
Numbers · Archivo 800–900
--round · tabular-nums
28.000 +6.400
Code · Space Mono 700
--mono · booking codes, IDs
KK7Q4M
Kanji · system CJK bold
--han
東 南 西 北 發 中

Tiles

The illustration language. An ivory face with a gold bottom edge, like the icon. The White Dragon is always a blank tile: never print 白. A face-down tile shows the gold back.

Sizes

西

Dragons

Face-down

Locked (not yet earned)

Medal ranks

1 2 3

App icon as a tile

Buttons

Buttons are tiles: a raised bottom edge that sinks 3px on press. One primary per view. Destructive actions are red with white text, the same height as the buttons beside them.

Segera diApp Store

Controls

Segmented

Malam iniBesokAkhir pekan

Chips & status

18/32 pemain 1 kursi lagi Ranked   Arriving Checked in Refunded

Toggle

Time slots (½ = half price)

17:00
17:30
18:00
18:30

Lists & cards

Grouped lists for lists, and one raised card per view for the thing that matters now. Not everything is a card.

Balai Mahjong Tiga Naga
Bandung · 2,1 km · ★ 4,9
Rp 60rb/jam
Rumah Bambu Hijau
Bandung · Buka s/d 23:00
Rp 75rb/jam
20:003 jam
Riichi santai
1 lagi
Balai Mahjong Tiga Naga · Rp 45rb
A
D
P
+

Data

Numbers are Archivo 800–900, tabular. Leaderboards are compact: place, name, points. Top three sit on gold, silver and bronze tiles. The viewer’s own row is tinted green.

Papan peringkat
#PemainPoin
1DDewi+214,6
2AAgus+188,1
3KKamu+142,0
Paid bookings today18▲ 4
Booking valueRp 3,42 jt▲ 12%

Game

The score tracker keeps the plus board that already works. East is on top. Winds are text labels. The corner shows the round as a big 東 over “East - 2”. Honba is in English. Player cards are raised because they are tappable.

East - 2
EastDealer
Kamu
28.000
Honba1×1
South
Dimas
18.000
NorthRiichi
Wira
22.600
West
Lia
31.400

POS

Every table is a card headed by its number on a tile. The card’s state shows in both colour and words: live (felt), ending (red), due (gold outline), free (outlined), blocked (striped).

1Main
1:24
s/d 21:00
2Segera
0:06
tersisa
320:00
Andi +3
Lunas
4Kosong
s/d 21:30

Motion

Small, physical and quick. Everything is readable at rest, and all motion switches off for anyone whose device is set to reduce motion.

Press

Tiles and buttons sink 2–3px with their edge shrinking. 90ms.

Lift

Cards rise 4px on hover and tiles tip −8° with a spring. 350–450ms.

Settle in

Cards rise 18px into place as they scroll in, staggered 70ms. Transform only, never hidden first.

Count up

Scores and money count up once when first seen. 1.1s ease-out.

Pop

Taking a seat or picking a slot scales 0.5 → 1.15 → 1. Spring.

Live

Only live things pulse: the red square on an active booking, an ending table’s clock.

Voice

Do
  • Indonesian by default, English as a switch. Admin is English.
  • Talk to “kamu”, the player; talk to the venue as the team that runs it.
  • Keep proper nouns: Riichi, Hong Kong, ITM, QRIS, Cari Kaki, chombo, Honba.
  • Rupiah as Rp 60.000, times in WIB, dates like “Rab, 23 Sep”.
  • Buttons say exactly what happens: “Pesan meja”, “Tagih Rp 138.000”.
Don’t
  • Show the payment provider’s name (“Pivot”) to venues or players. Say “gateway pembayaran”.
  • Use emoji as icons or avatars. Avatars are monograms.
  • Name real venues on marketing pages. Promo stays Bandung-only.
  • Write “3/4 players”. Show the seats.

Component catalogue

The shared components every surface uses. Web versions live in @kaki/ui-web, native versions in @kaki/ui-native; both take the same props and read the same tokens from @kaki/design-tokens.

ComponentUsed byVariants / props
Tileallsize xs/sm/md/lg · glyph · tone default/grn/red · haku (blank) · faceDown · locked · medal 1/2/3
TileButtonallprimary/ivory/danger/done · size sm/md · loading · disabled · icon
Chip · StatusPillallneutral/felt/hot · paid/due/done/refunded/…
Segmented · Tabsallitems · value · onChange · size
Group · Cellallleading (tile/avatar/icon) · title · meta · trailing (price/chevron/switch)
Card · LiveCardallraised · pressable · deep panel
Avatar · AvatarStackallimage or monogram · you (red ring) · +N
Sheet · Dialog · Toastallcapped height (shrinks), destructive confirm, success toast
EmptyState · ErrorState · Skeletonalltitle · body · action; no emoji
TitleDot (large title with red square)alleyebrow · title · trailing
SlotPicker · DayStripweb, app, POSslots · sold · halfPrice · :30 starts · trading night
OpenTableCardweb, appvariants A (tile row), B (compact), C/C2/D (invite cards)
Ticketweb, appbooking code (mono) · QR · wallet · share
LeaderboardTableweb, app, POS, admincompact 3-col · medal tiles · me row
ScoreBoard · SeatCard · RoundCornerweb /game, appplus board · East top · dealer/riichi · font-scale safe
TableCard · BillPanel · TimelinePOS (web + native)live/ending/due/free/blocked · QRIS/Tunai/Kartu · Jadwal rows
KpiCard · NeedsYouList · BarChartadmin, ownertrend · sparkline · sample-safe empty
SiteNav · SiteFooter · SideNavweb · admin/ownerID/EN switch · grouped sections · badges