create-playcanvas 0.10.1 → 0.11.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 (102) hide show
  1. package/README.md +26 -3
  2. package/dist/index.mjs +41 -38
  3. package/package.json +6 -3
  4. package/templates/_features/physics/assets/public/ammo/SOURCE.md +4 -1
  5. package/templates/{react/interactive-sphere/src/App.css → _shared/interactive-sphere/src/counter.css} +0 -6
  6. package/templates/_shared/web-lens/README.md +42 -0
  7. package/templates/_shared/web-lens/package.json +9 -0
  8. package/templates/_shared/web-lens/scripts/package-lens.mjs +231 -0
  9. package/templates/_shared/web-lens/src/dodge-game.ts +271 -0
  10. package/templates/_shared/web-lens/src/lens.css +155 -0
  11. package/templates/_shared/web-lens/src/lens.ts +91 -0
  12. package/templates/engine/base/README.md +1 -1
  13. package/templates/engine/base/package.json +4 -4
  14. package/templates/engine/base/vite.config.ts +3 -0
  15. package/templates/engine/first-person-controller/src/main.ts +2 -3
  16. package/templates/engine/interactive-sphere/src/App.ts +1 -1
  17. package/templates/engine/interactive-sphere/src/main.ts +3 -5
  18. package/templates/engine/model-viewer/src/main.ts +3 -3
  19. package/templates/engine/physics-playground/src/main.ts +2 -3
  20. package/templates/engine/spinning-cube/src/main.ts +1 -1
  21. package/templates/engine/splat-viewer/src/main.ts +1 -1
  22. package/templates/engine/third-person-controller/src/main.ts +2 -3
  23. package/templates/engine/web-lens/index.html +26 -0
  24. package/templates/engine/web-lens/src/main.ts +89 -0
  25. package/templates/engine/web-lens/vite.config.ts +44 -0
  26. package/templates/index.ts +6 -0
  27. package/templates/react/base/README.md +1 -1
  28. package/templates/react/base/package.json +6 -6
  29. package/templates/react/base/vite.config.ts +3 -0
  30. package/templates/react/interactive-sphere/src/App.tsx +5 -6
  31. package/templates/react/interactive-sphere/src/Scene.tsx +1 -1
  32. package/templates/react/model-viewer/src/App.tsx +4 -2
  33. package/templates/react/spinning-cube/src/App.tsx +2 -0
  34. package/templates/react/splat-viewer/src/App.tsx +2 -0
  35. package/templates/react/{splat-viewer → web-lens}/index.html +2 -3
  36. package/templates/react/web-lens/src/App.tsx +85 -0
  37. package/templates/react/web-lens/vite.config.ts +46 -0
  38. package/templates/web-components/base/README.md +1 -1
  39. package/templates/web-components/base/package.json +4 -4
  40. package/templates/web-components/base/vite.config.ts +3 -0
  41. package/templates/web-components/first-person-controller/index.html +1 -6
  42. package/templates/web-components/interactive-sphere/src/main.ts +2 -2
  43. package/templates/web-components/model-viewer/index.html +2 -2
  44. package/templates/web-components/model-viewer/src/main.ts +0 -1
  45. package/templates/web-components/physics-playground/index.html +1 -6
  46. package/templates/web-components/spinning-cube/src/main.ts +0 -1
  47. package/templates/web-components/splat-viewer/src/main.ts +0 -1
  48. package/templates/web-components/third-person-controller/index.html +1 -6
  49. package/templates/web-components/web-lens/index.html +36 -0
  50. package/templates/web-components/web-lens/src/main.ts +47 -0
  51. package/templates/web-components/web-lens/vite.config.ts +44 -0
  52. package/templates/_features/physics/assets/public/ammo/ammo.js +0 -973
  53. package/templates/engine/interactive-sphere/index.html +0 -13
  54. package/templates/engine/interactive-sphere/src/style.css +0 -28
  55. package/templates/engine/model-viewer/index.html +0 -13
  56. package/templates/engine/model-viewer/src/style.css +0 -8
  57. package/templates/engine/spinning-cube/index.html +0 -13
  58. package/templates/engine/spinning-cube/src/style.css +0 -8
  59. package/templates/engine/splat-viewer/index.html +0 -13
  60. package/templates/engine/splat-viewer/src/style.css +0 -8
  61. package/templates/react/base/.prettierignore +0 -3
  62. package/templates/react/base/_gitignore +0 -24
  63. package/templates/react/base/_npmrc +0 -1
  64. package/templates/react/base/prettier.config.mjs +0 -1
  65. package/templates/react/base/src/assets/playcanvas.png +0 -0
  66. package/templates/react/base/src/inspector.css +0 -33
  67. package/templates/react/base/src/inspector.ts +0 -38
  68. package/templates/react/base/src/starter.css +0 -104
  69. package/templates/react/base/src/vite-env.d.ts +0 -19
  70. package/templates/react/interactive-sphere/index.html +0 -13
  71. package/templates/react/interactive-sphere/src/index.css +0 -4
  72. package/templates/react/interactive-sphere/src/main.tsx +0 -11
  73. package/templates/react/model-viewer/index.html +0 -13
  74. package/templates/react/model-viewer/src/index.css +0 -9
  75. package/templates/react/model-viewer/src/main.tsx +0 -11
  76. package/templates/react/spinning-cube/index.html +0 -13
  77. package/templates/react/spinning-cube/src/index.css +0 -9
  78. package/templates/react/spinning-cube/src/main.tsx +0 -11
  79. package/templates/react/splat-viewer/src/index.css +0 -9
  80. package/templates/react/splat-viewer/src/main.tsx +0 -11
  81. package/templates/web-components/base/.prettierignore +0 -3
  82. package/templates/web-components/base/_gitignore +0 -24
  83. package/templates/web-components/base/_npmrc +0 -1
  84. package/templates/web-components/base/prettier.config.mjs +0 -1
  85. package/templates/web-components/base/src/assets/playcanvas.png +0 -0
  86. package/templates/web-components/base/src/inspector.css +0 -33
  87. package/templates/web-components/base/src/inspector.ts +0 -38
  88. package/templates/web-components/base/src/starter.css +0 -104
  89. package/templates/web-components/base/src/vite-env.d.ts +0 -19
  90. package/templates/web-components/interactive-sphere/src/style.css +0 -53
  91. package/templates/web-components/model-viewer/src/style.css +0 -8
  92. package/templates/web-components/spinning-cube/src/style.css +0 -8
  93. package/templates/web-components/splat-viewer/src/style.css +0 -8
  94. /package/templates/{engine/base → _common}/.prettierignore +0 -0
  95. /package/templates/{engine/base → _common}/_gitignore +0 -0
  96. /package/templates/{engine/base → _common}/_npmrc +0 -0
  97. /package/templates/{engine/base → _common}/prettier.config.mjs +0 -0
  98. /package/templates/{engine/base → _common}/src/assets/playcanvas.png +0 -0
  99. /package/templates/{engine/base → _common}/src/inspector.css +0 -0
  100. /package/templates/{engine/base → _common}/src/inspector.ts +0 -0
  101. /package/templates/{engine/base → _common}/src/starter.css +0 -0
  102. /package/templates/{engine/base → _common}/src/vite-env.d.ts +0 -0
package/README.md CHANGED
@@ -38,9 +38,19 @@ Every format uses TypeScript and includes Vite, ESLint, Prettier and a productio
38
38
 
39
39
  ## Starters
40
40
 
41
- Choose from 12 starter kits across basics, viewers, games, tools and XR. Run the creator to browse them; `spinning-cube` is the default.
41
+ Choose from starter kits across basics, viewers, games, tools and XR. Run the creator to browse them; `spinning-cube` is the default.
42
42
 
