> ## Documentation Index
> Fetch the complete documentation index at: https://substrate.docs.unknowncreatives.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart: Integrate Substrate into Your Project

> Vendor the Substrate engine, run substrate init, wire the three import aliases, and initialize the runtime solver — every step verified against the real CLI.

This guide walks you through the **vendored-checkout** integration path: getting the Substrate engine into your repo, running `substrate init`, wiring the three public import aliases, and initializing the runtime so your app computes APCA-solved token values. By the end, your app renders through the Substrate cascade and you've verified it. APCA attribution and use restrictions: see [About APCA](/reference/apca-solver#about-apca).

<Warning>
  The package is `@unknown-creatives/substrate`; a bare `npx substrate` still installs an unrelated third-party package — always use the scoped name.
</Warning>

## 1. Obtain Substrate

The CLI comes from npm: `npx @unknown-creatives/substrate <cmd>`. The **engine** is delivered separately and is never published to npm — clone the Substrate checkout you received from Unknown Creatives **outside** your project, then vendor the engine into your repo:

```bash theme={null}
# Clone Substrate outside your project. No install step needed —
# the published CLI brings its own dependencies.
git clone <substrate-repo-url> ~/substrate
SUBSTRATE_REPO=~/substrate

# Vendor the engine: sealed engine dirs go to substrate/engine/,
# pipeline outputs seed substrate/generated/ (a sibling, NOT inside engine/)
cd ~/my-app
mkdir -p substrate/engine
for d in src skills agents references knowledge scripts; do
  cp -R "$SUBSTRATE_REPO/$d" "substrate/engine/$d"
done
cp -R "$SUBSTRATE_REPO/generated" substrate/generated
```

None of these directories need `node_modules` or any install step inside your repo. Vendor the whole `src/` directory — if `src/kernel/`, `src/platforms/`, or `src/types/` is missing, `init` reports each as a blocker and exits non-zero.

Before running `init`, confirm the layout is detectable (`--dry-run` writes nothing):

```bash theme={null}
npx @unknown-creatives/substrate init --dry-run --platform claude-code
```

The first line must read `Found Substrate (client): substrate/engine`.

## 2. Run `substrate init`

From your project root:

```bash theme={null}
npx @unknown-creatives/substrate init
```

Every bare `substrate <cmd>` spelling in the rest of this guide means that scoped npx invocation.

<Note>
  Working on Substrate itself? Run the bin from your checkout instead — after `(cd "$SUBSTRATE_REPO" && npm ci)`, a shell function makes the bare spelling literal: `substrate() { node "$SUBSTRATE_REPO/packages/cli/bin/substrate-init.js" "$@"; }`
</Note>

`init` prints the Substrate it found, lets you pick which AI tools to configure, links the Substrate skills and the Bloom agent into each selected tool, scaffolds the client overlays, writes `.substrate/state.yaml`, and sets up the import aliases. Non-interactive alternatives:

```bash theme={null}
substrate init --all               # configure every supported platform
substrate init --platform cursor   # configure exactly one platform
substrate init --dry-run           # preview every action, write nothing
```

<Note>
  The `--platform` flag selects an **AI coding tool** (`claude-code`, `cursor`, `windsurf`, …) — it is not an output-target selector. Re-running `init` is idempotent, and `substrate init --refresh` replays your recorded selections. The full CLI surface is `init`, `add`, `upgrade`, `adopt`, `setup`, and `artifact`.
</Note>

## 3. Wire the three public aliases

Client code imports Substrate through exactly three public aliases — this is the whole import contract, and an engine swap never changes these import statements:

| Alias                     | Resolves to (client repo)       | Use it for                                                     |
| ------------------------- | ------------------------------- | -------------------------------------------------------------- |
| `@substrate/engine`       | `substrate/engine/src/index.ts` | the runtime engine API (APCA solver, token sync)               |
| `@substrate/components/*` | `substrate/components/*`        | client-owned components (`Surface`, `Button`, catalog entries) |
| `@substrate/generated/*`  | `substrate/generated/*`         | pipeline output — the generated CSS, registries, intermediates |

`init` **auto-writes** the aliases into `tsconfig.json` (idempotent; it manages only the `@substrate/*` zone and never touches your other options):

