Start from a template
A template is a complete, working app that the CLI copies into a new folder for you: a game, an interactive piece or a community card. Each one builds, validates and scans clean as it stands, so you start from something that already runs on a token page and change it into yours.
The templates ship in the @chaindaddy/apps package, and chaindaddy app init takes them from there (CLI 0.6.0 or later).
| Template | What it is | Category | Tier | Bundle, built |
|---|---|---|---|---|
game | A three.js arcade game: a ship dodging blocks, a best score, fullscreen, and a shop that sells from your token's store | games | rich, 6x3 | about 440 KB, 116 KB gzipped |
interactive | A generative canvas piece that visitors draw on. You set its title and palette on your page, and holders can unlock a palette | interactive | standard, 4x3 | about 16 KB, 7 KB gzipped |
community | Your token's open poll with a vote weighted by holding, its links and its holder count, in one card | social | standard, 4x3 | about 8 KB, 4 KB gzipped |
Start one
Sign in once, then name the template and a folder:
npm install -g @chaindaddy/cli@beta
chaindaddy app login
chaindaddy app init game my-game
cd my-game
npm install
npm run devThe same for the others:
chaindaddy app init interactive my-piece
chaindaddy app init community my-community--template game does the same as naming it first: chaindaddy app init --template game my-game.
The folder's name becomes the app's name, and its id is <your developer ID>/<folder>. The CLI writes both into capp.json and package.json. Your developer ID comes from chaindaddy app login; without a login, pass it yourself (chaindaddy app whoami shows it):
chaindaddy app init game my-game --developer-id <your developer ID> --non-interactive| Option | What it does |
|---|---|
--developer-id <id> | Your developer ID. Defaults to the one from chaindaddy app login |
--id <id> | The app id, <developer ID>/<name>. Defaults to <developer ID>/<folder> |
--name <name> | The display name. Defaults to the folder's name in title case |
--description <text> | One line about the app. Each template has its own default |
--non-interactive | Fail instead of asking when something required is missing |
--templates-tag <tag> | The @chaindaddy/apps version or dist-tag to take the templates from. Defaults to latest |
--from <path> | Take the templates from a local copy (a cd-apps checkout, its templates folder, or a .tgz) instead of npm |
Without a template, chaindaddy app init widget my-widget scaffolds a blank widget, and headless or full adds a runner. See Build your first app.
What you get
my-game/
├── capp.json the manifest, with your id, name and developer ID filled in
├── package.json the scripts below, and @chaindaddy/cli as a dev dependency
├── tsconfig.json
├── .gitignore
├── README.md this template's guide
└── src/
├── index.tsx the component the page renders (capp.json's entryComponent)
├── ui.tsx the page's theme colors, and a button in them
├── host.ts the page's actions as promises that always answer
├── widget-types.ts the contract: the props and every action with its answer
└── … the template's own files, belowEvery template carries the same two helpers:
src/host.tssends every action to the page and always gets an answer back:ask()for any action, plus sign-in, platform API calls and toasts. Send your own actions through it.src/widget-types.tsis the contract between your app and the page: the props it's given, and every action it can send with the answer each one gets. It's a copy from the@chaindaddy/appsversion you started from.
game and interactive also carry src/store.ts: useIap, which reads your token's store (the catalog, what the viewer holds, prices) and buys one item at a time. See Store and Rewards.
Each template declares exactly the permissions and data scopes it uses, and its tier sets the bundle size the scan allows: standard up to 250 KB, rich up to 1 MB. If you add an action, add its permission to capp.json.
The scripts:
| Script | Runs | What it does |
|---|---|---|
npm run dev | chaindaddy app dev | Your app on a local token page, rebuilt on save. See Test locally |
npm run build | chaindaddy app build | dist/bundle.js: one ES module, React left to the page |
npm run typecheck | tsc --noEmit | Type-checks your code |
npm run validate | chaindaddy app validate | capp.json against the manifest schema |
npm run scan | chaindaddy app scan | The same size and security checks we run |
npm run pack | chaindaddy app pack | The .capp package |
npm run sign | chaindaddy app sign --in-place | Signs it with your API key |
npm run submit | chaindaddy app submit --watch | Uploads it and waits for the automated checks |
game
A tiny three.js arcade game: a ship on an endless lane, dodging blocks. The best score stays on the viewer's device, PLAY goes fullscreen, and a SHOP sells from your token's store.
chaindaddy app init game my-game| File | What it does |
|---|---|
src/index.tsx | LaneRunner: the title, the score, game over, fullscreen, the best score |
src/game.ts | The three.js scene, the input and the frame loop, which pauses while the tab is hidden or the shop is open |
src/shop.tsx | The SHOP: the catalog with prices, BUY, SIGN IN, and the liveries |
src/store.ts | useIap and prices |
Steer with the arrow keys, A and D, or by dragging. Boost with space, up or a tap.
Permissions: ui:fullscreen (fullscreen), iap:purchase (iap-purchase), storage:local (the best score) and fetch:self-api (the store's catalog). The app never sees a wallet or an amount: the page sells the item on its own sheet.
Liveries. An item in your store whose metadata says { "slot": "livery", "color": "#rrggbb" } recolors the ship for a viewer who holds it. With several, the SHOP lets them pick. Other items show in the SHOP as they are; give them a meaning in your game the same way, by metadata.slot.
chaindaddy iap store open --chain base --crown <crownId>
chaindaddy iap sku create <storeId> --sku livery.mint --type non_consumable --name "Mint livery" \
--price-usd 2 --metadata '{"slot":"livery","color":"#39ff88"}'Every three.js class you import adds to the bundle. For online multiplayer with your own game server, prizes, and a far bigger three.js game kept small, read the FLUX GP kit, the full game this template comes from.
interactive
A generative 2D canvas: visitors drag across it and leave trails of light that drift and fade. You give it a title and a palette right on your token page.
chaindaddy app init interactive my-piece| File | What it does |
|---|---|
src/index.tsx | TrailCanvas: the owner's editor, the config, the holders' palette |
src/art.ts | The piece: particles on a flow field. It stops drawing while it's off screen or the tab is hidden |
src/config.ts | The owner's title and palette, loaded and saved as this app's config on the page |
src/store.ts | useIap, to find the holders' palette |
Your settings. As the page's owner, you get EDIT: a title and a palette from a few presets. The default, Page, uses your token page's own colors. SAVE stores them in the app's config on that page, and every visitor reads it. The config is kept under the app's id, the APP_ID constant in src/index.tsx: keep it the same as capp.json's id (the CLI writes both).
The holders' palette. An unlock item in your store whose metadata says { "slot": "palette" } lets visitors who hold it view the piece in that palette. metadata.colors sets it: the background first, then one to five trail colors. The item's rule does the unlocking, so the app buys nothing and needs no iap:purchase.
chaindaddy iap sku create <storeId> --sku palette.holders --type unlock --name "Holders' palette" \
--rule '{"hold":{"min":"1000000000000000000000000"}}' \
--metadata '{"slot":"palette","colors":["#0d0a02","#fbbf24","#fde68a","#f97316"]}'Permissions: fetch:self-api only. With prefers-reduced-motion, nothing moves by itself.
community
Your token's community in one card: its open poll with the standing and a VOTE, its links, and how many hold it.
chaindaddy app init community my-community| File | What it does |
|---|---|
src/index.tsx | CommunityCard: the poll, the links, the holders |
src/polls.ts | The token's polls: the open ones, their results, and casting a vote |
The poll. Open a Community Poll on your token page, and the card shows the first open one. A vote counts by what the voter holds at the poll's snapshot. VOTE asks the viewer's wallet to sign it (sign-typed-data, confirmed on the page's own sheet first), then sends it to Chain Daddy, which checks it and weighs it. See Poll votes.
Links and holders. The links come from your page (the website, X, Telegram and Discord), and a verified one is marked. The holder count is your page's own.
Permissions: fetch:self-api and wallet:sign. Data: chain:info, market:holders and profile:social.
Also in the list
chaindaddy app init --help lists two more names. Neither copies a template:
gallerystops and points you to the no-code Gallery: add it from Token Manager → Apps.enginestops too: a Godot or Unity web export needs no starter code. It suggestsgamefor a game in JavaScript.
Next steps
- Make it yours. Edit
src/index.tsxand the template's own files. The props and themes your app gets are in Widget Development, and every action is in Actions. - Sell and unlock. Add items to your store: Store and Rewards.
- Test.
npm run devruns it on a local token page: Test locally. - Check.
npm run build,npm run validateandnpm run scan. Fields are in the manifest reference. - Ship.
npm run pack && npm run sign && npm run submit, then send the build for review. See Submitting an App. Publishing needs a paid plan and the Developer Beta Program: Your page.
Guard rails
- No paid entry to anything with a prize.
- No paid random outcomes: no loot boxes.
- Holding your token unlocks things. It never earns anything.
See Token Prizes for contests you can run.