---
title: Quickstart
description: Scaffold a deck with deckard init, run it, and change a slide.
sidebar:
  label: Quickstart
  order: 1
---

`deckard init` writes a Next.js app with a sample deck in it, installs the dependencies, makes the first commit, and typechecks the result.

## Scaffold a deck

1. **Run init**

    ```bash
    npx @thebuilder/deckard-cli init my-talk
    ```

    `init` installs with whichever package manager invoked it. Through `npx` that is npm, through `pnpm dlx` it is pnpm. It writes no `packageManager` field, so the deck is not locked to that choice, and later `deckard` commands read the lockfile.

2. **Start the dev server**

    ```bash
    cd my-talk
    npm run dev
    ```

    The app redirects `/` to the first slide. Arrow keys move through the deck.

3. **Edit a slide**

    Open `deck/slides.tsx`. Change the `title` of the first entry and save. The open slide updates.

## What it writes

<FileTree>

- my-talk/
  - app/
    - slides/
      - blocks/ (the block families, yours to edit)
      - [id]/page.tsx
    - presenter/page.tsx
    - page.tsx
    - sitemap.ts
    - not-found.tsx
    - layout.tsx
    - globals.css
  - deck/
    - deck.ts (the defineDeck config)
    - slides.tsx (the slide array)
  - lib/utils.ts
  - public/
  - components.json
  - next.config.ts
  - package.json

</FileTree>

The theme is not a file. `init` writes it as an import from `@thebuilder/deckard-themes` in `deck/deck.ts`, so `--theme phosphor` changes one identifier.

## init flags

| Flag | Default | What it does |
| --- | --- | --- |
| `--theme <name>` | `meridian` | Any built-in, listed on the [theme gallery](/themes). |
| `--empty` | off | A bare deck instead of the sample one. |
| `--package-manager <name>` | detected | `bun`, `npm`, `pnpm`, or `yarn`. |
| `--no-install` | install runs | Write the files and stop. Skips the typecheck too. |
| `--no-git` | git runs | Skip `git init` and the first commit. |
| `--registry <url>` | `https://deckard.thebuilder.dk/r/{name}.json` | The `@deckard` registry written into `components.json`. |
| `--core-tarball <path>` | `^<cli version>` | Install `@thebuilder/deckard-core` from a local tarball instead of npm. |
| `--themes-tarball <path>` | `^<cli version>` | Same, for `@thebuilder/deckard-themes`. |
| `--cli-tarball <path>` | `^<cli version>` | Same, for `@thebuilder/deckard-cli`. |

`init` refuses a directory that already has files in it. It asks no questions.

## The blocks

The slide blocks ship inside the CLI package, and `init` copies them into `app/slides/blocks/`, where they are source you edit. Adding a block later fetches it from the registry the docs site serves. See [Blocks and the registry](/guides/blocks-and-the-registry).

## Adding a deck to an app you already have

`init` writes a new directory. Do the same four things by hand when the deck has to live inside an existing Next.js app.

1. **Install the packages**

    ```bash
    pnpm add @thebuilder/deckard-core @thebuilder/deckard-themes
    pnpm add -D @thebuilder/deckard-cli playwright pdf-lib
    ```

    `playwright` and `pdf-lib` are what `check-overflow`, `screenshots`, `contact-sheet`, and `export pdf` load from the deck. Leave them out if the deck will only ever be presented.

2. **Import the stylesheet**

    ```css app/globals.css
    @import "tailwindcss";
    @import "@thebuilder/deckard-core/styles.css";
    ```

    That sheet carries the `--slide-*` token contract and registers the package's own compiled output as a Tailwind source, so the runtime's utility classes survive without you naming a path inside `node_modules`. There is no `transpilePackages` entry to add.

3. **Install the slide blocks**

    ```bash
    pnpm dlx shadcn@latest add https://deckard.thebuilder.dk/r/preset-blocks.json
    ```

    This writes the block source and its barrel to `app/slides/blocks/`. The Introduction imports from that barrel.

4. **Write the deck**

    Create `deck/deck.ts` and `deck/slides.tsx` as shown on the [Introduction](/introduction).

5. **Re-export the four routes**

    ```tsx app/slides/[id]/page.tsx
    import { createSlideRoute } from "@thebuilder/deckard-core/next"
    import { deck } from "@/deck/deck"

    const { Page, generateMetadata, generateStaticParams } =
      createSlideRoute(deck)

    export { generateMetadata, generateStaticParams }
    export default Page
    ```

    The other three are `app/presenter/page.tsx`, `app/sitemap.ts`, and `app/page.tsx`. See [Route adapters](/reference/core#route-adapters).

Run `deckard doctor` afterwards. It checks exactly these things and names the one you missed.

## Next steps

<CardGroup cols={2}>
  <Card title="Writing slides" href="/guides/writing-slides" icon="file-text">
    Which block to reach for, and when a slide earns its own file.
  </Card>
  <Card title="Presenting" href="/guides/presenting" icon="presentation">
    Keys, the command center, the presenter window, notes, step reveals.
  </Card>
</CardGroup>
