create-playcanvas 0.5.1 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/README.md +20 -27
  2. package/dist/index.mjs +44 -42
  3. package/package.json +1 -1
  4. package/skills/calibrate-model/references/direct-engine.md +7 -4
  5. package/skills/calibrate-model/references/react.md +8 -3
  6. package/skills/calibrate-model/references/web-components.md +7 -4
  7. package/skills/configure-animation/references/web-components.md +18 -9
  8. package/skills/inspect-glb/SKILL.md +27 -18
  9. package/skills/inspect-glb/scripts/inspect.mjs +179 -50
  10. package/templates/_features/physics/assets/public/ammo/LICENSE +21 -0
  11. package/templates/_features/physics/assets/public/ammo/SOURCE.md +16 -0
  12. package/templates/_features/physics/assets/public/ammo/ammo.js +973 -0
  13. package/templates/_features/physics/assets/public/ammo/ammo.wasm.js +937 -0
  14. package/templates/_features/physics/assets/public/ammo/ammo.wasm.wasm +0 -0
  15. package/templates/_features/physics/react/package.json +5 -0
  16. package/templates/_features/physics/react/src/sync-ammo.d.ts +4 -0
  17. package/templates/_shared/ar-placement/README.md +7 -0
  18. package/templates/_shared/ar-placement/src/ar-placement.ts +123 -0
  19. package/templates/_shared/first-person-controller/README.md +7 -0
  20. package/templates/_shared/first-person-controller/src/controller.ts +18 -0
  21. package/templates/_shared/first-person-controller/src/scripts.d.ts +5 -0
  22. package/templates/_shared/interactive-sphere/README.md +7 -0
  23. package/templates/_shared/model-viewer/README.md +7 -0
  24. package/templates/_shared/physics-playground/README.md +7 -0
  25. package/templates/_shared/product-configurator/ASSET_LICENSES.md +3 -0
  26. package/templates/_shared/product-configurator/README.md +7 -0
  27. package/templates/_shared/product-configurator/src/product.css +14 -0
  28. package/templates/_shared/scene-editor/README.md +7 -0
  29. package/templates/_shared/scene-editor/src/scene-editor.ts +57 -0
  30. package/templates/_shared/spinning-cube/README.md +7 -0
  31. package/templates/_shared/splat-viewer/README.md +7 -0
  32. package/templates/_shared/sprite-game/README.md +7 -0
  33. package/templates/_shared/sprite-game/src/sprite-game.ts +197 -0
  34. package/templates/_shared/third-person-controller/README.md +7 -0
  35. package/templates/_shared/third-person-controller/src/controller.ts +53 -0
  36. package/templates/_shared/third-person-controller/src/scripts.d.ts +5 -0
  37. package/templates/_shared/vr-starter/README.md +7 -0
  38. package/templates/_shared/vr-starter/src/vr.ts +40 -0
  39. package/templates/_shared/vr-starter/src/xr.d.ts +11 -0
  40. package/templates/engine/ar-placement/src/main.ts +77 -0
  41. package/templates/engine/base/.prettierignore +1 -0
  42. package/templates/engine/base/README.md +1 -1
  43. package/templates/engine/base/_npmrc +1 -0
  44. package/templates/engine/base/eslint.config.mjs +1 -1
  45. package/templates/engine/base/index.html +13 -0
  46. package/templates/engine/base/src/starter.css +104 -0
  47. package/templates/engine/first-person-controller/src/main.ts +139 -0
  48. package/templates/engine/interactive-sphere/src/App.ts +9 -7
  49. package/templates/engine/interactive-sphere/src/main.ts +2 -29
  50. package/templates/engine/interactive-sphere/src/style.css +18 -97
  51. package/templates/engine/model-viewer/src/main.ts +3 -2
  52. package/templates/engine/physics-playground/src/main.ts +132 -0
  53. package/templates/engine/product-configurator/src/main.ts +156 -0
  54. package/templates/engine/scene-editor/src/main.ts +90 -0
  55. package/templates/engine/splat-viewer/src/main.ts +4 -3
  56. package/templates/engine/sprite-game/src/main.ts +72 -0
  57. package/templates/engine/third-person-controller/src/main.ts +216 -0
  58. package/templates/engine/vr-starter/src/main.ts +101 -0
  59. package/templates/index.ts +66 -5
  60. package/templates/react/ar-placement/src/App.tsx +58 -0
  61. package/templates/react/base/.prettierignore +1 -0
  62. package/templates/react/base/README.md +1 -1
  63. package/templates/react/base/_npmrc +1 -0
  64. package/templates/react/base/eslint.config.mjs +1 -1
  65. package/templates/react/base/index.html +13 -0
  66. package/templates/react/base/src/main.tsx +10 -0
  67. package/templates/react/base/src/starter.css +104 -0
  68. package/templates/react/first-person-controller/src/App.tsx +115 -0
  69. package/templates/react/interactive-sphere/src/App.css +18 -68
  70. package/templates/react/interactive-sphere/src/App.tsx +1 -22
  71. package/templates/react/interactive-sphere/src/Scene.tsx +7 -6
  72. package/templates/react/interactive-sphere/src/index.css +1 -48
  73. package/templates/react/model-viewer/src/App.tsx +2 -2
  74. package/templates/react/physics-playground/src/App.tsx +85 -0
  75. package/templates/react/product-configurator/src/App.tsx +157 -0
  76. package/templates/react/scene-editor/src/App.tsx +84 -0
  77. package/templates/react/splat-viewer/src/App.tsx +3 -3
  78. package/templates/react/sprite-game/src/App.tsx +38 -0
  79. package/templates/react/third-person-controller/src/App.tsx +193 -0
  80. package/templates/react/vr-starter/src/App.tsx +99 -0
  81. package/templates/web-components/ar-placement/index.html +44 -0
  82. package/templates/web-components/ar-placement/src/main.ts +13 -0
  83. package/templates/web-components/base/.prettierignore +1 -0
  84. package/templates/web-components/base/README.md +1 -1
  85. package/templates/web-components/base/_npmrc +1 -0
  86. package/templates/web-components/base/eslint.config.mjs +1 -1
  87. package/templates/web-components/base/package.json +1 -1
  88. package/templates/web-components/base/src/starter.css +104 -0
  89. package/templates/web-components/first-person-controller/index.html +168 -0
  90. package/templates/web-components/first-person-controller/src/main.ts +15 -0
  91. package/templates/web-components/interactive-sphere/index.html +5 -22
  92. package/templates/web-components/interactive-sphere/src/main.ts +5 -4
  93. package/templates/web-components/interactive-sphere/src/style.css +18 -76
  94. package/templates/web-components/model-viewer/index.html +1 -1
  95. package/templates/web-components/model-viewer/src/main.ts +2 -1
  96. package/templates/web-components/physics-playground/index.html +51 -0
  97. package/templates/web-components/physics-playground/src/main.ts +32 -0
  98. package/templates/web-components/product-configurator/index.html +51 -0
  99. package/templates/web-components/product-configurator/src/main.ts +93 -0
  100. package/templates/web-components/scene-editor/index.html +51 -0
  101. package/templates/web-components/scene-editor/src/main.ts +26 -0
  102. package/templates/web-components/spinning-cube/src/main.ts +1 -0
  103. package/templates/web-components/splat-viewer/index.html +2 -2
  104. package/templates/web-components/splat-viewer/src/main.ts +2 -1
  105. package/templates/web-components/sprite-game/index.html +34 -0
  106. package/templates/web-components/sprite-game/src/main.ts +9 -0
  107. package/templates/web-components/third-person-controller/index.html +183 -0
  108. package/templates/web-components/third-person-controller/src/main.ts +16 -0
  109. package/templates/web-components/vr-starter/index.html +80 -0
  110. package/templates/web-components/vr-starter/src/main.ts +12 -0
  111. package/templates/engine/interactive-sphere/src/assets/typescript.svg +0 -1
  112. package/templates/react/interactive-sphere/src/assets/react.svg +0 -1
  113. package/templates/web-components/interactive-sphere/src/assets/typescript.svg +0 -1
package/README.md CHANGED
@@ -2,14 +2,14 @@
2
2
 
