create-playcanvas 0.0.2-beta.2 → 0.0.2-beta.4
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/dist/index.mjs +1 -1
- package/package.json +1 -1
- package/templates/index.ts +47 -0
- package/templates/react-ts/README.md +82 -0
- package/templates/react-ts/_gitignore +24 -0
- package/templates/react-ts/eslint.config.js +23 -0
- package/templates/react-ts/index.html +13 -0
- package/templates/react-ts/package.json +36 -0
- package/templates/react-ts/public/environment-map.png +0 -0
- package/templates/react-ts/scripts/ensure-node-version.cjs +12 -0
- package/templates/react-ts/src/App.css +83 -0
- package/templates/react-ts/src/App.tsx +46 -0
- package/templates/react-ts/src/Scene.tsx +70 -0
- package/templates/react-ts/src/assets/playcanvas.png +0 -0
- package/templates/react-ts/src/assets/react.svg +1 -0
- package/templates/react-ts/src/index.css +73 -0
- package/templates/react-ts/src/main.tsx +10 -0
- package/templates/react-ts/src/vite-env.d.ts +1 -0
- package/templates/react-ts/tsconfig.app.json +27 -0
- package/templates/react-ts/tsconfig.json +7 -0
- package/templates/react-ts/tsconfig.node.json +25 -0
- package/templates/react-ts/vite.config.ts +7 -0
- package/templates/vanilla-ts/.env +0 -0
package/dist/index.mjs
CHANGED
|
@@ -41,7 +41,7 @@ ${C.gray(y)} ${e}
|
|
|
41
41
|
yarn`,h+=`
|
|
42
42
|
yarn dev`;break;default:h+=`
|
|
43
43
|
${F} install`,h+=`
|
|
44
|
-
${F} run dev`;break}au(h)}const{blue:Bu,cyan:mu}=C,ED=[{name:"react",display:"
|
|
44
|
+
${F} run dev`;break}au(h)}const{blue:Bu,cyan:mu}=C,ED=[{name:"react",display:"React",description:"with @playcanvas/react",color:mu,variants:[{name:"react-ts",display:"TypeScript",color:Bu}]}],gu=ED.flatMap(e=>e.variants.map(u=>u.name));async function pu({argTargetDir:e,defaultTargetDir:u,cancel:t}){let r=e?z(String(e)):void 0;if(!r){const i=await CD({message:"Project name:",defaultValue:u,placeholder:u});j(i)&&t(),r=z(i)}return r}async function fu({targetDir:e,argOverwrite:u,cancel:t}){if(m.existsSync(e)&&!Cu(e)){const r=u?"yes":await V({message:(e==="."?"Current directory":`Target directory "${e}"`)+" is not empty. Please choose how to proceed:",options:[{label:"Cancel operation",value:"no"},{label:"Remove existing files and continue",value:"yes"},{label:"Ignore files and continue",value:"ignore"}]});if(j(r))return t();switch(r){case"yes":ou(e);break;case"no":t();return}}}function lD(e){return/^(?:@[a-z\d\-*~][a-z\d\-*._~]*\/)?[a-z\d\-~][a-z\d\-._~]*$/.test(e)}function cD(e){return e.trim().toLowerCase().replace(/\s+/g,"-").replace(/^[._]/,"").replace(/[^a-z\d\-~]+/g,"-")}async function bu({targetDir:e,cancel:u}){let t=b.basename(b.resolve(e));if(!lD(t)){const r=await CD({message:"Package name:",defaultValue:cD(t),placeholder:cD(t),validate(i){if(!lD(i))return"Invalid package.json name"}});if(j(r))return u();t=r}return t}async function du({argTemplate:e,FRAMEWORKS:u,TEMPLATES:t,pkgInfo:r,getFullCustomCommand:i,cancel:s}){let D=e,n=!1;if(e&&!t.includes(e)&&(D=void 0,n=!0),!D){const F=await V({message:n?`"${e}" isn't a valid template. Please choose from below: `:"Select a framework:",options:u.map(a=>{const o=a.color;return{label:o(a.display||a.name),value:a,hint:a.description}})});if(j(F))return s();await V({message:"Select a variant:",options:F.variants.map(a=>{const o=a.color,E=a.customCommand?i(a.customCommand,r).replace(/ TARGET_DIR$/,""):void 0;return{label:o(a.display||a.name),value:a.name,hint:E}})}),D=F.variants[0].name}return D}const w=dD(process.argv.slice(2),{alias:{h:"help",t:"template",d:"delete"},boolean:["help","overwrite"],string:["template"]}),Au=process.cwd(),vu=`Usage: npm create playcanvas@latest [OPTION]...
|
|
45
45
|
|
|
46
46
|
Create a new PlayCanvas project in JavaScript or TypeScript.
|
|
47
47
|
With no arguments, start the CLI in interactive mode.
|
package/package.json
CHANGED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import colors, { yellow } from 'picocolors'
|
|
2
|
+
const { blue, cyan } = colors
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* You can add new frameworks here.
|
|
6
|
+
*
|
|
7
|
+
* The framework name is used to create the directory name.
|
|
8
|
+
* The framework display name is used to display the framework name in the CLI.
|
|
9
|
+
* The framework description is used to display the framework description in the CLI.
|
|
10
|
+
* The framework color is used to display the framework color in the CLI.
|
|
11
|
+
* The framework variants are used to display the framework variants in the CLI.
|
|
12
|
+
*
|
|
13
|
+
*/
|
|
14
|
+
export const FRAMEWORKS: Framework[] = [
|
|
15
|
+
{
|
|
16
|
+
name: 'react',
|
|
17
|
+
display: 'React',
|
|
18
|
+
description: 'with @playcanvas/react',
|
|
19
|
+
color: cyan,
|
|
20
|
+
variants: [
|
|
21
|
+
{
|
|
22
|
+
name: 'react-ts',
|
|
23
|
+
display: 'TypeScript',
|
|
24
|
+
color: blue,
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
export const TEMPLATES = FRAMEWORKS.flatMap((f) => f.variants.map((v) => v.name))
|
|
31
|
+
|
|
32
|
+
export type ColorFunc = (str: string | number) => string
|
|
33
|
+
|
|
34
|
+
export type FrameworkVariant = {
|
|
35
|
+
name: string
|
|
36
|
+
display: string
|
|
37
|
+
color: ColorFunc
|
|
38
|
+
customCommand?: string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type Framework = {
|
|
42
|
+
name: string
|
|
43
|
+
display: string
|
|
44
|
+
color: ColorFunc
|
|
45
|
+
description?: string
|
|
46
|
+
variants: FrameworkVariant[]
|
|
47
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
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://playcanvas-react.vercel.app)
|
|
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!
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Logs
|
|
2
|
+
logs
|
|
3
|
+
*.log
|
|
4
|
+
npm-debug.log*
|
|
5
|
+
yarn-debug.log*
|
|
6
|
+
yarn-error.log*
|
|
7
|
+
pnpm-debug.log*
|
|
8
|
+
lerna-debug.log*
|
|
9
|
+
|
|
10
|
+
node_modules
|
|
11
|
+
dist
|
|
12
|
+
dist-ssr
|
|
13
|
+
*.local
|
|
14
|
+
|
|
15
|
+
# Editor directories and files
|
|
16
|
+
.vscode/*
|
|
17
|
+
!.vscode/extensions.json
|
|
18
|
+
.idea
|
|
19
|
+
.DS_Store
|
|
20
|
+
*.suo
|
|
21
|
+
*.ntvs*
|
|
22
|
+
*.njsproj
|
|
23
|
+
*.sln
|
|
24
|
+
*.sw?
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import js from '@eslint/js'
|
|
2
|
+
import globals from 'globals'
|
|
3
|
+
import reactHooks from 'eslint-plugin-react-hooks'
|
|
4
|
+
import reactRefresh from 'eslint-plugin-react-refresh'
|
|
5
|
+
import tseslint from 'typescript-eslint'
|
|
6
|
+
import { globalIgnores } from 'eslint/config'
|
|
7
|
+
|
|
8
|
+
export default tseslint.config([
|
|
9
|
+
globalIgnores(['dist']),
|
|
10
|
+
{
|
|
11
|
+
files: ['**/*.{ts,tsx}'],
|
|
12
|
+
extends: [
|
|
13
|
+
js.configs.recommended,
|
|
14
|
+
tseslint.configs.recommended,
|
|
15
|
+
reactHooks.configs['recommended-latest'],
|
|
16
|
+
reactRefresh.configs.vite,
|
|
17
|
+
],
|
|
18
|
+
languageOptions: {
|
|
19
|
+
ecmaVersion: 2020,
|
|
20
|
+
globals: globals.browser,
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
])
|
|
@@ -0,0 +1,13 @@
|
|
|
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>
|
|
@@ -0,0 +1,36 @@
|
|
|
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
|
+
"lint": "eslint .",
|
|
14
|
+
"preview": "vite preview"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@playcanvas/react": "^0.5.0",
|
|
18
|
+
"playcanvas": "^2.8.2",
|
|
19
|
+
"react": "^19.1.0",
|
|
20
|
+
"react-dom": "^19.1.0"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@eslint/js": "^9.29.0",
|
|
24
|
+
"@types/react": "^19.1.8",
|
|
25
|
+
"@types/react-dom": "^19.1.6",
|
|
26
|
+
"@vitejs/plugin-react": "^4.5.2",
|
|
27
|
+
"eslint": "^9.29.0",
|
|
28
|
+
"eslint-plugin-react-hooks": "^5.2.0",
|
|
29
|
+
"eslint-plugin-react-refresh": "^0.4.20",
|
|
30
|
+
"globals": "^16.2.0",
|
|
31
|
+
"semver": "^7.7.2",
|
|
32
|
+
"typescript": "~5.8.3",
|
|
33
|
+
"typescript-eslint": "^8.34.1",
|
|
34
|
+
"vite": "^7.0.0"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,12 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
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 > .grow {
|
|
74
|
+
flex-grow: 1;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.pill {
|
|
78
|
+
background-color: #000;
|
|
79
|
+
color: #fff;
|
|
80
|
+
padding: 0.5rem 1rem;
|
|
81
|
+
border-radius: 0.5rem;
|
|
82
|
+
}
|
|
83
|
+
|
|
@@ -0,0 +1,46 @@
|
|
|
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://playcanvas-react.vercel.app/docs" 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
|
+
count is {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
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// @ts-expect-error - ShadowCatcher is not typed
|
|
2
|
+
import { Grid } from "playcanvas/scripts/esm/grid.mjs";
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
import { Entity } from "@playcanvas/react";
|
|
5
|
+
import { useEnvAtlas, useMaterial } from "@playcanvas/react/hooks";
|
|
6
|
+
import { Camera, EnvAtlas, Render, Script } from "@playcanvas/react/components";
|
|
7
|
+
import { OrbitControls } from "@playcanvas/react/scripts";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The Scene renders a sphere with a grid and camera controls
|
|
11
|
+
*/
|
|
12
|
+
function Scene({ onClick }: SceneProps) {
|
|
13
|
+
|
|
14
|
+
// Track the hover state and set the color based on the hover state
|
|
15
|
+
const [hovering, setHovering] = useState(false);
|
|
16
|
+
|
|
17
|
+
// Set a material color based on the hover state
|
|
18
|
+
const diffuse = hovering ? '#ffffff' : '#dddddd';
|
|
19
|
+
|
|
20
|
+
// Create a material for the sphere
|
|
21
|
+
const material = useMaterial({ diffuse });
|
|
22
|
+
|
|
23
|
+
// Load the environment map
|
|
24
|
+
const { asset: envMap } = useEnvAtlas('/environment-map.png');
|
|
25
|
+
|
|
26
|
+
// change the mouse cursor based on the hover state
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
document.body.style.cursor = hovering ? 'pointer' : 'default';
|
|
29
|
+
}, [hovering]);
|
|
30
|
+
|
|
31
|
+
// Don't render until the environment map is loaded
|
|
32
|
+
if (!envMap) return null;
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<>
|
|
36
|
+
{/* Render some environment lighting using the environment map */}
|
|
37
|
+
<EnvAtlas asset={envMap} showSkybox={false} />
|
|
38
|
+
|
|
39
|
+
{/* Render a background grid */}
|
|
40
|
+
<Entity scale={[1000, 1000, 1000]}>
|
|
41
|
+
<Script script={Grid} />
|
|
42
|
+
</Entity>
|
|
43
|
+
|
|
44
|
+
{/* Create a camera entity with orbit controls */}
|
|
45
|
+
<Entity name='camera' position={[4, 1, 4]}>
|
|
46
|
+
<Camera clearColor='#171717' />
|
|
47
|
+
<OrbitControls />
|
|
48
|
+
</Entity>
|
|
49
|
+
|
|
50
|
+
{/* Create and position entity with pointer events */}
|
|
51
|
+
<Entity
|
|
52
|
+
position={[0, 2, 0]}
|
|
53
|
+
scale={[4, 4, 4]}
|
|
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;
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
|
@@ -0,0 +1,73 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
@@ -0,0 +1,27 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
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
|
+
}
|
|
File without changes
|