create-playcanvas 0.2.6 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -47
- package/dist/index.mjs +49 -46
- package/package.json +54 -49
- package/templates/_shared/model-viewer/public/playcanvas-cube.glb +0 -0
- package/templates/engine/base/README.md +38 -0
- package/templates/engine/base/eslint.config.mjs +3 -0
- package/templates/engine/base/package.json +30 -0
- package/templates/engine/base/prettier.config.mjs +1 -0
- package/templates/engine/base/src/vite-env.d.ts +19 -0
- package/templates/engine/base/tsconfig.json +25 -0
- package/templates/engine/interactive-sphere/index.html +13 -0
- package/templates/engine/interactive-sphere/src/App.ts +180 -0
- package/templates/{vanilla-ts → engine/interactive-sphere}/src/main.ts +8 -8
- package/templates/engine/interactive-sphere/src/style.css +107 -0
- package/templates/engine/interactive-sphere/src/utils.ts +16 -0
- package/templates/engine/model-viewer/index.html +13 -0
- package/templates/engine/model-viewer/src/main.ts +81 -0
- package/templates/engine/model-viewer/src/style.css +8 -0
- package/templates/engine/spinning-cube/index.html +13 -0
- package/templates/engine/spinning-cube/src/main.ts +65 -0
- package/templates/engine/spinning-cube/src/style.css +8 -0
- package/templates/engine/splat-viewer/index.html +13 -0
- package/templates/engine/splat-viewer/src/main.ts +74 -0
- package/templates/engine/splat-viewer/src/style.css +8 -0
- package/templates/index.ts +47 -57
- package/templates/react/base/README.md +38 -0
- package/templates/react/base/eslint.config.mjs +14 -0
- package/templates/react/base/package.json +36 -0
- package/templates/react/base/prettier.config.mjs +1 -0
- package/templates/react/base/src/vite-env.d.ts +19 -0
- package/templates/react/base/tsconfig.json +26 -0
- package/templates/react/base/vite.config.ts +7 -0
- package/templates/react/interactive-sphere/index.html +13 -0
- package/templates/react/interactive-sphere/src/App.css +75 -0
- package/templates/react/interactive-sphere/src/App.tsx +43 -0
- package/templates/react/interactive-sphere/src/Scene.tsx +69 -0
- package/templates/react/interactive-sphere/src/index.css +51 -0
- package/templates/react/interactive-sphere/src/main.tsx +11 -0
- package/templates/react/model-viewer/index.html +13 -0
- package/templates/react/model-viewer/src/App.tsx +43 -0
- package/templates/react/model-viewer/src/index.css +9 -0
- package/templates/react/model-viewer/src/main.tsx +11 -0
- package/templates/react/spinning-cube/index.html +13 -0
- package/templates/react/spinning-cube/src/App.tsx +36 -0
- package/templates/react/spinning-cube/src/index.css +9 -0
- package/templates/react/spinning-cube/src/main.tsx +11 -0
- package/templates/react/splat-viewer/index.html +13 -0
- package/templates/react/splat-viewer/src/App.tsx +39 -0
- package/templates/react/splat-viewer/src/index.css +9 -0
- package/templates/react/splat-viewer/src/main.tsx +11 -0
- package/templates/web-components/base/README.md +66 -0
- package/templates/web-components/base/_gitignore +24 -0
- package/templates/web-components/base/eslint.config.mjs +3 -0
- package/templates/web-components/base/package.json +31 -0
- package/templates/web-components/base/prettier.config.mjs +1 -0
- package/templates/web-components/base/src/assets/playcanvas.png +0 -0
- package/templates/web-components/base/src/vite-env.d.ts +19 -0
- package/templates/web-components/base/tsconfig.json +25 -0
- package/templates/web-components/interactive-sphere/index.html +53 -0
- package/templates/web-components/interactive-sphere/src/assets/typescript.svg +1 -0
- package/templates/web-components/interactive-sphere/src/main.ts +76 -0
- package/templates/web-components/interactive-sphere/src/style.css +111 -0
- package/templates/web-components/model-viewer/index.html +34 -0
- package/templates/web-components/model-viewer/src/main.ts +26 -0
- package/templates/web-components/model-viewer/src/style.css +8 -0
- package/templates/web-components/spinning-cube/index.html +29 -0
- package/templates/web-components/spinning-cube/src/main.ts +20 -0
- package/templates/web-components/spinning-cube/src/style.css +8 -0
- package/templates/web-components/splat-viewer/index.html +31 -0
- package/templates/web-components/splat-viewer/src/main.ts +14 -0
- package/templates/web-components/splat-viewer/src/style.css +8 -0
- package/index.js +0 -3
- package/templates/react-ts/README.md +0 -82
- package/templates/react-ts/index.html +0 -13
- package/templates/react-ts/package.json +0 -29
- package/templates/react-ts/scripts/ensure-node-version.cjs +0 -12
- package/templates/react-ts/src/App.css +0 -87
- package/templates/react-ts/src/App.tsx +0 -46
- package/templates/react-ts/src/Scene.tsx +0 -70
- package/templates/react-ts/src/index.css +0 -73
- package/templates/react-ts/src/main.tsx +0 -10
- package/templates/react-ts/src/vite-env.d.ts +0 -1
- package/templates/react-ts/tsconfig.app.json +0 -27
- package/templates/react-ts/tsconfig.json +0 -7
- package/templates/react-ts/tsconfig.node.json +0 -25
- package/templates/react-ts/vite.config.ts +0 -7
- package/templates/vanilla-ts/README.md +0 -114
- package/templates/vanilla-ts/index.html +0 -13
- package/templates/vanilla-ts/package.json +0 -23
- package/templates/vanilla-ts/public/environment-map.png +0 -0
- package/templates/vanilla-ts/scripts/ensure-node-version.cjs +0 -12
- package/templates/vanilla-ts/src/App.ts +0 -182
- package/templates/vanilla-ts/src/style.css +0 -140
- package/templates/vanilla-ts/src/utils.ts +0 -16
- package/templates/vanilla-ts/src/vite-env.d.ts +0 -1
- package/templates/vanilla-ts/tsconfig.json +0 -25
- /package/templates/{react-ts → _shared/interactive-sphere}/public/environment-map.png +0 -0
- /package/templates/{react-ts → engine/base}/_gitignore +0 -0
- /package/templates/{react-ts → engine/base}/src/assets/playcanvas.png +0 -0
- /package/templates/{vanilla-ts → engine/interactive-sphere}/src/assets/typescript.svg +0 -0
- /package/templates/{vanilla-ts → react/base}/_gitignore +0 -0
- /package/templates/{vanilla-ts → react/base}/src/assets/playcanvas.png +0 -0
- /package/templates/{react-ts → react/interactive-sphere}/src/assets/react.svg +0 -0
|
@@ -0,0 +1,31 @@
|
|
|
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>PlayCanvas + Web Components</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<!-- Antialiasing is disabled - splat rendering is fragment bound, so MSAA costs a lot and adds little -->
|
|
11
|
+
<pc-app antialias="false" high-resolution="false">
|
|
12
|
+
<!-- Hosted so the template stays small. Capture or edit your own splat at
|
|
13
|
+
https://superspl.at, then drop the .sog or .ply in public/ and point this at it instead -->
|
|
14
|
+
<pc-asset id="splat" src="https://developer.playcanvas.com/assets/toy-cat.sog"></pc-asset>
|
|
15
|
+
|
|
16
|
+
<pc-scene>
|
|
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>
|
|
20
|
+
</pc-entity>
|
|
21
|
+
|
|
22
|
+
<!-- Splats are captured in their own space, so this one needs offsetting and flipping upright -->
|
|
23
|
+
<pc-entity name="toy cat" position="0 -0.7 0" rotation="0 0 180">
|
|
24
|
+
<pc-gsplat asset="splat"></pc-gsplat>
|
|
25
|
+
</pc-entity>
|
|
26
|
+
</pc-scene>
|
|
27
|
+
</pc-app>
|
|
28
|
+
|
|
29
|
+
<script type="module" src="/src/main.ts"></script>
|
|
30
|
+
</body>
|
|
31
|
+
</html>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { whenReady } from '@playcanvas/web-components';
|
|
2
|
+
import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs';
|
|
3
|
+
|
|
4
|
+
import './style.css';
|
|
5
|
+
|
|
6
|
+
// The camera is awaited as <pc-camera> rather than the <pc-entity> holding it - an entity becomes
|
|
7
|
+
// ready before its component children do, and CameraControls needs the camera component to exist
|
|
8
|
+
const cameraComponent = await whenReady('pc-camera');
|
|
9
|
+
|
|
10
|
+
// Engine scripts are resolved by the bundler, so they are attached through the entity rather than
|
|
11
|
+
// with <pc-script name="...">, which only resolves scripts fetched at runtime by <pc-asset>
|
|
12
|
+
const camera = cameraComponent.closestEntity;
|
|
13
|
+
camera?.entity?.addComponent('script');
|
|
14
|
+
camera?.entity?.script?.create(CameraControls);
|
package/index.js
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
# @playcanvas/react + TypeScript Starter
|
|
2
|
-
|
|
3
|
-
A modern, batteries-included starter for building PlayCanvas experiences with React and TypeScript, HMR and ESLint.
|
|
4
|
-
|
|
5
|
-
## Prerequisites
|
|
6
|
-
|
|
7
|
-
* **Node.js ≥ 20.19.0** (or ≥ 22.12.0). Use [nvm](https://github.com/nvm-sh/nvm) to install/switch:
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
nvm install 22 # or 20.19+
|
|
11
|
-
nvm use 22
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
## Getting Started
|
|
17
|
-
|
|
18
|
-
Scaffold and install dependencies:
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
npm create playcanvas@latest -t react-ts
|
|
22
|
-
cd playcanvas-project
|
|
23
|
-
npm install
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
Start the dev server with hot-module reload:
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
npm run dev
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
Open <http://localhost:5173> to view the app. Any file changes trigger instant reloads.
|
|
33
|
-
|
|
34
|
-
---
|
|
35
|
-
|
|
36
|
-
## Scripts
|
|
37
|
-
|
|
38
|
-
| Command | Description |
|
|
39
|
-
|--------------------|--------------------------------------|
|
|
40
|
-
| `npm run dev` | Start Vite dev server with HMR |
|
|
41
|
-
| `npm run build` | Type-check & bundle for production |
|
|
42
|
-
| `npm run preview` | Preview the production build locally |
|
|
43
|
-
| `npm run lint` | Run ESLint over the codebase |
|
|
44
|
-
|
|
45
|
-
---
|
|
46
|
-
|
|
47
|
-
## Project Structure
|
|
48
|
-
|
|
49
|
-
```
|
|
50
|
-
.
|
|
51
|
-
├── public/ # Static assets copied as-is
|
|
52
|
-
├── src/
|
|
53
|
-
│ ├── Scene.tsx # React wrapper around a PlayCanvas application
|
|
54
|
-
│ ├── App.tsx # Entry component
|
|
55
|
-
│ └── main.tsx # Vite/React bootstrap
|
|
56
|
-
├── vite.config.ts # Vite + React plugin config
|
|
57
|
-
└── ...
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
## Linting & Formatting
|
|
61
|
-
|
|
62
|
-
ESLint is pre-configured with TypeScript, React hooks, React Refresh, and global browser/node globals. Adjust `eslint.config.js` as your codebase grows.
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
## Deployment
|
|
67
|
-
|
|
68
|
-
Run `npm run build` to generate a static production bundle in `dist/`. Deploy the contents of that folder to any static hosting provider (Netlify, Vercel, GitHub Pages, Cloudflare Pages, etc.).
|
|
69
|
-
|
|
70
|
-
---
|
|
71
|
-
|
|
72
|
-
## Further Reading
|
|
73
|
-
|
|
74
|
-
* [PlayCanvas Engine Docs](https://developer.playcanvas.com)
|
|
75
|
-
* [PlayCanvas React Docs](https://developer.playcanvas.com/user-manual/react/)
|
|
76
|
-
* [React Docs](https://react.dev/)
|
|
77
|
-
* [Vite Docs](https://vitejs.dev/)
|
|
78
|
-
* [TypeScript Handbook](https://www.typescriptlang.org/docs/)
|
|
79
|
-
|
|
80
|
-
---
|
|
81
|
-
|
|
82
|
-
Made with ❤️. PRs and issues welcome!
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
-
<title>PlayCanvas + React + TS</title>
|
|
8
|
-
</head>
|
|
9
|
-
<body>
|
|
10
|
-
<div id="root"></div>
|
|
11
|
-
<script type="module" src="/src/main.tsx"></script>
|
|
12
|
-
</body>
|
|
13
|
-
</html>
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "playcanvas-project",
|
|
3
|
-
"private": true,
|
|
4
|
-
"version": "0.0.0",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"engines": {
|
|
7
|
-
"node": "^20.19.0 || >=22.12.0"
|
|
8
|
-
},
|
|
9
|
-
"scripts": {
|
|
10
|
-
"predev": "node ./scripts/ensure-node-version.cjs",
|
|
11
|
-
"dev": "vite",
|
|
12
|
-
"build": "tsc -b && vite build",
|
|
13
|
-
"preview": "vite preview"
|
|
14
|
-
},
|
|
15
|
-
"dependencies": {
|
|
16
|
-
"@playcanvas/react": "^0.11.3",
|
|
17
|
-
"playcanvas": "^2.17.2",
|
|
18
|
-
"react": "^19.2.5",
|
|
19
|
-
"react-dom": "^19.2.5"
|
|
20
|
-
},
|
|
21
|
-
"devDependencies": {
|
|
22
|
-
"@types/react": "^19.2.14",
|
|
23
|
-
"@types/react-dom": "^19.2.3",
|
|
24
|
-
"@vitejs/plugin-react": "^6.0.1",
|
|
25
|
-
"semver": "^7.7.4",
|
|
26
|
-
"typescript": "~6.0.2",
|
|
27
|
-
"vite": "^8.0.8"
|
|
28
|
-
}
|
|
29
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
const semver = require('semver');
|
|
2
|
-
const pkg = require('../package.json');
|
|
3
|
-
|
|
4
|
-
const requiredVersion = pkg.engines.node;
|
|
5
|
-
const currentVersion = process.version;
|
|
6
|
-
|
|
7
|
-
if (!semver.satisfies(currentVersion, requiredVersion)) {
|
|
8
|
-
console.error(`\n❌ Unsupported Node.js version: ${currentVersion}`);
|
|
9
|
-
console.error(`Required: ${requiredVersion}`);
|
|
10
|
-
console.error('Please upgrade your Node.js to continue.\n');
|
|
11
|
-
process.exit(1);
|
|
12
|
-
}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
#root {
|
|
2
|
-
display: flex;
|
|
3
|
-
flex-direction: column;
|
|
4
|
-
height: 100vh;
|
|
5
|
-
width: 100vw;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
header {
|
|
9
|
-
display: flex;
|
|
10
|
-
flex-direction: row;
|
|
11
|
-
align-items: center;
|
|
12
|
-
padding: 2rem;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
.absolute {
|
|
16
|
-
position: absolute;
|
|
17
|
-
top: 0;
|
|
18
|
-
left: 0;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
.full-bleed {
|
|
22
|
-
width: 100vw;
|
|
23
|
-
height: 100vh;
|
|
24
|
-
overflow: hidden;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
.logo {
|
|
28
|
-
height: 2em;
|
|
29
|
-
padding: .5em;
|
|
30
|
-
will-change: filter;
|
|
31
|
-
transition: filter 300ms;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
.playcanvas-logo {
|
|
35
|
-
border-radius: 100%;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.logo:hover {
|
|
39
|
-
filter: drop-shadow(0 0 2em #646cffaa);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
.logo.react:hover {
|
|
43
|
-
filter: drop-shadow(0 0 2em #61dafbaa);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
.card {
|
|
47
|
-
padding: 2em;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
.read-the-docs {
|
|
51
|
-
color: #888;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
.container{
|
|
55
|
-
position: absolute;
|
|
56
|
-
top: 0;
|
|
57
|
-
left: 0;
|
|
58
|
-
display: flex;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
.overlay {
|
|
62
|
-
margin: 0 auto;
|
|
63
|
-
text-align: center;
|
|
64
|
-
display: flex;
|
|
65
|
-
flex-direction: column;
|
|
66
|
-
align-items: center;
|
|
67
|
-
justify-content: stretch;
|
|
68
|
-
width: 100vw;
|
|
69
|
-
height: 100vh;
|
|
70
|
-
pointer-events: none;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
.overlay a {
|
|
74
|
-
pointer-events: auto;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
.overlay > .grow {
|
|
78
|
-
flex-grow: 1;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
.pill {
|
|
82
|
-
background-color: #000;
|
|
83
|
-
color: #fff;
|
|
84
|
-
padding: 0.5rem 1rem;
|
|
85
|
-
border-radius: 0.5rem;
|
|
86
|
-
}
|
|
87
|
-
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { Application } from "@playcanvas/react";
|
|
2
|
-
import { useState } from 'react'
|
|
3
|
-
import reactLogo from './assets/react.svg'
|
|
4
|
-
import playcanvasLogo from './assets/playcanvas.png'
|
|
5
|
-
import './App.css'
|
|
6
|
-
import Scene from "./Scene";
|
|
7
|
-
|
|
8
|
-
function App() {
|
|
9
|
-
const [count, setCount] = useState(0)
|
|
10
|
-
|
|
11
|
-
return (
|
|
12
|
-
<>
|
|
13
|
-
<div className="full-bleed">
|
|
14
|
-
<Application className="playcanvas-app">
|
|
15
|
-
<Scene onClick={() => setCount((count) => count + 1)}/>
|
|
16
|
-
</Application>
|
|
17
|
-
</div>
|
|
18
|
-
<div className="absolute overlay">
|
|
19
|
-
<div className="grow">
|
|
20
|
-
<header>
|
|
21
|
-
<h1>PlayCanvas + React</h1>
|
|
22
|
-
<a href="https://developer.playcanvas.com/user-manual/react/" target="_blank">
|
|
23
|
-
<img src={playcanvasLogo} className="playcanvas-logo logo" alt="PlayCanvas logo" />
|
|
24
|
-
</a>
|
|
25
|
-
<a href="https://react.dev" target="_blank">
|
|
26
|
-
<img src={reactLogo} className="logo react" alt="React logo" />
|
|
27
|
-
</a>
|
|
28
|
-
</header>
|
|
29
|
-
</div>
|
|
30
|
-
<div>
|
|
31
|
-
<span className="pill">
|
|
32
|
-
Click Count: {count}
|
|
33
|
-
</span>
|
|
34
|
-
<p>
|
|
35
|
-
Edit <code>src/Scene.tsx</code> and save to test HMR
|
|
36
|
-
</p>
|
|
37
|
-
</div>
|
|
38
|
-
<p className="read-the-docs">
|
|
39
|
-
Click on the PlayCanvas and React logos to learn more
|
|
40
|
-
</p>
|
|
41
|
-
</div>
|
|
42
|
-
</>
|
|
43
|
-
)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export default App
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
// @ts-expect-error - PlayCanvas ESM scripts don't have type declarations
|
|
2
|
-
import { CameraControls } from "playcanvas/scripts/esm/camera-controls.mjs";
|
|
3
|
-
// @ts-expect-error - PlayCanvas ESM scripts don't have type declarations
|
|
4
|
-
import { Grid } from "playcanvas/scripts/esm/grid.mjs";
|
|
5
|
-
import { useEffect, useState } from "react";
|
|
6
|
-
import { Entity } from "@playcanvas/react";
|
|
7
|
-
import { useEnvAtlas, useMaterial } from "@playcanvas/react/hooks";
|
|
8
|
-
import { Camera, Environment, Render, Script } from "@playcanvas/react/components";
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* The Scene renders a sphere with a grid and camera controls
|
|
12
|
-
*/
|
|
13
|
-
function Scene({ onClick }: SceneProps) {
|
|
14
|
-
|
|
15
|
-
// Track the hover state and set the color based on the hover state
|
|
16
|
-
const [hovering, setHovering] = useState(false);
|
|
17
|
-
|
|
18
|
-
// Set a material color based on the hover state
|
|
19
|
-
const diffuse = hovering ? 'orange' : 'lightgrey';
|
|
20
|
-
|
|
21
|
-
// Create a material for the sphere
|
|
22
|
-
const material = useMaterial({ diffuse });
|
|
23
|
-
|
|
24
|
-
// Load the environment map
|
|
25
|
-
const { asset: envMap } = useEnvAtlas('/environment-map.png');
|
|
26
|
-
|
|
27
|
-
// change the mouse cursor based on the hover state
|
|
28
|
-
useEffect(() => {
|
|
29
|
-
document.body.style.cursor = hovering ? 'pointer' : 'default';
|
|
30
|
-
}, [hovering]);
|
|
31
|
-
|
|
32
|
-
// Don't render until the environment map is loaded
|
|
33
|
-
if (!envMap) return null;
|
|
34
|
-
|
|
35
|
-
return (
|
|
36
|
-
<>
|
|
37
|
-
{/* Render some environment lighting using the environment map */}
|
|
38
|
-
<Environment envAtlas={envMap} showSkybox={false} />
|
|
39
|
-
|
|
40
|
-
{/* Render a background grid */}
|
|
41
|
-
<Entity scale={[1000, 1000, 1000]}>
|
|
42
|
-
<Script script={Grid} />
|
|
43
|
-
</Entity>
|
|
44
|
-
|
|
45
|
-
{/* Create a camera entity with camera controls */}
|
|
46
|
-
<Entity name='camera' position={[4, 1, 4]}>
|
|
47
|
-
<Camera clearColor='#171717' />
|
|
48
|
-
<Script script={CameraControls} />
|
|
49
|
-
</Entity>
|
|
50
|
-
|
|
51
|
-
{/* Create and position entity with pointer events */}
|
|
52
|
-
<Entity
|
|
53
|
-
position={[0, 0.5, 0]}
|
|
54
|
-
onClick={onClick}
|
|
55
|
-
onPointerOver={() => setHovering(true)}
|
|
56
|
-
onPointerOut={() => setHovering(false)}
|
|
57
|
-
>
|
|
58
|
-
|
|
59
|
-
{/* Render a sphere with the material */}
|
|
60
|
-
<Render type="sphere" material={material} />
|
|
61
|
-
</Entity>
|
|
62
|
-
</>
|
|
63
|
-
)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
type SceneProps = {
|
|
67
|
-
onClick: () => void;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export default Scene;
|
|
@@ -1,73 +0,0 @@
|
|
|
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
|
-
a {
|
|
17
|
-
font-weight: 500;
|
|
18
|
-
color: #646cff;
|
|
19
|
-
text-decoration: inherit;
|
|
20
|
-
}
|
|
21
|
-
a:hover {
|
|
22
|
-
color: #535bf2;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
a > img {
|
|
26
|
-
vertical-align: middle;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
body {
|
|
30
|
-
margin: 0;
|
|
31
|
-
display: flex;
|
|
32
|
-
place-items: center;
|
|
33
|
-
min-width: 320px;
|
|
34
|
-
min-height: 100vh;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
h1 {
|
|
38
|
-
font-size: 2.4em;
|
|
39
|
-
line-height: 1.1;
|
|
40
|
-
opacity: 0.85;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
button {
|
|
44
|
-
border-radius: 8px;
|
|
45
|
-
border: 1px solid transparent;
|
|
46
|
-
padding: 0.6em 1.2em;
|
|
47
|
-
font-size: 1em;
|
|
48
|
-
font-weight: 500;
|
|
49
|
-
font-family: inherit;
|
|
50
|
-
background-color: #1a1a1a;
|
|
51
|
-
cursor: pointer;
|
|
52
|
-
transition: border-color 0.25s;
|
|
53
|
-
}
|
|
54
|
-
button:hover {
|
|
55
|
-
border-color: #646cff;
|
|
56
|
-
}
|
|
57
|
-
button:focus,
|
|
58
|
-
button:focus-visible {
|
|
59
|
-
outline: 4px auto -webkit-focus-ring-color;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
@media (prefers-color-scheme: light) {
|
|
63
|
-
:root {
|
|
64
|
-
color: #213547;
|
|
65
|
-
background-color: #ffffff;
|
|
66
|
-
}
|
|
67
|
-
a:hover {
|
|
68
|
-
color: #747bff;
|
|
69
|
-
}
|
|
70
|
-
button {
|
|
71
|
-
background-color: #f9f9f9;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
/// <reference types="vite/client" />
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
4
|
-
"target": "ES2022",
|
|
5
|
-
"useDefineForClassFields": true,
|
|
6
|
-
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
7
|
-
"module": "ESNext",
|
|
8
|
-
"skipLibCheck": true,
|
|
9
|
-
|
|
10
|
-
/* Bundler mode */
|
|
11
|
-
"moduleResolution": "bundler",
|
|
12
|
-
"allowImportingTsExtensions": true,
|
|
13
|
-
"verbatimModuleSyntax": true,
|
|
14
|
-
"moduleDetection": "force",
|
|
15
|
-
"noEmit": true,
|
|
16
|
-
"jsx": "react-jsx",
|
|
17
|
-
|
|
18
|
-
/* Linting */
|
|
19
|
-
"strict": true,
|
|
20
|
-
"noUnusedLocals": true,
|
|
21
|
-
"noUnusedParameters": true,
|
|
22
|
-
"erasableSyntaxOnly": true,
|
|
23
|
-
"noFallthroughCasesInSwitch": true,
|
|
24
|
-
"noUncheckedSideEffectImports": true
|
|
25
|
-
},
|
|
26
|
-
"include": ["src"]
|
|
27
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
|
4
|
-
"target": "ES2023",
|
|
5
|
-
"lib": ["ES2023"],
|
|
6
|
-
"module": "ESNext",
|
|
7
|
-
"skipLibCheck": true,
|
|
8
|
-
|
|
9
|
-
/* Bundler mode */
|
|
10
|
-
"moduleResolution": "bundler",
|
|
11
|
-
"allowImportingTsExtensions": true,
|
|
12
|
-
"verbatimModuleSyntax": true,
|
|
13
|
-
"moduleDetection": "force",
|
|
14
|
-
"noEmit": true,
|
|
15
|
-
|
|
16
|
-
/* Linting */
|
|
17
|
-
"strict": true,
|
|
18
|
-
"noUnusedLocals": true,
|
|
19
|
-
"noUnusedParameters": true,
|
|
20
|
-
"erasableSyntaxOnly": true,
|
|
21
|
-
"noFallthroughCasesInSwitch": true,
|
|
22
|
-
"noUncheckedSideEffectImports": true
|
|
23
|
-
},
|
|
24
|
-
"include": ["vite.config.ts"]
|
|
25
|
-
}
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
# PlayCanvas + Vite Starter
|
|
2
|
-
|
|
3
|
-
A modern, batteries-included starter for building WebGL/PlayCanvas experiences with TypeScript.
|
|
4
|
-
|
|
5
|
-
* **PlayCanvas** `^2.8.2` – high-performance WebGL engine
|
|
6
|
-
* **Vite** `^7` – ultra-fast dev server & bundler with HMR
|
|
7
|
-
* **TypeScript** `~5.8` – static typing out-of-the-box
|
|
8
|
-
* **ESLint** `^9` – linting with recommended TypeScript rules
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## Prerequisites
|
|
13
|
-
|
|
14
|
-
* **Node.js ≥ 20.19.0** (or ≥ 22.12.0). Use [nvm](https://github.com/nvm-sh/nvm) to install/switch:
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
nvm install 22 # or 20.19+
|
|
18
|
-
nvm use 22
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## Getting Started
|
|
24
|
-
|
|
25
|
-
Clone the repo and install dependencies:
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
git clone <your-repo-url> playcanvas-project
|
|
29
|
-
cd playcanvas-project
|
|
30
|
-
npm install
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Start the dev server with hot-module reload:
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
npm run dev
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
Open <http://localhost:5173> to view the app. Any file changes trigger instant reloads.
|
|
40
|
-
|
|
41
|
-
---
|
|
42
|
-
|
|
43
|
-
## Scripts
|
|
44
|
-
|
|
45
|
-
| Command | Description |
|
|
46
|
-
|--------------------|--------------------------------------|
|
|
47
|
-
| `npm run dev` | Start Vite dev server with HMR |
|
|
48
|
-
| `npm run build` | Type-check & bundle for production |
|
|
49
|
-
| `npm run preview` | Preview the production build locally |
|
|
50
|
-
| `npm run lint` | Run ESLint over the codebase |
|
|
51
|
-
|
|
52
|
-
---
|
|
53
|
-
|
|
54
|
-
## Project Structure
|
|
55
|
-
|
|
56
|
-
```
|
|
57
|
-
.
|
|
58
|
-
├── public/ # Static assets copied as-is
|
|
59
|
-
├── src/
|
|
60
|
-
│ ├── components/
|
|
61
|
-
│ │ └── PlayCanvasCanvas.tsx # React wrapper around a PlayCanvas application
|
|
62
|
-
│ ├── App.tsx # Entry component
|
|
63
|
-
│ └── main.tsx # Vite/React bootstrap
|
|
64
|
-
├── vite.config.ts # Vite + React plugin config
|
|
65
|
-
└── ...
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
### `PlayCanvasCanvas.tsx` (concept)
|
|
69
|
-
|
|
70
|
-
```tsx
|
|
71
|
-
import { useEffect, useRef } from 'react'
|
|
72
|
-
import * as pc from 'playcanvas'
|
|
73
|
-
|
|
74
|
-
export default function PlayCanvasCanvas() {
|
|
75
|
-
const canvasRef = useRef<HTMLCanvasElement>(null)
|
|
76
|
-
|
|
77
|
-
useEffect(() => {
|
|
78
|
-
const canvas = canvasRef.current!
|
|
79
|
-
const app = new pc.Application(canvas, {})
|
|
80
|
-
app.start()
|
|
81
|
-
// demo scene setup here…
|
|
82
|
-
|
|
83
|
-
return () => app.destroy() // cleanup on unmount
|
|
84
|
-
}, [])
|
|
85
|
-
|
|
86
|
-
return <canvas ref={canvasRef} style={{ width: '100%', height: '100%' }} />
|
|
87
|
-
}
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
Use the component anywhere in your React tree to embed a PlayCanvas scene.
|
|
91
|
-
|
|
92
|
-
---
|
|
93
|
-
|
|
94
|
-
## Linting & Formatting
|
|
95
|
-
|
|
96
|
-
ESLint is pre-configured with TypeScript, React hooks, React Refresh, and global browser/node globals. Adjust `eslint.config.js` as your codebase grows.
|
|
97
|
-
|
|
98
|
-
---
|
|
99
|
-
|
|
100
|
-
## Deployment
|
|
101
|
-
|
|
102
|
-
Run `npm run build` to generate a static production bundle in `dist/`. Deploy the contents of that folder to any static hosting provider (Netlify, Vercel, GitHub Pages, Cloudflare Pages, etc.).
|
|
103
|
-
|
|
104
|
-
---
|
|
105
|
-
|
|
106
|
-
## Further Reading
|
|
107
|
-
|
|
108
|
-
* [PlayCanvas Engine Docs](https://developer.playcanvas.com/en/api/)
|
|
109
|
-
* [Vite Docs](https://vitejs.dev/)
|
|
110
|
-
* [TypeScript Handbook](https://www.typescriptlang.org/docs/)
|
|
111
|
-
|
|
112
|
-
---
|
|
113
|
-
|
|
114
|
-
Made with ❤️ and ☕ by **Your Name**. PRs and issues welcome!
|