build-app
Use when creating or restructuring a PlayCanvas app with the Engine API, @playcanvas/react, or @playcanvas/web-components, covering bootstrap, input, resize, physics, update loop, UI, and lifecycle.
SKILL.mdskills/build-app/SKILL.md
GitHubBuild an Engine application
Read package.json and the entry point, keep the surface that owns the lifecycle, and read only its
reference: direct Engine, React, or
Web Components. Choose from imports and markup, not dependencies.
Bootstrap
- Input is opt-in.
app.keyboard,mouse,touch,gamepads, andelementInputstaynullunless passed tonew Application(canvas, { ... }); UI buttons neednew ElementInput(canvas). - The Engine adds no window resize listener; call
app.resizeCanvas()from your own handler. graphicsDevice.maxPixelRatiodefaults to 1. Raise it, at most towindow.devicePixelRatio, only where the target holds its frame budget, callapp.resizeCanvas(), and confirm withcanvas.width / canvas.clientWidth.- Rigid bodies stay inert until Ammo loads through
WasmModule. Copy the loader from thephysics/falling-shapesexample withfind-examples. devtoolsdefaults totrue, so debugging tools can find the app (inspect-runtime). Set it tofalseonly to hide a production build.
Update loop
dtis already clamped byapp.maxDeltaTime(0.1 s); tune it instead of clamping by hand.app.timeScalescales it, and0pauses scaled time.- Keep app state explicit and owned in one place; advance time-dependent logic from
dt, and reset through the same setup used at start.
UI
- Render UI from app state; never keep the source of truth in the DOM or UI elements.
- Use a DOM or React overlay, or Engine
screenandelementcomponents adapted from auser-interfaceexample. - Hide unused elements with
enabled = false; an element at opacity 0 still draws.
Ownership
- Keep one owner for app creation, assets, entities, update callbacks, and teardown.
- Prefer the surface's declarative primitives. Put per-entity and per-frame behaviour in an Engine
Script. - Remove external events and resources in the lifecycle that created them.