create-playcanvas 0.5.1 → 0.6.1

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.
Files changed (113) hide show
  1. package/README.md +20 -27
  2. package/dist/index.mjs +44 -42
  3. package/package.json +1 -1
  4. package/skills/calibrate-model/references/direct-engine.md +7 -4
  5. package/skills/calibrate-model/references/react.md +8 -3
  6. package/skills/calibrate-model/references/web-components.md +7 -4
  7. package/skills/configure-animation/references/web-components.md +18 -9
  8. package/skills/inspect-glb/SKILL.md +27 -18
  9. package/skills/inspect-glb/scripts/inspect.mjs +179 -50
  10. package/templates/_features/physics/assets/public/ammo/LICENSE +21 -0
  11. package/templates/_features/physics/assets/public/ammo/SOURCE.md +16 -0
  12. package/templates/_features/physics/assets/public/ammo/ammo.js +973 -0
  13. package/templates/_features/physics/assets/public/ammo/ammo.wasm.js +937 -0
  14. package/templates/_features/physics/assets/public/ammo/ammo.wasm.wasm +0 -0
  15. package/templates/_features/physics/react/package.json +5 -0
  16. package/templates/_features/physics/react/src/sync-ammo.d.ts +4 -0
  17. package/templates/_shared/ar-placement/README.md +7 -0
  18. package/templates/_shared/ar-placement/src/ar-placement.ts +123 -0
  19. package/templates/_shared/first-person-controller/README.md +7 -0
  20. package/templates/_shared/first-person-controller/src/controller.ts +18 -0
  21. package/templates/_shared/first-person-controller/src/scripts.d.ts +5 -0
  22. package/templates/_shared/interactive-sphere/README.md +7 -0
  23. package/templates/_shared/model-viewer/README.md +7 -0
  24. package/templates/_shared/physics-playground/README.md +7 -0
  25. package/templates/_shared/product-configurator/ASSET_LICENSES.md +3 -0
  26. package/templates/_shared/product-configurator/README.md +7 -0
  27. package/templates/_shared/product-configurator/src/product.css +14 -0
  28. package/templates/_shared/scene-editor/README.md +7 -0
  29. package/templates/_shared/scene-editor/src/scene-editor.ts +57 -0
  30. package/templates/_shared/spinning-cube/README.md +7 -0
  31. package/templates/_shared/splat-viewer/README.md +7 -0
  32. package/templates/_shared/sprite-game/README.md +7 -0
  33. package/templates/_shared/sprite-game/src/sprite-game.ts +197 -0
  34. package/templates/_shared/third-person-controller/README.md +7 -0
  35. package/templates/_shared/third-person-controller/src/controller.ts +53 -0
  36. package/templates/_shared/third-person-controller/src/scripts.d.ts +5 -0
  37. package/templates/_shared/vr-starter/README.md +7 -0
  38. package/templates/_shared/vr-starter/src/vr.ts +40 -0
  39. package/templates/_shared/vr-starter/src/xr.d.ts +11 -0
  40. package/templates/engine/ar-placement/src/main.ts +77 -0
  41. package/templates/engine/base/.prettierignore +1 -0
  42. package/templates/engine/base/README.md +1 -1
  43. package/templates/engine/base/_npmrc +1 -0
  44. package/templates/engine/base/eslint.config.mjs +1 -1
  45. package/templates/engine/base/index.html +13 -0
  46. package/templates/engine/base/src/starter.css +104 -0
  47. package/templates/engine/first-person-controller/src/main.ts +139 -0
  48. package/templates/engine/interactive-sphere/src/App.ts +9 -7
  49. package/templates/engine/interactive-sphere/src/main.ts +2 -29
  50. package/templates/engine/interactive-sphere/src/style.css +18 -97
  51. package/templates/engine/model-viewer/src/main.ts +3 -2
  52. package/templates/engine/physics-playground/src/main.ts +132 -0
  53. package/templates/engine/product-configurator/src/main.ts +156 -0
  54. package/templates/engine/scene-editor/src/main.ts +90 -0
  55. package/templates/engine/splat-viewer/src/main.ts +4 -3
  56. package/templates/engine/sprite-game/src/main.ts +72 -0
  57. package/templates/engine/third-person-controller/src/main.ts +216 -0
  58. package/templates/engine/vr-starter/src/main.ts +101 -0
  59. package/templates/index.ts +66 -5
  60. package/templates/react/ar-placement/src/App.tsx +58 -0
  61. package/templates/react/base/.prettierignore +1 -0
  62. package/templates/react/base/README.md +1 -1
  63. package/templates/react/base/_npmrc +1 -0
  64. package/templates/react/base/eslint.config.mjs +1 -1
  65. package/templates/react/base/index.html +13 -0
  66. package/templates/react/base/src/main.tsx +10 -0
  67. package/templates/react/base/src/starter.css +104 -0
  68. package/templates/react/first-person-controller/src/App.tsx +115 -0
  69. package/templates/react/interactive-sphere/src/App.css +18 -68
  70. package/templates/react/interactive-sphere/src/App.tsx +1 -22
  71. package/templates/react/interactive-sphere/src/Scene.tsx +7 -6
  72. package/templates/react/interactive-sphere/src/index.css +1 -48
  73. package/templates/react/model-viewer/src/App.tsx +2 -2
  74. package/templates/react/physics-playground/src/App.tsx +85 -0
  75. package/templates/react/product-configurator/src/App.tsx +157 -0
  76. package/templates/react/scene-editor/src/App.tsx +84 -0
  77. package/templates/react/splat-viewer/src/App.tsx +3 -3
  78. package/templates/react/sprite-game/src/App.tsx +38 -0
  79. package/templates/react/third-person-controller/src/App.tsx +193 -0
  80. package/templates/react/vr-starter/src/App.tsx +99 -0
  81. package/templates/web-components/ar-placement/index.html +44 -0
  82. package/templates/web-components/ar-placement/src/main.ts +13 -0
  83. package/templates/web-components/base/.prettierignore +1 -0
  84. package/templates/web-components/base/README.md +1 -1
  85. package/templates/web-components/base/_npmrc +1 -0
  86. package/templates/web-components/base/eslint.config.mjs +1 -1
  87. package/templates/web-components/base/package.json +1 -1
  88. package/templates/web-components/base/src/starter.css +104 -0
  89. package/templates/web-components/first-person-controller/index.html +168 -0
  90. package/templates/web-components/first-person-controller/src/main.ts +15 -0
  91. package/templates/web-components/interactive-sphere/index.html +5 -22
  92. package/templates/web-components/interactive-sphere/src/main.ts +5 -4
  93. package/templates/web-components/interactive-sphere/src/style.css +18 -76
  94. package/templates/web-components/model-viewer/index.html +1 -1
  95. package/templates/web-components/model-viewer/src/main.ts +2 -1
  96. package/templates/web-components/physics-playground/index.html +51 -0
  97. package/templates/web-components/physics-playground/src/main.ts +32 -0
  98. package/templates/web-components/product-configurator/index.html +51 -0
  99. package/templates/web-components/product-configurator/src/main.ts +93 -0
  100. package/templates/web-components/scene-editor/index.html +51 -0
  101. package/templates/web-components/scene-editor/src/main.ts +26 -0
  102. package/templates/web-components/spinning-cube/src/main.ts +1 -0
  103. package/templates/web-components/splat-viewer/index.html +2 -2
  104. package/templates/web-components/splat-viewer/src/main.ts +2 -1
  105. package/templates/web-components/sprite-game/index.html +34 -0
  106. package/templates/web-components/sprite-game/src/main.ts +9 -0
  107. package/templates/web-components/third-person-controller/index.html +183 -0
  108. package/templates/web-components/third-person-controller/src/main.ts +16 -0
  109. package/templates/web-components/vr-starter/index.html +80 -0
  110. package/templates/web-components/vr-starter/src/main.ts +12 -0
  111. package/templates/engine/interactive-sphere/src/assets/typescript.svg +0 -1
  112. package/templates/react/interactive-sphere/src/assets/react.svg +0 -1
  113. package/templates/web-components/interactive-sphere/src/assets/typescript.svg +0 -1