```jsonc theme={null}
{
  "compilerOptions": {
    "paths": {
      "@substrate/engine": ["./substrate/engine/src/index.ts"],
      "@substrate/components/*": ["./substrate/components/*"],
      "@substrate/generated/*": ["./substrate/generated/*"]
    }
  }
}
```

Bundler and test configs are code, so `init` doesn't edit them — it writes an importable manifest, `.substrate/aliases.js`, that you spread into your bundler's alias config:

```ts theme={null}
// vite.config.ts
import { defineConfig } from 'vite';
import { substrateAliases } from './.substrate/aliases.js';

export default defineConfig({
  resolve: { alias: substrateAliases },
});
```

To reprint every block without touching disk, run `substrate init --report-aliases`.

## 4. First import

Two things run at app startup: load the **generated CSS barrel** once at your app entry (it establishes the full cascade), then initialize the **engine** — the runtime APCA solver, the only JS Substrate requires. On the vendored path you add this yourself; on the supervised `substrate setup` path this exact module is generated for you as `src/substrate.setup.ts`:

<RuntimeInitExample />

Any element then opts into the cascade with `data-ucs` plus a `data-mode` role (the full attribute contract is on [Markup Opt-In](/markup)):

<MarkupOptInExample />

To move along the scheme axis (light ↔ dark), update the preference vector and re-sync — the CSS reacts automatically:

```ts theme={null}
prefs.scheme = prefs.scheme === 0 ? 1 : 0;
syncPrefsToCssVars(prefs);
updateAllVars(brand, prefs);
```

There is no theme attribute to toggle: `scheme` is a continuous value (0 → 1), the runtime sets `data-brand` on the root itself, and named modes like `dark` or `highContrast` are presets over the same continuum — see [Core Concepts](/core-concepts#modes).

## 5. Verify

These checks need nothing beyond Node and what `init` wrote:

```bash theme={null}
# 1. Detection: prints `Found Substrate (client): substrate/engine`, writes nothing.
substrate init --dry-run --platform claude-code

# 2. Alias wiring: every @substrate/* target init wrote resolves on disk.
node --input-type=module -e "
import fs from 'node:fs';
import RuntimeInitExample from '/snippets/runtime-init-example.mdx';
import MarkupOptInExample from '/snippets/markup-optin-example.mdx';
const { substrateAliases } = await import('./.substrate/aliases.js');
for (const [alias, target] of Object.entries(substrateAliases)) {
  if (!fs.existsSync(target)) { console.error('MISSING', alias, '->', target); process.exit(1); }
  console.log('OK', alias, '->', target);
}
"

# 3. The generated CSS barrel is present.
node -e "require('node:fs').accessSync('substrate/generated/global/css/index.gen.css'); console.log('OK css barrel')"
```

To prove the engine itself is sound, run its always-on suite **in the Substrate checkout** (the vendored engine deliberately ships no test runner):

```bash theme={null}
cd "$SUBSTRATE_REPO" && npm run test:unit
```

## 6. Discover catalog content

Substrate ships a catalog of starting-point content — component configs, brand configs — that you scaffold into your client-owned content root as you need it:

```bash theme={null}
substrate add --list                                        # see what's available
substrate add components/badge --generate-command "npm run generate"
```

`add` scaffolds the entry's files with provenance headers, records the fetch in `.substrate/manifest.yaml`, and runs your generate command so the pipeline picks the new config up immediately.

***

<CardGroup cols={2}>
  <Card title="Runtime & Imports" icon="plug" href="/integration">
    The required wiring in depth: the alias contract, the three-call sequence, and the OS preference helpers.
  </Card>

  <Card title="Surface Component" icon="layer-group" href="/surface-component">
    Required when surfaces nest — cards, panels, insets — so contrast is re-solved against the local background.
  </Card>

  <Card title="Core Concepts" icon="lightbulb" href="/core-concepts">
    The runtime-solver mental model: intents, the preference vector, APCA solving per surface, and the cascade.
  </Card>

  <Card title="Brand Config Overview" icon="sliders" href="/brand-config/overview">
    Author your own brand: the YAML schema, the open intents map, and the flexibility bounds.
  </Card>
</CardGroup>
