Engine conventions
Read package.json and the installed playcanvas source before relying on version-sensitive API
details. Apply these stable conventions throughout the project.
Coordinates and angles
- Use the right-handed coordinate system: +Y is up and the gameplay ground plane is XZ.
- Treat
entity.forward and the camera viewing direction as -Z; entity.right is +X and
entity.up is +Y. lookAt points -Z at the target.
- Expect glTF models authored toward +Z to need a yaw correction. Inspect and calibrate each
directional model instead of applying one global correction.
- Pass degrees in XYZ order to high-level angle APIs.
- Keep pitch, yaw, and roll as application state. Do not repeatedly read
getEulerAngles() and
feed its decomposition back into setEulerAngles().
- Interpolate periodic angles with
math.lerpAngle() or rotations with Quat.slerp(), not scalar
lerp across the 0/360 seam.
Transforms and units
- Use
setPosition, setRotation, and setEulerAngles for world transforms.
- Use the
setLocal* variants below a parent.
- Treat units as metres. Physics gravity defaults to
(0, -9.81, 0).
- Keep gameplay transforms on a semantic root and asset-authoring corrections on a child.
- Do not scale rigid-body roots or skinned bones.
Cameras, materials, and bounds
- Perspective camera FOV is vertical and defaults to 45 degrees.
- Smooth an orbit camera's focus, yaw, pitch, and distance, then derive its position. Do not
Vec3.lerp() between orbit positions on opposite sides of the focus; the chord crosses the subject.
- Before writing custom camera input, inspect the installed controller script and its matching
Engine example. Preserve their gesture mapping and damping unless the product explicitly asks
for different behavior; do not derive signs from memory.
- Define the input contract in screen space, then verify positive and negative movement on both axes
with real input after a rendered frame. Judge the camera basis or a projected fixed landmark, not
world-space camera coordinates or internal angle signs; both can approve inverted behavior.
- Materials cull back faces by default; counter-clockwise winding defines the front face.
- Clone and reassign a shared material before editing it for only some meshes, including default
and asset-imported materials. Per-mesh uniforms use
meshInstance.setParameter() without cloning.
setParameter uploads raw values; author colours in sRGB and convert with Color#linear()
before upload — do not hand-roll gamma.
- Entities do not have an
aabb. Union descendant meshInstance.aabb values after transforms have
synchronized.
- Let
Mesh.update() calculate local bounds. If passing false for updateBoundingBox, assign an
explicit mesh.aabb before the mesh can be culled.
- Expand custom-mesh bounds by the maximum vertex-shader displacement; CPU bounds do not observe
shader deformation.
- Treat offline skinned-mesh bounds as bind-pose estimates and confirm animated poses at runtime.
Imports
Use named ESM imports from playcanvas. Import production scripts only from
playcanvas/scripts/esm/**; legacy sibling script directories depend on a global Engine namespace.
Runtime confirmation
Offline measurements cannot prove facing, animated poses, or final placement. Confirm each one in the
running application:
- Start the project's own dev server or build; do not construct a separate harness.
- Log the value from inside the Engine, using
getPosition(), getEulerAngles(), a
meshInstance.aabb, or an anim component's active state, from a Script or an update callback.
- For large or vertex-displaced meshes, inspect their runtime AABB and
visibleThisFrame after a
rendered frame from at least two representative camera angles.
- Confirm a directional model's visible front aligns with its semantic root's
forward; a stored
yaw or runtime transform alone cannot prove mesh facing.
- Read that logged value from the browser console. Screenshots judge composition and orientation;
numeric claims require logged values.
- Record the confirmed value in application state or an asset tuning record, then remove the logging.
1---2name: apply-conventions3description: Use when writing or reviewing PlayCanvas Engine code involving entity transforms, cameras, physics, materials, model orientation, bounds, or imports to apply the Engine's coordinate and API conventions.4---56# Engine conventions78Read `package.json` and the installed `playcanvas` source before relying on version-sensitive API9details. Apply these stable conventions throughout the project.1011## Coordinates and angles1213- Use the right-handed coordinate system: +Y is up and the gameplay ground plane is XZ.14- Treat `entity.forward` and the camera viewing direction as -Z; `entity.right` is +X and15 `entity.up` is +Y. `lookAt` points -Z at the target.16- Expect glTF models authored toward +Z to need a yaw correction. Inspect and calibrate each17 directional model instead of applying one global correction.18- Pass degrees in XYZ order to high-level angle APIs.19- Keep pitch, yaw, and roll as application state. Do not repeatedly read `getEulerAngles()` and20 feed its decomposition back into `setEulerAngles()`.21- Interpolate periodic angles with `math.lerpAngle()` or rotations with `Quat.slerp()`, not scalar22 lerp across the 0/360 seam.2324## Transforms and units2526- Use `setPosition`, `setRotation`, and `setEulerAngles` for world transforms.27- Use the `setLocal*` variants below a parent.28- Treat units as metres. Physics gravity defaults to `(0, -9.81, 0)`.29- Keep gameplay transforms on a semantic root and asset-authoring corrections on a child.30- Do not scale rigid-body roots or skinned bones.3132## Cameras, materials, and bounds3334- Perspective camera FOV is vertical and defaults to 45 degrees.35- Smooth an orbit camera's focus, yaw, pitch, and distance, then derive its position. Do not36 `Vec3.lerp()` between orbit positions on opposite sides of the focus; the chord crosses the subject.37- Before writing custom camera input, inspect the installed controller script and its matching38 Engine example. Preserve their gesture mapping and damping unless the product explicitly asks39 for different behavior; do not derive signs from memory.40- Define the input contract in screen space, then verify positive and negative movement on both axes41 with real input after a rendered frame. Judge the camera basis or a projected fixed landmark, not42 world-space camera coordinates or internal angle signs; both can approve inverted behavior.43- Materials cull back faces by default; counter-clockwise winding defines the front face.44- Clone and reassign a shared material before editing it for only some meshes, including default45 and asset-imported materials. Per-mesh uniforms use `meshInstance.setParameter()` without cloning.46- `setParameter` uploads raw values; author colours in sRGB and convert with `Color#linear()`47 before upload — do not hand-roll gamma.48- Entities do not have an `aabb`. Union descendant `meshInstance.aabb` values after transforms have49 synchronized.50- Let `Mesh.update()` calculate local bounds. If passing `false` for `updateBoundingBox`, assign an51 explicit `mesh.aabb` before the mesh can be culled.52- Expand custom-mesh bounds by the maximum vertex-shader displacement; CPU bounds do not observe53 shader deformation.54- Treat offline skinned-mesh bounds as bind-pose estimates and confirm animated poses at runtime.5556## Imports5758Use named ESM imports from `playcanvas`. Import production scripts only from59`playcanvas/scripts/esm/**`; legacy sibling script directories depend on a global Engine namespace.6061## Runtime confirmation6263Offline measurements cannot prove facing, animated poses, or final placement. Confirm each one in the64running application:6566- Start the project's own dev server or build; do not construct a separate harness.67- Log the value from inside the Engine, using `getPosition()`, `getEulerAngles()`, a68 `meshInstance.aabb`, or an anim component's active state, from a `Script` or an update callback.69- For large or vertex-displaced meshes, inspect their runtime AABB and `visibleThisFrame` after a70 rendered frame from at least two representative camera angles.71- Confirm a directional model's visible front aligns with its semantic root's `forward`; a stored72 yaw or runtime transform alone cannot prove mesh facing.73- Read that logged value from the browser console. Screenshots judge composition and orientation;74 numeric claims require logged values.75- Record the confirmed value in application state or an asset tuning record, then remove the logging.