43
- ![The twelve PlayCanvas starter scenes](images/starter-catalog.webp)
43
+ ![The PlayCanvas starter scenes](images/starter-catalog.webp)
44
+
45
+ ## Snapchat Web Lenses
46
+
47
+ The `web-lens` starter is a portrait game ready to publish to Snapchat as a [Web Lens](https://developers.snap.com/web-lenses/home), with the [Web Lens API](https://developers.snap.com/web-lenses/web-lens-api) wired up for leaderboards, Bitmoji and storage:
48
+
49
+ ```bash
50
+ npm create playcanvas@latest my-lens -- --starter web-lens
51
+ ```
52
+
53
+ Its `npm run package` script builds the game, checks it against the Web Lens upload rules (size limits, relative paths and no network access) and writes the zip to upload through [My Lenses](https://my-lenses.snapchat.com/).
44
54
 
45
55
  ## CLI Options
46
56
 
@@ -59,7 +69,7 @@ npm create playcanvas@latest my-game -- -f react -y
59
69
  | `--yes` | `-y` | Skip the prompts and take the defaults |
60
70
  | `--help` | `-h` | Show command help |
61
71
 
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.
72
+ `--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`. A run without a terminal, such as one started by an AI agent or in CI, takes the same defaults, so it never waits on a prompt. The previous `--template` and `--boilerplate` long flags remain accepted for compatibility.
63
73
 
64
74
  ## Agent skills
65
75
 
@@ -69,12 +79,25 @@ Every project includes [`@playcanvas/skills`](https://github.com/playcanvas/skil
69
79
 
70
80
  ```bash
71
81
  npm install
82
+ npm test
72
83
  npm run build
73
84
  node dist/index.mjs
74
85
  ```
75
86
 
76
87
  Contributions are welcome. Please open an issue before proposing a new format, starter or another substantial change.
77
88
 
89
+ ### Adding a starter
90
+
91
+ A project is assembled from the layers under `templates/`, in this order. A file in a later layer replaces the same file in an earlier one, and each layer's `package.json` is merged into those before it.
92
+
93
+ 1. `_common/`: files every project gets
94
+ 2. `<format>/base/`: the format's tooling and README, a default `index.html` for Engine and React, and React's `src/main.tsx`
95
+ 3. `_shared/<starter>/`: the starter's format-independent code and assets. Its `README.md` is inserted into the base README above `## Prerequisites`
96
+ 4. `_features/<feature>/<layer>/`: what each of the starter's `features` needs in that format, as mapped by `FEATURES` in `templates/index.ts`
97
+ 5. `<format>/<starter>/`: the starter's scene in that format
98
+
99
+ To add a starter, list it in `STARTERS` in `templates/index.ts`, add `_shared/<starter>/README.md`, and add its scene to every format: `engine/<starter>/src/main.ts`, `react/<starter>/src/App.tsx`, and `web-components/<starter>/index.html` with `src/main.ts`. Import `./starter.css` for the shared page and panel styles, and override a base file only when the starter needs something different. `npm test` checks that the starter exists in every format, and CI scaffolds and builds it in each one.
100
+
78
101
  ## License
79
102
 
80
103
  [MIT](LICENSE)
package/dist/index.mjs CHANGED
@@ -1,57 +1,57 @@
1
1
  #!/usr/bin/env node
2
- import{styleText as l}from"node:util";import B,{stdin as Le,stdout as he}from"node:process";import Ne from"node:readline";import"node:tty";import $ from"node:fs";import y from"node:path";import{fileURLToPath as De}from"node:url";const We=(()=>{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}})(),Ve=e=>e===12288||e>=65281&&e<=65376||e>=65504&&e<=65510,Ue=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,Ge=/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y,Ke=/[\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,He=/\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"),ze=/(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y,Je=new RegExp("\\p{M}+","gu"),Ye={limit:1/0,ellipsis:""},fe=(e,t={},r={})=>{const i=t.limit??1/0,n=t.ellipsis??"",c=t?.ellipsisWidth??(n?fe(n,Ye,r).width:0),a=0,o=r.controlWidth??0,s=r.tabWidth??8,u=r.emojiWidth??2,d=2,h=r.regularWidth??1,m=r.wideWidth??d,p=[[ze,h],[Ge,a],[Ke,o],[He,s],[de,u],[me,m]];let f=0,b=0,F=e.length,T=0,O=!1,M=F,k=Math.max(0,i-c),w=0,S=0,x=0,E=0;e:for(;;){if(S>w||b>=F&&b>f){const _=e.slice(w,S)||e.slice(f,b);T=0;for(const R of _.replaceAll(Je,"")){const I=R.codePointAt(0)||0;if(Ve(I)?E=d:Ue(I)?E=m:E=h,x+E>k&&(M=Math.min(M,Math.max(w,f)+T)),x+E>i){O=!0;break e}T+=R.length,x+=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(T=I===me?We(e.slice(b,I.lastIndex)):I===de?1:I.lastIndex-b,E=T*g,x+E>k&&(M=Math.min(M,b+Math.floor((k-x)/g))),x+E>i){O=!0;break e}x+=E,w=f,S=b,b=f=I.lastIndex;continue e}}b+=1}return{width:O?k:x,index:O?M:F,truncated:O,ellipsed:O&&i>=c}},qe={limit:1/0,ellipsis:"",ellipsisWidth:0},N=(e,t={})=>fe(e,qe,t).width,z="\x1B",pe="\x9B",Xe=39,te="\x07",ge="[",Ze="]",be="m",re=`${Ze}8;;`,ye=new RegExp(`(?:\\${ge}(?<code>\\d+)m|\\${re}(?<uri>.*)${te})`,"y"),$e=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},xe=e=>`${z}${ge}${e}${be}`,we=e=>`${z}${re}${e}${te}`,se=(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(),u=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(re,d+1)),n?c?h===te&&(n=!1,c=!1):h===be&&(n=!1):(o+=m,o===r&&!u.done&&(e.push(""),o=0)),s=u,u=i.next(),d+=h.length}a=e.at(-1),!o&&a!==void 0&&a.length&&e.length>1&&(e[e.length-2]+=e.pop())},Qe=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("")},et=(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(""),se(o,m,t),s=N(o.at(-1)??"");continue}if(s+p>t&&s&&p){if(r.wordWrap===!1&&s<t){se(o,m,t),s=N(o.at(-1)??"");continue}o.push(""),s=0}if(s+p>t&&r.wordWrap===!1){se(o,m,t),s=N(o.at(-1)??"");continue}o[o.length-1]+=m,s+=p}r.trim!==!1&&(o=o.map(h=>Qe(h)));const u=o.join(`
3
- `);let d=!1;for(let h=0;h<u.length;h++){const m=u[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(u)?.groups;if(f?.code!==void 0){const b=Number.parseFloat(f.code);n=b===Xe?void 0:b}else f?.uri!==void 0&&(c=f.uri.length===0?void 0:f.uri)}if(u[h+1]===`
4
- `){c&&(i+=we(""));const p=n?$e(n):void 0;n&&p&&(i+=xe(p))}else m===`
5
- `&&(n&&$e(n)&&(i+=xe(n)),c&&(i+=we(c)))}return i},tt=/\r?\n/;function J(e,t,r){return String(e).normalize().split(tt).map(i=>et(i,t,r)).join(`
6
- `)}function rt(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var ie,ve;function st(){if(ve)return ie;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 ie={cursor:i,scroll:n,erase:c,beep:r},ie}var P=st();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 it=["up","down","left","right","space","enter","cancel"],W={actions:new Set(it),aliases:new Map([["k","up"],["j","down"],["h","left"],["l","right"],["","cancel"],["escape","cancel"]]),withGuide:!0};function nt(e){if(e!==void 0)return e;const t=process.env.ACCESSIBLE;return t!==void 0&&t!==""&&t!=="0"&&t!=="false"}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 at(e,t){if(e===t)return;const r=e.split(`
2
+ import{styleText as c}from"node:util";import k,{stdin as Ae,stdout as ae}from"node:process";import ke from"node:readline";import"node:tty";import w from"node:fs";import x from"node:path";import{fileURLToPath as je}from"node:url";const Oe=(()=>{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,Me=/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y,Pe=/[\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"),De=/(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y,We=new RegExp("\\p{M}+","gu"),Ve={limit:1/0,ellipsis:""},ce=(e,t={},r={})=>{const i=t.limit??1/0,n=t.ellipsis??"",l=t?.ellipsisWidth??(n?ce(n,Ve,r).width:0),a=0,o=r.controlWidth??0,s=r.tabWidth??8,u=r.emojiWidth??2,d=2,h=r.regularWidth??1,m=r.wideWidth??d,b=[[De,h],[Me,a],[Pe,o],[Ne,s],[le,u],[oe,m]];let g=0,$=0,_=e.length,F=0,T=!1,R=_,I=Math.max(0,i-l),v=0,f=0,y=0,p=0;e:for(;;){if(f>v||$>=_&&$>g){const S=e.slice(v,f)||e.slice(g,$);F=0;for(const B of S.replaceAll(We,"")){const C=B.codePointAt(0)||0;if(Be(C)?p=d:Le(C)?p=m:p=h,y+p>I&&(R=Math.min(R,Math.max(v,g)+F)),y+p>i){T=!0;break e}F+=B.length,y+=p}v=f=0}if($>=_)break e;for(let S=0,B=b.length;S<B;S++){const[C,ne]=b[S];if(C.lastIndex=$,C.test(e)){if(F=C===oe?Oe(e.slice($,C.lastIndex)):C===le?1:C.lastIndex-$,p=F*ne,y+p>I&&(R=Math.min(R,$+Math.floor((I-y)/ne))),y+p>i){T=!0;break e}y+=p,v=g,f=$,$=g=C.lastIndex;continue e}}$+=1}return{width:T?I:y,index:T?R:_,truncated:T,ellipsed:T&&i>=l}},Ue={limit:1/0,ellipsis:"",ellipsisWidth:0},M=(e,t={})=>ce(e,Ue,t).width,V="\x1B",ue="\x9B",Ge=39,q="\x07",he="[",Ke="]",me="m",X=`${Ke}8;;`,de=new RegExp(`(?:\\${he}(?<code>\\d+)m|\\${X}(?<uri>.*)${q})`,"y"),fe=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},pe=e=>`${V}${he}${e}${me}`,ge=e=>`${V}${X}${e}${q}`,Z=(e,t,r)=>{const i=t[Symbol.iterator]();let n=!1,l=!1,a=e.at(-1),o=a===void 0?0:M(a),s=i.next(),u=i.next(),d=0;for(;!s.done;){const h=s.value,m=M(h);o+m<=r?e[e.length-1]+=h:(e.push(h),o=0),(h===V||h===ue)&&(n=!0,l=t.startsWith(X,d+1)),n?l?h===q&&(n=!1,l=!1):h===me&&(n=!1):(o+=m,o===r&&!u.done&&(e.push(""),o=0)),s=u,u=i.next(),d+=h.length}a=e.at(-1),!o&&a!==void 0&&a.length&&e.length>1&&(e[e.length-2]+=e.pop())},He=e=>{const t=e.split(" ");let r=t.length;for(;r&&!M(t[r-1]);)r--;return r===t.length?e:t.slice(0,r).join(" ")+t.slice(r).join("")},ze=(e,t,r={})=>{if(r.trim!==!1&&e.trim()==="")return"";let i="",n,l;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 g=o.at(-1)??"",$=g.trimStart();g.length!==$.length&&(o[o.length-1]=$,s=M($))}h!==0&&(s>=t&&(r.wordWrap===!1||r.trim===!1)&&(o.push(""),s=0),(s||r.trim===!1)&&(o[o.length-1]+=" ",s++));const b=M(m);if(r.hard&&b>t){const g=t-s,$=1+Math.floor((b-g-1)/t);Math.floor((b-1)/t)<$&&o.push(""),Z(o,m,t),s=M(o.at(-1)??"");continue}if(s+b>t&&s&&b){if(r.wordWrap===!1&&s<t){Z(o,m,t),s=M(o.at(-1)??"");continue}o.push(""),s=0}if(s+b>t&&r.wordWrap===!1){Z(o,m,t),s=M(o.at(-1)??"");continue}o[o.length-1]+=m,s+=b}r.trim!==!1&&(o=o.map(h=>He(h)));const u=o.join(`
3
+ `);let d=!1;for(let h=0;h<u.length;h++){const m=u[h];if(i+=m,d)d=!1;else if(d=m>="\uD800"&&m<="\uDBFF",d)continue;if(m===V||m===ue){de.lastIndex=h+1;const g=de.exec(u)?.groups;if(g?.code!==void 0){const $=Number.parseFloat(g.code);n=$===Ge?void 0:$}else g?.uri!==void 0&&(l=g.uri.length===0?void 0:g.uri)}if(u[h+1]===`
4
+ `){l&&(i+=ge(""));const b=n?fe(n):void 0;n&&b&&(i+=pe(b))}else m===`
5
+ `&&(n&&fe(n)&&(i+=pe(n)),l&&(i+=ge(l)))}return i},Je=/\r?\n/;function U(e,t,r){return String(e).normalize().split(Je).map(i=>ze(i,t,r)).join(`
6
+ `)}function Ye(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var Q,be;function qe(){if(be)return Q;be=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)},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 s=0;s<a;s++)o+=this.line+(s<a-1?i.up():"");return a&&(o+=i.left),o}};return Q={cursor:i,scroll:n,erase:l,beep:r},Q}var O=qe();function G(e,t,r){if(!r.some(a=>!a.disabled))return e;const i=e+t,n=Math.max(r.length-1,0),l=i<0?n:i>n?0:i;return r[l]?.disabled?G(l,t<0?-1:1,r):l}const Xe=["up","down","left","right","space","enter","cancel"],P={actions:new Set(Xe),aliases:new Map([["k","up"],["j","down"],["h","left"],["l","right"],["","cancel"],["escape","cancel"]]),withGuide:!0};function Ze(e){if(e!==void 0)return e;const t=process.env.ACCESSIBLE;return t!==void 0&&t!==""&&t!=="0"&&t!=="false"}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
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 ne=Symbol("clack:cancel");function K(e){return e===ne}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 ae(e,t,r,i=r,n=r,c){const a=Ee(e??he);return J(t,a-r.length,{hard:!0,trim:!1}).split(`
8
+ `),n=Math.max(r.length,i.length),l=[];for(let a=0;a<n;a++)r[a]!==i[a]&&l.push(a);return{lines:l,numLinesBefore:r.length,numLinesAfter:i.length,numLines:n}}globalThis.process.platform.startsWith("win");const ee=Symbol("clack:cancel");function W(e){return e===ee}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,xe=e=>"rows"in e&&typeof e.rows=="number"?e.rows:20;function te(e,t,r,i=r,n=r,l){const a=$e(e??ae);return U(t,a-r.length,{hard:!0,trim:!1}).split(`
9
9
  `).map((o,s,u)=>{const d=o;return s===0?`${i}${d}`:s===u.length-1?`${n}${d}`:`${r}${d}`}).join(`
10
- `)}function ot(e,t){if("~standard"in e){const r=e["~standard"].validate(t);return r instanceof Promise?r.then(i=>i.issues?.at(0)?.message):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="";get accessible(){return nt(this.opts.accessible)}constructor(t,r=!0){const{input:i=Le,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(ne);this._abortSignal.addEventListener("abort",()=>{this.state="cancel",this.close()},{once:!0})}this.rl=Ne.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(ne)})})}_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("")}async onKeypress(t,r){if(this.state!=="validating"){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=ot(this.opts.validate,this.value);let n;i instanceof Promise?(this.state="validating",this.render(),n=await i):n=i,n&&(this.error=n instanceof Error?n.message:n,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=at(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(`
10
+ `)}function et(e,t){if("~standard"in e){const r=e["~standard"].validate(t);return r instanceof Promise?r.then(i=>i.issues?.at(0)?.message):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="";get accessible(){return Ze(this.opts.accessible)}constructor(t,r=!0){const{input:i=Ae,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=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 l of i)l.cb(...r),l.once&&n.push(()=>i.splice(i.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(ee);this._abortSignal.addEventListener("abort",()=>{this.state="cancel",this.close()},{once:!0})}this.rl=ke.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(O.cursor.show),this.output.off("resize",this.render),K(this.input,!1),t(this.value)}),this.once("cancel",()=>{this.output.write(O.cursor.show),this.output.off("resize",this.render),K(this.input,!1),t(ee)})})}_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("")}async onKeypress(t,r){if(this.state!=="validating"){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 i=et(this.opts.validate,this.value);let n;i instanceof Promise?(this.state="validating",this.render(),n=await i):n=i,n&&(this.error=n instanceof Error?n.message:n,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(O.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(O.cursor.hide);else{const r=Qe(this._prevFrame,t),i=xe(this.output);if(this.restoreCursor(),r){const n=Math.max(0,r.numLinesAfter-i),l=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(O.cursor.move(0,a-l)),this.output.write(O.erase.lines(1));const o=t.split(`
13
+ `);this.output.write(o[a]),this._prevFrame=t,this.output.write(O.cursor.move(0,o.length-a-1));return}else if(r.lines.length>1){if(n<l)a=n;else{const s=a-l;s>0&&this.output.write(O.cursor.move(0,s))}this.output.write(O.erase.down());const o=t.split(`
14
14
  `).slice(a);this.output.write(o.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 ct=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 lt 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}${l("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 ut(){return B.platform!=="win32"?B.env.TERM!=="linux":!!B.env.CI||!!B.env.WT_SESSION||!!B.env.TERMINUS_SUBLIME||B.env.ConEmuTask==="{cmd::Cmder}"||B.env.TERM_PROGRAM==="Terminus-Sublime"||B.env.TERM_PROGRAM==="vscode"||B.env.TERM==="xterm-256color"||B.env.TERM==="alacritty"||B.env.TERMINAL_EMULATOR==="JetBrains-JediTerm"}const ht=ut(),j=(e,t)=>ht?e:t,Fe=j("\u25C6","*"),mt=j("\u25A0","x"),dt=j("\u25B2","x"),Ce=j("\u25C7","o"),v=j("\u2502","|"),V=j("\u2514","\u2014"),ft=j("\u25CF",">"),Te=j("\u25CB"," "),pt=j("\u25CF","\u2022"),gt=j("\u25C6","*"),bt=j("\u25B2","!"),yt=j("\u25A0","x"),Re=e=>{switch(e){case"initial":case"active":return l("cyan",Fe);case"cancel":return l("red",mt);case"error":return l("yellow",dt);case"submit":return l("green",Ce);case"validating":return l("dim",Fe)}},$t=e=>{switch(e){case"initial":case"active":return l("cyan",v);case"cancel":return l("red",v);case"error":return l("yellow",v);case"submit":return l("green",v)}};function xt(e,t){const r=[`${t?`${l("cyan",v)} `:""}${e.join(" \u2022 ")}`];return t&&r.push(l("cyan",V)),r}const Ae=(e,t,r,i,n,c=!1)=>{let a=t,o=0;if(c)for(let s=i-1;s>=r;s--){const u=e[s];if(u&&(a-=u.length),o++,a<=n)break}else for(let s=r;s<i;s++){const u=e[s];if(u&&(a-=u.length),o++,a<=n)break}return{lineCount:a,removals:o}},wt=({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),u=l("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 T=0;p&&T++,f&&T++;const O=m+(p?1:0),M=b-(f?1:0);for(let w=O;w<M;w++){const S=t[w],x=S?r(S,w===e):"",E=J(x,o,{hard:!0,trim:!1}).split(`
16
- `);F.push(E),T+=E.length}if(T>d){let w=0,S=0,x=T;const E=e-O;let _=d;const R=()=>Ae(F,x,0,E,_),I=()=>Ae(F,x,E+1,F.length,_,!0);p?({lineCount:x,removals:w}=R(),x>_&&(f||(_-=1),{lineCount:x,removals:S}=I())):(f||(_-=1),{lineCount:x,removals:S}=I(),x>_&&(_-=1,{lineCount:x,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(u);for(const w of F)for(const S of w)k.push(S);return f&&k.push(u),k};`${l("dim","\u2191/\u2193")}`,`${l("dim","Space:")}`,`${l("dim","Enter:")}`;const D={message:(e=[],{symbol:t=l("gray",v),secondarySymbol:r=l("gray",v),output:i=process.stdout,spacing:n=1,withGuide:c}={})=>{const a=[],o=c??W.withGuide,s=o?r:"",u=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(`${u}${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(`
15
+ `)),this._prevFrame=t;return}}this.output.write(O.erase.down())}this.output.write(t),this.state==="initial"&&(this.state="active"),this._prevFrame=t}}}let tt=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),i=r===-1?0:r;this.cursor=this.options[i]?.disabled?G(i,1,this.options):i,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()})}};class rt 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),i=t.slice(this.cursor,this.cursor+1),n=t.slice(this.cursor+1);return`${r}${c("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 st(){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 it=st(),A=(e,t)=>it?e:t,ve=A("\u25C6","*"),nt=A("\u25A0","x"),at=A("\u25B2","x"),Se=A("\u25C7","o"),E=A("\u2502","|"),N=A("\u2514","\u2014"),ot=A("\u25CF",">"),Ee=A("\u25CB"," "),lt=A("\u25CF","\u2022"),ct=A("\u25C6","*"),ut=A("\u25B2","!"),ht=A("\u25A0","x"),_e=e=>{switch(e){case"initial":case"active":return c("cyan",ve);case"cancel":return c("red",nt);case"error":return c("yellow",at);case"submit":return c("green",Se);case"validating":return c("dim",ve)}},mt=e=>{switch(e){case"initial":case"active":return c("cyan",E);case"cancel":return c("red",E);case"error":return c("yellow",E);case"submit":return c("green",E)}};function dt(e,t){const r=[`${t?`${c("cyan",E)} `:""}${e.join(" \u2022 ")}`];return t&&r.push(c("cyan",N)),r}const Ie=(e,t,r,i,n,l=!1)=>{let a=t,o=0;if(l)for(let s=i-1;s>=r;s--){const u=e[s];if(u&&(a-=u.length),o++,a<=n)break}else for(let s=r;s<i;s++){const u=e[s];if(u&&(a-=u.length),o++,a<=n)break}return{lineCount:a,removals:o}},ft=({cursor:e,options:t,style:r,output:i=process.stdout,maxItems:n=Number.POSITIVE_INFINITY,columnPadding:l=0,rowPadding:a=4})=>{const o=$e(i)-l,s=xe(i),u=c("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 b=h<t.length&&m>0,g=h<t.length&&m+h<t.length;const $=Math.min(m+h,t.length),_=[];let F=0;b&&F++,g&&F++;const T=m+(b?1:0),R=$-(g?1:0);for(let v=T;v<R;v++){const f=t[v],y=f?r(f,v===e):"",p=U(y,o,{hard:!0,trim:!1}).split(`
16
+ `);_.push(p),F+=p.length}if(F>d){let v=0,f=0,y=F;const p=e-T;let S=d;const B=()=>Ie(_,y,0,p,S),C=()=>Ie(_,y,p+1,_.length,S,!0);b?({lineCount:y,removals:v}=B(),y>S&&(g||(S-=1),{lineCount:y,removals:f}=C())):(g||(S-=1),{lineCount:y,removals:f}=C(),y>S&&(S-=1,{lineCount:y,removals:v}=B())),v>0&&(b=!0,_.splice(0,v)),f>0&&(g=!0,_.splice(_.length-f,f))}const I=[];b&&I.push(u);for(const v of _)for(const f of v)I.push(f);return g&&I.push(u),I};`${c("dim","\u2191/\u2193")}`,`${c("dim","Space:")}`,`${c("dim","Enter:")}`;const L={message:(e=[],{symbol:t=c("gray",E),secondarySymbol:r=c("gray",E),output:i=process.stdout,spacing:n=1,withGuide:l}={})=>{const a=[],o=l??P.withGuide,s=o?r:"",u=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,...b]=h;m.length>0?a.push(`${u}${m}`):a.push(o?t:"");for(const g of b)g.length>0?a.push(`${d}${g}`):a.push(o?r:"")}i.write(`${a.join(`
18
18
  `)}
