Dua
Tinta

The design system of taufiqdp.com

Paste it into your AI agent, or save it as DESIGN.md in a repo.

Two inks

Every screen is two inks on paper: one dark ink for all type, one bright ink for accents.

Dua Tinta is Indonesian for two inks. The site reads like a risograph zine printed on newsprint, personal and a little loud, but the layout underneath stays plain and calm so the writing, photos and music carry it. Photographs are the one exception to the two-ink rule: they always show in their original colours, as shot.

Ink pairs
Five, switchable in the header
Typeface
Archivo, one family
Corners
Square, except a round few
Shadows
None, it's print

Colour

Three tokens do all the work: --ink, --pop and --paper. Never hard-code a hex value in a component, or the ink switcher stops working.

Ink

#3255A4. All text, headings, outlines, the now-playing bar and halftone dots.

Pop

#FF6C2F. Accents only: divider rules, link underlines, the halftone ground, equalizer bars.

Paper

#F4F4F1. The page ground, and the text colour on ink surfaces.

Ink pairs

Each pair is a type ink and an accent ink, set with data-ink on <html>. Pick one to repaint this page. Shared link previews always use the default pair.

Two fixed colours sit outside the pairs: a black scrim at 85% behind an opened photo, and the white ground of the round avatar.

Type

One family, Archivo, loaded with its width axis. The personality comes from width and weight extremes, not a second typeface. Headlines are always uppercase, condensed and heavy. Everything else is sentence case.

headline-displayFluid up to 176px, 900, 70% width, line height 0.84. The name.

Display

headline-xl80px, 900, 75% width, line height 0.9

Headline

headline-lgFluid 40 to 64px, 900, 75% width. Section headings.

Section title

headline-md32px, 800, 80% width, line height 1. Post titles.

Post title goes here

headline-sm24px, 800, 80% width, line height 1.25. Job and song titles.

Job title

body-lgFluid 20 to 26px, 400, line height 1.375. The lede.

A short lede introduces the page in a line or two.

body-md17px, 400, line height 1.5

Body text runs at normal width and weight, in sentence case.

body-prose17px, 400, line height 1.625, 68 characters max

Blog prose gets a little more air between lines and stops at 68 characters, so long posts stay easy to follow from one line to the next.

body-sm14px, 400, line height 1.4

Photo caption goes here

label-md14px, 700. Navigation.

Navigation

label-sm13px, 400. Dates, captions, fact labels.

January 1, 2026

codeRoboto Mono 14px, 500. Blog code only.

--ink: #3255a4;

Layout

From 768px up the home page is two columns. On the left, a sticky masthead: a 3:2 header photo with the name overlapping its bottom edge. On the right, sections scroll by, split by pop rules. Below 768px it all stacks into one column. Other pages are a single left-aligned column. Nothing is centred except an opened photo.
page-max-width1440px
Content stops growing past this width.
page-margin16, 24, 40px
Side margins on phones, tablets and desktop.
column-gap72px max
Between the masthead and the sections.
section-gap48px
Above each pop rule.
section-padding-top36px
Below each pop rule.
heading-gap24px
Below a section heading.
item-gap16px
Between items in a list.
gallery-gap8px
Between masonry photos, which keep their real aspect ratios.

Shape and depth

Print has square corners and no shadows. Hierarchy comes from type size and weight, the pop rules, and overlap: the name in the masthead sits on its photo with mix-blend-mode: multiply, so where it crosses the photo it darkens like overprinted ink.

Photos and blocks, 0
Avatar, round
Swatch, round
Pill
Pill, round
--pop
Inline code, 4px
ink + pop
Code block, 8px

Components

Links

Read the post

Ink text with a 2px pop underline, offset 4px. Navigation links show the underline on hover only.

List row

Jan 2026 – now
Job titleCompany name

Experience, songs and posts: a display-type title, a regular line under it, tabular figures for dates and counts.

Halftone placeholder

Ink dots on a 14px grid over pop, fading out diagonally. Stands in for any photo or cover that is loading or missing, and pulses gently unless reduced motion is on.

Now-playing bar

Now playingSong title Listen on Spotify

Fixed to the bottom of every page. Solid ink with paper text; the three pop bars bounce only while a song is playing. The whole bar is one link.

Ink switcher

Five two-dot swatches in the header. The selected one gets a 2px ink ring. The choice is saved per visitor and applied before first paint.

Do and don't

Do

  • Use only the ink, pop and paper tokens, so every pair works.
  • Show photographs in their original colours.
  • Set headlines uppercase, condensed and heavy.
  • Keep body text at 4.5:1 contrast or better, and check new pairs before adding them.
  • Give every photo real alt text and keep keyboard focus visible.
  • Stop the equalizer and loading pulses when reduced motion is on.
  • Credit outside data where it's shown, like “via Last.fm”.

Don't

  • Add a third colour or a grey.
  • Set text in pop, on paper or on ink.
  • Duotone or tint photographs.
  • Use uppercase for body text or labels.
  • Add drop shadows, rounded cards or gradient washes.
  • Round photos or blocks. Only the avatar, swatches and pills are round.
  • Centre content blocks. Keep the left edge strong.

Source

This page is drawn from design.md. In code, the source of truth is app/global.css. Drop these tokens into any page to print in Dua Tinta:

:root, [data-ink=orange] { --ink: #3255a4; --pop: #ff6c2f; }
[data-ink=pink]     { --ink: #0078bf; --pop: #ff48b0; }
[data-ink=green]    { --ink: #407060; --pop: #ffb511; }
[data-ink=burgundy] { --ink: #914e72; --pop: #ffe800; }
[data-ink=black]    { --ink: #000;    --pop: #ff4c65; }
:root { --paper: #f4f4f1; }