create-playcanvas 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.mjs +35 -33
- package/package.json +4 -4
- package/skills/add-effects/SKILL.md +21 -72
- package/skills/apply-conventions/SKILL.md +33 -59
- package/skills/assemble-scene/SKILL.md +18 -43
- package/skills/assemble-scene/references/direct-engine.md +2 -2
- package/skills/assemble-scene/references/react.md +3 -3
- package/skills/assemble-scene/references/web-components.md +2 -2
- package/skills/bake-lighting/SKILL.md +25 -50
- package/skills/build-app/SKILL.md +29 -28
- package/skills/build-app/references/web-components.md +3 -3
- package/skills/calibrate-model/SKILL.md +18 -48
- package/skills/calibrate-model/references/web-components.md +3 -3
- package/skills/configure-animation/SKILL.md +21 -37
- package/skills/configure-animation/references/direct-engine.md +2 -2
- package/skills/configure-animation/references/react.md +3 -3
- package/skills/find-examples/SKILL.md +24 -60
- package/skills/inspect-glb/SKILL.md +21 -62
- package/skills/light-scene/SKILL.md +29 -82
- package/skills/load-assets/SKILL.md +52 -0
- package/skills/override-shader-chunks/SKILL.md +21 -55
- package/skills/reduce-draw-calls/SKILL.md +24 -48
- package/skills/reuse-scripts/SKILL.md +23 -42
- package/skills/reuse-scripts/references/direct-engine.md +8 -28
- package/skills/reuse-scripts/references/react.md +2 -12
- package/skills/reuse-scripts/references/web-components.md +2 -15
- package/skills/verify-pixels/SKILL.md +30 -44
- package/templates/engine/base/package.json +3 -3
- package/templates/react/ar-placement/src/App.tsx +29 -21
- package/templates/react/base/package.json +8 -8
- package/templates/react/sprite-game/src/App.tsx +21 -13
- package/templates/web-components/base/package.json +4 -4
- package/templates/web-components/interactive-sphere/index.html +1 -1
- package/templates/web-components/splat-viewer/index.html +1 -1
- package/skills/build-hud/SKILL.md +0 -38
- package/skills/manage-game-state/SKILL.md +0 -48
|
@@ -7,11 +7,11 @@ import { Entity } from '@playcanvas/react';
|
|
|
7
7
|
import { Collision, RigidBody } from '@playcanvas/react/components';
|
|
8
8
|
|
|
9
9
|
// Model is the project's calibrated component from calibrate-model, not a library export
|
|
10
|
-
const
|
|
11
|
-
<Entity name={`
|
|
10
|
+
const SceneObject = ({ id, position, heading }) => (
|
|
11
|
+
<Entity name={`Model_${id}`} position={position} rotation={[0, heading, 0]}>
|
|
12
12
|
<RigidBody type="dynamic" mass={1} />
|
|
13
13
|
<Collision type="capsule" />
|
|
14
|
-
<Model id="
|
|
14
|
+
<Model id="model" src="/models/model.glb" />
|
|
15
15
|
</Entity>
|
|
16
16
|
);
|
|
17
17
|
```
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
Represent the whole gameplay object below one semantic root:
|
|
4
4
|
|
|
5
5
|
```html
|
|
6
|
-
<pc-entity name="
|
|
6
|
+
<pc-entity name="Model_1" position="4 0 -3" rotation="0 90 0">
|
|
7
7
|
<pc-rigid-body type="dynamic" mass="1"></pc-rigid-body>
|
|
8
8
|
<pc-collision type="capsule"></pc-collision>
|
|
9
9
|
<pc-entity position="0 0.8 0" rotation="0 180 0" scale="0.01 0.01 0.01">
|
|
10
|
-
<pc-model asset="
|
|
10
|
+
<pc-model asset="model"></pc-model>
|
|
11
11
|
</pc-entity>
|
|
12
12
|
</pc-entity>
|
|
13
13
|
```
|
|
@@ -1,61 +1,36 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: bake-lighting
|
|
3
|
-
description: Use when
|
|
3
|
+
description: Use when static PlayCanvas lighting, shadows, or ambient occlusion cost too much per frame and should be baked into lightmaps.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# Bake static lighting
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
shadow-map rendering and per-pixel dynamic lighting for that light entirely.
|
|
8
|
+
Lightmaps remove per-frame shadow and lighting cost for static lights on static geometry.
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
- `Application` registers `Lightmapper`; manual `AppOptions` bootstraps set
|
|
11
|
+
`lightmapper = Lightmapper`.
|
|
12
|
+
- On the light, set `bake = true`; once every mesh it lights is lightmapped, set
|
|
13
|
+
`affectDynamic = false`.
|
|
14
|
+
- On each mesh, set `render.lightmapped = true`, or it goes unlit once `affectDynamic` is off. Size
|
|
15
|
+
it with `lightmapSizeMultiplier`; `castShadowsLightmap` lets meshes shadow each other.
|
|
16
|
+
- Set the mode on `scene.lightmapMode`: `BAKE_COLOR` for flat diffuse, or the default
|
|
17
|
+
`BAKE_COLORDIR`, which adds direction for normal- or specular-mapped materials.
|
|
18
|
+
- Bake AO without lights with `scene.ambientBake`, `ambientBakeNumSamples`, and
|
|
19
|
+
`ambientBakeOcclusionBrightness` and `ambientBakeOcclusionContrast`.
|
|
20
|
+
- The Engine bakes once on the first rendered frame. Call `app.lightmapper.bake(null, mode)` only
|
|
21
|
+
for nodes added later or to re-bake.
|
|
12
22
|
|
|
13
|
-
|
|
14
|
-
wires this by default; only a manual `AppOptions` assembly needs the explicit line.
|
|
15
|
-
- Per light: `light.bake = true`, then `light.affectDynamic = false` once every mesh it lights is
|
|
16
|
-
lightmapped, so it stops contributing to the real-time pass.
|
|
17
|
-
- Per mesh: `render.lightmapped = true` — required for the mesh to receive any light once
|
|
18
|
-
`affectDynamic` is false, a correctness requirement, not just an optimization —
|
|
19
|
-
`render.lightmapSizeMultiplier` to size its lightmap, `render.castShadowsLightmap` so lightmapped
|
|
20
|
-
meshes still shadow each other in the bake.
|
|
21
|
-
- Bake mode: `BAKE_COLOR` for flat diffuse materials; `BAKE_COLORDIR` adds a dominant-light-direction
|
|
22
|
-
pass for normal- or specular-mapped materials that need one.
|
|
23
|
-
- Baked ambient occlusion, independent of any light: `scene.ambientBake` plus
|
|
24
|
-
`ambientBakeNumSamples`, `ambientBakeOcclusionBrightness`/`OcclusionContrast`.
|
|
25
|
-
- Run `app.lightmapper.bake(null, mode)` once the scene exists; `null` bakes every lightmapped node.
|
|
23
|
+
## A second UV set is required
|
|
26
24
|
|
|
27
|
-
|
|
25
|
+
A node bakes only when every mesh instance has `SEMANTIC_TEXCOORD1`. Otherwise it is skipped, with
|
|
26
|
+
only a debug-build log, and stays dynamically lit. Primitives have the set; imported GLBs often do
|
|
27
|
+
not. Check, then unwrap or re-export.
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
non-overlapping UV channel suitable for a lightmap atlas. Read the installed engine's source for
|
|
31
|
-
what its `Lightmapper` actually requires — which UV set it samples, whether it unwraps one for you —
|
|
32
|
-
before assuming a real model will bake correctly. Do not carry a primitive-only test result into
|
|
33
|
-
production assets unchecked.
|
|
29
|
+
## On-device or offline
|
|
34
30
|
|
|
35
|
-
|
|
31
|
+
Time `bake()` on the target device. Move to an offline bake shipped as textures only when it misses
|
|
32
|
+
the startup budget or needs detail the runtime lightmapper cannot produce, and state the added
|
|
33
|
+
download size.
|
|
36
34
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
- the estimated bake time does not fit the startup or first-paint budget on the target device, or
|
|
41
|
-
- the result needs stylized material detail beyond lighting that the runtime `Lightmapper` cannot
|
|
42
|
-
produce.
|
|
43
|
-
|
|
44
|
-
Only then move to an offline bake shipped as assets, following the same shape as any other
|
|
45
|
-
generated-asset pipeline: registry-keyed per-asset configs (a new asset is a config change, not new
|
|
46
|
-
pipeline code), a CLI with per-target fast paths, staged size logging, worker-thread parallelism for
|
|
47
|
-
build time, and a coverage self-audit that fails the bake when an expected output is missing or
|
|
48
|
-
empty.
|
|
49
|
-
|
|
50
|
-
## Keep dynamic objects consistent
|
|
51
|
-
|
|
52
|
-
Whichever rung you use, dynamic objects moving through baked lighting must not read as ignoring it:
|
|
53
|
-
sample or approximate the baked occlusion/shadow field for them and their attachments so they dim to
|
|
54
|
-
the same levels as the static geometry around them, and ground them with a contact shadow. A
|
|
55
|
-
dynamic object whose custom shading must meet baked maps is `override-shader-chunks` territory.
|
|
56
|
-
|
|
57
|
-
## Prove it
|
|
58
|
-
|
|
59
|
-
Capture `verify-pixels`-style frames both in and out of the baked shadow, before and after the
|
|
60
|
-
change, and compare them. A screenshot glanced at once is not proof the bake reproduced the lighting
|
|
61
|
-
it removed.
|
|
35
|
+
Dynamic objects moving through baked light need approximated occlusion and a contact shadow, or
|
|
36
|
+
they look pasted on. Compare `verify-pixels` captures in and out of baked shadow.
|
|
@@ -1,41 +1,42 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: build-app
|
|
3
|
-
description: Use when creating or restructuring a PlayCanvas
|
|
3
|
+
description: 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.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Build an Engine application
|
|
7
7
|
|
|
8
|
-
Read `package.json` and the
|
|
9
|
-
|
|
8
|
+
Read `package.json` and the entry point, keep the surface that owns the lifecycle, and read only its
|
|
9
|
+
reference: [direct Engine](references/direct-engine.md), [React](references/react.md), or
|
|
10
|
+
[Web Components](references/web-components.md). Choose from imports and markup, not dependencies.
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
- read [references/web-components.md](references/web-components.md) for `pc-*` elements or
|
|
13
|
-
`@playcanvas/web-components` imports;
|
|
14
|
-
- read [references/direct-engine.md](references/direct-engine.md) for direct `playcanvas` bootstrap
|
|
15
|
-
code without a wrapper-owned lifecycle.
|
|
12
|
+
## Bootstrap
|
|
16
13
|
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
- Input is opt-in. `app.keyboard`, `mouse`, `touch`, `gamepads`, and `elementInput` stay `null`
|
|
15
|
+
unless passed to `new Application(canvas, { ... })`; UI buttons need `new ElementInput(canvas)`.
|
|
16
|
+
- The Engine adds no window resize listener; call `app.resizeCanvas()` from your own handler.
|
|
17
|
+
- `graphicsDevice.maxPixelRatio` defaults to 1. Raise it, at most to `window.devicePixelRatio`, only
|
|
18
|
+
where the target holds its frame budget, call `app.resizeCanvas()`, and confirm with
|
|
19
|
+
`canvas.width / canvas.clientWidth`.
|
|
20
|
+
- Rigid bodies stay inert until Ammo loads through `WasmModule`. Copy the loader from the
|
|
21
|
+
`physics/falling-shapes` example with `find-examples`.
|
|
19
22
|
|
|
20
|
-
##
|
|
23
|
+
## Update loop
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
the value.
|
|
25
|
+
- `dt` is already clamped by `app.maxDeltaTime` (0.1 s); tune it instead of clamping by hand.
|
|
26
|
+
`app.timeScale` scales it, and `0` pauses scaled time.
|
|
27
|
+
- Keep app state explicit and owned in one place; advance time-dependent logic from `dt`, and reset
|
|
28
|
+
through the same setup used at start.
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
and the height ratio should match the chosen pixel ratio. CSS dimensions and a screenshot filepath
|
|
30
|
-
do not prove rendering density.
|
|
30
|
+
## UI
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
- Render UI from app state; never keep the source of truth in the DOM or UI elements.
|
|
33
|
+
- Use a DOM or React overlay, or Engine `screen` and `element` components adapted from a
|
|
34
|
+
`user-interface` example.
|
|
35
|
+
- Hide unused elements with `enabled = false`; an element at opacity 0 still draws.
|
|
33
36
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
|
|
39
|
-
-
|
|
40
|
-
backgrounded tab or a slow frame cannot inject one large integration step;
|
|
41
|
-
- clean up external events and resources in the lifecycle that created them.
|
|
37
|
+
## Ownership
|
|
38
|
+
|
|
39
|
+
- Keep one owner for app creation, assets, entities, update callbacks, and teardown.
|
|
40
|
+
- Prefer the surface's declarative primitives. Put per-entity and per-frame behaviour in an Engine
|
|
41
|
+
`Script`.
|
|
42
|
+
- Remove external events and resources in the lifecycle that created them.
|
|
@@ -20,10 +20,10 @@ Build supported application structure declaratively:
|
|
|
20
20
|
|
|
21
21
|
```html
|
|
22
22
|
<pc-app>
|
|
23
|
-
<pc-asset id="
|
|
23
|
+
<pc-asset id="model" src="/models/model.glb"></pc-asset>
|
|
24
24
|
<pc-scene>
|
|
25
|
-
<pc-entity name="
|
|
26
|
-
<pc-model asset="
|
|
25
|
+
<pc-entity name="Model" position="0 0 -4">
|
|
26
|
+
<pc-model asset="model"></pc-model>
|
|
27
27
|
</pc-entity>
|
|
28
28
|
</pc-scene>
|
|
29
29
|
</pc-app>
|
|
@@ -1,65 +1,35 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: calibrate-model
|
|
3
|
-
description: Use before repeatedly placing GLB models in PlayCanvas
|
|
3
|
+
description: Use before repeatedly placing GLB models in PlayCanvas to record each asset's uniform scale, grounding offset, pivot compensation, and yaw once.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Model calibration
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
`
|
|
10
|
-
one tuning record per asset:
|
|
8
|
+
Measure each unique GLB once with `inspect-glb`, only trusting bounds when `boundsSource` is
|
|
9
|
+
`vertices`, and keep one tuning record per asset:
|
|
11
10
|
|
|
12
11
|
```ts
|
|
13
12
|
const ASSET_TUNING = {
|
|
14
13
|
model: {
|
|
15
|
-
boundsSource: 'vertices',
|
|
16
|
-
|
|
17
|
-
dims: [8, 7, 18],
|
|
18
|
-
center: [0, 2.5, 0],
|
|
19
|
-
groundOffset: 1,
|
|
20
|
-
intended: { dimension: 'length', size: 18 },
|
|
21
|
-
scale: 0.9,
|
|
22
|
-
y: 0.9,
|
|
23
|
-
yaw: 180
|
|
14
|
+
boundsSource: 'vertices', dims: [8, 7, 18], center: [0, 2.5, 0], groundOffset: 1,
|
|
15
|
+
intended: { dimension: 'length', size: 18 }, scale: 1, y: 1, yaw: 180
|
|
24
16
|
}
|
|
25
17
|
} as const;
|
|
26
18
|
```
|
|
27
19
|
|
|
28
|
-
|
|
20
|
+
1. Pick the dimension that defines the model's real size, in metres or relative to an already
|
|
21
|
+
calibrated model.
|
|
22
|
+
2. Set `scale = intendedSize / measuredDimension` and, for floor-resting models,
|
|
23
|
+
`y = groundOffset * scale`. Record a deliberate offset for models that should not rest on the
|
|
24
|
+
floor.
|
|
25
|
+
3. Confirm facing once in the running app and record `yaw`.
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
3. For a floor-resting model, calculate `y = groundOffset * scale`. Record a deliberate offset for
|
|
34
|
-
waterlines, embedded objects, or airborne models.
|
|
35
|
-
4. Confirm directional facing once in the running app, as the `apply-conventions` skill describes.
|
|
36
|
-
PlayCanvas entities face -Z while glTF convention is +Z, but asset packs vary.
|
|
37
|
-
5. Retain `boundsSource`, `aabb`, `dims`, `center`, `groundOffset`, and the intended size with
|
|
38
|
-
`{ scale, y, yaw }`. Use the scaled footprint and centre for initial spacing; do not re-derive or
|
|
39
|
-
add per-instance nudges.
|
|
27
|
+
Nest three levels so a root position means the same for every asset: the semantic root, a yaw
|
|
28
|
+
wrapper, then the visual child with the scale and local position
|
|
29
|
+
`(-center.x * scale, y, -center.z * scale)`. Apply calibration once, never per instance.
|
|
40
30
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
footprint centre over the base. Apply the authored yaw on a wrapper, then the scale and the full
|
|
44
|
-
offset on the render child inside it, so an off-centre pivot is compensated in the authored frame and
|
|
45
|
-
never re-rotated by the yaw or by gameplay heading:
|
|
31
|
+
Place the root on a measured support point, such as a mount point or raycast, not a global AABB
|
|
32
|
+
maximum. Skinned bounds are bind-pose estimates; confirm contact in animated poses.
|
|
46
33
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
yaw.setLocalEulerAngles(0, t.yaw, 0);
|
|
50
|
-
const visual = instantiate(asset);
|
|
51
|
-
visual.setLocalScale(t.scale, t.scale, t.scale);
|
|
52
|
-
visual.setLocalPosition(-t.center[0] * t.scale, t.y, -t.center[2] * t.scale);
|
|
53
|
-
yaw.addChild(visual);
|
|
54
|
-
root.addChild(yaw);
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
Keep `y` as the local correction that brings the measured minimum to the root plane; the X and Z
|
|
58
|
-
terms bring the footprint centre onto the root axis. Place that root at a measured support point. A support name or global AABB maximum is not
|
|
59
|
-
a surface measurement. Use an authored mount point or runtime support query for curved or stepped
|
|
60
|
-
geometry. Treat skinned bounds as bind-pose estimates and confirm foot contact in the active poses.
|
|
61
|
-
|
|
62
|
-
Read exactly one reference matching the code being edited:
|
|
63
|
-
[direct Engine](references/direct-engine.md), [React](references/react.md), or
|
|
64
|
-
[Web Components](references/web-components.md). Choose from imports and markup, not installed
|
|
65
|
-
dependencies alone.
|
|
34
|
+
Read only the reference matching the code: [direct Engine](references/direct-engine.md),
|
|
35
|
+
[React](references/react.md), or [Web Components](references/web-components.md).
|
|
@@ -4,12 +4,12 @@ Keep gameplay placement on the outer entity and calibration on a visual child:
|
|
|
4
4
|
|
|
5
5
|
```html
|
|
6
6
|
<pc-app>
|
|
7
|
-
<pc-asset id="
|
|
7
|
+
<pc-asset id="model" src="/models/model.glb"></pc-asset>
|
|
8
8
|
<pc-scene>
|
|
9
|
-
<pc-entity name="
|
|
9
|
+
<pc-entity name="Model" position="12 0 -4" rotation="0 90 0">
|
|
10
10
|
<pc-entity rotation="0 180 0">
|
|
11
11
|
<pc-entity position="-0.45 1.2 0.225" scale="0.9 0.9 0.9">
|
|
12
|
-
<pc-model asset="
|
|
12
|
+
<pc-model asset="model"></pc-model>
|
|
13
13
|
</pc-entity>
|
|
14
14
|
</pc-entity>
|
|
15
15
|
</pc-entity>
|
|
@@ -1,50 +1,34 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: configure-animation
|
|
3
|
-
description: Use before playing, blending, or retargeting GLB animation clips in PlayCanvas
|
|
3
|
+
description: Use before playing, blending, or retargeting GLB animation clips in PlayCanvas, or when diagnosing T-pose, frozen playback, or binding failures.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Animation setup
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Get clip and joint names from `inspect-glb`; never guess them.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
Clamp every 1D blend parameter to the first and last child points before updating it. PlayCanvas
|
|
20
|
-
does not clamp values outside that span: every child can receive zero weight and synchronized clips
|
|
21
|
-
can receive non-finite speeds, freezing the pose. Exercise the first, interior, and last blend
|
|
22
|
-
points with real gameplay input.
|
|
23
|
-
|
|
24
|
-
## Retarget only compatible rigs
|
|
25
|
-
|
|
26
|
-
For each source `animationTargets` entry, remove its final `.translation`, `.rotation`, `.scale`, or
|
|
27
|
-
`.weights` suffix and match the remaining path against the destination's `nodePaths`. The top-level
|
|
28
|
-
model root may differ; the remaining parent chain must match. Equal joint counts or similar bone
|
|
29
|
-
names are insufficient. Confirm the result in the running app as the `apply-conventions` skill
|
|
30
|
-
describes; frozen, partial, or exploded motion means the rigs are incompatible.
|
|
10
|
+
- For one clip, use the surface's simple playback path. For blending, transitions, or events, adapt
|
|
11
|
+
an `AnimStateGraph` from an official animation example with `find-examples`.
|
|
12
|
+
- Put the `anim` component on or above the rendered skinned hierarchy, not on a separate pivot.
|
|
13
|
+
- Clamp every 1D blend parameter to its first and last child points. The Engine does not; values
|
|
14
|
+
outside the span zero every weight and can make synced speeds non-finite, freezing the pose.
|
|
15
|
+
- Retarget only when each source `animationTargets` path, minus its `.translation`, `.rotation`,
|
|
16
|
+
`.scale`, or `.weights` suffix, matches a destination `nodePaths` entry below the model root.
|
|
17
|
+
Equal joint counts or similar names are not enough.
|
|
18
|
+
- Scale a wrapper, never skinned bones.
|
|
31
19
|
|
|
32
20
|
## Prove playback
|
|
33
21
|
|
|
34
|
-
An
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
confirm pose changes at idle and at both ends of each blend tree. Zero joint motion indicates a
|
|
38
|
-
binding, playback, or blend-weight failure even when reported state names look correct.
|
|
22
|
+
An active state or advancing state time does not prove motion. Sample two non-root joints over
|
|
23
|
+
several rendered frames at idle and at both ends of each blend tree. Zero joint motion means a
|
|
24
|
+
binding, playback, or blend-weight failure.
|
|
39
25
|
|
|
40
|
-
## Diagnose
|
|
26
|
+
## Diagnose
|
|
41
27
|
|
|
42
|
-
-
|
|
43
|
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
28
|
+
- T-pose: no clip assigned, target paths differ, or the anim component sits outside the rendered
|
|
29
|
+
hierarchy.
|
|
30
|
+
- Frozen pose: an unclamped blend input or a non-finite speed.
|
|
31
|
+
- Partial or exploded motion: incompatible rigs.
|
|
46
32
|
|
|
47
|
-
Read
|
|
48
|
-
[
|
|
49
|
-
[Web Components](references/web-components.md). Choose from imports and markup, not installed
|
|
50
|
-
dependencies alone.
|
|
33
|
+
Read only the reference matching the code: [direct Engine](references/direct-engine.md),
|
|
34
|
+
[React](references/react.md), or [Web Components](references/web-components.md).
|
|
@@ -21,10 +21,10 @@ Place the anim component on or above the complete skinned render hierarchy befor
|
|
|
21
21
|
Attaching it to an unrelated pivot does not bind the clip.
|
|
22
22
|
|
|
23
23
|
Clamp 1D state-graph parameters to their authored child range. For children at `0.5`, `3.5`, and
|
|
24
|
-
`8`, do not pass an unclamped
|
|
24
|
+
`8`, do not pass an unclamped value:
|
|
25
25
|
|
|
26
26
|
```ts
|
|
27
|
-
entity.anim?.setFloat('
|
|
27
|
+
entity.anim?.setFloat('blend', Math.max(0.5, Math.min(8, value)));
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
After assignment, drive the real gameplay inputs through the range and sample expected moving
|
|
@@ -7,13 +7,13 @@ import { Entity } from '@playcanvas/react';
|
|
|
7
7
|
import { Anim, Render } from '@playcanvas/react/components';
|
|
8
8
|
import { useModel } from '@playcanvas/react/hooks';
|
|
9
9
|
|
|
10
|
-
const
|
|
11
|
-
const { asset, error } = useModel('/models/
|
|
10
|
+
const Model = () => {
|
|
11
|
+
const { asset, error } = useModel('/models/model.glb');
|
|
12
12
|
if (error) throw new Error(error);
|
|
13
13
|
if (!asset) return null;
|
|
14
14
|
|
|
15
15
|
return (
|
|
16
|
-
<Entity name="
|
|
16
|
+
<Entity name="Model">
|
|
17
17
|
<Render type="asset" asset={asset} />
|
|
18
18
|
<Anim asset={asset} activate />
|
|
19
19
|
</Entity>
|
|
@@ -1,79 +1,43 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: find-examples
|
|
3
|
-
description: Use when implementing
|
|
3
|
+
description: Use when implementing a PlayCanvas feature the project does not use yet, to find and adapt the official example matching the installed version.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Official examples
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
Examples are version-matched recipes to adapt, not modules to import. When the Engine ships a script
|
|
9
|
+
for the behaviour, use `reuse-scripts` first.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
required behavior.
|
|
11
|
+
## Find the example
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
When `node_modules/playcanvas` is a local source checkout or linked build — a symlink, a workspace,
|
|
17
|
-
or a path dependency — its `examples/src/examples/**` are already on disk. Read them directly and
|
|
18
|
-
skip the GitHub fetch below. A linked engine can sit ahead of any published tag, and a pre-release
|
|
19
|
-
version (`-alpha`, `-beta`) may have no matching public tree, so the on-disk source is the ground
|
|
20
|
-
truth. Fall back to GitHub only when the examples are absent locally; the published npm package
|
|
21
|
-
omits `examples/`.
|
|
22
|
-
|
|
23
|
-
```sh
|
|
24
|
-
ls node_modules/playcanvas/examples/src/examples 2>/dev/null && echo "linked engine: read local examples, skip the fetch"
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Search the active surface's own catalog first, then the Engine catalog. Engine examples are the
|
|
28
|
-
largest set and port to every surface; the per-surface catalogs are smaller but need no translation.
|
|
29
|
-
|
|
30
|
-
| Surface | Repository | Package | Ref | Example paths |
|
|
31
|
-
| --- | --- | --- | --- | --- |
|
|
32
|
-
| direct Engine | `playcanvas/engine` | `playcanvas` | `v<version>` | `examples/src/examples/<category>/<name>.example.mjs` |
|
|
33
|
-
| Web Components | `playcanvas/web-components` | `@playcanvas/web-components` | `v<version>` | `examples/<name>.html` |
|
|
34
|
-
| React | `playcanvas/developer-site` | `@playcanvas/react` | `main` | `docs/user-manual/react/examples/<name>.mdx` |
|
|
35
|
-
|
|
36
|
-
Resolve the installed version instead of assuming the newest API:
|
|
37
|
-
|
|
38
|
-
```sh
|
|
39
|
-
PKG=playcanvas # or @playcanvas/web-components
|
|
40
|
-
TAG="v$(node -p "JSON.parse(require('fs').readFileSync('node_modules/$PKG/package.json')).version")" || exit 1
|
|
41
|
-
gh api "repos/playcanvas/engine/git/trees/$TAG?recursive=1" \
|
|
42
|
-
| grep -o '"examples/src/examples/[^"]*\.example\.mjs"'
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
Read the resolved package rather than the dependency list; `playcanvas` is often a transitive
|
|
46
|
-
dependency of `@playcanvas/react` or `@playcanvas/web-components`. Stop on a failed read instead of
|
|
47
|
-
requesting an invalid tag: an unresolved version produces an empty example list, not an error. When
|
|
48
|
-
the package is not below the project root's `node_modules`, run the command from the workspace that
|
|
49
|
-
depends on it.
|
|
50
|
-
|
|
51
|
-
List a different surface by substituting its repository and path pattern, such as
|
|
52
|
-
`'"examples/[^"]*\.html"'` for Web Components. Fetch a candidate from the same ref:
|
|
13
|
+
If `node_modules/playcanvas/examples/src/examples` exists, it is a linked or source checkout: read
|
|
14
|
+
it locally. The npm package omits `examples/`, so otherwise fetch from the installed tag:
|
|
53
15
|
|
|
54
16
|
```sh
|
|
17
|
+
TAG="v$(node -p "JSON.parse(require('fs').readFileSync('node_modules/playcanvas/package.json')).version")" || exit 1
|
|
18
|
+
gh api "repos/playcanvas/engine/git/trees/$TAG?recursive=1" | grep -o '"examples/src/examples/[^"]*\.example\.mjs"'
|
|
55
19
|
gh api "repos/playcanvas/engine/contents/examples/src/examples/<category>/<name>.example.mjs?ref=$TAG" \
|
|
56
20
|
--jq .content | base64 --decode
|
|
57
21
|
```
|
|
58
22
|
|
|
59
|
-
|
|
60
|
-
|
|
23
|
+
Read the resolved package, not the dependency list; `playcanvas` is often transitive. An empty list
|
|
24
|
+
means an invalid tag: stop rather than guess. Use `main` only when the version has no tag.
|
|
61
25
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
26
|
+
| Surface | Repository | Ref | Example paths |
|
|
27
|
+
| --- | --- | --- | --- |
|
|
28
|
+
| direct Engine | `playcanvas/engine` | `v<version>` | `examples/src/examples/<category>/<name>.example.mjs` |
|
|
29
|
+
| Web Components | `playcanvas/web-components` | `v<version>` | `examples/<name>.html` |
|
|
30
|
+
| React | `playcanvas/developer-site` | `main` | `docs/user-manual/react/examples/<name>.mdx` |
|
|
66
31
|
|
|
67
|
-
|
|
32
|
+
Search the surface's catalog first, then the Engine's. React pages track the latest package; verify
|
|
33
|
+
each prop against the installed declarations. Fetch example assets, including the Draco, Basis, and
|
|
34
|
+
Ammo decoders under `examples/assets/wasm`, from the same ref.
|
|
68
35
|
|
|
69
|
-
|
|
70
|
-
example browser's controls and context imports.
|
|
36
|
+
## Adapt it
|
|
71
37
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
38
|
+
Keep component options, scene setup, materials, shaders, assets, and update logic; drop the example
|
|
39
|
+
browser's controls and imports. When one example joins several systems, such as layers, depth,
|
|
40
|
+
camera frame, and sky, get that baseline rendering before customizing it.
|
|
75
41
|
|
|
76
|
-
Read
|
|
77
|
-
[
|
|
78
|
-
[Web Components](references/web-components.md). Choose from imports and markup, not installed
|
|
79
|
-
dependencies alone.
|
|
42
|
+
Read only the reference matching the code: [direct Engine](references/direct-engine.md),
|
|
43
|
+
[React](references/react.md), or [Web Components](references/web-components.md).
|