19
- `)},info:(e,t)=>{D.message(e,{...t,symbol:l("blue",pt)})},success:(e,t)=>{D.message(e,{...t,symbol:l("green",gt)})},step:(e,t)=>{D.message(e,{...t,symbol:l("green",Ce)})},warn:(e,t)=>{D.message(e,{...t,symbol:l("yellow",bt)})},warning:(e,t)=>{D.warn(e,t)},error:(e,t)=>{D.message(e,{...t,symbol:l("red",yt)})}},vt=(e="",t)=>{const r=process.stdout,i=`${l("gray",V)} `;r.write(`${i}${l("red",e)}
19
+ `)},info:(e,t)=>{L.message(e,{...t,symbol:c("blue",lt)})},success:(e,t)=>{L.message(e,{...t,symbol:c("green",ct)})},step:(e,t)=>{L.message(e,{...t,symbol:c("green",Se)})},warn:(e,t)=>{L.message(e,{...t,symbol:c("yellow",ut)})},warning:(e,t)=>{L.warn(e,t)},error:(e,t)=>{L.message(e,{...t,symbol:c("red",ht)})}},pt=(e="",t)=>{const r=process.stdout,i=`${c("gray",N)} `;r.write(`${i}${c("red",e)}
20
20
 
21
- `)},St=(e="",t)=>{const r=process.stdout,i=`${l("gray",v)}
22
- ${l("gray",V)} `;r.write(`${i}${e}
21
+ `)},gt=(e="",t)=>{const r=process.stdout,i=`${c("gray",E)}
22
+ ${c("gray",N)} `;r.write(`${i}${e}
23
23
 
