Skip to content
open tomato/ design-to-code
GitHub
design-to-code pages
  1. design-to-code
  2. Getting started

Getting started

Import a design export, read its discovery report, check every page loads, and choose which pages to keep.

This page takes a small export of two pages, Homepage.html and Homepage v2.html, from import to a choice of which page to keep. Every verb runs from the root of the design-to-code repository.

Before you start

You need Bun and git. serve --check and the later stages drive Chromium through Playwright, a browser automation library, so the setup step installs it.

git clone https://github.com/open-tomato/design-to-code.git
cd design-to-code
bun install
bun run setup

bun run setup runs playwright install chromium, which downloads Chromium into Playwright's cache in your home folder. [verify: bun run setup was not run for this page; Chromium was already in the cache, and the clone and bun install ran as written.]

Name your project

A project is one JSON file in projects/, named after its slug. The slug is lowercase letters and digits, with hyphens between runs. source.dir is where the export will be copied, relative to the repository root.

{
  "slug": "homepage",
  "source": { "dir": "design/homepage" }
}

Save it as projects/homepage.json. Every verb reads the project named by the environment variable D2C_PROJECT.

Import the export

import copies a folder or a .zip into source.dir, and writes a record of every file with its hash. The folder need not exist yet.

D2C_PROJECT=homepage bun run d2c import --source=../export-homepage
$ bun bin/d2c.ts import "--source=../export-homepage"
d2c import: 2 files (folder) imported into design/homepage

A second import into a folder that is not empty refuses, and names --force, which empties it first. A zip made by macOS Finder's "Compress" works as it is: its __MACOSX/ folder and .DS_Store files are left out.

Check the config

config prints the project's config with every default filled in. Run it after the import, because the loader refuses a source.dir that does not exist:

D2C_PROJECT=homepage bun run d2c config
$ bun bin/d2c.ts config
{
  "source": {
    "dir": "design/homepage"
  },
  "storybook": {
    "mode": "managed"
  },
  "levels": [
    "particles",
    "atoms",
    "molecules",
    "organisms",
    "templates",
    "layouts"
  ],
  "slug": "homepage",
  "name": "homepage",
  "target": {
    "kind": "component-library",
    "dir": "components/homepage"
  },
  "baselineDir": "baselines/homepage"
}

Run before the import, the same command exits 1:

$ bun bin/d2c.ts config
d2c config: projects/homepage.json: source.dir: 'design/homepage' does not exist (…/design/homepage)
error: script "d2c" exited with code 1

Read what is in it

assess --scripts-only lists every page, script, stylesheet, token file and asset, and writes the list to discovery.json in source.dir:

D2C_PROJECT=homepage bun run d2c assess --scripts-only
$ bun bin/d2c.ts assess --scripts-only
d2c assess: 2 pages, 0 token files, 0 variant maps; wrote design/homepage/discovery.json (scripts only)

Each page in the report counts its data-* attributes. Here Homepage.html shows "data-component": 3, which the seed stage reads later.

NOTE

Without --scripts-only, assess also starts one Claude session, through claude -p with no tools, to add notes on each page's role and on which pages are versions of the same thing. That session counts against your Claude usage. It was not run for this page.

Check that every page loads

serve --check loads every kept page in a headless browser and reports console errors, failed requests and blank pages in serve-check.json. It exits 1 when any page has one.

D2C_PROJECT=homepage bun run d2c serve --check
$ bun bin/d2c.ts serve --check
d2c serve: checked 2 pages at http://127.0.0.1:4600/; wrote design/homepage/serve-check.json

The server never rewrites a page to make it work, because the export is what everything later is compared against. A broken page goes back to the designer.

Choose the pages to keep

serve without --check serves the export at a local address with a navigation bar on every page, and runs until you stop it with Ctrl-C. D2C_PORT picks the port; unset, it takes the first free one from 4600.

D2C_PROJECT=homepage D2C_PORT=4655 bun run d2c serve
$ bun bin/d2c.ts serve
d2c serve: serving design/homepage at http://127.0.0.1:4655/

The address on its own answers "not found" unless the export has an index.html, so open one of the pages under it, such as http://127.0.0.1:4655/Homepage.html. The navigation bar on that page lists every page in the export. Compare the two versions, and press Discard on the one you do not want. The button writes your choice into pages.discard in the project file. [verify: the buttons were not pressed for this page; the request they send to /__d2c/pages was, and it wrote pages.discard.] You can also write it yourself:

{
  "slug": "homepage",
  "source": { "dir": "design/homepage" },
  "pages": { "discard": ["Homepage v2.html"] }
}

A page in pages.discard is left out of every later stage. Every other page is kept.

Next

From pages to components captures a baseline of the kept pages and lists the components to build.