Skip to content

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).

TemplateWhat it isCategoryTierBundle, built
gameA three.js arcade game: a ship dodging blocks, a best score, fullscreen, and a shop that sells from your token's storegamesrich, 6x3about 440 KB, 116 KB gzipped
interactiveA generative canvas piece that visitors draw on. You set its title and palette on your page, and holders can unlock a paletteinteractivestandard, 4x3about 16 KB, 7 KB gzipped
communityYour token's open poll with a vote weighted by holding, its links and its holder count, in one cardsocialstandard, 4x3about 8 KB, 4 KB gzipped

Start one ​

Sign in once, then name the template and a folder:

bash
npm install -g @chaindaddy/cli@beta
chaindaddy app login

chaindaddy app init game my-game
cd my-game
npm install
npm run dev

The same for the others:

bash
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):

bash
chaindaddy app init game my-game --developer-id <your developer ID> --non-interactive
OptionWhat 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-interactiveFail 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, below

Every template carries the same two helpers:

  • src/host.ts sends 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.ts is 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/apps version 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:

ScriptRunsWhat it does
npm run devchaindaddy app devYour app on a local token page, rebuilt on save. See Test locally
npm run buildchaindaddy app builddist/bundle.js: one ES module, React left to the page
npm run typechecktsc --noEmitType-checks your code
npm run validatechaindaddy app validatecapp.json against the manifest schema
npm run scanchaindaddy app scanThe same size and security checks we run
npm run packchaindaddy app packThe .capp package
npm run signchaindaddy app sign --in-placeSigns it with your API key
npm run submitchaindaddy app submit --watchUploads 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.

bash
chaindaddy app init game my-game
FileWhat it does
src/index.tsxLaneRunner: the title, the score, game over, fullscreen, the best score
src/game.tsThe three.js scene, the input and the frame loop, which pauses while the tab is hidden or the shop is open
src/shop.tsxThe SHOP: the catalog with prices, BUY, SIGN IN, and the liveries
src/store.tsuseIap 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.

bash
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.

bash
chaindaddy app init interactive my-piece
FileWhat it does
src/index.tsxTrailCanvas: the owner's editor, the config, the holders' palette
src/art.tsThe piece: particles on a flow field. It stops drawing while it's off screen or the tab is hidden
src/config.tsThe owner's title and palette, loaded and saved as this app's config on the page
src/store.tsuseIap, 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.

bash
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.

bash
chaindaddy app init community my-community
FileWhat it does
src/index.tsxCommunityCard: the poll, the links, the holders
src/polls.tsThe 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:

  • gallery stops and points you to the no-code Gallery: add it from Token Manager → Apps.
  • engine stops too: a Godot or Unity web export needs no starter code. It suggests game for a game in JavaScript.

Next steps ​

  1. Make it yours. Edit src/index.tsx and the template's own files. The props and themes your app gets are in Widget Development, and every action is in Actions.
  2. Sell and unlock. Add items to your store: Store and Rewards.
  3. Test. npm run dev runs it on a local token page: Test locally.
  4. Check. npm run build, npm run validate and npm run scan. Fields are in the manifest reference.
  5. 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.