24
- `)},Et=[`${l("dim","\u2191/\u2193")} to navigate`,`${l("dim","Enter:")} confirm`],X=(e,t)=>e.includes(`
24
+ `)},bt=[`${c("dim","\u2191/\u2193")} to navigate`,`${c("dim","Enter:")} confirm`],H=(e,t)=>e.includes(`
25
25
  `)?e.split(`
26
26
  `).map(r=>t(r)).join(`
27
- `):t(e),oe=e=>{const t=(i,n)=>{if(i===void 0)return"";const c=i.label??String(i.value);switch(n){case"disabled":return`${l("gray",Te)} ${X(c,a=>l("gray",a))}${i.hint?` ${l("dim",`(${i.hint??"disabled"})`)}`:""}`;case"selected":return`${X(c,a=>l("dim",a))}`;case"active":return`${l("green",ft)} ${c}${i.hint?` ${l("dim",`(${i.hint})`)}`:""}`;case"cancelled":return`${X(c,a=>l(["strikethrough","dim"],a))}`;default:return`${l("dim",Te)} ${X(c,a=>l("dim",a))}`}},r=e.showInstructions??!0;return new ct({options:e.options,signal:e.signal,input:e.input,output:e.output,initialValue:e.initialValue,render(){const i=e.withGuide??W.withGuide,n=`${Re(this.state)} `,c=`${$t(this.state)} `,a=ae(e.output,e.message,c,n),o=`${i?`${l("gray",v)}
27
+ `):t(e),re=e=>{const t=(i,n)=>{if(i===void 0)return"";const l=i.label??String(i.value);switch(n){case"disabled":return`${c("gray",Ee)} ${H(l,a=>c("gray",a))}${i.hint?` ${c("dim",`(${i.hint??"disabled"})`)}`:""}`;case"selected":return`${H(l,a=>c("dim",a))}`;case"active":return`${c("green",ot)} ${l}${i.hint?` ${c("dim",`(${i.hint})`)}`:""}`;case"cancelled":return`${H(l,a=>c(["strikethrough","dim"],a))}`;default:return`${c("dim",Ee)} ${H(l,a=>c("dim",a))}`}},r=e.showInstructions??!0;return new tt({options:e.options,signal:e.signal,input:e.input,output:e.output,initialValue:e.initialValue,render(){const i=e.withGuide??P.withGuide,n=`${_e(this.state)} `,l=`${mt(this.state)} `,a=te(e.output,e.message,l,n),o=`${i?`${c("gray",E)}
28
28
  `:""}${a}
29
- `;switch(this.state){case"submit":{const s=i?`${l("gray",v)} `:"",u=ae(e.output,t(this.options[this.cursor],"selected"),s);return`${o}${u}`}case"cancel":{const s=i?`${l("gray",v)} `:"",u=ae(e.output,t(this.options[this.cursor],"cancelled"),s);return`${o}${u}${i?`
30
- ${l("gray",v)}`:""}`}default:{const s=i?`${l("cyan",v)} `:"",u=o.split(`
31
- `).length,d=r?xt(Et,i):i?[l("cyan",V)]:[],h=d.join(`
32
- `),m=d.length+1;return`${o}${s}${wt({output:e.output,cursor:this.cursor,options:this.options,maxItems:e.maxItems,columnPadding:s.length,rowPadding:u+m,style:(p,f)=>t(p,p.disabled?"disabled":f?"active":"inactive")}).join(`
29
+ `;switch(this.state){case"submit":{const s=i?`${c("gray",E)} `:"",u=te(e.output,t(this.options[this.cursor],"selected"),s);return`${o}${u}`}case"cancel":{const s=i?`${c("gray",E)} `:"",u=te(e.output,t(this.options[this.cursor],"cancelled"),s);return`${o}${u}${i?`
30
+ ${c("gray",E)}`:""}`}default:{const s=i?`${c("cyan",E)} `:"",u=o.split(`
31
+ `).length,d=r?dt(bt,i):i?[c("cyan",N)]:[],h=d.join(`
32
+ `),m=d.length+1;return`${o}${s}${ft({output:e.output,cursor:this.cursor,options:this.options,maxItems:e.maxItems,columnPadding:s.length,rowPadding:u+m,style:(b,g)=>t(b,b.disabled?"disabled":g?"active":"inactive")}).join(`
33
33
  ${s}`)}
34
34
  ${h}
35
- `}}}}).prompt()};`${l("gray",v)}`;const ke=e=>new lt({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?`${l("gray",v)}
36
- `:""}${Re(this.state)} `}${e.message}
37
- `,i=e.placeholder&&e.placeholder.length>0?l("inverse",e.placeholder[0])+l("dim",e.placeholder.slice(1)):l(["inverse","hidden"],"_"),n=this.userInput?this.userInputWithCursor:i,c=this.value??"";switch(this.state){case"validating":{const a=t?`${l("cyan",v)} `:"",o=t?l("cyan",V):"",s=l("dim",n),u=l("dim","Validating...");return`${r}${a}${s}
35
+ `}}}}).prompt()};`${c("gray",E)}`;const Fe=e=>new rt({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?`${c("gray",E)}
36
+ `:""}${_e(this.state)} `}${e.message}
37
+ `,i=e.placeholder&&e.placeholder.length>0?c("inverse",e.placeholder[0])+c("dim",e.placeholder.slice(1)):c(["inverse","hidden"],"_"),n=this.userInput?this.userInputWithCursor:i,l=this.value??"";switch(this.state){case"validating":{const a=t?`${c("cyan",E)} `:"",o=t?c("cyan",N):"",s=c("dim",n),u=c("dim","Validating...");return`${r}${a}${s}
38
38
  ${o} ${u}
39
- `}case"error":{const a=this.error?` ${l("yellow",this.error)}`:"",o=t?`${l("yellow",v)} `:"",s=t?l("yellow",V):"";return`${r.trim()}
39
+ `}case"error":{const a=this.error?` ${c("yellow",this.error)}`:"",o=t?`${c("yellow",E)} `:"",s=t?c("yellow",N):"";return`${r.trim()}
40
40
  ${o}${n}
41
41
  ${s}${a}
42
- `}case"submit":{const a=c?`${t?" ":""}${l("dim",c)}`:"",o=t?l("gray",v):"";return`${r}${o}${a}`}case"cancel":{const a=c?` ${l(["strikethrough","dim"],c)}`:"",o=t?l("gray",v):"";return`${r}${o}${a}${c.trim()?`
43
- ${o}`:""}`}default:{const a=t?`${l("cyan",v)} `:"",o=t?l("cyan",V):"";return`${r}${a}${n}
42
+ `}case"submit":{const a=l?`${t?" ":""}${c("dim",l)}`:"",o=t?c("gray",E):"";return`${r}${o}${a}`}case"cancel":{const a=l?` ${c(["strikethrough","dim"],l)}`:"",o=t?c("gray",E):"";return`${r}${o}${a}${l.trim()?`
43
+ ${o}`:""}`}default:{const a=t?`${c("cyan",E)} `:"",o=t?c("cyan",N):"";return`${r}${a}${n}
44
44
  ${o}
45
- `}}}}).prompt();function ce(e){return e==null?[]:Array.isArray(e)?e:[e]}function _t(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 It(e,t){e=e||[],t=t||{};var r,i,n,c,a,o={_:[]},s=0,u=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=ce(t.string),t.boolean=ce(t.boolean),m)for(r in t.alias)for(i=t.alias[r]=ce(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]]||[],u=i.length;u-- >0;)t.boolean.push(i[u]);for(s=t.string.length;s-- >0;)for(i=t.alias[t.string[s]]||[],u=i.length;u-- >0;)t.string.push(i[u]);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(u=0;u<n.length&&n.charCodeAt(u)===45;u++);if(u===0)o._.push(n);else if(n.substring(u,u+3)==="no-"){if(c=n.substring(u+3),p&&!~b.indexOf(c))return t.unknown(n);o[c]=!1}else{for(d=u+1;d<n.length&&n.charCodeAt(d)!==61;d++);for(c=n.substring(u,d),a=n.substring(++d)||s+1===h||(""+e[s+1]).charCodeAt(0)===45||e[++s],i=u===2?[c]:c,d=0;d<i.length;d++){if(c=i[d],p&&!~b.indexOf(c))return t.unknown("-".repeat(u)+c);_t(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:{}},je;function Ft(){if(je)return Z.exports;je=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,u=o)=>d=>{let h=""+d,m=h.indexOf(s,o.length);return~m?o+c(h,s,u,m)+s:o+h+s},c=(o,s,u,d)=>{let h="",m=0;do h+=o.substring(m,d)+u,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 Ct=Ft();const Tt=rt(Ct),{cyan:Rt,magenta:At,yellow:kt}=Tt,H=[{name:"engine",display:"Engine",description:"with the PlayCanvas Engine API directly",color:kt},{name:"react",display:"React",description:"with @playcanvas/react",color:Rt},{name:"web-components",display:"Web Components",description:"with @playcanvas/web-components",color:At}],Oe={physics:{engine:["assets"],react:["react"],"web-components":["assets"]}},U=[{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"}],jt=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 oe({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},Ot=async({argStarter:e,yes:t,cancel:r})=>{if(e&&U.some(n=>n.name===e))return e;if(!process.stdout.isTTY||t){if(!e)return U[0].name;throw new Error(`Unknown starter: ${e}. Choose from: ${U.map(n=>n.name).join(", ")}`)}const i=await oe({message:e?`"${e}" isn't a valid starter. Please choose from below: `:"Select a starter:",initialValue:U[0].name,options:U.map(n=>({label:n.display,value:n.name,hint:`${n.category} \xB7 ${n.description}`}))});return K(i)&&r(),i},Be=e=>/^(?:@[a-z\d\-*~][a-z\d\-*._~]*\/)?[a-z\d\-~][a-z\d\-._~]*$/.test(e),le=e=>e.trim().toLowerCase().replace(/\s+/g,"-").replace(/^[._]/,"").replace(/[^a-z\d\-~]+/g,"-"),Bt=async({targetDir:e,yes:t,cancel:r})=>{let i=y.basename(y.resolve(e));if(!Be(i)){if(t)return le(i);const n=await ke({message:"Package name:",defaultValue:le(i),placeholder:le(i),validate:c=>{if(!c||!Be(c))return"Invalid package.json name"}});if(K(n))return r();i=n}return i},Q=e=>e.trim().replace(/\/+$/g,""),Mt=e=>{const t=$.readdirSync(e);return t.length===0||t.length===1&&t[0]===".git"},Pt=e=>{if($.existsSync(e))for(const t of $.readdirSync(e))t!==".git"&&$.rmSync(y.resolve(e,t),{recursive:!0,force:!0})},Lt=async({argTargetDir:e,defaultTargetDir:t,yes:r,cancel:i})=>{let n=e?Q(String(e)):void 0;if(!n&&r)return t;if(!n){const c=await ke({message:"Project name:",defaultValue:t,placeholder:t,validate:a=>{if(a&&!Q(a))return"Invalid project name"}});K(c)&&i(),n=Q(c)}return n},Nt=async({targetDir:e,argOverwrite:t,yes:r,cancel:i})=>{if($.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 oe({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":Pt(e);break;case"no":i();return}}},Dt=["scripts","dependencies","devDependencies","peerDependencies","engines"],Me="## Prerequisites",Wt={engine:"src/main.ts",react:"src/App.tsx","web-components":"src/main.ts"},Vt=e=>{const{cwd:t,targetDir:r,format:i,starter:n,packageName:c,skills:a,renameFiles:o}=e,s=y.resolve(t,r);$.mkdirSync(s,{recursive:!0});const u=process.env.npm_config_user_agent?.split("/")[0]??"npm";D.step(`Creating project in ${s}...`);const d=De(import.meta.url),h=y.dirname(d),m=[y.resolve(h,"../templates"),y.resolve(h,"../../templates")].find(g=>$.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 C of U){const A=y.join(m,g.name,C.name),G=Wt[g.name];if(!G||!$.existsSync(y.join(A,G)))throw new Error(`Incomplete starter matrix: ${g.name}/${C.name}`);for(const ee of C.features??[]){const ue=Oe[ee]?.[g.name];if(!ue?.length||ue.some(Pe=>!$.existsSync(y.join(m,"_features",ee,Pe))))throw new Error(`Incomplete feature matrix: ${ee}/${g.name}`)}}const f=U.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"),T=y.join(p,n),O=(f.features??[]).flatMap(g=>Oe[g][i].map(C=>y.join(m,"_features",g,C))),M=[b,F,...O,T],k=M.map(g=>{const C=y.join(g,"package.json");return $.existsSync(C)?JSON.parse($.readFileSync(C,"utf-8")):{}}),w=[k[1],k[0],...k.slice(2)];if(!$.existsSync(T))throw new Error(`Starter directory not found: ${i}/${n}`);for(const g of M)$.existsSync(g)&&$.cpSync(g,s,{recursive:!0});const S=y.join(b,"README.md"),x=y.join(s,"README.md");$.existsSync(S)&&$.writeFileSync(x,$.readFileSync(x,"utf8").replace(Me,`${$.readFileSync(S,"utf8").trimEnd()}
45
+ `}}}}).prompt();function se(e){return e==null?[]:Array.isArray(e)?e:[e]}function yt(e,t,r,i){var n,l=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]=l==null?a:Array.isArray(l)?l.concat(a):[l,a]}function $t(e,t){e=e||[],t=t||{};var r,i,n,l,a,o={_:[]},s=0,u=0,d=0,h=e.length;const m=t.alias!==void 0,b=t.unknown!==void 0,g=t.default!==void 0;if(t.alias=t.alias||{},t.string=se(t.string),t.boolean=se(t.boolean),m)for(r in t.alias)for(i=t.alias[r]=se(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]]||[],u=i.length;u-- >0;)t.boolean.push(i[u]);for(s=t.string.length;s-- >0;)for(i=t.alias[t.string[s]]||[],u=i.length;u-- >0;)t.string.push(i[u]);if(g){for(r in t.default)if(l=typeof t.default[r],i=t.alias[r]=t.alias[r]||[],t[l]!==void 0)for(t[l].push(r),s=0;s<i.length;s++)t[l].push(i[s])}const $=b?Object.keys(t.alias):[];for(s=0;s<h;s++){if(n=e[s],n==="--"){o._=o._.concat(e.slice(++s));break}for(u=0;u<n.length&&n.charCodeAt(u)===45;u++);if(u===0)o._.push(n);else if(n.substring(u,u+3)==="no-"){if(l=n.substring(u+3),b&&!~$.indexOf(l))return t.unknown(n);o[l]=!1}else{for(d=u+1;d<n.length&&n.charCodeAt(d)!==61;d++);for(l=n.substring(u,d),a=n.substring(++d)||s+1===h||(""+e[s+1]).charCodeAt(0)===45||e[++s],i=u===2?[l]:l,d=0;d<i.length;d++){if(l=i[d],b&&!~$.indexOf(l))return t.unknown("-".repeat(u)+l);yt(o,l,d+1<i.length||a,t)}}}if(g)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:{}},Ce;function xt(){if(Ce)return z.exports;Ce=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,u=o)=>d=>{let h=""+d,m=h.indexOf(s,o.length);return~m?o+l(h,s,u,m)+s:o+h+s},l=(o,s,u,d)=>{let h="",m=0;do h+=o.substring(m,d)+u,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 wt=xt();const vt=Ye(wt),{cyan:St,magenta:Et,yellow:_t}=vt,J=[{name:"engine",display:"Engine",description:"with the PlayCanvas Engine API directly",color:_t},{name:"react",display:"React",description:"with @playcanvas/react",color:St},{name:"web-components",display:"Web Components",description:"with @playcanvas/web-components",color:Et}],It={physics:{engine:["assets"],react:["react"],"web-components":["assets"]}},D=[{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:"web-lens",display:"Snapchat Web Lens",category:"Games",description:"a portrait game with Snapchat leaderboards, packaged for upload"},{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"}],Ft=async({argFormat:e,yes:t,cancel:r})=>{if(e&&J.some(n=>n.name===e))return e;if(e&&t)throw new Error(`Unknown format: ${e}. Choose from: ${J.map(n=>n.name).join(", ")}`);if(t)return J[0].name;const i=await re({message:e?`"${e}" isn't a valid format. Please choose from below: `:"Select a format:",options:J.map(n=>({label:n.color(n.display),value:n.name,hint:n.description}))});return W(i)&&r(),i},Ct=async({argStarter:e,yes:t,cancel:r})=>{if(e&&D.some(n=>n.name===e))return e;if(t){if(!e)return D[0].name;throw new Error(`Unknown starter: ${e}. Choose from: ${D.map(n=>n.name).join(", ")}`)}const i=await re({message:e?`"${e}" isn't a valid starter. Please choose from below: `:"Select a starter:",initialValue:D[0].name,options:D.map(n=>({label:n.display,value:n.name,hint:`${n.category} \xB7 ${n.description}`}))});return W(i)&&r(),i},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,"-"),Tt=async({targetDir:e,yes:t,cancel:r})=>{let i=x.basename(x.resolve(e));if(!Te(i)){if(t)return ie(i);const n=await Fe({message:"Package name:",defaultValue:ie(i),placeholder:ie(i),validate:l=>{if(!l||!Te(l))return"Invalid package.json name"}});if(W(n))return r();i=n}return i},Y=e=>e.trim().replace(/\/+$/g,""),Rt=e=>{const t=w.readdirSync(e);return t.length===0||t.length===1&&t[0]===".git"},At=e=>{if(w.existsSync(e))for(const t of w.readdirSync(e))t!==".git"&&w.rmSync(x.resolve(e,t),{recursive:!0,force:!0})},kt=async({argTargetDir:e,defaultTargetDir:t,yes:r,cancel:i})=>{let n=e?Y(String(e)):void 0;if(!n&&r)return t;if(!n){const l=await Fe({message:"Project name:",defaultValue:t,placeholder:t,validate:a=>{if(a&&!Y(a))return"Invalid project name"}});W(l)&&i(),n=Y(l)}return n},jt=async({targetDir:e,argOverwrite:t,yes:r,cancel:i})=>{if(w.existsSync(e)&&!Rt(e)){if(r&&!t)throw new Error(`Target directory "${e}" is not empty. Pass --overwrite to remove its contents.`);const n=t?"yes":await re({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(W(n))return i();switch(n){case"yes":At(e);break;case"no":i();return}}},Ot=["scripts","dependencies","devDependencies","peerDependencies","engines"],Re="## Prerequisites",Bt=e=>{const{cwd:t,targetDir:r,format:i,starter:n,packageName:l,skills:a,renameFiles:o}=e,s=x.resolve(t,r);w.mkdirSync(s,{recursive:!0});const u=process.env.npm_config_user_agent?.split("/")[0]??"npm";L.step(`Creating project in ${s}...`);const d=je(import.meta.url),h=x.dirname(d),m=e.templatesDir??[x.resolve(h,"../templates"),x.resolve(h,"../../templates")].find(f=>w.existsSync(x.join(f,i)));if(!m)throw new Error(`Format directory not found for: ${i}`);const b=D.find(f=>f.name===n);if(!b)throw new Error(`Starter not found: ${n}`);const g=x.join(m,"_shared",n),$=x.join(m,i,n);if(!w.existsSync($))throw new Error(`Starter directory not found: ${i}/${n}`);const _=[x.join(m,"_common"),x.join(m,i,"base"),g,...(b.features??[]).flatMap(f=>It[f][i].map(y=>x.join(m,"_features",f,y))),$].filter(f=>w.existsSync(f)),F=x.join(g,"README.md");for(const f of _){const y=x.join(f,"package.json");w.cpSync(f,s,{recursive:!0,filter:p=>p!==y&&p!==F})}if(w.existsSync(F)){const f=x.join(s,"README.md"),y=`${w.readFileSync(F,"utf8").trimEnd()}
46
46
 
47
- ${Me}`));for(const[g,C]of Object.entries(o)){const A=y.join(s,g);$.existsSync(A)&&$.renameSync(A,y.join(s,C))}const E=y.join(s,"package.json"),_=Object.assign({},...w);for(const g of Dt){const C=Object.assign({},...w.map(A=>A?.[g]));Object.keys(C).length?_[g]=C:delete _[g]}if(_.name=c,$.writeFileSync(E,JSON.stringify(_,null,4)+`
48
- `),a){const g=[y.resolve(h,"../skills"),y.resolve(h,"../../skills")].find(A=>$.existsSync(A));if(!g)throw new Error("Skills directory not found");const C=$.readdirSync(g,{withFileTypes:!0}).filter(A=>A.isDirectory()).map(A=>A.name);for(const A of[".claude/skills",".agents/skills"])for(const G of C)$.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:
49
- `;const I=y.isAbsolute(r)?s:y.relative(t,s);switch(s!==t&&(R+=`
50
- cd ${I.includes(" ")?`"${I}"`:I}`),u){case"yarn":R+=`
51
- yarn`,R+=`
52
- yarn dev`;break;default:R+=`
53
- ${u} install`,R+=`
54
- ${u} run dev`;break}St(R)},L=It(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"]}),Ut=process.cwd(),Gt=`Usage: npm create playcanvas@latest [OPTION]...
47
+ ${Re}`,p=w.readFileSync(f,"utf8").replace(Re,()=>y);w.writeFileSync(f,p)}for(const[f,y]of Object.entries(o)){const p=x.join(s,f);w.existsSync(p)&&w.renameSync(p,x.join(s,y))}const T=_.map(f=>x.join(f,"package.json")).filter(f=>w.existsSync(f)).map(f=>JSON.parse(w.readFileSync(f,"utf-8"))),R=Object.assign({},...T);for(const f of Ot){const y=Object.assign({},...T.map(S=>S[f])),p=Object.entries(y).sort(([S],[B])=>S>B?1:-1);p.length?R[f]=Object.fromEntries(p):delete R[f]}if(R.name=l,w.writeFileSync(x.join(s,"package.json"),JSON.stringify(R,null,4)+`
48
+ `),a){const f=[x.resolve(h,"../skills"),x.resolve(h,"../../skills")].find(p=>w.existsSync(p));if(!f)throw new Error("Skills directory not found");const y=w.readdirSync(f,{withFileTypes:!0}).filter(p=>p.isDirectory()).map(p=>p.name);for(const p of[".claude/skills",".agents/skills"])for(const S of y)w.cpSync(x.join(f,S),x.join(s,p,S),{recursive:!0});L.step("Added PlayCanvas agent skills (opt out with --no-skills)")}let I=`Project created. Now run:
49
+ `;const v=x.isAbsolute(r)?s:x.relative(t,s);switch(s!==t&&(I+=`
50
+ cd ${v.includes(" ")?`"${v}"`:v}`),u){case"yarn":I+=`
51
+ yarn`,I+=`
52
+ yarn dev`;break;default:I+=`
53
+ ${u} install`,I+=`
54
+ ${u} run dev`;break}gt(I)},j=$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"]}),Lt=process.cwd(),Mt=`Usage: npm create playcanvas@latest [OPTION]...
55
55
 
56
56
  Create a new PlayCanvas project with TypeScript.
57
57
  With no arguments, start the CLI in interactive mode.
@@ -63,4 +63,7 @@ Options:
63
63
  --no-skills omit the PlayCanvas agent skills
64
64
  -y, --yes skip the prompts and take the defaults
65
65
  -h, --help show help
66
- `,Kt={_gitignore:".gitignore",_npmrc:".npmrc"},Ht="playcanvas-project",zt=async()=>{const e=L._[0]?Q(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(Gt);return}const c=()=>{vt("Operation cancelled"),process.exit(0)},a=await Lt({argTargetDir:e,defaultTargetDir:Ht,yes:n,cancel:c});await Nt({targetDir:a,argOverwrite:i,yes:n,cancel:c});const o=await Bt({targetDir:a,yes:n,cancel:c}),s=await jt({argFormat:t,yes:n,cancel:c}),u=await Ot({argStarter:r,yes:n,cancel:c}),d=L.skills??!0;Vt({cwd:Ut,targetDir:a,format:s,starter:u,packageName:o,skills:d,renameFiles:Kt})};zt().catch(e=>{console.error(e instanceof Error?e.message:e),process.exitCode=1});
66
+
67
+ Without a terminal, as when an AI agent or CI runs it, the CLI takes the
68
+ defaults for any option not passed, as --yes does.
69
+ `,Pt={_gitignore:".gitignore",_npmrc:".npmrc"},Nt="playcanvas-project",Dt=async()=>{const e=j._[0]?Y(String(j._[0])):void 0,t=j.format??j.template,r=j.starter??j.boilerplate,i=j.overwrite,n=!!(process.stdin.isTTY&&process.stdout.isTTY),l=j.yes||!n;if(j.help){console.log(Mt);return}!n&&!j.yes&&L.info("Not running in a terminal, so using the defaults for any option not passed");const a=()=>{pt("Operation cancelled"),process.exit(0)},o=await kt({argTargetDir:e,defaultTargetDir:Nt,yes:l,cancel:a});await jt({targetDir:o,argOverwrite:i,yes:l,cancel:a});const s=await Tt({targetDir:o,yes:l,cancel:a}),u=await Ft({argFormat:t,yes:l,cancel:a}),d=await Ct({argStarter:r,yes:l,cancel:a}),h=j.skills??!0;Bt({cwd:Lt,targetDir:o,format:u,starter:d,packageName:s,skills:h,renameFiles:Pt})};Dt().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.10.1",
3
+ "version": "0.11.1",
4
4
  "description": "Scaffold a PlayCanvas project",
5
5
  "keywords": [
6
6
  "playcanvas",
@@ -39,6 +39,7 @@
39
39
  "fmt:fix": "prettier --write .",
40
40
  "lint": "eslint .",
41
41
  "lint:fix": "eslint . --fix",
42
+ "test": "vitest run",
42
43
  "typecheck": "tsc --noEmit"
43
44
  },
44
45
  "devDependencies": {
@@ -48,8 +49,10 @@
48
49
  "eslint": "^9.39.5",
49
50
  "mri": "^1.2.0",
50
51
  "picocolors": "^1.1.1",
51
- "prettier": "^3.9.9",
52
- "unbuild": "^3.6.1"
52
+ "prettier": "^3.9.10",
53
+ "unbuild": "^3.6.1",
54
+ "vite": "^8.3.5",
55
+ "vitest": "^5.0.5"
53
56
  },
54
57
  "engines": {
55
58
  "node": ">=22.23.2"
@@ -7,10 +7,13 @@ These files are copied from `playcanvas/engine` tag `v2.21.4` (commit
7
7
  They are a WebAssembly build of [ammo.js](https://github.com/kripken/ammo.js),
8
8
  distributed under the zlib license in `LICENSE`.
9
9
 
10
+ The asm.js fallback in that folder, `ammo.js`, is left out, so the starters
11
+ configure no fallback: every browser that runs them supports WebAssembly, and
12
+ Vite would copy the 2 MB file into every physics project's build.
13
+
10
14
  ## SHA-256
11
15
 
12
16
  ```text
13
- ef166d1315bc4a6441a8de341ecdf6ac4e7d69055caec65c523ed1a4e8e19b15 ammo.js
14
17
  5645b5a0c4f03be9d9d1ae604ffacd5e5e525310cfd1d0ed27474cdd1f34aab0 ammo.wasm.js
15
18
  a61b504d4a6ce6bb93bd843e0f61edb8115e7317f1b3462247031a83ddb25d09 ammo.wasm.wasm
16
19
  ```
@@ -1,9 +1,3 @@
1
- .full-bleed {
2
- width: 100vw;
3
- height: 100vh;
4
- overflow: hidden;
5
- }
6
-
7
1
  .counter {
8
2
  position: fixed;
9
3
  bottom: 22px;
@@ -0,0 +1,42 @@
1
+ ## Snapchat Web Lens
2
+
3
+ A portrait, one-thumb dodge game set up to run inside Snapchat as a [Web Lens](https://developers.snap.com/web-lenses/home). It submits each run to the Lens leaderboard, keeps the player's best score in Snapchat storage and shows their Bitmoji, all through the [Web Lens API](https://developers.snap.com/web-lenses/web-lens-api).
4
+
5
+ ### Controls
6
+
7
+ Drag left and right to steer the ball around the falling blocks. Tap to start, and tap again after a crash to play another run.
8
+
9
+ ### Publishing to Snapchat
10
+
11
+ ```bash
12
+ npm run package
13
+ ```
14
+
15
+ This builds the game into `dist/lens/`, checks it against the [Web Lens upload rules](https://developers.snap.com/web-lenses/requirements) and writes a zip to `dist/` to upload through [My Lenses](https://my-lenses.snapchat.com/). It writes no zip if:
16
+
17
+ - the zip is over 8 MB, or `index.html` is over 1 MB
18
+ - the build refers to one of its own files by an absolute path, such as `/assets/game.js`
19
+ - the build loads anything from another host, such as a script from a CDN or a web font
20
+ - the build uses something the Lens sandbox blocks, such as an `<iframe>` or a web app manifest
21
+
22
+ It warns about any other host your scripts mention, since a Lens can't reach the network. To check the build itself, `npm run start` serves it under the same rules, so a request for anything outside the zip fails in the browser console as it would in Snapchat.
23
+
24
+ ### How it fits together
25
+
26
+ - `src/dodge-game.ts` is the game, an engine script that fires a `game:state` app event for the HUD to follow.
27
+ - `src/lens.ts` wraps the Web Lens API. Outside Snapchat the API answers from a built-in stub with canned data, so the game runs in any browser, and every call falls back to playing on without the feature.
28
+ - `src/lens.css` fills the phone screen and shows a 9:16 column on wider screens. It keeps the HUD clear of the controls Snapchat draws over the top of a Lens, and `npm run dev` marks the room they take.
29
+ - `vite.config.ts` makes every URL in the build relative, which a Lens needs.
30
+
31
+ ### Make it your own
32
+
33
+ The game is the only part that's specific to Dodge, so replace it and keep the rest:
34
+
35
+ - **Replace** `src/dodge-game.ts` with your game. The HUD follows its `game:state` app event and shows the text in its `CARDS`, so fire the same event from your game, or rework the HUD in `index.html` and `src/main.ts` (`src/App.tsx` in React). Rename Dodge in the page `<title>` too.
36
+ - **Keep** `src/lens.ts`, `src/lens.css`, `vite.config.ts` and `scripts/package-lens.mjs`. None of them depends on the game.
37
+ - **Report each run to Snapchat** by calling `recordScore(score)` from `src/lens.ts` when it ends. That submits the score to the leaderboard, saves a new best to Snapchat storage and resolves the best score. Call `showLeaderboard()` from a button, and `loadBest()` and `loadAvatar()` at startup for the saved best and the player's Bitmoji.
38
+ - **Stick to what a Lens needs:** a portrait layout, a HUD kept inside the safe area with the `--inset-*` properties from `src/lens.css`, a pause when the page is hidden, audio that starts from a tap, and every asset bundled into the build, since a Lens can't reach the network.
39
+
40
+ Lenses run on phones, in portrait. To try the game on yours, run `npm run dev -- --host` and open the network URL it prints.
41
+
42
+ When you're ready to publish, follow Snap's [publishing guide](https://developers.snap.com/web-lenses/publishing): you'll also need a 512 × 512 PNG icon and a 5-second, 720 × 1280 preview video.
@@ -0,0 +1,9 @@
1
+ {
2
+ "description": "A PlayCanvas game for Snapchat Web Lenses",
3
+ "scripts": {
4
+ "package": "vite build && node scripts/package-lens.mjs dist/lens"
5
+ },
6
+ "dependencies": {
7
+ "@snap/web-lens-api": "^0.1.2"
8
+ }
9
+ }