3
3
  [![NPM Version](https://img.shields.io/npm/v/create-playcanvas)](https://www.npmjs.com/package/create-playcanvas)
4
4
  [![NPM Downloads](https://img.shields.io/npm/dw/create-playcanvas)](https://npmtrends.com/create-playcanvas)
5
- [![License](https://img.shields.io/npm/l/create-playcanvas)](https://github.com/playcanvas/create-playcanvas/blob/main/LICENSE)
5
+ [![License](https://img.shields.io/npm/l/create-playcanvas)](LICENSE)
6
6
  [![Discord](https://img.shields.io/badge/Discord-5865F2?style=flat&logo=discord&logoColor=white&color=black)](https://discord.gg/RSaMRzg)
7
7
  [![Reddit](https://img.shields.io/badge/Reddit-FF4500?style=flat&logo=reddit&logoColor=white&color=black)](https://www.reddit.com/r/PlayCanvas)
8
8
  [![X](https://img.shields.io/badge/X-000000?style=flat&logo=x&logoColor=white&color=black)](https://x.com/intent/follow?screen_name=playcanvas)
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, [`@playcanvas/react`](https://github.com/playcanvas/react) or [`@playcanvas/web-components`](https://github.com/playcanvas/web-components).
12
+ Scaffold a Vite-powered PlayCanvas project with TypeScript. Pick a format and a runnable starter, then build from there.
13
13
 
14
14
  ## Getting Started
15
15
 
@@ -26,47 +26,40 @@ bun x create-playcanvas@latest
26
26
 
27
27
  Then follow the prompts. Requires Node.js 22.23.2 or later.
28
28
 
29
- ## Templates
29
+ ## Formats
30
30
 
31
- | Template | Description |
31
+ | Format | Description |
32
32
  | ---------------- | -------------------------------------------- |
33
33
  | `engine` | The PlayCanvas Engine API directly |
34
34
  | `react` | `@playcanvas/react` components |
35
35
  | `web-components` | `@playcanvas/web-components` custom elements |
36
36
 
37
- Every template is TypeScript, and includes Vite, ESLint, Prettier and a production build.
37
+ Every format uses TypeScript and includes Vite, ESLint, Prettier and a production build.
38
38
 
39
- ## Boilerplates
39
+ ## Starters
40
40
 
41
- Each template offers a choice of starting scene. `spinning-cube` is the default.
41
+ Choose from 12 starter kits across basics, viewers, games, tools and XR. Run the creator to browse them; `spinning-cube` is the default.
42
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
+ ![The twelve PlayCanvas starter scenes](images/starter-catalog.webp)
51
44
 
52
45
  ## CLI Options
53
46
 
54
- Pass a project name, template and boilerplate to skip the prompts:
47
+ Pass a project name and options to skip the prompts:
55
48
 
56
49
  ```bash
57
- npm create playcanvas@latest my-game -- --template react --boilerplate spinning-cube
50
+ npm create playcanvas@latest my-game -- -f react -y
58
51
  ```
59
52
 
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
- | `--no-skills` | | Omit the PlayCanvas agent skills (included by default) |
66
- | `--yes` | `-y` | Skip the prompts and take the defaults |
67
- | `--help` | `-h` | Show command help |
53
+ | Option | Shorthand | Description |
54
+ | ------------------ | --------- | ------------------------------------------------------- |
55
+ | `--format <name>` | `-f` | Use a format from the list above |
56
+ | `--starter <name>` | `-s` | Use a starter from the list above |
57
+ | `--overwrite` | | Remove existing files from a non-empty target directory |
58
+ | `--no-skills` | | Omit the PlayCanvas agent skills (included by default) |
59
+ | `--yes` | `-y` | Skip the prompts and take the defaults |
60
+ | `--help` | `-h` | Show command help |
68
61
 
69
- `--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`.
62
+ `--yes` takes `playcanvas-project`, the `engine` format and the `spinning-cube` starter for anything you don't pass. It never deletes files, so a non-empty target directory still needs `--overwrite`. The previous `--template` and `--boilerplate` long flags remain accepted for compatibility.
70
63
 
71
64
  ## Agent skills
72
65
 
@@ -80,7 +73,7 @@ npm run build
80
73
  node dist/index.mjs
81
74
  ```
82
75
 
83
- Contributions are welcome. Please open an issue before proposing a new template or another substantial change.
76
+ Contributions are welcome. Please open an issue before proposing a new format, starter or another substantial change.
84
77
 
85
78
  ## License
86
79
 
package/dist/index.mjs CHANGED
@@ -1,62 +1,64 @@
1
1
  #!/usr/bin/env node
2
- import{styleText as u}from"node:util";import A,{stdin as Ce,stdout as ae}from"node:process";import Re from"node:readline";import"node:tty";import _ from"node:fs";import y from"node:path";import{fileURLToPath as ke}from"node:url";const Ae=(()=>{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,n=t.ellipsis??"",l=t?.ellipsisWidth??(n?ce(n,De,r).width:0),a=0,o=r.controlWidth??0,i=r.tabWidth??8,c=r.emojiWidth??2,d=2,h=r.regularWidth??1,m=r.wideWidth??d,f=[[Pe,h],[Oe,a],[Me,o],[Ne,i],[le,c],[oe,m]];let p=0,g=0,S=e.length,w=0,T=!1,v=S,I=Math.max(0,s-l),b=0,E=0,x=0,F=0;e:for(;;){if(E>b||g>=S&&g>p){const C=e.slice(b,E)||e.slice(p,g);w=0;for(const N of C.replaceAll(je,"")){const R=N.codePointAt(0)||0;if(Be(R)?F=d:Le(R)?F=m:F=h,x+F>I&&(v=Math.min(v,Math.max(b,p)+w)),x+F>s){T=!0;break e}w+=N.length,x+=F}b=E=0}if(g>=S)break e;for(let C=0,N=f.length;C<N;C++){const[R,ne]=f[C];if(R.lastIndex=g,R.test(e)){if(w=R===oe?Ae(e.slice(g,R.lastIndex)):R===le?1:R.lastIndex-g,F=w*ne,x+F>I&&(v=Math.min(v,g+Math.floor((I-x)/ne))),x+F>s){T=!0;break e}x+=F,b=p,E=g,g=p=R.lastIndex;continue e}}g+=1}return{width:T?I:x,index:T?v:S,truncated:T,ellipsed:T&&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 n=!1,l=!1,a=e.at(-1),o=a===void 0?0:L(a),i=s.next(),c=s.next(),d=0;for(;!i.done;){const h=i.value,m=L(h);o+m<=r?e[e.length-1]+=h:(e.push(h),o=0),(h===V||h===ue)&&(n=!0,l=t.startsWith(q,d+1)),n?l?h===Y&&(n=!1,l=!1):h===me&&(n=!1):(o+=m,o===r&&!c.done&&(e.push(""),o=0)),i=c,c=s.next(),d+=h.length}a=e.at(-1),!o&&a!==void 0&&a.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="",n,l;const a=e.split(" ");let o=[""],i=0;for(let h=0;h<a.length;h++){const m=a[h];if(r.trim!==!1){const p=o.at(-1)??"",g=p.trimStart();p.length!==g.length&&(o[o.length-1]=g,i=L(g))}h!==0&&(i>=t&&(r.wordWrap===!1||r.trim===!1)&&(o.push(""),i=0),(i||r.trim===!1)&&(o[o.length-1]+=" ",i++));const f=L(m);if(r.hard&&f>t){const p=t-i,g=1+Math.floor((f-p-1)/t);Math.floor((f-1)/t)<g&&o.push(""),X(o,m,t),i=L(o.at(-1)??"");continue}if(i+f>t&&i&&f){if(r.wordWrap===!1&&i<t){X(o,m,t),i=L(o.at(-1)??"");continue}o.push(""),i=0}if(i+f>t&&r.wordWrap===!1){X(o,m,t),i=L(o.at(-1)??"");continue}o[o.length-1]+=m,i+=f}r.trim!==!1&&(o=o.map(h=>Ge(h)));const c=o.join(`
3
- `);let d=!1;for(let h=0;h<c.length;h++){const m=c[h];if(s+=m,d)d=!1;else if(d=m>="\uD800"&&m<="\uDBFF",d)continue;if(m===V||m===ue){de.lastIndex=h+1;const p=de.exec(c)?.groups;if(p?.code!==void 0){const g=Number.parseFloat(p.code);n=g===Ve?void 0:g}else p?.uri!==void 0&&(l=p.uri.length===0?void 0:p.uri)}if(c[h+1]===`
4
- `){l&&(s+=ge(""));const f=n?pe(n):void 0;n&&f&&(s+=fe(f))}else m===`
5
- `&&(n&&pe(n)&&(s+=fe(n)),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(a,o){return o?`${t}${o+1};${a+1}H`:`${t}${a+1}G`},move(a,o){let i="";return a<0?i+=`${t}${-a}D`:a>0&&(i+=`${t}${a}C`),o<0?i+=`${t}${-o}A`:o>0&&(i+=`${t}${o}B`),i},up:(a=1)=>`${t}${a}A`,down:(a=1)=>`${t}${a}B`,forward:(a=1)=>`${t}${a}C`,backward:(a=1)=>`${t}${a}D`,nextLine:(a=1)=>`${t}E`.repeat(a),prevLine:(a=1)=>`${t}F`.repeat(a),left:`${t}G`,hide:`${t}?25l`,show:`${t}?25h`,save:`${e}7`,restore:`${e}8`},n={up:(a=1)=>`${t}S`.repeat(a),down:(a=1)=>`${t}T`.repeat(a)},l={screen:`${t}2J`,up:(a=1)=>`${t}1J`.repeat(a),down:(a=1)=>`${t}J`.repeat(a),line:`${t}2K`,lineEnd:`${t}K`,lineStart:`${t}1K`,lines(a){let o="";for(let i=0;i<a;i++)o+=this.line+(i<a-1?s.up():"");return a&&(o+=s.left),o}};return Z={cursor:s,scroll:n,erase:l,beep:r},Z}var B=Je();function G(e,t,r){if(!r.some(a=>!a.disabled))return e;const s=e+t,n=Math.max(r.length-1,0),l=s<0?n:s>n?0:s;return r[l]?.disabled?G(l,t<0?-1:1,r):l}const Ye=["up","down","left","right","space","enter","cancel"],P={actions:new Set(Ye),aliases:new Map([["k","up"],["j","down"],["h","left"],["l","right"],["","cancel"],["escape","cancel"]]),withGuide:!0};function ye(e,t){if(typeof e=="string")return P.aliases.get(e)===t;for(const r of e)if(r!==void 0&&ye(r,t))return!0;return!1}function qe(e,t){if(e===t)return;const r=e.split(`
7
- `),s=t.split(`
8
- `),n=Math.max(r.length,s.length),l=[];for(let a=0;a<n;a++)r[a]!==s[a]&&l.push(a);return{lines:l,numLinesBefore:r.length,numLinesAfter:s.length,numLines:n}}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 xe=e=>"columns"in e&&typeof e.columns=="number"?e.columns:80,$e=e=>"rows"in e&&typeof e.rows=="number"?e.rows:20;function ee(e,t,r,s=r,n=r,l){const a=xe(e??ae);return U(t,a-r.length,{hard:!0,trim:!1}).split(`
9
- `).map((o,i,c)=>{const d=o;return i===0?`${s}${d}`:i===c.length-1?`${n}${d}`:`${r}${d}`}).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:n=ae,render:l,signal:a,...o}=t;this.opts=o,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=a,this.input=s,this.output=n}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)??[],n=[];for(const l of s)l.cb(...r),l.once&&n.push(()=>s.splice(s.indexOf(l),1));for(const l of n)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&&P.aliases.has(r.name)&&this.emit("cursor",P.aliases.get(r.name)),P.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")}ye([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=$e(this.output);if(this.restoreCursor(),r){const n=Math.max(0,r.numLinesAfter-s),l=Math.max(0,r.numLinesBefore-s);let a=r.lines.find(o=>o>=n);if(a===void 0){this._prevFrame=t;return}if(r.lines.length===1){this.output.write(B.cursor.move(0,a-l)),this.output.write(B.erase.lines(1));const o=t.split(`
13
- `);this.output.write(o[a]),this._prevFrame=t,this.output.write(B.cursor.move(0,o.length-a-1));return}else if(r.lines.length>1){if(n<l)a=n;else{const i=a-l;i>0&&this.output.write(B.cursor.move(0,i))}this.output.write(B.erase.down());const o=t.split(`
2
+ import{styleText as u}from"node:util";import M,{stdin as Pe,stdout as he}from"node:process";import Le from"node:readline";import"node:tty";import x from"node:fs";import y from"node:path";import{fileURLToPath as Ne}from"node:url";const De=(()=>{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}})(),We=e=>e===12288||e>=65281&&e<=65376||e>=65504&&e<=65510,Ve=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,Ue=/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y,Ge=/[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y,me=/(?:(?![\uFF61-\uFF9F\uFF00-\uFFEF])[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Tangut}]){1,1000}/yu,Ke=/\t{1,1000}/y,de=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"),He=/(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y,ze=new RegExp("\\p{M}+","gu"),Je={limit:1/0,ellipsis:""},fe=(e,t={},r={})=>{const i=t.limit??1/0,n=t.ellipsis??"",c=t?.ellipsisWidth??(n?fe(n,Je,r).width:0),a=0,o=r.controlWidth??0,s=r.tabWidth??8,l=r.emojiWidth??2,d=2,h=r.regularWidth??1,m=r.wideWidth??d,p=[[He,h],[Ue,a],[Ge,o],[Ke,s],[de,l],[me,m]];let f=0,b=0,F=e.length,C=0,O=!1,B=F,k=Math.max(0,i-c),w=0,S=0,$=0,E=0;e:for(;;){if(S>w||b>=F&&b>f){const _=e.slice(w,S)||e.slice(f,b);C=0;for(const R of _.replaceAll(ze,"")){const I=R.codePointAt(0)||0;if(We(I)?E=d:Ve(I)?E=m:E=h,$+E>k&&(B=Math.min(B,Math.max(w,f)+C)),$+E>i){O=!0;break e}C+=R.length,$+=E}w=S=0}if(b>=F)break e;for(let _=0,R=p.length;_<R;_++){const[I,g]=p[_];if(I.lastIndex=b,I.test(e)){if(C=I===me?De(e.slice(b,I.lastIndex)):I===de?1:I.lastIndex-b,E=C*g,$+E>k&&(B=Math.min(B,b+Math.floor((k-$)/g))),$+E>i){O=!0;break e}$+=E,w=f,S=b,b=f=I.lastIndex;continue e}}b+=1}return{width:O?k:$,index:O?B:F,truncated:O,ellipsed:O&&i>=c}},Ye={limit:1/0,ellipsis:"",ellipsisWidth:0},N=(e,t={})=>fe(e,Ye,t).width,z="\x1B",pe="\x9B",qe=39,ee="\x07",ge="[",Xe="]",be="m",te=`${Xe}8;;`,ye=new RegExp(`(?:\\${ge}(?<code>\\d+)m|\\${te}(?<uri>.*)${ee})`,"y"),xe=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},$e=e=>`${z}${ge}${e}${be}`,we=e=>`${z}${te}${e}${ee}`,re=(e,t,r)=>{const i=t[Symbol.iterator]();let n=!1,c=!1,a=e.at(-1),o=a===void 0?0:N(a),s=i.next(),l=i.next(),d=0;for(;!s.done;){const h=s.value,m=N(h);o+m<=r?e[e.length-1]+=h:(e.push(h),o=0),(h===z||h===pe)&&(n=!0,c=t.startsWith(te,d+1)),n?c?h===ee&&(n=!1,c=!1):h===be&&(n=!1):(o+=m,o===r&&!l.done&&(e.push(""),o=0)),s=l,l=i.next(),d+=h.length}a=e.at(-1),!o&&a!==void 0&&a.length&&e.length>1&&(e[e.length-2]+=e.pop())},Ze=e=>{const t=e.split(" ");let r=t.length;for(;r&&!N(t[r-1]);)r--;return r===t.length?e:t.slice(0,r).join(" ")+t.slice(r).join("")},Qe=(e,t,r={})=>{if(r.trim!==!1&&e.trim()==="")return"";let i="",n,c;const a=e.split(" ");let o=[""],s=0;for(let h=0;h<a.length;h++){const m=a[h];if(r.trim!==!1){const f=o.at(-1)??"",b=f.trimStart();f.length!==b.length&&(o[o.length-1]=b,s=N(b))}h!==0&&(s>=t&&(r.wordWrap===!1||r.trim===!1)&&(o.push(""),s=0),(s||r.trim===!1)&&(o[o.length-1]+=" ",s++));const p=N(m);if(r.hard&&p>t){const f=t-s,b=1+Math.floor((p-f-1)/t);Math.floor((p-1)/t)<b&&o.push(""),re(o,m,t),s=N(o.at(-1)??"");continue}if(s+p>t&&s&&p){if(r.wordWrap===!1&&s<t){re(o,m,t),s=N(o.at(-1)??"");continue}o.push(""),s=0}if(s+p>t&&r.wordWrap===!1){re(o,m,t),s=N(o.at(-1)??"");continue}o[o.length-1]+=m,s+=p}r.trim!==!1&&(o=o.map(h=>Ze(h)));const l=o.join(`
3
+ `);let d=!1;for(let h=0;h<l.length;h++){const m=l[h];if(i+=m,d)d=!1;else if(d=m>="\uD800"&&m<="\uDBFF",d)continue;if(m===z||m===pe){ye.lastIndex=h+1;const f=ye.exec(l)?.groups;if(f?.code!==void 0){const b=Number.parseFloat(f.code);n=b===qe?void 0:b}else f?.uri!==void 0&&(c=f.uri.length===0?void 0:f.uri)}if(l[h+1]===`
4
+ `){c&&(i+=we(""));const p=n?xe(n):void 0;n&&p&&(i+=$e(p))}else m===`
5
+ `&&(n&&xe(n)&&(i+=$e(n)),c&&(i+=we(c)))}return i},et=/\r?\n/;function J(e,t,r){return String(e).normalize().split(et).map(i=>Qe(i,t,r)).join(`
6
+ `)}function tt(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var se,ve;function rt(){if(ve)return se;ve=1;const e="\x1B",t=`${e}[`,r="\x07",i={to(a,o){return o?`${t}${o+1};${a+1}H`:`${t}${a+1}G`},move(a,o){let s="";return a<0?s+=`${t}${-a}D`:a>0&&(s+=`${t}${a}C`),o<0?s+=`${t}${-o}A`:o>0&&(s+=`${t}${o}B`),s},up:(a=1)=>`${t}${a}A`,down:(a=1)=>`${t}${a}B`,forward:(a=1)=>`${t}${a}C`,backward:(a=1)=>`${t}${a}D`,nextLine:(a=1)=>`${t}E`.repeat(a),prevLine:(a=1)=>`${t}F`.repeat(a),left:`${t}G`,hide:`${t}?25l`,show:`${t}?25h`,save:`${e}7`,restore:`${e}8`},n={up:(a=1)=>`${t}S`.repeat(a),down:(a=1)=>`${t}T`.repeat(a)},c={screen:`${t}2J`,up:(a=1)=>`${t}1J`.repeat(a),down:(a=1)=>`${t}J`.repeat(a),line:`${t}2K`,lineEnd:`${t}K`,lineStart:`${t}1K`,lines(a){let o="";for(let s=0;s<a;s++)o+=this.line+(s<a-1?i.up():"");return a&&(o+=i.left),o}};return se={cursor:i,scroll:n,erase:c,beep:r},se}var P=rt();function Y(e,t,r){if(!r.some(a=>!a.disabled))return e;const i=e+t,n=Math.max(r.length-1,0),c=i<0?n:i>n?0:i;return r[c]?.disabled?Y(c,t<0?-1:1,r):c}const st=["up","down","left","right","space","enter","cancel"],W={actions:new Set(st),aliases:new Map([["k","up"],["j","down"],["h","left"],["l","right"],["","cancel"],["escape","cancel"]]),withGuide:!0};function Se(e,t){if(typeof e=="string")return W.aliases.get(e)===t;for(const r of e)if(r!==void 0&&Se(r,t))return!0;return!1}function it(e,t){if(e===t)return;const r=e.split(`
7
+ `),i=t.split(`
8
+ `),n=Math.max(r.length,i.length),c=[];for(let a=0;a<n;a++)r[a]!==i[a]&&c.push(a);return{lines:c,numLinesBefore:r.length,numLinesAfter:i.length,numLines:n}}globalThis.process.platform.startsWith("win");const ie=Symbol("clack:cancel");function K(e){return e===ie}function q(e,t){const r=e;r.isTTY&&r.setRawMode(t)}const Ee=e=>"columns"in e&&typeof e.columns=="number"?e.columns:80,_e=e=>"rows"in e&&typeof e.rows=="number"?e.rows:20;function ne(e,t,r,i=r,n=r,c){const a=Ee(e??he);return J(t,a-r.length,{hard:!0,trim:!1}).split(`
9
+ `).map((o,s,l)=>{const d=o;return s===0?`${i}${d}`:s===l.length-1?`${n}${d}`:`${r}${d}`}).join(`
10
+ `)}function nt(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 Ie{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:i=Pe,output:n=he,render:c,signal:a,...o}=t;this.opts=o,this.onKeypress=this.onKeypress.bind(this),this.close=this.close.bind(this),this.render=this.render.bind(this),this._render=c.bind(this),this._track=r,this._abortSignal=a,this.input=i,this.output=n}unsubscribe(){this._subscribers.clear()}setSubscriber(t,r){const i=this._subscribers.get(t)??[];i.push(r),this._subscribers.set(t,i)}on(t,r){this.setSubscriber(t,{cb:r})}once(t,r){this.setSubscriber(t,{cb:r,once:!0})}emit(t,...r){const i=this._subscribers.get(t)??[],n=[];for(const c of i)c.cb(...r),c.once&&n.push(()=>i.splice(i.indexOf(c),1));for(const c of n)c()}prompt(){return new Promise(t=>{if(this._abortSignal){if(this._abortSignal.aborted)return this.state="cancel",this.close(),t(ie);this._abortSignal.addEventListener("abort",()=>{this.state="cancel",this.close()},{once:!0})}this.rl=Le.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),q(this.input,!0),this.output.on("resize",this.render),this.render(),this.once("submit",()=>{this.output.write(P.cursor.show),this.output.off("resize",this.render),q(this.input,!1),t(this.value)}),this.once("cancel",()=>{this.output.write(P.cursor.show),this.output.off("resize",this.render),q(this.input,!1),t(ie)})})}_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&&W.aliases.has(r.name)&&this.emit("cursor",W.aliases.get(r.name)),W.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 i=nt(this.opts.validate,this.value);i&&(this.error=i instanceof Error?i.message:i,this.state="error",this.rl?.write(this.userInput))}this.state!=="error"&&(this.state="submit")}Se([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
+ `),q(this.input,!1),this.rl?.close(),this.rl=void 0,this.emit(`${this.state}`,this.value),this.unsubscribe()}restoreCursor(){const t=J(this._prevFrame,process.stdout.columns,{hard:!0,trim:!1}).split(`
12
+ `).length-1;this.output.write(P.cursor.move(-999,t*-1))}render(){const t=J(this._render(this)??"",process.stdout.columns,{hard:!0,trim:!1});if(t!==this._prevFrame){if(this.state==="initial")this.output.write(P.cursor.hide);else{const r=it(this._prevFrame,t),i=_e(this.output);if(this.restoreCursor(),r){const n=Math.max(0,r.numLinesAfter-i),c=Math.max(0,r.numLinesBefore-i);let a=r.lines.find(o=>o>=n);if(a===void 0){this._prevFrame=t;return}if(r.lines.length===1){this.output.write(P.cursor.move(0,a-c)),this.output.write(P.erase.lines(1));const o=t.split(`
13
+ `);this.output.write(o[a]),this._prevFrame=t,this.output.write(P.cursor.move(0,o.length-a-1));return}else if(r.lines.length>1){if(n<c)a=n;else{const s=a-c;s>0&&this.output.write(P.cursor.move(0,s))}this.output.write(P.erase.down());const o=t.split(`
14
14
  `).slice(a);this.output.write(o.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:n})=>n===t.initialValue),s=r===-1?0:r;this.cursor=this.options[s]?.disabled?G(s,1,this.options):s,this.changeValue(),this.on("cursor",n=>{switch(n){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),n=t.slice(this.cursor+1);return`${r}${u("inverse",s)}${n}`}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 A.platform!=="win32"?A.env.TERM!=="linux":!!A.env.CI||!!A.env.WT_SESSION||!!A.env.TERMINUS_SUBLIME||A.env.ConEmuTask==="{cmd::Cmder}"||A.env.TERM_PROGRAM==="Terminus-Sublime"||A.env.TERM_PROGRAM==="vscode"||A.env.TERM==="xterm-256color"||A.env.TERM==="alacritty"||A.env.TERMINAL_EMULATOR==="JetBrains-JediTerm"}const tt=et(),k=(e,t)=>tt?e:t,rt=k("\u25C6","*"),it=k("\u25A0","x"),st=k("\u25B2","x"),ve=k("\u25C7","o"),$=k("\u2502","|"),j=k("\u2514","\u2014"),nt=k("\u25CF",">"),Ee=k("\u25CB"," "),at=k("\u25CF","\u2022"),ot=k("\u25C6","*"),lt=k("\u25B2","!"),ct=k("\u25A0","x"),_e=e=>{switch(e){case"initial":case"active":return u("cyan",rt);case"cancel":return u("red",it);case"error":return u("yellow",st);case"submit":return u("green",ve)}},ut=e=>{switch(e){case"initial":case"active":return u("cyan",$);case"cancel":return u("red",$);case"error":return u("yellow",$);case"submit":return u("green",$)}};function ht(e,t){const r=[`${t?`${u("cyan",$)} `:""}${e.join(" \u2022 ")}`];return t&&r.push(u("cyan",j)),r}const Se=(e,t,r,s,n,l=!1)=>{let a=t,o=0;if(l)for(let i=s-1;i>=r;i--){const c=e[i];if(c&&(a-=c.length),o++,a<=n)break}else for(let i=r;i<s;i++){const c=e[i];if(c&&(a-=c.length),o++,a<=n)break}return{lineCount:a,removals:o}},mt=({cursor:e,options:t,style:r,output:s=process.stdout,maxItems:n=Number.POSITIVE_INFINITY,columnPadding:l=0,rowPadding:a=4})=>{const o=xe(s)-l,i=$e(s),c=u("dim","..."),d=Math.max(i-a,0),h=Math.max(Math.min(n,d),5);let m=0;e>=h-3&&(m=Math.max(Math.min(e-h+3,t.length-h),0));let f=h<t.length&&m>0,p=h<t.length&&m+h<t.length;const g=Math.min(m+h,t.length),S=[];let w=0;f&&w++,p&&w++;const T=m+(f?1:0),v=g-(p?1:0);for(let b=T;b<v;b++){const E=t[b],x=E?r(E,b===e):"",F=U(x,o,{hard:!0,trim:!1}).split(`
16
- `);S.push(F),w+=F.length}if(w>d){let b=0,E=0,x=w;const F=e-T;let C=d;const N=()=>Se(S,x,0,F,C),R=()=>Se(S,x,F+1,S.length,C,!0);f?({lineCount:x,removals:b}=N(),x>C&&(p||(C-=1),{lineCount:x,removals:E}=R())):(p||(C-=1),{lineCount:x,removals:E}=R(),x>C&&(C-=1,{lineCount:x,removals:b}=N())),b>0&&(f=!0,S.splice(0,b)),E>0&&(p=!0,S.splice(S.length-E,E))}const I=[];f&&I.push(c);for(const b of S)for(const E of b)I.push(E);return p&&I.push(c),I};`${u("dim","\u2191/\u2193")}`,`${u("dim","Space:")}`,`${u("dim","Enter:")}`;const O={message:(e=[],{symbol:t=u("gray",$),secondarySymbol:r=u("gray",$),output:s=process.stdout,spacing:n=1,withGuide:l}={})=>{const a=[],o=l??P.withGuide,i=o?r:"",c=o?`${t} `:"",d=o?`${r} `:"";for(let m=0;m<n;m++)a.push(i);const h=Array.isArray(e)?e:e.split(`
17
- `);if(h.length>0){const[m,...f]=h;m.length>0?a.push(`${c}${m}`):a.push(o?t:"");for(const p of f)p.length>0?a.push(`${d}${p}`):a.push(o?r:"")}s.write(`${a.join(`
15
+ `)),this._prevFrame=t;return}}this.output.write(P.erase.down())}this.output.write(t),this.state==="initial"&&(this.state="active"),this._prevFrame=t}}}let at=class extends Ie{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:n})=>n===t.initialValue),i=r===-1?0:r;this.cursor=this.options[i]?.disabled?Y(i,1,this.options):i,this.changeValue(),this.on("cursor",n=>{switch(n){case"left":case"up":this.cursor=Y(this.cursor,-1,this.options);break;case"down":case"right":this.cursor=Y(this.cursor,1,this.options);break}this.changeValue()})}};class ot extends Ie{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),i=t.slice(this.cursor,this.cursor+1),n=t.slice(this.cursor+1);return`${r}${u("inverse",i)}${n}`}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 ct(){return M.platform!=="win32"?M.env.TERM!=="linux":!!M.env.CI||!!M.env.WT_SESSION||!!M.env.TERMINUS_SUBLIME||M.env.ConEmuTask==="{cmd::Cmder}"||M.env.TERM_PROGRAM==="Terminus-Sublime"||M.env.TERM_PROGRAM==="vscode"||M.env.TERM==="xterm-256color"||M.env.TERM==="alacritty"||M.env.TERMINAL_EMULATOR==="JetBrains-JediTerm"}const lt=ct(),j=(e,t)=>lt?e:t,ut=j("\u25C6","*"),ht=j("\u25A0","x"),mt=j("\u25B2","x"),Fe=j("\u25C7","o"),v=j("\u2502","|"),U=j("\u2514","\u2014"),dt=j("\u25CF",">"),Te=j("\u25CB"," "),ft=j("\u25CF","\u2022"),pt=j("\u25C6","*"),gt=j("\u25B2","!"),bt=j("\u25A0","x"),Ce=e=>{switch(e){case"initial":case"active":return u("cyan",ut);case"cancel":return u("red",ht);case"error":return u("yellow",mt);case"submit":return u("green",Fe)}},yt=e=>{switch(e){case"initial":case"active":return u("cyan",v);case"cancel":return u("red",v);case"error":return u("yellow",v);case"submit":return u("green",v)}};function xt(e,t){const r=[`${t?`${u("cyan",v)} `:""}${e.join(" \u2022 ")}`];return t&&r.push(u("cyan",U)),r}const Re=(e,t,r,i,n,c=!1)=>{let a=t,o=0;if(c)for(let s=i-1;s>=r;s--){const l=e[s];if(l&&(a-=l.length),o++,a<=n)break}else for(let s=r;s<i;s++){const l=e[s];if(l&&(a-=l.length),o++,a<=n)break}return{lineCount:a,removals:o}},$t=({cursor:e,options:t,style:r,output:i=process.stdout,maxItems:n=Number.POSITIVE_INFINITY,columnPadding:c=0,rowPadding:a=4})=>{const o=Ee(i)-c,s=_e(i),l=u("dim","..."),d=Math.max(s-a,0),h=Math.max(Math.min(n,d),5);let m=0;e>=h-3&&(m=Math.max(Math.min(e-h+3,t.length-h),0));let p=h<t.length&&m>0,f=h<t.length&&m+h<t.length;const b=Math.min(m+h,t.length),F=[];let C=0;p&&C++,f&&C++;const O=m+(p?1:0),B=b-(f?1:0);for(let w=O;w<B;w++){const S=t[w],$=S?r(S,w===e):"",E=J($,o,{hard:!0,trim:!1}).split(`
16
+ `);F.push(E),C+=E.length}if(C>d){let w=0,S=0,$=C;const E=e-O;let _=d;const R=()=>Re(F,$,0,E,_),I=()=>Re(F,$,E+1,F.length,_,!0);p?({lineCount:$,removals:w}=R(),$>_&&(f||(_-=1),{lineCount:$,removals:S}=I())):(f||(_-=1),{lineCount:$,removals:S}=I(),$>_&&(_-=1,{lineCount:$,removals:w}=R())),w>0&&(p=!0,F.splice(0,w)),S>0&&(f=!0,F.splice(F.length-S,S))}const k=[];p&&k.push(l);for(const w of F)for(const S of w)k.push(S);return f&&k.push(l),k};`${u("dim","\u2191/\u2193")}`,`${u("dim","Space:")}`,`${u("dim","Enter:")}`;const D={message:(e=[],{symbol:t=u("gray",v),secondarySymbol:r=u("gray",v),output:i=process.stdout,spacing:n=1,withGuide:c}={})=>{const a=[],o=c??W.withGuide,s=o?r:"",l=o?`${t} `:"",d=o?`${r} `:"";for(let m=0;m<n;m++)a.push(s);const h=Array.isArray(e)?e:e.split(`
17
+ `);if(h.length>0){const[m,...p]=h;m.length>0?a.push(`${l}${m}`):a.push(o?t:"");for(const f of p)f.length>0?a.push(`${d}${f}`):a.push(o?r:"")}i.write(`${a.join(`
18
18
  `)}
19
- `)},info:(e,t)=>{O.message(e,{...t,symbol:u("blue",at)})},success:(e,t)=>{O.message(e,{...t,symbol:u("green",ot)})},step:(e,t)=>{O.message(e,{...t,symbol:u("green",ve)})},warn:(e,t)=>{O.message(e,{...t,symbol:u("yellow",lt)})},warning:(e,t)=>{O.warn(e,t)},error:(e,t)=>{O.message(e,{...t,symbol:u("red",ct)})}},dt=(e="",t)=>{const r=process.stdout,s=`${u("gray",j)} `;r.write(`${s}${u("red",e)}
19
+ `)},info:(e,t)=>{D.message(e,{...t,symbol:u("blue",ft)})},success:(e,t)=>{D.message(e,{...t,symbol:u("green",pt)})},step:(e,t)=>{D.message(e,{...t,symbol:u("green",Fe)})},warn:(e,t)=>{D.message(e,{...t,symbol:u("yellow",gt)})},warning:(e,t)=>{D.warn(e,t)},error:(e,t)=>{D.message(e,{...t,symbol:u("red",bt)})}},wt=(e="",t)=>{const r=process.stdout,i=`${u("gray",U)} `;r.write(`${i}${u("red",e)}
20
20
 
21
- `)},pt=(e="",t)=>{const r=process.stdout,s=`${u("gray",$)}
22
- ${u("gray",j)} `;r.write(`${s}${e}
21
+ `)},vt=(e="",t)=>{const r=process.stdout,i=`${u("gray",v)}
22
+ ${u("gray",U)} `;r.write(`${i}${e}
23
23
 
24
- `)},ft=[`${u("dim","\u2191/\u2193")} to navigate`,`${u("dim","Enter:")} confirm`],H=(e,t)=>e.includes(`
24
+ `)},St=[`${u("dim","\u2191/\u2193")} to navigate`,`${u("dim","Enter:")} confirm`],X=(e,t)=>e.includes(`
25
25
  `)?e.split(`
26
26
  `).map(r=>t(r)).join(`
27
- `):t(e),te=e=>{const t=(s,n)=>{if(s===void 0)return"";const l=s.label??String(s.value);switch(n){case"disabled":return`${u("gray",Ee)} ${H(l,a=>u("gray",a))}${s.hint?` ${u("dim",`(${s.hint??"disabled"})`)}`:""}`;case"selected":return`${H(l,a=>u("dim",a))}`;case"active":return`${u("green",nt)} ${l}${s.hint?` ${u("dim",`(${s.hint})`)}`:""}`;case"cancelled":return`${H(l,a=>u(["strikethrough","dim"],a))}`;default:return`${u("dim",Ee)} ${H(l,a=>u("dim",a))}`}},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??P.withGuide,n=`${_e(this.state)} `,l=`${ut(this.state)} `,a=ee(e.output,e.message,l,n),o=`${s?`${u("gray",$)}
27
+ `):t(e),ae=e=>{const t=(i,n)=>{if(i===void 0)return"";const c=i.label??String(i.value);switch(n){case"disabled":return`${u("gray",Te)} ${X(c,a=>u("gray",a))}${i.hint?` ${u("dim",`(${i.hint??"disabled"})`)}`:""}`;case"selected":return`${X(c,a=>u("dim",a))}`;case"active":return`${u("green",dt)} ${c}${i.hint?` ${u("dim",`(${i.hint})`)}`:""}`;case"cancelled":return`${X(c,a=>u(["strikethrough","dim"],a))}`;default:return`${u("dim",Te)} ${X(c,a=>u("dim",a))}`}},r=e.showInstructions??!0;return new at({options:e.options,signal:e.signal,input:e.input,output:e.output,initialValue:e.initialValue,render(){const i=e.withGuide??W.withGuide,n=`${Ce(this.state)} `,c=`${yt(this.state)} `,a=ne(e.output,e.message,c,n),o=`${i?`${u("gray",v)}
28
28
  `:""}${a}
29
- `;switch(this.state){case"submit":{const i=s?`${u("gray",$)} `:"",c=ee(e.output,t(this.options[this.cursor],"selected"),i);return`${o}${c}`}case"cancel":{const i=s?`${u("gray",$)} `:"",c=ee(e.output,t(this.options[this.cursor],"cancelled"),i);return`${o}${c}${s?`
30
- ${u("gray",$)}`:""}`}default:{const i=s?`${u("cyan",$)} `:"",c=o.split(`
31
- `).length,d=r?ht(ft,s):s?[u("cyan",j)]:[],h=d.join(`
32
- `),m=d.length+1;return`${o}${i}${mt({output:e.output,cursor:this.cursor,options:this.options,maxItems:e.maxItems,columnPadding:i.length,rowPadding:c+m,style:(f,p)=>t(f,f.disabled?"disabled":p?"active":"inactive")}).join(`
33
- ${i}`)}
29
+ `;switch(this.state){case"submit":{const s=i?`${u("gray",v)} `:"",l=ne(e.output,t(this.options[this.cursor],"selected"),s);return`${o}${l}`}case"cancel":{const s=i?`${u("gray",v)} `:"",l=ne(e.output,t(this.options[this.cursor],"cancelled"),s);return`${o}${l}${i?`
30
+ ${u("gray",v)}`:""}`}default:{const s=i?`${u("cyan",v)} `:"",l=o.split(`
31
+ `).length,d=r?xt(St,i):i?[u("cyan",U)]:[],h=d.join(`
32
+ `),m=d.length+1;return`${o}${s}${$t({output:e.output,cursor:this.cursor,options:this.options,maxItems:e.maxItems,columnPadding:s.length,rowPadding:l+m,style:(p,f)=>t(p,p.disabled?"disabled":f?"active":"inactive")}).join(`
33
+ ${s}`)}
34
34
  ${h}
35
- `}}}}).prompt()};`${u("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??P.withGuide,r=`${`${t?`${u("gray",$)}
36
- `:""}${_e(this.state)} `}${e.message}
37
- `,s=e.placeholder&&e.placeholder.length>0?u("inverse",e.placeholder[0])+u("dim",e.placeholder.slice(1)):u(["inverse","hidden"],"_"),n=this.userInput?this.userInputWithCursor:s,l=this.value??"";switch(this.state){case"error":{const a=this.error?` ${u("yellow",this.error)}`:"",o=t?`${u("yellow",$)} `:"",i=t?u("yellow",j):"";return`${r.trim()}
35
+ `}}}}).prompt()};`${u("gray",v)}`;const Ae=e=>new ot({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??W.withGuide,r=`${`${t?`${u("gray",v)}
36
+ `:""}${Ce(this.state)} `}${e.message}
37
+ `,i=e.placeholder&&e.placeholder.length>0?u("inverse",e.placeholder[0])+u("dim",e.placeholder.slice(1)):u(["inverse","hidden"],"_"),n=this.userInput?this.userInputWithCursor:i,c=this.value??"";switch(this.state){case"error":{const a=this.error?` ${u("yellow",this.error)}`:"",o=t?`${u("yellow",v)} `:"",s=t?u("yellow",U):"";return`${r.trim()}
38
38
  ${o}${n}
39
- ${i}${a}
40
- `}case"submit":{const a=l?` ${u("dim",l)}`:"",o=t?u("gray",$):"";return`${r}${o}${a}`}case"cancel":{const a=l?` ${u(["strikethrough","dim"],l)}`:"",o=t?u("gray",$):"";return`${r}${o}${a}${l.trim()?`
41
- ${o}`:""}`}default:{const a=t?`${u("cyan",$)} `:"",o=t?u("cyan",j):"";return`${r}${a}${n}
39
+ ${s}${a}
40
+ `}case"submit":{const a=c?` ${u("dim",c)}`:"",o=t?u("gray",v):"";return`${r}${o}${a}`}case"cancel":{const a=c?` ${u(["strikethrough","dim"],c)}`:"",o=t?u("gray",v):"";return`${r}${o}${a}${c.trim()?`
41
+ ${o}`:""}`}default:{const a=t?`${u("cyan",v)} `:"",o=t?u("cyan",U):"";return`${r}${a}${n}
42
42
  ${o}
43
- `}}}}).prompt();function re(e){return e==null?[]:Array.isArray(e)?e:[e]}function gt(e,t,r,s){var n,l=e[t],a=~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((n=+r,n*0===0?n:r)),!!r):(n=+r,n*0===0?n:r);e[t]=l==null?a:Array.isArray(l)?l.concat(a):[l,a]}function bt(e,t){e=e||[],t=t||{};var r,s,n,l,a,o={_:[]},i=0,c=0,d=0,h=e.length;const m=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),m)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]]||[],c=s.length;c-- >0;)t.boolean.push(s[c]);for(i=t.string.length;i-- >0;)for(s=t.alias[t.string[i]]||[],c=s.length;c-- >0;)t.string.push(s[c]);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(n=e[i],n==="--"){o._=o._.concat(e.slice(++i));break}for(c=0;c<n.length&&n.charCodeAt(c)===45;c++);if(c===0)o._.push(n);else if(n.substring(c,c+3)==="no-"){if(l=n.substring(c+3),f&&!~g.indexOf(l))return t.unknown(n);o[l]=!1}else{for(d=c+1;d<n.length&&n.charCodeAt(d)!==61;d++);for(l=n.substring(c,d),a=n.substring(++d)||i+1===h||(""+e[i+1]).charCodeAt(0)===45||e[++i],s=c===2?[l]:l,d=0;d<s.length;d++){if(l=s[d],f&&!~g.indexOf(l))return t.unknown("-".repeat(c)+l);gt(o,l,d+1<s.length||a,t)}}}if(p)for(r in t.default)o[r]===void 0&&(o[r]=t.default[r]);if(m)for(r in o)for(s=t.alias[r]||[];s.length>0;)o[s.shift()]=o[r];return o}var z={exports:{}},Fe;function yt(){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),n=(o,i,c=o)=>d=>{let h=""+d,m=h.indexOf(i,o.length);return~m?o+l(h,i,c,m)+i:o+h+i},l=(o,i,c,d)=>{let h="",m=0;do h+=o.substring(m,d)+c,m=d+i.length,d=o.indexOf(i,m);while(~d);return h+o.substring(m)},a=(o=s)=>{let i=o?n:()=>String;return{isColorSupported:o,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=a(),z.exports.createColors=a,z.exports}var xt=yt();const $t=ze(xt),{cyan:wt,magenta:vt,yellow:Et}=$t,J=[{name:"engine",display:"Engine",description:"with the PlayCanvas Engine API directly",color:Et},{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"}],_t=async({argBoilerplate:e,yes:t,cancel:r})=>{if(e&&W.some(n=>n.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(n=>n.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(n=>({label:n.display,value:n.name,hint:n.description}))});return D(s)&&r(),s},St=async({argTemplate:e,yes:t,cancel:r})=>{if(e&&J.some(n=>n.name===e))return e;if(e&&(!process.stdout.isTTY||t))throw new Error(`Unknown template: ${e}. Choose from: ${J.map(n=>n.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(n=>({label:n.color(n.display),value:n.name,hint:n.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=y.basename(y.resolve(e));if(!Te(s)){if(t)return ie(s);const n=await Ie({message:"Package name:",defaultValue:ie(s),placeholder:ie(s),validate:l=>{if(!l||!Te(l))return"Invalid package.json name"}});if(D(n))return r();s=n}return s},se=e=>e.trim().replace(/\/+$/g,""),Ft=e=>{const t=_.readdirSync(e);return t.length===0||t.length===1&&t[0]===".git"},Tt=e=>{if(_.existsSync(e))for(const t of _.readdirSync(e))t!==".git"&&_.rmSync(y.resolve(e,t),{recursive:!0,force:!0})},Ct=async({argTargetDir:e,defaultTargetDir:t,yes:r,cancel:s})=>{let n=e?se(String(e)):void 0;if(!n&&r)return t;if(!n){const l=await Ie({message:"Project name:",defaultValue:t,placeholder:t});D(l)&&s(),n=se(l)}return n},Rt=async({targetDir:e,argOverwrite:t,yes:r,cancel:s})=>{if(_.existsSync(e)&&!Ft(e)){if(r&&!t)throw new Error(`Target directory "${e}" is not empty. Pass --overwrite to remove its contents.`);const n=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(n))return s();switch(n){case"yes":Tt(e);break;case"no":s();return}}},kt=e=>{const{cwd:t,targetDir:r,template:s,boilerplate:n,packageName:l,skills:a,renameFiles:o}=e,i=y.resolve(t,r);_.mkdirSync(i,{recursive:!0});const c=process.env.npm_config_user_agent?.split("/")[0]??"npm";O.step(`Creating project in ${i}...`);const d=ke(import.meta.url),h=y.dirname(d),m=[y.resolve(h,"../templates"),y.resolve(h,"../../templates")].find(v=>_.existsSync(y.join(v,s)));if(!m)throw new Error(`Template directory not found for: ${s}`);const f=y.join(m,s),p=y.join(m,"_shared",n);_.existsSync(p)&&_.cpSync(p,i,{recursive:!0});for(const v of["base",n]){const I=y.join(f,v);if(!_.existsSync(I))throw new Error(`Boilerplate directory not found: ${s}/${v}`);_.cpSync(I,i,{recursive:!0})}for(const[v,I]of Object.entries(o)){const b=y.join(i,v);_.existsSync(b)&&_.renameSync(b,y.join(i,I))}const g=y.join(i,"package.json"),S=JSON.parse(_.readFileSync(g,"utf-8"));if(S.name=l,_.writeFileSync(g,JSON.stringify(S,null,4)+`
44
- `),a){const v=[y.resolve(h,"../skills"),y.resolve(h,"../../skills")].find(b=>_.existsSync(b));if(!v)throw new Error("Skills directory not found");const I=_.readdirSync(v,{withFileTypes:!0}).filter(b=>b.isDirectory()).map(b=>b.name);for(const b of[".claude/skills",".agents/skills"])for(const E of I)_.cpSync(y.join(v,E),y.join(i,b,E),{recursive:!0});O.step("Added PlayCanvas agent skills (opt out with --no-skills)")}let w=`Project created. Now run:
45
- `;const T=y.isAbsolute(r)?i:y.relative(t,i);switch(i!==t&&(w+=`
46
- cd ${T.includes(" ")?`"${T}"`:T}`),c){case"yarn":w+=`
47
- yarn`,w+=`
48
- yarn dev`;break;default:w+=`
49
- ${c} install`,w+=`
50
- ${c} run dev`;break}pt(w)},M=bt(process.argv.slice(2),{alias:{h:"help",t:"template",b:"boilerplate",y:"yes"},boolean:["help","overwrite","yes"],string:["template","boilerplate"]}),At=process.cwd(),Bt=`Usage: npm create playcanvas@latest [OPTION]...
43
+ `}}}}).prompt();function oe(e){return e==null?[]:Array.isArray(e)?e:[e]}function Et(e,t,r,i){var n,c=e[t],a=~i.string.indexOf(t)?r==null||r===!0?"":String(r):typeof r=="boolean"?r:~i.boolean.indexOf(t)?r==="false"?!1:r==="true"||(e._.push((n=+r,n*0===0?n:r)),!!r):(n=+r,n*0===0?n:r);e[t]=c==null?a:Array.isArray(c)?c.concat(a):[c,a]}function _t(e,t){e=e||[],t=t||{};var r,i,n,c,a,o={_:[]},s=0,l=0,d=0,h=e.length;const m=t.alias!==void 0,p=t.unknown!==void 0,f=t.default!==void 0;if(t.alias=t.alias||{},t.string=oe(t.string),t.boolean=oe(t.boolean),m)for(r in t.alias)for(i=t.alias[r]=oe(t.alias[r]),s=0;s<i.length;s++)(t.alias[i[s]]=i.concat(r)).splice(s,1);for(s=t.boolean.length;s-- >0;)for(i=t.alias[t.boolean[s]]||[],l=i.length;l-- >0;)t.boolean.push(i[l]);for(s=t.string.length;s-- >0;)for(i=t.alias[t.string[s]]||[],l=i.length;l-- >0;)t.string.push(i[l]);if(f){for(r in t.default)if(c=typeof t.default[r],i=t.alias[r]=t.alias[r]||[],t[c]!==void 0)for(t[c].push(r),s=0;s<i.length;s++)t[c].push(i[s])}const b=p?Object.keys(t.alias):[];for(s=0;s<h;s++){if(n=e[s],n==="--"){o._=o._.concat(e.slice(++s));break}for(l=0;l<n.length&&n.charCodeAt(l)===45;l++);if(l===0)o._.push(n);else if(n.substring(l,l+3)==="no-"){if(c=n.substring(l+3),p&&!~b.indexOf(c))return t.unknown(n);o[c]=!1}else{for(d=l+1;d<n.length&&n.charCodeAt(d)!==61;d++);for(c=n.substring(l,d),a=n.substring(++d)||s+1===h||(""+e[s+1]).charCodeAt(0)===45||e[++s],i=l===2?[c]:c,d=0;d<i.length;d++){if(c=i[d],p&&!~b.indexOf(c))return t.unknown("-".repeat(l)+c);Et(o,c,d+1<i.length||a,t)}}}if(f)for(r in t.default)o[r]===void 0&&(o[r]=t.default[r]);if(m)for(r in o)for(i=t.alias[r]||[];i.length>0;)o[i.shift()]=o[r];return o}var Z={exports:{}},ke;function It(){if(ke)return Z.exports;ke=1;let e=process||{},t=e.argv||[],r=e.env||{},i=!(r.NO_COLOR||t.includes("--no-color"))&&(!!r.FORCE_COLOR||t.includes("--color")||e.platform==="win32"||(e.stdout||{}).isTTY&&r.TERM!=="dumb"||!!r.CI),n=(o,s,l=o)=>d=>{let h=""+d,m=h.indexOf(s,o.length);return~m?o+c(h,s,l,m)+s:o+h+s},c=(o,s,l,d)=>{let h="",m=0;do h+=o.substring(m,d)+l,m=d+s.length,d=o.indexOf(s,m);while(~d);return h+o.substring(m)},a=(o=i)=>{let s=o?n:()=>String;return{isColorSupported:o,reset:s("\x1B[0m","\x1B[0m"),bold:s("\x1B[1m","\x1B[22m","\x1B[22m\x1B[1m"),dim:s("\x1B[2m","\x1B[22m","\x1B[22m\x1B[2m"),italic:s("\x1B[3m","\x1B[23m"),underline:s("\x1B[4m","\x1B[24m"),inverse:s("\x1B[7m","\x1B[27m"),hidden:s("\x1B[8m","\x1B[28m"),strikethrough:s("\x1B[9m","\x1B[29m"),black:s("\x1B[30m","\x1B[39m"),red:s("\x1B[31m","\x1B[39m"),green:s("\x1B[32m","\x1B[39m"),yellow:s("\x1B[33m","\x1B[39m"),blue:s("\x1B[34m","\x1B[39m"),magenta:s("\x1B[35m","\x1B[39m"),cyan:s("\x1B[36m","\x1B[39m"),white:s("\x1B[37m","\x1B[39m"),gray:s("\x1B[90m","\x1B[39m"),bgBlack:s("\x1B[40m","\x1B[49m"),bgRed:s("\x1B[41m","\x1B[49m"),bgGreen:s("\x1B[42m","\x1B[49m"),bgYellow:s("\x1B[43m","\x1B[49m"),bgBlue:s("\x1B[44m","\x1B[49m"),bgMagenta:s("\x1B[45m","\x1B[49m"),bgCyan:s("\x1B[46m","\x1B[49m"),bgWhite:s("\x1B[47m","\x1B[49m"),blackBright:s("\x1B[90m","\x1B[39m"),redBright:s("\x1B[91m","\x1B[39m"),greenBright:s("\x1B[92m","\x1B[39m"),yellowBright:s("\x1B[93m","\x1B[39m"),blueBright:s("\x1B[94m","\x1B[39m"),magentaBright:s("\x1B[95m","\x1B[39m"),cyanBright:s("\x1B[96m","\x1B[39m"),whiteBright:s("\x1B[97m","\x1B[39m"),bgBlackBright:s("\x1B[100m","\x1B[49m"),bgRedBright:s("\x1B[101m","\x1B[49m"),bgGreenBright:s("\x1B[102m","\x1B[49m"),bgYellowBright:s("\x1B[103m","\x1B[49m"),bgBlueBright:s("\x1B[104m","\x1B[49m"),bgMagentaBright:s("\x1B[105m","\x1B[49m"),bgCyanBright:s("\x1B[106m","\x1B[49m"),bgWhiteBright:s("\x1B[107m","\x1B[49m")}};return Z.exports=a(),Z.exports.createColors=a,Z.exports}var Ft=It();const Tt=tt(Ft),{cyan:Ct,magenta:Rt,yellow:At}=Tt,H=[{name:"engine",display:"Engine",description:"with the PlayCanvas Engine API directly",color:At},{name:"react",display:"React",description:"with @playcanvas/react",color:Ct},{name:"web-components",display:"Web Components",description:"with @playcanvas/web-components",color:Rt}],je={physics:{engine:["assets"],react:["react"],"web-components":["assets"]}},V=[{name:"spinning-cube",display:"Spinning Cube",category:"Basics",description:"a rotating cube and a light"},{name:"interactive-sphere",display:"Interactive Sphere",category:"Basics",description:"orbit controls, a grid and pointer picking"},{name:"model-viewer",display:"Model Viewer",category:"Viewers",description:"a glTF model, orbit controls and a procedural sky"},{name:"splat-viewer",display:"Splat Viewer",category:"Viewers",description:"a Gaussian splat and orbit controls"},{name:"product-configurator",display:"Product Configurator",category:"Viewers",description:"product variants, materials and orbit controls"},{name:"physics-playground",display:"Physics Playground",category:"Games",description:"rigid bodies, collisions, spawning and reset",features:["physics"]},{name:"first-person-controller",display:"First-Person Controller",category:"Games",description:"first-person movement, mouse look and jumping",features:["physics"]},{name:"third-person-controller",display:"Third-Person Controller",category:"Games",description:"an animated character, follow camera and locomotion",features:["physics"]},{name:"sprite-game",display:"Sprite Game",category:"Games",description:"an orthographic camera, sprite animation and input"},{name:"scene-editor",display:"Scene Editor",category:"Tools",description:"selection and translate, rotate and scale gizmos"},{name:"vr-starter",display:"VR Starter",category:"XR",description:"immersive VR, controllers and locomotion"},{name:"ar-placement",display:"AR Placement",category:"XR",description:"mobile AR, hit testing and object placement"}],kt=async({argFormat:e,yes:t,cancel:r})=>{if(e&&H.some(n=>n.name===e))return e;if(e&&(!process.stdout.isTTY||t))throw new Error(`Unknown format: ${e}. Choose from: ${H.map(n=>n.name).join(", ")}`);if(t)return H[0].name;const i=await ae({message:e?`"${e}" isn't a valid format. Please choose from below: `:"Select a format:",options:H.map(n=>({label:n.color(n.display),value:n.name,hint:n.description}))});return K(i)&&r(),i},jt=async({argStarter:e,yes:t,cancel:r})=>{if(e&&V.some(n=>n.name===e))return e;if(!process.stdout.isTTY||t){if(!e)return V[0].name;throw new Error(`Unknown starter: ${e}. Choose from: ${V.map(n=>n.name).join(", ")}`)}const i=await ae({message:e?`"${e}" isn't a valid starter. Please choose from below: `:"Select a starter:",initialValue:V[0].name,options:V.map(n=>({label:n.display,value:n.name,hint:`${n.category} \xB7 ${n.description}`}))});return K(i)&&r(),i},Oe=e=>/^(?:@[a-z\d\-*~][a-z\d\-*._~]*\/)?[a-z\d\-~][a-z\d\-._~]*$/.test(e),ce=e=>e.trim().toLowerCase().replace(/\s+/g,"-").replace(/^[._]/,"").replace(/[^a-z\d\-~]+/g,"-"),Ot=async({targetDir:e,yes:t,cancel:r})=>{let i=y.basename(y.resolve(e));if(!Oe(i)){if(t)return ce(i);const n=await Ae({message:"Package name:",defaultValue:ce(i),placeholder:ce(i),validate:c=>{if(!c||!Oe(c))return"Invalid package.json name"}});if(K(n))return r();i=n}return i},le=e=>e.trim().replace(/\/+$/g,""),Mt=e=>{const t=x.readdirSync(e);return t.length===0||t.length===1&&t[0]===".git"},Bt=e=>{if(x.existsSync(e))for(const t of x.readdirSync(e))t!==".git"&&x.rmSync(y.resolve(e,t),{recursive:!0,force:!0})},Pt=async({argTargetDir:e,defaultTargetDir:t,yes:r,cancel:i})=>{let n=e?le(String(e)):void 0;if(!n&&r)return t;if(!n){const c=await Ae({message:"Project name:",defaultValue:t,placeholder:t});K(c)&&i(),n=le(c)}return n},Lt=async({targetDir:e,argOverwrite:t,yes:r,cancel:i})=>{if(x.existsSync(e)&&!Mt(e)){if(r&&!t)throw new Error(`Target directory "${e}" is not empty. Pass --overwrite to remove its contents.`);const n=t?"yes":await ae({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(K(n))return i();switch(n){case"yes":Bt(e);break;case"no":i();return}}},Nt=["scripts","dependencies","devDependencies","peerDependencies","engines"],Me="## Prerequisites",Dt={engine:"src/main.ts",react:"src/App.tsx","web-components":"src/main.ts"},Wt=e=>{const{cwd:t,targetDir:r,format:i,starter:n,packageName:c,skills:a,renameFiles:o}=e,s=y.resolve(t,r);x.mkdirSync(s,{recursive:!0});const l=process.env.npm_config_user_agent?.split("/")[0]??"npm";D.step(`Creating project in ${s}...`);const d=Ne(import.meta.url),h=y.dirname(d),m=[y.resolve(h,"../templates"),y.resolve(h,"../../templates")].find(g=>x.existsSync(y.join(g,i)));if(!m)throw new Error(`Format directory not found for: ${i}`);const p=y.join(m,i);for(const g of H)for(const T of V){const A=y.join(m,g.name,T.name),G=Dt[g.name];if(!G||!x.existsSync(y.join(A,G)))throw new Error(`Incomplete starter matrix: ${g.name}/${T.name}`);for(const Q of T.features??[]){const ue=je[Q]?.[g.name];if(!ue?.length||ue.some(Be=>!x.existsSync(y.join(m,"_features",Q,Be))))throw new Error(`Incomplete feature matrix: ${Q}/${g.name}`)}}const f=V.find(g=>g.name===n);if(!f)throw new Error(`Starter not found: ${n}`);const b=y.join(m,"_shared",n),F=y.join(p,"base"),C=y.join(p,n),O=(f.features??[]).flatMap(g=>je[g][i].map(T=>y.join(m,"_features",g,T))),B=[b,F,...O,C],k=B.map(g=>{const T=y.join(g,"package.json");return x.existsSync(T)?JSON.parse(x.readFileSync(T,"utf-8")):{}}),w=[k[1],k[0],...k.slice(2)];if(!x.existsSync(C))throw new Error(`Starter directory not found: ${i}/${n}`);for(const g of B)x.existsSync(g)&&x.cpSync(g,s,{recursive:!0});const S=y.join(b,"README.md"),$=y.join(s,"README.md");x.existsSync(S)&&x.writeFileSync($,x.readFileSync($,"utf8").replace(Me,`${x.readFileSync(S,"utf8").trimEnd()}
44
+
45
+ ${Me}`));for(const[g,T]of Object.entries(o)){const A=y.join(s,g);x.existsSync(A)&&x.renameSync(A,y.join(s,T))}const E=y.join(s,"package.json"),_=Object.assign({},...w);for(const g of Nt){const T=Object.assign({},...w.map(A=>A?.[g]));Object.keys(T).length?_[g]=T:delete _[g]}if(_.name=c,x.writeFileSync(E,JSON.stringify(_,null,4)+`
46
+ `),a){const g=[y.resolve(h,"../skills"),y.resolve(h,"../../skills")].find(A=>x.existsSync(A));if(!g)throw new Error("Skills directory not found");const T=x.readdirSync(g,{withFileTypes:!0}).filter(A=>A.isDirectory()).map(A=>A.name);for(const A of[".claude/skills",".agents/skills"])for(const G of T)x.cpSync(y.join(g,G),y.join(s,A,G),{recursive:!0});D.step("Added PlayCanvas agent skills (opt out with --no-skills)")}let R=`Project created. Now run:
47
+ `;const I=y.isAbsolute(r)?s:y.relative(t,s);switch(s!==t&&(R+=`
48
+ cd ${I.includes(" ")?`"${I}"`:I}`),l){case"yarn":R+=`
49
+ yarn`,R+=`
50
+ yarn dev`;break;default:R+=`
51
+ ${l} install`,R+=`
52
+ ${l} run dev`;break}vt(R)},L=_t(process.argv.slice(2),{alias:{b:"boilerplate",f:"format",h:"help",s:"starter",t:"template",y:"yes"},boolean:["help","overwrite","yes"],string:["format","starter","template","boilerplate"]}),Vt=process.cwd(),Ut=`Usage: npm create playcanvas@latest [OPTION]...
51
53
 
52
54
  Create a new PlayCanvas project with TypeScript.
53
55
  With no arguments, start the CLI in interactive mode.
54
56
 
55
57
  Options:
56
- -t, --template NAME use a specific template
57
- -b, --boilerplate NAME use a specific boilerplate
58
+ -f, --format NAME use a specific format
59
+ -s, --starter NAME use a specific starter
58
60
  --overwrite remove existing files from a non-empty target directory
59
61
  --no-skills omit the PlayCanvas agent skills
60
62
  -y, --yes skip the prompts and take the defaults
61
63
  -h, --help show help
62
- `,Lt={_gitignore:".gitignore"},Ot="playcanvas-project",Mt=async()=>{const e=M._[0]?se(String(M._[0])):void 0,t=M.template,r=M.boilerplate,s=M.overwrite,n=M.yes;if(M.help){console.log(Bt);return}const l=()=>{dt("Operation cancelled"),process.exit(0)},a=await Ct({argTargetDir:e,defaultTargetDir:Ot,yes:n,cancel:l});await Rt({targetDir:a,argOverwrite:s,yes:n,cancel:l});const o=await It({targetDir:a,yes:n,cancel:l}),i=await St({argTemplate:t,yes:n,cancel:l}),c=await _t({argBoilerplate:r,yes:n,cancel:l}),d=M.skills??!0;kt({cwd:At,targetDir:a,template:i,boilerplate:c,packageName:o,skills:d,renameFiles:Lt})};Mt().catch(e=>{console.error(e instanceof Error?e.message:e),process.exitCode=1});
64
+ `,Gt={_gitignore:".gitignore",_npmrc:".npmrc"},Kt="playcanvas-project",Ht=async()=>{const e=L._[0]?le(String(L._[0])):void 0,t=L.format??L.template,r=L.starter??L.boilerplate,i=L.overwrite,n=L.yes;if(L.help){console.log(Ut);return}const c=()=>{wt("Operation cancelled"),process.exit(0)},a=await Pt({argTargetDir:e,defaultTargetDir:Kt,yes:n,cancel:c});await Lt({targetDir:a,argOverwrite:i,yes:n,cancel:c});const o=await Ot({targetDir:a,yes:n,cancel:c}),s=await kt({argFormat:t,yes:n,cancel:c}),l=await jt({argStarter:r,yes:n,cancel:c}),d=L.skills??!0;Wt({cwd:Vt,targetDir:a,format:s,starter:l,packageName:o,skills:d,renameFiles:Gt})};Ht().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.5.1",
3
+ "version": "0.6.1",
4
4
  "description": "Scaffold a PlayCanvas project",
5
5
  "keywords": [
6
6
  "playcanvas",
@@ -11,12 +11,15 @@ const instance = (name: keyof typeof ASSET_TUNING) => {
11
11
  castShadows: true
12
12
  });
13
13
  model.setLocalScale(t.scale, t.scale, t.scale);
14
- model.setLocalPosition(0, t.y, 0);
15
- model.setLocalEulerAngles(0, t.yaw, 0);
14
+ model.setLocalPosition(-t.center[0] * t.scale, t.y, -t.center[2] * t.scale);
16
15
  const root = new Entity(name);
17
- root.addChild(model);
16
+ const yaw = new Entity(`${name}-yaw`);
17
+ yaw.setLocalEulerAngles(0, t.yaw, 0);
18
+ yaw.addChild(model);
19
+ root.addChild(yaw);
18
20
  return root;
19
21
  };
20
22
  ```
21
23
 
22
- Only position and rotate the returned root. Keep the calibration inside `instance()`.
24
+ Only position and rotate the returned root. Keep the yaw, scale, and pivot compensation inside
25
+ `instance()`.
@@ -15,13 +15,18 @@ const Model = ({ id, src, heading = 0, position = [0, 0, 0] }) => {
15
15
 
16
16
  return (
17
17
  <Entity name={id} position={position} rotation={[0, heading, 0]}>
18
- <Entity position={[0, t.y, 0]} rotation={[0, t.yaw, 0]} scale={[t.scale, t.scale, t.scale]}>
19
- <Render type="asset" asset={asset} />
18
+ <Entity rotation={[0, t.yaw, 0]}>
19
+ <Entity
20
+ position={[-t.center[0] * t.scale, t.y, -t.center[2] * t.scale]}
21
+ scale={[t.scale, t.scale, t.scale]}
22
+ >
23
+ <Render type="asset" asset={asset} />
24
+ </Entity>
20
25
  </Entity>
21
26
  </Entity>
22
27
  );
23
28
  };
24
29
  ```
25
30
 
26
- Add project-specific prop types without changing the two-level transform structure. Keep hooks
31
+ Add project-specific prop types without changing the three-level transform structure. Keep hooks
27
32
  unconditional and asset URLs stable.
@@ -7,13 +7,16 @@ Keep gameplay placement on the outer entity and calibration on a visual child:
7
7
  <pc-asset id="ship" src="/models/ship.glb"></pc-asset>
8
8
  <pc-scene>
9
9
  <pc-entity name="Ship" position="12 0 -4" rotation="0 90 0">
10
- <pc-entity position="0 1.2 0" rotation="0 180 0" scale="0.9 0.9 0.9">
11
- <pc-model asset="ship"></pc-model>
10
+ <pc-entity rotation="0 180 0">
11
+ <pc-entity position="-0.45 1.2 0.225" scale="0.9 0.9 0.9">
12
+ <pc-model asset="ship"></pc-model>
13
+ </pc-entity>
12
14
  </pc-entity>
13
15
  </pc-entity>
14
16
  </pc-scene>
15
17
  </pc-app>
16
18
  ```
17
19
 
18
- Generate repeated markup from one `{ scale, y, yaw }` record per asset. Keep all vector attributes
19
- space-separated and use degrees for rotations.
20
+ Generate repeated markup from one `{ scale, y, yaw, center }` record per asset. Calculate the visual
21
+ position as `-center.x * scale, y, -center.z * scale`. Keep vector attributes space-separated and use
22
+ degrees for rotations.
@@ -1,13 +1,22 @@
1
1
  # Web Components projects
2
2
 
3
- `<pc-model>` already covers the simplest case without any script: when the loaded container has
4
- animations it adds an `anim` component and assigns `animations[0]` under the state name `animation`.
5
- It always takes the first clip and has no attribute for choosing another.
3
+ Use `<pc-anim>` inside `<pc-model>` to animate the model hierarchy. Without `<pc-anim-clip>`
4
+ children, it assigns every animation from the model's container by track name and starts the first
5
+ clip. Select and cross-fade declaratively:
6
6
 
7
- There is no animation component beyond that. Put explicit clip selection, multiple clips, state
8
- graphs, and retargeting in a module-scoped Engine `Script`, load it with `<pc-asset>`, and attach it
9
- to the same `<pc-entity>` hierarchy as the rendered model using `<pc-scripts>` and `<pc-script>`.
7
+ ```html
8
+ <pc-entity>
9
+ <pc-model asset="character">
10
+ <pc-anim clip="Idle" transition-time="0.2"></pc-anim>
11
+ </pc-model>
12
+ </pc-entity>
13
+ ```
10
14
 
11
- Pass clip names and simple configuration as `<pc-script>` attributes. Use its `attributes` JSON
12
- attribute for nested state-graph configuration. Keep scale on a visual child `<pc-entity>`, not on
13
- skinned bones, and confirm playback after `pc-app` is ready.
15
+ Add `<pc-anim-clip name="...">` children to declare a subset, rename states, set per-clip `loop` or
16
+ `speed`, or source tracks through an explicit `asset`. Use `<pc-anim>` attributes for `activate`,
17
+ `clip`, `speed`, and `transition-time`; its `play`, `pause`, and `transition` methods cover imperative
18
+ playback.
19
+
20
+ Use a module-scoped Engine `Script` only for state graphs, retargeting, or orchestration beyond that
21
+ component contract. Keep scale on a visual child `<pc-entity>`, not on skinned bones, and confirm
22
+ playback after `pc-app` is ready.
@@ -19,20 +19,27 @@ The output provides:
19
19
  - `groundOffset` for the model wrapper's local Y position;
20
20
  - `center` for the pivot offset from the geometry centre: a non-zero X or Z means the root's
21
21
  position is not where the model appears, and Y feeds grounding;
22
- - `boundsSource` for proving how precisely the bounds were measured;
22
+ - `boundsSource` and `boundsPose` for proving how and at which pose the bounds were measured;
23
+ - `requiresRuntimeCheck` for animated morphs, skins, and incomplete decoding;
23
24
  - `nodePaths`, `clips`, `joints`, and `animationTargets` for animation setup and rig comparison;
24
- - `skinned` to flag bind-pose bounds that need runtime confirmation.
25
+ - `morphed`, `morphAnimated`, and `skinned` for pose-sensitive assets.
25
26
 
26
27
  ## Bounds precision
27
28
 
28
- `aabb`, `dims`, `center`, and `groundOffset` are decoded from actual vertex positions and transformed
29
- by each node's world matrix, so they are exact and can place meshes touching without a gap. Confirm
30
- `boundsSource` before relying on that precision:
29
+ `aabb`, `dims`, `center`, and `groundOffset` are decoded from actual vertex positions, default morph
30
+ weights, and each node's world matrix. Confirm both source and pose before relying on them:
31
31
 
32
- - `vertices` means every primitive was decoded and the bounds are exact.
32
+ - `vertices` means every primitive was decoded and the bounds are exact for `boundsPose`.
33
33
  - `accessor-minmax` means at least one primitive could not be decoded, so its bounds fall back to the
34
34
  node-transformed local box. That over-estimates a mesh which does not fill its own box on a node
35
35
  rotated off-axis, by up to 41 percent for a 45-degree yaw. `boundsNotes` gives the cause.
36
+ - `incomplete` means some visible default-pose geometry could not be measured; do not calibrate from
37
+ the reported bounds.
38
+ - `null` means no usable bounds could be recovered.
39
+
40
+ `static` and `default-morph` bounds describe visible geometry at its authored default pose. `bind`
41
+ describes skinned vertices before animation. When `requiresRuntimeCheck` is true, confirm grounding
42
+ and maximum animated extent in the running application even if `boundsSource` is `vertices`.
36
43
 
37
44
  Carry `boundsSource`, `aabb`, `dims`, `center`, and `groundOffset` into the asset tuning record.
38
45
  `groundOffset` seats the base in Y; `center.x` and `center.z` are the horizontal pivot offset that
@@ -41,28 +48,30 @@ authored pivot happens to be. Running the inspector alone is not placement evide
41
48
  broad-phase spacing, but cannot locate a non-planar support surface or attachment point. Use an
42
49
  authored mount point or confirm the support in the running application before placing another model.
43
50
 
44
- ## Extract from any container with gltf-transform
51
+ ## Extract from compressed containers
45
52
 
46
- The bundled inspector decodes plain vertex buffers only. When a primitive is draco- or
47
- meshopt-compressed, sparse, or in an external buffer it falls back to `accessor-minmax` or reports
48
- nothing, and `boundsNotes` names the cause. Use gltf-transform as the precursor that normalizes any
49
- container into a plain GLB the inspector can then measure exactly. Decompress a scratch copy with the
50
- passes that would alter geometry or hierarchy disabled, and inspect the copy rather than shipping it:
53
+ The bundled inspector decodes plain, interleaved, quantized, and sparse vertex buffers. For Draco,
54
+ Meshopt, or external buffers, `boundsNotes` names the cause. Parse and rewrite a scratch copy with
55
+ glTF Transform's lossless `copy` command, then inspect that copy rather than shipping it:
51
56
 
52
57
  ```sh
53
- npx @gltf-transform/cli optimize in.glb scratch.glb \
54
- --compress false --simplify false --flatten false --join false
58
+ npx --yes @gltf-transform/cli@4.4.2 copy in.glb scratch.glb
55
59
  node <skill-directory>/scripts/inspect.mjs scratch.glb
56
60
  ```
57
61
 
62
+ `copy` preserves decoded vertex values, scenes, nodes, and materials while removing Draco and
63
+ Meshopt compression. Existing lossy compression may already have quantized the source. Do not
64
+ substitute `optimize`: it enables additional transforms unless each one is understood and disabled.
65
+
58
66
  The Engine has no `EXT_meshopt_compression` support, so a meshopt asset will not render as shipped.
59
67
  If it must appear in the scene, transcode it to an uncompressed GLB the same way — subject to the
60
68
  project's rules on modifying assets — so it both loads and measures.
61
69
 
62
- These exact bounds intentionally disagree with the Engine at runtime. `MeshInstance.aabb` transforms
63
- the mesh's declared local box, so for a node rotated off-axis it reads larger than the geometry
64
- really is. Treat that difference as expected and place from these bounds. A skinned mesh node's own
65
- transform is ignored here because glTF requires it; the Engine resolves to the same result.
70
+ These geometry-fit bounds can intentionally disagree with the Engine's runtime culling AABB.
71
+ `MeshInstance.aabb` transforms the declared local box and expands it conservatively for morph
72
+ targets, so it can be larger than visible geometry. Place static models from exact inspected bounds;
73
+ confirm morph and skin extremes at runtime. A skinned mesh node's own transform is ignored here
74
+ because glTF requires it; the Engine resolves to the same result.
66
75
 
67
76
  Shortlist files first; do not dump an entire asset pack into context. Bounds cannot prove facing.
68
77
  glTF convention is +Z forward while PlayCanvas entities face -Z, and asset packs vary. Confirm each