@@ -15,7 +15,7 @@
15
15
  <!-- Camera. Orbit controls are attached in src/main.ts. The sky is HDR, so it needs
16
16
  tone mapping to bring it back into displayable range - without it the whole
17
17
  image blows out to white -->
18
- <pc-entity name="camera" position="0 0 3">
18
+ <pc-entity name="camera" position="2.6 1.5 3.2" rotation="-16 39 0">
19
19
  <pc-camera tonemap="aces2"></pc-camera>
20
20
  </pc-entity>
21
21
 
@@ -3,6 +3,7 @@ import { whenReady } from '@playcanvas/web-components';
3
3
  import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs';
4
4
  import { ProceduralSky } from 'playcanvas/scripts/esm/sky/procedural-sky.mjs';
5
5
 
6
+ import './starter.css';
6
7
  import './style.css';
7
8
 
8
9
  // The camera is awaited as <pc-camera> rather than the <pc-entity> holding it - an entity becomes
@@ -16,7 +17,7 @@ const [cameraComponent, sky] = await Promise.all([
16
17
  // with <pc-script name="...">, which only resolves scripts fetched at runtime by <pc-asset>
17
18
  const camera = cameraComponent.closestEntity;
18
19
  camera?.entity?.addComponent('script');
19
- camera?.entity?.script?.create(CameraControls);
20
+ camera?.entity?.script?.create(CameraControls, { properties: { sceneSize: 2.5 } });
20
21
 
21
22
  sky.entity?.addComponent('script');
22
23
 
@@ -0,0 +1,51 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/png" href="/src/assets/playcanvas.png" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Physics Playground</title>
8
+ </head>
9
+ <body>
10
+ <pc-app>
11
+ <pc-module
12
+ name="Ammo"
13
+ glue="/ammo/ammo.wasm.js"
14
+ wasm="/ammo/ammo.wasm.wasm"
15
+ fallback="/ammo/ammo.js"
16
+ ></pc-module>
17
+ <pc-material id="floor-material" diffuse="#2e333d" gloss="0.2"></pc-material>
18
+ <pc-material id="cyan-material" diffuse="#29ade6" gloss="0.45"></pc-material>
19
+ <pc-material id="coral-material" diffuse="#f25738" gloss="0.45"></pc-material>
20
+ <pc-material id="yellow-material" diffuse="#f9ad2e" gloss="0.45"></pc-material>
21
+ <pc-scene>
22
+ <pc-entity name="camera" position="10 8 10" rotation="-23 45 0"
23
+ ><pc-camera clear-color="#0d121c"></pc-camera
24
+ ></pc-entity>
25
+ <pc-entity name="light" rotation="45 35 0"
26
+ ><pc-light
27
+ type="directional"
28
+ intensity="2.5"
29
+ cast-shadows
30
+ shadow-bias="0.2"
31
+ normal-offset-bias="0.05"
32
+ ></pc-light
33
+ ></pc-entity>
34
+ <pc-entity name="floor" position="0 -0.1 0" scale="10 0.2 10"
35
+ ><pc-render type="box" material="floor-material"></pc-render
36
+ ><pc-collision type="box" half-extents="5 0.1 5"></pc-collision
37
+ ><pc-rigidbody type="static"></pc-rigidbody
38
+ ></pc-entity>
39
+ <pc-entity id="bodies"></pc-entity>
40
+ </pc-scene>
41
+ </pc-app>
42
+ <div class="hud">
43
+ <section class="panel">
44
+ <h1>Physics Playground</h1>
45
+ <p>Rigid bodies, collisions and runtime spawning.</p>
46
+ <div class="controls"><button id="spawn">Spawn object</button><button id="reset">Reset</button></div>
47
+ </section>
48
+ </div>
49
+ <script type="module" src="/src/main.ts"></script>
50
+ </body>
51
+ </html>
@@ -0,0 +1,32 @@
1
+ import { whenReady } from '@playcanvas/web-components';
2
+ import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs';
3
+
4
+ import './starter.css';
5
+
6
+ const MATERIALS = ['cyan-material', 'coral-material', 'yellow-material'];
7
+ const TYPES = ['box', 'sphere', 'capsule', 'cylinder'];
8
+ const SCALES = ['0.9 0.9 0.9', '0.9 0.9 0.9', '0.7 1.1 0.7', '0.8 1.1 0.8'];
9
+
10
+ const camera = (await whenReady('pc-camera')).closestEntity!.entity!;
11
+ camera.addComponent('script');
12
+ camera.script!.create(CameraControls, { properties: { sceneSize: 10 } });
13
+
14
+ const bodies = document.getElementById('bodies')!;
15
+ let count = 0;
16
+ const spawn = () => {
17
+ const i = count++;
18
+ const type = TYPES[i % TYPES.length];
19
+ bodies.insertAdjacentHTML(
20
+ 'beforeend',
21
+ `<pc-entity data-body position="${((i % 4) - 1.5) * 1.1} ${0.7 + Math.floor(i / 4) * 1.1} ${(Math.floor(i / 4) - 1) * 1.4}" rotation="${i * 13} ${i * 29} 0" scale="${SCALES[i % SCALES.length]}"><pc-render type="${type}" material="${MATERIALS[i % MATERIALS.length]}"></pc-render><pc-collision type="${type}"></pc-collision><pc-rigidbody type="dynamic" mass="1" restitution="0.35"></pc-rigidbody></pc-entity>`
22
+ );
23
+ };
24
+ const reset = () => {
25
+ bodies.replaceChildren();
26
+ count = 0;
27
+ for (let i = 0; i < 12; i++) spawn();
28
+ };
29
+
30
+ document.getElementById('spawn')!.onclick = spawn;
31
+ document.getElementById('reset')!.onclick = reset;
32
+ reset();
@@ -0,0 +1,51 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/png" href="/src/assets/playcanvas.png" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Product Configurator</title>
8
+ </head>
9
+ <body>
10
+ <pc-app>
11
+ <pc-asset id="car" src="https://developer.playcanvas.com/assets/lambo.glb"></pc-asset>
12
+ <pc-scene>
13
+ <pc-entity name="sky"></pc-entity>
14
+ <pc-entity name="camera" position="5.5 3.2 6.5" rotation="-16 40 0">
15
+ <pc-camera fov="40" tonemap="aces2"></pc-camera>
16
+ </pc-entity>
17
+ <pc-entity name="light" rotation="45 -145 0">
18
+ <pc-light
19
+ type="directional"
20
+ intensity="2.5"
21
+ cast-shadows
22
+ shadow-bias="0.2"
23
+ normal-offset-bias="0.05"
24
+ ></pc-light>
25
+ </pc-entity>
26
+ <pc-entity name="studio-ground"></pc-entity>
27
+ <pc-entity name="car">
28
+ <pc-model asset="car"></pc-model>
29
+ </pc-entity>
30
+ </pc-scene>
31
+ </pc-app>
32
+ <div class="hud">
33
+ <section class="panel">
34
+ <h1>Product Configurator</h1>
35
+ <p>Choose a paint finish, then drag to orbit.</p>
36
+ <div class="controls variants" id="paints">
37
+ <button aria-pressed="true" data-color="#d6293e" data-shade="#9b1731">
38
+ <span class="finish" style="--color: #d6293e"></span>Crimson
39
+ </button>
40
+ <button data-color="#d8e4e9" data-shade="#8fa8b5">
41
+ <span class="finish" style="--color: #d8e4e9"></span>Arctic
42
+ </button>
43
+ <button data-color="#9acb34" data-shade="#3c742d">
44
+ <span class="finish" style="--color: #9acb34"></span>Volt
45
+ </button>
46
+ </div>
47
+ </section>
48
+ </div>
49
+ <script type="module" src="/src/main.ts"></script>
50
+ </body>
51
+ </html>
@@ -0,0 +1,93 @@
1
+ import type { AssetElement, EntityElement, ModelElement } from '@playcanvas/web-components';
2
+ import { whenReady } from '@playcanvas/web-components';
3
+ import type { RenderComponent } from 'playcanvas';
4
+ import { Color, CylinderGeometry, Mesh, MeshInstance, StandardMaterial, Vec2, Vec3 } from 'playcanvas';
5
+ import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs';
6
+ import { ProceduralSky } from 'playcanvas/scripts/esm/sky/procedural-sky.mjs';
7
+
8
+ import './product.css';
9
+ import './starter.css';
10
+
11
+ const CAMERA_FOCUS = new Vec3(0, 0.8, 0);
12
+ const CAMERA_PITCH = new Vec2(-85, -4);
13
+
14
+ const [cameraComponent, , model, sky, groundElement] = await Promise.all([
15
+ whenReady('pc-camera'),
16
+ whenReady<AssetElement>('#car'),
17
+ whenReady<ModelElement>('pc-model'),
18
+ whenReady<EntityElement>('pc-entity[name="sky"]'),
19
+ whenReady<EntityElement>('pc-entity[name="studio-ground"]')
20
+ ]);
21
+
22
+ const camera = cameraComponent.closestEntity!.entity!;
23
+ const app = camera.camera!.system.app;
24
+ camera.camera!.requestSceneColorMap(true);
25
+ camera.addComponent('script');
26
+ camera.script!.create(CameraControls, {
27
+ properties: {
28
+ sceneSize: 6.2,
29
+ focusPoint: CAMERA_FOCUS,
30
+ pitchRange: CAMERA_PITCH,
31
+ enableFly: false,
32
+ enablePan: false
33
+ }
34
+ });
35
+
36
+ sky.entity!.addComponent('script');
37
+ sky.entity!.script!.create(ProceduralSky, { properties: { luminance: 0.18 } });
38
+
39
+ const podium = new StandardMaterial();
40
+ podium.diffuse = new Color(0.3, 0.32, 0.34);
41
+ podium.metalness = 0.15;
42
+ podium.gloss = 0.65;
43
+ podium.update();
44
+
45
+ const ground = groundElement.entity!;
46
+ ground.setPosition(0, -0.08, 0);
47
+ ground.addComponent('render', {
48
+ meshInstances: [
49
+ new MeshInstance(
50
+ Mesh.fromGeometry(
51
+ app.graphicsDevice,
52
+ new CylinderGeometry({ radius: 4, height: 0.16, heightSegments: 1, capSegments: 128 })
53
+ ),
54
+ podium
55
+ )
56
+ ],
57
+ castShadows: false,
58
+ receiveShadows: true
59
+ });
60
+
61
+ const entity = model.entity!;
62
+ entity.setLocalEulerAngles(-90, -25, 0);
63
+ entity.root.syncHierarchy();
64
+ const meshes = (entity.findComponents('render') as RenderComponent[]).flatMap((render) => render.meshInstances);
65
+ const bounds = meshes[0].aabb.clone();
66
+ meshes.slice(1).forEach((mesh) => bounds.add(mesh.aabb));
67
+ const scale = 5 / Math.max(bounds.halfExtents.x * 2, bounds.halfExtents.z * 2);
68
+ entity.setLocalScale(scale, scale, scale);
69
+ entity.root.syncHierarchy();
70
+ bounds.copy(meshes[0].aabb);
71
+ meshes.slice(1).forEach((mesh) => bounds.add(mesh.aabb));
72
+ entity.setPosition(-bounds.center.x, 0.03 - bounds.getMin().y, -bounds.center.z);
73
+
74
+ const body = meshes.filter((mesh) => mesh.material.name === 'material');
75
+ const panels = meshes.filter((mesh) => mesh.material.name === 'material_1');
76
+ const paint = body[0].material.clone() as StandardMaterial;
77
+ const shade = panels[0].material.clone() as StandardMaterial;
78
+ body.forEach((mesh) => (mesh.material = paint));
79
+ panels.forEach((mesh) => (mesh.material = shade));
80
+ paint.diffuse.fromString('#d6293e');
81
+ shade.diffuse.fromString('#9b1731');
82
+ paint.update();
83
+ shade.update();
84
+
85
+ document.querySelectorAll<HTMLButtonElement>('#paints button').forEach((button, i, buttons) => {
86
+ button.onclick = () => {
87
+ paint.diffuse.fromString(button.dataset.color!);
88
+ shade.diffuse.fromString(button.dataset.shade!);
89
+ paint.update();
90
+ shade.update();
91
+ buttons.forEach((item, j) => (item.ariaPressed = String(i === j)));
92
+ };
93
+ });
@@ -0,0 +1,51 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/png" href="/src/assets/playcanvas.png" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Scene Editor</title>
8
+ </head>
9
+ <body>
10
+ <pc-app>
11
+ <pc-material id="coral" diffuse="#ff5145"></pc-material>
12
+ <pc-material id="cyan" diffuse="#24addf"></pc-material>
13
+ <pc-scene>
14
+ <pc-entity name="camera" position="4 3.2 5" rotation="-18 39 0"
15
+ ><pc-camera clear-color="#0a0f17"></pc-camera
16
+ ></pc-entity>
17
+ <pc-entity name="light" rotation="45 30 0"
18
+ ><pc-light
19
+ type="directional"
20
+ intensity="2.5"
21
+ cast-shadows
22
+ shadow-bias="0.2"
23
+ normal-offset-bias="0.05"
24
+ ></pc-light
25
+ ></pc-entity>
26
+ <pc-entity name="grid" scale="12 12 12"></pc-entity>
27
+ <pc-entity name="cube" position="-1.2 0.5 0"
28
+ ><pc-render type="box" material="coral"></pc-render
29
+ ></pc-entity>
30
+ <pc-entity name="sphere" position="1.2 0.5 0"
31
+ ><pc-render type="sphere" material="cyan"></pc-render
32
+ ></pc-entity>
33
+ <pc-entity name="editor"></pc-entity>
34
+ </pc-scene>
35
+ </pc-app>
36
+ <div class="hud">
37
+ <section class="panel">
38
+ <h1>Scene Editor</h1>
39
+ <p>Select an object, then translate, rotate or scale it.</p>
40
+ <div class="controls">
41
+ <button data-target="0" aria-pressed="true">Cube</button><button data-target="1">Sphere</button>
42
+ </div>
43
+ <div class="controls">
44
+ <button data-mode="translate" aria-pressed="true">Move</button
45
+ ><button data-mode="rotate">Rotate</button><button data-mode="scale">Scale</button>
46
+ </div>
47
+ </section>
48
+ </div>
49
+ <script type="module" src="/src/main.ts"></script>
50
+ </body>
51
+ </html>
@@ -0,0 +1,26 @@
1
+ import type { EntityElement } from '@playcanvas/web-components';
2
+ import { whenReady } from '@playcanvas/web-components';
3
+ import { Grid } from 'playcanvas/scripts/esm/grid.mjs';
4
+
5
+ import { SceneEditor } from './scene-editor';
6
+ import './starter.css';
7
+
8
+ const [appElement, camera, grid, cube, sphere, editor] = await Promise.all([
9
+ whenReady('pc-app'),
10
+ whenReady<EntityElement>('pc-entity[name="camera"]'),
11
+ whenReady<EntityElement>('pc-entity[name="grid"]'),
12
+ whenReady<EntityElement>('pc-entity[name="cube"]'),
13
+ whenReady<EntityElement>('pc-entity[name="sphere"]'),
14
+ whenReady<EntityElement>('pc-entity[name="editor"]')
15
+ ]);
16
+
17
+ grid.entity!.addComponent('script');
18
+ grid.entity!.script!.create(Grid);
19
+ editor.entity!.addComponent('script');
20
+ editor.entity!.script!.create(SceneEditor, {
21
+ properties: {
22
+ camera: camera.entity,
23
+ targets: [cube.entity, sphere.entity],
24
+ layer: appElement.app!.scene.layers.getLayerByName('World')
25
+ }
26
+ });
@@ -2,6 +2,7 @@ import type { EntityElement } from '@playcanvas/web-components';
2
2
  import { whenReady } from '@playcanvas/web-components';
3
3
  import { Script } from 'playcanvas';
4
4
 
5
+ import './starter.css';
5
6
  import './style.css';
6
7
 
7
8
  class Rotate extends Script {
@@ -15,8 +15,8 @@
15
15
 
16
16
  <pc-scene>
17
17
  <!-- Camera. Orbit controls are attached in src/main.ts -->
18
- <pc-entity name="camera" position="0 0 2.5">
19
- <pc-camera></pc-camera>
18
+ <pc-entity name="camera" position="0 0 2.8">
19
+ <pc-camera clear-color="#8f949e"></pc-camera>
20
20
  </pc-entity>
21
21
 
22
22
  <!-- Splats are captured in their own space, so this one needs offsetting and flipping upright -->
@@ -1,6 +1,7 @@
1
1
  import { whenReady } from '@playcanvas/web-components';
2
2
  import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs';
3
3
 
4
+ import './starter.css';
4
5
  import './style.css';
5
6
 
6
7
  // The camera is awaited as <pc-camera> rather than the <pc-entity> holding it - an entity becomes
@@ -11,4 +12,4 @@ const cameraComponent = await whenReady('pc-camera');
11
12
  // with <pc-script name="...">, which only resolves scripts fetched at runtime by <pc-asset>
12
13
  const camera = cameraComponent.closestEntity;
13
14
  camera?.entity?.addComponent('script');
14
- camera?.entity?.script?.create(CameraControls);
15
+ camera?.entity?.script?.create(CameraControls, { properties: { sceneSize: 2 } });
@@ -0,0 +1,34 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/png" href="/src/assets/playcanvas.png" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Sprite Game</title>
8
+ </head>
9
+ <body>
10
+ <pc-app>
11
+ <pc-material id="dirt-material" emissive="#734729"></pc-material>
12
+ <pc-material id="grass-material" emissive="#479e57"></pc-material>
13
+ <pc-scene>
14
+ <pc-entity name="camera" position="0 0 10"
15
+ ><pc-camera projection="orthographic" ortho-height="4.4" clear-color="#5cb9e6"></pc-camera
16
+ ></pc-entity>
17
+ <pc-entity name="dirt" position="0 -3.39 0" scale="20 2.6 1"
18
+ ><pc-render type="box" material="dirt-material"></pc-render
19
+ ></pc-entity>
20
+ <pc-entity name="grass" position="0 -2 0" scale="20 0.18 1"
21
+ ><pc-render type="box" material="grass-material"></pc-render
22
+ ></pc-entity>
23
+ <pc-entity name="game" position="0 -2.15 0"></pc-entity>
24
+ </pc-scene>
25
+ </pc-app>
26
+ <div class="hud">
27
+ <section class="panel">
28
+ <h1>Sprite Game</h1>
29
+ <p>Use A/D or the arrow keys to move and Space to jump.</p>
30
+ </section>
31
+ </div>
32
+ <script type="module" src="/src/main.ts"></script>
33
+ </body>
34
+ </html>
@@ -0,0 +1,9 @@
1
+ import type { EntityElement } from '@playcanvas/web-components';
2
+ import { whenReady } from '@playcanvas/web-components';
3
+
4
+ import { SpriteGame } from './sprite-game';
5
+ import './starter.css';
6
+
7
+ const game = await whenReady<EntityElement>('pc-entity[name="game"]');
8
+ game.entity!.addComponent('script');
9
+ game.entity!.script!.create(SpriteGame);
@@ -0,0 +1,183 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/png" href="/src/assets/playcanvas.png" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Third-Person Controller</title>
8
+ </head>
9
+ <body>
10
+ <pc-app>
11
+ <pc-material id="ground-material" diffuse="#33662e"></pc-material>
12
+ <pc-material id="block-material" diffuse="#57594d"></pc-material>
13
+ <pc-material id="wood-material" diffuse="#572e14"></pc-material>
14
+ <pc-material id="leaves-material" diffuse="#144d1f"></pc-material>
15
+ <pc-material id="tips-material" diffuse="#1f6629"></pc-material>
16
+ <pc-material id="shirt-material" diffuse="#268bd2"></pc-material>
17
+ <pc-material id="skin-material" diffuse="#c78759"></pc-material>
18
+ <pc-material id="pants-material" diffuse="#2e4a85"></pc-material>
19
+ <pc-module
20
+ name="Ammo"
21
+ glue="/ammo/ammo.wasm.js"
22
+ wasm="/ammo/ammo.wasm.wasm"
23
+ fallback="/ammo/ammo.js"
24
+ ></pc-module>
25
+ <pc-scene>
26
+ <pc-entity name="camera" position="0 3 6"><pc-camera clear-color="#7ab8e6"></pc-camera></pc-entity>
27
+ <pc-entity name="light" rotation="45 30 0"
28
+ ><pc-light
29
+ type="directional"
30
+ intensity="2.5"
31
+ cast-shadows
32
+ shadow-bias="0.2"
33
+ normal-offset-bias="0.05"
34
+ ></pc-light
35
+ ></pc-entity>
36
+ <pc-entity name="ground" position="0 -0.1 0" scale="20 0.2 20"
37
+ ><pc-render type="box" material="ground-material"></pc-render
38
+ ><pc-collision type="box" half-extents="10 0.1 10"></pc-collision
39
+ ><pc-rigidbody type="static"></pc-rigidbody
40
+ ></pc-entity>
41
+ <pc-entity name="block-0" position="-4.5 0.5 -3.5" scale="2.4 1 2.4"
42
+ ><pc-render type="box" material="block-material"></pc-render
43
+ ><pc-collision type="box" half-extents="1.2 0.5 1.2"></pc-collision
44
+ ><pc-rigidbody type="static"></pc-rigidbody
45
+ ></pc-entity>
46
+ <pc-entity name="block-1" position="4.2 0.5 -2.8" rotation="0 25 0" scale="2.4 1 2.4"
47
+ ><pc-render type="box" material="block-material"></pc-render
48
+ ><pc-collision type="box" half-extents="1.2 0.5 1.2"></pc-collision
49
+ ><pc-rigidbody type="static"></pc-rigidbody
50
+ ></pc-entity>
51
+ <pc-entity name="block-2" position="-3.7 0.5 3.2" rotation="0 50 0" scale="2.4 1 2.4"
52
+ ><pc-render type="box" material="block-material"></pc-render
53
+ ><pc-collision type="box" half-extents="1.2 0.5 1.2"></pc-collision
54
+ ><pc-rigidbody type="static"></pc-rigidbody
55
+ ></pc-entity>
56
+ <pc-entity name="block-3" position="3.8 0.5 3.6" rotation="0 75 0" scale="2.4 1 2.4"
57
+ ><pc-render type="box" material="block-material"></pc-render
58
+ ><pc-collision type="box" half-extents="1.2 0.5 1.2"></pc-collision
59
+ ><pc-rigidbody type="static"></pc-rigidbody
60
+ ></pc-entity>
61
+ <pc-entity name="tree-0-trunk" position="-7 0.99 -6" scale="0.418 1.98 0.418"
62
+ ><pc-render type="box" material="wood-material"></pc-render
63
+ ><pc-collision type="box" half-extents="0.209 0.99 0.209"></pc-collision
64
+ ><pc-rigidbody type="static"></pc-rigidbody
65
+ ></pc-entity>
66
+ <pc-entity name="tree-0-crown-0" position="-7 2.09 -6" scale="2.31 1.98 2.31"
67
+ ><pc-render type="cone" material="leaves-material"></pc-render
68
+ ></pc-entity>
69
+ <pc-entity name="tree-0-crown-1" position="-7 2.915 -6" scale="1.76 1.705 1.76"
70
+ ><pc-render type="cone" material="tips-material"></pc-render
71
+ ></pc-entity>
72
+ <pc-entity name="tree-0-crown-2" position="-7 3.63 -6" scale="1.21 1.54 1.21"
73
+ ><pc-render type="cone" material="leaves-material"></pc-render
74
+ ></pc-entity>
75
+ <pc-entity name="tree-1-trunk" position="6.5 1.125 -6.5" scale="0.475 2.25 0.475"
76
+ ><pc-render type="box" material="wood-material"></pc-render
77
+ ><pc-collision type="box" half-extents="0.2375 1.125 0.2375"></pc-collision
78
+ ><pc-rigidbody type="static"></pc-rigidbody
79
+ ></pc-entity>
80
+ <pc-entity name="tree-1-crown-0" position="6.5 2.375 -6.5" scale="2.625 2.25 2.625"
81
+ ><pc-render type="cone" material="leaves-material"></pc-render
82
+ ></pc-entity>
83
+ <pc-entity name="tree-1-crown-1" position="6.5 3.3125 -6.5" scale="2 1.9375 2"
84
+ ><pc-render type="cone" material="tips-material"></pc-render
85
+ ></pc-entity>
86
+ <pc-entity name="tree-1-crown-2" position="6.5 4.125 -6.5" scale="1.375 1.75 1.375"
87
+ ><pc-render type="cone" material="leaves-material"></pc-render
88
+ ></pc-entity>
89
+ <pc-entity name="tree-2-trunk" position="-7.5 0.81 5" scale="0.342 1.62 0.342"
90
+ ><pc-render type="box" material="wood-material"></pc-render
91
+ ><pc-collision type="box" half-extents="0.171 0.81 0.171"></pc-collision
92
+ ><pc-rigidbody type="static"></pc-rigidbody
93
+ ></pc-entity>
94
+ <pc-entity name="tree-2-crown-0" position="-7.5 1.71 5" scale="1.89 1.62 1.89"
95
+ ><pc-render type="cone" material="leaves-material"></pc-render
96
+ ></pc-entity>
97
+ <pc-entity name="tree-2-crown-1" position="-7.5 2.385 5" scale="1.44 1.395 1.44"
98
+ ><pc-render type="cone" material="tips-material"></pc-render
99
+ ></pc-entity>
100
+ <pc-entity name="tree-2-crown-2" position="-7.5 2.97 5" scale="0.99 1.26 0.99"
101
+ ><pc-render type="cone" material="leaves-material"></pc-render
102
+ ></pc-entity>
103
+ <pc-entity name="tree-3-trunk" position="7 1.035 5.5" scale="0.437 2.07 0.437"
104
+ ><pc-render type="box" material="wood-material"></pc-render
105
+ ><pc-collision type="box" half-extents="0.2185 1.035 0.2185"></pc-collision
106
+ ><pc-rigidbody type="static"></pc-rigidbody
107
+ ></pc-entity>
108
+ <pc-entity name="tree-3-crown-0" position="7 2.185 5.5" scale="2.415 2.07 2.415"
109
+ ><pc-render type="cone" material="leaves-material"></pc-render
110
+ ></pc-entity>
111
+ <pc-entity name="tree-3-crown-1" position="7 3.0475 5.5" scale="1.84 1.7825 1.84"
112
+ ><pc-render type="cone" material="tips-material"></pc-render
113
+ ></pc-entity>
114
+ <pc-entity name="tree-3-crown-2" position="7 3.795 5.5" scale="1.265 1.61 1.265"
115
+ ><pc-render type="cone" material="leaves-material"></pc-render
116
+ ></pc-entity>
117
+ <pc-entity name="tree-4-trunk" position="-2.2 0.765 -8" scale="0.323 1.53 0.323"
118
+ ><pc-render type="box" material="wood-material"></pc-render
119
+ ><pc-collision type="box" half-extents="0.1615 0.765 0.1615"></pc-collision
120
+ ><pc-rigidbody type="static"></pc-rigidbody
121
+ ></pc-entity>
122
+ <pc-entity name="tree-4-crown-0" position="-2.2 1.615 -8" scale="1.785 1.53 1.785"
123
+ ><pc-render type="cone" material="leaves-material"></pc-render
124
+ ></pc-entity>
125
+ <pc-entity name="tree-4-crown-1" position="-2.2 2.2525 -8" scale="1.36 1.3175 1.36"
126
+ ><pc-render type="cone" material="tips-material"></pc-render
127
+ ></pc-entity>
128
+ <pc-entity name="tree-4-crown-2" position="-2.2 2.805 -8" scale="0.935 1.19 0.935"
129
+ ><pc-render type="cone" material="leaves-material"></pc-render
130
+ ></pc-entity>
131
+ <pc-entity name="fallen-log" position="0 0.35 6" scale="3.8 0.7 0.7"
132
+ ><pc-render type="box" material="wood-material"></pc-render
133
+ ><pc-collision type="box" half-extents="1.9 0.35 0.35"></pc-collision
134
+ ><pc-rigidbody type="static"></pc-rigidbody
135
+ ></pc-entity>
136
+ <pc-entity name="stump" position="-1.8 0.4 -2.2" scale="0.9 0.8 0.9"
137
+ ><pc-render type="box" material="wood-material"></pc-render
138
+ ><pc-collision type="box" half-extents="0.45 0.4 0.45"></pc-collision
139
+ ><pc-rigidbody type="static"></pc-rigidbody
140
+ ></pc-entity>
141
+ <pc-entity name="player" position="0 1.1 0">
142
+ <pc-collision type="capsule" radius="0.5" height="2.4" linear-offset="0 0.1 0"></pc-collision>
143
+ <pc-rigidbody type="dynamic" mass="70" angular-factor="0 0 0"></pc-rigidbody>
144
+ <pc-entity name="character" position="0 0.2 0">
145
+ <pc-entity name="body" scale="0.56 0.88 0.38"
146
+ ><pc-render type="box" material="shirt-material"></pc-render
147
+ ></pc-entity>
148
+ <pc-entity name="head" position="0 0.76 0" scale="0.52 0.6 0.52"
149
+ ><pc-render type="box" material="skin-material"></pc-render
150
+ ></pc-entity>
151
+ <pc-entity name="left-arm" position="-0.38 0.44 0">
152
+ <pc-entity position="0 -0.44 0" scale="0.18 0.88 0.32"
153
+ ><pc-render type="box" material="shirt-material"></pc-render
154
+ ></pc-entity>
155
+ </pc-entity>
156
+ <pc-entity name="right-arm" position="0.38 0.44 0">
157
+ <pc-entity position="0 -0.44 0" scale="0.18 0.88 0.32"
158
+ ><pc-render type="box" material="shirt-material"></pc-render
159
+ ></pc-entity>
160
+ </pc-entity>
161
+ <pc-entity name="left-leg" position="-0.15 -0.44 0">
162
+ <pc-entity position="0 -0.43 0" scale="0.24 0.86 0.34"
163
+ ><pc-render type="box" material="pants-material"></pc-render
164
+ ></pc-entity>
165
+ </pc-entity>
166
+ <pc-entity name="right-leg" position="0.15 -0.44 0">
167
+ <pc-entity position="0 -0.43 0" scale="0.24 0.86 0.34"
168
+ ><pc-render type="box" material="pants-material"></pc-render
169
+ ></pc-entity>
170
+ </pc-entity>
171
+ </pc-entity>
172
+ </pc-entity>
173
+ </pc-scene>
174
+ </pc-app>
175
+ <div class="hud">
176
+ <section class="panel">
177
+ <h1>Third-Person Controller</h1>
178
+ <p>Click the scene, then use WASD to move, mouse to orbit and Space to jump.</p>
179
+ </section>
180
+ </div>
181
+ <script type="module" src="/src/main.ts"></script>
182
+ </body>
183
+ </html>
@@ -0,0 +1,16 @@
1
+ import type { EntityElement } from '@playcanvas/web-components';
2
+ import { whenReady } from '@playcanvas/web-components';
3
+
4
+ import { addThirdPersonController } from './controller';
5
+ import './starter.css';
6
+
7
+ await Promise.all([
8
+ whenReady('pc-entity[name="player"] > pc-collision'),
9
+ whenReady('pc-entity[name="player"] > pc-rigidbody')
10
+ ]);
11
+ const [player, camera, model] = await Promise.all([
12
+ whenReady<EntityElement>('pc-entity[name="player"]'),
13
+ whenReady<EntityElement>('pc-entity[name="camera"]'),
14
+ whenReady<EntityElement>('pc-entity[name="character"]')
15
+ ]);
16
+ addThirdPersonController(player.entity!, camera.entity!, model.entity!);