sails-frontend
Sails Frontend
Goal
Keep frontend work on the typed Sails path first: generated lib.ts plus @gear-js/react-hooks, with @gear-js/api reserved for low-level fallback cases that the Sails stack does not cover cleanly.
Inputs
assets/frontend-bootstrap-checklist.md../../references/sails-frontend-and-gear-js.md../../references/sails-idl-client-pipeline.md../../references/sails-cheatsheet.md../../references/sails-gtest-and-local-validation.md../../references/scale-binary-decoding-guide.md../../references/voucher-and-signless-flows.md
Minimal Path (simple apps)
For a straightforward app (counter, single-service CRUD) where the contract is already built:
npx create-vara-app my-dapp --idl path/to/service.idlcd my-dapp && npm install && npm run dev- Verify: one read query renders, one write action shows disabled/pending/success/error states
- Done — the scaffold handles providers, wallet, typed wrappers, and env validation
Skip the rest of this skill unless you need to customize screens, add Next.js support, wire vouchers, or handle advanced flows.
Bootstrap with create-vara-app
When a Sails app needs a frontend — whether the project is brand-new or an existing repo without one — start with create-vara-app.
Prerequisite: the contract must be built first so the .idl file exists. If the .idl is not available yet, build the contract (cargo build) or use create-vara-app without --idl to scaffold with a demo contract.
npx create-vara-app my-dapp --idl path/to/service.idl
npm: https://www.npmjs.com/package/create-vara-app GitHub: https://github.com/gear-foundation/create-vara-app
This scaffolds a Vite + React + TypeScript frontend with:
- Typed query/transaction wrappers from the IDL
- Wallet integration (SubWallet, Polkadot.js, Talisman)
- Live event subscriptions
- Client-side input validation
- Debug panel with runtime IDL explorer
Without --idl, scaffolds with a demo contract. With --idl, parses the service name and generates typed components automatically.
After the contract changes, re-run the scaffold from the project root:
npx tsx scripts/scaffold-client.ts
Detection: if the project has scripts/scaffold-client.ts, it was bootstrapped with create-vara-app. Use the scaffold script for regeneration. Otherwise use sails-js-cli.
After bootstrap, continue with the Standard Path below to customize screens, add queries, or wire advanced flows.
Standard Path
- Treat the program
.idlas the frontend source of truth. - Generate or refresh the typed client. If
scripts/scaffold-client.tsexists, runnpx tsx scripts/scaffold-client.tsfrom the project root. Otherwise usesails-js-clibefore wiring screens, hooks, or forms. - Compose the React root around TanStack Query plus Gear providers: query client, API provider, account provider, and alert provider.
- Prefer
useProgramwith the generatedProgramclass for typed service access. - Use
useProgramQueryfor Sails queries anduseProgramEventonly where live subscriptions are actually needed. - Use
usePrepareProgramTransactionto obtaingasLimit,extrinsic, or fee data before send when the UX needs validation or previews. - Use
useSendProgramTransactionfor commands, awaitresult.response, and surface pending, success, and failure states in the UI instead of relying only on extrinsic submission. - Pass
voucherIdonly when the flow is intentionally voucher-backed or prepaid. Treat full gasless or signless UX as a separate product decision; use the dedicated EZ-transactions path when the product spec requires it. - Drop to low-level
@gear-js/apionly for dynamic multi-IDL control, metadata work, raw mailbox or voucher flows, or directapi.message.send,api.programState.read, andapi.programState.readUsingWasmcases. On those paths, identify whether the bytes are IDL-driven, metadata-driven, orstate.meta.wasm-driven before decoding.
Next.js App Router Compatibility
When the target frontend is a Next.js App Router project:
@gear-js/api,sails-js, and wallet subdependencies use browser globals and WASM that break in Server Components. Add them totranspilePackagesinnext.config.jsand mark all Gear provider/hook files with'use client'.- If
@gear-js/react-hooksor its wallet subdependencies cause persistent server-build failures aftertranspilePackages, fall back to a lower-levelsails-js+@gear-js/apiintegration path with runtime-onlyawait import(...)boundaries in client components. If falling back, commit to the lower-level path for the entire project. - On the lower-level fallback path, add
@polkadot/utiland@polkadot/util-cryptoas explicit dependencies — they are no longer pulled in transitively without the hooks stack. next/font/googlefetches fonts at build time and will fail in offline CI or proof-loop environments. Usenext/font/localor system fonts instead.- Run
next buildbeforetsc --noEmitin App Router projects; route types are generated during the build step.
See ../../references/sails-frontend-and-gear-js.md for the full Next.js compatibility guide.
Repo Layout For Mixed Workspaces
In monorepos with both a Rust Sails program and a web frontend, check for app/ directory collisions. The Rust program crate conventionally uses app/ and Next.js App Router also expects app/. Common resolution: keep the Rust app/ crate and place the frontend in frontend/ or web/.
sails-js-parser Initialization
When using sails-js for runtime IDL parsing (not the generated lib.ts client path), the Sails class requires an explicit parser instance from the separate sails-js-parser package. See ../../references/sails-frontend-and-gear-js.md for the initialization pattern.
API Surface Validation
Before handoff, validate the installed sails-js API surface against the conventions in ../../references/sails-frontend-and-gear-js.md. Key points:
- The transaction builder method is
signAndSend(), notsendAndWait(). - Function arguments are positional, not wrapped in objects.
- Confirm
program.<serviceName>.<functionName>exists on the generated client before wiring UI.
Dependency Freshness Policy
Before generating or editing a Vara frontend, resolve package versions from the target project and the current package metadata, not from memory.
Order of precedence:
- Existing repo lockfile and
package.json - Current
peerDependenciesof@gear-js/react-hooksand related packages - Current published package versions if this is a new project
Rules:
- Do not pin Gear/Vara frontend package versions from memory.
- If the repo already has a lockfile, preserve it unless there is a clear compatibility issue.
- If starting a new frontend, first determine the current compatible package set, then write
package.json. - If using
@gear-js/wallet-connect, also verify the required UI package set and required styles. - Name the resolved versions explicitly in the output.
Wallet UI Styling Rule
If the frontend uses packaged Gear wallet/UI components such as:
@gear-js/wallet-connect@gear-js/ui@gear-js/vara-ui
then import the required package styles at the app entrypoint before considering the wallet integration complete.
Minimum check:
- wallet button renders correctly
- modal is visually positioned and styled correctly
- alert container is visible and not collapsed
Wallet Readiness Rule
For wallet-bound actions, distinguish at least these states in the UI:
- wallets are still loading
- no Vara-compatible wallet extension is available
- wallet exists but no account is connected
- account is connected and ready for signing
Do not collapse these states into a single generic “wallet not ready” message.
Disabled signed actions should expose a visible reason, such as:
- wallets are still loading
- no wallet extension found
- connect a wallet first
- program is not ready yet
Env Validation Rule
Validate required env values such as endpoint and program IDs before rendering feature screens.
Missing env values must fail visibly, not silently.
Definition of Done
Do not hand off a Vara frontend until all of the following are true:
- dependency versions were resolved from the actual project/package metadata, not memory
- app root includes
QueryClientProvider,ApiProvider,AccountProvider, andAlertProvider - if packaged wallet/UI components are used, their styles are imported and the wallet UI is usable; otherwise, the custom wallet flow is visible and usable
- at least one read query works
- at least one signed transaction path is wired and shows disabled, pending, and success or error states in the UI
- signed write actions are disabled when wallet/account prerequisites are missing
- at least one invalid form path is handled without sending a transaction
- affected queries refetch after successful mutations unless an explicit live-subscription strategy is used
- build passes
- installed
sails-jsAPI surface was validated:signAndSendmethod, positional arguments, and query builder pattern match the conventions in the reference doc - if runtime IDL parsing is used,
sails-js-parseris installed and parser initialization is present - if using Next.js App Router,
transpilePackagesand'use client'boundaries are confirmed - IDL snapshot is checked in or the generation command is documented
- the final note includes exact run commands and required env vars
Transaction UX Rule
Every write action must expose at least:
- disabled state when prerequisites are missing
- pending state
- success state
- error state with a visible message
Do not rely only on console logs or implicit alerts.
Final Validation Pass
Before handoff, review the frontend specifically for:
- provider setup
- wallet connection assumptions
- wallet readiness states
- required CSS imports for packaged UI
- transaction status rendering
- disabled states for unauthenticated actions
- query refetch after successful mutations
- invalid form handling before send
- env variable wiring
- package version freshness
Route Here When
- the builder asks for a React, Vite, or TypeScript dApp on Vara
- the task is wallet connect, account selection, transaction signing, or voucher-aware sends
- the task is wiring Sails queries, commands, events, and typed generated clients
- the task needs program IDs, endpoint env vars, loading states, error states, or response handling in the UI
- the task needs a justified low-level fallback with
@gear-js/api
Required Output Shape
Name these decisions explicitly in the work product:
- chosen frontend stack and package surface
.idland generated client path- endpoint and program ID env contract
- provider composition at app root
- per-screen mapping of queries, commands, and events
- signing, gas, voucher, and response-handling strategy
- low-level escape hatches, if any
- chosen integration path: hooks-based or lower-level fallback (if Next.js App Router)
Guardrails
- Prefer generated clients and hooks over hand-built SCALE payloads for standard Sails apps.
- Do not ship seed phrases, private keys, or test mnemonics in frontend code.
- On manual transaction-builder or low-level Gear-JS paths, make the gas strategy explicit.
- Do not enable
watchsubscriptions everywhere by default; only subscribe where the UX truly benefits. - Do not mix Sails IDL-driven calls with metadata-driven low-level calls unless the reason is named explicitly.
- Do not decode arbitrary raw bytes with plain SCALE rules until you have named whether the source is a Sails interface path, a full-state metadata path, or a state-function path.
- Do not embed machine-specific absolute paths in generated configs, scripts, or documentation. Use project-relative paths.
- When handing off to a frontend, confirm the IDL snapshot is available. Cross-reference
sails-idl-clientfor the canonical handoff pattern. - Do not assume
sendAndWait()exists on thesails-jstransaction builder; the correct method issignAndSend().
More from gear-foundation/vara-skills
vara-skills
Use when a builder needs the top-level router for the provisional standard Gear/Vara Sails skill pack across Codex, Claude, or OpenClaw. Do not use for Vara.eth or ethexe work, non-Sails programs, or broad protocol research.
197sails-new-app
Use when a builder is starting a new standard Gear/Vara Sails app and needs the correct greenfield sequence before implementation. Do not use for edits to an established repo, Vara.eth or ethexe targets, or non-Sails templates.
2sails-dev-env
Use when a builder needs to prepare or repair a local macOS, Linux, or Windows machine for standard Gear/Vara Sails Rust development before building, testing, or running a local node. Do not use for live-network deployment, app-specific feature work, or Vara.eth/ethexe-only setup.
2vara-wallet
Use when an agent needs to interact with Vara Network on-chain — deploy programs, call Sails methods, manage wallets, transfer tokens, monitor events. Not for building Sails programs (use vara-skills for that).
2sails-gtest
Use when a builder needs the standard Gear/Vara Sails gtest loop for feature verification, debugging, or regression coverage. Do not use for live-network-only validation, deployment-first workflows, or non-Sails programs.
2task-decomposer
Use when approved spec and architecture artifacts must become an ordered implementation plan for Gear or Vara work. Do not use when the architecture is still unsettled or when the request is only asking for a high-level idea.
2