create-playcanvas 0.15.0 → 0.16.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 +69 -24
- package/dist/index.mjs +11 -11
- package/package.json +1 -1
- package/templates/_shared/scene-editor/AGENTS.md +8 -0
- package/templates/_shared/scene-editor/README.md +15 -2
- package/templates/_shared/scene-editor/src/scene-editor.ts +186 -36
- package/templates/engine/ar-placement/index.html +20 -0
- package/templates/engine/ar-placement/src/main.ts +22 -12
- package/templates/engine/base/AGENTS.md +1 -0
- package/templates/engine/base/README.md +1 -1
- package/templates/engine/first-person-controller/index.html +19 -0
- package/templates/engine/first-person-controller/src/main.ts +16 -11
- package/templates/engine/product-configurator/index.html +30 -0
- package/templates/engine/product-configurator/src/main.ts +33 -32
- package/templates/engine/scene-editor/index.html +33 -0
- package/templates/engine/scene-editor/src/main.ts +56 -47
- package/templates/engine/sprite-game/index.html +19 -0
- package/templates/engine/sprite-game/src/main.ts +19 -11
- package/templates/engine/third-person-controller/index.html +19 -0
- package/templates/engine/third-person-controller/src/main.ts +16 -11
- package/templates/engine/vr-starter/index.html +20 -0
- package/templates/engine/vr-starter/src/main.ts +22 -12
- package/templates/index.ts +1 -14
- package/templates/react/base/AGENTS.md +1 -0
- package/templates/react/scene-editor/src/App.tsx +73 -40
- package/templates/web-components/base/AGENTS.md +1 -0
- package/templates/web-components/scene-editor/index.html +32 -25
- package/templates/web-components/scene-editor/src/main.ts +33 -11
- package/templates/_shared/interactive-sphere/README.md +0 -7
- package/templates/_shared/interactive-sphere/public/environment-map.png +0 -0
- package/templates/_shared/interactive-sphere/src/counter.css +0 -19
- package/templates/_shared/physics-playground/README.md +0 -7
- package/templates/engine/interactive-sphere/src/App.ts +0 -182
- package/templates/engine/interactive-sphere/src/main.ts +0 -16
- package/templates/engine/interactive-sphere/src/utils.ts +0 -16
- package/templates/engine/physics-playground/src/main.ts +0 -131
- package/templates/react/interactive-sphere/src/App.tsx +0 -21
- package/templates/react/interactive-sphere/src/Scene.tsx +0 -70
- package/templates/react/physics-playground/src/App.tsx +0 -85
- package/templates/web-components/interactive-sphere/index.html +0 -36
- package/templates/web-components/interactive-sphere/src/main.ts +0 -76
- package/templates/web-components/physics-playground/index.html +0 -46
- package/templates/web-components/physics-playground/src/main.ts +0 -32
|
@@ -0,0 +1,20 @@
|
|
|
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
|
+
<canvas id="application-canvas"></canvas>
|
|
11
|
+
<div class="hud">
|
|
12
|
+
<section class="panel">
|
|
13
|
+
<h1>AR Placement</h1>
|
|
14
|
+
<p id="xr-status">Checking AR support…</p>
|
|
15
|
+
<div class="controls"><button id="xr-button" disabled>Start AR</button></div>
|
|
16
|
+
</section>
|
|
17
|
+
</div>
|
|
18
|
+
<script type="module" src="/src/main.ts"></script>
|
|
19
|
+
</body>
|
|
20
|
+
</html>
|
|
@@ -17,24 +17,36 @@ import {
|
|
|
17
17
|
import { ArPlacement } from './ar-placement';
|
|
18
18
|
import './starter.css';
|
|
19
19
|
|
|
20
|
-
document.body.insertAdjacentHTML(
|
|
21
|
-
'beforeend',
|
|
22
|
-
'<div class="hud"><section class="panel"><h1>AR Placement</h1><p id="xr-status">Checking AR support…</p><div class="controls"><button id="xr-button" disabled>Start AR</button></div></section></div>'
|
|
23
|
-
);
|
|
24
|
-
|
|
25
20
|
const canvas = document.getElementById('application-canvas') as HTMLCanvasElement;
|
|
21
|
+
|
|
26
22
|
const device = await createGraphicsDevice(canvas);
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
device.maxPixelRatio = Math.min(window.devicePixelRatio, 2);
|
|
24
|
+
|
|
25
|
+
const createOptions = new AppOptions();
|
|
26
|
+
createOptions.graphicsDevice = device;
|
|
27
|
+
createOptions.componentSystems = [
|
|
28
|
+
RenderComponentSystem,
|
|
29
|
+
CameraComponentSystem,
|
|
30
|
+
LightComponentSystem,
|
|
31
|
+
ScriptComponentSystem
|
|
32
|
+
];
|
|
33
|
+
createOptions.xr = XrManager;
|
|
31
34
|
|
|
32
35
|
const app = new AppBase(canvas);
|
|
33
|
-
app.init(
|
|
36
|
+
app.init(createOptions);
|
|
34
37
|
app.start();
|
|
38
|
+
|
|
39
|
+
// Set the canvas to fill the window and automatically change resolution to be the same as the canvas size
|
|
35
40
|
app.setCanvasFillMode(FILLMODE_FILL_WINDOW);
|
|
36
41
|
app.setCanvasResolution(RESOLUTION_AUTO);
|
|
37
42
|
|
|
43
|
+
// Ensure canvas is resized when window changes size
|
|
44
|
+
const resize = () => app.resizeCanvas();
|
|
45
|
+
window.addEventListener('resize', resize);
|
|
46
|
+
app.on('destroy', () => {
|
|
47
|
+
window.removeEventListener('resize', resize);
|
|
48
|
+
});
|
|
49
|
+
|
|
38
50
|
const camera = new Entity('camera');
|
|
39
51
|
camera.addComponent('camera', { clearColor: new Color(0.05, 0.08, 0.12, 1) });
|
|
40
52
|
camera.setPosition(3, 2.4, 4);
|
|
@@ -73,5 +85,3 @@ const placement = new Entity('placement');
|
|
|
73
85
|
placement.addComponent('script');
|
|
74
86
|
placement.script!.create(ArPlacement, { properties: { camera, preview } });
|
|
75
87
|
app.root.addChild(placement);
|
|
76
|
-
|
|
77
|
-
window.addEventListener('resize', () => app.resizeCanvas());
|
|
@@ -26,6 +26,7 @@ A PlayCanvas Engine app in TypeScript, built with Vite. The scene is built in co
|
|
|
26
26
|
- Builds use relative URLs (`base: './'` in `vite.config.ts`), so they run from any folder. Load files in `public/` with relative paths such as `./model.glb`, not `/model.glb`.
|
|
27
27
|
- The engine ships ready-made scripts, such as camera controls and character controllers, under `playcanvas/scripts/esm/`. Use one before writing the same behavior yourself.
|
|
28
28
|
- `node_modules/playcanvas/build/playcanvas.d.ts` documents the installed engine's API.
|
|
29
|
+
- For guides, start from the [Engine guides index](https://developer.playcanvas.com/user-manual/engine/llms.txt), which links a Markdown version of every page.
|
|
29
30
|
- TypeScript is strict, and unused locals and parameters are errors.
|
|
30
31
|
|
|
31
32
|
## Checking your work
|
|
@@ -45,6 +45,6 @@ This project includes [`@playcanvas/skills`](https://github.com/playcanvas/skill
|
|
|
45
45
|
## Further reading
|
|
46
46
|
|
|
47
47
|
- [PlayCanvas Engine manual](https://developer.playcanvas.com/user-manual/engine/)
|
|
48
|
-
- [PlayCanvas examples](https://playcanvas.
|
|
48
|
+
- [PlayCanvas examples](https://playcanvas.com/examples)
|
|
49
49
|
- [Vite documentation](https://vite.dev/)
|
|
50
50
|
- [TypeScript documentation](https://www.typescriptlang.org/docs/)
|
|
@@ -0,0 +1,19 @@
|
|
|
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
|
+
<canvas id="application-canvas"></canvas>
|
|
11
|
+
<div class="hud">
|
|
12
|
+
<section class="panel">
|
|
13
|
+
<h1>First-Person Controller</h1>
|
|
14
|
+
<p>Click the scene, then use WASD, mouse look and Space to jump.</p>
|
|
15
|
+
</section>
|
|
16
|
+
</div>
|
|
17
|
+
<script type="module" src="/src/main.ts"></script>
|
|
18
|
+
</body>
|
|
19
|
+
</html>
|
|
@@ -28,16 +28,14 @@ await new Promise<void>((resolve) => {
|
|
|
28
28
|
WasmModule.getInstance('Ammo', () => resolve());
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
-
document.body.insertAdjacentHTML(
|
|
32
|
-
'beforeend',
|
|
33
|
-
'<div class="hud"><section class="panel"><h1>First-Person Controller</h1><p>Click the scene, then use WASD, mouse look and Space to jump.</p></section></div>'
|
|
34
|
-
);
|
|
35
|
-
|
|
36
31
|
const canvas = document.getElementById('application-canvas') as HTMLCanvasElement;
|
|
32
|
+
|
|
37
33
|
const device = await createGraphicsDevice(canvas);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
device.maxPixelRatio = Math.min(window.devicePixelRatio, 2);
|
|
35
|
+
|
|
36
|
+
const createOptions = new AppOptions();
|
|
37
|
+
createOptions.graphicsDevice = device;
|
|
38
|
+
createOptions.componentSystems = [
|
|
41
39
|
RenderComponentSystem,
|
|
42
40
|
CameraComponentSystem,
|
|
43
41
|
LightComponentSystem,
|
|
@@ -47,11 +45,20 @@ options.componentSystems = [
|
|
|
47
45
|
];
|
|
48
46
|
|
|
49
47
|
const app = new AppBase(canvas);
|
|
50
|
-
app.init(
|
|
48
|
+
app.init(createOptions);
|
|
51
49
|
app.start();
|
|
50
|
+
|
|
51
|
+
// Set the canvas to fill the window and automatically change resolution to be the same as the canvas size
|
|
52
52
|
app.setCanvasFillMode(FILLMODE_FILL_WINDOW);
|
|
53
53
|
app.setCanvasResolution(RESOLUTION_AUTO);
|
|
54
54
|
|
|
55
|
+
// Ensure canvas is resized when window changes size
|
|
56
|
+
const resize = () => app.resizeCanvas();
|
|
57
|
+
window.addEventListener('resize', resize);
|
|
58
|
+
app.on('destroy', () => {
|
|
59
|
+
window.removeEventListener('resize', resize);
|
|
60
|
+
});
|
|
61
|
+
|
|
55
62
|
const material = (color: Color) => {
|
|
56
63
|
const result = new StandardMaterial();
|
|
57
64
|
result.diffuse = color;
|
|
@@ -134,5 +141,3 @@ const fill = new Entity('fill');
|
|
|
134
141
|
fill.addComponent('light', { type: 'directional', intensity: 0.8 });
|
|
135
142
|
fill.setEulerAngles(-25, -140, 0);
|
|
136
143
|
app.root.addChild(fill);
|
|
137
|
-
|
|
138
|
-
window.addEventListener('resize', () => app.resizeCanvas());
|
|
@@ -0,0 +1,30 @@
|
|
|
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
|
+
<canvas id="application-canvas"></canvas>
|
|
11
|
+
<div class="hud">
|
|
12
|
+
<section class="panel">
|
|
13
|
+
<h1>Product Configurator</h1>
|
|
14
|
+
<p>Choose a paint finish, then drag to orbit.</p>
|
|
15
|
+
<div class="controls variants" id="paints">
|
|
16
|
+
<button aria-pressed="true" data-color="#d6293e" data-shade="#9b1731">
|
|
17
|
+
<span class="finish" style="--color: #d6293e"></span>Crimson
|
|
18
|
+
</button>
|
|
19
|
+
<button data-color="#d8e4e9" data-shade="#8fa8b5">
|
|
20
|
+
<span class="finish" style="--color: #d8e4e9"></span>Arctic
|
|
21
|
+
</button>
|
|
22
|
+
<button data-color="#9acb34" data-shade="#3c742d">
|
|
23
|
+
<span class="finish" style="--color: #9acb34"></span>Volt
|
|
24
|
+
</button>
|
|
25
|
+
</div>
|
|
26
|
+
</section>
|
|
27
|
+
</div>
|
|
28
|
+
<script type="module" src="/src/main.ts"></script>
|
|
29
|
+
</body>
|
|
30
|
+
</html>
|
|
@@ -29,33 +29,38 @@ import './product.css';
|
|
|
29
29
|
import './starter.css';
|
|
30
30
|
|
|
31
31
|
const PRODUCT_URL = 'https://developer.playcanvas.com/assets/lambo.glb';
|
|
32
|
-
const PAINTS = [
|
|
33
|
-
{ name: 'Crimson', color: '#d6293e', shade: '#9b1731' },
|
|
34
|
-
{ name: 'Arctic', color: '#d8e4e9', shade: '#8fa8b5' },
|
|
35
|
-
{ name: 'Volt', color: '#9acb34', shade: '#3c742d' }
|
|
36
|
-
];
|
|
37
32
|
const CAMERA_FOCUS = new Vec3(0, 0.8, 0);
|
|
38
33
|
const CAMERA_PITCH = new Vec2(-85, -4);
|
|
39
34
|
|
|
40
|
-
document.body.insertAdjacentHTML(
|
|
41
|
-
'beforeend',
|
|
42
|
-
`<div class="hud"><section class="panel"><h1>Product Configurator</h1><p>Choose a paint finish, then drag to orbit.</p><div class="controls variants" id="paints">${PAINTS.map(({ name, color }, i) => `<button aria-pressed="${i === 0}" data-color="${color}"><span class="finish" style="--color:${color}"></span>${name}</button>`).join('')}</div></section></div>`
|
|
43
|
-
);
|
|
44
|
-
|
|
45
35
|
const canvas = document.getElementById('application-canvas') as HTMLCanvasElement;
|
|
36
|
+
|
|
46
37
|
const device = await createGraphicsDevice(canvas);
|
|
47
|
-
device.maxPixelRatio = Math.min(
|
|
38
|
+
device.maxPixelRatio = Math.min(window.devicePixelRatio, 2);
|
|
48
39
|
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
40
|
+
const createOptions = new AppOptions();
|
|
41
|
+
createOptions.graphicsDevice = device;
|
|
42
|
+
createOptions.componentSystems = [
|
|
43
|
+
RenderComponentSystem,
|
|
44
|
+
CameraComponentSystem,
|
|
45
|
+
LightComponentSystem,
|
|
46
|
+
ScriptComponentSystem
|
|
47
|
+
];
|
|
48
|
+
createOptions.resourceHandlers = [TextureHandler, ContainerHandler];
|
|
53
49
|
|
|
54
50
|
const app = new AppBase(canvas);
|
|
55
|
-
app.init(
|
|
51
|
+
app.init(createOptions);
|
|
52
|
+
|
|
53
|
+
// Set the canvas to fill the window and automatically change resolution to be the same as the canvas size
|
|
56
54
|
app.setCanvasFillMode(FILLMODE_FILL_WINDOW);
|
|
57
55
|
app.setCanvasResolution(RESOLUTION_AUTO);
|
|
58
56
|
|
|
57
|
+
// Ensure canvas is resized when window changes size
|
|
58
|
+
const resize = () => app.resizeCanvas();
|
|
59
|
+
window.addEventListener('resize', resize);
|
|
60
|
+
app.on('destroy', () => {
|
|
61
|
+
window.removeEventListener('resize', resize);
|
|
62
|
+
});
|
|
63
|
+
|
|
59
64
|
const product = new Asset('car', 'container', { url: PRODUCT_URL });
|
|
60
65
|
await new Promise<void>((resolve) => new AssetListLoader([product], app.assets).load(() => resolve()));
|
|
61
66
|
|
|
@@ -82,10 +87,18 @@ const paint = body[0].material!.clone() as StandardMaterial;
|
|
|
82
87
|
const shade = panels[0].material!.clone() as StandardMaterial;
|
|
83
88
|
body.forEach((mesh) => (mesh.material = paint));
|
|
84
89
|
panels.forEach((mesh) => (mesh.material = shade));
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
90
|
+
|
|
91
|
+
// Each paint button in index.html carries its finish's two colors
|
|
92
|
+
const buttons = document.querySelectorAll<HTMLButtonElement>('#paints button');
|
|
93
|
+
const choose = (button: HTMLButtonElement) => {
|
|
94
|
+
paint.diffuse.fromString(button.dataset.color!);
|
|
95
|
+
shade.diffuse.fromString(button.dataset.shade!);
|
|
96
|
+
paint.update();
|
|
97
|
+
shade.update();
|
|
98
|
+
buttons.forEach((item) => (item.ariaPressed = String(item === button)));
|
|
99
|
+
};
|
|
100
|
+
buttons.forEach((button) => (button.onclick = () => choose(button)));
|
|
101
|
+
choose(buttons[0]);
|
|
89
102
|
|
|
90
103
|
const sky = new Entity('sky');
|
|
91
104
|
sky.addComponent('script');
|
|
@@ -141,15 +154,3 @@ light.addComponent('light', {
|
|
|
141
154
|
});
|
|
142
155
|
light.setEulerAngles(45, -145, 0);
|
|
143
156
|
app.root.addChild(light);
|
|
144
|
-
|
|
145
|
-
document.querySelectorAll<HTMLButtonElement>('#paints button').forEach((button, i, buttons) => {
|
|
146
|
-
button.onclick = () => {
|
|
147
|
-
paint.diffuse.fromString(PAINTS[i].color);
|
|
148
|
-
shade.diffuse.fromString(PAINTS[i].shade);
|
|
149
|
-
paint.update();
|
|
150
|
-
shade.update();
|
|
151
|
-
buttons.forEach((item, j) => (item.ariaPressed = String(i === j)));
|
|
152
|
-
};
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
window.addEventListener('resize', () => app.resizeCanvas());
|
|
@@ -0,0 +1,33 @@
|
|
|
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
|
+
<canvas id="application-canvas"></canvas>
|
|
11
|
+
<div class="hud">
|
|
12
|
+
<section class="panel">
|
|
13
|
+
<h1>Scene Editor</h1>
|
|
14
|
+
<p>Click an object to select it, then drag its gizmo. Drag anywhere else to orbit.</p>
|
|
15
|
+
<div class="controls">
|
|
16
|
+
<button data-mode="translate" aria-pressed="true">Move</button>
|
|
17
|
+
<button data-mode="rotate" aria-pressed="false">Rotate</button>
|
|
18
|
+
<button data-mode="scale" aria-pressed="false">Scale</button>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="controls">
|
|
21
|
+
<button data-add="box">Add box</button>
|
|
22
|
+
<button data-add="sphere">Add sphere</button>
|
|
23
|
+
<button data-add="cone">Add cone</button>
|
|
24
|
+
</div>
|
|
25
|
+
<div class="controls">
|
|
26
|
+
<button id="delete" disabled>Delete</button>
|
|
27
|
+
<button id="reset">Reset</button>
|
|
28
|
+
</div>
|
|
29
|
+
</section>
|
|
30
|
+
</div>
|
|
31
|
+
<script type="module" src="/src/main.ts"></script>
|
|
32
|
+
</body>
|
|
33
|
+
</html>
|
|
@@ -6,52 +6,57 @@ import {
|
|
|
6
6
|
Entity,
|
|
7
7
|
FILLMODE_FILL_WINDOW,
|
|
8
8
|
LightComponentSystem,
|
|
9
|
-
RenderComponentSystem,
|
|
10
9
|
RESOLUTION_AUTO,
|
|
10
|
+
RenderComponentSystem,
|
|
11
11
|
ScriptComponentSystem,
|
|
12
|
-
StandardMaterial,
|
|
13
12
|
createGraphicsDevice
|
|
14
13
|
} from 'playcanvas';
|
|
14
|
+
import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs';
|
|
15
15
|
import { Grid } from 'playcanvas/scripts/esm/grid.mjs';
|
|
16
16
|
|
|
17
17
|
import { SceneEditor } from './scene-editor';
|
|
18
|
+
import type { Mode, Shape } from './scene-editor';
|
|
18
19
|
import './starter.css';
|
|
19
20
|
|
|
20
|
-
document.body.insertAdjacentHTML(
|
|
21
|
-
'beforeend',
|
|
22
|
-
'<div class="hud"><section class="panel"><h1>Scene Editor</h1><p>Select an object, then translate, rotate or scale it.</p><div class="controls"><button data-target="0" aria-pressed="true">Cube</button><button data-target="1">Sphere</button></div><div class="controls"><button data-mode="translate" aria-pressed="true">Move</button><button data-mode="rotate">Rotate</button><button data-mode="scale">Scale</button></div></section></div>'
|
|
23
|
-
);
|
|
24
|
-
|
|
25
21
|
const canvas = document.getElementById('application-canvas') as HTMLCanvasElement;
|
|
22
|
+
|
|
26
23
|
const device = await createGraphicsDevice(canvas);
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
device.maxPixelRatio = Math.min(window.devicePixelRatio, 2);
|
|
25
|
+
|
|
26
|
+
const createOptions = new AppOptions();
|
|
27
|
+
createOptions.graphicsDevice = device;
|
|
28
|
+
createOptions.componentSystems = [
|
|
29
|
+
RenderComponentSystem,
|
|
30
|
+
CameraComponentSystem,
|
|
31
|
+
LightComponentSystem,
|
|
32
|
+
ScriptComponentSystem
|
|
33
|
+
];
|
|
30
34
|
|
|
31
35
|
const app = new AppBase(canvas);
|
|
32
|
-
app.init(
|
|
36
|
+
app.init(createOptions);
|
|
33
37
|
app.start();
|
|
38
|
+
|
|
39
|
+
// Set the canvas to fill the window and automatically change resolution to be the same as the canvas size
|
|
34
40
|
app.setCanvasFillMode(FILLMODE_FILL_WINDOW);
|
|
35
41
|
app.setCanvasResolution(RESOLUTION_AUTO);
|
|
36
42
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
cyan.diffuse = new Color(0.14, 0.68, 0.88);
|
|
44
|
-
cyan.update();
|
|
43
|
+
// Ensure canvas is resized when window changes size
|
|
44
|
+
const resize = () => app.resizeCanvas();
|
|
45
|
+
window.addEventListener('resize', resize);
|
|
46
|
+
app.on('destroy', () => {
|
|
47
|
+
window.removeEventListener('resize', resize);
|
|
48
|
+
});
|
|
45
49
|
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
app.root.addChild(
|
|
50
|
+
const light = new Entity('light');
|
|
51
|
+
light.addComponent('light', { type: 'directional', intensity: 2.5 });
|
|
52
|
+
light.setEulerAngles(45, 30, 0);
|
|
53
|
+
app.root.addChild(light);
|
|
50
54
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
// A weaker light from behind keeps the sides the first can't reach from going black
|
|
56
|
+
const fill = new Entity('fill');
|
|
57
|
+
fill.addComponent('light', { type: 'directional', intensity: 0.8 });
|
|
58
|
+
fill.setEulerAngles(-25, -140, 0);
|
|
59
|
+
app.root.addChild(fill);
|
|
55
60
|
|
|
56
61
|
const grid = new Entity('grid');
|
|
57
62
|
grid.addComponent('script');
|
|
@@ -59,32 +64,36 @@ grid.script!.create(Grid);
|
|
|
59
64
|
grid.setLocalScale(12, 12, 12);
|
|
60
65
|
app.root.addChild(grid);
|
|
61
66
|
|
|
67
|
+
// Create camera entity with orbit controls
|
|
62
68
|
const camera = new Entity('camera');
|
|
63
69
|
camera.addComponent('camera', { clearColor: new Color(0.04, 0.06, 0.09) });
|
|
64
70
|
camera.setPosition(4, 3.2, 5);
|
|
65
71
|
camera.lookAt(0, 0.5, 0);
|
|
72
|
+
camera.addComponent('script');
|
|
73
|
+
camera.script!.create(CameraControls, { properties: { sceneSize: 5 } });
|
|
66
74
|
app.root.addChild(camera);
|
|
67
75
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
shadowBias: 0.2,
|
|
74
|
-
normalOffsetBias: 0.05
|
|
75
|
-
});
|
|
76
|
-
light.setEulerAngles(45, 30, 0);
|
|
77
|
-
app.root.addChild(light);
|
|
76
|
+
// The editor creates the objects under its own entity, from the scene saved in this browser
|
|
77
|
+
const host = new Entity('editor');
|
|
78
|
+
host.addComponent('script');
|
|
79
|
+
const editor = host.script!.create(SceneEditor, { properties: { camera } }) as SceneEditor;
|
|
80
|
+
app.root.addChild(host);
|
|
78
81
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
82
|
+
// The HUD drives the editor, and follows its selection
|
|
83
|
+
const modes = document.querySelectorAll<HTMLButtonElement>('[data-mode]');
|
|
84
|
+
modes.forEach((button) => {
|
|
85
|
+
button.addEventListener('click', () => {
|
|
86
|
+
editor.mode = button.dataset.mode as Mode;
|
|
87
|
+
modes.forEach((other) => (other.ariaPressed = String(other === button)));
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
document.querySelectorAll<HTMLButtonElement>('[data-add]').forEach((button) => {
|
|
91
|
+
button.addEventListener('click', () => editor.add(button.dataset.add as Shape));
|
|
87
92
|
});
|
|
88
|
-
app.root.addChild(editor);
|
|
89
93
|
|
|
90
|
-
|
|
94
|
+
const remove = document.getElementById('delete') as HTMLButtonElement;
|
|
95
|
+
remove.addEventListener('click', () => editor.remove());
|
|
96
|
+
document.getElementById('reset')!.addEventListener('click', () => editor.reset());
|
|
97
|
+
app.on('editor:select', (selected: Entity | null) => {
|
|
98
|
+
remove.disabled = !selected;
|
|
99
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
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
|
+
<canvas id="application-canvas"></canvas>
|
|
11
|
+
<div class="hud">
|
|
12
|
+
<section class="panel">
|
|
13
|
+
<h1>Sprite Game</h1>
|
|
14
|
+
<p>Use A/D or the arrow keys to move and Space to jump.</p>
|
|
15
|
+
</section>
|
|
16
|
+
</div>
|
|
17
|
+
<script type="module" src="/src/main.ts"></script>
|
|
18
|
+
</body>
|
|
19
|
+
</html>
|
|
@@ -16,25 +16,35 @@ import {
|
|
|
16
16
|
import { SpriteGame } from './sprite-game';
|
|
17
17
|
import './starter.css';
|
|
18
18
|
|
|
19
|
-
document.body.insertAdjacentHTML(
|
|
20
|
-
'beforeend',
|
|
21
|
-
'<div class="hud"><section class="panel"><h1>Sprite Game</h1><p>Use A/D or the arrow keys to move and Space to jump.</p></section></div>'
|
|
22
|
-
);
|
|
23
|
-
|
|
24
19
|
const canvas = document.getElementById('application-canvas') as HTMLCanvasElement;
|
|
20
|
+
|
|
25
21
|
const device = await createGraphicsDevice(canvas);
|
|
26
22
|
device.maxPixelRatio = Math.min(window.devicePixelRatio, 2);
|
|
27
23
|
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
const createOptions = new AppOptions();
|
|
25
|
+
createOptions.graphicsDevice = device;
|
|
26
|
+
createOptions.componentSystems = [
|
|
27
|
+
RenderComponentSystem,
|
|
28
|
+
CameraComponentSystem,
|
|
29
|
+
SpriteComponentSystem,
|
|
30
|
+
ScriptComponentSystem
|
|
31
|
+
];
|
|
31
32
|
|
|
32
33
|
const app = new AppBase(canvas);
|
|
33
|
-
app.init(
|
|
34
|
+
app.init(createOptions);
|
|
34
35
|
app.start();
|
|
36
|
+
|
|
37
|
+
// Set the canvas to fill the window and automatically change resolution to be the same as the canvas size
|
|
35
38
|
app.setCanvasFillMode(FILLMODE_FILL_WINDOW);
|
|
36
39
|
app.setCanvasResolution(RESOLUTION_AUTO);
|
|
37
40
|
|
|
41
|
+
// Ensure canvas is resized when window changes size
|
|
42
|
+
const resize = () => app.resizeCanvas();
|
|
43
|
+
window.addEventListener('resize', resize);
|
|
44
|
+
app.on('destroy', () => {
|
|
45
|
+
window.removeEventListener('resize', resize);
|
|
46
|
+
});
|
|
47
|
+
|
|
38
48
|
const camera = new Entity('camera');
|
|
39
49
|
camera.addComponent('camera', {
|
|
40
50
|
projection: 1,
|
|
@@ -68,5 +78,3 @@ game.setPosition(0, -2.15, 0);
|
|
|
68
78
|
game.addComponent('script');
|
|
69
79
|
game.script!.create(SpriteGame);
|
|
70
80
|
app.root.addChild(game);
|
|
71
|
-
|
|
72
|
-
window.addEventListener('resize', () => app.resizeCanvas());
|
|
@@ -0,0 +1,19 @@
|
|
|
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
|
+
<canvas id="application-canvas"></canvas>
|
|
11
|
+
<div class="hud">
|
|
12
|
+
<section class="panel">
|
|
13
|
+
<h1>Third-Person Controller</h1>
|
|
14
|
+
<p>Click the scene, then use WASD to move, mouse to orbit and Space to jump.</p>
|
|
15
|
+
</section>
|
|
16
|
+
</div>
|
|
17
|
+
<script type="module" src="/src/main.ts"></script>
|
|
18
|
+
</body>
|
|
19
|
+
</html>
|
|
@@ -49,16 +49,14 @@ await new Promise<void>((resolve) => {
|
|
|
49
49
|
WasmModule.getInstance('Ammo', () => resolve());
|
|
50
50
|
});
|
|
51
51
|
|
|
52
|
-
document.body.insertAdjacentHTML(
|
|
53
|
-
'beforeend',
|
|
54
|
-
'<div class="hud"><section class="panel"><h1>Third-Person Controller</h1><p>Click the scene, then use WASD to move, mouse to orbit and Space to jump.</p></section></div>'
|
|
55
|
-
);
|
|
56
|
-
|
|
57
52
|
const canvas = document.getElementById('application-canvas') as HTMLCanvasElement;
|
|
53
|
+
|
|
58
54
|
const device = await createGraphicsDevice(canvas);
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
device.maxPixelRatio = Math.min(window.devicePixelRatio, 2);
|
|
56
|
+
|
|
57
|
+
const createOptions = new AppOptions();
|
|
58
|
+
createOptions.graphicsDevice = device;
|
|
59
|
+
createOptions.componentSystems = [
|
|
62
60
|
RenderComponentSystem,
|
|
63
61
|
CameraComponentSystem,
|
|
64
62
|
LightComponentSystem,
|
|
@@ -68,10 +66,19 @@ options.componentSystems = [
|
|
|
68
66
|
];
|
|
69
67
|
|
|
70
68
|
const app = new AppBase(canvas);
|
|
71
|
-
app.init(
|
|
69
|
+
app.init(createOptions);
|
|
72
70
|
app.start();
|
|
71
|
+
|
|
72
|
+
// Set the canvas to fill the window and automatically change resolution to be the same as the canvas size
|
|
73
73
|
app.setCanvasFillMode(FILLMODE_FILL_WINDOW);
|
|
74
74
|
app.setCanvasResolution(RESOLUTION_AUTO);
|
|
75
|
+
|
|
76
|
+
// Ensure canvas is resized when window changes size
|
|
77
|
+
const resize = () => app.resizeCanvas();
|
|
78
|
+
window.addEventListener('resize', resize);
|
|
79
|
+
app.on('destroy', () => {
|
|
80
|
+
window.removeEventListener('resize', resize);
|
|
81
|
+
});
|
|
75
82
|
app.scene.ambientLight = new Color(0.28, 0.32, 0.38);
|
|
76
83
|
|
|
77
84
|
const groundMaterial = new StandardMaterial();
|
|
@@ -216,5 +223,3 @@ light.addComponent('light', {
|
|
|
216
223
|
});
|
|
217
224
|
light.setEulerAngles(45, 30, 0);
|
|
218
225
|
app.root.addChild(light);
|
|
219
|
-
|
|
220
|
-
window.addEventListener('resize', () => app.resizeCanvas());
|
|
@@ -0,0 +1,20 @@
|
|
|
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>VR Starter</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<canvas id="application-canvas"></canvas>
|
|
11
|
+
<div class="hud">
|
|
12
|
+
<section class="panel">
|
|
13
|
+
<h1>VR Starter</h1>
|
|
14
|
+
<p id="xr-status">Checking VR support…</p>
|
|
15
|
+
<div class="controls"><button id="xr-button" disabled>Enter VR</button></div>
|
|
16
|
+
</section>
|
|
17
|
+
</div>
|
|
18
|
+
<script type="module" src="/src/main.ts"></script>
|
|
19
|
+
</body>
|
|
20
|
+
</html>
|