create-playcanvas 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/index.mjs +35 -33
  2. package/package.json +4 -4
  3. package/skills/add-effects/SKILL.md +21 -72
  4. package/skills/apply-conventions/SKILL.md +33 -59
  5. package/skills/assemble-scene/SKILL.md +18 -43
  6. package/skills/assemble-scene/references/direct-engine.md +2 -2
  7. package/skills/assemble-scene/references/react.md +3 -3
  8. package/skills/assemble-scene/references/web-components.md +2 -2
  9. package/skills/bake-lighting/SKILL.md +25 -50
  10. package/skills/build-app/SKILL.md +29 -28
  11. package/skills/build-app/references/web-components.md +3 -3
  12. package/skills/calibrate-model/SKILL.md +18 -48
  13. package/skills/calibrate-model/references/web-components.md +3 -3
  14. package/skills/configure-animation/SKILL.md +21 -37
  15. package/skills/configure-animation/references/direct-engine.md +2 -2
  16. package/skills/configure-animation/references/react.md +3 -3
  17. package/skills/find-examples/SKILL.md +24 -60
  18. package/skills/inspect-glb/SKILL.md +21 -62
  19. package/skills/light-scene/SKILL.md +29 -82
  20. package/skills/load-assets/SKILL.md +52 -0
  21. package/skills/override-shader-chunks/SKILL.md +21 -55
  22. package/skills/reduce-draw-calls/SKILL.md +24 -48
  23. package/skills/reuse-scripts/SKILL.md +23 -42
  24. package/skills/reuse-scripts/references/direct-engine.md +8 -28
  25. package/skills/reuse-scripts/references/react.md +2 -12
  26. package/skills/reuse-scripts/references/web-components.md +2 -15
  27. package/skills/verify-pixels/SKILL.md +30 -44
  28. package/templates/engine/base/package.json +3 -3
  29. package/templates/react/ar-placement/src/App.tsx +29 -21
  30. package/templates/react/base/package.json +8 -8
  31. package/templates/react/sprite-game/src/App.tsx +21 -13
  32. package/templates/web-components/base/package.json +4 -4
  33. package/templates/web-components/interactive-sphere/index.html +1 -1
  34. package/templates/web-components/splat-viewer/index.html +1 -1
  35. package/skills/build-hud/SKILL.md +0 -38
  36. package/skills/manage-game-state/SKILL.md +0 -48
package/dist/index.mjs CHANGED
@@ -1,55 +1,57 @@
1
1
  #!/usr/bin/env node
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(`
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(`
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 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(`
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(`
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
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(`
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
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(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(`
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(`
18
18
  `)}
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)}
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)}
20
20
 
21
- `)},vt=(e="",t)=>{const r=process.stdout,i=`${u("gray",v)}
22
- ${u("gray",U)} `;r.write(`${i}${e}
21
+ `)},St=(e="",t)=>{const r=process.stdout,i=`${l("gray",v)}
22
+ ${l("gray",V)} `;r.write(`${i}${e}
23
23
 
24
- `)},St=[`${u("dim","\u2191/\u2193")} to navigate`,`${u("dim","Enter:")} confirm`],X=(e,t)=>e.includes(`
24
+ `)},Et=[`${l("dim","\u2191/\u2193")} to navigate`,`${l("dim","Enter:")} confirm`],X=(e,t)=>e.includes(`
25
25
  `)?e.split(`
26
26
  `).map(r=>t(r)).join(`
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)}
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)}
28
28
  `:""}${a}
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(`
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(`
33
33
  ${s}`)}
34
34
  ${h}
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()}
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}
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()}
38
40
  ${o}${n}
