create-playcanvas 0.3.0 → 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 +37 -25
- package/dist/index.mjs +48 -46
- package/package.json +2 -1
- package/templates/_shared/model-viewer/public/playcanvas-cube.glb +0 -0
- package/templates/{vanilla-ts → engine/base}/README.md +3 -19
- package/templates/{vanilla-ts → engine/base}/src/vite-env.d.ts +6 -0
- package/templates/{vanilla-ts → engine/interactive-sphere}/src/main.ts +1 -1
- package/templates/{vanilla-ts → engine/interactive-sphere}/src/style.css +1 -1
- package/templates/{vanilla-ts → engine/interactive-sphere}/src/utils.ts +0 -1
- 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 +37 -5
- package/templates/{react-ts → react/base}/README.md +2 -19
- package/templates/{react-ts → react/base}/src/vite-env.d.ts +6 -0
- package/templates/{react-ts → react/interactive-sphere}/src/Scene.tsx +1 -2
- 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/templates/vanilla-ts/public/environment-map.png +0 -0
- /package/templates/{react-ts → _shared/interactive-sphere}/public/environment-map.png +0 -0
- /package/templates/{react-ts → engine/base}/_gitignore +0 -0
- /package/templates/{vanilla-ts → engine/base}/eslint.config.mjs +0 -0
- /package/templates/{vanilla-ts → engine/base}/package.json +0 -0
- /package/templates/{react-ts → engine/base}/prettier.config.mjs +0 -0
- /package/templates/{react-ts → engine/base}/src/assets/playcanvas.png +0 -0
- /package/templates/{vanilla-ts → engine/base}/tsconfig.json +0 -0
- /package/templates/{vanilla-ts → engine/interactive-sphere}/index.html +0 -0
- /package/templates/{vanilla-ts → engine/interactive-sphere}/src/App.ts +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/{react-ts → react/base}/eslint.config.mjs +0 -0
- /package/templates/{react-ts → react/base}/package.json +0 -0
- /package/templates/{vanilla-ts → react/base}/prettier.config.mjs +0 -0
- /package/templates/{vanilla-ts → react/base}/src/assets/playcanvas.png +0 -0
- /package/templates/{react-ts → react/base}/tsconfig.json +0 -0
- /package/templates/{react-ts → react/base}/vite.config.ts +0 -0
- /package/templates/{react-ts → react/interactive-sphere}/index.html +0 -0
- /package/templates/{react-ts → react/interactive-sphere}/src/App.css +0 -0
- /package/templates/{react-ts → react/interactive-sphere}/src/App.tsx +0 -0
- /package/templates/{react-ts → react/interactive-sphere}/src/assets/react.svg +0 -0
- /package/templates/{react-ts → react/interactive-sphere}/src/index.css +0 -0
- /package/templates/{react-ts → react/interactive-sphere}/src/main.tsx +0 -0
package/README.md
CHANGED
|
@@ -9,51 +9,63 @@
|
|
|
9
9
|
|
|
10
10
|
| [Engine Manual](https://developer.playcanvas.com/user-manual/engine/) | [React Manual](https://developer.playcanvas.com/user-manual/react/) | [Examples](https://playcanvas.github.io/) | [Forum](https://forum.playcanvas.com/) |
|
|
11
11
|
|
|
12
|
-
Scaffold a Vite-powered PlayCanvas project with TypeScript. Choose the PlayCanvas Engine directly
|
|
12
|
+
Scaffold a Vite-powered PlayCanvas project with TypeScript. Choose the PlayCanvas Engine directly, [`@playcanvas/react`](https://github.com/playcanvas/react) or [`@playcanvas/web-components`](https://github.com/playcanvas/web-components).
|
|
13
13
|
|
|
14
14
|
## Getting Started
|
|
15
15
|
|
|
16
|
-
Requires Node.js 22.23.2 or later.
|
|
17
|
-
|
|
18
16
|
```bash
|
|
17
|
+
# npm
|
|
19
18
|
npm create playcanvas@latest
|
|
20
|
-
|
|
21
|
-
npm install
|
|
22
|
-
npm run dev
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
The interactive setup asks for a project name, handles an existing target directory, sets the package name and lets you choose a template.
|
|
26
|
-
|
|
27
|
-
You can also use another package manager:
|
|
28
|
-
|
|
29
|
-
```bash
|
|
19
|
+
# pnpm
|
|
30
20
|
pnpm create playcanvas@latest
|
|
21
|
+
# yarn
|
|
31
22
|
yarn create playcanvas
|
|
23
|
+
# bun
|
|
32
24
|
bun x create-playcanvas@latest
|
|
33
25
|
```
|
|
34
26
|
|
|
27
|
+
Then follow the prompts. Requires Node.js 22.23.2 or later.
|
|
28
|
+
|
|
35
29
|
## Templates
|
|
36
30
|
|
|
37
|
-
| Template
|
|
38
|
-
|
|
|
39
|
-
| `
|
|
40
|
-
| `react
|
|
31
|
+
| Template | Description |
|
|
32
|
+
| ---------------- | -------------------------------------------- |
|
|
33
|
+
| `engine` | The PlayCanvas Engine API directly |
|
|
34
|
+
| `react` | `@playcanvas/react` components |
|
|
35
|
+
| `web-components` | `@playcanvas/web-components` custom elements |
|
|
36
|
+
|
|
37
|
+
Every template is TypeScript, and includes Vite, ESLint, Prettier and a production build.
|
|
38
|
+
|
|
39
|
+
## Boilerplates
|
|
41
40
|
|
|
42
|
-
|
|
41
|
+
Each template offers a choice of starting scene. `spinning-cube` is the default.
|
|
42
|
+
|
|
43
|
+
| Boilerplate | Description |
|
|
44
|
+
| -------------------- | ---------------------------------------------- |
|
|
45
|
+
| `spinning-cube` | A rotating cube and a light |
|
|
46
|
+
| `interactive-sphere` | Orbit controls, a grid and pointer picking |
|
|
47
|
+
| `model-viewer` | A glTF model, orbit controls, a procedural sky |
|
|
48
|
+
| `splat-viewer` | A Gaussian splat and orbit controls |
|
|
49
|
+
|
|
50
|
+
A template is a `base` directory of shared tooling plus one directory per boilerplate, which is copied over the top. Assets a boilerplate needs in every template live once in `templates/_shared/<boilerplate>` and are seeded in first.
|
|
43
51
|
|
|
44
52
|
## CLI Options
|
|
45
53
|
|
|
46
|
-
Pass a project name and
|
|
54
|
+
Pass a project name, template and boilerplate to skip the prompts:
|
|
47
55
|
|
|
48
56
|
```bash
|
|
49
|
-
npm create playcanvas@latest my-game -- --template react-
|
|
57
|
+
npm create playcanvas@latest my-game -- --template react --boilerplate spinning-cube
|
|
50
58
|
```
|
|
51
59
|
|
|
52
|
-
| Option
|
|
53
|
-
|
|
|
54
|
-
| `--template <name>`
|
|
55
|
-
| `--
|
|
56
|
-
| `--
|
|
60
|
+
| Option | Shorthand | Description |
|
|
61
|
+
| ---------------------- | --------- | ------------------------------------------------------- |
|
|
62
|
+
| `--template <name>` | `-t` | Use a template from the list above |
|
|
63
|
+
| `--boilerplate <name>` | `-b` | Use a boilerplate from the list above |
|
|
64
|
+
| `--overwrite` | | Remove existing files from a non-empty target directory |
|
|
65
|
+
| `--yes` | `-y` | Skip the prompts and take the defaults |
|
|
66
|
+
| `--help` | `-h` | Show command help |
|
|
67
|
+
|
|
68
|
+
`--yes` takes `playcanvas-project`, the `engine` template and the `spinning-cube` boilerplate for anything you don't pass. It never deletes files, so a non-empty target directory still needs `--overwrite`.
|
|
57
69
|
|
|
58
70
|
## Development
|
|
59
71
|
|
package/dist/index.mjs
CHANGED
|
@@ -1,59 +1,61 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{styleText as c}from"node:util";import
|
|
3
|
-
`);let m=!1;for(let h=0;h<u.length;h++){const d=u[h];if(
|
|
4
|
-
`){l&&(
|
|
5
|
-
`&&(
|
|
6
|
-
`)}function
|
|
7
|
-
`),
|
|
8
|
-
`),
|
|
9
|
-
`).map((
|
|
10
|
-
`)}function
|
|
11
|
-
`),
|
|
12
|
-
`).length-1;this.output.write(
|
|
13
|
-
`);this.output.write(
|
|
14
|
-
`).slice(
|
|
15
|
-
`)),this._prevFrame=
|
|
16
|
-
`);b.push(
|
|
17
|
-
`);if(h.length>0){const[d,...
|
|
2
|
+
import{styleText as c}from"node:util";import k,{stdin as Ce,stdout as ae}from"node:process";import Re from"node:readline";import"node:tty";import I from"node:fs";import _ from"node:path";import{fileURLToPath as Ae}from"node:url";const ke=(()=>{const e=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g;return t=>{let r=0;for(e.lastIndex=0;e.test(t);)r+=1;return t.length-r}})(),Be=e=>e===12288||e>=65281&&e<=65376||e>=65504&&e<=65510,Le=e=>e===8987||e===9001||e>=12272&&e<=12287||e>=12289&&e<=12350||e>=12441&&e<=12543||e>=12549&&e<=12591||e>=12593&&e<=12686||e>=12688&&e<=12771||e>=12783&&e<=12830||e>=12832&&e<=12871||e>=12880&&e<=19903||e>=65040&&e<=65049||e>=65072&&e<=65106||e>=65108&&e<=65126||e>=65128&&e<=65131||e>=127488&&e<=127490||e>=127504&&e<=127547||e>=127552&&e<=127560||e>=131072&&e<=196605||e>=196608&&e<=262141,Oe=/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y,Me=/[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y,oe=/(?:(?![\uFF61-\uFF9F\uFF00-\uFFEF])[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Tangut}]){1,1000}/yu,Ne=/\t{1,1000}/y,le=new RegExp("[\\u{1F1E6}-\\u{1F1FF}]{2}|\\u{1F3F4}[\\u{E0061}-\\u{E007A}]{2}[\\u{E0030}-\\u{E0039}\\u{E0061}-\\u{E007A}]{1,3}\\u{E007F}|(?:\\p{Emoji}\\uFE0F\\u20E3?|\\p{Emoji_Modifier_Base}\\p{Emoji_Modifier}?|\\p{Emoji_Presentation})(?:\\u200D(?:\\p{Emoji_Modifier_Base}\\p{Emoji_Modifier}?|\\p{Emoji_Presentation}|\\p{Emoji}\\uFE0F\\u20E3?))*","yu"),Pe=/(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y,je=new RegExp("\\p{M}+","gu"),De={limit:1/0,ellipsis:""},ce=(e,t={},r={})=>{const s=t.limit??1/0,a=t.ellipsis??"",l=t?.ellipsisWidth??(a?ce(a,De,r).width:0),o=0,n=r.controlWidth??0,i=r.tabWidth??8,u=r.emojiWidth??2,m=2,h=r.regularWidth??1,d=r.wideWidth??m,f=[[Pe,h],[Oe,o],[Me,n],[Ne,i],[le,u],[oe,d]];let p=0,g=0,b=e.length,E=0,w=!1,C=b,R=Math.max(0,s-l),y=0,S=0,x=0,v=0;e:for(;;){if(S>y||g>=b&&g>p){const F=e.slice(y,S)||e.slice(p,g);E=0;for(const O of F.replaceAll(je,"")){const T=O.codePointAt(0)||0;if(Be(T)?v=m:Le(T)?v=d:v=h,x+v>R&&(C=Math.min(C,Math.max(y,p)+E)),x+v>s){w=!0;break e}E+=O.length,x+=v}y=S=0}if(g>=b)break e;for(let F=0,O=f.length;F<O;F++){const[T,ne]=f[F];if(T.lastIndex=g,T.test(e)){if(E=T===oe?ke(e.slice(g,T.lastIndex)):T===le?1:T.lastIndex-g,v=E*ne,x+v>R&&(C=Math.min(C,g+Math.floor((R-x)/ne))),x+v>s){w=!0;break e}x+=v,y=p,S=g,g=p=T.lastIndex;continue e}}g+=1}return{width:w?R:x,index:w?C:b,truncated:w,ellipsed:w&&s>=l}},We={limit:1/0,ellipsis:"",ellipsisWidth:0},L=(e,t={})=>ce(e,We,t).width,V="\x1B",ue="\x9B",Ve=39,Y="\x07",he="[",Ue="]",me="m",q=`${Ue}8;;`,de=new RegExp(`(?:\\${he}(?<code>\\d+)m|\\${q}(?<uri>.*)${Y})`,"y"),pe=e=>{if(e>=30&&e<=37||e>=90&&e<=97)return 39;if(e>=40&&e<=47||e>=100&&e<=107)return 49;if(e===1||e===2)return 22;if(e===3)return 23;if(e===4)return 24;if(e===7)return 27;if(e===8)return 28;if(e===9)return 29;if(e===0)return 0},fe=e=>`${V}${he}${e}${me}`,ge=e=>`${V}${q}${e}${Y}`,X=(e,t,r)=>{const s=t[Symbol.iterator]();let a=!1,l=!1,o=e.at(-1),n=o===void 0?0:L(o),i=s.next(),u=s.next(),m=0;for(;!i.done;){const h=i.value,d=L(h);n+d<=r?e[e.length-1]+=h:(e.push(h),n=0),(h===V||h===ue)&&(a=!0,l=t.startsWith(q,m+1)),a?l?h===Y&&(a=!1,l=!1):h===me&&(a=!1):(n+=d,n===r&&!u.done&&(e.push(""),n=0)),i=u,u=s.next(),m+=h.length}o=e.at(-1),!n&&o!==void 0&&o.length&&e.length>1&&(e[e.length-2]+=e.pop())},Ge=e=>{const t=e.split(" ");let r=t.length;for(;r&&!L(t[r-1]);)r--;return r===t.length?e:t.slice(0,r).join(" ")+t.slice(r).join("")},Ke=(e,t,r={})=>{if(r.trim!==!1&&e.trim()==="")return"";let s="",a,l;const o=e.split(" ");let n=[""],i=0;for(let h=0;h<o.length;h++){const d=o[h];if(r.trim!==!1){const p=n.at(-1)??"",g=p.trimStart();p.length!==g.length&&(n[n.length-1]=g,i=L(g))}h!==0&&(i>=t&&(r.wordWrap===!1||r.trim===!1)&&(n.push(""),i=0),(i||r.trim===!1)&&(n[n.length-1]+=" ",i++));const f=L(d);if(r.hard&&f>t){const p=t-i,g=1+Math.floor((f-p-1)/t);Math.floor((f-1)/t)<g&&n.push(""),X(n,d,t),i=L(n.at(-1)??"");continue}if(i+f>t&&i&&f){if(r.wordWrap===!1&&i<t){X(n,d,t),i=L(n.at(-1)??"");continue}n.push(""),i=0}if(i+f>t&&r.wordWrap===!1){X(n,d,t),i=L(n.at(-1)??"");continue}n[n.length-1]+=d,i+=f}r.trim!==!1&&(n=n.map(h=>Ge(h)));const u=n.join(`
|
|
3
|
+
`);let m=!1;for(let h=0;h<u.length;h++){const d=u[h];if(s+=d,m)m=!1;else if(m=d>="\uD800"&&d<="\uDBFF",m)continue;if(d===V||d===ue){de.lastIndex=h+1;const p=de.exec(u)?.groups;if(p?.code!==void 0){const g=Number.parseFloat(p.code);a=g===Ve?void 0:g}else p?.uri!==void 0&&(l=p.uri.length===0?void 0:p.uri)}if(u[h+1]===`
|
|
4
|
+
`){l&&(s+=ge(""));const f=a?pe(a):void 0;a&&f&&(s+=fe(f))}else d===`
|
|
5
|
+
`&&(a&&pe(a)&&(s+=fe(a)),l&&(s+=ge(l)))}return s},He=/\r?\n/;function U(e,t,r){return String(e).normalize().split(He).map(s=>Ke(s,t,r)).join(`
|
|
6
|
+
`)}function ze(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var Z,be;function Je(){if(be)return Z;be=1;const e="\x1B",t=`${e}[`,r="\x07",s={to(o,n){return n?`${t}${n+1};${o+1}H`:`${t}${o+1}G`},move(o,n){let i="";return o<0?i+=`${t}${-o}D`:o>0&&(i+=`${t}${o}C`),n<0?i+=`${t}${-n}A`:n>0&&(i+=`${t}${n}B`),i},up:(o=1)=>`${t}${o}A`,down:(o=1)=>`${t}${o}B`,forward:(o=1)=>`${t}${o}C`,backward:(o=1)=>`${t}${o}D`,nextLine:(o=1)=>`${t}E`.repeat(o),prevLine:(o=1)=>`${t}F`.repeat(o),left:`${t}G`,hide:`${t}?25l`,show:`${t}?25h`,save:`${e}7`,restore:`${e}8`},a={up:(o=1)=>`${t}S`.repeat(o),down:(o=1)=>`${t}T`.repeat(o)},l={screen:`${t}2J`,up:(o=1)=>`${t}1J`.repeat(o),down:(o=1)=>`${t}J`.repeat(o),line:`${t}2K`,lineEnd:`${t}K`,lineStart:`${t}1K`,lines(o){let n="";for(let i=0;i<o;i++)n+=this.line+(i<o-1?s.up():"");return o&&(n+=s.left),n}};return Z={cursor:s,scroll:a,erase:l,beep:r},Z}var B=Je();function G(e,t,r){if(!r.some(o=>!o.disabled))return e;const s=e+t,a=Math.max(r.length-1,0),l=s<0?a:s>a?0:s;return r[l]?.disabled?G(l,t<0?-1:1,r):l}const Ye=["up","down","left","right","space","enter","cancel"],M={actions:new Set(Ye),aliases:new Map([["k","up"],["j","down"],["h","left"],["l","right"],["","cancel"],["escape","cancel"]]),withGuide:!0};function xe(e,t){if(typeof e=="string")return M.aliases.get(e)===t;for(const r of e)if(r!==void 0&&xe(r,t))return!0;return!1}function qe(e,t){if(e===t)return;const r=e.split(`
|
|
7
|
+
`),s=t.split(`
|
|
8
|
+
`),a=Math.max(r.length,s.length),l=[];for(let o=0;o<a;o++)r[o]!==s[o]&&l.push(o);return{lines:l,numLinesBefore:r.length,numLinesAfter:s.length,numLines:a}}globalThis.process.platform.startsWith("win");const Q=Symbol("clack:cancel");function D(e){return e===Q}function K(e,t){const r=e;r.isTTY&&r.setRawMode(t)}const $e=e=>"columns"in e&&typeof e.columns=="number"?e.columns:80,ye=e=>"rows"in e&&typeof e.rows=="number"?e.rows:20;function ee(e,t,r,s=r,a=r,l){const o=$e(e??ae);return U(t,o-r.length,{hard:!0,trim:!1}).split(`
|
|
9
|
+
`).map((n,i,u)=>{const m=n;return i===0?`${s}${m}`:i===u.length-1?`${a}${m}`:`${r}${m}`}).join(`
|
|
10
|
+
`)}function Xe(e,t){if("~standard"in e){const r=e["~standard"].validate(t);if(r instanceof Promise)throw new TypeError("Schema validation must be synchronous. Update `validate()` and remove any asynchronous logic.");return r.issues?.at(0)?.message}return e(t)}class we{input;output;_abortSignal;rl;opts;_render;_track=!1;_prevFrame="";_subscribers=new Map;_cursor=0;state="initial";error="";value;userInput="";constructor(t,r=!0){const{input:s=Ce,output:a=ae,render:l,signal:o,...n}=t;this.opts=n,this.onKeypress=this.onKeypress.bind(this),this.close=this.close.bind(this),this.render=this.render.bind(this),this._render=l.bind(this),this._track=r,this._abortSignal=o,this.input=s,this.output=a}unsubscribe(){this._subscribers.clear()}setSubscriber(t,r){const s=this._subscribers.get(t)??[];s.push(r),this._subscribers.set(t,s)}on(t,r){this.setSubscriber(t,{cb:r})}once(t,r){this.setSubscriber(t,{cb:r,once:!0})}emit(t,...r){const s=this._subscribers.get(t)??[],a=[];for(const l of s)l.cb(...r),l.once&&a.push(()=>s.splice(s.indexOf(l),1));for(const l of a)l()}prompt(){return new Promise(t=>{if(this._abortSignal){if(this._abortSignal.aborted)return this.state="cancel",this.close(),t(Q);this._abortSignal.addEventListener("abort",()=>{this.state="cancel",this.close()},{once:!0})}this.rl=Re.createInterface({input:this.input,tabSize:2,prompt:"",escapeCodeTimeout:50,terminal:!0}),this.rl.prompt(),this.opts.initialUserInput!==void 0&&this._setUserInput(this.opts.initialUserInput,!0),this.input.on("keypress",this.onKeypress),K(this.input,!0),this.output.on("resize",this.render),this.render(),this.once("submit",()=>{this.output.write(B.cursor.show),this.output.off("resize",this.render),K(this.input,!1),t(this.value)}),this.once("cancel",()=>{this.output.write(B.cursor.show),this.output.off("resize",this.render),K(this.input,!1),t(Q)})})}_isActionKey(t,r){return t===" "}_shouldSubmit(t,r){return!0}_setValue(t){this.value=t,this.emit("value",this.value)}_setUserInput(t,r){this.userInput=t??"",this.emit("userInput",this.userInput),r&&this._track&&this.rl&&(this.rl.write(this.userInput),this._cursor=this.rl.cursor)}_clearUserInput(){this.rl?.write(null,{ctrl:!0,name:"u"}),this._setUserInput("")}onKeypress(t,r){if(this._track&&r.name!=="return"&&(r.name&&this._isActionKey(t,r)&&this.rl?.write(null,{ctrl:!0,name:"h"}),this._cursor=this.rl?.cursor??0,this._setUserInput(this.rl?.line)),this.state==="error"&&(this.state="active"),r?.name&&(!this._track&&M.aliases.has(r.name)&&this.emit("cursor",M.aliases.get(r.name)),M.actions.has(r.name)&&this.emit("cursor",r.name)),t&&(t.toLowerCase()==="y"||t.toLowerCase()==="n")&&this.emit("confirm",t.toLowerCase()==="y"),this.emit("key",t,r),r?.name==="return"&&this._shouldSubmit(t,r)){if(this.opts.validate){const s=Xe(this.opts.validate,this.value);s&&(this.error=s instanceof Error?s.message:s,this.state="error",this.rl?.write(this.userInput))}this.state!=="error"&&(this.state="submit")}xe([t,r?.name,r?.sequence],"cancel")&&(this.state="cancel"),(this.state==="submit"||this.state==="cancel")&&this.emit("finalize"),this.render(),(this.state==="submit"||this.state==="cancel")&&this.close()}close(){this.input.unpipe(),this.input.removeListener("keypress",this.onKeypress),this.output.write(`
|
|
11
|
+
`),K(this.input,!1),this.rl?.close(),this.rl=void 0,this.emit(`${this.state}`,this.value),this.unsubscribe()}restoreCursor(){const t=U(this._prevFrame,process.stdout.columns,{hard:!0,trim:!1}).split(`
|
|
12
|
+
`).length-1;this.output.write(B.cursor.move(-999,t*-1))}render(){const t=U(this._render(this)??"",process.stdout.columns,{hard:!0,trim:!1});if(t!==this._prevFrame){if(this.state==="initial")this.output.write(B.cursor.hide);else{const r=qe(this._prevFrame,t),s=ye(this.output);if(this.restoreCursor(),r){const a=Math.max(0,r.numLinesAfter-s),l=Math.max(0,r.numLinesBefore-s);let o=r.lines.find(n=>n>=a);if(o===void 0){this._prevFrame=t;return}if(r.lines.length===1){this.output.write(B.cursor.move(0,o-l)),this.output.write(B.erase.lines(1));const n=t.split(`
|
|
13
|
+
`);this.output.write(n[o]),this._prevFrame=t,this.output.write(B.cursor.move(0,n.length-o-1));return}else if(r.lines.length>1){if(a<l)o=a;else{const i=o-l;i>0&&this.output.write(B.cursor.move(0,i))}this.output.write(B.erase.down());const n=t.split(`
|
|
14
|
+
`).slice(o);this.output.write(n.join(`
|
|
15
|
+
`)),this._prevFrame=t;return}}this.output.write(B.erase.down())}this.output.write(t),this.state==="initial"&&(this.state="active"),this._prevFrame=t}}}let Ze=class extends we{options;cursor=0;get _selectedValue(){return this.options[this.cursor]}changeValue(){const t=this._selectedValue;this.value=t===void 0?void 0:t.value}constructor(t){super(t,!1),this.options=t.options;const r=this.options.findIndex(({value:a})=>a===t.initialValue),s=r===-1?0:r;this.cursor=this.options[s]?.disabled?G(s,1,this.options):s,this.changeValue(),this.on("cursor",a=>{switch(a){case"left":case"up":this.cursor=G(this.cursor,-1,this.options);break;case"down":case"right":this.cursor=G(this.cursor,1,this.options);break}this.changeValue()})}},Qe=class extends we{get userInputWithCursor(){if(this.state==="submit")return this.userInput;const t=this.userInput;if(this.cursor>=t.length)return`${this.userInput}\u2588`;const r=t.slice(0,this.cursor),s=t.slice(this.cursor,this.cursor+1),a=t.slice(this.cursor+1);return`${r}${c("inverse",s)}${a}`}get cursor(){return this._cursor}constructor(t){super({...t,initialUserInput:t.initialUserInput??t.initialValue}),this.on("userInput",r=>{this._setValue(r)}),this.on("finalize",()=>{this.value||(this.value=t.defaultValue),this.value===void 0&&(this.value="")})}};function et(){return k.platform!=="win32"?k.env.TERM!=="linux":!!k.env.CI||!!k.env.WT_SESSION||!!k.env.TERMINUS_SUBLIME||k.env.ConEmuTask==="{cmd::Cmder}"||k.env.TERM_PROGRAM==="Terminus-Sublime"||k.env.TERM_PROGRAM==="vscode"||k.env.TERM==="xterm-256color"||k.env.TERM==="alacritty"||k.env.TERMINAL_EMULATOR==="JetBrains-JediTerm"}const tt=et(),A=(e,t)=>tt?e:t,rt=A("\u25C6","*"),it=A("\u25A0","x"),st=A("\u25B2","x"),ve=A("\u25C7","o"),$=A("\u2502","|"),j=A("\u2514","\u2014"),nt=A("\u25CF",">"),_e=A("\u25CB"," "),at=A("\u25CF","\u2022"),ot=A("\u25C6","*"),lt=A("\u25B2","!"),ct=A("\u25A0","x"),Ee=e=>{switch(e){case"initial":case"active":return c("cyan",rt);case"cancel":return c("red",it);case"error":return c("yellow",st);case"submit":return c("green",ve)}},ut=e=>{switch(e){case"initial":case"active":return c("cyan",$);case"cancel":return c("red",$);case"error":return c("yellow",$);case"submit":return c("green",$)}};function ht(e,t){const r=[`${t?`${c("cyan",$)} `:""}${e.join(" \u2022 ")}`];return t&&r.push(c("cyan",j)),r}const Se=(e,t,r,s,a,l=!1)=>{let o=t,n=0;if(l)for(let i=s-1;i>=r;i--){const u=e[i];if(u&&(o-=u.length),n++,o<=a)break}else for(let i=r;i<s;i++){const u=e[i];if(u&&(o-=u.length),n++,o<=a)break}return{lineCount:o,removals:n}},mt=({cursor:e,options:t,style:r,output:s=process.stdout,maxItems:a=Number.POSITIVE_INFINITY,columnPadding:l=0,rowPadding:o=4})=>{const n=$e(s)-l,i=ye(s),u=c("dim","..."),m=Math.max(i-o,0),h=Math.max(Math.min(a,m),5);let d=0;e>=h-3&&(d=Math.max(Math.min(e-h+3,t.length-h),0));let f=h<t.length&&d>0,p=h<t.length&&d+h<t.length;const g=Math.min(d+h,t.length),b=[];let E=0;f&&E++,p&&E++;const w=d+(f?1:0),C=g-(p?1:0);for(let y=w;y<C;y++){const S=t[y],x=S?r(S,y===e):"",v=U(x,n,{hard:!0,trim:!1}).split(`
|
|
16
|
+
`);b.push(v),E+=v.length}if(E>m){let y=0,S=0,x=E;const v=e-w;let F=m;const O=()=>Se(b,x,0,v,F),T=()=>Se(b,x,v+1,b.length,F,!0);f?({lineCount:x,removals:y}=O(),x>F&&(p||(F-=1),{lineCount:x,removals:S}=T())):(p||(F-=1),{lineCount:x,removals:S}=T(),x>F&&(F-=1,{lineCount:x,removals:y}=O())),y>0&&(f=!0,b.splice(0,y)),S>0&&(p=!0,b.splice(b.length-S,S))}const R=[];f&&R.push(u);for(const y of b)for(const S of y)R.push(S);return p&&R.push(u),R};`${c("dim","\u2191/\u2193")}`,`${c("dim","Space:")}`,`${c("dim","Enter:")}`;const N={message:(e=[],{symbol:t=c("gray",$),secondarySymbol:r=c("gray",$),output:s=process.stdout,spacing:a=1,withGuide:l}={})=>{const o=[],n=l??M.withGuide,i=n?r:"",u=n?`${t} `:"",m=n?`${r} `:"";for(let d=0;d<a;d++)o.push(i);const h=Array.isArray(e)?e:e.split(`
|
|
17
|
+
`);if(h.length>0){const[d,...f]=h;d.length>0?o.push(`${u}${d}`):o.push(n?t:"");for(const p of f)p.length>0?o.push(`${m}${p}`):o.push(n?r:"")}s.write(`${o.join(`
|
|
18
18
|
`)}
|
|
19
|
-
`)},info:(t
|
|
19
|
+
`)},info:(e,t)=>{N.message(e,{...t,symbol:c("blue",at)})},success:(e,t)=>{N.message(e,{...t,symbol:c("green",ot)})},step:(e,t)=>{N.message(e,{...t,symbol:c("green",ve)})},warn:(e,t)=>{N.message(e,{...t,symbol:c("yellow",lt)})},warning:(e,t)=>{N.warn(e,t)},error:(e,t)=>{N.message(e,{...t,symbol:c("red",ct)})}},dt=(e="",t)=>{const r=process.stdout,s=`${c("gray",j)} `;r.write(`${s}${c("red",e)}
|
|
20
20
|
|
|
21
|
-
`)},
|
|
22
|
-
${c("gray",
|
|
21
|
+
`)},pt=(e="",t)=>{const r=process.stdout,s=`${c("gray",$)}
|
|
22
|
+
${c("gray",j)} `;r.write(`${s}${e}
|
|
23
23
|
|
|
24
|
-
`)},
|
|
25
|
-
`)?
|
|
26
|
-
`).map(r=>
|
|
27
|
-
`):e
|
|
28
|
-
`:""}${
|
|
29
|
-
`;switch(this.state){case"submit":{const s
|
|
30
|
-
${c("gray",$)}`:""}`}default:{const s
|
|
31
|
-
`).length,m=r?
|
|
32
|
-
`),d=m.length+1;return`${
|
|
33
|
-
${
|
|
24
|
+
`)},ft=[`${c("dim","\u2191/\u2193")} to navigate`,`${c("dim","Enter:")} confirm`],H=(e,t)=>e.includes(`
|
|
25
|
+
`)?e.split(`
|
|
26
|
+
`).map(r=>t(r)).join(`
|
|
27
|
+
`):t(e),te=e=>{const t=(s,a)=>{if(s===void 0)return"";const l=s.label??String(s.value);switch(a){case"disabled":return`${c("gray",_e)} ${H(l,o=>c("gray",o))}${s.hint?` ${c("dim",`(${s.hint??"disabled"})`)}`:""}`;case"selected":return`${H(l,o=>c("dim",o))}`;case"active":return`${c("green",nt)} ${l}${s.hint?` ${c("dim",`(${s.hint})`)}`:""}`;case"cancelled":return`${H(l,o=>c(["strikethrough","dim"],o))}`;default:return`${c("dim",_e)} ${H(l,o=>c("dim",o))}`}},r=e.showInstructions??!0;return new Ze({options:e.options,signal:e.signal,input:e.input,output:e.output,initialValue:e.initialValue,render(){const s=e.withGuide??M.withGuide,a=`${Ee(this.state)} `,l=`${ut(this.state)} `,o=ee(e.output,e.message,l,a),n=`${s?`${c("gray",$)}
|
|
28
|
+
`:""}${o}
|
|
29
|
+
`;switch(this.state){case"submit":{const i=s?`${c("gray",$)} `:"",u=ee(e.output,t(this.options[this.cursor],"selected"),i);return`${n}${u}`}case"cancel":{const i=s?`${c("gray",$)} `:"",u=ee(e.output,t(this.options[this.cursor],"cancelled"),i);return`${n}${u}${s?`
|
|
30
|
+
${c("gray",$)}`:""}`}default:{const i=s?`${c("cyan",$)} `:"",u=n.split(`
|
|
31
|
+
`).length,m=r?ht(ft,s):s?[c("cyan",j)]:[],h=m.join(`
|
|
32
|
+
`),d=m.length+1;return`${n}${i}${mt({output:e.output,cursor:this.cursor,options:this.options,maxItems:e.maxItems,columnPadding:i.length,rowPadding:u+d,style:(f,p)=>t(f,f.disabled?"disabled":p?"active":"inactive")}).join(`
|
|
33
|
+
${i}`)}
|
|
34
34
|
${h}
|
|
35
|
-
`}}}}).prompt()};`${c("gray",$)}`;const
|
|
36
|
-
`:""}${
|
|
37
|
-
`,
|
|
38
|
-
${
|
|
39
|
-
${
|
|
40
|
-
`}case"submit":{const
|
|
41
|
-
${
|
|
42
|
-
${
|
|
43
|
-
`}}}}).prompt();function
|
|
44
|
-
`);let
|
|
45
|
-
`;const
|
|
46
|
-
cd ${
|
|
47
|
-
yarn`,
|
|
48
|
-
yarn dev`;break;default:
|
|
49
|
-
${
|
|
50
|
-
${
|
|
35
|
+
`}}}}).prompt()};`${c("gray",$)}`;const Ie=e=>new Qe({validate:e.validate,placeholder:e.placeholder,defaultValue:e.defaultValue,initialValue:e.initialValue,output:e.output,signal:e.signal,input:e.input,render(){const t=e?.withGuide??M.withGuide,r=`${`${t?`${c("gray",$)}
|
|
36
|
+
`:""}${Ee(this.state)} `}${e.message}
|
|
37
|
+
`,s=e.placeholder&&e.placeholder.length>0?c("inverse",e.placeholder[0])+c("dim",e.placeholder.slice(1)):c(["inverse","hidden"],"_"),a=this.userInput?this.userInputWithCursor:s,l=this.value??"";switch(this.state){case"error":{const o=this.error?` ${c("yellow",this.error)}`:"",n=t?`${c("yellow",$)} `:"",i=t?c("yellow",j):"";return`${r.trim()}
|
|
38
|
+
${n}${a}
|
|
39
|
+
${i}${o}
|
|
40
|
+
`}case"submit":{const o=l?` ${c("dim",l)}`:"",n=t?c("gray",$):"";return`${r}${n}${o}`}case"cancel":{const o=l?` ${c(["strikethrough","dim"],l)}`:"",n=t?c("gray",$):"";return`${r}${n}${o}${l.trim()?`
|
|
41
|
+
${n}`:""}`}default:{const o=t?`${c("cyan",$)} `:"",n=t?c("cyan",j):"";return`${r}${o}${a}
|
|
42
|
+
${n}
|
|
43
|
+
`}}}}).prompt();function re(e){return e==null?[]:Array.isArray(e)?e:[e]}function gt(e,t,r,s){var a,l=e[t],o=~s.string.indexOf(t)?r==null||r===!0?"":String(r):typeof r=="boolean"?r:~s.boolean.indexOf(t)?r==="false"?!1:r==="true"||(e._.push((a=+r,a*0===0?a:r)),!!r):(a=+r,a*0===0?a:r);e[t]=l==null?o:Array.isArray(l)?l.concat(o):[l,o]}function bt(e,t){e=e||[],t=t||{};var r,s,a,l,o,n={_:[]},i=0,u=0,m=0,h=e.length;const d=t.alias!==void 0,f=t.unknown!==void 0,p=t.default!==void 0;if(t.alias=t.alias||{},t.string=re(t.string),t.boolean=re(t.boolean),d)for(r in t.alias)for(s=t.alias[r]=re(t.alias[r]),i=0;i<s.length;i++)(t.alias[s[i]]=s.concat(r)).splice(i,1);for(i=t.boolean.length;i-- >0;)for(s=t.alias[t.boolean[i]]||[],u=s.length;u-- >0;)t.boolean.push(s[u]);for(i=t.string.length;i-- >0;)for(s=t.alias[t.string[i]]||[],u=s.length;u-- >0;)t.string.push(s[u]);if(p){for(r in t.default)if(l=typeof t.default[r],s=t.alias[r]=t.alias[r]||[],t[l]!==void 0)for(t[l].push(r),i=0;i<s.length;i++)t[l].push(s[i])}const g=f?Object.keys(t.alias):[];for(i=0;i<h;i++){if(a=e[i],a==="--"){n._=n._.concat(e.slice(++i));break}for(u=0;u<a.length&&a.charCodeAt(u)===45;u++);if(u===0)n._.push(a);else if(a.substring(u,u+3)==="no-"){if(l=a.substring(u+3),f&&!~g.indexOf(l))return t.unknown(a);n[l]=!1}else{for(m=u+1;m<a.length&&a.charCodeAt(m)!==61;m++);for(l=a.substring(u,m),o=a.substring(++m)||i+1===h||(""+e[i+1]).charCodeAt(0)===45||e[++i],s=u===2?[l]:l,m=0;m<s.length;m++){if(l=s[m],f&&!~g.indexOf(l))return t.unknown("-".repeat(u)+l);gt(n,l,m+1<s.length||o,t)}}}if(p)for(r in t.default)n[r]===void 0&&(n[r]=t.default[r]);if(d)for(r in n)for(s=t.alias[r]||[];s.length>0;)n[s.shift()]=n[r];return n}var z={exports:{}},Fe;function xt(){if(Fe)return z.exports;Fe=1;let e=process||{},t=e.argv||[],r=e.env||{},s=!(r.NO_COLOR||t.includes("--no-color"))&&(!!r.FORCE_COLOR||t.includes("--color")||e.platform==="win32"||(e.stdout||{}).isTTY&&r.TERM!=="dumb"||!!r.CI),a=(n,i,u=n)=>m=>{let h=""+m,d=h.indexOf(i,n.length);return~d?n+l(h,i,u,d)+i:n+h+i},l=(n,i,u,m)=>{let h="",d=0;do h+=n.substring(d,m)+u,d=m+i.length,m=n.indexOf(i,d);while(~m);return h+n.substring(d)},o=(n=s)=>{let i=n?a:()=>String;return{isColorSupported:n,reset:i("\x1B[0m","\x1B[0m"),bold:i("\x1B[1m","\x1B[22m","\x1B[22m\x1B[1m"),dim:i("\x1B[2m","\x1B[22m","\x1B[22m\x1B[2m"),italic:i("\x1B[3m","\x1B[23m"),underline:i("\x1B[4m","\x1B[24m"),inverse:i("\x1B[7m","\x1B[27m"),hidden:i("\x1B[8m","\x1B[28m"),strikethrough:i("\x1B[9m","\x1B[29m"),black:i("\x1B[30m","\x1B[39m"),red:i("\x1B[31m","\x1B[39m"),green:i("\x1B[32m","\x1B[39m"),yellow:i("\x1B[33m","\x1B[39m"),blue:i("\x1B[34m","\x1B[39m"),magenta:i("\x1B[35m","\x1B[39m"),cyan:i("\x1B[36m","\x1B[39m"),white:i("\x1B[37m","\x1B[39m"),gray:i("\x1B[90m","\x1B[39m"),bgBlack:i("\x1B[40m","\x1B[49m"),bgRed:i("\x1B[41m","\x1B[49m"),bgGreen:i("\x1B[42m","\x1B[49m"),bgYellow:i("\x1B[43m","\x1B[49m"),bgBlue:i("\x1B[44m","\x1B[49m"),bgMagenta:i("\x1B[45m","\x1B[49m"),bgCyan:i("\x1B[46m","\x1B[49m"),bgWhite:i("\x1B[47m","\x1B[49m"),blackBright:i("\x1B[90m","\x1B[39m"),redBright:i("\x1B[91m","\x1B[39m"),greenBright:i("\x1B[92m","\x1B[39m"),yellowBright:i("\x1B[93m","\x1B[39m"),blueBright:i("\x1B[94m","\x1B[39m"),magentaBright:i("\x1B[95m","\x1B[39m"),cyanBright:i("\x1B[96m","\x1B[39m"),whiteBright:i("\x1B[97m","\x1B[39m"),bgBlackBright:i("\x1B[100m","\x1B[49m"),bgRedBright:i("\x1B[101m","\x1B[49m"),bgGreenBright:i("\x1B[102m","\x1B[49m"),bgYellowBright:i("\x1B[103m","\x1B[49m"),bgBlueBright:i("\x1B[104m","\x1B[49m"),bgMagentaBright:i("\x1B[105m","\x1B[49m"),bgCyanBright:i("\x1B[106m","\x1B[49m"),bgWhiteBright:i("\x1B[107m","\x1B[49m")}};return z.exports=o(),z.exports.createColors=o,z.exports}var $t=xt();const yt=ze($t),{cyan:wt,magenta:vt,yellow:_t}=yt,J=[{name:"engine",display:"Engine",description:"with the PlayCanvas Engine API directly",color:_t},{name:"react",display:"React",description:"with @playcanvas/react",color:wt},{name:"web-components",display:"Web Components",description:"with @playcanvas/web-components",color:vt}],W=[{name:"spinning-cube",display:"Spinning Cube",description:"a rotating cube and a light"},{name:"interactive-sphere",display:"Interactive Sphere",description:"orbit controls, a grid and pointer picking"},{name:"model-viewer",display:"Model Viewer",description:"a glTF model, orbit controls and a procedural sky"},{name:"splat-viewer",display:"Splat Viewer",description:"a Gaussian splat and orbit controls"}],Et=async({argBoilerplate:e,yes:t,cancel:r})=>{if(e&&W.some(a=>a.name===e))return e;if(!process.stdout.isTTY||t){if(!e)return W[0].name;throw new Error(`Unknown boilerplate: ${e}. Choose from: ${W.map(a=>a.name).join(", ")}`)}const s=await te({message:e?`"${e}" isn't a valid boilerplate. Please choose from below: `:"Select a boilerplate:",initialValue:W[0].name,options:W.map(a=>({label:a.display,value:a.name,hint:a.description}))});return D(s)&&r(),s},St=async({argTemplate:e,yes:t,cancel:r})=>{if(e&&J.some(a=>a.name===e))return e;if(e&&(!process.stdout.isTTY||t))throw new Error(`Unknown template: ${e}. Choose from: ${J.map(a=>a.name).join(", ")}`);if(t)return J[0].name;const s=await te({message:e?`"${e}" isn't a valid template. Please choose from below: `:"Select a template:",options:J.map(a=>({label:a.color(a.display),value:a.name,hint:a.description}))});return D(s)&&r(),s},Te=e=>/^(?:@[a-z\d\-*~][a-z\d\-*._~]*\/)?[a-z\d\-~][a-z\d\-._~]*$/.test(e),ie=e=>e.trim().toLowerCase().replace(/\s+/g,"-").replace(/^[._]/,"").replace(/[^a-z\d\-~]+/g,"-"),It=async({targetDir:e,yes:t,cancel:r})=>{let s=_.basename(_.resolve(e));if(!Te(s)){if(t)return ie(s);const a=await Ie({message:"Package name:",defaultValue:ie(s),placeholder:ie(s),validate:l=>{if(!l||!Te(l))return"Invalid package.json name"}});if(D(a))return r();s=a}return s},se=e=>e.trim().replace(/\/+$/g,""),Ft=e=>{const t=I.readdirSync(e);return t.length===0||t.length===1&&t[0]===".git"},Tt=e=>{if(I.existsSync(e))for(const t of I.readdirSync(e))t!==".git"&&I.rmSync(_.resolve(e,t),{recursive:!0,force:!0})},Ct=async({argTargetDir:e,defaultTargetDir:t,yes:r,cancel:s})=>{let a=e?se(String(e)):void 0;if(!a&&r)return t;if(!a){const l=await Ie({message:"Project name:",defaultValue:t,placeholder:t});D(l)&&s(),a=se(l)}return a},Rt=async({targetDir:e,argOverwrite:t,yes:r,cancel:s})=>{if(I.existsSync(e)&&!Ft(e)){if(r&&!t)throw new Error(`Target directory "${e}" is not empty. Pass --overwrite to remove its contents.`);const a=t?"yes":await te({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(D(a))return s();switch(a){case"yes":Tt(e);break;case"no":s();return}}},At=e=>{const{cwd:t,targetDir:r,template:s,boilerplate:a,packageName:l,renameFiles:o}=e,n=_.resolve(t,r);I.mkdirSync(n,{recursive:!0});const i=process.env.npm_config_user_agent?.split("/")[0]??"npm";N.step(`Creating project in ${n}...`);const u=Ae(import.meta.url),m=_.dirname(u),h=[_.resolve(m,"../templates"),_.resolve(m,"../../templates")].find(w=>I.existsSync(_.join(w,s)));if(!h)throw new Error(`Template directory not found for: ${s}`);const d=_.join(h,s),f=_.join(h,"_shared",a);I.existsSync(f)&&I.cpSync(f,n,{recursive:!0});for(const w of["base",a]){const C=_.join(d,w);if(!I.existsSync(C))throw new Error(`Boilerplate directory not found: ${s}/${w}`);I.cpSync(C,n,{recursive:!0})}for(const[w,C]of Object.entries(o)){const R=_.join(n,w);I.existsSync(R)&&I.renameSync(R,_.join(n,C))}const p=_.join(n,"package.json"),g=JSON.parse(I.readFileSync(p,"utf-8"));g.name=l,I.writeFileSync(p,JSON.stringify(g,null,4)+`
|
|
44
|
+
`);let b=`Project created. Now run:
|
|
45
|
+
`;const E=_.isAbsolute(r)?n:_.relative(t,n);switch(n!==t&&(b+=`
|
|
46
|
+
cd ${E.includes(" ")?`"${E}"`:E}`),i){case"yarn":b+=`
|
|
47
|
+
yarn`,b+=`
|
|
48
|
+
yarn dev`;break;default:b+=`
|
|
49
|
+
${i} install`,b+=`
|
|
50
|
+
${i} run dev`;break}pt(b)},P=bt(process.argv.slice(2),{alias:{h:"help",t:"template",b:"boilerplate",y:"yes"},boolean:["help","overwrite","yes"],string:["template","boilerplate"]}),kt=process.cwd(),Bt=`Usage: npm create playcanvas@latest [OPTION]...
|
|
51
51
|
|
|
52
52
|
Create a new PlayCanvas project with TypeScript.
|
|
53
53
|
With no arguments, start the CLI in interactive mode.
|
|
54
54
|
|
|
55
55
|
Options:
|
|
56
56
|
-t, --template NAME use a specific template
|
|
57
|
+
-b, --boilerplate NAME use a specific boilerplate
|
|
57
58
|
--overwrite remove existing files from a non-empty target directory
|
|
59
|
+
-y, --yes skip the prompts and take the defaults
|
|
58
60
|
-h, --help show help
|
|
59
|
-
`,
|
|
61
|
+
`,Lt={_gitignore:".gitignore"},Ot="playcanvas-project",Mt=async()=>{const e=P._[0]?se(String(P._[0])):void 0,t=P.template,r=P.boilerplate,s=P.overwrite,a=P.yes;if(P.help){console.log(Bt);return}const l=()=>{dt("Operation cancelled"),process.exit(0)},o=await Ct({argTargetDir:e,defaultTargetDir:Ot,yes:a,cancel:l});await Rt({targetDir:o,argOverwrite:s,yes:a,cancel:l});const n=await It({targetDir:o,yes:a,cancel:l}),i=await St({argTemplate:t,yes:a,cancel:l}),u=await Et({argBoilerplate:r,yes:a,cancel:l});At({cwd:kt,targetDir:o,template:i,boilerplate:u,packageName:n,renameFiles:Lt})};Mt().catch(e=>{console.error(e instanceof Error?e.message:e),process.exitCode=1});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-playcanvas",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Scaffold a PlayCanvas project",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"playcanvas",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"template",
|
|
10
10
|
"vite",
|
|
11
11
|
"react",
|
|
12
|
+
"web-components",
|
|
12
13
|
"typescript",
|
|
13
14
|
"webgl",
|
|
14
15
|
"webgpu",
|
|
Binary file
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# PlayCanvas + TypeScript Starter
|
|
1
|
+
# PlayCanvas Engine + TypeScript Starter
|
|
2
2
|
|
|
3
3
|
A Vite-powered PlayCanvas Engine project with TypeScript, hot module replacement, ESLint and Prettier.
|
|
4
4
|
|
|
@@ -9,13 +9,13 @@ Node.js 22.23.2 or later.
|
|
|
9
9
|
## Getting started
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
npm create playcanvas@latest playcanvas-project -- --template
|
|
12
|
+
npm create playcanvas@latest playcanvas-project -- --template engine
|
|
13
13
|
cd playcanvas-project
|
|
14
14
|
npm install
|
|
15
15
|
npm run dev
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
Open <http://localhost:5173>. Edit `src
|
|
18
|
+
Open <http://localhost:5173>. Edit the files under `src/` and save to see the scene update.
|
|
19
19
|
|
|
20
20
|
## Scripts
|
|
21
21
|
|
|
@@ -28,22 +28,6 @@ Open <http://localhost:5173>. Edit `src/App.ts` to test hot module replacement.
|
|
|
28
28
|
| `npm run fmt` | Check formatting |
|
|
29
29
|
| `npm run typecheck` | Run TypeScript checks |
|
|
30
30
|
|
|
31
|
-
## Project structure
|
|
32
|
-
|
|
33
|
-
```text
|
|
34
|
-
.
|
|
35
|
-
├── public/
|
|
36
|
-
│ └── environment-map.png
|
|
37
|
-
├── src/
|
|
38
|
-
│ ├── assets/
|
|
39
|
-
│ ├── App.ts
|
|
40
|
-
│ ├── main.ts
|
|
41
|
-
│ └── style.css
|
|
42
|
-
├── eslint.config.mjs
|
|
43
|
-
├── index.html
|
|
44
|
-
└── tsconfig.json
|
|
45
|
-
```
|
|
46
|
-
|
|
47
31
|
Run `npm run build` to generate a deployable static site in `dist/`.
|
|
48
32
|
|
|
49
33
|
## Further reading
|
|
@@ -11,3 +11,9 @@ declare module 'playcanvas/scripts/esm/grid.mjs' {
|
|
|
11
11
|
|
|
12
12
|
export const Grid: typeof Script & (new () => Script);
|
|
13
13
|
}
|
|
14
|
+
|
|
15
|
+
declare module 'playcanvas/scripts/esm/sky/procedural-sky.mjs' {
|
|
16
|
+
import type { Script } from 'playcanvas';
|
|
17
|
+
|
|
18
|
+
export const ProceduralSky: typeof Script & (new () => Script);
|
|
19
|
+
}
|
|
@@ -16,7 +16,7 @@ document.querySelector<HTMLDivElement>('#root')!.innerHTML = `
|
|
|
16
16
|
<img src="${playcanvasLogo}" class="playcanvas-logo logo" alt="PlayCanvas logo" />
|
|
17
17
|
</a>
|
|
18
18
|
<a href="https://www.typescriptlang.org/" target="_blank">
|
|
19
|
-
<img src="${typescriptLogo}" class="logo
|
|
19
|
+
<img src="${typescriptLogo}" class="logo typescript" alt="TypeScript logo" />
|
|
20
20
|
</a>
|
|
21
21
|
</header>
|
|
22
22
|
</div>
|
|
@@ -0,0 +1,13 @@
|
|
|
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 + TS</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<canvas id="application-canvas"></canvas>
|
|
11
|
+
<script type="module" src="/src/main.ts"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { ContainerResource } from 'playcanvas';
|
|
2
|
+
import {
|
|
3
|
+
AppBase,
|
|
4
|
+
AppOptions,
|
|
5
|
+
Asset,
|
|
6
|
+
AssetListLoader,
|
|
7
|
+
CameraComponentSystem,
|
|
8
|
+
ContainerHandler,
|
|
9
|
+
Entity,
|
|
10
|
+
FILLMODE_FILL_WINDOW,
|
|
11
|
+
RESOLUTION_AUTO,
|
|
12
|
+
RenderComponentSystem,
|
|
13
|
+
ScriptComponentSystem,
|
|
14
|
+
TONEMAP_ACES2,
|
|
15
|
+
TextureHandler,
|
|
16
|
+
createGraphicsDevice
|
|
17
|
+
} from 'playcanvas';
|
|
18
|
+
import { CameraControls } from 'playcanvas/scripts/esm/camera-controls.mjs';
|
|
19
|
+
import { ProceduralSky } from 'playcanvas/scripts/esm/sky/procedural-sky.mjs';
|
|
20
|
+
|
|
21
|
+
import './style.css';
|
|
22
|
+
|
|
23
|
+
// Swap this for your own model - anything you drop in public/ is served from the site root
|
|
24
|
+
const MODEL_URL = '/playcanvas-cube.glb';
|
|
25
|
+
|
|
26
|
+
const canvas = document.getElementById('application-canvas') as HTMLCanvasElement;
|
|
27
|
+
|
|
28
|
+
const device = await createGraphicsDevice(canvas);
|
|
29
|
+
device.maxPixelRatio = Math.min(window.devicePixelRatio, 2);
|
|
30
|
+
|
|
31
|
+
const createOptions = new AppOptions();
|
|
32
|
+
createOptions.graphicsDevice = device;
|
|
33
|
+
createOptions.componentSystems = [RenderComponentSystem, CameraComponentSystem, ScriptComponentSystem];
|
|
34
|
+
createOptions.resourceHandlers = [TextureHandler, ContainerHandler];
|
|
35
|
+
|
|
36
|
+
const app = new AppBase(canvas);
|
|
37
|
+
app.init(createOptions);
|
|
38
|
+
|
|
39
|
+
// Set the canvas to fill the window and automatically change resolution to be the same as the canvas size
|
|
40
|
+
app.setCanvasFillMode(FILLMODE_FILL_WINDOW);
|
|
41
|
+
app.setCanvasResolution(RESOLUTION_AUTO);
|
|
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
|
+
|
|
50
|
+
// Load the model before starting, so the first frame already has something in it
|
|
51
|
+
const model = new Asset('model', 'container', { url: MODEL_URL });
|
|
52
|
+
|
|
53
|
+
await new Promise<void>((resolve) => {
|
|
54
|
+
new AssetListLoader([model], app.assets).load(() => resolve());
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
app.start();
|
|
58
|
+
|
|
59
|
+
// A container asset holds the whole glTF scene, so instantiate it to get an entity hierarchy
|
|
60
|
+
app.root.addChild((model.resource as ContainerResource).instantiateRenderEntity());
|
|
61
|
+
|
|
62
|
+
// The procedural sky is both the background and the image-based lighting, so no light or
|
|
63
|
+
// environment map asset is needed. Its default luminance is scene-scale bright, so turn it down to
|
|
64
|
+
// keep the model out of clipping
|
|
65
|
+
const sky = new Entity('sky');
|
|
66
|
+
sky.addComponent('script');
|
|
67
|
+
sky.script?.create(ProceduralSky, {
|
|
68
|
+
properties: { luminance: 0.2 }
|
|
69
|
+
});
|
|
70
|
+
app.root.addChild(sky);
|
|
71
|
+
|
|
72
|
+
// Create camera entity with orbit controls. The sky is HDR, so it needs tone mapping to bring it
|
|
73
|
+
// back into displayable range - without it the whole image blows out to white
|
|
74
|
+
const camera = new Entity('camera');
|
|
75
|
+
camera.addComponent('camera', {
|
|
76
|
+
toneMapping: TONEMAP_ACES2
|
|
77
|
+
});
|
|
78
|
+
camera.setPosition(0, 0, 3);
|
|
79
|
+
camera.addComponent('script');
|
|
80
|
+
camera.script?.create(CameraControls);
|
|
81
|
+
app.root.addChild(camera);
|