Build for Dunea

Quickstart: your first theme

Make a theme from tokens, fonts and a style guide, validate it, and submit it for review.

A theme is a single JSON file: design tokens, two or three fonts, and an art-direction guide that the Dunea AI follows when it designs an app. There is no server and no code. In this guide you build Harbour, a calm, nautical theme for local businesses.

You need Node.js 18 or later and a Dunea account.

Scaffold the theme

npx -p @dunea/plugin-sdk dunea-plugin init harbour --theme
cd harbour

This creates dunea.theme.json and a README.md.

Set the tokens

Open dunea.theme.json and set the listing details and tokens:

dunea.theme.json
{
  "schemaVersion": 1,
  "kind": "theme",
  "id": "harbour",
  "version": "0.1.0",
  "name": "Harbour",
  "tagline": "Calm navy and sand, with a crisp serif, for local businesses by the water.",
  "description": "Harbour pairs deep navy and warm sand with a crisp Fraunces serif and a quiet Inter text face. Generous spacing, square-ish corners and a single coral accent. Made for cafes, boat hire, guesthouses, surf schools and other local businesses that want to feel calm and trustworthy.",
  "icon": "https://example.com/harbour/icon.png",
  "screenshots": ["https://example.com/harbour/home.png"],
  "developer": {
    "name": "Your Studio",
    "supportEmail": "hello@example.com",
    "privacyUrl": "https://example.com/privacy"
  },
  "pricing": { "model": "free" },
  "categories": ["local-business", "minimal"],
  "tokens": {
    "colors": {
      "background": "#fbf8f3",
      "surface": "#f1ebe1",
      "text": "#14213d",
      "muted": "#5c6478",
      "primary": "#14213d",
      "primaryText": "#fbf8f3",
      "accent": "#e76f51",
      "border": "#e2d9cb"
    },
    "fonts": { "heading": "Fraunces", "body": "Inter" },
    "radius": 4,
    "density": "airy",
    "typeScale": 1.333
  },
  "guide": "...",
  "sections": []
}
  • Every colour is a #rrggbb hex. Check that text on background and primaryText on primary are easy to read.
  • Fonts must come from the allow-list.
  • Leave out darkColors for a single-mode theme, or add the same eight keys for a dark palette.

Write the guide

The guide is markdown, 200 to 12,000 characters, and it is what makes a theme feel designed. Write concrete instructions the AI can follow. In JSON, newlines are \n:

"guide": "## Mood\nA quiet harbour town on a clear morning: calm, honest, unhurried. Never loud, never salesy.\n\n## Layout\n- Wide margins and one idea per section. Separate sections with space and a single 1px rule in the border colour, never with coloured bands.\n- Left-align text. Keep paragraphs under 65 characters per line.\n\n## Typography\n- Headings in Fraunces at weight 600, tight leading; body in Inter at 16-17px, line-height 1.6.\n- Small labels in Inter, uppercase, tracked 0.12em, muted colour.\n\n## Colour\nNavy and sand carry the page. Coral is the accent: one button, link underline or numeral per screen, never a background.\n\n## Imagery\nNatural light, water, rope, wood and real people at work. No stock handshakes, no gradients, no illustrations of waves.\n\n## Motion\nGentle fades and 8px rises over 500ms. No bounces, no parallax.\n\n## Copy tone\nShort, plain sentences. Concrete details (opening hours, distances, prices). Buttons say what happens: \"Book a table\", \"See the timetable\".\n\n## Don't\n- No drop shadows or rounded pills.\n- Never more than one accent element per viewport."

Put the most important direction first: if the AI's brief runs long, the end of the guide is what gets trimmed. See Writing a great guide.

Add section recipes (optional)

Recipes describe how to build a particular section in your style. The AI fetches a recipe before it builds that section.

"sections": [
  {
    "name": "Hero",
    "recipe": "Full-width section on the background colour. Left 6 columns: a small uppercase label, a two-line Fraunces heading at the 5xl step, one sentence of body copy in muted text, and one primary button. Right 6 columns: a single landscape photo with 4px corners. On mobile the photo comes first."
  },
  {
    "name": "Opening hours",
    "recipe": "A two-column definition list on the surface colour: day names on the left in uppercase tracked labels, times on the right in the body face. 1px border-colour rules between rows. Today's row has a coral dot before the day name."
  }
]

Validate

npx -p @dunea/plugin-sdk dunea-plugin validate
OK dunea.theme.json: theme "harbour" v0.1.0
  guide: 1083 chars, sections: Hero, Opening hours

npx -p @dunea/plugin-sdk dunea-plugin check also runs the review checklist, including the contrast checks (DUN-T001, DUN-T002).

Publish and submit

Create a developer token in the Dunea developer portal, then:

export DUNEA_DEV_TOKEN=...
npx -p @dunea/plugin-sdk dunea-plugin publish --submit

This creates the listing, uploads 0.1.0 and submits it for review. If it prints a client secret, store it safely; themes do not receive webhooks, so you will not use it.

Track the review with:

npx -p @dunea/plugin-sdk dunea-plugin status harbour

Next steps

On this page