39
41
  ${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
+ `}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
44
  ${o}
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()}
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()}
44
46
 
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
+ ${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:
47
49
  `;const I=y.isAbsolute(r)?s:y.relative(t,s);switch(s!==t&&(R+=`
48
- cd ${I.includes(" ")?`"${I}"`:I}`),l){case"yarn":R+=`
50
+ cd ${I.includes(" ")?`"${I}"`:I}`),u){case"yarn":R+=`
49
51
  yarn`,R+=`
50
52
  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]...
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]...
53
55
 
54
56
  Create a new PlayCanvas project with TypeScript.
55
57
  With no arguments, start the CLI in interactive mode.
@@ -61,4 +63,4 @@ Options:
61
63
  --no-skills omit the PlayCanvas agent skills
62
64
  -y, --yes skip the prompts and take the defaults
63
65
  -h, --help show help
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});
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});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-playcanvas",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Scaffold a PlayCanvas project",
5
5
  "keywords": [
6
6
  "playcanvas",
@@ -42,13 +42,13 @@
42
42
  "typecheck": "tsc --noEmit"
43
43
  },
44
44
  "devDependencies": {
45
- "@clack/prompts": "^1.7.0",
45
+ "@clack/prompts": "^1.8.1",
46
46
  "@playcanvas/eslint-config": "3.0.0-beta.8",
47
- "@types/node": "22.20.1",
47
+ "@types/node": "22.20.4",
48
48
  "eslint": "^9.39.5",
49
49
  "mri": "^1.2.0",
50
50
  "picocolors": "^1.1.1",
51
- "prettier": "^3.9.6",
51
+ "prettier": "^3.9.9",
52
52
  "unbuild": "^3.6.1"
53
53
  },
54
54
  "engines": {
@@ -1,81 +1,30 @@
1
1
  ---
2
2
  name: add-effects
3
- description: Use when adding transient visual effects or trails to a PlayCanvas app to select an Engine-native implementation, place and layer it correctly, manage its lifecycle, and verify the rendered result.
3
+ description: Use when adding visual effects to a PlayCanvas app, to choose between particle systems, shader chunks, runtime meshes, and post-processing.
4
4
  ---
5
5
 
6
- # Effects and game feel
6
+ # Effects
7
7
 
8
- Add transient effects as short-lived, self-owning entities triggered by application events, not as
9
- permanent scene fixtures.
8
+ Pick the Engine building block first, then adapt its closest official example with
9
+ `find-examples`:
10
10
 
11
- Reuse before authoring. Adapt the closest official particle example with `find-examples`, prefer the
12
- Engine's built-in particle component over a hand-written system, and discover any shipped trail or
13
- effect script with `reuse-scripts`.
11
+ - Particle systems: the `particlesystem` component (`graphics/particles-*` examples).
12
+ - Custom shading on existing surfaces: `StandardMaterial` chunk overrides
13
+ (`override-shader-chunks`), or a `ShaderMaterial` when the effect needs its own shader pair.
14
+ - Procedural or per-frame geometry: a runtime-updated `Mesh` on a `render` component
15
+ (`graphics/mesh-*` examples), or `WideLineRenderer` for lines with width.
16
+ - Full-screen effects: `CameraFrame` (`light-scene`).
17
+ - Gaussian splat effects: the shipped gsplat scripts (`reuse-scripts`).
14
18
 
15
- Copy particle curve construction from the installed example exactly. `CurveSet` takes one key array
16
- per channel, such as `new CurveSet([0, x0, 1, x1], [0, y0, 1, y1], [0, z0, 1,
17
- z1])`; do not flatten three channels into one array. A malformed curve can type-check and then fail
18
- inside the particle texture upload. Create one emitter, render a frame, and require empty runtime
19
- and console diagnostics before reusing the helper for smoke, spray, or splashes.
19
+ ## Engine gotchas
20
20
 
21
- For a polished wake, smoke, or spray requirement, do not stop at scaled planes, crossed billboards,
22
- or generic render primitives. Use the built-in particle component for smoke and spray; reserve a
23
- custom mesh and material for a continuously sampled wake ribbon. Verify tint and blending against
24
- the actual scene lighting and surface.
21
+ - `CurveSet` takes one key array per channel. A flattened array type-checks, then fails at texture
22
+ upload.
23
+ - Create emitters and meshes at load and reuse them. Fire an emitter with `reset()` then `play()`;
24
+ one-shots use `loop: false`.
25
+ - The first use of a shader stalls a frame. Render each effect once behind a loading screen.
26
+ - Animate values with `setParameter`, not a per-frame `material.update()`.
27
+ - A lit material on a custom mesh needs normals; otherwise use an unlit material.
25
28
 
26
- ## Place and layer
27
-
28
- - Spawn an effect at the emitter's world mount point, either parent it there or copy the world
29
- transform once, and let it destroy itself when finished. Never leak emitters.
30
- - Keep additive or transparent effects above the surface they sit on and biased toward the camera so
31
- they do not z-fight. Inspect soft transparency at grazing angles for hard edges, black quads, or
32
- dropout.
33
- - Size and orient effects from the emitter's calibrated bounds, not a guessed constant.
34
-
35
- ## Moving trails
36
-
37
- - Treat built-in render primitives as blocking geometry for soft effects. Follow the closest
38
- official example to choose particles, a custom mesh, textures, materials, and blending for the
39
- intended visual behavior.
40
- - Match every custom mesh's vertex streams to its material. A lit `StandardMaterial` needs normals;
41
- calculate and set them before `mesh.update()`, or deliberately use an unlit material. Treat a
42
- missing vertex-attribute diagnostic as a rendering failure even when some frames still appear.
43
- For a dynamic horizontal ribbon created with `setVertexStream`, allocate a normal array alongside
44
- positions, fill every vertex with `(0, 1, 0)`, and upload it as `SEMANTIC_NORMAL` before the first
45
- `update()`. Recheck this whenever changing the ribbon's material type.
46
- - Never attach an empty dynamic mesh to an enabled render component. Upload a valid initial vertex
47
- and index set before creating its `MeshInstance`, or keep the render entity disabled until the
48
- first complete update. On reset, disable it or restore valid seed geometry; do not call
49
- `mesh.clear()` while an enabled renderer still references it. Reflection and refraction cameras
50
- render the same mesh and can expose this lifecycle bug before the gameplay camera does.
51
- - Judge a trail from its intended cameras. If it reads as a flat decal, use the reference example to
52
- add the minimum depth cue needed rather than stacking arbitrary geometry.
53
- - Sample the trail continuously. Append segments on a small time- or distance-step and interpolate
54
- between them; coarse per-distance chunks make the trail stutter and break into visible dashes as
55
- the object speeds up.
56
- - Anchor it to the mover's contact or exhaust point, scale emission rate and length with speed, and
57
- fade the tail so it dissolves instead of cutting off with a hard edge.
58
-
59
- ## Camera shake and hit feedback
60
-
61
- - Drive camera shake as a decaying offset on a camera parent or an additive layer; never write it
62
- into the smoothed chase position, or it fights the follow. Keep shake and follow separate, as the
63
- orbit-camera rule in `apply-conventions` requires.
64
- - Stagger the parts of a compound effect over a few frames — flash, then smoke, then splash — so an
65
- event reads as a sequence rather than a single pop.
66
- - Keep the readable peak long enough for the gameplay camera to see the layers together. A flash can
67
- be brief, but the longer-lived layers should overlap for several frames rather than leaving the
68
- primary action frame visually identical to the idle state.
69
- - For side-mounted emitters, derive every spawn point and direction from calibrated world-space
70
- mounts on the mover. Confirm the effect starts outside the source geometry from both sides; an
71
- active cooldown with only a tiny flash elsewhere in the frame is failed feedback.
72
-
73
- ## Prove it fires
74
-
75
- Trigger each effect through real gameplay input and confirm with a screenshot captured at its peak,
76
- not a saved filepath. Confirm the effect is visible from the gameplay camera and from a grazing
77
- angle, that emitters are gone after their lifetime (query the entity count), and that nothing leaves
78
- a black quad or a hard edge over the surface.
79
-
80
- Choose the authoring surface with the `build-app` skill; create effects through its entity and
81
- component primitives and own their lifecycle in the surface that spawned them.
29
+ Trigger each effect through the app's real inputs, and confirm repeated triggers keep entity counts
30
+ stable.
@@ -1,75 +1,49 @@
1
1
  ---
2
2
  name: apply-conventions
3
- description: Use when writing or reviewing PlayCanvas Engine code involving entity transforms, cameras, physics, materials, model orientation, bounds, or imports to apply the Engine's coordinate and API conventions.
3
+ description: Use when writing PlayCanvas Engine code touching transforms, cameras, lights, materials, meshes, bounds, or imports, to apply Engine conventions and avoid legacy APIs.
4
4
  ---
5
5
 
6
6
  # Engine conventions
7
7
 
8
- Read `package.json` and the installed `playcanvas` source before relying on version-sensitive API
9
- details. Apply these stable conventions throughout the project.
8
+ Check version-sensitive APIs against installed `playcanvas` declarations.
10
9
 
11
- ## Coordinates and angles
10
+ ## Coordinates
12
11
 
13
- - Use the right-handed coordinate system: +Y is up and the gameplay ground plane is XZ.
14
- - Treat `entity.forward` and the camera viewing direction as -Z; `entity.right` is +X and
15
- `entity.up` is +Y. `lookAt` points -Z at the target.
16
- - Expect glTF models authored toward +Z to need a yaw correction. Inspect and calibrate each
17
- directional model instead of applying one global correction.
18
- - Pass degrees in XYZ order to high-level angle APIs.
19
- - Keep pitch, yaw, and roll as application state. Do not repeatedly read `getEulerAngles()` and
20
- feed its decomposition back into `setEulerAngles()`.
21
- - Interpolate periodic angles with `math.lerpAngle()` or rotations with `Quat.slerp()`, not scalar
22
- lerp across the 0/360 seam.
12
+ - Right-handed, +Y up, metres. `entity.forward`, cameras, and `lookAt` use -Z.
13
+ - Directional and spot lights shine along local -Y, straight down by default. Aim them with
14
+ `setEulerAngles`, not `lookAt`.
15
+ - glTF models usually face +Z; record per-model yaw with `calibrate-model`.
16
+ - Angle APIs take degrees in XYZ order. Keep pitch, yaw, and roll as app state; never feed
17
+ `getEulerAngles()` back into `setEulerAngles()`. Interpolate with `math.lerpAngle` or
18
+ `Quat.slerp`.
19
+ - Use world setters on semantic roots and `setLocal*` below a parent. Never scale rigid-body roots
20
+ or skinned bones.
23
21
 
24
- ## Transforms and units
22
+ ## Current APIs
25
23
 
26
- - Use `setPosition`, `setRotation`, and `setEulerAngles` for world transforms.
27
- - Use the `setLocal*` variants below a parent.
28
- - Treat units as metres. Physics gravity defaults to `(0, -9.81, 0)`.
29
- - Keep gameplay transforms on a semantic root and asset-authoring corrections on a child.
30
- - Do not scale rigid-body roots or skinned bones.
24
+ - `render` and `anim` components, not `model` and `animation`.
25
+ - ESM `class X extends Script` with `static scriptName`, not `createScript`.
26
+ - `Mesh.fromGeometry(device, new BoxGeometry())`, not `createBox` and the other `create*` helpers.
27
+ - Named imports from `playcanvas`; shipped scripts only from `playcanvas/scripts/esm/**`.
31
28
 
32
- ## Cameras, materials, and bounds
29
+ ## Cameras
33
30
 
34
- - Perspective camera FOV is vertical and defaults to 45 degrees.
35
- - Smooth an orbit camera's focus, yaw, pitch, and distance, then derive its position. Do not
36
- `Vec3.lerp()` between orbit positions on opposite sides of the focus; the chord crosses the subject.
37
- - Before writing custom camera input, inspect the installed controller script and its matching
38
- Engine example. Preserve their gesture mapping and damping unless the product explicitly asks
39
- for different behavior; do not derive signs from memory.
40
- - Define the input contract in screen space, then verify positive and negative movement on both axes
41
- with real input after a rendered frame. Judge the camera basis or a projected fixed landmark, not
42
- world-space camera coordinates or internal angle signs; both can approve inverted behavior.
43
- - Materials cull back faces by default; counter-clockwise winding defines the front face.
44
- - Clone a material before per-instance tinting or edits, and assign the clone; never mutate one
45
- shared by other instances, including default and asset-imported materials.
46
- - `setParameter` uploads raw values; author colours in sRGB and convert with `Color#linear()`
47
- before upload — do not hand-roll gamma.
48
- - Entities do not have an `aabb`. Union descendant `meshInstance.aabb` values after transforms have
49
- synchronized.
50
- - Let `Mesh.update()` calculate local bounds. If passing `false` for `updateBoundingBox`, assign an
51
- explicit `mesh.aabb` before the mesh can be culled.
52
- - Expand custom-mesh bounds by the maximum vertex-shader displacement; CPU bounds do not observe
53
- shader deformation.
54
- - Treat offline skinned-mesh bounds as bind-pose estimates and confirm animated poses at runtime.
31
+ - FOV is vertical, 45° by default. Check shipped camera scripts before writing controls
32
+ (`reuse-scripts`).
55
33
 
56
- ## Imports
34
+ ## Materials and bounds
57
35
 
58
- Use named ESM imports from `playcanvas`. Import production scripts only from
59
- `playcanvas/scripts/esm/**`; legacy sibling script directories depend on a global Engine namespace.
36
+ - `StandardMaterial.useMetalness` defaults to `false`; enable it before using `metalness`.
37
+ - Call `material.update()` after property edits. Per-mesh values use `meshInstance.setParameter()`
38
+ with no update or clone.
39
+ - Clone shared materials, including imported ones, before editing them for some meshes.
40
+ - `setParameter` uploads raw values; convert sRGB colours with `Color#linear()`.
41
+ - Back faces cull by default; counter-clockwise winding is the front face.
42
+ - Entities have no `aabb`; union descendant `meshInstance.aabb`. If `mesh.update()` skips bounds,
43
+ set `mesh.aabb` yourself, and expand it by any vertex-shader displacement.
60
44
 
61
- ## Runtime confirmation
45
+ ## Verify in the running app
62
46
 
63
- Offline measurements cannot prove facing, animated poses, or final placement. Confirm each one in the
64
- running application:
65
-
66
- - Start the project's own dev server or build; do not construct a separate harness.
67
- - Log the value from inside the Engine, using `getPosition()`, `getEulerAngles()`, a
68
- `meshInstance.aabb`, or an anim component's active state, from a `Script` or an update callback.
69
- - For large or vertex-displaced meshes, inspect their runtime AABB and `visibleThisFrame` after a
70
- rendered frame from at least two representative camera angles.
71
- - Confirm a directional model's visible front aligns with its semantic root's `forward`; a stored
72
- yaw or runtime transform alone cannot prove mesh facing.
73
- - Read that logged value from the browser console. Screenshots judge composition and orientation;
74
- numeric claims require logged values.
75
- - Record the confirmed value in application state or an asset tuning record, then remove the logging.
47
+ Offline values cannot prove facing, poses, or placement. Log values from a `Script` or update
48
+ callback in the running app, and judge visuals only from screenshots you have inspected. A saved
49
+ file path is not evidence.
@@ -1,53 +1,28 @@
1
1
  ---
2
2
  name: assemble-scene
3
- description: Use when composing PlayCanvas Engine, React, or Web Components gameplay entities, model hierarchies, colliders, or physics objects to create one semantic root per object with calibrated visuals and predictable lifecycle ownership.
3
+ description: Use when composing PlayCanvas entity hierarchies from models, colliders, rigid bodies, and scripts, so each object has one semantic root and clear lifecycle.
4
4
  ---
5
5
 
6
6
  # Scene assembly
7
7
 
8
- Represent one gameplay object with one named semantic root. Put gameplay position, heading,
9
- rigid-body, collision, and behavior on that root. Put calibrated render transforms below it.
8
+ Each scene object has one named root. Put position, heading, `rigidbody`, `collision`, and
9
+ scripts on the root, and the calibrated visual from `calibrate-model` below it. Apply calibration
10
+ once; if the tuning record is missing, calibrate first.
10
11
 
11
- Consume the existing tuning record from `calibrate-model` exactly once. If it is missing, stop and
12
- calibrate the model; do not calculate or adjust asset tuning during assembly.
12
+ - Name roots by role, with predictable names for repeated instances.
13
+ - Size colliders from measured bounds and keep them aligned with render bounds.
14
+ - Space roots by the scaled footprint in the tuning record, not by pivot position. A non-90° yaw
15
+ rotates the footprint, so reserve its larger horizontal extent.
16
+ - Keep UI, effects, cameras, and lights outside model hierarchies.
17
+ - Remove the root through its surface's lifecycle and unregister events it owns.
18
+ - Rigid bodies need Ammo loaded first (`build-app`).
13
19
 
14
- ## Assembly rules
20
+ ## Check placement
15
21
 
16
- - Name roots by gameplay role and use predictable names for repeated instances.
17
- - Apply model calibration once inside the visual child; never reapply scale, grounding, or authored
18
- yaw during placement.
19
- - Space neighbouring roots by their scaled footprints and pivot offsets from `calibrate-model`, not
20
- by pivot position. A non-90° authored yaw rotates a footprint, so reserve its larger horizontal
21
- extent as a conservative radius.
22
- - Put rigid-body and collision components on the same root. Size colliders from measured bounds.
23
- - Use local transforms below a parent and world transforms only for semantic roots.
24
- - Keep UI, effects, cameras, and lights outside gameplay model hierarchies.
25
- - Remove the root through its authoring surface's lifecycle. Unregister external events it owns.
26
- - Do not scale rigid-body roots or skinned bones.
22
+ After a rendered frame, measure each support or attachment at the object's actual position, using
23
+ a mount point, raycast, or geometry sample. A positive gap floats; a negative gap penetrates.
24
+ Overlapping world AABBs between unrelated roots are a failure unless two different views prove the
25
+ overlap is empty space.
27
26
 
28
- ## Prove placement
29
-
30
- Declare intentional support, attachment, or containment relationships between roots. After a
31
- rendered frame, measure each relationship at the supported object's actual position. Use a mount
32
- point, collision ray, or geometry sample; use a support root's AABB maximum only when its top is flat
33
- across the full footprint. Record the signed contact gap: positive means floating and negative means
34
- penetration. A relationship name does not exempt the pair from this check.
35
-
36
- Union descendant world `meshInstance.aabb` values for each semantic root and compare unrelated peer
37
- roots. Any intersection with positive depth on X, Y, and Z beyond a small tolerance is an unresolved
38
- placement failure: move the root from its calibrated footprint, or prove the apparent AABB overlap
39
- is empty geometry from at least two materially different views. Never accept one model inside
40
- another from a single screenshot.
41
-
42
- Also check expected root counts, component descendants, aligned render and collider bounds, and
43
- role-based names. Compare final dimensions with each calibration record's intended size and reference
44
- object. Inspect composition and facing from images returned into your context by an image-capable
45
- browser tool. A saved screenshot path, screen coordinate, AABB, or visibility flag is not visual
46
- evidence. If you cannot inspect the image, report those claims unverified. Hierarchy and placement
47
- claims require runtime values logged from the application itself, as the `apply-conventions` skill
48
- describes.
49
-
50
- Read exactly one reference matching the code being edited:
51
- [direct Engine](references/direct-engine.md), [React](references/react.md), or
52
- [Web Components](references/web-components.md). Choose from imports and markup, not installed
53
- dependencies alone.
27
+ Read only the reference matching the code: [direct Engine](references/direct-engine.md),
28
+ [React](references/react.md), or [Web Components](references/web-components.md).
@@ -5,8 +5,8 @@ Create one root and place a previously calibrated model beneath it:
5
5
  ```ts
6
6
  import { Entity } from 'playcanvas';
7
7
 
8
- const root = new Entity('Enemy_1');
9
- root.addChild(instance('enemy'));
8
+ const root = new Entity('Model_1');
9
+ root.addChild(instance('model'));
10
10
  root.setPosition(x, 0, z);
11
11
  root.setEulerAngles(0, heading, 0);
12
12
  app.root.addChild(root);