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.
- package/README.md +20 -27
- package/dist/index.mjs +44 -42
- package/package.json +1 -1
- package/skills/calibrate-model/references/direct-engine.md +7 -4
- package/skills/calibrate-model/references/react.md +8 -3
- package/skills/calibrate-model/references/web-components.md +7 -4
- package/skills/configure-animation/references/web-components.md +18 -9
- package/skills/inspect-glb/SKILL.md +27 -18
- package/skills/inspect-glb/scripts/inspect.mjs +179 -50
- package/templates/_features/physics/assets/public/ammo/LICENSE +21 -0
- package/templates/_features/physics/assets/public/ammo/SOURCE.md +16 -0
- package/templates/_features/physics/assets/public/ammo/ammo.js +973 -0
- package/templates/_features/physics/assets/public/ammo/ammo.wasm.js +937 -0
- package/templates/_features/physics/assets/public/ammo/ammo.wasm.wasm +0 -0
- package/templates/_features/physics/react/package.json +5 -0
- package/templates/_features/physics/react/src/sync-ammo.d.ts +4 -0
- package/templates/_shared/ar-placement/README.md +7 -0
- package/templates/_shared/ar-placement/src/ar-placement.ts +123 -0
- package/templates/_shared/first-person-controller/README.md +7 -0
- package/templates/_shared/first-person-controller/src/controller.ts +18 -0
- package/templates/_shared/first-person-controller/src/scripts.d.ts +5 -0
- package/templates/_shared/interactive-sphere/README.md +7 -0
- package/templates/_shared/model-viewer/README.md +7 -0
- package/templates/_shared/physics-playground/README.md +7 -0
- package/templates/_shared/product-configurator/ASSET_LICENSES.md +3 -0
- package/templates/_shared/product-configurator/README.md +7 -0
- package/templates/_shared/product-configurator/src/product.css +14 -0
- package/templates/_shared/scene-editor/README.md +7 -0
- package/templates/_shared/scene-editor/src/scene-editor.ts +57 -0
- package/templates/_shared/spinning-cube/README.md +7 -0
- package/templates/_shared/splat-viewer/README.md +7 -0
- package/templates/_shared/sprite-game/README.md +7 -0
- package/templates/_shared/sprite-game/src/sprite-game.ts +197 -0
- package/templates/_shared/third-person-controller/README.md +7 -0
- package/templates/_shared/third-person-controller/src/controller.ts +53 -0
- package/templates/_shared/third-person-controller/src/scripts.d.ts +5 -0
- package/templates/_shared/vr-starter/README.md +7 -0
- package/templates/_shared/vr-starter/src/vr.ts +40 -0
- package/templates/_shared/vr-starter/src/xr.d.ts +11 -0
- package/templates/engine/ar-placement/src/main.ts +77 -0
- package/templates/engine/base/.prettierignore +1 -0
- package/templates/engine/base/README.md +1 -1
- package/templates/engine/base/_npmrc +1 -0
- package/templates/engine/base/eslint.config.mjs +1 -1
- package/templates/engine/base/index.html +13 -0
- package/templates/engine/base/src/starter.css +104 -0
- package/templates/engine/first-person-controller/src/main.ts +139 -0
- package/templates/engine/interactive-sphere/src/App.ts +9 -7
- package/templates/engine/interactive-sphere/src/main.ts +2 -29
- package/templates/engine/interactive-sphere/src/style.css +18 -97
- package/templates/engine/model-viewer/src/main.ts +3 -2
- package/templates/engine/physics-playground/src/main.ts +132 -0
- package/templates/engine/product-configurator/src/main.ts +156 -0
- package/templates/engine/scene-editor/src/main.ts +90 -0
- package/templates/engine/splat-viewer/src/main.ts +4 -3
- package/templates/engine/sprite-game/src/main.ts +72 -0
- package/templates/engine/third-person-controller/src/main.ts +216 -0
- package/templates/engine/vr-starter/src/main.ts +101 -0
- package/templates/index.ts +66 -5
- package/templates/react/ar-placement/src/App.tsx +58 -0
- package/templates/react/base/.prettierignore +1 -0
- package/templates/react/base/README.md +1 -1
- package/templates/react/base/_npmrc +1 -0
- package/templates/react/base/eslint.config.mjs +1 -1
- package/templates/react/base/index.html +13 -0
- package/templates/react/base/src/main.tsx +10 -0
- package/templates/react/base/src/starter.css +104 -0
- package/templates/react/first-person-controller/src/App.tsx +115 -0
- package/templates/react/interactive-sphere/src/App.css +18 -68
- package/templates/react/interactive-sphere/src/App.tsx +1 -22
- package/templates/react/interactive-sphere/src/Scene.tsx +7 -6
- package/templates/react/interactive-sphere/src/index.css +1 -48
- package/templates/react/model-viewer/src/App.tsx +2 -2
- package/templates/react/physics-playground/src/App.tsx +85 -0
- package/templates/react/product-configurator/src/App.tsx +157 -0
- package/templates/react/scene-editor/src/App.tsx +84 -0
- package/templates/react/splat-viewer/src/App.tsx +3 -3
- package/templates/react/sprite-game/src/App.tsx +38 -0
- package/templates/react/third-person-controller/src/App.tsx +193 -0
- package/templates/react/vr-starter/src/App.tsx +99 -0
- package/templates/web-components/ar-placement/index.html +44 -0
- package/templates/web-components/ar-placement/src/main.ts +13 -0
- package/templates/web-components/base/.prettierignore +1 -0
- package/templates/web-components/base/README.md +1 -1
- package/templates/web-components/base/_npmrc +1 -0
- package/templates/web-components/base/eslint.config.mjs +1 -1
- package/templates/web-components/base/package.json +1 -1
- package/templates/web-components/base/src/starter.css +104 -0
- package/templates/web-components/first-person-controller/index.html +168 -0
- package/templates/web-components/first-person-controller/src/main.ts +15 -0
- package/templates/web-components/interactive-sphere/index.html +5 -22
- package/templates/web-components/interactive-sphere/src/main.ts +5 -4
- package/templates/web-components/interactive-sphere/src/style.css +18 -76
- package/templates/web-components/model-viewer/index.html +1 -1
- package/templates/web-components/model-viewer/src/main.ts +2 -1
- package/templates/web-components/physics-playground/index.html +51 -0
- package/templates/web-components/physics-playground/src/main.ts +32 -0
- package/templates/web-components/product-configurator/index.html +51 -0
- package/templates/web-components/product-configurator/src/main.ts +93 -0
- package/templates/web-components/scene-editor/index.html +51 -0
- package/templates/web-components/scene-editor/src/main.ts +26 -0
- package/templates/web-components/spinning-cube/src/main.ts +1 -0
- package/templates/web-components/splat-viewer/index.html +2 -2
- package/templates/web-components/splat-viewer/src/main.ts +2 -1
- package/templates/web-components/sprite-game/index.html +34 -0
- package/templates/web-components/sprite-game/src/main.ts +9 -0
- package/templates/web-components/third-person-controller/index.html +183 -0
- package/templates/web-components/third-person-controller/src/main.ts +16 -0
- package/templates/web-components/vr-starter/index.html +80 -0
- package/templates/web-components/vr-starter/src/main.ts +12 -0
- package/templates/engine/interactive-sphere/src/assets/typescript.svg +0 -1
- package/templates/react/interactive-sphere/src/assets/react.svg +0 -1
- package/templates/web-components/interactive-sphere/src/assets/typescript.svg +0 -1
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { Application, Entity } from '@playcanvas/react';
|
|
2
|
+
import { Camera, Light, Render } from '@playcanvas/react/components';
|
|
3
|
+
import { useApp, useMaterial } from '@playcanvas/react/hooks';
|
|
4
|
+
import type { Entity as PcEntity } from 'playcanvas';
|
|
5
|
+
import { useEffect, useRef } from 'react';
|
|
6
|
+
|
|
7
|
+
import './starter.css';
|
|
8
|
+
import { setupVr } from './vr';
|
|
9
|
+
|
|
10
|
+
function Scene() {
|
|
11
|
+
const app = useApp();
|
|
12
|
+
const rig = useRef<PcEntity>(null);
|
|
13
|
+
const camera = useRef<PcEntity>(null);
|
|
14
|
+
const floor = useMaterial({ diffuse: '#61666e' });
|
|
15
|
+
const wall = useMaterial({ diffuse: '#3d424a' });
|
|
16
|
+
const cyan = useMaterial({ diffuse: '#1fb3db' });
|
|
17
|
+
const coral = useMaterial({ diffuse: '#ff594d' });
|
|
18
|
+
const yellow = useMaterial({ diffuse: '#ffbf33' });
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (rig.current && camera.current) return setupVr(app, rig.current, camera.current);
|
|
22
|
+
}, [app]);
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<>
|
|
26
|
+
<Entity name="light" rotation={[45, 30, 0]}>
|
|
27
|
+
<Light type="directional" intensity={2} castShadows shadowBias={0.2} normalOffsetBias={0.05} />
|
|
28
|
+
</Entity>
|
|
29
|
+
<Entity name="floor" scale={[10, 1, 10]}>
|
|
30
|
+
<Render type="plane" material={floor} />
|
|
31
|
+
</Entity>
|
|
32
|
+
{[
|
|
33
|
+
['back-wall', [0, 2, -3.5], [8, 4, 0.2]],
|
|
34
|
+
['left-wall', [-4, 2, 0], [0.2, 4, 7]],
|
|
35
|
+
['right-wall', [4, 2, 0], [0.2, 4, 7]]
|
|
36
|
+
].map(([name, position, scale]) => (
|
|
37
|
+
<Entity
|
|
38
|
+
key={name as string}
|
|
39
|
+
name={name as string}
|
|
40
|
+
position={position as [number, number, number]}
|
|
41
|
+
scale={scale as [number, number, number]}
|
|
42
|
+
>
|
|
43
|
+
<Render type="box" material={wall} />
|
|
44
|
+
</Entity>
|
|
45
|
+
))}
|
|
46
|
+
{[
|
|
47
|
+
[-2.4, cyan],
|
|
48
|
+
[0, coral],
|
|
49
|
+
[2.4, yellow]
|
|
50
|
+
].map(([x, material], i) => (
|
|
51
|
+
<Entity key={i} position={[x as number, 2.4, -3.35]} scale={[1.3, 1.3, 0.12]}>
|
|
52
|
+
<Render type="box" material={material as never} />
|
|
53
|
+
</Entity>
|
|
54
|
+
))}
|
|
55
|
+
{[-2.4, 0, 2.4].map((x) => (
|
|
56
|
+
<Entity key={x} position={[x, 0.45, -1.6]} scale={[1, 0.9, 1]}>
|
|
57
|
+
<Render type="box" material={wall} />
|
|
58
|
+
</Entity>
|
|
59
|
+
))}
|
|
60
|
+
<Entity position={[-2.4, 1.35, -1.6]} scale={[0.7, 0.7, 0.7]}>
|
|
61
|
+
<Render type="sphere" material={cyan} />
|
|
62
|
+
</Entity>
|
|
63
|
+
<Entity position={[0, 1.35, -1.6]} scale={[0.7, 0.7, 0.7]}>
|
|
64
|
+
<Render type="box" material={coral} />
|
|
65
|
+
</Entity>
|
|
66
|
+
<Entity position={[2.4, 1.35, -1.6]} scale={[0.8, 0.9, 0.8]}>
|
|
67
|
+
<Render type="cone" material={yellow} />
|
|
68
|
+
</Entity>
|
|
69
|
+
<Entity name="xr-rig" ref={rig}>
|
|
70
|
+
<Entity name="camera" ref={camera} position={[0, 1.6, 4]}>
|
|
71
|
+
<Camera clearColor="#292e38" />
|
|
72
|
+
</Entity>
|
|
73
|
+
</Entity>
|
|
74
|
+
</>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function App() {
|
|
79
|
+
return (
|
|
80
|
+
<>
|
|
81
|
+
<Application graphicsDeviceOptions={{ xrCompatible: true }}>
|
|
82
|
+
<Scene />
|
|
83
|
+
</Application>
|
|
84
|
+
<div className="hud">
|
|
85
|
+
<section className="panel">
|
|
86
|
+
<h1>VR Starter</h1>
|
|
87
|
+
<p id="xr-status">Checking VR support…</p>
|
|
88
|
+
<div className="controls">
|
|
89
|
+
<button id="xr-button" disabled>
|
|
90
|
+
Enter VR
|
|
91
|
+
</button>
|
|
92
|
+
</div>
|
|
93
|
+
</section>
|
|
94
|
+
</div>
|
|
95
|
+
</>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export default App;
|
|
@@ -0,0 +1,44 @@
|
|
|
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>AR Placement</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<pc-app alpha>
|
|
11
|
+
<pc-material id="surface-material" diffuse="#474d57"></pc-material>
|
|
12
|
+
<pc-material id="cyan" diffuse="#1ab3e6"></pc-material>
|
|
13
|
+
<pc-material id="coral" diffuse="#ff5926"></pc-material>
|
|
14
|
+
<pc-scene>
|
|
15
|
+
<pc-entity name="camera" position="3 2.4 4" rotation="-20 37 0"
|
|
16
|
+
><pc-camera clear-color="#0d141f"></pc-camera
|
|
17
|
+
></pc-entity>
|
|
18
|
+
<pc-entity name="light" rotation="45 30 0"
|
|
19
|
+
><pc-light type="directional" intensity="2"></pc-light
|
|
20
|
+
></pc-entity>
|
|
21
|
+
<pc-entity name="preview">
|
|
22
|
+
<pc-entity name="surface" scale="4 0.15 4"
|
|
23
|
+
><pc-render type="cylinder" material="surface-material"></pc-render
|
|
24
|
+
></pc-entity>
|
|
25
|
+
<pc-entity name="box" position="0 0.65 0"
|
|
26
|
+
><pc-render type="box" material="cyan"></pc-render
|
|
27
|
+
></pc-entity>
|
|
28
|
+
<pc-entity name="reticle" position="0 0.12 0" scale="1.5 0.03 1.5"
|
|
29
|
+
><pc-render type="cylinder" material="coral"></pc-render
|
|
30
|
+
></pc-entity>
|
|
31
|
+
</pc-entity>
|
|
32
|
+
<pc-entity name="placement"></pc-entity>
|
|
33
|
+
</pc-scene>
|
|
34
|
+
</pc-app>
|
|
35
|
+
<div class="hud">
|
|
36
|
+
<section class="panel">
|
|
37
|
+
<h1>AR Placement</h1>
|
|
38
|
+
<p id="xr-status">Checking AR support…</p>
|
|
39
|
+
<div class="controls"><button id="xr-button" disabled>Start AR</button></div>
|
|
40
|
+
</section>
|
|
41
|
+
</div>
|
|
42
|
+
<script type="module" src="/src/main.ts"></script>
|
|
43
|
+
</body>
|
|
44
|
+
</html>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { EntityElement } from '@playcanvas/web-components';
|
|
2
|
+
import { whenReady } from '@playcanvas/web-components';
|
|
3
|
+
|
|
4
|
+
import { ArPlacement } from './ar-placement';
|
|
5
|
+
import './starter.css';
|
|
6
|
+
|
|
7
|
+
const [camera, preview, placement] = await Promise.all([
|
|
8
|
+
whenReady<EntityElement>('pc-entity[name="camera"]'),
|
|
9
|
+
whenReady<EntityElement>('pc-entity[name="preview"]'),
|
|
10
|
+
whenReady<EntityElement>('pc-entity[name="placement"]')
|
|
11
|
+
]);
|
|
12
|
+
placement.entity!.addComponent('script');
|
|
13
|
+
placement.entity!.script!.create(ArPlacement, { properties: { camera: camera.entity, preview: preview.entity } });
|
|
@@ -10,7 +10,7 @@ Node.js 22.23.2 or later.
|
|
|
10
10
|
## Getting started
|
|
11
11
|
|
|
12
12
|
```bash
|
|
13
|
-
npm create playcanvas@latest playcanvas-project -- --
|
|
13
|
+
npm create playcanvas@latest playcanvas-project -- --format web-components
|
|
14
14
|
cd playcanvas-project
|
|
15
15
|
npm install
|
|
16
16
|
npm run dev
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
registry=https://registry.npmjs.org/
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
* {
|
|
2
|
+
box-sizing: border-box;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
html,
|
|
6
|
+
body,
|
|
7
|
+
#root,
|
|
8
|
+
#application,
|
|
9
|
+
pc-app,
|
|
10
|
+
canvas {
|
|
11
|
+
width: 100%;
|
|
12
|
+
height: 100%;
|
|
13
|
+
margin: 0;
|
|
14
|
+
overflow: hidden;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
body {
|
|
18
|
+
background: #11151c;
|
|
19
|
+
color: #f8fafc;
|
|
20
|
+
font-family: Inter, ui-sans-serif, system-ui, sans-serif;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
canvas,
|
|
24
|
+
pc-app {
|
|
25
|
+
display: block;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.hud {
|
|
29
|
+
position: fixed;
|
|
30
|
+
inset: 0;
|
|
31
|
+
z-index: 10;
|
|
32
|
+
padding: 20px;
|
|
33
|
+
pointer-events: none;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.panel {
|
|
37
|
+
width: min(360px, calc(100vw - 40px));
|
|
38
|
+
padding: 16px;
|
|
39
|
+
border: 1px solid #ffffff24;
|
|
40
|
+
border-radius: 14px;
|
|
41
|
+
background: #0b1019d9;
|
|
42
|
+
box-shadow: 0 12px 40px #0008;
|
|
43
|
+
backdrop-filter: blur(12px);
|
|
44
|
+
pointer-events: auto;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
h1 {
|
|
48
|
+
margin: 0 0 6px;
|
|
49
|
+
font-size: 18px;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
p {
|
|
53
|
+
margin: 6px 0 0;
|
|
54
|
+
color: #aeb8c8;
|
|
55
|
+
font-size: 13px;
|
|
56
|
+
line-height: 1.45;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.controls {
|
|
60
|
+
display: flex;
|
|
61
|
+
flex-wrap: wrap;
|
|
62
|
+
gap: 8px;
|
|
63
|
+
margin-top: 14px;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
button {
|
|
67
|
+
padding: 8px 11px;
|
|
68
|
+
border: 1px solid #ffffff24;
|
|
69
|
+
border-radius: 9px;
|
|
70
|
+
background: #263247;
|
|
71
|
+
color: inherit;
|
|
72
|
+
cursor: pointer;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
button:hover,
|
|
76
|
+
button[aria-pressed='true'] {
|
|
77
|
+
border-color: #41b6e6;
|
|
78
|
+
background: #334867;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
button:disabled {
|
|
82
|
+
cursor: not-allowed;
|
|
83
|
+
opacity: 0.5;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.swatch {
|
|
87
|
+
width: 32px;
|
|
88
|
+
height: 32px;
|
|
89
|
+
padding: 0;
|
|
90
|
+
border-radius: 50%;
|
|
91
|
+
background: var(--color);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.crosshair {
|
|
95
|
+
position: fixed;
|
|
96
|
+
top: 50%;
|
|
97
|
+
left: 50%;
|
|
98
|
+
width: 16px;
|
|
99
|
+
height: 16px;
|
|
100
|
+
border: 2px solid #fff;
|
|
101
|
+
border-radius: 50%;
|
|
102
|
+
translate: -50% -50%;
|
|
103
|
+
box-shadow: 0 0 4px #000;
|
|
104
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
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>First-Person Controller</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<pc-app>
|
|
11
|
+
<pc-material id="floor-material" diffuse="#474d52" emissive="#0e0f10" gloss="0.2"></pc-material>
|
|
12
|
+
<pc-material id="wall-material" diffuse="#6b737a" emissive="#151718" gloss="0.25"></pc-material>
|
|
13
|
+
<pc-material id="blue-material" diffuse="#154a7a" emissive="#040f18" gloss="0.4"></pc-material>
|
|
14
|
+
<pc-material id="green-material" diffuse="#2e6638" emissive="#09140b" gloss="0.2"></pc-material>
|
|
15
|
+
<pc-material id="wood-material" diffuse="#7a451a" emissive="#180e05" gloss="0.2"></pc-material>
|
|
16
|
+
<pc-material id="metal-material" diffuse="#475461" emissive="#0e1113" gloss="0.5"></pc-material>
|
|
17
|
+
<pc-module
|
|
18
|
+
name="Ammo"
|
|
19
|
+
glue="/ammo/ammo.wasm.js"
|
|
20
|
+
wasm="/ammo/ammo.wasm.wasm"
|
|
21
|
+
fallback="/ammo/ammo.js"
|
|
22
|
+
></pc-module>
|
|
23
|
+
<pc-scene>
|
|
24
|
+
<pc-entity name="light" rotation="50 30 0"
|
|
25
|
+
><pc-light
|
|
26
|
+
type="directional"
|
|
27
|
+
intensity="2.5"
|
|
28
|
+
cast-shadows
|
|
29
|
+
shadow-bias="0.2"
|
|
30
|
+
normal-offset-bias="0.05"
|
|
31
|
+
></pc-light
|
|
32
|
+
></pc-entity>
|
|
33
|
+
<pc-entity name="fill" rotation="-25 -140 0"
|
|
34
|
+
><pc-light type="directional" intensity="0.8"></pc-light
|
|
35
|
+
></pc-entity>
|
|
36
|
+
<pc-entity name="floor" position="0 -0.1 0" scale="18 0.2 18"
|
|
37
|
+
><pc-render type="box" material="floor-material"></pc-render
|
|
38
|
+
><pc-collision type="box" half-extents="9 0.1 9"></pc-collision
|
|
39
|
+
><pc-rigidbody type="static"></pc-rigidbody
|
|
40
|
+
></pc-entity>
|
|
41
|
+
<pc-entity name="back-wall" position="0 1.5 -9" scale="18 3 0.3"
|
|
42
|
+
><pc-render type="box" material="wall-material"></pc-render
|
|
43
|
+
><pc-collision type="box" half-extents="9 1.5 0.15"></pc-collision
|
|
44
|
+
><pc-rigidbody type="static"></pc-rigidbody
|
|
45
|
+
></pc-entity>
|
|
46
|
+
<pc-entity name="front-wall" position="0 1.5 9" scale="18 3 0.3"
|
|
47
|
+
><pc-render type="box" material="wall-material"></pc-render
|
|
48
|
+
><pc-collision type="box" half-extents="9 1.5 0.15"></pc-collision
|
|
49
|
+
><pc-rigidbody type="static"></pc-rigidbody
|
|
50
|
+
></pc-entity>
|
|
51
|
+
<pc-entity name="left-wall" position="-9 1.5 0" scale="0.3 3 18"
|
|
52
|
+
><pc-render type="box" material="wall-material"></pc-render
|
|
53
|
+
><pc-collision type="box" half-extents="0.15 1.5 9"></pc-collision
|
|
54
|
+
><pc-rigidbody type="static"></pc-rigidbody
|
|
55
|
+
></pc-entity>
|
|
56
|
+
<pc-entity name="right-wall" position="9 1.5 0" scale="0.3 3 18"
|
|
57
|
+
><pc-render type="box" material="wall-material"></pc-render
|
|
58
|
+
><pc-collision type="box" half-extents="0.15 1.5 9"></pc-collision
|
|
59
|
+
><pc-rigidbody type="static"></pc-rigidbody
|
|
60
|
+
></pc-entity>
|
|
61
|
+
<pc-entity name="blue-crate" position="-2 0.75 -3" scale="1.5 1.5 1.5"
|
|
62
|
+
><pc-render type="box" material="blue-material"></pc-render
|
|
63
|
+
><pc-collision type="box" half-extents="0.75 0.75 0.75"></pc-collision
|
|
64
|
+
><pc-rigidbody type="static"></pc-rigidbody
|
|
65
|
+
></pc-entity>
|
|
66
|
+
<pc-entity name="green-crate" position="3 0.5 1" scale="2.5 1 1"
|
|
67
|
+
><pc-render type="box" material="green-material"></pc-render
|
|
68
|
+
><pc-collision type="box" half-extents="1.25 0.5 0.5"></pc-collision
|
|
69
|
+
><pc-rigidbody type="static"></pc-rigidbody
|
|
70
|
+
></pc-entity>
|
|
71
|
+
<pc-entity name="cargo-left-0" position="-5.5 0.75 -5.5" scale="2 1.5 2"
|
|
72
|
+
><pc-render type="box" material="wood-material"></pc-render
|
|
73
|
+
><pc-collision type="box" half-extents="1 0.75 1"></pc-collision
|
|
74
|
+
><pc-rigidbody type="static"></pc-rigidbody
|
|
75
|
+
></pc-entity>
|
|
76
|
+
<pc-entity name="cargo-left-1" position="-5.5 2 -5.5" scale="1.5 1 1.5"
|
|
77
|
+
><pc-render type="box" material="blue-material"></pc-render
|
|
78
|
+
><pc-collision type="box" half-extents="0.75 0.5 0.75"></pc-collision
|
|
79
|
+
><pc-rigidbody type="static"></pc-rigidbody
|
|
80
|
+
></pc-entity>
|
|
81
|
+
<pc-entity name="cargo-right-0" position="5.3 0.6 -4.8" scale="2.4 1.2 2"
|
|
82
|
+
><pc-render type="box" material="green-material"></pc-render
|
|
83
|
+
><pc-collision type="box" half-extents="1.2 0.6 1"></pc-collision
|
|
84
|
+
><pc-rigidbody type="static"></pc-rigidbody
|
|
85
|
+
></pc-entity>
|
|
86
|
+
<pc-entity name="cargo-right-1" position="5.3 1.7 -4.8" scale="1.5 1 1.5"
|
|
87
|
+
><pc-render type="box" material="wood-material"></pc-render
|
|
88
|
+
><pc-collision type="box" half-extents="0.75 0.5 0.75"></pc-collision
|
|
89
|
+
><pc-rigidbody type="static"></pc-rigidbody
|
|
90
|
+
></pc-entity>
|
|
91
|
+
<pc-entity name="cargo-center" position="0 0.6 -6.5" scale="2.2 1.2 1.8"
|
|
92
|
+
><pc-render type="box" material="blue-material"></pc-render
|
|
93
|
+
><pc-collision type="box" half-extents="1.1 0.6 0.9"></pc-collision
|
|
94
|
+
><pc-rigidbody type="static"></pc-rigidbody
|
|
95
|
+
></pc-entity>
|
|
96
|
+
<pc-entity name="shelf-left-post-0" position="-6.8 1.4 -3.5" scale="0.25 2.8 0.25"
|
|
97
|
+
><pc-render type="box" material="metal-material"></pc-render
|
|
98
|
+
><pc-collision type="box" half-extents="0.125 1.4 0.125"></pc-collision
|
|
99
|
+
><pc-rigidbody type="static"></pc-rigidbody
|
|
100
|
+
></pc-entity>
|
|
101
|
+
<pc-entity name="shelf-left-post-1" position="-6.8 1.4 0" scale="0.25 2.8 0.25"
|
|
102
|
+
><pc-render type="box" material="metal-material"></pc-render
|
|
103
|
+
><pc-collision type="box" half-extents="0.125 1.4 0.125"></pc-collision
|
|
104
|
+
><pc-rigidbody type="static"></pc-rigidbody
|
|
105
|
+
></pc-entity>
|
|
106
|
+
<pc-entity name="shelf-left-post-2" position="-6.8 1.4 3.5" scale="0.25 2.8 0.25"
|
|
107
|
+
><pc-render type="box" material="metal-material"></pc-render
|
|
108
|
+
><pc-collision type="box" half-extents="0.125 1.4 0.125"></pc-collision
|
|
109
|
+
><pc-rigidbody type="static"></pc-rigidbody
|
|
110
|
+
></pc-entity>
|
|
111
|
+
<pc-entity name="shelf-right-post-0" position="6.8 1.4 -3.5" scale="0.25 2.8 0.25"
|
|
112
|
+
><pc-render type="box" material="metal-material"></pc-render
|
|
113
|
+
><pc-collision type="box" half-extents="0.125 1.4 0.125"></pc-collision
|
|
114
|
+
><pc-rigidbody type="static"></pc-rigidbody
|
|
115
|
+
></pc-entity>
|
|
116
|
+
<pc-entity name="shelf-right-post-1" position="6.8 1.4 0" scale="0.25 2.8 0.25"
|
|
117
|
+
><pc-render type="box" material="metal-material"></pc-render
|
|
118
|
+
><pc-collision type="box" half-extents="0.125 1.4 0.125"></pc-collision
|
|
119
|
+
><pc-rigidbody type="static"></pc-rigidbody
|
|
120
|
+
></pc-entity>
|
|
121
|
+
<pc-entity name="shelf-right-post-2" position="6.8 1.4 3.5" scale="0.25 2.8 0.25"
|
|
122
|
+
><pc-render type="box" material="metal-material"></pc-render
|
|
123
|
+
><pc-collision type="box" half-extents="0.125 1.4 0.125"></pc-collision
|
|
124
|
+
><pc-rigidbody type="static"></pc-rigidbody
|
|
125
|
+
></pc-entity>
|
|
126
|
+
<pc-entity name="shelf-left-low" position="-6.8 0.65 0" scale="1.1 0.18 7.5"
|
|
127
|
+
><pc-render type="box" material="metal-material"></pc-render
|
|
128
|
+
><pc-collision type="box" half-extents="0.55 0.09 3.75"></pc-collision
|
|
129
|
+
><pc-rigidbody type="static"></pc-rigidbody
|
|
130
|
+
></pc-entity>
|
|
131
|
+
<pc-entity name="shelf-left-high" position="-6.8 2.1 0" scale="1.1 0.18 7.5"
|
|
132
|
+
><pc-render type="box" material="metal-material"></pc-render
|
|
133
|
+
><pc-collision type="box" half-extents="0.55 0.09 3.75"></pc-collision
|
|
134
|
+
><pc-rigidbody type="static"></pc-rigidbody
|
|
135
|
+
></pc-entity>
|
|
136
|
+
<pc-entity name="shelf-right-low" position="6.8 0.65 0" scale="1.1 0.18 7.5"
|
|
137
|
+
><pc-render type="box" material="metal-material"></pc-render
|
|
138
|
+
><pc-collision type="box" half-extents="0.55 0.09 3.75"></pc-collision
|
|
139
|
+
><pc-rigidbody type="static"></pc-rigidbody
|
|
140
|
+
></pc-entity>
|
|
141
|
+
<pc-entity name="shelf-right-high" position="6.8 2.1 0" scale="1.1 0.18 7.5"
|
|
142
|
+
><pc-render type="box" material="metal-material"></pc-render
|
|
143
|
+
><pc-collision type="box" half-extents="0.55 0.09 3.75"></pc-collision
|
|
144
|
+
><pc-rigidbody type="static"></pc-rigidbody
|
|
145
|
+
></pc-entity>
|
|
146
|
+
<pc-entity name="pallet" position="-2.5 0.15 2.5" scale="3 0.3 2"
|
|
147
|
+
><pc-render type="box" material="wood-material"></pc-render
|
|
148
|
+
><pc-collision type="box" half-extents="1.5 0.15 1"></pc-collision
|
|
149
|
+
><pc-rigidbody type="static"></pc-rigidbody
|
|
150
|
+
></pc-entity>
|
|
151
|
+
<pc-entity name="player" position="0 1 5">
|
|
152
|
+
<pc-collision type="capsule" radius="0.45" height="1.8"></pc-collision>
|
|
153
|
+
<pc-rigidbody type="dynamic" mass="80" angular-factor="0 0 0"></pc-rigidbody>
|
|
154
|
+
<pc-entity name="camera" position="0 0.65 0"
|
|
155
|
+
><pc-camera clear-color="#61a3db" fov="80"></pc-camera
|
|
156
|
+
></pc-entity>
|
|
157
|
+
</pc-entity>
|
|
158
|
+
</pc-scene>
|
|
159
|
+
</pc-app>
|
|
160
|
+
<div class="hud">
|
|
161
|
+
<section class="panel">
|
|
162
|
+
<h1>First-Person Controller</h1>
|
|
163
|
+
<p>Click the scene, then use WASD, mouse look and Space to jump.</p>
|
|
164
|
+
</section>
|
|
165
|
+
</div>
|
|
166
|
+
<script type="module" src="/src/main.ts"></script>
|
|
167
|
+
</body>
|
|
168
|
+
</html>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { EntityElement } from '@playcanvas/web-components';
|
|
2
|
+
import { whenReady } from '@playcanvas/web-components';
|
|
3
|
+
|
|
4
|
+
import { addFirstPersonController } 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] = await Promise.all([
|
|
12
|
+
whenReady<EntityElement>('pc-entity[name="player"]'),
|
|
13
|
+
whenReady<EntityElement>('pc-entity[name="camera"]')
|
|
14
|
+
]);
|
|
15
|
+
addFirstPersonController(player.entity!, camera.entity!);
|
|
@@ -13,40 +13,23 @@
|
|
|
13
13
|
|
|
14
14
|
<pc-scene>
|
|
15
15
|
<!-- Camera. Orbit controls are attached in src/main.ts -->
|
|
16
|
-
<pc-entity name="camera" position="
|
|
17
|
-
<pc-camera clear-color="#
|
|
16
|
+
<pc-entity name="camera" position="3.2 1.5 3.2" rotation="-10 45 0">
|
|
17
|
+
<pc-camera clear-color="#07101a"></pc-camera>
|
|
18
18
|
</pc-entity>
|
|
19
19
|
|
|
20
20
|
<!-- Lighting comes from the environment map, which is applied in src/main.ts -->
|
|
21
21
|
|
|
22
22
|
<!-- Background grid. The grid script is attached in src/main.ts -->
|
|
23
|
-
<pc-entity name="grid" scale="
|
|
23
|
+
<pc-entity name="grid" scale="12 12 12"></pc-entity>
|
|
24
24
|
|
|
25
25
|
<!-- The sphere. pc-app dispatches pointer events onto whatever the pointer hits -->
|
|
26
|
-
<pc-entity name="sphere" position="0 0.
|
|
26
|
+
<pc-entity name="sphere" position="0 0.7 0" scale="1.25 1.25 1.25">
|
|
27
27
|
<pc-render type="sphere" material="sphere-material"></pc-render>
|
|
28
28
|
</pc-entity>
|
|
29
29
|
</pc-scene>
|
|
30
30
|
</pc-app>
|
|
31
31
|
|
|
32
|
-
<
|
|
33
|
-
<div class="grow">
|
|
34
|
-
<header>
|
|
35
|
-
<h1>PlayCanvas + Web Components</h1>
|
|
36
|
-
<a href="https://developer.playcanvas.com/user-manual/web-components/" target="_blank">
|
|
37
|
-
<img src="/src/assets/playcanvas.png" class="playcanvas-logo logo" alt="PlayCanvas logo" />
|
|
38
|
-
</a>
|
|
39
|
-
<a href="https://www.typescriptlang.org/" target="_blank">
|
|
40
|
-
<img src="/src/assets/typescript.svg" class="logo typescript" alt="TypeScript logo" />
|
|
41
|
-
</a>
|
|
42
|
-
</header>
|
|
43
|
-
</div>
|
|
44
|
-
<div>
|
|
45
|
-
<span id="counter" class="pill">Click Count: 0</span>
|
|
46
|
-
<p>Edit <code>index.html</code> and save to reload the scene</p>
|
|
47
|
-
</div>
|
|
48
|
-
<p class="read-the-docs">Click on the PlayCanvas and TypeScript logos to learn more</p>
|
|
49
|
-
</div>
|
|
32
|
+
<p id="counter" class="counter">Click count: 0</p>
|
|
50
33
|
|
|
51
34
|
<script type="module" src="/src/main.ts"></script>
|
|
52
35
|
</body>
|
|
@@ -5,10 +5,11 @@ import { Asset, TEXTURETYPE_RGBP } from 'playcanvas';
|
|
|
5
5
|
import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs';
|
|
6
6
|
import { Grid } from 'playcanvas/scripts/esm/grid.mjs';
|
|
7
7
|
|
|
8
|
+
import './starter.css';
|
|
8
9
|
import './style.css';
|
|
9
10
|
|
|
10
|
-
const HOVER_COLOR = '
|
|
11
|
-
const DEFAULT_COLOR = '
|
|
11
|
+
const HOVER_COLOR = '#40ccff';
|
|
12
|
+
const DEFAULT_COLOR = '#e6edf9';
|
|
12
13
|
|
|
13
14
|
// The camera is awaited as <pc-camera> rather than the <pc-entity> holding it - an entity becomes
|
|
14
15
|
// ready before its component children do, and CameraControls needs the camera component to exist
|
|
@@ -49,7 +50,7 @@ if (skyboxLayer) {
|
|
|
49
50
|
// with <pc-script name="...">, which only resolves scripts fetched at runtime by <pc-asset>
|
|
50
51
|
const camera = cameraComponent.closestEntity;
|
|
51
52
|
camera?.entity?.addComponent('script');
|
|
52
|
-
camera?.entity?.script?.create(CameraControls);
|
|
53
|
+
camera?.entity?.script?.create(CameraControls, { properties: { sceneSize: 3 } });
|
|
53
54
|
grid.entity?.addComponent('script');
|
|
54
55
|
grid.entity?.script?.create(Grid);
|
|
55
56
|
|
|
@@ -72,5 +73,5 @@ sphere.addEventListener('pointerleave', () => {
|
|
|
72
73
|
|
|
73
74
|
sphere.addEventListener('pointerup', () => {
|
|
74
75
|
count++;
|
|
75
|
-
counterElement.textContent = `Click
|
|
76
|
+
counterElement.textContent = `Click count: ${count}`;
|
|
76
77
|
});
|
|
@@ -1,39 +1,4 @@
|
|
|
1
|
-
:root {
|
|
2
|
-
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
|
|
3
|
-
line-height: 1.5;
|
|
4
|
-
font-weight: 400;
|
|
5
|
-
|
|
6
|
-
color-scheme: light dark;
|
|
7
|
-
color: rgba(255, 255, 255, 0.87);
|
|
8
|
-
background-color: #242424;
|
|
9
|
-
|
|
10
|
-
font-synthesis: none;
|
|
11
|
-
text-rendering: optimizeLegibility;
|
|
12
|
-
-webkit-font-smoothing: antialiased;
|
|
13
|
-
-moz-osx-font-smoothing: grayscale;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
header {
|
|
17
|
-
display: flex;
|
|
18
|
-
flex-direction: row;
|
|
19
|
-
align-items: center;
|
|
20
|
-
padding: 2rem;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
a {
|
|
24
|
-
font-weight: 500;
|
|
25
|
-
color: #646cff;
|
|
26
|
-
pointer-events: auto;
|
|
27
|
-
text-decoration: inherit;
|
|
28
|
-
}
|
|
29
|
-
a:hover {
|
|
30
|
-
color: #535bf2;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
1
|
body {
|
|
34
|
-
width: 100%;
|
|
35
|
-
height: 100%;
|
|
36
|
-
padding: 0;
|
|
37
2
|
margin: 0;
|
|
38
3
|
overflow: hidden;
|
|
39
4
|
}
|
|
@@ -67,45 +32,22 @@ pc-app {
|
|
|
67
32
|
display: block;
|
|
68
33
|
}
|
|
69
34
|
|
|
70
|
-
.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
:
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
flex-direction: column;
|
|
89
|
-
align-items: center;
|
|
90
|
-
justify-content: stretch;
|
|
91
|
-
width: 100vw;
|
|
92
|
-
height: 100vh;
|
|
93
|
-
pointer-events: none;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
.overlay > .grow {
|
|
97
|
-
flex-grow: 1;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
.absolute {
|
|
101
|
-
position: absolute;
|
|
102
|
-
top: 0;
|
|
103
|
-
left: 0;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
.pill {
|
|
107
|
-
background-color: #000;
|
|
108
|
-
color: #fff;
|
|
109
|
-
padding: 0.5rem 1rem;
|
|
110
|
-
border-radius: 0.5rem;
|
|
35
|
+
.counter {
|
|
36
|
+
position: fixed;
|
|
37
|
+
bottom: 22px;
|
|
38
|
+
left: 50%;
|
|
39
|
+
z-index: 2;
|
|
40
|
+
margin: 0;
|
|
41
|
+
padding: 9px 13px;
|
|
42
|
+
border: 1px solid #ffffff24;
|
|
43
|
+
border-radius: 999px;
|
|
44
|
+
background: #07101bd9;
|
|
45
|
+
color: #f8fafc;
|
|
46
|
+
font:
|
|
47
|
+
650 12px Inter,
|
|
48
|
+
ui-sans-serif,
|
|
49
|
+
system-ui,
|
|
50
|
+
sans-serif;
|
|
51
|
+
translate: -50% 0;
|
|
52
|
+
backdrop-filter: blur(10px);
|
|
111
53
|
}
|