# Quick Start

Source: /tuil/docs/introduction/quick-start
Locale: en

Create, run, and extend your first tuil application.



## Prerequisites [#prerequisites]

* Bun 1.3.14 or newer
* A terminal with color and Unicode support
* React experience; Ink experience is useful but not required

## Create the application [#create-the-application]

The initializer owns package selection, configuration, application structure,
and the first runnable screen:

<CodeBlockTabs defaultValue="npm">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="npm">
      npm
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="pnpm">
      pnpm
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="yarn">
      yarn
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="bun">
      bun
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="npm">
    ```bash
    npx @mwillbanks/tuil create my-terminal-app
    cd my-terminal-app
    npm run dev
    ```
  </CodeBlockTab>

  <CodeBlockTab value="pnpm">
    ```bash
    pnpm dlx @mwillbanks/tuil create my-terminal-app
    cd my-terminal-app
    pnpm run dev
    ```
  </CodeBlockTab>

  <CodeBlockTab value="yarn">
    ```bash
    yarn dlx @mwillbanks/tuil create my-terminal-app
    cd my-terminal-app
    yarn dev
    ```
  </CodeBlockTab>

  <CodeBlockTab value="bun">
    ```bash
    bun x @mwillbanks/tuil create my-terminal-app
    cd my-terminal-app
    bun run dev
    ```
  </CodeBlockTab>
</CodeBlockTabs>

The generated entry point defines one application boundary and passes it to the
Ink renderer:

```tsx
import { createApp } from "@mwillbanks/tuil";
import { Box, Heading, Text, render } from "@mwillbanks/tuil-ink";

function App() {
  return (
    <Box flexDirection="column" padding="md">
      <Heading>My first tuil</Heading>
      <Text label="Status">Runtime ready.</Text>
    </Box>
  );
}

const app = createApp({
  id: "my-terminal-app",
  component: App,
});

const instance = render(<App />, { app });
await instance.waitUntilExit();
```

## Add a component [#add-a-component]

Registry components are copied into your project so you own their source:

<CodeBlockTabs defaultValue="npm">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="npm">
      npm
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="pnpm">
      pnpm
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="yarn">
      yarn
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="bun">
      bun
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="npm">
    ```bash
    npx @mwillbanks/tuil add button field text-input
    ```
  </CodeBlockTab>

  <CodeBlockTab value="pnpm">
    ```bash
    pnpm dlx @mwillbanks/tuil add button field text-input
    ```
  </CodeBlockTab>

  <CodeBlockTab value="yarn">
    ```bash
    yarn dlx @mwillbanks/tuil add button field text-input
    ```
  </CodeBlockTab>

  <CodeBlockTab value="bun">
    ```bash
    bun x @mwillbanks/tuil add button field text-input
    ```
  </CodeBlockTab>
</CodeBlockTabs>

The CLI resolves transitive registry dependencies, detects every destination
conflict before writing, and leaves unrelated project files untouched.

## Add runtime behavior [#add-runtime-behavior]

Define events next to the application boundary:

```tsx
import { createApp, defineEvents, event } from "@mwillbanks/tuil";

const app = createApp({
  component: App,
  events: defineEvents({
    "task:completed": event<{ id: string }>(),
  }),
});

app.events.on("task:completed", ({ payload }) => {
  console.log(`Completed ${payload.id}`);
});
```

Continue with [What is tuil?](./what-is-tuil), then use the
[architecture guide](/tuil/docs/concepts/architecture) to choose the right package
boundaries.
