Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/user-manual/web-components/programmatic-access.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Keep that entry's URL identical to the library's `<script>` tag, or the page loa

:::note[Elements That Never Become Ready]

The promise never settles if the element cannot finish initializing — for example, a `<pc-script-instance>` that is not a direct child of `<pc-script>`, a [`<pc-node>`](./tags/pc-node.md) that cannot resolve its `name`, a [`<pc-model>`](./tags/pc-model.md) whose `asset` names no declared asset, a [`<pc-wasm>`](./tags/pc-wasm.md) without a `name` or whose module fails to load, or a [`<pc-app>`](./tags/pc-app.md) that could not create a graphics device (see its [`error` event](./tags/pc-app.md#events)). A component element with no `<pc-entity>`, `<pc-model>` or `<pc-node>` above it is the exception: it still becomes ready, but its `component` is `null`. In each of these cases, the console says what went wrong.
The promise never settles if the element cannot finish initializing — for example, a `<pc-script-instance>` that is not a direct child of `<pc-script>`, a [`<pc-node>`](./tags/pc-node.md) that cannot resolve its `name`, a [`<pc-model>`](./tags/pc-model.md) whose `asset` names no declared asset, a [`<pc-wasm>`](./tags/pc-wasm.md) without a `name` or with one in the wrong case, or a [`<pc-app>`](./tags/pc-app.md) that could not create a graphics device (see its [`error` event](./tags/pc-app.md#events)). A component element with no `<pc-entity>`, `<pc-model>` or `<pc-node>` above it is the exception: it still becomes ready, but its `component` is `null`. In each of these cases, the console says what went wrong.

An element *removed* from the document before it finished initializing does not become ready either — nothing is wrong, so nothing is reported, but an await on its `ready()` will not complete unless the element is put back, which carries the wait over to its next initialization. When teardown can race initialization (common with [cloned templates](templates.md)), race the await against your own teardown signal — see [Removing an Instance](templates.md#removing-an-instance).

Expand Down Expand Up @@ -128,10 +128,10 @@ const material = MaterialElement.get('gold'); // the material declared by <pc-ma

`AssetElement.get` returns the registered [`Asset`](https://api.playcanvas.com/engine/classes/Asset.html), which may not have finished loading yet — check `asset.loaded`, or subscribe to its `load` event, before using `asset.resource`. A failed load also sets `loaded`, with no `resource`. Looking a `lazy` asset up this way does not start its load, so call `app.assets.load(asset)` if nothing else will.

[`<pc-wasm>`](./tags/pc-wasm.md) initializes asynchronously like the elements above — it becomes ready once its module has loaded, so `whenReady('pc-wasm')` awaits the load. (`Basis` is the exception: it is ready as soon as its transcoder starts loading.) You will rarely need it: `<pc-app>` waits for every `<pc-wasm>` among its children before it creates its graphics device, so an app that is ready is an app whose modules have loaded. Awaiting the app is how you wait for Ammo:
[`<pc-wasm>`](./tags/pc-wasm.md) initializes asynchronously like the elements above — it becomes ready once its module has loaded or failed to load, so `whenReady('pc-wasm')` awaits the load. (`Basis` is the exception: it is ready as soon as its transcoder starts loading.) Readiness does not mean success: a module that fails also fires an [`error` event](./tags/pc-wasm.md#events). You will rarely need it: `<pc-app>` waits for every `<pc-wasm>` among its children to settle before it creates its graphics device, so by the time the app is ready each module has loaded or reported its failure. Awaiting the app is how you wait for Ammo:

```javascript
const { app } = await whenReady('pc-app'); // every <pc-wasm> has loaded by now
const { app } = await whenReady('pc-app'); // every <pc-wasm> has loaded or failed by now
```

One caveat sets `<pc-wasm>` apart: its readiness is sticky. WebAssembly modules configure engine-global state that never unloads, so removing and re-inserting the element neither resets its readiness nor loads the module again — see [Readiness](./tags/pc-wasm.md#readiness).
Expand Down
2 changes: 1 addition & 1 deletion docs/user-manual/web-components/tags/pc-app.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ The `<pc-app>` tag is the root element for your PlayCanvas application. It is us
| `physics-time-scale` | Number | `"1"` | Scale on the time the physics simulation advances by each frame, applied on top of `time-scale`: below 1 is slow motion, above 1 speeds it up, and `"0"` pauses physics while the rest of the application keeps running — for a pause menu, say, that must stay interactive while the world stands still |
| `picking` | Enum | `"auto"` | When the application picks the scene under the pointer to dispatch [pointer events](../pc-entity#events) on entity elements: `"auto"` \| `"always"` \| `"none"`. `auto` picks for an event type only while a listener for it is registered on an entity element or on [`<pc-scene>`](../pc-scene); `always` picks for every pointer event, which listeners the application cannot see need, such as one on the document or a framework's delegated handler like React's `onPointerMove`; `none` never picks, so entities receive no pointer events. Picking renders the scene again, which is why `auto` is the default. See [When Events Are Dispatched](../pc-entity#when-events-are-dispatched) |
| `stencil-buffer` | Boolean | `"true"` | Whether the application allocates a stencil buffer |
| `time-scale` | Number | `"1"` | Scale on the time the application advances by each frame. Scripts, animation and physics all advance by the scaled time, so below 1 is slow motion, above 1 speeds it up, and `"0"` pauses all three together while the scene keeps rendering. To slow down or pause physics alone, use `physics-time-scale` |
| `time-scale` | Number | `"1"` | Scale on the time the application advances by each frame. Scripts, animation and physics all advance by the scaled time, so below 1 is slow motion, above 1 speeds it up, and `"0"` freezes everything that advances with time while the scene keeps rendering. It does not pause scripts: their `update` and `postUpdate` methods still run every frame with a `dt` of 0, so input handling, spawning and any other logic that is not multiplied by `dt` carries on — give gameplay code its own pause check. To slow down or pause physics alone, use `physics-time-scale` |
| `with-credentials` | Boolean | `"false"` | Whether asset requests send credentials (cookies and HTTP authentication) to other origins, which the asset server must allow through CORS. The engine keeps this setting in an HTTP client shared by the whole page, so it applies to every `<pc-app>` on the page: an app that boots with it switches it on for all of them, and a later change on any app sets it for all of them |

</div>
Expand Down
2 changes: 1 addition & 1 deletion docs/user-manual/web-components/tags/pc-asset.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ Listen to these events using [`addEventListener()`](https://developer.mozilla.or
| `load` | Fired each time the asset finishes loading, including a `lazy` asset loaded later and any subsequent reloads. |
| `error` | An [`ErrorEvent`](https://developer.mozilla.org/en-US/docs/Web/API/ErrorEvent) fired when the asset fails to load, with the engine's error in `message`. |

Neither event bubbles, so listen on the element itself — or use a capture-phase listener on `<pc-app>` to observe every asset it holds. The same listener also sees other elements' `error` events, such as [`<pc-model>`](../pc-model)'s and the app's own, so check the target:
Neither event bubbles, so listen on the element itself — or use a capture-phase listener on `<pc-app>` to observe every asset it holds. The same listener also sees other elements' `error` events, such as [`<pc-model>`](../pc-model)'s, [`<pc-wasm>`](../pc-wasm)'s and the app's own, so check the target:

```javascript
document.querySelector('pc-app').addEventListener('error', (event) => {
Expand Down
39 changes: 28 additions & 11 deletions docs/user-manual/web-components/tags/pc-wasm.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ The `<pc-wasm>` tag loads a WebAssembly module the engine needs before the appli

</div>

The `name` is case-sensitive — the engine looks the module up by exact name. The modules consumed by the engine are `Ammo` (physics), `Basis` (texture transcoding) and `DracoDecoderModule` (mesh decompression).
The `name` is case-sensitive — the engine looks the module up by exact name. The modules consumed by the engine are `Ammo` (physics), `Basis` (texture transcoding) and `DracoDecoderModule` (mesh decompression). Getting the case wrong is the one load failure the element cannot report: with `name="ammo"`, the engine throws a `TypeError` as the glue script loads, no `error` event fires, and neither the element nor its `<pc-app>` ever becomes ready.

:::note[When these are read]

Expand All @@ -37,26 +37,43 @@ attributes before appending the element to the document.

## Readiness

The element initializes asynchronously and becomes ready once its module has loaded: it fires the
standard `ready` event and can be awaited with `whenReady('pc-wasm')` — see
The element initializes asynchronously and becomes ready once its module has loaded or failed to
load: it fires the standard `ready` event and can be awaited with `whenReady('pc-wasm')` — see
[Programmatic Access](../programmatic-access.md). (`Basis` is the exception: it is ready as soon
as its transcoder starts loading.) You will rarely need to, though: a `<pc-app>` waits for every
`<pc-wasm>` among its children before creating its graphics device, so an app that is ready is an
app whose modules have loaded. A `<pc-wasm>` nested any deeper still loads, but the app does not
wait for it.
as its transcoder starts loading.) Readiness means the load settled, not that it succeeded; a
module that fails also fires [`error`](#events). You will rarely need to wait for the element,
though: a `<pc-app>` waits for every `<pc-wasm>` among its children to settle before creating its
graphics device, so by the time the app is ready each module has either loaded or reported its
failure. A `<pc-wasm>` nested any deeper still loads, but the app does not wait for it.

Readiness is deliberately sticky. A WebAssembly module configures engine-global state that never
unloads, so removing the element does not return it to a pending state, and re-inserting it does
not load the module again.

A `<pc-wasm>` without a `name` logs a warning and never becomes ready — but it does not block
the containing `<pc-app>` from booting. A module that fails to load, from a mistyped URL or a
server that refuses it, is worse: the element never becomes ready and its `<pc-app>` never starts,
with only a `failed to initialize module=...` error in the console to show for it.
the containing `<pc-app>` from booting.

Declare `Ammo` in the markup rather than adding it later. The engine looks for the physics module
once, as the application starts, so an app that booted without it runs without physics.

## Events

Listen to this event using [`addEventListener()`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) or by assigning an event listener to the `oneventname` property of this interface.

| Event | Description |
| --- | --- |
| `error` | An [`ErrorEvent`](https://developer.mozilla.org/en-US/docs/Web/API/ErrorEvent) fired when the module fails to load — from a mistyped URL, say, or a server that refuses it — with the engine's error in `message`. It fires once per element, and the element still becomes ready. A `Basis` module never fires it. |

The event does not bubble, so listen on the element itself or with a capture-phase listener on
`<pc-app>`.

A module that fails to load does not stop the application. The element logs
`pc-wasm failed to load module '<name>' - <error>` to the console, and the containing `<pc-app>`
boots without the module — a failed `Ammo` leaves the app running without physics. The engine
never tries to load a failed module again, so every `<pc-wasm>` for that module fails with it: one
already waiting when the load fails, and one added later, in a second `<pc-app>` say, which fails
straight away.

## Example

Loading the `Ammo` physics module. The box only falls because the module is declared — the app waits for it before booting, so physics is ready when the scene starts. Try removing the `<pc-wasm>` tag and re-running:
Expand Down Expand Up @@ -90,7 +107,7 @@ Loading the `Ammo` physics module. The box only falls because the module is decl

You can programmatically create and manipulate `<pc-wasm>` elements using the [WasmElement API](https://api.playcanvas.com/web-components/classes/WasmElement.html).

The element exposes no engine object of its own. Once it is ready the module has been instantiated through the engine's `WasmModule` under its `name` (`Basis` goes through the engine's Basis initializer instead). Ammo's glue script defines the global `Ammo`, so scripts can use it directly; reach other modules through `WasmModule.getInstance(name, callback)`.
The element exposes no engine object of its own. A module that loads is instantiated through the engine's `WasmModule` under its `name` (`Basis` goes through the engine's Basis initializer instead). Ammo's glue script defines the global `Ammo`, so scripts can use it directly; reach other modules through `WasmModule.getInstance(name, callback)`. Both depend on the load succeeding, which readiness does not tell you: after a failed load the element is still ready, but `Ammo` stays undefined and `getInstance` never calls its callback. Code that needs a module must handle that outcome — listen for the element's [`error`](#events) event and carry on without the module, running without physics for a failed `Ammo`, rather than wait on `getInstance`.

## See Also

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ PlayCanvas Web Components を使えば、HTML だけでリッチな 3D シーン

:::note[準備完了にならない要素]

要素が初期化を完了できない場合、Promiseは決して解決されません。たとえば、`<pc-script>` の直接の子ではない `<pc-script-instance>`、`name` を解決できない [`<pc-node>`](./tags/pc-node.md)、`asset` が宣言されたどのアセットも指していない [`<pc-model>`](./tags/pc-model.md)、`name` がないかモジュールの読み込みに失敗した [`<pc-wasm>`](./tags/pc-wasm.md)、グラフィックスデバイスを作成できなかった [`<pc-app>`](./tags/pc-app.md)(その [`error` イベント](./tags/pc-app.md#events)を参照)などです。例外は、上に `<pc-entity>`・`<pc-model>`・`<pc-node>` のいずれもないコンポーネント要素で、この場合はready状態にはなりますが、`component` は `null` になります。これらのいずれの場合も、何が問題だったかがコンソールに出力されます。
要素が初期化を完了できない場合、Promiseは決して解決されません。たとえば、`<pc-script>` の直接の子ではない `<pc-script-instance>`、`name` を解決できない [`<pc-node>`](./tags/pc-node.md)、`asset` が宣言されたどのアセットも指していない [`<pc-model>`](./tags/pc-model.md)、`name` がないか、その大文字と小文字が誤っている [`<pc-wasm>`](./tags/pc-wasm.md)、グラフィックスデバイスを作成できなかった [`<pc-app>`](./tags/pc-app.md)(その [`error` イベント](./tags/pc-app.md#events)を参照)などです。例外は、上に `<pc-entity>`・`<pc-model>`・`<pc-node>` のいずれもないコンポーネント要素で、この場合はready状態にはなりますが、`component` は `null` になります。これらのいずれの場合も、何が問題だったかがコンソールに出力されます。

初期化が完了する前にドキュメントから*削除された*要素も、ready状態にはなりません — 何も問題は起きていないので何も報告されませんが、要素が元に戻されない限り、その `ready()` に対するawaitは完了しません。元に戻された場合、待機は次の初期化に引き継がれます。破棄が初期化と競合しうる場合([クローンされたテンプレート](templates.md)ではよくあることです)は、awaitを自分自身の破棄シグナルと競争させてください — [インスタンスを削除する](templates.md#removing-an-instance)を参照してください。

Expand Down Expand Up @@ -128,10 +128,10 @@ const material = MaterialElement.get('gold'); // <pc-material id="gold"> が宣

`AssetElement.get` は登録済みの [`Asset`](https://api.playcanvas.com/engine/classes/Asset.html) を返しますが、読み込みが完了していない場合があります。`asset.resource` を使用する前に、`asset.loaded` を確認するか、`load` イベントを購読してください。読み込みに失敗した場合も `loaded` は設定され、`resource` はありません。`lazy` のアセットをこの方法で取得しても読み込みは始まらないため、他に読み込むものがなければ `app.assets.load(asset)` を呼び出してください。

[`<pc-wasm>`](./tags/pc-wasm.md) は、上記の要素と同じく非同期に初期化されます。モジュールの読み込みが完了するとready状態になるため、`whenReady('pc-wasm')` で読み込みを待機できます(例外は `Basis` で、トランスコーダーの読み込みが始まった時点でready状態になります)。とはいえ、これが必要になることはほとんどありません。`<pc-app>` は、自身の子要素であるすべての `<pc-wasm>` を待ってからグラフィックスデバイスを作成するため、準備完了したアプリとは、モジュールの読み込みが完了したアプリです。Ammoを待つ方法は、アプリを待つことです。
[`<pc-wasm>`](./tags/pc-wasm.md) は、上記の要素と同じく非同期に初期化されます。モジュールの読み込みが完了するか失敗するとready状態になるため、`whenReady('pc-wasm')` で読み込みを待機できます(例外は `Basis` で、トランスコーダーの読み込みが始まった時点でready状態になります)。ready状態は成功を意味しません。失敗したモジュールは [`error` イベント](./tags/pc-wasm.md#events)も発生させます。とはいえ、これが必要になることはほとんどありません。`<pc-app>` は、自身の子要素であるすべての `<pc-wasm>` の読み込みが決着するのを待ってからグラフィックスデバイスを作成するため、アプリが準備完了した時点で、各モジュールは読み込みを完了しているか、失敗を報告しています。Ammoを待つ方法は、アプリを待つことです。

```javascript
const { app } = await whenReady('pc-app'); // この時点ですべての <pc-wasm> は読み込み済みです
const { app } = await whenReady('pc-app'); // この時点ですべての <pc-wasm> の読み込みは完了または失敗しています
```

1つだけ `<pc-wasm>` に特有の注意点があります。そのready状態は固定(スティッキー)です。WebAssemblyモジュールは決してアンロードされないエンジングローバルな状態を構成するため、要素を削除して再挿入してもready状態はリセットされず、モジュールが再読み込みされることもありません。[準備完了](./tags/pc-wasm.md#readiness)を参照してください。
Expand Down
Loading
Loading