greenlight-motion 0.2.0 → 0.2.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.
- package/README.md +9 -9
- package/dist/greenlight-motion-script.mjs +61 -2
- package/dist/greenlight-motion.js +1 -1
- package/dist/greenlight-motion.mjs +1 -1
- package/package.json +1 -1
- package/skill/SKILL.md +40 -10
- package/skill/references/scene-script.md +16 -0
package/README.md
CHANGED
|
@@ -17,16 +17,16 @@ The agent writes the video as data: a `project.json` and its files. The engine t
|
|
|
17
17
|
## Quick start
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
npx greenlight-motion@0.2.
|
|
21
|
-
npx greenlight-motion@0.2.
|
|
20
|
+
npx greenlight-motion@0.2.1 doctor # Node 18+, Chrome or Edge, WebGPU, H.264: what's missing and how to fix it
|
|
21
|
+
npx greenlight-motion@0.2.1 init my-video # a working starter: index.html, project.json, assets/
|
|
22
22
|
# edit my-video/project.json, put pictures / video / sound in my-video/assets/
|
|
23
23
|
# or: write my-video/script.json (a scene script, skill/references/scene-script.md), then
|
|
24
|
-
npx greenlight-motion@0.2.
|
|
25
|
-
npx greenlight-motion@0.2.
|
|
26
|
-
npx greenlight-motion@0.2.
|
|
27
|
-
npx greenlight-motion@0.2.
|
|
28
|
-
npx greenlight-motion@0.2.
|
|
29
|
-
npx greenlight-motion@0.2.
|
|
24
|
+
npx greenlight-motion@0.2.1 script my-video # script.json → project.json with the Video Editor's own presets
|
|
25
|
+
npx greenlight-motion@0.2.1 check my-video # what to fix: missing files, template mistakes, blank frames, broken plugins
|
|
26
|
+
npx greenlight-motion@0.2.1 stills my-video # frames + a labelled contact sheet, to look at
|
|
27
|
+
npx greenlight-motion@0.2.1 render my-video --fps 60 --motion-blur
|
|
28
|
+
npx greenlight-motion@0.2.1 pack my-video # everything in ONE html file
|
|
29
|
+
npx greenlight-motion@0.2.1 pack my-video --glvideo # ONE .glvideo: double-clicked, it opens in GreenLight Dash
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
Also: `trace` (every animated layer's values frame by frame, plus the layer's moments), `set key=value`
|
|
@@ -72,7 +72,7 @@ The engine is one classic script, so it runs from a double-clicked file, a CDN o
|
|
|
72
72
|
|
|
73
73
|
```html
|
|
74
74
|
<div id="app"></div>
|
|
75
|
-
<script src="https://cdn.jsdelivr.net/npm/greenlight-motion@0.2.
|
|
75
|
+
<script src="https://cdn.jsdelivr.net/npm/greenlight-motion@0.2.1/dist/greenlight-motion.js"></script>
|
|
76
76
|
<script>
|
|
77
77
|
GreenLightMotion.mountStudio(document.getElementById('app'), {
|
|
78
78
|
project: { /* project.json */ },
|
|
@@ -18870,6 +18870,27 @@ function cameraCatalog() {
|
|
|
18870
18870
|
var FONT = "'Helvetica Neue', Helvetica, Arial, sans-serif";
|
|
18871
18871
|
var TEXT = new Map([...PRESETS, ...CLASSIC_PRESETS].map((p) => [p.id, p]));
|
|
18872
18872
|
var TEXT_RENAMED = { "glide-soft": "glide-continuous" };
|
|
18873
|
+
var rgbOf = (c) => {
|
|
18874
|
+
const m = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(String(c || "").trim());
|
|
18875
|
+
if (!m) return null;
|
|
18876
|
+
const h = m[1].length === 3 ? m[1].split("").map((x) => x + x).join("") : m[1];
|
|
18877
|
+
return [0, 2, 4].map((i) => parseInt(h.slice(i, i + 2), 16));
|
|
18878
|
+
};
|
|
18879
|
+
var vivid = (c) => {
|
|
18880
|
+
const v = rgbOf(c);
|
|
18881
|
+
return !!v && Math.max(...v) - Math.min(...v) >= 40;
|
|
18882
|
+
};
|
|
18883
|
+
var luminance = (c) => {
|
|
18884
|
+
const v = rgbOf(c);
|
|
18885
|
+
if (!v) return null;
|
|
18886
|
+
const [r, g, b2] = v.map((x) => x / 255 <= 0.03928 ? x / 255 / 12.92 : ((x / 255 + 0.055) / 1.055) ** 2.4);
|
|
18887
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b2;
|
|
18888
|
+
};
|
|
18889
|
+
var contrast = (a, b2) => {
|
|
18890
|
+
const la = luminance(a), lb = luminance(b2);
|
|
18891
|
+
return la == null || lb == null ? 21 : (Math.max(la, lb) + 0.05) / (Math.min(la, lb) + 0.05);
|
|
18892
|
+
};
|
|
18893
|
+
var EDGE_FILLED = /* @__PURE__ */ new Set(["Advanced Zoom", "Advanced Movement"]);
|
|
18873
18894
|
var KF_IN = new Map(kfpVariants(KEYFRAME_PRESETS, "in").map((p) => [p.id, p]));
|
|
18874
18895
|
var KF_OUT = new Map(kfpVariants(KEYFRAME_PRESETS, "out").map((p) => [p.id, p]));
|
|
18875
18896
|
var ROLES = { headline: [0.11, 800], subhead: [0.05, 500], body: [0.036, 400], label: [0.028, 600] };
|
|
@@ -19287,12 +19308,33 @@ function compileScript(script, caps, files = /* @__PURE__ */ new Map()) {
|
|
|
19287
19308
|
else {
|
|
19288
19309
|
const patch = presetPatch(item, p, { clipSec: end - start, fontPx: size, mode: "replace" });
|
|
19289
19310
|
item.textAnimators = el?.textExit ? patch.textAnimators : patch.textAnimators.filter((a) => !(a.range?.drive === "time" && a.range?.animate === "out"));
|
|
19311
|
+
const boxed = [];
|
|
19290
19312
|
item.textAnimators.forEach((a, ai) => (a.effects || []).forEach((fx, fi) => {
|
|
19291
|
-
|
|
19313
|
+
const at2 = `textAnimators.${ai}.effects.${fi}`;
|
|
19314
|
+
if (Array.isArray(fx.colors)) {
|
|
19315
|
+
fx.colors.forEach((c, ci) => {
|
|
19316
|
+
if (vivid(c)) {
|
|
19317
|
+
fx.colors[ci] = colors.accent;
|
|
19318
|
+
accentTargets.push({ itemId: id, path: `${at2}.colors.${ci}` });
|
|
19319
|
+
}
|
|
19320
|
+
});
|
|
19321
|
+
} else if (typeof fx.color === "string" && vivid(fx.color)) {
|
|
19292
19322
|
fx.color = colors.accent;
|
|
19293
|
-
accentTargets.push({ itemId: id, path:
|
|
19323
|
+
accentTargets.push({ itemId: id, path: `${at2}.color` });
|
|
19324
|
+
if (fx.type === "box" && !boxed.includes(a)) boxed.push(a);
|
|
19294
19325
|
}
|
|
19295
19326
|
}));
|
|
19327
|
+
if (boxed.length) {
|
|
19328
|
+
const ink = contrast("#0b0d0c", colors.accent) >= contrast("#ffffff", colors.accent) ? "#0b0d0c" : "#ffffff";
|
|
19329
|
+
const fills = item.textAnimators.flatMap((a) => (a.effects || []).filter((fx) => fx.type === "fill"));
|
|
19330
|
+
if (fills.length) fills.forEach((fx) => {
|
|
19331
|
+
if (contrast(fx.color, colors.accent) < 4.5) fx.color = ink;
|
|
19332
|
+
});
|
|
19333
|
+
else if (contrast(color, colors.accent) < 4.5) {
|
|
19334
|
+
let pidN = Math.max(0, ...item.textAnimators.flatMap((a) => (a.effects || []).map((fx) => Number(String(fx.pid).replace(/^\D+/, "")) || 0)));
|
|
19335
|
+
for (const a of boxed) a.effects = [...a.effects || [], { pid: `p${++pidN}`, type: "fill", color: ink }];
|
|
19336
|
+
}
|
|
19337
|
+
}
|
|
19296
19338
|
item.propertyKeyframes = { ...item.propertyKeyframes || {}, ...patch.propertyKeyframes };
|
|
19297
19339
|
if (patch.textAnimatorPivotX != null) {
|
|
19298
19340
|
item.textAnimatorPivotX = patch.textAnimatorPivotX;
|
|
@@ -19417,6 +19459,7 @@ function compileScript(script, caps, files = /* @__PURE__ */ new Map()) {
|
|
|
19417
19459
|
else if (tr !== "None") {
|
|
19418
19460
|
const prev = num7(scenes[si - 1]?.duration, 3);
|
|
19419
19461
|
sceneItem.transition = tr;
|
|
19462
|
+
if (EDGE_FILLED.has(tr)) sceneItem.transitionOptions = { edgeMode: "none" };
|
|
19420
19463
|
sceneItem.transitionDuration = r3(clamp5(num7(sc?.transitionDuration, 0.6), 0.2, Math.min(prev, D) / 2));
|
|
19421
19464
|
total -= sceneItem.transitionDuration;
|
|
19422
19465
|
if ((S.sound ?? "auto") === "auto") project.sounds.push({ sfx: soundOk("soft-swoosh", where) ? "soft-swoosh" : "standard-swoosh", on: project.channels[0].items.at(-1).id, at: "end" });
|
|
@@ -19495,6 +19538,19 @@ var refOf = (host, topic) => host === "chat" ? `get_motion_reference "${topic}"`
|
|
|
19495
19538
|
function scriptFormatGuide(host = "chat") {
|
|
19496
19539
|
return `## The scene script
|
|
19497
19540
|
|
|
19541
|
+
**Before the script, a direction.** Presets make a video move; they don't give it an idea. Decide in a few lines first,
|
|
19542
|
+
and keep them next to the script:
|
|
19543
|
+
- **The idea**: ONE picture from the subject's own world (its object, place or action: a coffee shop's steam and cup rim,
|
|
19544
|
+
a budgeting app's receipt printing line by line, a running app's track the scenes run along), carried through every scene.
|
|
19545
|
+
- **The palette**: background, text, one accent, plus only the colours that carry meaning (good / bad, before / after).
|
|
19546
|
+
Light or dark on purpose.
|
|
19547
|
+
- **The type**: a big headline against a small support line; aligned left or centred on purpose, not by default.
|
|
19548
|
+
- **Each scene**: what it SHOWS besides its words, built from shapes, lines, \`svg\` you write, keyframes and the camera.
|
|
19549
|
+
The same line centred on a gradient in every scene reads as a template. Judge the stills against the direction, not
|
|
19550
|
+
only for mistakes.${host === "cli" ? `
|
|
19551
|
+
What a script can't say (a custom GLSL shader on a shape or the background, words dipping under a surface with a track
|
|
19552
|
+
matte, masks, particles, 3D) goes on from \`project.json\`: SKILL.md, "Beyond the script".` : ""}
|
|
19553
|
+
|
|
19498
19554
|
\`\`\`json
|
|
19499
19555
|
{
|
|
19500
19556
|
"title": "Bean There \u2014 opening day",
|
|
@@ -19539,6 +19595,9 @@ function scriptFormatGuide(host = "chat") {
|
|
|
19539
19595
|
(the scene's camera doesn't move it: a logo, a caption). Keyframes also take a \`z\` track.
|
|
19540
19596
|
- **Scene**: \`duration\` (s), \`transition\` into it (default Cross Fade, 0.6 s; \`transitionDuration\`), \`camera\` (below; default push-in),
|
|
19541
19597
|
\`background\` (overrides style), \`sounds\`: [{ "sfx", "at" }]. Script-level \`sound\`: auto (default: a whoosh on each transition and on the first headline) | none.
|
|
19598
|
+
**A transition overlaps the scenes on both sides**, so the video lasts the scenes' durations added up MINUS every
|
|
19599
|
+
transition: five 3 s scenes with the default 0.6 s transitions run 15 \u2212 4 \xD7 0.6 = 12.6 s. To hit a length, add the
|
|
19600
|
+
transitions back to the scenes (${host === "chat" ? "build_video" : "`script`"} prints the total).
|
|
19542
19601
|
- **camera** \u2014 a quick move of the whole scene: ${CAMERAS.join(" | ")}. Or a REAL camera that films the scene's elements in 3D (the
|
|
19543
19602
|
Video Editor's own camera layer; the scene's backdrop stays put, so its edge never shows). One of:
|
|
19544
19603
|
- \`{ "move": id }\` \u2014 a camera move from the catalogue (or just \`"camera": "cm-quiet-push"\`), spread over the scene;
|
|
@@ -18515,7 +18515,7 @@ ${Jh("Box · Text · Pin",Zh("R","T","N"))}
|
|
|
18515
18515
|
${Jh("Hide · Crop · Range",Zh("X","C","G"))}
|
|
18516
18516
|
</div>
|
|
18517
18517
|
</div>`}let eSe=!1;function tSe(t,{project:e,sources:n,strips:a,parts:s,config:r,assets:o=null,chat:i=null}={}){if(!t)throw new Error("GreenLightMotion.mountStudio needs an element");if(eSe)throw new Error("GreenLightMotion.mountStudio: one studio per page");if(e&&(window.GL_LAB_PROJECT=e),!window.GL_LAB_PROJECT)throw new Error("GreenLightMotion.mountStudio needs a project");if(n&&(window.RV_SOURCES=n),a&&(window.RV_STRIPS=a),s&&(window.RV_PARTS=s),r&&(window.RV_CONFIG=r),!window.RV_CONFIG&&!window.RV_SOURCES){const c=window.GL_LAB_PROJECT.template?.title||window.GL_LAB_PROJECT.name||"Video";window.RV_CONFIG={title:c,storeKey:"glm-studio-"+String(c).toLowerCase().replace(/[^a-z0-9]+/g,"-").slice(0,40),start:"edit",startAt:0,saveLabel:"Copy for agent",saveTitle:"Your notes, highlights and changes, as text for your agent",savedText:"Ready to copy",copyNote:"<b>Your review.</b> Copy it and give it to your agent with this video."}}if(!document.querySelector(".lab-side")){const c=document.createElement("aside");c.className="lab-side",c.setAttribute("aria-label","Sources"),c.hidden=!0,c.innerHTML=BMt((window.RV_SOURCES||[]).length||1),t.after(c)}if(!document.getElementById("lab-toast")){const c=document.createElement("div");c.id="lab-toast",c.setAttribute("role","status"),document.body.append(c)}if(!document.querySelector("style[data-greenlight-studio]")){const c=document.createElement("style");c.setAttribute("data-greenlight-studio","");const d=[U9t,G9t,j9t,V9t,H9t,W9t,$9t].join(`
|
|
18518
|
-
`);c.textContent=i?Z8e(d):d,document.head.append(c)}if(i&&!document.querySelector("style[data-greenlight-chat]")){const c=document.querySelector("style[data-greenlight-motion]");c&&(c.textContent=Z8e(c.textContent));const d=document.createElement("style");d.setAttribute("data-greenlight-chat",""),d.textContent=Y9t,document.head.insertBefore(d,c||document.querySelector("style[data-greenlight-studio]"))}window.LabNoteEngine={...mMt,zipStore:jte};const l={el:t,assets:o};eSe=!0;for(const c of[gMt,xMt,yMt,vMt,bMt,_Mt,IMt])c(l);return i&&(l.chat=RMt(l,i)),l}const Kte="0.2.
|
|
18518
|
+
`);c.textContent=i?Z8e(d):d,document.head.append(c)}if(i&&!document.querySelector("style[data-greenlight-chat]")){const c=document.querySelector("style[data-greenlight-motion]");c&&(c.textContent=Z8e(c.textContent));const d=document.createElement("style");d.setAttribute("data-greenlight-chat",""),d.textContent=Y9t,document.head.insertBefore(d,c||document.querySelector("style[data-greenlight-studio]"))}window.LabNoteEngine={...mMt,zipStore:jte};const l={el:t,assets:o};eSe=!0;for(const c of[gMt,xMt,yMt,vMt,bMt,_Mt,IMt])c(l);return i&&(l.chat=RMt(l,i)),l}const Kte="0.2.1",uz=()=>{};kxt(),z3t();function FMt({project:t,playerRef:e}){const n=t.videoSize||{w:1920,h:1080};return le.jsx("div",{style:{width:n.w,height:n.h,background:"#000"},children:le.jsx($Me,{ref:e,channels:t.channels||[],clips:t.clips||[],isPlaying:!1,setIsPlaying:uz,currentTime:0,playheadTime:0,setCurrentTime:uz,setPlayheadTime:uz,soundEnabled:!1,forceMuteAudio:!1,videoWidth:n.w,videoHeight:n.h,outputSize:null,previewQuality:"full",motionBlurEnabled:t.motionBlurEnabled===!0,background:t.background||null,markers:t.markers||[],textVariables:t.textVariables||[],timecodeFps:t.fps||30})})}const LMt=async(t,e,n)=>{const a=performance.now()+e;for(;!t();){if(performance.now()>a)throw new Error(`GreenLightMotion: timed out waiting for ${n}`);await new Promise(s=>setTimeout(s,30))}};async function nSe(t,{renderer:e="webgpu",assets:n=null}={}){if(!t)throw new Error("GreenLightMotion.create needs a container element");if(e==="webgpu"&&!navigator.gpu)throw new Error("This browser has no WebGPU");EY(e),HY(e);const a=o0e.createRoot(t),s={current:null};let r=!1,o=fte(n);OL(o);let i=null;const l=d=>pI({channels:i?.channels||[],clips:i?.clips||[],getPlayer:()=>s.current,range:d}),c=()=>{if(r)throw new Error("GreenLightMotion: disposed");if(!s.current)throw new Error("GreenLightMotion: load a project first");return s.current};return{version:Kte,async load(d,{assets:h}={}){if(!d||typeof d!="object")throw new Error("GreenLightMotion.load needs a project");h&&(o.dispose(),o=fte(h),OL(o)),U3t();const u=await vI(d),f=await t6e(u,o);return i=f,a.render(le.jsx(FMt,{project:f,playerRef:s})),await LMt(()=>s.current,1e4,"the player"),{missing:gI()}},missingAssets:gI,async renderFrame(d,h={}){const u=Math.max(0,Number(d)||0);return c(),await l({start:u,end:u+.001}),c().captureFrameAtTime(u,h)},isExportSupported(){try{return!!c().isWebCodecsSupported?.()}catch{return!1}},async export({format:d="mp4",fps:h=30,onProgress:u=uz,signal:f}={}){const p=c();if(!p.isWebCodecsSupported?.())throw new Error("This browser cannot encode video (WebCodecs)");return await l(null),p.exportVideo(d,u,f,h)},dispose(){r=!0,a.unmount(),o.dispose(),OL(null)}}}function aSe(t,{project:e,assets:n=null,theme:a="dark"}={}){if(!t)throw new Error("GreenLightMotion.mountPage needs an element");if(!e)throw new Error("GreenLightMotion.mountPage needs a project");EY("webgpu"),HY("webgpu");const s=o0e.createRoot(t);return s.render(le.jsx(z9t,{project:e,assets:n,theme:a})),{unmount:()=>s.unmount()}}window.GreenLightMotion={create:nSe,mountPage:aSe,mountStudio:tSe,checkTemplate:qMe,checkSoundCues:T6e,sounds:N4,missingAssets:gI,pluginStatus:e6e,normalize:vI,trace:async(t,e)=>G8e(await vI(t),e),version:Kte};const zMt=["alphaMap","alphaTest","anisotropy","anisotropyMap","anisotropyRotation","aoMap","aoMapIntensity","attenuationColor","attenuationDistance","bumpMap","clearcoat","clearcoatMap","clearcoatNormalMap","clearcoatNormalScale","clearcoatRoughness","color","dispersion","displacementMap","emissive","emissiveIntensity","emissiveMap","envMap","envMapIntensity","gradientMap","ior","iridescence","iridescenceIOR","iridescenceMap","iridescenceThicknessMap","lightMap","lightMapIntensity","map","matcap","metalness","metalnessMap","normalMap","normalScale","opacity","roughness","roughnessMap","sheen","sheenColor","sheenColorMap","sheenRoughnessMap","shininess","specular","specularColor","specularColorMap","specularIntensity","specularIntensityMap","specularMap","thickness","transmission","transmissionMap"],Jte=new WeakMap;class sSe{constructor(e){this.renderObjects=new WeakMap,this.hasNode=this.containsNode(e),this.hasAnimation=e.object.isSkinnedMesh===!0,this.refreshUniforms=zMt,this.renderId=0}firstInitialization(e){return this.renderObjects.has(e)===!1?(this.getRenderObjectData(e),!0):!1}needsVelocity(e){const n=e.getMRT();return n!==null&&n.has("velocity")}getRenderObjectData(e){let n=this.renderObjects.get(e);if(n===void 0){const{geometry:a,material:s,object:r}=e;if(n={material:this.getMaterialData(s),geometry:{id:a.id,attributes:this.getAttributesData(a.attributes),indexId:a.index?a.index.id:null,indexVersion:a.index?a.index.version:null,drawRange:{start:a.drawRange.start,count:a.drawRange.count}},worldMatrix:r.matrixWorld.clone()},r.center&&(n.center=r.center.clone()),r.morphTargetInfluences&&(n.morphTargetInfluences=r.morphTargetInfluences.slice()),e.bundle!==null&&(n.version=e.bundle.version),n.material.transmission>0){const{width:o,height:i}=e.context;n.bufferWidth=o,n.bufferHeight=i}n.lights=this.getLightsData(e.lightsNode.getLights()),this.renderObjects.set(e,n)}return n}getAttributesData(e){const n={};for(const a in e){const s=e[a];n[a]={id:s.id,version:s.version}}return n}containsNode(e){const n=e.material;for(const a in n)if(n[a]&&n[a].isNode)return!0;return!!(e.context.modelViewMatrix||e.context.modelNormalViewMatrix||e.context.getAO||e.context.getShadow)}getMaterialData(e){const n={};for(const a of this.refreshUniforms){const s=e[a];s!=null&&(typeof s=="object"&&s.clone!==void 0?s.isTexture===!0?n[a]={id:s.id,version:s.version}:n[a]=s.clone():n[a]=s)}return n}equals(e,n){const{object:a,material:s,geometry:r}=e,o=this.getRenderObjectData(e);if(o.worldMatrix.equals(a.matrixWorld)!==!0)return o.worldMatrix.copy(a.matrixWorld),!1;const i=o.material;for(const v in i){const b=i[v],M=s[v];if(b.equals!==void 0){if(b.equals(M)===!1)return b.copy(M),!1}else if(M.isTexture===!0){if(b.id!==M.id||b.version!==M.version)return b.id=M.id,b.version=M.version,!1}else if(b!==M)return i[v]=M,!1}if(i.transmission>0){const{width:v,height:b}=e.context;if(o.bufferWidth!==v||o.bufferHeight!==b)return o.bufferWidth=v,o.bufferHeight=b,!1}const l=o.geometry,c=r.attributes,d=l.attributes,h=Object.keys(d),u=Object.keys(c);if(l.id!==r.id)return l.id=r.id,!1;if(h.length!==u.length)return o.geometry.attributes=this.getAttributesData(c),!1;for(const v of h){const b=d[v],M=c[v];if(M===void 0)return delete d[v],!1;if(b.id!==M.id||b.version!==M.version)return b.id=M.id,b.version=M.version,!1}const f=r.index,p=l.indexId,m=l.indexVersion,g=f?f.id:null,x=f?f.version:null;if(p!==g||m!==x)return l.indexId=g,l.indexVersion=x,!1;if(l.drawRange.start!==r.drawRange.start||l.drawRange.count!==r.drawRange.count)return l.drawRange.start=r.drawRange.start,l.drawRange.count=r.drawRange.count,!1;if(o.morphTargetInfluences){let v=!1;for(let b=0;b<o.morphTargetInfluences.length;b++)o.morphTargetInfluences[b]!==a.morphTargetInfluences[b]&&(o.morphTargetInfluences[b]=a.morphTargetInfluences[b],v=!0);if(v)return!1}if(o.lights){for(let v=0;v<n.length;v++)if(o.lights[v].map!==n[v].map)return!1}return o.center&&o.center.equals(a.center)===!1?(o.center.copy(a.center),!0):(e.bundle!==null&&(o.version=e.bundle.version),!0)}getLightsData(e){const n=[];for(const a of e)a.isSpotLight===!0&&a.map!==null&&n.push({map:a.map.version});return n}getLights(e,n){if(Jte.has(e)){const s=Jte.get(e);if(s.renderId===n)return s.lightsData}const a=this.getLightsData(e.getLights());return Jte.set(e,{renderId:n,lightsData:a}),a}needsRefresh(e,n){if(this.hasNode||this.hasAnimation||this.firstInitialization(e)||this.needsVelocity(n.renderer))return!0;const{renderId:a}=n;if(this.renderId!==a)return this.renderId=a,!0;const s=e.object.static===!0,r=e.bundle!==null&&e.bundle.static===!0&&this.getRenderObjectData(e).version===e.bundle.version;if(s||r)return!1;const o=this.getLights(e.lightsNode,a);return this.equals(e,o)!==!0}}const UMt=[/^StackTrace\.js$/,/^TSLCore\.js$/,/^.*Node\.js$/,/^three\.webgpu.*\.js$/];function GMt(t){const e=/(?:at\s+(.+?)\s+\()?(?:(.+?)@)?([^@\s()]+):(\d+):(\d+)/;return t.split(`
|
|
18519
18519
|
`).map(n=>{const a=n.match(e);if(!a)return null;const s=a[1]||a[2]||"",r=a[3].split("?")[0],o=parseInt(a[4],10),i=parseInt(a[5],10),l=r.split("/").pop();return{fn:s,file:l,line:o,column:i}}).filter(n=>n&&!UMt.some(a=>a.test(n.file)))}class Kl{constructor(e=null){this.isStackTrace=!0,this.stack=GMt(e||new Error().stack)}getLocation(){if(this.stack.length===0)return"[Unknown location]";const e=this.stack[0],n=e.fn;return`${n?`"${n}()" at `:""}"${e.file}:${e.line}"`}getError(e){if(this.stack.length===0)return e;const n=this.stack.map(a=>{const s=`${a.file}:${a.line}:${a.column}`;return a.fn?` at ${a.fn} (${s})`:` at ${s}`}).join(`
|
|
18520
18520
|
`);return`${e}
|
|
18521
18521
|
${n}`}}function Zte(t,e=0){let n=3735928559^e,a=1103547991^e;if(t instanceof Array)for(let s=0,r;s<t.length;s++)r=t[s],n=Math.imul(n^r,2654435761),a=Math.imul(a^r,1597334677);else for(let s=0,r;s<t.length;s++)r=t.charCodeAt(s),n=Math.imul(n^r,2654435761),a=Math.imul(a^r,1597334677);return n=Math.imul(n^n>>>16,2246822507),n^=Math.imul(a^a>>>13,3266489909),a=Math.imul(a^a>>>16,2246822507),a^=Math.imul(n^n>>>13,3266489909),4294967296*(2097151&a)+(n>>>0)}const F4=t=>Zte(t),T8=t=>Zte(t),C8=(...t)=>Zte(t),jMt=new Map([[1,"float"],[2,"vec2"],[3,"vec3"],[4,"vec4"],[9,"mat3"],[16,"mat4"]]),rSe=new WeakMap;function ene(t){return jMt.get(t)}function II(t){if(/[iu]?vec\d/.test(t))return t.startsWith("ivec")?Int32Array:t.startsWith("uvec")?Uint32Array:Float32Array;if(/mat\d/.test(t)||/float/.test(t))return Float32Array;if(/uint/.test(t))return Uint32Array;if(/int/.test(t))return Int32Array;throw new Error(`THREE.NodeUtils: Unsupported type: ${t}`)}function tne(t){if(/float|int|uint/.test(t))return 1;if(/vec2/.test(t))return 2;if(/vec3/.test(t))return 3;if(/vec4/.test(t)||/mat2/.test(t))return 4;if(/mat3/.test(t))return 9;if(/mat4/.test(t))return 16;On(`TSL: Unsupported type: ${t}`,new Kl)}function oSe(t){if(/float|int|uint/.test(t))return 1;if(/vec2/.test(t))return 2;if(/vec3/.test(t))return 3;if(/vec4/.test(t)||/mat2/.test(t))return 4;if(/mat3/.test(t))return 12;if(/mat4/.test(t))return 16;On(`TSL: Unsupported type: ${t}`,new Kl)}function iSe(t){if(/float|int|uint/.test(t))return 4;if(/vec2/.test(t))return 8;if(/vec3/.test(t)||/vec4/.test(t))return 16;if(/mat2/.test(t))return 8;if(/mat3/.test(t)||/mat4/.test(t))return 16;On(`TSL: Unsupported type: ${t}`,new Kl)}function cx(t){if(t==null)return null;const e=typeof t;return t.isNode===!0?"node":e==="number"?"float":e==="boolean"?"bool":e==="string"?"string":e==="function"?"shader":t.isVector2===!0?"vec2":t.isVector3===!0?"vec3":t.isVector4===!0?"vec4":t.isMatrix2===!0?"mat2":t.isMatrix3===!0?"mat3":t.isMatrix4===!0?"mat4":t.isColor===!0?"color":t instanceof ArrayBuffer?"ArrayBuffer":null}function dz(t,...e){const n=t?t.slice(-4):void 0;return e.length===1&&(n==="vec2"?e=[e[0],e[0]]:n==="vec3"?e=[e[0],e[0],e[0]]:n==="vec4"&&(e=[e[0],e[0],e[0],e[0]])),t==="color"?new Ht(...e):n==="vec2"?new Te(...e):n==="vec3"?new Ie(...e):n==="vec4"?new Vn(...e):n==="mat2"?new eM(...e):n==="mat3"?new Pa(...e):n==="mat4"?new Xn(...e):t==="bool"?e[0]||!1:t==="float"||t==="int"||t==="uint"?e[0]||0:t==="string"?e[0]||"":t==="ArrayBuffer"?cSe(e[0]):null}function nne(t){let e=rSe.get(t);return e===void 0&&(e={},rSe.set(t,e)),e}function lSe(t){let e="";const n=new Uint8Array(t);for(let a=0;a<n.length;a++)e+=String.fromCharCode(n[a]);return btoa(e)}function cSe(t){return Uint8Array.from(atob(t),e=>e.charCodeAt(0)).buffer}var VMt=Object.freeze({__proto__:null,arrayBufferToBase64:lSe,base64ToArrayBuffer:cSe,getAlignmentFromType:iSe,getDataFromObject:nne,getLengthFromType:tne,getMemoryLengthFromType:oSe,getTypeFromLength:ene,getTypedArrayFromType:II,getValueFromType:dz,getValueType:cx,hash:C8,hashArray:T8,hashString:F4});const _8={VERTEX:"vertex",FRAGMENT:"fragment"},Hs={NONE:"none",FRAME:"frame",RENDER:"render",OBJECT:"object"},uSe={BOOLEAN:"bool",INTEGER:"int",FLOAT:"float",VECTOR2:"vec2",VECTOR3:"vec3",VECTOR4:"vec4",MATRIX2:"mat2",MATRIX3:"mat3",MATRIX4:"mat4"},jc={READ_ONLY:"readOnly",WRITE_ONLY:"writeOnly",READ_WRITE:"readWrite"},ane=["fragment","vertex"],fz=["setup","analyze","generate"],hz=[...ane,"compute"],eb=["x","y","z","w"],HMt={analyze:"setup",generate:"analyze"};let WMt=0;class Ka extends Qd{static get type(){return"Node"}constructor(e=null){super(),this.nodeType=e,this.updateType=Hs.NONE,this.updateBeforeType=Hs.NONE,this.updateAfterType=Hs.NONE,this.uuid=eu.generateUUID(),this.version=0,this.name="",this.global=!1,this.parents=!1,this.isNode=!0,this._beforeNodes=null,this._cacheKey=null,this._cacheKeyVersion=0,Object.defineProperty(this,"id",{value:WMt++}),this.stackTrace=null,Ka.captureStackTrace===!0&&(this.stackTrace=new Kl)}set needsUpdate(e){e===!0&&this.version++}get type(){return this.constructor.type}onUpdate(e,n){return this.updateType=n,this.update=e.bind(this),this}onFrameUpdate(e){return this.onUpdate(e,Hs.FRAME)}onRenderUpdate(e){return this.onUpdate(e,Hs.RENDER)}onObjectUpdate(e){return this.onUpdate(e,Hs.OBJECT)}onReference(e){return this.updateReference=e.bind(this),this}updateReference(){return this}isGlobal(){return this.global}*getChildren(){for(const{childNode:e}of this._getChildren())yield e}dispose(){this.dispatchEvent({type:"dispose"})}traverse(e){e(this);for(const n of this.getChildren())n.traverse(e)}_getChildren(e=new Set){const n=[];e.add(this);for(const a of Object.getOwnPropertyNames(this)){const s=this[a];if(!(a.startsWith("_")===!0||e.has(s))){if(Array.isArray(s)===!0)for(let r=0;r<s.length;r++){const o=s[r];o&&o.isNode===!0&&n.push({property:a,index:r,childNode:o})}else if(s&&s.isNode===!0)n.push({property:a,childNode:s});else if(s&&Object.getPrototypeOf(s)===Object.prototype)for(const r in s){if(r.startsWith("_")===!0)continue;const o=s[r];o&&o.isNode===!0&&n.push({property:a,index:r,childNode:o})}}}return n}getCacheKey(e=!1,n=null){if(e=e||this.version!==this._cacheKeyVersion,e===!0||this._cacheKey===null){n===null&&(n=new Set);const a=[];for(const{property:s,childNode:r}of this._getChildren(n))a.push(F4(s.slice(0,-4)),r.getCacheKey(e,n));this._cacheKey=C8(T8(a),this.customCacheKey()),this._cacheKeyVersion=this.version}return this._cacheKey}customCacheKey(){return this.id}getScope(){return this}getHash(){return this.uuid}getUpdateType(){return this.updateType}getUpdateBeforeType(){return this.updateBeforeType}getUpdateAfterType(){return this.updateAfterType}getElementType(e){const n=this.getNodeType(e);return e.getElementType(n)}getMemberType(){return"void"}getNodeType(e){const n=e.getNodeProperties(this);return n.outputNode?n.outputNode.getNodeType(e):this.nodeType}getShared(e){const n=this.getHash(e);return e.getNodeFromHash(n)||this}getArrayCount(){return null}setup(e){const n=e.getNodeProperties(this);let a=0;for(const s of this.getChildren())n["node"+a++]=s;return n.outputNode||null}analyze(e,n=null){const a=e.increaseUsage(this);if(this.parents===!0){const s=e.getDataFromNode(this,"any");s.stages=s.stages||{},s.stages[e.shaderStage]=s.stages[e.shaderStage]||[],s.stages[e.shaderStage].push(n)}if(a===1){const s=e.getNodeProperties(this);for(const r of Object.values(s))r&&r.isNode===!0&&r.build(e,this)}}generate(e,n){const{outputNode:a}=e.getNodeProperties(this);if(a&&a.isNode===!0)return a.build(e,n)}updateBefore(){Nn("Abstract function.")}updateAfter(){Nn("Abstract function.")}update(){Nn("Abstract function.")}before(e){return this._beforeNodes===null&&(this._beforeNodes=[]),this._beforeNodes.push(e),this}build(e,n=null){const a=this.getShared(e);if(this!==a)return a.build(e,n);if(this._beforeNodes!==null){const l=this._beforeNodes;this._beforeNodes=null;for(const c of l)c.build(e,n);this._beforeNodes=l}const s=e.getDataFromNode(this);s.buildStages=s.buildStages||{},s.buildStages[e.buildStage]=!0;const r=HMt[e.buildStage];if(r&&s.buildStages[r]!==!0){const l=e.getBuildStage();e.setBuildStage(r),this.build(e),e.setBuildStage(l)}e.addChain(this);let o=null;const i=e.getBuildStage();if(i==="setup"){e.addNode(this),this.updateReference(e);const l=e.getNodeProperties(this);if(l.initialized!==!0){l.initialized=!0,l.outputNode=this.setup(e)||l.outputNode||null;for(const c of Object.values(l))if(c&&c.isNode===!0){if(c.parents===!0){const d=e.getNodeProperties(c);d.parents=d.parents||[],d.parents.push(this)}c.build(e)}e.addSequentialNode(this)}o=l.outputNode}else if(i==="analyze")this.analyze(e,n);else if(i==="generate"){if(this.generate.length<2){const c=this.getNodeType(e),d=e.getDataFromNode(this);o=d.snippet,o===void 0?d.generated===void 0?(d.generated=!0,o=this.generate(e)||"",d.snippet=o):(Nn("Node: Recursion detected.",this),o="/* Recursion detected. */"):d.flowCodes!==void 0&&e.context.nodeBlock!==void 0&&e.addFlowCodeHierarchy(this,e.context.nodeBlock),o=e.format(o,c,n)}else o=this.generate(e,n)||"";o===""&&n!==null&&n!=="void"&&n!=="OutputType"&&(On(`TSL: Invalid generated code, expected a "${n}".`),o=e.generateConst(n))}return e.removeChain(this),o}getSerializeChildren(){return this._getChildren()}serialize(e){const n=this.getSerializeChildren(),a={};for(const{property:s,index:r,childNode:o}of n)r!==void 0?(a[s]===void 0&&(a[s]=Number.isInteger(r)?[]:{}),a[s][r]=o.toJSON(e.meta).uuid):a[s]=o.toJSON(e.meta).uuid;Object.keys(a).length>0&&(e.inputNodes=a)}deserialize(e){if(e.inputNodes!==void 0){const n=e.meta.nodes;for(const a in e.inputNodes)if(Array.isArray(e.inputNodes[a])){const s=[];for(const r of e.inputNodes[a])s.push(n[r]);this[a]=s}else if(typeof e.inputNodes[a]=="object"){const s={};for(const r in e.inputNodes[a]){const o=e.inputNodes[a][r];s[r]=n[o]}this[a]=s}else{const s=e.inputNodes[a];this[a]=n[s]}}}toJSON(e){const{uuid:n,type:a}=this,s=e===void 0||typeof e=="string";s&&(e={textures:{},images:{},nodes:{}});let r=e.nodes[n];r===void 0&&(r={uuid:n,type:a,meta:e,metadata:{version:4.7,type:"Node",generator:"Node.toJSON"}},s!==!0&&(e.nodes[r.uuid]=r),this.serialize(r),delete r.meta);function o(i){const l=[];for(const c in i){const d=i[c];delete d.metadata,l.push(d)}return l}if(s){const i=o(e.textures),l=o(e.images),c=o(e.nodes);i.length>0&&(r.textures=i),l.length>0&&(r.images=l),c.length>0&&(r.nodes=c)}return r}}Ka.captureStackTrace=!1;class tb extends Ka{static get type(){return"ArrayElementNode"}constructor(e,n){super(),this.node=e,this.indexNode=n,this.isArrayElementNode=!0}getNodeType(e){return this.node.getElementType(e)}getMemberType(e,n){return this.node.getMemberType(e,n)}generate(e){const n=this.indexNode.getNodeType(e),a=this.node.build(e),s=this.indexNode.build(e,!e.isVector(n)&&e.isInteger(n)?n:"uint");return`${a}[ ${s} ]`}}class sne extends Ka{static get type(){return"ConvertNode"}constructor(e,n){super(),this.node=e,this.convertTo=n}getNodeType(e){const n=this.node.getNodeType(e);let a=null;for(const s of this.convertTo.split("|"))(a===null||e.getTypeLength(n)===e.getTypeLength(s))&&(a=s);return a}serialize(e){super.serialize(e),e.convertTo=this.convertTo}deserialize(e){super.deserialize(e),this.convertTo=e.convertTo}generate(e,n){const a=this.node,s=this.getNodeType(e),r=a.build(e,s);return e.format(r,s,n)}}class Pl extends Ka{static get type(){return"TempNode"}constructor(e=null){super(e),this.isTempNode=!0}hasDependencies(e){return e.getDataFromNode(this).usageCount>1}build(e,n){if(e.getBuildStage()==="generate"){const s=e.getVectorType(this.getNodeType(e,n)),r=e.getDataFromNode(this);if(r.propertyName!==void 0)return e.format(r.propertyName,s,n);if(s!=="void"&&n!=="void"&&this.hasDependencies(e)){const o=super.build(e,s),i=e.getVarFromNode(this,null,s),l=e.getPropertyName(i);return e.addLineFlowCode(`${l} = ${o}`,this),r.snippet=o,r.propertyName=l,e.format(r.propertyName,s,n)}}return super.build(e,n)}}class dSe extends Pl{static get type(){return"JoinNode"}constructor(e=[],n=null){super(n),this.nodes=e}getNodeType(e){return this.nodeType!==null?e.getVectorType(this.nodeType):e.getTypeFromLength(this.nodes.reduce((n,a)=>n+e.getTypeLength(a.getNodeType(e)),0))}generate(e,n){const a=this.getNodeType(e),s=e.getTypeLength(a),r=this.nodes,o=e.getComponentType(a),i=[];let l=0;for(const d of r){if(l>=s){On(`TSL: Length of parameters exceeds maximum length of function '${a}()' type.`,this.stackTrace);break}let h=d.getNodeType(e),u=e.getTypeLength(h),f;if(l+u>s&&(On(`TSL: Length of '${a}()' data exceeds maximum length of output type.`,this.stackTrace),u=s-l,h=e.getTypeFromLength(u)),l+=u,f=d.build(e,h),e.getComponentType(h)!==o){const m=e.getTypeFromLength(u,o);f=e.format(f,h,m)}i.push(f)}const c=`${e.getType(a)}( ${i.join(", ")} )`;return e.format(c,a,n)}}const $Mt=eb.join("");class rne extends Ka{static get type(){return"SplitNode"}constructor(e,n="x"){super(),this.node=e,this.components=n,this.isSplitNode=!0}getVectorLength(){let e=this.components.length;for(const n of this.components)e=Math.max(eb.indexOf(n)+1,e);return e}getComponentType(e){return e.getComponentType(this.node.getNodeType(e))}getNodeType(e){return e.getTypeFromLength(this.components.length,this.getComponentType(e))}getScope(){return this.node.getScope()}generate(e,n){const a=this.node,s=e.getTypeLength(a.getNodeType(e));let r=null;if(s>1){let o=null;this.getVectorLength()>=s&&(o=e.getTypeFromLength(this.getVectorLength(),this.getComponentType(e)));const l=a.build(e,o);this.components.length===s&&this.components===$Mt.slice(0,this.components.length)?r=e.format(l,o,n):r=e.format(`${l}.${this.components}`,this.getNodeType(e),n)}else r=a.build(e,n);return r}serialize(e){super.serialize(e),e.components=this.components}deserialize(e){super.deserialize(e),this.components=e.components}}class fSe extends Pl{static get type(){return"SetNode"}constructor(e,n,a){super(),this.sourceNode=e,this.components=n,this.targetNode=a}getNodeType(e){return this.sourceNode.getNodeType(e)}generate(e){const{sourceNode:n,components:a,targetNode:s}=this,r=this.getNodeType(e),o=e.getComponentType(s.getNodeType(e)),i=e.getTypeFromLength(a.length,o),l=s.build(e,i),c=n.build(e,r),d=e.getTypeLength(r),h=[];for(let u=0;u<d;u++){const f=eb[u];f===a[0]?(h.push(l),u+=a.length-1):h.push(c+"."+f)}return`${e.getType(r)}( ${h.join(", ")} )`}}class hSe extends Pl{static get type(){return"FlipNode"}constructor(e,n){super(),this.sourceNode=e,this.components=n}getNodeType(e){return this.sourceNode.getNodeType(e)}generate(e){const{components:n,sourceNode:a}=this,s=this.getNodeType(e),r=a.build(e),o=e.getVarFromNode(this),i=e.getPropertyName(o);e.addLineFlowCode(i+" = "+r,this);const l=e.getTypeLength(s),c=[];let d=0;for(let h=0;h<l;h++){const u=eb[h];u===n[d]?(c.push("1.0 - "+(i+"."+u)),d++):c.push(i+"."+u)}return`${e.getType(s)}( ${c.join(", ")} )`}}class pz extends Ka{static get type(){return"InputNode"}constructor(e,n=null){super(n),this.isInputNode=!0,this.value=e,this.precision=null}getNodeType(){return this.nodeType===null?cx(this.value):this.nodeType}getInputType(e){return this.getNodeType(e)}setPrecision(e){return this.precision=e,this}serialize(e){super.serialize(e),e.value=this.value,this.value&&this.value.toArray&&(e.value=this.value.toArray()),e.valueType=cx(this.value),e.nodeType=this.nodeType,e.valueType==="ArrayBuffer"&&(e.value=lSe(e.value)),e.precision=this.precision}deserialize(e){super.deserialize(e),this.nodeType=e.nodeType,this.value=Array.isArray(e.value)?dz(e.valueType,...e.value):e.value,this.precision=e.precision||null,this.value&&this.value.fromArray&&(this.value=this.value.fromArray(e.value))}generate(){Nn("Abstract function.")}}const pSe=/float|u?int/;class fh extends pz{static get type(){return"ConstNode"}constructor(e,n=null){super(e,n),this.isConstNode=!0}generateConst(e){return e.generateConst(this.getNodeType(e),this.value)}generate(e,n){const a=this.getNodeType(e);return pSe.test(a)&&pSe.test(n)?e.generateConst(n,this.value):e.format(this.generateConst(e),a,n)}}class mSe extends Ka{static get type(){return"MemberNode"}constructor(e,n){super(),this.structNode=e,this.property=n,this.isMemberNode=!0}hasMember(e){return this.structNode.isMemberNode&&this.structNode.hasMember(e)===!1?!1:this.structNode.getMemberType(e,this.property)!=="void"}getNodeType(e){return this.hasMember(e)===!1?"float":this.structNode.getMemberType(e,this.property)}getMemberType(e,n){if(this.hasMember(e)===!1)return"float";const a=this.getNodeType(e);return e.getStructTypeNode(a).getMemberType(e,n)}generate(e){if(this.hasMember(e)===!1){Nn(`TSL: Member "${this.property}" does not exist in struct.`,this.stackTrace);const a=this.getNodeType(e);return e.generateConst(a)}return this.structNode.build(e)+"."+this.property}}let nb=null;const one=new Map;function Hn(t,e){if(one.has(t)){Nn(`TSL: Redefinition of method chaining '${t}'.`);return}if(typeof e!="function")throw new Error(`THREE.TSL: Node element ${t} is not a function`);one.set(t,e),t!=="assign"&&(Ka.prototype[t]=function(...n){return this.isStackNode?this.addToStack(e(...n)):e(this,...n)},Ka.prototype[t+"Assign"]=function(...n){return this.isStackNode?this.assign(n[0],e(...n)):this.assign(e(this,...n))})}const YMt=t=>t.replace(/r|s/g,"x").replace(/g|t/g,"y").replace(/b|p/g,"z").replace(/a|q/g,"w"),gSe=t=>YMt(t).split("").sort().join("");Ka.prototype.assign=function(...t){if(this.isStackNode!==!0)return nb!==null?nb.assign(this,...t):On("TSL: No stack defined for assign operation. Make sure the assign is inside a Fn().",new Kl),this;{const e=one.get("assign");return this.addToStack(e(...t))}},Ka.prototype.toVarIntent=function(){return this},Ka.prototype.get=function(t){return new mSe(this,t)};const EI={};function mz(t,e,n){EI[t]=EI[e]=EI[n]={get(){this._cache=this._cache||{};let o=this._cache[t];return o===void 0&&(o=new rne(this,t),this._cache[t]=o),o},set(o){this[t].assign(Ja(o))}};const a=t.toUpperCase(),s=e.toUpperCase(),r=n.toUpperCase();Ka.prototype["set"+a]=Ka.prototype["set"+s]=Ka.prototype["set"+r]=function(o){const i=gSe(t);return new fSe(this,i,Ja(o))},Ka.prototype["flip"+a]=Ka.prototype["flip"+s]=Ka.prototype["flip"+r]=function(){const o=gSe(t);return new hSe(this,o)}}const K1=["x","y","z","w"],J1=["r","g","b","a"],Z1=["s","t","p","q"];for(let t=0;t<4;t++){let e=K1[t],n=J1[t],a=Z1[t];mz(e,n,a);for(let s=0;s<4;s++){e=K1[t]+K1[s],n=J1[t]+J1[s],a=Z1[t]+Z1[s],mz(e,n,a);for(let r=0;r<4;r++){e=K1[t]+K1[s]+K1[r],n=J1[t]+J1[s]+J1[r],a=Z1[t]+Z1[s]+Z1[r],mz(e,n,a);for(let o=0;o<4;o++)e=K1[t]+K1[s]+K1[r]+K1[o],n=J1[t]+J1[s]+J1[r]+J1[o],a=Z1[t]+Z1[s]+Z1[r]+Z1[o],mz(e,n,a)}}}for(let t=0;t<32;t++)EI[t]={get(){this._cache=this._cache||{};let e=this._cache[t];return e===void 0&&(e=new tb(this,new fh(t,"uint")),this._cache[t]=e),e},set(e){this[t].assign(Ja(e))}};Object.defineProperties(Ka.prototype,EI);const xSe=new WeakMap,qMt=function(t,e=null){const n=cx(t);return n==="node"?t:e===null&&(n==="float"||n==="boolean")||n&&n!=="shader"&&n!=="string"?Ja(une(t,e)):n==="shader"?t.isFn?t:Kt(t):t},XMt=function(t,e=null){for(const n in t)t[n]=Ja(t[n],e);return t},QMt=function(t,e=null){const n=t.length;for(let a=0;a<n;a++)t[a]=Ja(t[a],e);return t},ySe=function(t,e=null,n=null,a=null){function s(d){return a!==null?(d=Ja(Object.assign(d,a)),a.intent===!0&&(d=d.toVarIntent())):d=Ja(d),d}let r,o=e,i,l;function c(d){let h;return o?h=/[a-z]/i.test(o)?o+"()":o:h=t.type,i!==void 0&&d.length<i?(On(`TSL: "${h}" parameter length is less than minimum required.`,new Kl),d.concat(new Array(i-d.length).fill(0))):l!==void 0&&d.length>l?(On(`TSL: "${h}" parameter length exceeds limit.`,new Kl),d.slice(0,l)):d}return e===null?r=(...d)=>s(new t(...L4(c(d)))):n!==null?(n=Ja(n),r=(...d)=>s(new t(e,...L4(c(d)),n))):r=(...d)=>s(new t(e,...L4(c(d)))),r.setParameterLength=(...d)=>(d.length===1?i=l=d[0]:d.length===2&&([i,l]=d),r),r.setName=d=>(o=d,r),r},KMt=function(t,...e){return new t(...L4(e))};class JMt extends Ka{constructor(e,n){super(),this.shaderNode=e,this.rawInputs=n,this.isShaderCallNodeInternal=!0}getNodeType(e){return this.shaderNode.nodeType||this.getOutputNode(e).getNodeType(e)}getElementType(e){return this.getOutputNode(e).getElementType(e)}getMemberType(e,n){return this.getOutputNode(e).getMemberType(e,n)}call(e){const{shaderNode:n,rawInputs:a}=this,s=e.getNodeProperties(n),r=e.getClosestSubBuild(n.subBuilds)||"",o=r||"default";if(s[o])return s[o];const i=e.subBuildFn,l=e.fnCall;e.subBuildFn=r,e.fnCall=this;let c=null;if(n.layout){let d=xSe.get(e.constructor);d===void 0&&(d=new WeakMap,xSe.set(e.constructor,d));let h=d.get(n);h===void 0&&(h=Ja(e.buildFunctionNode(n)),d.set(n,h)),e.addInclude(h);const u=a?ZMt(a):null;c=Ja(h.call(u))}else{const d=new Proxy(e,{get:(m,g,x)=>{let v;return Symbol.iterator===g?v=function*(){yield void 0}:v=Reflect.get(m,g,x),v}}),h=a?e6t(a):null,u=Array.isArray(a)?a.length>0:a!==null,f=n.jsFunc,p=u||f.length>1?f(h,d):f(d);c=Ja(p)}return e.subBuildFn=i,e.fnCall=l,n.once&&(s[o]=c),c}setupOutput(e){return e.addStack(),e.stack.outputNode=this.call(e),e.removeStack()}getOutputNode(e){const n=e.getNodeProperties(this),a=e.getSubBuildOutput(this);return n[a]=n[a]||this.setupOutput(e),n[a].subBuild=e.getClosestSubBuild(this),n[a]}build(e,n=null){let a=null;const s=e.getBuildStage(),r=e.getNodeProperties(this),o=e.getSubBuildOutput(this),i=this.getOutputNode(e),l=e.fnCall;if(e.fnCall=this,s==="setup"){const c=e.getSubBuildProperty("initialized",this);if(r[c]!==!0&&(r[c]=!0,r[o]=this.getOutputNode(e),r[o].build(e),this.shaderNode.subBuilds))for(const d of e.chaining){const h=e.getDataFromNode(d,"any");h.subBuilds=h.subBuilds||new Set;for(const u of this.shaderNode.subBuilds)h.subBuilds.add(u)}a=r[o]}else s==="analyze"?i.build(e,n):s==="generate"&&(a=i.build(e,n)||"");return e.fnCall=l,a}}function ZMt(t){let e;return yz(t),t[0]&&(t[0].isNode||Object.getPrototypeOf(t[0])!==Object.prototype)?e=[...t]:e=t[0],e}function e6t(t){let e=0;return yz(t),new Proxy(t,{get:(n,a,s)=>{let r;if(a==="length")return r=t.length,r;if(Symbol.iterator===a)r=function*(){for(const o of t)yield Ja(o)};else{if(t.length>0)if(Object.getPrototypeOf(t[0])===Object.prototype){const o=t[0];o[a]===void 0?r=o[e++]:r=Reflect.get(o,a,s)}else t[0]instanceof Ka&&(t[a]===void 0?r=t[e++]:r=Reflect.get(t,a,s));else r=Reflect.get(n,a,s);r=Ja(r)}return r}})}class t6t extends Ka{constructor(e,n){super(n),this.jsFunc=e,this.layout=null,this.global=!0,this.once=!1}setLayout(e){return this.layout=e,this}getLayout(){return this.layout}call(e=null){return new JMt(this,e)}setup(){return this.call()}}const n6t=[!1,!0],a6t=[0,1,2,3],s6t=[-1,-2],vSe=[.5,1.5,1/3,1e-6,1e6,Math.PI,Math.PI*2,1/Math.PI,2/Math.PI,1/(Math.PI*2),Math.PI/2],ine=new Map;for(const t of n6t)ine.set(t,new fh(t));const lne=new Map;for(const t of a6t)lne.set(t,new fh(t,"uint"));const cne=new Map([...lne].map(t=>new fh(t.value,"int")));for(const t of s6t)cne.set(t,new fh(t,"int"));const gz=new Map([...cne].map(t=>new fh(t.value)));for(const t of vSe)gz.set(t,new fh(t));for(const t of vSe)gz.set(-t,new fh(-t));const xz={bool:ine,uint:lne,ints:cne,float:gz},bSe=new Map([...ine,...gz]),une=(t,e)=>bSe.has(t)?bSe.get(t):t.isNode===!0?t:new fh(t,e),X0=function(t,e=null){return(...n)=>{for(const s of n)if(s===void 0)return On(`TSL: Invalid parameter for the type "${t}".`,new Kl),new fh(0,t);if((n.length===0||!["bool","float","int","uint"].includes(t)&&n.every(s=>{const r=typeof s;return r!=="object"&&r!=="function"}))&&(n=[dz(t,...n)]),n.length===1&&e!==null&&e.has(n[0]))return DI(e.get(n[0]));if(n.length===1){const s=une(n[0],t);return s.nodeType===t?DI(s):DI(new sne(s,t))}const a=n.map(s=>une(s));return DI(new dSe(a,t))}},kI=t=>typeof t=="object"&&t!==null?t.value:t,wSe=t=>t!=null?t.nodeType||t.convertTo||(typeof t=="string"?t:null):null;function I8(t,e){return new t6t(t,e)}const Ja=(t,e=null)=>qMt(t,e),DI=(t,e=null)=>Ja(t,e).toVarIntent(),yz=(t,e=null)=>new XMt(t,e),L4=(t,e=null)=>new QMt(t,e),hr=(t,e=null,n=null,a=null)=>new ySe(t,e,n,a),_a=(t,...e)=>new KMt(t,...e),ba=(t,e=null,n=null,a={})=>new ySe(t,e,n,{...a,intent:!0});let r6t=0;class o6t extends Ka{constructor(e,n=null){super();let a=null;n!==null&&(typeof n=="object"?a=n.return:(typeof n=="string"?a=n:On("TSL: Invalid layout type.",new Kl),n=null)),this.shaderNode=new I8(e,a),n!==null&&this.setLayout(n),this.isFn=!0}setLayout(e){const n=this.shaderNode.nodeType;if(typeof e.inputs!="object"){const a={name:"fn"+r6t++,type:n,inputs:[]};for(const s in e)s!=="return"&&a.inputs.push({name:s,type:e[s]});e=a}return this.shaderNode.setLayout(e),this}getNodeType(e){return this.shaderNode.getNodeType(e)||"float"}call(...e){const n=this.shaderNode.call(e);return this.shaderNode.nodeType==="void"&&n.toStack(),n.toVarIntent()}once(e=null){return this.shaderNode.once=!0,this.shaderNode.subBuilds=e,this}generate(e){const n=this.getNodeType(e);return On('TSL: "Fn()" was declared but not invoked. Try calling it like "Fn()( ...params )".',this.stackTrace),e.generateConst(n)}}function Kt(t,e=null){const n=new o6t(t,e);return new Proxy(()=>{},{apply(a,s,r){return n.call(...r)},get(a,s,r){return Reflect.get(n,s,r)},set(a,s,r,o){return Reflect.set(n,s,r,o)}})}const NI=t=>{nb=t},dne=()=>nb,ns=(...t)=>nb.If(...t),i6t=(...t)=>nb.Switch(...t);function vz(t){return nb&&nb.addToStack(t),t}Hn("toStack",vz);const MSe=new X0("color"),bt=new X0("float",xz.float),Gt=new X0("int",xz.ints),ia=new X0("uint",xz.uint),ep=new X0("bool",xz.bool),ha=new X0("vec2"),Q0=new X0("ivec2"),fne=new X0("uvec2"),SSe=new X0("bvec2"),$t=new X0("vec3"),hne=new X0("ivec3"),z4=new X0("uvec3"),pne=new X0("bvec3"),ja=new X0("vec4"),mne=new X0("ivec4"),gne=new X0("uvec4"),ASe=new X0("bvec4"),bz=new X0("mat2"),Vc=new X0("mat3"),ab=new X0("mat4"),l6t=(t="")=>new fh(t,"string"),c6t=t=>new fh(t,"ArrayBuffer");Hn("toColor",MSe),Hn("toFloat",bt),Hn("toInt",Gt),Hn("toUint",ia),Hn("toBool",ep),Hn("toVec2",ha),Hn("toIVec2",Q0),Hn("toUVec2",fne),Hn("toBVec2",SSe),Hn("toVec3",$t),Hn("toIVec3",hne),Hn("toUVec3",z4),Hn("toBVec3",pne),Hn("toVec4",ja),Hn("toIVec4",mne),Hn("toUVec4",gne),Hn("toBVec4",ASe),Hn("toMat2",bz),Hn("toMat3",Vc),Hn("toMat4",ab);const TSe=hr(tb).setParameterLength(2),CSe=(t,e)=>new sne(Ja(t),e),u6t=(t,e)=>new rne(Ja(t),e);Hn("element",TSe),Hn("convert",CSe);const d6t=t=>(Nn("TSL: append() has been renamed to Stack().",new Kl),vz(t));Hn("append",t=>(Nn("TSL: .append() has been renamed to .toStack().",new Kl),vz(t)));class Ho extends Ka{static get type(){return"PropertyNode"}constructor(e,n=null,a=!1){super(e),this.name=n,this.varying=a,this.isPropertyNode=!0,this.global=!0}customCacheKey(){return F4(this.type+":"+(this.name||"")+":"+(this.varying?"1":"0"))}getHash(e){return this.name||super.getHash(e)}generate(e){let n;return this.varying===!0?(n=e.getVaryingFromNode(this,this.name),n.needsInterpolation=!0):n=e.getVarFromNode(this,this.name),e.getPropertyName(n)}}const bm=(t,e)=>new Ho(t,e),hh=(t,e)=>new Ho(t,e,!0),di=_a(Ho,"vec4","DiffuseColor"),U4=_a(Ho,"vec3","DiffuseContribution"),xne=_a(Ho,"vec3","EmissiveColor"),eg=_a(Ho,"float","Roughness"),ux=_a(Ho,"float","Metalness"),wz=_a(Ho,"float","Clearcoat"),E8=_a(Ho,"float","ClearcoatRoughness"),ph=_a(Ho,"vec3","Sheen"),sb=_a(Ho,"float","SheenRoughness"),Mz=_a(Ho,"float","Iridescence"),Sz=_a(Ho,"float","IridescenceIOR"),Az=_a(Ho,"float","IridescenceThickness"),Tz=_a(Ho,"float","AlphaT"),rb=_a(Ho,"float","Anisotropy"),RI=_a(Ho,"vec3","AnisotropyT"),G4=_a(Ho,"vec3","AnisotropyB"),ob=_a(Ho,"color","SpecularColor"),j4=_a(Ho,"color","SpecularColorBlended"),V4=_a(Ho,"float","SpecularF90"),Cz=_a(Ho,"float","Shininess"),k8=_a(Ho,"vec4","Output"),H4=_a(Ho,"float","dashSize"),PI=_a(Ho,"float","gapSize"),f6t=_a(Ho,"float","pointWidth"),OI=_a(Ho,"float","IOR"),_z=_a(Ho,"float","Transmission"),yne=_a(Ho,"float","Thickness"),vne=_a(Ho,"float","AttenuationDistance"),bne=_a(Ho,"color","AttenuationColor"),wne=_a(Ho,"float","Dispersion");class Mne extends Ka{static get type(){return"UniformGroupNode"}constructor(e,n=!1,a=1){super("string"),this.name=e,this.shared=n,this.order=a,this.isUniformGroup=!0}serialize(e){super.serialize(e),e.name=this.name,e.version=this.version,e.shared=this.shared}deserialize(e){super.deserialize(e),this.name=e.name,this.version=e.version,this.shared=e.shared}}const _Se=t=>new Mne(t),Iz=(t,e=0)=>new Mne(t,!0,e),ISe=Iz("frame"),xs=Iz("render"),Sne=_Se("object");class D8 extends pz{static get type(){return"UniformNode"}constructor(e,n=null){super(e,n),this.isUniformNode=!0,this.name="",this.groupNode=Sne}setName(e){return this.name=e,this}label(e){return Nn('TSL: "label()" has been deprecated. Use "setName()" instead.',new Kl),this.setName(e)}setGroup(e){return this.groupNode=e,this}getGroup(){return this.groupNode}getUniformHash(e){return this.getHash(e)}onUpdate(e,n){return e=e.bind(this),super.onUpdate(a=>{const s=e(a,this);s!==void 0&&(this.value=s)},n)}getInputType(e){let n=super.getInputType(e);return n==="bool"&&(n="uint"),n}generate(e,n){const a=this.getNodeType(e),s=this.getUniformHash(e);let r=e.getNodeFromHash(s);r===void 0&&(e.setHashNode(this,s),r=this);const o=r.getInputType(e),i=e.getUniformFromNode(r,o,e.shaderStage,this.name||e.context.nodeName),l=e.getPropertyName(i);e.context.nodeName!==void 0&&delete e.context.nodeName;let c=l;if(a==="bool"){const d=e.getDataFromNode(this);let h=d.propertyName;if(h===void 0){const u=e.getVarFromNode(this,null,"bool");h=e.getPropertyName(u),d.propertyName=h,c=e.format(l,o,a),e.addLineFlowCode(`${h} = ${c}`,this)}c=h}return e.format(c,a,n)}}const us=(t,e)=>{const n=wSe(e||t);if(n===t&&(t=dz(n)),t&&t.isNode===!0){let a=t.value;t.traverse(s=>{s.isConstNode===!0&&(a=s.value)}),t=a}return new D8(t,n)};class Ane extends Pl{static get type(){return"ArrayNode"}constructor(e,n,a=null){super(e),this.count=n,this.values=a,this.isArrayNode=!0}getArrayCount(){return this.count}getNodeType(e){return this.nodeType===null?this.values[0].getNodeType(e):this.nodeType}getElementType(e){return this.getNodeType(e)}getMemberType(e,n){return this.nodeType===null?this.values[0].getMemberType(e,n):super.getMemberType(e,n)}generate(e){const n=this.getNodeType(e);return e.generateArray(n,this.count,this.values)}}const ESe=(...t)=>{let e;if(t.length===1){const n=t[0];e=new Ane(null,n.length,n)}else{const n=t[0],a=t[1];e=new Ane(n,a)}return Ja(e)};Hn("toArray",(t,e)=>ESe(Array(e).fill(t)));class kSe extends Pl{static get type(){return"AssignNode"}constructor(e,n){super(),this.targetNode=e,this.sourceNode=n,this.isAssignNode=!0}hasDependencies(){return!1}getNodeType(e,n){return n!=="void"?this.targetNode.getNodeType(e):"void"}needsSplitAssign(e){const{targetNode:n}=this;if(e.isAvailable("swizzleAssign")===!1&&n.isSplitNode&&n.components.length>1){const a=e.getTypeLength(n.node.getNodeType(e));return eb.join("").slice(0,a)!==n.components}return!1}setup(e){const{targetNode:n,sourceNode:a}=this,s=n.getScope(),r=e.getDataFromNode(s);r.assign=!0;const o=e.getNodeProperties(this);o.sourceNode=a,o.targetNode=n.context({assign:!0})}generate(e,n){const{targetNode:a,sourceNode:s}=e.getNodeProperties(this),r=this.needsSplitAssign(e),o=a.build(e),i=a.getNodeType(e),l=s.build(e,i),c=s.getNodeType(e),d=e.getDataFromNode(this);let h;if(d.initialized===!0)n!=="void"&&(h=o);else if(r){const u=e.getVarFromNode(this,null,i),f=e.getPropertyName(u);e.addLineFlowCode(`${f} = ${l}`,this);const p=a.node,g=p.node.context({assign:!0}).build(e);for(let x=0;x<p.components.length;x++){const v=p.components[x];e.addLineFlowCode(`${g}.${v} = ${f}[ ${x} ]`,this)}n!=="void"&&(h=o)}else h=`${o} = ${l}`,(n==="void"||c==="void")&&(e.addLineFlowCode(h,this),n!=="void"&&(h=o));return d.initialized=!0,e.format(h,i,n)}}const DSe=hr(kSe).setParameterLength(2);Hn("assign",DSe);class NSe extends Pl{static get type(){return"FunctionCallNode"}constructor(e=null,n={}){super(),this.functionNode=e,this.parameters=n}setParameters(e){return this.parameters=e,this}getParameters(){return this.parameters}getNodeType(e){return this.functionNode.getNodeType(e)}getMemberType(e,n){return this.functionNode.getMemberType(e,n)}generate(e){const n=[],a=this.functionNode,s=a.getInputs(e),r=this.parameters,o=(l,c)=>{const d=c.type,h=d==="pointer";let u;return h?u="&"+l.build(e):u=l.build(e,d),u};if(Array.isArray(r)){if(r.length>s.length)On("TSL: The number of provided parameters exceeds the expected number of inputs in 'Fn()'."),r.length=s.length;else if(r.length<s.length)for(On("TSL: The number of provided parameters is less than the expected number of inputs in 'Fn()'.");r.length<s.length;)r.push(bt(0));for(let l=0;l<r.length;l++)n.push(o(r[l],s[l]))}else for(const l of s){const c=r[l.name];c!==void 0?n.push(o(c,l)):(On(`TSL: Input '${l.name}' not found in 'Fn()'.`),n.push(o(bt(0),l)))}return`${a.build(e,"property")}( ${n.join(", ")} )`}}const RSe=(t,...e)=>(e=e.length>1||e[0]&&e[0].isNode===!0?L4(e):yz(e[0]),new NSe(Ja(t),e));Hn("call",RSe);const h6t={"==":"equal","!=":"notEqual","<":"lessThan",">":"greaterThan","<=":"lessThanEqual",">=":"greaterThanEqual","%":"mod"};class ml extends Pl{static get type(){return"OperatorNode"}constructor(e,n,a,...s){if(super(),s.length>0){let r=new ml(e,n,a);for(let o=0;o<s.length-1;o++)r=new ml(e,r,s[o]);n=r,a=s[s.length-1]}this.op=e,this.aNode=n,this.bNode=a,this.isOperatorNode=!0}getOperatorMethod(e,n){return e.getMethod(h6t[this.op],n)}getNodeType(e,n=null){const a=this.op,s=this.aNode,r=this.bNode,o=s.getNodeType(e),i=r?r.getNodeType(e):null;if(o==="void"||i==="void")return n||"void";if(a==="%")return o;if(a==="~"||a==="&"||a==="|"||a==="^"||a===">>"||a==="<<")return e.getIntegerType(o);if(a==="!"||a==="&&"||a==="||"||a==="^^")return"bool";if(a==="=="||a==="!="||a==="<"||a===">"||a==="<="||a===">="){const l=Math.max(e.getTypeLength(o),e.getTypeLength(i));return l>1?`bvec${l}`:"bool"}else{if(e.isMatrix(o)){if(i==="float")return o;if(e.isVector(i))return e.getVectorFromMatrix(o);if(e.isMatrix(i))return o}else if(e.isMatrix(i)){if(o==="float")return i;if(e.isVector(o))return e.getVectorFromMatrix(i)}return e.getTypeLength(i)>e.getTypeLength(o)?i:o}}generate(e,n){const a=this.op,{aNode:s,bNode:r}=this,o=this.getNodeType(e,n);let i=null,l=null;o!=="void"?(i=s.getNodeType(e),l=r?r.getNodeType(e):null,a==="<"||a===">"||a==="<="||a===">="||a==="=="||a==="!="?e.isVector(i)?l=i:e.isVector(l)?i=l:i!==l&&(i=l="float"):a===">>"||a==="<<"?(i=o,l=e.changeComponentType(l,"uint")):a==="%"?(i=o,l=e.isInteger(i)&&e.isInteger(l)?l:i):e.isMatrix(i)?l==="float"?l="float":e.isVector(l)?l=e.getVectorFromMatrix(i):e.isMatrix(l)||(i=l=o):e.isMatrix(l)?i==="float"?i="float":e.isVector(i)?i=e.getVectorFromMatrix(l):i=l=o:i=l=o):i=l=o;const c=s.build(e,i),d=r?r.build(e,l):null,h=e.getFunctionOperator(a);if(n!=="void"){const u=e.renderer.coordinateSystem===Tc;if(a==="=="||a==="!="||a==="<"||a===">"||a==="<="||a===">=")return u?e.isVector(i)?e.format(`${this.getOperatorMethod(e,n)}( ${c}, ${d} )`,o,n):e.format(`( ${c} ${a} ${d} )`,o,n):e.format(`( ${c} ${a} ${d} )`,o,n);if(a==="%")return e.isInteger(l)?e.format(`( ${c} % ${d} )`,o,n):e.format(`${this.getOperatorMethod(e,o)}( ${c}, ${d} )`,o,n);if(a==="!"||a==="~")return e.format(`(${a}${c})`,i,n);if(h)return e.format(`${h}( ${c}, ${d} )`,o,n);if(e.isMatrix(i)&&l==="float")return e.format(`( ${d} ${a} ${c} )`,o,n);if(i==="float"&&e.isMatrix(l))return e.format(`${c} ${a} ${d}`,o,n);{let f=`( ${c} ${a} ${d} )`;return!u&&o==="bool"&&e.isVector(i)&&e.isVector(l)&&(f=`all${f}`),e.format(f,o,n)}}else if(i!=="void")return h?e.format(`${h}( ${c}, ${d} )`,o,n):e.isMatrix(i)&&l==="float"?e.format(`${d} ${a} ${c}`,o,n):e.format(`${c} ${a} ${d}`,o,n)}serialize(e){super.serialize(e),e.op=this.op}deserialize(e){super.deserialize(e),this.op=e.op}}const R0=ba(ml,"+").setParameterLength(2,1/0).setName("add"),ho=ba(ml,"-").setParameterLength(2,1/0).setName("sub"),Xs=ba(ml,"*").setParameterLength(2,1/0).setName("mul"),mh=ba(ml,"/").setParameterLength(2,1/0).setName("div"),BI=ba(ml,"%").setParameterLength(2).setName("mod"),PSe=ba(ml,"==").setParameterLength(2).setName("equal"),OSe=ba(ml,"!=").setParameterLength(2).setName("notEqual"),BSe=ba(ml,"<").setParameterLength(2).setName("lessThan"),Tne=ba(ml,">").setParameterLength(2).setName("greaterThan"),FSe=ba(ml,"<=").setParameterLength(2).setName("lessThanEqual"),LSe=ba(ml,">=").setParameterLength(2).setName("greaterThanEqual"),zSe=ba(ml,"&&").setParameterLength(2,1/0).setName("and"),USe=ba(ml,"||").setParameterLength(2,1/0).setName("or"),GSe=ba(ml,"!").setParameterLength(1).setName("not"),jSe=ba(ml,"^^").setParameterLength(2).setName("xor"),VSe=ba(ml,"&").setParameterLength(2).setName("bitAnd"),HSe=ba(ml,"~").setParameterLength(1).setName("bitNot"),WSe=ba(ml,"|").setParameterLength(2).setName("bitOr"),$Se=ba(ml,"^").setParameterLength(2).setName("bitXor"),YSe=ba(ml,"<<").setParameterLength(2).setName("shiftLeft"),qSe=ba(ml,">>").setParameterLength(2).setName("shiftRight"),XSe=Kt(([t])=>(t.addAssign(1),t)),QSe=Kt(([t])=>(t.subAssign(1),t)),KSe=Kt(([t])=>{const e=Gt(t).toConst();return t.addAssign(1),e}),JSe=Kt(([t])=>{const e=Gt(t).toConst();return t.subAssign(1),e});Hn("add",R0),Hn("sub",ho),Hn("mul",Xs),Hn("div",mh),Hn("mod",BI),Hn("equal",PSe),Hn("notEqual",OSe),Hn("lessThan",BSe),Hn("greaterThan",Tne),Hn("lessThanEqual",FSe),Hn("greaterThanEqual",LSe),Hn("and",zSe),Hn("or",USe),Hn("not",GSe),Hn("xor",jSe),Hn("bitAnd",VSe),Hn("bitNot",HSe),Hn("bitOr",WSe),Hn("bitXor",$Se),Hn("shiftLeft",YSe),Hn("shiftRight",qSe),Hn("incrementBefore",XSe),Hn("decrementBefore",QSe),Hn("increment",KSe),Hn("decrement",JSe);const ZSe=(t,e)=>(Nn('TSL: "modInt()" is deprecated. Use "mod( int( ... ) )" instead.',new Kl),BI(Gt(t),Gt(e)));Hn("modInt",ZSe);class xn extends Pl{static get type(){return"MathNode"}constructor(e,n,a=null,s=null){if(super(),(e===xn.MAX||e===xn.MIN)&&arguments.length>3){let r=new xn(e,n,a);for(let o=2;o<arguments.length-1;o++)r=new xn(e,r,arguments[o]);n=r,a=arguments[arguments.length-1],s=null}this.method=e,this.aNode=n,this.bNode=a,this.cNode=s,this.isMathNode=!0}getInputType(e){const n=this.aNode.getNodeType(e),a=this.bNode?this.bNode.getNodeType(e):null,s=this.cNode?this.cNode.getNodeType(e):null,r=e.isMatrix(n)?0:e.getTypeLength(n),o=e.isMatrix(a)?0:e.getTypeLength(a),i=e.isMatrix(s)?0:e.getTypeLength(s);return r>o&&r>i?n:o>i?a:i>r?s:n}getNodeType(e){const n=this.method;return n===xn.LENGTH||n===xn.DISTANCE||n===xn.DOT?"float":n===xn.CROSS?"vec3":n===xn.ALL||n===xn.ANY?"bool":n===xn.EQUALS?e.changeComponentType(this.aNode.getNodeType(e),"bool"):this.getInputType(e)}setup(e){const{aNode:n,bNode:a,method:s}=this;let r=null;if(s===xn.ONE_MINUS)r=ho(1,n);else if(s===xn.RECIPROCAL)r=mh(1,n);else if(s===xn.DIFFERENCE)r=Oi(ho(n,a));else if(s===xn.TRANSFORM_DIRECTION){let o=n,i=a;e.isMatrix(o.getNodeType(e))?i=ja($t(i),0):o=ja($t(o),0);const l=Xs(o,i).xyz;r=cf(l)}return r!==null?r:super.setup(e)}generate(e,n){if(e.getNodeProperties(this).outputNode)return super.generate(e,n);let s=this.method;const r=this.getNodeType(e),o=this.getInputType(e),i=this.aNode,l=this.bNode,c=this.cNode,d=e.renderer.coordinateSystem;if(s===xn.NEGATE)return e.format("( - "+i.build(e,o)+" )",r,n);{const h=[];return s===xn.CROSS?h.push(i.build(e,r),l.build(e,r)):d===Tc&&s===xn.STEP?h.push(i.build(e,e.getTypeLength(i.getNodeType(e))===1?"float":o),l.build(e,o)):d===Tc&&(s===xn.MIN||s===xn.MAX)?h.push(i.build(e,o),l.build(e,e.getTypeLength(l.getNodeType(e))===1?"float":o)):s===xn.REFRACT?h.push(i.build(e,o),l.build(e,o),c.build(e,"float")):s===xn.MIX?h.push(i.build(e,o),l.build(e,o),c.build(e,e.getTypeLength(c.getNodeType(e))===1?"float":o)):(d===Cc&&s===xn.ATAN&&l!==null&&(s="atan2"),e.shaderStage!=="fragment"&&(s===xn.DFDX||s===xn.DFDY)&&(Nn(`TSL: '${s}' is not supported in the ${e.shaderStage} stage.`,this.stackTrace),s="/*"+s+"*/"),h.push(i.build(e,o)),l!==null&&h.push(l.build(e,o)),c!==null&&h.push(c.build(e,o))),e.format(`${e.getMethod(s,r)}( ${h.join(", ")} )`,r,n)}}serialize(e){super.serialize(e),e.method=this.method}deserialize(e){super.deserialize(e),this.method=e.method}}xn.ALL="all",xn.ANY="any",xn.RADIANS="radians",xn.DEGREES="degrees",xn.EXP="exp",xn.EXP2="exp2",xn.LOG="log",xn.LOG2="log2",xn.SQRT="sqrt",xn.INVERSE_SQRT="inversesqrt",xn.FLOOR="floor",xn.CEIL="ceil",xn.NORMALIZE="normalize",xn.FRACT="fract",xn.SIN="sin",xn.COS="cos",xn.TAN="tan",xn.ASIN="asin",xn.ACOS="acos",xn.ATAN="atan",xn.ABS="abs",xn.SIGN="sign",xn.LENGTH="length",xn.NEGATE="negate",xn.ONE_MINUS="oneMinus",xn.DFDX="dFdx",xn.DFDY="dFdy",xn.ROUND="round",xn.RECIPROCAL="reciprocal",xn.TRUNC="trunc",xn.FWIDTH="fwidth",xn.TRANSPOSE="transpose",xn.DETERMINANT="determinant",xn.INVERSE="inverse",xn.EQUALS="equals",xn.MIN="min",xn.MAX="max",xn.STEP="step",xn.REFLECT="reflect",xn.DISTANCE="distance",xn.DIFFERENCE="difference",xn.DOT="dot",xn.CROSS="cross",xn.POW="pow",xn.TRANSFORM_DIRECTION="transformDirection",xn.MIX="mix",xn.CLAMP="clamp",xn.REFRACT="refract",xn.SMOOTHSTEP="smoothstep",xn.FACEFORWARD="faceforward";const Cne=bt(1e-6),p6t=bt(1e6),Ez=bt(Math.PI),m6t=bt(Math.PI*2),g6t=bt(Math.PI*2),x6t=bt(Math.PI*.5),eAe=ba(xn,xn.ALL).setParameterLength(1),tAe=ba(xn,xn.ANY).setParameterLength(1),nAe=ba(xn,xn.RADIANS).setParameterLength(1),aAe=ba(xn,xn.DEGREES).setParameterLength(1),_ne=ba(xn,xn.EXP).setParameterLength(1),N8=ba(xn,xn.EXP2).setParameterLength(1),kz=ba(xn,xn.LOG).setParameterLength(1),tg=ba(xn,xn.LOG2).setParameterLength(1),Ad=ba(xn,xn.SQRT).setParameterLength(1),Ine=ba(xn,xn.INVERSE_SQRT).setParameterLength(1),ng=ba(xn,xn.FLOOR).setParameterLength(1),Dz=ba(xn,xn.CEIL).setParameterLength(1),cf=ba(xn,xn.NORMALIZE).setParameterLength(1),wm=ba(xn,xn.FRACT).setParameterLength(1),Td=ba(xn,xn.SIN).setParameterLength(1),Mm=ba(xn,xn.COS).setParameterLength(1),sAe=ba(xn,xn.TAN).setParameterLength(1),rAe=ba(xn,xn.ASIN).setParameterLength(1),Ene=ba(xn,xn.ACOS).setParameterLength(1),kne=ba(xn,xn.ATAN).setParameterLength(1,2),Oi=ba(xn,xn.ABS).setParameterLength(1),Dne=ba(xn,xn.SIGN).setParameterLength(1),ag=ba(xn,xn.LENGTH).setParameterLength(1),Nne=ba(xn,xn.NEGATE).setParameterLength(1),oAe=ba(xn,xn.ONE_MINUS).setParameterLength(1),Rne=ba(xn,xn.DFDX).setParameterLength(1),Pne=ba(xn,xn.DFDY).setParameterLength(1),iAe=ba(xn,xn.ROUND).setParameterLength(1),lAe=ba(xn,xn.RECIPROCAL).setParameterLength(1),One=ba(xn,xn.TRUNC).setParameterLength(1),Bne=ba(xn,xn.FWIDTH).setParameterLength(1),cAe=ba(xn,xn.TRANSPOSE).setParameterLength(1),uAe=ba(xn,xn.DETERMINANT).setParameterLength(1),dAe=ba(xn,xn.INVERSE).setParameterLength(1),uf=ba(xn,xn.MIN).setParameterLength(2,1/0),Ol=ba(xn,xn.MAX).setParameterLength(2,1/0),W4=ba(xn,xn.STEP).setParameterLength(2),fAe=ba(xn,xn.REFLECT).setParameterLength(2),hAe=ba(xn,xn.DISTANCE).setParameterLength(2),pAe=ba(xn,xn.DIFFERENCE).setParameterLength(2),tp=ba(xn,xn.DOT).setParameterLength(2),dx=ba(xn,xn.CROSS).setParameterLength(2),np=ba(xn,xn.POW).setParameterLength(2),Fne=t=>Xs(t,t),mAe=t=>Xs(t,t,t),Lne=t=>Xs(t,t,t,t),gAe=ba(xn,xn.TRANSFORM_DIRECTION).setParameterLength(2),xAe=t=>Xs(Dne(t),np(Oi(t),1/3)),zne=t=>tp(t,t),Wr=ba(xn,xn.MIX).setParameterLength(3),Sm=(t,e=0,n=1)=>new xn(xn.CLAMP,Ja(t),Ja(e),Ja(n)),Nz=t=>Sm(t),Une=ba(xn,xn.REFRACT).setParameterLength(3),gh=ba(xn,xn.SMOOTHSTEP).setParameterLength(3),Gne=ba(xn,xn.FACEFORWARD).setParameterLength(3),yAe=Kt(([t])=>{const a=43758.5453,s=tp(t.xy,ha(12.9898,78.233)),r=BI(s,Ez);return wm(Td(r).mul(a))}),vAe=(t,e,n)=>Wr(e,n,t),bAe=(t,e,n)=>gh(e,n,t),wAe=(t,e)=>W4(e,t),y6t=Gne,v6t=Ine;Hn("all",eAe),Hn("any",tAe),Hn("radians",nAe),Hn("degrees",aAe),Hn("exp",_ne),Hn("exp2",N8),Hn("log",kz),Hn("log2",tg),Hn("sqrt",Ad),Hn("inverseSqrt",Ine),Hn("floor",ng),Hn("ceil",Dz),Hn("normalize",cf),Hn("fract",wm),Hn("sin",Td),Hn("cos",Mm),Hn("tan",sAe),Hn("asin",rAe),Hn("acos",Ene),Hn("atan",kne),Hn("abs",Oi),Hn("sign",Dne),Hn("length",ag),Hn("lengthSq",zne),Hn("negate",Nne),Hn("oneMinus",oAe),Hn("dFdx",Rne),Hn("dFdy",Pne),Hn("round",iAe),Hn("reciprocal",lAe),Hn("trunc",One),Hn("fwidth",Bne),Hn("min",uf),Hn("max",Ol),Hn("step",wAe),Hn("reflect",fAe),Hn("distance",hAe),Hn("dot",tp),Hn("cross",dx),Hn("pow",np),Hn("pow2",Fne),Hn("pow3",mAe),Hn("pow4",Lne),Hn("transformDirection",gAe),Hn("mix",vAe),Hn("clamp",Sm),Hn("refract",Une),Hn("smoothstep",bAe),Hn("faceForward",Gne),Hn("difference",pAe),Hn("saturate",Nz),Hn("cbrt",xAe),Hn("transpose",cAe),Hn("determinant",uAe),Hn("inverse",dAe),Hn("rand",yAe);class MAe extends Ka{static get type(){return"ConditionalNode"}constructor(e,n,a=null){super(),this.condNode=e,this.ifNode=n,this.elseNode=a}getNodeType(e){const{ifNode:n,elseNode:a}=e.getNodeProperties(this);if(n===void 0)return e.flowBuildStage(this,"setup"),this.getNodeType(e);const s=n.getNodeType(e);if(a!==null){const r=a.getNodeType(e);if(e.getTypeLength(r)>e.getTypeLength(s))return r}return s}setup(e){const n=this.condNode,a=this.ifNode.isolate(),s=this.elseNode?this.elseNode.isolate():null,r=e.context.nodeBlock;e.getDataFromNode(a).parentNodeBlock=r,s!==null&&(e.getDataFromNode(s).parentNodeBlock=r);const o=e.context.uniformFlow,i=e.getNodeProperties(this);i.condNode=n,i.ifNode=o?a:a.context({nodeBlock:a}),i.elseNode=s?o?s:s.context({nodeBlock:s}):null}generate(e,n){const a=this.getNodeType(e),s=e.getDataFromNode(this);if(s.nodeProperty!==void 0)return s.nodeProperty;const{condNode:r,ifNode:o,elseNode:i}=e.getNodeProperties(this),l=e.currentFunctionNode,c=n!=="void",d=c?bm(a).build(e):"";s.nodeProperty=d;const h=r.build(e,"bool");if(e.context.uniformFlow&&i!==null){const p=o.build(e,a),m=i.build(e,a),g=e.getTernary(h,p,m);return e.format(g,a,n)}e.addFlowCode(`
|
|
@@ -79142,7 +79142,7 @@ function n7t(t, { project: e, sources: a, strips: r, parts: n, config: i, assets
|
|
|
79142
79142
|
for (const u of [z8t, F8t, L8t, U8t, j8t, X8t, Y8t]) u(l);
|
|
79143
79143
|
return s && (l.chat = e7t(l, s)), l;
|
|
79144
79144
|
}
|
|
79145
|
-
const _Ce = "0.2.
|
|
79145
|
+
const _Ce = "0.2.1", Lz = () => {
|
|
79146
79146
|
};
|
|
79147
79147
|
Pbt(), Y4t();
|
|
79148
79148
|
function i7t({ project: t, playerRef: e }) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "greenlight-motion",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "GreenLight Motion Engine: AI agents make motion-design videos (3D, camera, effects, transitions, text animation, particles, motion blur) with the GreenLight Dash Video Editor's own engine, in the user's browser.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"video",
|
package/skill/SKILL.md
CHANGED
|
@@ -18,12 +18,19 @@ You never write UI or animation code. If something is not in the format, it is n
|
|
|
18
18
|
## Setup (once per machine)
|
|
19
19
|
|
|
20
20
|
```
|
|
21
|
-
npx greenlight-motion@0.2.
|
|
21
|
+
npx greenlight-motion@0.2.1 doctor
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
It checks Node 18+, Chrome or Edge, WebGPU and H.264 encoding, and prints a fix for anything missing. Do not install
|
|
25
25
|
anything globally without asking the user. Always pin the version in every command you run.
|
|
26
26
|
|
|
27
|
+
## First, a direction
|
|
28
|
+
|
|
29
|
+
Before any JSON, decide in a few lines what the video LOOKS like: one visual idea from the subject's own world carried
|
|
30
|
+
through every scene, the palette, the type, and what each scene shows besides its words. Presets make a video move;
|
|
31
|
+
the direction makes it look designed. `skill/references/scene-script.md` opens with how. Then build to it, and judge
|
|
32
|
+
every contact sheet against it.
|
|
33
|
+
|
|
27
34
|
## The fast way: a scene script
|
|
28
35
|
|
|
29
36
|
For a new video, start with a **scene script** instead of a whole project: a short JSON file — scenes, their texts and
|
|
@@ -32,7 +39,7 @@ animation presets (the same converter the GreenLight Motion connector uses in Cl
|
|
|
32
39
|
keyframes rarely look as good. The format, the design rules and the catalogues: `skill/references/scene-script.md`.
|
|
33
40
|
|
|
34
41
|
```
|
|
35
|
-
npx greenlight-motion@0.2.
|
|
42
|
+
npx greenlight-motion@0.2.1 script <folder> --from scenes.json # or write <folder>/script.json, then: script <folder>
|
|
36
43
|
```
|
|
37
44
|
|
|
38
45
|
Then `check` and `stills` (below), fix the SCRIPT and run `script` again — it rewrites `project.json`. A scene's
|
|
@@ -40,16 +47,39 @@ Then `check` and `stills` (below), fix the SCRIPT and run `script` again — it
|
|
|
40
47
|
`z`). For what a script can't say (3D models, particles, motion paths, masks, text animators by hand), go on from `project.json` with the
|
|
41
48
|
workflow below and stop running `script` (it refuses to overwrite a project edited since, unless `--force`).
|
|
42
49
|
|
|
50
|
+
## Beyond the script: the signature visual
|
|
51
|
+
|
|
52
|
+
The script gives structure; the picture that makes the video THIS product's usually needs the engine's full format.
|
|
53
|
+
Build it with `apply` on the project `script` wrote (the item ids are the script's element ids):
|
|
54
|
+
|
|
55
|
+
- **A material of its own**: a custom GLSL shader on a shape or the whole background (water, light through glass,
|
|
56
|
+
paper, heat): `shapeBackground` / `background` `{ "type": "shader", "shaderId": "custom", "shaderCode": "void
|
|
57
|
+
mainImage(out vec4 o, in vec2 fc) { … }" }`, Shadertoy-style, `iTime` from the timeline
|
|
58
|
+
(`references/video-backgrounds.md`, Custom GLSL shaders).
|
|
59
|
+
- **Layers that interact**: a track matte, so words dip under a surface or show only through a shape
|
|
60
|
+
(`"trackMatte": { "sourceId": "<item>", "mode": "alpha" | "alphaInverted" | "luma" | "lumaInverted" }` on the layer
|
|
61
|
+
that is cut; the source is hidden from the output; `references/video-shapes.md`). Clipping masks and Layer Mask
|
|
62
|
+
(`references/video-effects.md`) for reveals.
|
|
63
|
+
- **Your own drawing and motion**: SVG you write (`{ "type": "image", "svg": "…" }` in the script), shapes with
|
|
64
|
+
keyframes, motion paths (`references/video-paths.md`), particles (`references/video-particles.md`), 3D
|
|
65
|
+
(`references/video-3d.md`), Text Animators by hand (`references/video-text.md`).
|
|
66
|
+
- **Sound when nothing may be downloaded**: write it in code. A short Node script can write a 48 kHz WAV (a soft bed, a
|
|
67
|
+
click, a noise whoosh) into `assets/`, then use it as the script's `music` or as an audio clip. Keep the bed quiet
|
|
68
|
+
under the hits.
|
|
69
|
+
|
|
70
|
+
Keep the build repeatable: put your edits in a file you `apply` again after each `script` run (`script --force`, then
|
|
71
|
+
`apply`), so the script and the hand-made layers never drift apart.
|
|
72
|
+
|
|
43
73
|
## Workflow
|
|
44
74
|
|
|
45
|
-
1. `npx greenlight-motion@0.2.
|
|
75
|
+
1. `npx greenlight-motion@0.2.1 init <folder>` — starts from a working example (title, subtitle, accent line, four
|
|
46
76
|
options). `--from file.json` starts from a project you have (for example one exported from GreenLight Dash).
|
|
47
77
|
2. Edit `<folder>/project.json` — for changes to an EXISTING project prefer `apply` (below): it checks every edit and
|
|
48
78
|
applies all or nothing. Put pictures, video, sound and fonts in `<folder>/assets/` and refer to them as
|
|
49
79
|
`"asset:<file>"` (e.g. `"url": "asset:product.png"`).
|
|
50
|
-
3. `npx greenlight-motion@0.2.
|
|
80
|
+
3. `npx greenlight-motion@0.2.1 check <folder>` — fix everything it lists (missing files, template mistakes, blank
|
|
51
81
|
frames, page errors). `--json` for machine output.
|
|
52
|
-
4. `npx greenlight-motion@0.2.
|
|
82
|
+
4. `npx greenlight-motion@0.2.1 stills <folder>` — renders frames and **a labelled contact sheet**. Open and look at
|
|
53
83
|
it before you go on: layout, readability, timing. Fix and repeat. `--at 0.5,1.2,3` for exact times.
|
|
54
84
|
5. Hand it over: tell the user to open `<folder>/index.html` (Chrome or Edge), or `pack` it into one file, or
|
|
55
85
|
`render` the MP4 yourself (`--fps 60 --motion-blur` for fast motion).
|
|
@@ -114,7 +144,7 @@ editor's own normalizer), so write only what you mean.
|
|
|
114
144
|
Full references (generated from the editor's own docs; ignore the `/api/` routes they mention):
|
|
115
145
|
`skill/references/` — video-design, scene-script, video-projects, video-text, video-text-kinetic, video-text-presets, video-shapes, video-keyframes,
|
|
116
146
|
video-camera, video-3d, video-effects, video-transitions, video-particles, video-paths, video-backgrounds, video-grid.
|
|
117
|
-
Machine-readable lists: `npx greenlight-motion@0.2.
|
|
147
|
+
Machine-readable lists: `npx greenlight-motion@0.2.1 schema effects | transitions | easings | paths | expressions`.
|
|
118
148
|
|
|
119
149
|
## Template
|
|
120
150
|
|
|
@@ -161,7 +191,7 @@ an absolute moment; `align` `sync` (default) / `start` / `end`; `offset` seconds
|
|
|
161
191
|
|
|
162
192
|
The library is 77 hand-picked sounds in categories (whooshes and swooshes, transitions, clicks, pop-ups and
|
|
163
193
|
notifications, data blips, typing and writing, foley, bubbles, impacts and bass drops, camera, gears, voice clips).
|
|
164
|
-
`npx greenlight-motion@0.2.
|
|
194
|
+
`npx greenlight-motion@0.2.1 schema sounds` lists every one with its `category`, `use` (what it is for), `duration`
|
|
165
195
|
and `sync`. Pick by `category` and `use`, then by name.
|
|
166
196
|
|
|
167
197
|
- **Where the files come from:** the GreenLight sound CDN. `build` downloads each sound a cue uses into
|
|
@@ -177,7 +207,7 @@ The page has **Notes**: the user marks what should change right on the frame (a
|
|
|
177
207
|
and writes a note for each mark. Every note carries the moment (seconds and frame), the mark in composition pixels
|
|
178
208
|
and the layers under it (item ids in project.json), so you change exactly that and nothing else.
|
|
179
209
|
|
|
180
|
-
- **They review on this computer:** run `npx greenlight-motion@0.2.
|
|
210
|
+
- **They review on this computer:** run `npx greenlight-motion@0.2.1 review <folder>` and give them the URL it prints
|
|
181
211
|
(it keeps running; `--open` opens their browser, only when they ask). Their notes land in `<folder>/review/`: read
|
|
182
212
|
`review/NOTES.md`, look at the `at-<t>s.png` pictures (the marks are numbered), make the changes (`apply`), `build`
|
|
183
213
|
again and tell them to reload the page.
|
|
@@ -206,11 +236,11 @@ that fails (`plugin`); look at `stills` for the look. A package that carries its
|
|
|
206
236
|
|
|
207
237
|
The same project opens in GreenLight Dash (the desktop editor this engine comes from) for full editing: the page's
|
|
208
238
|
edit note offers **Open in GreenLight Dash** (it imports the folder as a new project on the open board; a page with
|
|
209
|
-
changes saves a `.glvideo`). `npx greenlight-motion@0.2.
|
|
239
|
+
changes saves a `.glvideo`). `npx greenlight-motion@0.2.1 pack <folder> --glvideo` writes that file yourself: ONE
|
|
210
240
|
`.glvideo` (the project + its files) that opens in GreenLight Dash on a double-click, or dropped on its board. Hand it
|
|
211
241
|
over when the user wants to keep editing in the app. A
|
|
212
242
|
GreenLight Dash project comes the other way through the app's **Export for agents** — a ready folder like the one
|
|
213
|
-
`init` makes, with the options the author ticked. `npx greenlight-motion@0.2.
|
|
243
|
+
`init` makes, with the options the author ticked. `npx greenlight-motion@0.2.1 init <folder> --from <its project.json>`
|
|
214
244
|
starts from one too. Never tell the user they must install it: the page plays, changes options and renders on its own.
|
|
215
245
|
|
|
216
246
|
## Files
|
|
@@ -13,6 +13,19 @@ works too (it has to stay reachable). SVG you write: `{ "type": "image", "svg":
|
|
|
13
13
|
|
|
14
14
|
## The scene script
|
|
15
15
|
|
|
16
|
+
**Before the script, a direction.** Presets make a video move; they don't give it an idea. Decide in a few lines first,
|
|
17
|
+
and keep them next to the script:
|
|
18
|
+
- **The idea**: ONE picture from the subject's own world (its object, place or action: a coffee shop's steam and cup rim,
|
|
19
|
+
a budgeting app's receipt printing line by line, a running app's track the scenes run along), carried through every scene.
|
|
20
|
+
- **The palette**: background, text, one accent, plus only the colours that carry meaning (good / bad, before / after).
|
|
21
|
+
Light or dark on purpose.
|
|
22
|
+
- **The type**: a big headline against a small support line; aligned left or centred on purpose, not by default.
|
|
23
|
+
- **Each scene**: what it SHOWS besides its words, built from shapes, lines, `svg` you write, keyframes and the camera.
|
|
24
|
+
The same line centred on a gradient in every scene reads as a template. Judge the stills against the direction, not
|
|
25
|
+
only for mistakes.
|
|
26
|
+
What a script can't say (a custom GLSL shader on a shape or the background, words dipping under a surface with a track
|
|
27
|
+
matte, masks, particles, 3D) goes on from `project.json`: SKILL.md, "Beyond the script".
|
|
28
|
+
|
|
16
29
|
```json
|
|
17
30
|
{
|
|
18
31
|
"title": "Bean There — opening day",
|
|
@@ -57,6 +70,9 @@ works too (it has to stay reachable). SVG you write: `{ "type": "image", "svg":
|
|
|
57
70
|
(the scene's camera doesn't move it: a logo, a caption). Keyframes also take a `z` track.
|
|
58
71
|
- **Scene**: `duration` (s), `transition` into it (default Cross Fade, 0.6 s; `transitionDuration`), `camera` (below; default push-in),
|
|
59
72
|
`background` (overrides style), `sounds`: [{ "sfx", "at" }]. Script-level `sound`: auto (default: a whoosh on each transition and on the first headline) | none.
|
|
73
|
+
**A transition overlaps the scenes on both sides**, so the video lasts the scenes' durations added up MINUS every
|
|
74
|
+
transition: five 3 s scenes with the default 0.6 s transitions run 15 − 4 × 0.6 = 12.6 s. To hit a length, add the
|
|
75
|
+
transitions back to the scenes (`script` prints the total).
|
|
60
76
|
- **camera** — a quick move of the whole scene: none | push-in | pull-out | drift-left | drift-right | drift-up. Or a REAL camera that films the scene's elements in 3D (the
|
|
61
77
|
Video Editor's own camera layer; the scene's backdrop stays put, so its edge never shows). One of:
|
|
62
78
|
- `{ "move": id }` — a camera move from the catalogue (or just `"camera": "cm-quiet-push"`), spread over the scene;
|