create-playcanvas 0.8.1 → 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/package.json +1 -1
- package/skills/add-effects/SKILL.md +21 -83
- 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 -56
- package/skills/build-app/SKILL.md +36 -37
- 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 -97
- package/skills/load-assets/SKILL.md +52 -0
- package/skills/override-shader-chunks/SKILL.md +21 -61
- package/skills/reduce-draw-calls/SKILL.md +24 -54
- package/skills/reuse-scripts/SKILL.md +23 -46
- package/skills/reuse-scripts/references/direct-engine.md +3 -3
- package/skills/verify-pixels/SKILL.md +24 -58
- package/skills/build-hud/SKILL.md +0 -38
- package/skills/manage-game-state/SKILL.md +0 -48
|
@@ -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).
|
|
@@ -1,81 +1,40 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: inspect-glb
|
|
3
|
-
description: Use before loading, placing, scaling, or animating GLB
|
|
3
|
+
description: Use before loading, placing, scaling, or animating GLB models in PlayCanvas to measure bounds, grounding, clips, joints, and hierarchy with the bundled offline inspector.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Inspect GLBs
|
|
7
7
|
|
|
8
|
-
Resolve `scripts/inspect.mjs` relative to this skill
|
|
9
|
-
|
|
8
|
+
Resolve `scripts/inspect.mjs` relative to this skill and run it before choosing transforms or
|
|
9
|
+
animation names. Shortlist files; do not dump a whole asset pack into context.
|
|
10
10
|
|
|
11
11
|
```sh
|
|
12
|
-
node <skill-directory>/scripts/inspect.mjs public/models
|
|
13
|
-
node <skill-directory>/scripts/inspect.mjs public/models/{Ship,Enemy}_*.glb
|
|
12
|
+
node <skill-directory>/scripts/inspect.mjs public/models/*.glb
|
|
14
13
|
```
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
## Read the output
|
|
17
16
|
|
|
18
|
-
- `dims`
|
|
19
|
-
- `
|
|
20
|
-
- `
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
- `
|
|
24
|
-
- `
|
|
25
|
-
- `
|
|
17
|
+
- `dims`, `center`, and `groundOffset` give the uniform scale input, the pivot offset, and the Y
|
|
18
|
+
seat. Non-zero `center.x` or `center.z` means the model does not sit on its root.
|
|
19
|
+
- `boundsSource`: trust bounds for placement only when it is `vertices`. `accessor-minmax` can
|
|
20
|
+
over-estimate rotated nodes by up to 41 percent; `incomplete` or `null` means do not calibrate.
|
|
21
|
+
`boundsNotes` gives the cause.
|
|
22
|
+
- `boundsPose`: `static` and `default-morph` are the authored pose; `bind` is the skinned rest pose.
|
|
23
|
+
- `requiresRuntimeCheck` flags morphs, skins, or partial decoding; confirm extents in the app.
|
|
24
|
+
- `nodePaths`, `clips`, `joints`, and `animationTargets` feed `configure-animation`.
|
|
26
25
|
|
|
27
|
-
|
|
26
|
+
Bounds cannot prove facing. Confirm it in the running app and record the yaw with
|
|
27
|
+
`calibrate-model`. Runtime `meshInstance.aabb` expands conservatively for morphs, so place static
|
|
28
|
+
models from inspected bounds.
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
weights, and each node's world matrix. Confirm both source and pose before relying on them:
|
|
30
|
+
## Compressed files
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
rotated off-axis, by up to 41 percent for a 45-degree yaw. `boundsNotes` gives the cause.
|
|
36
|
-
- `incomplete` means some visible default-pose geometry could not be measured; do not calibrate from
|
|
37
|
-
the reported bounds.
|
|
38
|
-
- `null` means no usable bounds could be recovered.
|
|
39
|
-
|
|
40
|
-
`static` and `default-morph` bounds describe visible geometry at its authored default pose. `bind`
|
|
41
|
-
describes skinned vertices before animation. When `requiresRuntimeCheck` is true, confirm grounding
|
|
42
|
-
and maximum animated extent in the running application even if `boundsSource` is `vertices`.
|
|
43
|
-
|
|
44
|
-
Carry `boundsSource`, `aabb`, `dims`, `center`, and `groundOffset` into the asset tuning record.
|
|
45
|
-
`groundOffset` seats the base in Y; `center.x` and `center.z` are the horizontal pivot offset that
|
|
46
|
-
`calibrate-model` must compensate, so a placed root sits where the mesh appears, not where the
|
|
47
|
-
authored pivot happens to be. Running the inspector alone is not placement evidence. Its global AABB supports plane grounding and
|
|
48
|
-
broad-phase spacing, but cannot locate a non-planar support surface or attachment point. Use an
|
|
49
|
-
authored mount point or confirm the support in the running application before placing another model.
|
|
50
|
-
|
|
51
|
-
## Extract from compressed containers
|
|
52
|
-
|
|
53
|
-
The bundled inspector decodes plain, interleaved, quantized, and sparse vertex buffers. For Draco,
|
|
54
|
-
Meshopt, or external buffers, `boundsNotes` names the cause. Parse and rewrite a scratch copy with
|
|
55
|
-
glTF Transform's lossless `copy` command, then inspect that copy rather than shipping it:
|
|
32
|
+
The inspector decodes plain, interleaved, quantized, and sparse buffers. For Draco, Meshopt, or
|
|
33
|
+
external buffers, inspect a lossless scratch copy; do not use `optimize`, which applies extra
|
|
34
|
+
transforms:
|
|
56
35
|
|
|
57
36
|
```sh
|
|
58
37
|
npx --yes @gltf-transform/cli@4.4.2 copy in.glb scratch.glb
|
|
59
|
-
node <skill-directory>/scripts/inspect.mjs scratch.glb
|
|
60
38
|
```
|
|
61
39
|
|
|
62
|
-
|
|
63
|
-
Meshopt compression. Existing lossy compression may already have quantized the source. Do not
|
|
64
|
-
substitute `optimize`: it enables additional transforms unless each one is understood and disabled.
|
|
65
|
-
|
|
66
|
-
The Engine has no `EXT_meshopt_compression` support, so a meshopt asset will not render as shipped.
|
|
67
|
-
If it must appear in the scene, transcode it to an uncompressed GLB the same way — subject to the
|
|
68
|
-
project's rules on modifying assets — so it both loads and measures.
|
|
69
|
-
|
|
70
|
-
These geometry-fit bounds can intentionally disagree with the Engine's runtime culling AABB.
|
|
71
|
-
`MeshInstance.aabb` transforms the declared local box and expands it conservatively for morph
|
|
72
|
-
targets, so it can be larger than visible geometry. Place static models from exact inspected bounds;
|
|
73
|
-
confirm morph and skin extremes at runtime. A skinned mesh node's own transform is ignored here
|
|
74
|
-
because glTF requires it; the Engine resolves to the same result.
|
|
75
|
-
|
|
76
|
-
Shortlist files first; do not dump an entire asset pack into context. Bounds cannot prove facing.
|
|
77
|
-
glTF convention is +Z forward while PlayCanvas entities face -Z, and asset packs vary. Confirm each
|
|
78
|
-
directional model once in the running app as the `apply-conventions` skill describes, and store its
|
|
79
|
-
yaw correction with its scale and grounding.
|
|
80
|
-
|
|
81
|
-
Use `npx @gltf-transform/cli inspect` only when vertex or texture statistics justify extra tooling.
|
|
40
|
+
The Engine cannot load `EXT_meshopt_compression`; see `load-assets` before shipping such files.
|
|
@@ -1,109 +1,41 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: light-scene
|
|
3
|
-
description: Use when
|
|
3
|
+
description: Use when lighting or rendering a PlayCanvas scene, covering lights, ambient and environment lighting, sky, shadows, tone mapping, exposure, fog, and post-processing.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# Light and render a scene
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
than from memory.
|
|
8
|
+
Engine defaults give a flat, dark image; change them deliberately. Tune against inspected
|
|
9
|
+
screenshots, one class of value at a time.
|
|
11
10
|
|
|
12
|
-
##
|
|
11
|
+
## Defaults to change
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
- `scene.ambientLight` is black, so unlit sides render pure black. Light ambient and reflections
|
|
14
|
+
from an environment atlas or skybox, or set an ambient colour.
|
|
15
|
+
- Cameras default to `TONEMAP_LINEAR`. Choose `TONEMAP_NEUTRAL`, `TONEMAP_ACES2`, or
|
|
16
|
+
`TONEMAP_FILMIC` (on `cameraFrame.rendering.toneMapping` when using `CameraFrame`), set exposure,
|
|
17
|
+
then balance light intensities to it.
|
|
18
|
+
- Shadows are off. Enable `castShadows` on the key light. Directional `shadowDistance` is 40 m, so
|
|
19
|
+
use cascades for large scenes, and `SHADOWUPDATE_THISFRAME` for static shadows. Size resolution to
|
|
20
|
+
the framed subject.
|
|
21
|
+
- Lights shine along local -Y (`apply-conventions`).
|
|
18
22
|
|
|
19
|
-
##
|
|
23
|
+
## Use what ships
|
|
20
24
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
- `CameraFrame` handles tone mapping, bloom, SSAO, DOF, vignette, and grading. Call `update()` after
|
|
26
|
+
changes and destroy it with the app. Keep bloom intensity within the documented 0 to 0.1.
|
|
27
|
+
- `scene.sky.type` (`SKYTYPE_DOME`, `SKYTYPE_BOX`, `SKYTYPE_INFINITE`) grounds an environment sky.
|
|
28
|
+
- The `ProceduralSky` script owns a linked sun light: set the light's base intensity, then tune
|
|
29
|
+
elevation and azimuth on the sky, not the light.
|
|
30
|
+
- The `ShadowCatcher` script grounds subjects that have no lit floor.
|
|
31
|
+
- Clustered lighting is on by default, so many point and spot lights are cheap.
|
|
32
|
+
- Bake static lights with `bake-lighting`; stylize shading with `override-shader-chunks`.
|
|
29
33
|
|
|
30
|
-
|
|
34
|
+
Find each integration's example with `find-examples`.
|
|
31
35
|
|
|
32
|
-
|
|
33
|
-
`reuse-scripts` skill and adapt the closest official example with `find-examples`:
|
|
36
|
+
## Warning signs
|
|
34
37
|
|
|
35
|
-
-
|
|
36
|
-
|
|
37
|
-
-
|
|
38
|
-
|
|
39
|
-
For an outdoor scene whose brief asks for reflective, photoreal water, stop before authoring the
|
|
40
|
-
scene and read both `reuse-scripts` and `find-examples`. Use `graphics/water.example.mjs` as the
|
|
41
|
-
initial composition recipe: it already joins the production `Water` script, sky, sun, `CameraFrame`,
|
|
42
|
-
water layer, scene depth, and reflection pipeline. Get that complete frame rendering before
|
|
43
|
-
replacing its assets or tuning its look; a custom normal-mapped material or tessellated plane is not
|
|
44
|
-
that baseline.
|
|
45
|
-
|
|
46
|
-
For that water scene, keep both production integrations visible in the implementation:
|
|
47
|
-
|
|
48
|
-
- import and create `Water` from `playcanvas/scripts/esm/water.mjs` on the water entity, preserving
|
|
49
|
-
the example's required render component, camera reference, water layer, depth map, and textures;
|
|
50
|
-
- construct `CameraFrame` from `playcanvas` for the gameplay camera, set a deliberate tone map and
|
|
51
|
-
restrained grade, call `update()`, and destroy it with the application.
|
|
52
|
-
|
|
53
|
-
Do not continue to cosmetic tuning while a required integration is missing or diagnostics report
|
|
54
|
-
a shader, texture, or framebuffer error.
|
|
55
|
-
|
|
56
|
-
## Light and expose
|
|
57
|
-
|
|
58
|
-
- Establish one dominant key light with a clear direction and warm or cool intent, then add soft
|
|
59
|
-
fill or ambient so shadows are not crushed to black. A single flat ambient with no key reads as an
|
|
60
|
-
asset gallery.
|
|
61
|
-
- Choose a physically based tone mapping and a deliberate exposure, then balance light intensities to
|
|
62
|
-
that exposure, not the reverse.
|
|
63
|
-
- Drive ambient and reflections from the sky or an environment map, not a constant colour, so
|
|
64
|
-
materials pick up their surroundings.
|
|
65
|
-
- Tune the HDR stack in isolation before styling it. Begin with neutral tone mapping, scene exposure
|
|
66
|
-
`1`, procedural-sky luminance near its official-example value, bloom off, grading neutral, fog off,
|
|
67
|
-
and reflection/specular strengths at their defaults. Capture a screenshot, then change one class of
|
|
68
|
-
value at a time. Do not simultaneously raise key intensity, sky luminance, exposure, reflection,
|
|
69
|
-
saturation, fog brightness, and bloom.
|
|
70
|
-
- Treat linked procedural skies as the owner of the sun light's direction, colour, and intensity.
|
|
71
|
-
Set the light's base intensity before assigning it to the sky and tune the sky elevation/azimuth;
|
|
72
|
-
do not also hand-author the light transform or colour as though they remained independent.
|
|
73
|
-
- Preserve the source assets' albedo colours. If diffuse texture colours collapse toward white or a
|
|
74
|
-
single warm tint, reduce the HDR stack before compensating with darker material colours.
|
|
75
|
-
|
|
76
|
-
## Shadow and ground
|
|
77
|
-
|
|
78
|
-
- Enable shadows on the key light and size the shadow area and resolution to the framed subject, not
|
|
79
|
-
the whole world. Soften the penumbra rather than only raising resolution.
|
|
80
|
-
- Ground subjects with a contact or catcher shadow when the surface beneath them is not itself lit.
|
|
81
|
-
|
|
82
|
-
## Grade with restraint
|
|
83
|
-
|
|
84
|
-
- Bloom, fog, vignette, and colour grade unify a frame; overdone bloom and heavy fog destroy
|
|
85
|
-
silhouette and depth. Start subtle and increase only against the screenshot. `CameraFrame` bloom
|
|
86
|
-
intensity is documented for the `0` to `0.1` range; stay inside it.
|
|
87
|
-
- Match fog colour and density to the sky so the horizon stays coherent.
|
|
88
|
-
- Preserve surface detail through the brightest reflection path. If glare clips a large part of the
|
|
89
|
-
frame to white or a reflection becomes an opaque black blob, rebalance exposure, light intensity,
|
|
90
|
-
reflection strength, and shadow bias before adding more post-processing.
|
|
91
|
-
- Compare both the brightest surface and the shadow-facing side of the hero subject in the same
|
|
92
|
-
screenshot. Reject the grade if either broad highlight clipping or crushed-black silhouette hides
|
|
93
|
-
texture detail. A mechanically valid frame is not visually complete while either failure remains.
|
|
94
|
-
|
|
95
|
-
## Prove the look
|
|
96
|
-
|
|
97
|
-
For changes to an existing look, show old and new at the same pose in one image. If the difference
|
|
98
|
-
is not visible, report that before spending more time tuning.
|
|
99
|
-
|
|
100
|
-
Tune against pixels, not numbers. Capture the intended framing with an image-returning browser
|
|
101
|
-
screenshot tool and inspect the returned image, as `apply-conventions` and the local agent guide
|
|
102
|
-
require; a saved filepath is not evidence. Use two fixed poses, capture with a headless browser, and
|
|
103
|
-
return images at accept-or-reject points only, not after every edit. Confirm the subject is exposed
|
|
104
|
-
and readable, shadows are present but not crushed, and the grade is restrained, from the real
|
|
105
|
-
gameplay camera at the target resolution. Confirm the post-process camera keeps rendering as it
|
|
106
|
-
orbits and pitches.
|
|
107
|
-
|
|
108
|
-
Choose the authoring surface with the `build-app` skill and set lights, camera, and scene settings
|
|
109
|
-
through its own primitives before reaching into the Engine.
|
|
38
|
+
- Albedo washing toward white: reduce exposure, sky, and light intensity before darkening
|
|
39
|
+
materials.
|
|
40
|
+
- Large areas clipped white or crushed black: rebalance exposure and lights before adding post.
|
|
41
|
+
- A fog colour that differs from the sky horizon breaks the horizon line.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: load-assets
|
|
3
|
+
description: Use when loading glTF/GLB models or textures in PlayCanvas, choosing Draco or Basis/KTX2 compression, or setting up decoders and preloading.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Load assets
|
|
7
|
+
|
|
8
|
+
## glTF is fully supported
|
|
9
|
+
|
|
10
|
+
Load `.glb` files as `container` assets and call `asset.resource.instantiateRenderEntity()`, not
|
|
11
|
+
`instantiateModelEntity`. The importer already handles `KHR_lights_punctual`, `KHR_materials_*`
|
|
12
|
+
(clearcoat, sheen, transmission, volume, iridescence, variants, and more), `KHR_texture_transform`,
|
|
13
|
+
and `EXT_mesh_gpu_instancing`; do not rebuild these by hand. Preload asset sets with
|
|
14
|
+
`AssetListLoader`.
|
|
15
|
+
|
|
16
|
+
## Compress for size
|
|
17
|
+
|
|
18
|
+
- Geometry: Draco (`KHR_draco_mesh_compression`). Meshopt is not supported, so decode such files
|
|
19
|
+
before shipping.
|
|
20
|
+
- Textures: KTX2 with Basis (`KHR_texture_basisu`) transcodes to a GPU format, cutting both
|
|
21
|
+
download size and VRAM. ETC1S is smallest and lossy. UASTC is larger and keeps
|
|
22
|
+
detail, which matters most for normal maps. Weigh size against visible detail.
|
|
23
|
+
|
|
24
|
+
## Set up decoders
|
|
25
|
+
|
|
26
|
+
The npm package ships no Draco or Basis wasm. Copy `draco/` and `basis/` from the Engine's
|
|
27
|
+
`examples/assets/wasm` at the installed tag (`find-examples`), and configure them before loading:
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
import { WasmModule, basisInitialize } from 'playcanvas';
|
|
31
|
+
|
|
32
|
+
WasmModule.setConfig('DracoDecoderModule', {
|
|
33
|
+
glueUrl: '/wasm/draco/draco.wasm.js',
|
|
34
|
+
wasmUrl: '/wasm/draco/draco.wasm.wasm',
|
|
35
|
+
fallbackUrl: '/wasm/draco/draco.js'
|
|
36
|
+
});
|
|
37
|
+
await new Promise((resolve) => WasmModule.getInstance('DracoDecoderModule', resolve));
|
|
38
|
+
basisInitialize({
|
|
39
|
+
glueUrl: '/wasm/basis/basis.wasm.js',
|
|
40
|
+
wasmUrl: '/wasm/basis/basis.wasm.wasm',
|
|
41
|
+
fallbackUrl: '/wasm/basis/basis.js'
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
In Web Components, a `<pc-wasm name="DracoDecoderModule">` element under `<pc-app>` sets the Draco
|
|
46
|
+
config with `glue`, `wasm`, and `fallback` attributes.
|
|
47
|
+
|
|
48
|
+
## Other assets
|
|
49
|
+
|
|
50
|
+
- Raise `texture.anisotropy`, which defaults to 1, for surfaces viewed at grazing angles.
|
|
51
|
+
- Gaussian splats load as `gsplat` assets onto a `gsplat` component; start from a
|
|
52
|
+
`gaussian-splatting` example.
|