# Start a screen from a template

squiggle add screen writes a new screen that already has what the report card checks: a handle on every control, a flow that drives it, its declared controls and a renders budget it meets.

## Before you start

- An app set up with `squiggle init`. The screens use `agentHint` from `@squiggle.sh/react-native`.
- Expo Router, to get a route written for you. Without it you get everything else, and the command tells you which component to mount.

## Add a screen

Name the kind, then the route. The route name is lower-case letters, digits and dashes; leave it out and the screen is named after its kind.

```shell
squiggle add screen list orders
```

Output:

```text
add screen list orders · A searchable list of rows, with a count, a selection and an empty state.
  ✔ the list template: src/screens/orders.tsx
  ✔ its route: src/app/orders.tsx
  ✔ its flow: .squiggle/flows/orders.yaml
  ✔ its interface: .squiggle/interfaces/orders.json
  ✔ its budget: rendersPerTap 60: .squiggle/config.jsonc

  squiggle flow orders                      drive it
  squiggle card --files src/app/orders.tsx  its report card
```

Then run its flow, and its card:

```shell
squiggle flow orders
```

```shell
squiggle card --files src/app/orders.tsx
```

## The six kinds

| Kind | What you get |
| --- | --- |
| `list` | A searchable list of rows, with a count, a selection and an empty state. Rows are drawn by a plain ScrollView; switch to FlatList past about a hundred rows. |
| `form` | Name, email and message fields, checked when you press Send, with an error under each field and a sent state. |
| `auth` | Email and password sign-in with a busy state and an error. Pass your own check as signIn; the default accepts any well-formed email with a password of eight or more characters. |
| `detail` | A grid of tiles. Pressing one opens its detail, and the tile’s artwork grows into the detail’s header. |
| `settings` | Toggles with an On/Off readout, a Delete account button that asks twice, and Done. |
| `onboarding` | Pages with Next, Back and Skip, ending in Get started. |

Each screen comes with sample data, so it runs before you connect it to anything. Replace the sample data and the default callbacks with your own.

Try each one below. The phone runs the same file `squiggle add screen` writes, its flow drives it, and the report card is built from that run.

## What it writes

| File | What it is |
| --- | --- |
| `src/screens/<name>.tsx` | The screen, as one file you own. It imports only react-native and @squiggle.sh/react-native. Without a src folder, it goes in screens/. |
| `src/app/<name>.tsx` | The route that shows it. Props that leave the screen, such as onDone, call router.back(). |
| `.squiggle/flows/<name>.yaml` | A flow that opens the screen, uses it, asserts what changed on screen, and goes back, so the next run starts the screen fresh. |
| `.squiggle/interfaces/<name>.json` | Every control the screen draws when it opens, with its testID. The report card checks the running screen against them, so when you add a control with a testID, add it here too, or the card’s interface row fails. |
| `.squiggle/config.jsonc` | A budget for the screen: at most 60 renders for any one tap. Your other settings and comments stay as they are. |

The route for a settings screen named prefs:

```shell
import { router } from 'expo-router';

import { SettingsScreen } from '../screens/prefs';

export default function PrefsRoute() {
  return <SettingsScreen onDone={() => router.back()} />;
}
```

## Options

| Flag | What it does |
| --- | --- |
| `--app-dir <dir>` | The app’s directory, when you run it from somewhere else, such as the root of a monorepo. The flow, the interface and the budget still go in the project’s .squiggle folder. |
| `--dry-run` | Lists every file it would write, and writes none. |
| `--force` | Overwrites files that already exist. |
| `--json` | Prints each file with its status: written, planned, exists or todo. |

## When something is already there

- **A file exists.** It is left alone and listed as skipped. Add `--force` to overwrite it, or pick another name.
- **The screen already has a budget.** It is never changed, with or without `--force`.
- **Your config can’t be edited safely.** The command writes everything else and prints the budget line to add yourself.
- **An unknown kind or a name with spaces or capitals** stops it with exit code 2 and the kinds it has.

> **Two screens of one kind**
>
> Two screens from the same template share control names, such as `list-search`. A flow that runs on one screen at a time is fine; rename the handles in one copy if both are ever on screen together.

## How the templates are checked

Every template runs in Squiggle’s own CI, inside the demo app the [web Studio](https://squiggle.sh/) drives, with its flow and its report card. A change that turns a template’s card red fails that CI run: every control has to be reachable by name, its flow has to pass, and no tap may cost more than 60 renders. See [The report card](https://squiggle.sh/docs/run/card) for what each row means.
