shodo is an expressive, malleable visual layer for the web: sharp text that dissolves, scrambles and flows, paint that mixes like pigment, and fields of colour, grain and glass. It sits on top of spryte.
The icon is a single rounded outline with four soft lobes, drawn as one stroke with round ends, like a brush loop. It holds still; the text around it is what moves. Source: brand/assets/icon.svg.
Below 32 px use favicon.svg: the same outline with a heavier stroke. brand/icons.mjs renders the PNG app icons from icon.svg.
The wordmark is the word shodo set in Genoid Bold, always lowercase. Next to the icon it makes the lockup. On the site shodo itself draws it, so it can take the house effects. Say it “shodo”, never “Shodo” or “SHODO”.
Clear space is the height of the o on every side. Never stretch, outline, add a shadow or set the wordmark in another font. Genoid is a demo licence until bought; League Spartan Black is the fallback.
Ink and white carry every page, with fog for quiet surfaces and night for dark grounds. Cobalt is the one accent: a link, a button, a highlight, once per screen. The field colours are for colour fields, art and cards, where shodo paints, blurs and grains them; they don't carry interface text.
| pair | contrast | use |
| ink on white | 16.6 : 1 | AAA |
| ink on fog | 14.9 : 1 | AAA |
| ink on paper | 13.6 : 1 | AAA |
| cobalt on white | 7.1 : 1 | AAA |
| white on cobalt | 7.1 : 1 | AAA |
| ink on orange | 5.8 : 1 | AA |
| ink on pink | 7.1 : 1 | AAA |
| ink on yellow | 11.0 : 1 | AAA |
| white on night | 19.6 : 1 | AAA |
Contrast ratios computed with the WCAG relative-luminance formula. Before 2026-11-09 the palette was pale blurples (mist, haze, lilac, peri, blurple, ink, deep); those tokens stay in tokens.css for old versions.
Genoid for the wordmark-sized moments: hero lines and big display words. Geist for section and card titles, Public Sans for reading, Geist Mono for code and labels. Everything is set in lowercase except code. Genoid is still a demo licence and only loads locally; Geist, Public Sans and Geist Mono are open fonts. Never Bricolage Grotesque.
Body copy sits in Public Sans at 16 px with generous line height. Keep lines near 62 characters and let headings wrap in balanced lines.
draw.sprites(frames, data, n, opts, { stride: 4, frame: 2, user: 3 })The icon language borrows from the logo: soft round ends, circles instead of corners, and a single moving idea per icon.
Shapes in shodo are liquid. Containers change their corner radii when hovered, blobs merge when they get close, and nothing snaps. Move the pointer over the field.
drag or hover: metaballs merge when they touch
cubic-bezier(.34, 1.56, .64, 1)
For anything that arrives: a chip, a swatch, a button under the pointer. Slight overshoot, 160 to 300 ms.
cubic-bezier(.45, 0, .2, 1)
For shape changes: radii and blobs. Long and smooth, 400 to 700 ms.
With reduced motion on, blobs stop drifting and hover only changes colour.
“Dissolve text edge-first.” Not “Unlock next-generation typographic experiences.”
shodo starts lowercase, even at the start of a sentence, like spryte.
Fonts baked for Lettra load unchanged. Say so, and never imply the JOYCO team is involved.
:root {
/* shodo palette before 2026-11-09 (retired; kept for old versions) */
--shodo-mist: #F2F0FF;
--shodo-haze: #E2DDFF;
--shodo-lilac: #CCC4FF;
--shodo-peri: #A99EFF;
--shodo-blurple: #7A67F5;
--shodo-ink: #1B1450;
--shodo-deep: #120E33;
/* Added 2026-11-08 for the splash page footer: a near-black ground under the wordmark (docs/decisions.md). */
--shodo-night: #0B0920;
/* Palette since 2026-11-09. Base: ink and white, fog for quiet surfaces. Accent: cobalt, once per screen.
Field colours for colour fields, art and cards. The pale blurples above (mist to deep) are retired as the
brand palette and kept for old versions. */
--shodo-white: #FFFFFF;
--shodo-fog: #F3F2EF;
--shodo-cobalt: #2443E0;
--shodo-orange: #FF6A21;
--shodo-pink: #FF7EB6;
--shodo-paper: #F2E8C9;
--shodo-yellow: #F5CF2E;
/* shape and motion */
--shodo-radius-s: 14px;
--shodo-radius-m: 22px;
--shodo-radius-l: 36px;
--shodo-ease-spring: cubic-bezier(.34, 1.56, .64, 1);
--shodo-ease-flow: cubic-bezier(.45, 0, .2, 1);
--shodo-dur-fast: 160ms;
--shodo-dur-flow: 520ms;
}