Manual Setup without MCP
Download your tokens and use Bezel Kit to generate files for your app. This works on all plans, including Free, without MCP or an AI assistant.
You'll need Node.js 22.13+ and a Bezel project with tokens. Run these commands from your app's directory, using its package manager; the examples use npm.
1. Install Bezel Kit
npm install --save-dev @bezel-labs/bezel-kit
2. Download your tokens
In Bezel, open your project and click Download in the app header.
Save it as design-tokens.json in your app's root directory.
3. Create bezel.json
npx bezel init
This creates bezel.json. Generated files go in src/bezel/, or bezel/ if your app has no src folder. TypeScript projects also get context and font modules.
For a custom folder, use npx bezel init --dir <path>. To change an existing setup, edit the output paths in bezel.json.
4. Generate files and connect your app
Add a tokens script and run it before your existing dev/build commands. This example uses Vite:
{
"scripts": {
"tokens": "bezel build",
"dev": "npm run tokens && vite",
"build": "npm run tokens && vite build"
}
}
Generate your files:
npm run tokens
Import the CSS once in your entry file, adjusting the path to match your output folder:
import './bezel/variables.css';
Use the generated CSS variables in your app. See how names are chosen if a variable is missing or has an unexpected name.
Generated files are overwritten by builds and added to .gitignore; keep handwritten code outside those output paths.
5. Live preview (optional)
Crystal lets Bezel's preview panel apply token edits to your app live:
- Install Crystal (recommended): enable the receiver in all builds, including production.
- Install Crystal behind a dev flag: enable the receiver only in development.
- Skip Crystal: use generated tokens without live preview.
If you already have Crystal configured, you can keep your existing setup.
Install Crystal (recommended)
npm install @bezel-labs/crystal
Initialize it once in your browser entry or client lifecycle:
import { startLivePreviewReceiver } from '@bezel-labs/crystal';
const receiver = startLivePreviewReceiver({
allowedOrigins: ['https://app.bezel.new']
});
Install Crystal behind a dev flag
npm install --save-dev @bezel-labs/crystal
For a Vite browser entry, place the dynamic import inside the development guard:
if (import.meta.env.DEV) {
import('@bezel-labs/crystal').then(({ startLivePreviewReceiver }) => {
const receiver = startLivePreviewReceiver({
allowedOrigins: ['https://app.bezel.new']
});
import.meta.hot?.dispose(() => receiver.stop());
});
}
For other frameworks, use their development flag and browser lifecycle. For example, Next.js uses process.env.NODE_ENV !== 'production', with receiver initialization inside a client effect.
Verify that your production build excludes the receiver.
For either option, avoid initialization during server rendering and call receiver.stop() during lifecycle cleanup to prevent duplicate listeners.
Keep the origin allowlist explicit. In Bezel's preview panel, set Preview URL to your running app or Storybook URL, then edit a token to check that it updates live.
Keep the default nameExtension in bezel.json so live preview and generated CSS use matching variable names.
For nested iframes such as Storybook, see the Crystal relay setup.
6. Update tokens manually
After changing tokens in Bezel:
- Click Download again.
- Replace your app's
design-tokens.jsonwith the downloaded file. - Run
npm run tokens.
Live preview does not update your local token file. Download and rebuild to keep your changes.
Command reference
Run npx bezel --help for available commands and flags. See Bezel Kit for configuration and output details.
Next steps
- Quick Start using MCP — let your coding assistant manage setup and token syncing on Pro or higher
- Live Preview — templates, themes, and responsive views