diff --git a/README.md b/README.md index fb79e71..5bd62eb 100644 --- a/README.md +++ b/README.md @@ -122,12 +122,18 @@ out/ Humanize PPT 当前重点是稳定“资料 → AST生产契约 → 风格预览/完整deck → presenter/export → QA”的工作流。更多renderer自动化、视频生成、部署平台集成和团队包上传会放到后续版本,不塞进这次目录整理。 +V0.6.1 补充了 guizang downstream 工作流经验:Humanize PPT 先产出 AST 契约,guizang 负责中文稳定渲染,素材生产和视觉 QA 作为独立 pass 记录。文字精确的信息图优先用 SVG/HTML 等确定性素材;Remotion 用作短流程视频素材,不替代 PPT 页面本体。 + +V0.6.2 固定中文 PPT 的下一段默认路径:`Humanize PPT → guizang → material QA → presenter → static deploy`。当内容是中文且没有显式要求多风格探索时,优先把 guizang 当作稳定成稿路径;成稿后再补演讲模式和部署包,而不是把 presenter 当成另一种视觉风格。 + ## 在线预览 - 首页:https://learnprompt.github.io/humanize-ppt/ - Skill分享PPT展示页:https://learnprompt.github.io/humanize-ppt/showcase/skill-share/ +- Hermes Agent Mastery 演讲模式:https://learnprompt.github.io/humanize-ppt/showcase/hermes-agent-mastery/presenter/ +- Hermes Agent Mastery PPT:https://learnprompt.github.io/humanize-ppt/showcase/hermes-agent-mastery/ppt/ -风格探索、演讲者模式和其他生成模式还在调试中,公开入口先隐藏。稳定后再恢复在线Demo入口。 +风格探索和其他生成模式还在调试中,公开入口先隐藏。中文 guizang → presenter 路径先作为稳定样例开放。 ## 参考文档 @@ -135,6 +141,8 @@ Humanize PPT 当前重点是稳定“资料 → AST生产契约 → 风格预览 - [OPC工作流](docs/OPC-workflow.md) - [Agent Teams](docs/agent-teams.md) - [Smoke Test](docs/smoke-test.md) +- [Guizang material QA](references/guizang-material-qa.md) +- [Guizang presenter deploy](references/guizang-presenter-deploy.md) - [版本历史](docs/versions/) - [发版前审查清单](docs/plans/2026-05-25-release-readiness-checklist.md) diff --git a/SKILL.md b/SKILL.md index 5daed9e..55f97a4 100644 --- a/SKILL.md +++ b/SKILL.md @@ -1,7 +1,7 @@ --- name: humanize-ppt description: AST-based outline director and router for human-centered AI presentation workflows. Use before generating PPT/HTML slides from raw material, or as the single entrypoint that routes to downstream PPT Skills. -version: 0.6.0 +version: 0.6.2 author: LearnPrompt license: MIT metadata: @@ -101,12 +101,17 @@ C — Complete / Control 10. When `beautiful-html-templates` is the preview-first route, do not stop at a planned command file. A connected path must produce real `outputs/beautiful/previews/index.html`, three candidate title-slide previews, `preview_manifest.json`, a render report, and a QA-visible route status. Treat this as V0.3+ capability, because it changes the user-facing workflow from routing advice to visible style selection. 11. When the user chooses a Beautiful candidate, run V0.4+ `--selected-template ` and produce a real full deck at `outputs/beautiful/selected/index.html` plus `selected_manifest.json`. Do not call this complete if only the preview gallery exists. 12. In V0.5, presenter/export are post-processing adapters. They require a rendered final deck (`outputs//index.html` or `outputs/beautiful/selected/index.html`), not just a preview gallery. +13. When routing to `guizang-ppt-skill`, treat guizang as the stable Chinese production renderer, then run a separate visual/material QA pass before presenter or deploy. Check that template class names actually exist in the copied template CSS; do not trust layout docs blindly. If an SVG, GPT image, screenshot, or Remotion clip is inserted, it must support the page instead of repeating the page title, and all internal text must fit within its own safe area. +14. For Swiss-style guizang decks, use Remotion as a material producer for short process clips and deterministic SVG/HTML diagrams for text-heavy Chinese information graphics. Prefer GPT image generation for non-textual photos, mood images, or visual concepts; use deterministic SVG/HTML when exact Chinese labels, grid alignment, or validation-friendly text is required. +15. For Chinese PPT production, the default stable path is `Humanize PPT → guizang → material QA → presenter → static deploy` unless the user explicitly requests preview-first style exploration, PPTX conversion, or another renderer. Presenter mode is a completion path after the guizang deck is finalized. ## Operational references - `references/agent-teams-public-preview.md` — Agent Teams architecture, specialist-agent command protocol, public preview release loop, and README split convention. - `references/humanize-ppt-public-writing.md` — Public-facing positioning and article/script patterns: Humanize PPT as adaptable outline/director layer, not a fixed 4-Skill bundle. - `references/workbuddy-team-packaging-and-video-materials.md` — WorkBuddy/CodeBuddy team upload zip structure, validation script, scenario rules shape, and the Remotion/HyperFrames-as-material-producers pitfall. +- `references/guizang-material-qa.md` — Guizang downstream workflow, material production rules, Swiss visual QA checklist, and failure patterns learned from a full Humanize PPT → guizang deck pass. +- `references/guizang-presenter-deploy.md` — Default Chinese PPT production path: guizang stable deck, material QA, presenter shell, and static deploy checks. - `references/beautiful-preview-first-adapter.md` — Durable adapter pattern for connecting `beautiful-html-templates`: version boundary, template selection, real title-slide previews, manifests, QA, and pitfalls. - `references/selected-template-full-deck-adapter.md` — Durable adapter pattern for V0.4 selected-template full deck generation: required artifacts, routing, QA, and TDD coverage. - `references/presenter-export-adapter.md` — Durable adapter pattern for adding V0.5-style presenter shell and export package after a final deck exists. @@ -114,6 +119,8 @@ C — Complete / Control - `docs/versions/v0.3-preview-first.md` — V0.3 Preview-First implementation notes: real `beautiful-html-templates` preview gallery, template selection, manifests, and version boundary. - `docs/versions/v0.4-selected-template-full-deck.md` — V0.4 Selected Template Full Deck notes: `--selected-template`, selected deck output, manifests, QA, and current boundaries. - `docs/versions/v0.5-presenter-export-adapter.md` — V0.5 Presenter / Export Adapter notes: `--presenter-adapter`, `--export-adapter`, output artifacts, and boundaries. +- `docs/versions/v0.6.1-guizang-material-qa.md` — V0.6.1 Guizang material QA notes: downstream artifact recording, Remotion-as-material, SVG-safe Chinese diagrams, and visual review rules. +- `docs/versions/v0.6.2-guizang-presenter-deploy.md` — V0.6.2 Guizang presenter deploy notes: Chinese default path, `postMessage` presenter shell, and public static showcase. - `docs/smoke-test.md` — No-dependency smoke check for validating the stable entrypoint on machines without pytest. - `docs/plans/2026-05-25-release-readiness-checklist.md` — V0.6 release-readiness checklist and release-note draft. diff --git a/docs/index.html b/docs/index.html index 70a3f7e..b2b541d 100644 --- a/docs/index.html +++ b/docs/index.html @@ -127,12 +127,13 @@

Humanize PPT · Preview

把 AI 从聊天框带进真实工作流

-

Humanize PPT 是基于 AST 理论的 PPT 大纲导演 Skill。当前公开页先展示已调好的 Skill 分享 PPT;风格探索、演讲者模式和导出适配器继续稳定后再开放公开入口。

+

Humanize PPT 是基于 AST 理论的 PPT 大纲导演 Skill。当前公开页展示已调好的 Skill 分享 PPT,以及中文 guizang → presenter 的稳定样例。

-

Skill 分享 PPT

-

HTML PPT 发布版,适合现在作为线上展示页面使用。

- 打开展示 +

Hermes Agent Mastery

+

中文 guizang 成稿 + 演讲模式,作为 V0.6.2 的稳定路径样例。

+ 打开演讲模式 + Skill 分享 PPT Agent Teams
@@ -142,8 +143,8 @@

Roadmap

diff --git a/docs/index.md b/docs/index.md index 1e86ae6..e6d6820 100644 --- a/docs/index.md +++ b/docs/index.md @@ -3,4 +3,6 @@ Public preview docs. The current public preview shows the tuned Skill sharing deck first. - Showcase: `showcase/skill-share/` -- Roadmap: style exploration, presenter mode, and other demo modes are hidden until the workflows are stable. +- Hermes Agent Mastery presenter: `showcase/hermes-agent-mastery/presenter/` +- Hermes Agent Mastery PPT: `showcase/hermes-agent-mastery/ppt/` +- Roadmap: style exploration and other demo modes are hidden until the workflows are stable. diff --git a/docs/showcase/hermes-agent-mastery/README.md b/docs/showcase/hermes-agent-mastery/README.md new file mode 100644 index 0000000..1b815e5 --- /dev/null +++ b/docs/showcase/hermes-agent-mastery/README.md @@ -0,0 +1,21 @@ +# Agent 从入门到精通 Hermes 版 + +这是一次 Humanize PPT → guizang-ppt-skill → material QA → presenter mode 的中文稳定生产样例。 + +## 在线路径 + +合并到 `main` 并由 GitHub Pages 发布后: + +- PPT:`https://learnprompt.github.io/humanize-ppt/showcase/hermes-agent-mastery/ppt/` +- 演讲模式:`https://learnprompt.github.io/humanize-ppt/showcase/hermes-agent-mastery/presenter/` + +## 本地路径 + +- `ppt/index.html`:完整 guizang Swiss HTML PPT。 +- `presenter/index.html`:讲者控制台。 +- `presenter/notes.json`:逐页讲者备注。 +- `presenter/presenter_manifest.json`:演讲模式产物记录。 + +## 说明 + +这个样例固定中文 PPT 的推荐后处理路径:先用 guizang 做稳定中文成稿,再做素材/视觉 QA,最后补 presenter/deploy。 diff --git a/docs/showcase/hermes-agent-mastery/index.html b/docs/showcase/hermes-agent-mastery/index.html new file mode 100644 index 0000000..553c4cd --- /dev/null +++ b/docs/showcase/hermes-agent-mastery/index.html @@ -0,0 +1,20 @@ + + + + + + Agent 从入门到精通 Hermes 版 + + + + +
+

Agent 从入门到精通 Hermes 版

+

正在打开演讲模式。也可以直接进入 PresenterPPT

+
+ + diff --git a/docs/showcase/hermes-agent-mastery/ppt/README.md b/docs/showcase/hermes-agent-mastery/ppt/README.md new file mode 100644 index 0000000..5a21a08 --- /dev/null +++ b/docs/showcase/hermes-agent-mastery/ppt/README.md @@ -0,0 +1,7 @@ +# Agent 从入门到精通:Hermes 版 + +Guizang PPT Skill Swiss Style output. + +- Open: ./index.html +- Style: Swiss Internationalism / IKB +- Slides: 8 diff --git a/docs/showcase/hermes-agent-mastery/ppt/assets/motion.min.js b/docs/showcase/hermes-agent-mastery/ppt/assets/motion.min.js new file mode 100644 index 0000000..2474e15 --- /dev/null +++ b/docs/showcase/hermes-agent-mastery/ppt/assets/motion.min.js @@ -0,0 +1,8 @@ +/** + * Bundled by jsDelivr using Rollup v2.79.2 and Terser v5.39.0. + * Original file: /npm/motion@11.11.17/dist/es/motion/lib/index.mjs + * + * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files + */ +function t(t,e){const n=t.indexOf(e);n>-1&&t.splice(n,1)}class e{constructor(){this.subscriptions=[]}add(e){var n,s;return n=this.subscriptions,s=e,-1===n.indexOf(s)&&n.push(s),()=>t(this.subscriptions,e)}notify(t,e,n){const s=this.subscriptions.length;if(s)if(1===s)this.subscriptions[0](t,e,n);else for(let i=0;it;const r=["read","resolveKeyframes","update","preRender","render","postRender"];const{schedule:o,cancel:a,state:l,steps:u}=function(t,e){let n=!1,s=!0;const i={delta:0,timestamp:0,isProcessing:!1},o=()=>n=!0,a=r.reduce(((t,e)=>(t[e]=function(t){let e=new Set,n=new Set,s=!1,i=!1;const r=new WeakSet;let o={delta:0,timestamp:0,isProcessing:!1};function a(e){r.has(e)&&(l.schedule(e),t()),e(o)}const l={schedule:(t,i=!1,o=!1)=>{const a=o&&s?e:n;return i&&r.add(t),a.has(t)||a.add(t),t},cancel:t=>{n.delete(t),r.delete(t)},process:t=>{o=t,s?i=!0:(s=!0,[e,n]=[n,e],n.clear(),e.forEach(a),s=!1,i&&(i=!1,l.process(t)))}};return l}(o),t)),{}),{read:l,resolveKeyframes:u,update:c,preRender:h,render:d,postRender:p}=a,f=()=>{const r=performance.now();n=!1,i.delta=s?1e3/60:Math.max(Math.min(r-i.timestamp,40),1),i.timestamp=r,i.isProcessing=!0,l.process(i),u.process(i),c.process(i),h.process(i),d.process(i),p.process(i),i.isProcessing=!1,n&&e&&(s=!1,t(f))};return{schedule:r.reduce(((e,r)=>{const o=a[r];return e[r]=(e,r=!1,a=!1)=>(n||(n=!0,s=!0,i.isProcessing||t(f)),o.schedule(e,r,a)),e}),{}),cancel:t=>{for(let e=0;e(void 0===c&&d.set(l.isProcessing||s?l.timestamp:performance.now()),c),set:t=>{c=t,queueMicrotask(h)}};class p{constructor(t,e={}){this.version="11.11.17",this.canTrackVelocity=null,this.events={},this.updateAndNotify=(t,e=!0)=>{const n=d.now();this.updatedAt!==n&&this.setPrevFrameValue(),this.prev=this.current,this.setCurrent(t),this.current!==this.prev&&this.events.change&&this.events.change.notify(this.current),e&&this.events.renderRequest&&this.events.renderRequest.notify(this.current)},this.hasAnimated=!1,this.setCurrent(t),this.owner=e.owner}setCurrent(t){var e;this.current=t,this.updatedAt=d.now(),null===this.canTrackVelocity&&void 0!==t&&(this.canTrackVelocity=(e=this.current,!isNaN(parseFloat(e))))}setPrevFrameValue(t=this.current){this.prevFrameValue=t,this.prevUpdatedAt=this.updatedAt}onChange(t){return this.on("change",t)}on(t,n){this.events[t]||(this.events[t]=new e);const s=this.events[t].add(n);return"change"===t?()=>{s(),o.read((()=>{this.events.change.getSize()||this.stop()}))}:s}clearListeners(){for(const t in this.events)this.events[t].clear()}attach(t,e){this.passiveEffect=t,this.stopPassiveEffect=e}set(t,e=!0){e&&this.passiveEffect?this.passiveEffect(t,this.updateAndNotify):this.updateAndNotify(t,e)}setWithVelocity(t,e,n){this.set(e),this.prev=void 0,this.prevFrameValue=t,this.prevUpdatedAt=this.updatedAt-n}jump(t,e=!0){this.updateAndNotify(t),this.prev=t,this.prevUpdatedAt=this.prevFrameValue=void 0,e&&this.stop(),this.stopPassiveEffect&&this.stopPassiveEffect()}get(){return this.current}getPrevious(){return this.prev}getVelocity(){const t=d.now();if(!this.canTrackVelocity||void 0===this.prevFrameValue||t-this.updatedAt>30)return 0;const e=Math.min(this.updatedAt-this.prevUpdatedAt,30);return n(parseFloat(this.current)-parseFloat(this.prevFrameValue),e)}start(t){return this.stop(),new Promise((e=>{this.hasAnimated=!0,this.animation=t(e),this.events.animationStart&&this.events.animationStart.notify()})).then((()=>{this.events.animationComplete&&this.events.animationComplete.notify(),this.clearAnimation()}))}stop(){this.animation&&(this.animation.stop(),this.events.animationCancel&&this.events.animationCancel.notify()),this.clearAnimation()}isAnimating(){return!!this.animation}clearAnimation(){delete this.animation}destroy(){this.clearListeners(),this.stop(),this.stopPassiveEffect&&this.stopPassiveEffect()}}function f(t,e){return new p(t,e)}function m(t){let e;return()=>(void 0===e&&(e=t()),e)}const g=m((()=>void 0!==window.ScrollTimeline));class y{constructor(t){this.stop=()=>this.runAll("stop"),this.animations=t.filter(Boolean)}then(t,e){return Promise.all(this.animations).then(t).catch(e)}getAll(t){return this.animations[0][t]}setAll(t,e){for(let n=0;ng()&&n.attachTimeline?n.attachTimeline(t):e(n)));return()=>{n.forEach(((t,e)=>{t&&t(),this.animations[e].stop()}))}}get time(){return this.getAll("time")}set time(t){this.setAll("time",t)}get speed(){return this.getAll("speed")}set speed(t){this.setAll("speed",t)}get startTime(){return this.getAll("startTime")}get duration(){let t=0;for(let e=0;ee[t]()))}flatten(){this.runAll("flatten")}play(){this.runAll("play")}pause(){this.runAll("pause")}cancel(){this.runAll("cancel")}complete(){this.runAll("complete")}}const v=t=>1e3*t,w=t=>t/1e3;function b(t,e,s){const i=Math.max(e-5,0);return n(s-t(i),e-i)}let T=i,x=i;const S=(t,e,n)=>n>e?e:n{const s=e*o,i=s*t,r=s-n,a=P(e,o),l=Math.exp(-i);return V-r/a*l},r=e=>{const s=e*o*t,r=s*n+n,a=Math.pow(o,2)*Math.pow(e,2)*t,l=Math.exp(-s),u=P(Math.pow(e,2),o);return(-i(e)+V>0?-1:1)*((r-a)*l)/u}):(i=e=>Math.exp(-e*t)*((e-n)*t+1)-.001,r=e=>Math.exp(-e*t)*(t*t*(n-e)));const a=function(t,e,n){let s=n;for(let n=1;nvoid 0!==t[e]))}function E({keyframes:t,restDelta:e,restSpeed:n,...s}){const i=t[0],r=t[t.length-1],o={done:!1,value:i},{stiffness:a,damping:l,mass:u,duration:c,velocity:h,isResolvedFromDuration:d}=function(t){let e={velocity:0,stiffness:100,damping:10,mass:1,isResolvedFromDuration:!1,...t};if(!C(t,F)&&C(t,k)){const n=A(t);e={...e,...n,mass:1},e.isResolvedFromDuration=!0}return e}({...s,velocity:-w(s.velocity||0)}),p=h||0,f=l/(2*Math.sqrt(a*u)),m=r-i,g=w(Math.sqrt(a/u)),y=Math.abs(m)<5;let T;if(n||(n=y?.01:2),e||(e=y?.005:.5),f<1){const t=P(g,f);T=e=>{const n=Math.exp(-f*g*e);return r-n*((p+f*g*m)/t*Math.sin(t*e)+m*Math.cos(t*e))}}else if(1===f)T=t=>r-Math.exp(-g*t)*(m+(p+g*m)*t);else{const t=g*Math.sqrt(f*f-1);T=e=>{const n=Math.exp(-f*g*e),s=Math.min(t*e,300);return r-n*((p+f*g*m)*Math.sinh(s)+t*m*Math.cosh(s))/t}}return{calculatedDuration:d&&c||null,next:t=>{const s=T(t);if(d)o.done=t>=c;else{let i=0;f<1&&(i=0===t?v(p):b(T,t,s));const a=Math.abs(i)<=n,l=Math.abs(r-s)<=e;o.done=a&&l}return o.value=o.done?r:s,o}}}const O=2e4;function R(t){let e=0;let n=t.next(e);for(;!n.done&&e=O?1/0:e}function B(t,e=100,n){const s=n({...t,keyframes:[0,e]}),i=Math.min(R(s),O);return{type:"keyframes",ease:t=>s.next(i*t).value/e,duration:w(i)}}const I=(t,e,n)=>t+(e-t)*n,L=(t,e,n)=>{const s=e-t;return 0===s?1:(n-t)/s};function W(t,e){const n=t[t.length-1];for(let s=1;s<=e;s++){const i=L(0,e,s);t.push(I(n,1,i))}}function D(t){const e=[0];return W(e,t.length-1),e}const N=t=>Boolean(t&&t.getVelocity);function K(t,e,n){var s;if("string"==typeof t){let i=document;e&&(x(Boolean(e.current)),i=e.current),n?(null!==(s=n[t])&&void 0!==s||(n[t]=i.querySelectorAll(t)),t=n[t]):t=i.querySelectorAll(t)}else t instanceof Element&&(t=[t]);return Array.from(t||[])}function $(t){return"object"==typeof t&&!Array.isArray(t)}function j(t,e,n,s){return"string"==typeof t&&$(e)?K(t,n,s):t instanceof NodeList?Array.from(t):Array.isArray(t)?t:[t]}function z(t){return"function"==typeof t}function H(t,e,n,s){var i;return"number"==typeof e?e:e.startsWith("-")||e.startsWith("+")?Math.max(0,t+parseFloat(e)):"<"===e?n:null!==(i=s.get(e))&&void 0!==i?i:t}const U=(t,e,n)=>{const s=e-t;return((n-t)%s+s)%s+t},Y=t=>Array.isArray(t)&&"number"!=typeof t[0];function q(t,e){return Y(t)?t[U(0,t.length,e)]:t}function X(e,n,s,i,r,o){!function(e,n,s){for(let i=0;in&&r.at"number"==typeof t,et=t=>t.every(tt),nt=new WeakMap,st=["transformPerspective","x","y","z","translateX","translateY","translateZ","scale","scaleX","scaleY","rotate","rotateX","rotateY","rotateZ","skew","skewX","skewY"],it=new Set(st),rt={type:"spring",stiffness:500,damping:25,restSpeed:10},ot={type:"keyframes",duration:.8},at={type:"keyframes",ease:[.25,.1,.35,1],duration:.3},lt=(t,{keyframes:e})=>e.length>2?ot:it.has(t)?t.startsWith("scale")?{type:"spring",stiffness:550,damping:0===e[1]?2*Math.sqrt(550):30,restSpeed:10}:rt:at;function ut(t,e){return t?t[e]||t.default||t:void 0}const ct=t=>null!==t;function ht(t,{repeat:e,repeatType:n="loop"},s){const i=t.filter(ct),r=e&&"loop"!==n&&e%2==1?0:i.length-1;return r&&void 0!==s?s:i[r]}const dt=(t,e,n)=>(((1-3*n+3*e)*t+(3*n-6*e))*t+3*e)*t;function pt(t,e,n,s){if(t===e&&n===s)return i;const r=e=>function(t,e,n,s,i){let r,o,a=0;do{o=e+(n-e)/2,r=dt(o,s,i)-t,r>0?n=o:e=o}while(Math.abs(r)>1e-7&&++a<12);return o}(e,0,1,t,n);return t=>0===t||1===t?t:dt(r(t),e,s)}const ft=t=>e=>e<=.5?t(2*e)/2:(2-t(2*(1-e)))/2,mt=t=>e=>1-t(1-e),gt=pt(.33,1.53,.69,.99),yt=mt(gt),vt=ft(yt),wt=t=>(t*=2)<1?.5*yt(t):.5*(2-Math.pow(2,-10*(t-1))),bt=t=>1-Math.sin(Math.acos(t)),Tt=mt(bt),xt=ft(bt),St=t=>/^0[^.\s]+$/u.test(t);const Vt=t=>/^-?(?:\d+(?:\.\d+)?|\.\d+)$/u.test(t),At=t=>e=>"string"==typeof e&&e.startsWith(t),Mt=At("--"),Pt=At("var(--"),kt=t=>!!Pt(t)&&Ft.test(t.split("/*")[0].trim()),Ft=/var\(--(?:[\w-]+\s*|[\w-]+\s*,(?:\s*[^)(\s]|\s*\((?:[^)(]|\([^)(]*\))*\))+\s*)\)$/iu,Ct=/^var\(--(?:([\w-]+)|([\w-]+), ?([a-zA-Z\d ()%#.,-]+))\)/u;function Et(t,e,n=1){const[s,i]=function(t){const e=Ct.exec(t);if(!e)return[,];const[,n,s,i]=e;return[`--${null!=n?n:s}`,i]}(t);if(!s)return;const r=window.getComputedStyle(e).getPropertyValue(s);if(r){const t=r.trim();return Vt(t)?parseFloat(t):t}return kt(i)?Et(i,e,n+1):i}const Ot={test:t=>"number"==typeof t,parse:parseFloat,transform:t=>t},Rt={...Ot,transform:t=>S(0,1,t)},Bt={...Ot,default:1},It=t=>({test:e=>"string"==typeof e&&e.endsWith(t)&&1===e.split(" ").length,parse:parseFloat,transform:e=>`${e}${t}`}),Lt=It("deg"),Wt=It("%"),Dt=It("px"),Nt=It("vh"),Kt=It("vw"),$t={...Wt,parse:t=>Wt.parse(t)/100,transform:t=>Wt.transform(100*t)},jt=new Set(["width","height","top","left","right","bottom","x","y","translateX","translateY"]),zt=t=>t===Ot||t===Dt,Ht=(t,e)=>parseFloat(t.split(", ")[e]),Ut=(t,e)=>(n,{transform:s})=>{if("none"===s||!s)return 0;const i=s.match(/^matrix3d\((.+)\)$/u);if(i)return Ht(i[1],e);{const e=s.match(/^matrix\((.+)\)$/u);return e?Ht(e[1],t):0}},Yt=new Set(["x","y","z"]),qt=st.filter((t=>!Yt.has(t)));const Xt={width:({x:t},{paddingLeft:e="0",paddingRight:n="0"})=>t.max-t.min-parseFloat(e)-parseFloat(n),height:({y:t},{paddingTop:e="0",paddingBottom:n="0"})=>t.max-t.min-parseFloat(e)-parseFloat(n),top:(t,{top:e})=>parseFloat(e),left:(t,{left:e})=>parseFloat(e),bottom:({y:t},{top:e})=>parseFloat(e)+(t.max-t.min),right:({x:t},{left:e})=>parseFloat(e)+(t.max-t.min),x:Ut(4,13),y:Ut(5,14)};Xt.translateX=Xt.x,Xt.translateY=Xt.y;const Gt=t=>e=>e.test(t),Zt=[Ot,Dt,Wt,Lt,Kt,Nt,{test:t=>"auto"===t,parse:t=>t}],_t=t=>Zt.find(Gt(t)),Jt=new Set;let Qt=!1,te=!1;function ee(){if(te){const t=Array.from(Jt).filter((t=>t.needsMeasurement)),e=new Set(t.map((t=>t.element))),n=new Map;e.forEach((t=>{const e=function(t){const e=[];return qt.forEach((n=>{const s=t.getValue(n);void 0!==s&&(e.push([n,s.get()]),s.set(n.startsWith("scale")?1:0))})),e}(t);e.length&&(n.set(t,e),t.render())})),t.forEach((t=>t.measureInitialState())),e.forEach((t=>{t.render();const e=n.get(t);e&&e.forEach((([e,n])=>{var s;null===(s=t.getValue(e))||void 0===s||s.set(n)}))})),t.forEach((t=>t.measureEndState())),t.forEach((t=>{void 0!==t.suspendedScrollY&&window.scrollTo(0,t.suspendedScrollY)}))}te=!1,Qt=!1,Jt.forEach((t=>t.complete())),Jt.clear()}function ne(){Jt.forEach((t=>{t.readKeyframes(),t.needsMeasurement&&(te=!0)}))}class se{constructor(t,e,n,s,i,r=!1){this.isComplete=!1,this.isAsync=!1,this.needsMeasurement=!1,this.isScheduled=!1,this.unresolvedKeyframes=[...t],this.onComplete=e,this.name=n,this.motionValue=s,this.element=i,this.isAsync=r}scheduleResolve(){this.isScheduled=!0,this.isAsync?(Jt.add(this),Qt||(Qt=!0,o.read(ne),o.resolveKeyframes(ee))):(this.readKeyframes(),this.complete())}readKeyframes(){const{unresolvedKeyframes:t,name:e,element:n,motionValue:s}=this;for(let i=0;iMath.round(1e5*t)/1e5,re=/-?(?:\d+(?:\.\d+)?|\.\d+)/gu;const oe=/^(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\))$/iu,ae=(t,e)=>n=>Boolean("string"==typeof n&&oe.test(n)&&n.startsWith(t)||e&&!function(t){return null==t}(n)&&Object.prototype.hasOwnProperty.call(n,e)),le=(t,e,n)=>s=>{if("string"!=typeof s)return s;const[i,r,o,a]=s.match(re);return{[t]:parseFloat(i),[e]:parseFloat(r),[n]:parseFloat(o),alpha:void 0!==a?parseFloat(a):1}},ue={...Ot,transform:t=>Math.round((t=>S(0,255,t))(t))},ce={test:ae("rgb","red"),parse:le("red","green","blue"),transform:({red:t,green:e,blue:n,alpha:s=1})=>"rgba("+ue.transform(t)+", "+ue.transform(e)+", "+ue.transform(n)+", "+ie(Rt.transform(s))+")"};const he={test:ae("#"),parse:function(t){let e="",n="",s="",i="";return t.length>5?(e=t.substring(1,3),n=t.substring(3,5),s=t.substring(5,7),i=t.substring(7,9)):(e=t.substring(1,2),n=t.substring(2,3),s=t.substring(3,4),i=t.substring(4,5),e+=e,n+=n,s+=s,i+=i),{red:parseInt(e,16),green:parseInt(n,16),blue:parseInt(s,16),alpha:i?parseInt(i,16)/255:1}},transform:ce.transform},de={test:ae("hsl","hue"),parse:le("hue","saturation","lightness"),transform:({hue:t,saturation:e,lightness:n,alpha:s=1})=>"hsla("+Math.round(t)+", "+Wt.transform(ie(e))+", "+Wt.transform(ie(n))+", "+ie(Rt.transform(s))+")"},pe={test:t=>ce.test(t)||he.test(t)||de.test(t),parse:t=>ce.test(t)?ce.parse(t):de.test(t)?de.parse(t):he.parse(t),transform:t=>"string"==typeof t?t:t.hasOwnProperty("red")?ce.transform(t):de.transform(t)},fe=/(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\))/giu;const me="number",ge="color",ye=/var\s*\(\s*--(?:[\w-]+\s*|[\w-]+\s*,(?:\s*[^)(\s]|\s*\((?:[^)(]|\([^)(]*\))*\))+\s*)\)|#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\)|-?(?:\d+(?:\.\d+)?|\.\d+)/giu;function ve(t){const e=t.toString(),n=[],s={color:[],number:[],var:[]},i=[];let r=0;const o=e.replace(ye,(t=>(pe.test(t)?(s.color.push(r),i.push(ge),n.push(pe.parse(t))):t.startsWith("var(")?(s.var.push(r),i.push("var"),n.push(t)):(s.number.push(r),i.push(me),n.push(parseFloat(t))),++r,"${}"))).split("${}");return{values:n,split:o,indexes:s,types:i}}function we(t){return ve(t).values}function be(t){const{split:e,types:n}=ve(t),s=e.length;return t=>{let i="";for(let r=0;r"number"==typeof t?0:t;const xe={test:function(t){var e,n;return isNaN(t)&&"string"==typeof t&&((null===(e=t.match(re))||void 0===e?void 0:e.length)||0)+((null===(n=t.match(fe))||void 0===n?void 0:n.length)||0)>0},parse:we,createTransformer:be,getAnimatableNone:function(t){const e=we(t);return be(t)(e.map(Te))}},Se=new Set(["brightness","contrast","saturate","opacity"]);function Ve(t){const[e,n]=t.slice(0,-1).split("(");if("drop-shadow"===e)return t;const[s]=n.match(re)||[];if(!s)return t;const i=n.replace(s,"");let r=Se.has(e)?1:0;return s!==n&&(r*=100),e+"("+r+i+")"}const Ae=/\b([a-z-]*)\(.*?\)/gu,Me={...xe,getAnimatableNone:t=>{const e=t.match(Ae);return e?e.map(Ve).join(" "):t}},Pe={borderWidth:Dt,borderTopWidth:Dt,borderRightWidth:Dt,borderBottomWidth:Dt,borderLeftWidth:Dt,borderRadius:Dt,radius:Dt,borderTopLeftRadius:Dt,borderTopRightRadius:Dt,borderBottomRightRadius:Dt,borderBottomLeftRadius:Dt,width:Dt,maxWidth:Dt,height:Dt,maxHeight:Dt,top:Dt,right:Dt,bottom:Dt,left:Dt,padding:Dt,paddingTop:Dt,paddingRight:Dt,paddingBottom:Dt,paddingLeft:Dt,margin:Dt,marginTop:Dt,marginRight:Dt,marginBottom:Dt,marginLeft:Dt,backgroundPositionX:Dt,backgroundPositionY:Dt},ke={rotate:Lt,rotateX:Lt,rotateY:Lt,rotateZ:Lt,scale:Bt,scaleX:Bt,scaleY:Bt,scaleZ:Bt,skew:Lt,skewX:Lt,skewY:Lt,distance:Dt,translateX:Dt,translateY:Dt,translateZ:Dt,x:Dt,y:Dt,z:Dt,perspective:Dt,transformPerspective:Dt,opacity:Rt,originX:$t,originY:$t,originZ:Dt},Fe={...Ot,transform:Math.round},Ce={...Pe,...ke,zIndex:Fe,size:Dt,fillOpacity:Rt,strokeOpacity:Rt,numOctaves:Fe},Ee={...Ce,color:pe,backgroundColor:pe,outlineColor:pe,fill:pe,stroke:pe,borderColor:pe,borderTopColor:pe,borderRightColor:pe,borderBottomColor:pe,borderLeftColor:pe,filter:Me,WebkitFilter:Me},Oe=t=>Ee[t];function Re(t,e){let n=Oe(t);return n!==Me&&(n=xe),n.getAnimatableNone?n.getAnimatableNone(e):void 0}const Be=new Set(["auto","none","0"]);class Ie extends se{constructor(t,e,n,s,i){super(t,e,n,s,i,!0)}readKeyframes(){const{unresolvedKeyframes:t,element:e,name:n}=this;if(!e||!e.current)return;super.readKeyframes();for(let n=0;n{e.getValue(t).set(n)})),this.resolveNoneKeyframes()}}const Le=(t,e)=>"zIndex"!==e&&(!("number"!=typeof t&&!Array.isArray(t))||!("string"!=typeof t||!xe.test(t)&&"0"!==t||t.startsWith("url(")));function We(t,e,n,s){const i=t[0];if(null===i)return!1;if("display"===e||"visibility"===e)return!0;const r=t[t.length-1],o=Le(i,e),a=Le(r,e);return!(!o||!a)&&(function(t){const e=t[0];if(1===t.length)return!0;for(let n=0;n40?this.resolvedAt:this.createdAt}get resolved(){return this._resolved||this.hasAttemptedResolve||(ne(),ee()),this._resolved}onKeyframesResolved(t,e){this.resolvedAt=d.now(),this.hasAttemptedResolve=!0;const{name:n,type:s,velocity:i,delay:r,onComplete:o,onUpdate:a,isGenerator:l}=this.options;if(!l&&!We(t,n,s,i)){if(!r)return null==a||a(ht(t,this.options,e)),null==o||o(),void this.resolveFinishedPromise();this.options.duration=0}const u=this.initPlayback(t,e);!1!==u&&(this._resolved={keyframes:t,finalKeyframe:e,...u},this.onPostResolved())}onPostResolved(){}then(t,e){return this.currentFinishedPromise.then(t,e)}flatten(){this.options.type="keyframes",this.options.ease="linear"}updateFinishedPromise(){this.currentFinishedPromise=new Promise((t=>{this.resolveFinishedPromise=t}))}}function Ne({keyframes:t,velocity:e=0,power:n=.8,timeConstant:s=325,bounceDamping:i=10,bounceStiffness:r=500,modifyTarget:o,min:a,max:l,restDelta:u=.5,restSpeed:c}){const h=t[0],d={done:!1,value:h},p=t=>void 0===a?l:void 0===l||Math.abs(a-t)-f*Math.exp(-t/s),v=t=>g+y(t),w=t=>{const e=y(t),n=v(t);d.done=Math.abs(e)<=u,d.value=d.done?g:n};let T,x;const S=t=>{var e;(e=d.value,void 0!==a&&el)&&(T=t,x=E({keyframes:[d.value,p(d.value)],velocity:b(v,t,d.value),damping:i,stiffness:r,restDelta:u,restSpeed:c}))};return S(0),{calculatedDuration:null,next:t=>{let e=!1;return x||void 0!==T||(e=!0,w(t),S(t)),void 0!==T&&t>=T?x.next(t-T):(!e&&w(t),d)}}}const Ke=pt(.42,0,1,1),$e=pt(0,0,.58,1),je=pt(.42,0,.58,1),ze=t=>Array.isArray(t)&&"number"==typeof t[0],He={linear:i,easeIn:Ke,easeInOut:je,easeOut:$e,circIn:bt,circInOut:xt,circOut:Tt,backIn:yt,backInOut:vt,backOut:gt,anticipate:wt},Ue=t=>{if(ze(t)){x(4===t.length);const[e,n,s,i]=t;return pt(e,n,s,i)}return"string"==typeof t?He[t]:t},Ye=(t,e)=>n=>e(t(n)),qe=(...t)=>t.reduce(Ye);function Xe(t,e,n){return n<0&&(n+=1),n>1&&(n-=1),n<1/6?t+6*(e-t)*n:n<.5?e:n<2/3?t+(e-t)*(2/3-n)*6:t}function Ge(t,e){return n=>n>0?e:t}const Ze=(t,e,n)=>{const s=t*t,i=n*(e*e-s)+s;return i<0?0:Math.sqrt(i)},_e=[he,ce,de];function Je(t){const e=(n=t,_e.find((t=>t.test(n))));var n;if(!Boolean(e))return!1;let s=e.parse(t);return e===de&&(s=function({hue:t,saturation:e,lightness:n,alpha:s}){t/=360,n/=100;let i=0,r=0,o=0;if(e/=100){const s=n<.5?n*(1+e):n+e-n*e,a=2*n-s;i=Xe(a,s,t+1/3),r=Xe(a,s,t),o=Xe(a,s,t-1/3)}else i=r=o=n;return{red:Math.round(255*i),green:Math.round(255*r),blue:Math.round(255*o),alpha:s}}(s)),s}const Qe=(t,e)=>{const n=Je(t),s=Je(e);if(!n||!s)return Ge(t,e);const i={...n};return t=>(i.red=Ze(n.red,s.red,t),i.green=Ze(n.green,s.green,t),i.blue=Ze(n.blue,s.blue,t),i.alpha=I(n.alpha,s.alpha,t),ce.transform(i))},tn=new Set(["none","hidden"]);function en(t,e){return n=>I(t,e,n)}function nn(t){return"number"==typeof t?en:"string"==typeof t?kt(t)?Ge:pe.test(t)?Qe:on:Array.isArray(t)?sn:"object"==typeof t?pe.test(t)?Qe:rn:Ge}function sn(t,e){const n=[...t],s=n.length,i=t.map(((t,n)=>nn(t)(t,e[n])));return t=>{for(let e=0;e{for(const e in s)n[e]=s[e](t);return n}}const on=(t,e)=>{const n=xe.createTransformer(e),s=ve(t),i=ve(e);return s.indexes.var.length===i.indexes.var.length&&s.indexes.color.length===i.indexes.color.length&&s.indexes.number.length>=i.indexes.number.length?tn.has(t)&&!i.values.length||tn.has(e)&&!s.values.length?function(t,e){return tn.has(t)?n=>n<=0?t:e:n=>n>=1?e:t}(t,e):qe(sn(function(t,e){var n;const s=[],i={color:0,var:0,number:0};for(let r=0;re[0];if(2===o&&t[0]===t[1])return()=>e[1];t[0]>t[o-1]&&(t=[...t].reverse(),e=[...e].reverse());const a=function(t,e,n){const s=[],r=n||an,o=t.length-1;for(let n=0;n{let n=0;if(l>1)for(;nu(S(t[0],t[o-1],e)):u}function un({duration:t=300,keyframes:e,times:n,ease:s="easeInOut"}){const i=Y(s)?s.map(Ue):Ue(s),r={done:!1,value:e[0]},o=function(t,e){return t.map((t=>t*e))}(n&&n.length===e.length?n:D(e),t),a=ln(o,e,{ease:Array.isArray(i)?i:(l=e,u=i,l.map((()=>u||je)).splice(0,l.length-1))});var l,u;return{calculatedDuration:t,next:e=>(r.value=a(e),r.done=e>=t,r)}}const cn=t=>{const e=({timestamp:e})=>t(e);return{start:()=>o.update(e,!0),stop:()=>a(e),now:()=>l.isProcessing?l.timestamp:d.now()}},hn={decay:Ne,inertia:Ne,tween:un,keyframes:un,spring:E},dn=t=>t/100;class pn extends De{constructor(t){super(t),this.holdTime=null,this.cancelTime=null,this.currentTime=0,this.playbackSpeed=1,this.pendingPlayState="running",this.startTime=null,this.state="idle",this.stop=()=>{if(this.resolver.cancel(),this.isStopped=!0,"idle"===this.state)return;this.teardown();const{onStop:t}=this.options;t&&t()};const{name:e,motionValue:n,element:s,keyframes:i}=this.options,r=(null==s?void 0:s.KeyframeResolver)||se;this.resolver=new r(i,((t,e)=>this.onKeyframesResolved(t,e)),e,n,s),this.resolver.scheduleResolve()}flatten(){super.flatten(),this._resolved&&Object.assign(this._resolved,this.initPlayback(this._resolved.keyframes))}initPlayback(t){const{type:e="keyframes",repeat:n=0,repeatDelay:s=0,repeatType:i,velocity:r=0}=this.options,o=z(e)?e:hn[e]||un;let a,l;o!==un&&"number"!=typeof t[0]&&(a=qe(dn,an(t[0],t[1])),t=[0,100]);const u=o({...this.options,keyframes:t});"mirror"===i&&(l=o({...this.options,keyframes:[...t].reverse(),velocity:-r})),null===u.calculatedDuration&&(u.calculatedDuration=R(u));const{calculatedDuration:c}=u,h=c+s;return{generator:u,mirroredGenerator:l,mapPercentToKeyframes:a,calculatedDuration:c,resolvedDuration:h,totalDuration:h*(n+1)-s}}onPostResolved(){const{autoplay:t=!0}=this.options;this.play(),"paused"!==this.pendingPlayState&&t?this.state=this.pendingPlayState:this.pause()}tick(t,e=!1){const{resolved:n}=this;if(!n){const{keyframes:t}=this.options;return{done:!0,value:t[t.length-1]}}const{finalKeyframe:s,generator:i,mirroredGenerator:r,mapPercentToKeyframes:o,keyframes:a,calculatedDuration:l,totalDuration:u,resolvedDuration:c}=n;if(null===this.startTime)return i.next(0);const{delay:h,repeat:d,repeatType:p,repeatDelay:f,onUpdate:m}=this.options;this.speed>0?this.startTime=Math.min(this.startTime,t):this.speed<0&&(this.startTime=Math.min(t-u/this.speed,this.startTime)),e?this.currentTime=t:null!==this.holdTime?this.currentTime=this.holdTime:this.currentTime=Math.round(t-this.startTime)*this.speed;const g=this.currentTime-h*(this.speed>=0?1:-1),y=this.speed>=0?g<0:g>u;this.currentTime=Math.max(g,0),"finished"===this.state&&null===this.holdTime&&(this.currentTime=u);let v=this.currentTime,w=i;if(d){const t=Math.min(this.currentTime,u)/c;let e=Math.floor(t),n=t%1;!n&&t>=1&&(n=1),1===n&&e--,e=Math.min(e,d+1);Boolean(e%2)&&("reverse"===p?(n=1-n,f&&(n-=f/c)):"mirror"===p&&(w=r)),v=S(0,1,n)*c}const b=y?{done:!1,value:a[0]}:w.next(v);o&&(b.value=o(b.value));let{done:T}=b;y||null===l||(T=this.speed>=0?this.currentTime>=u:this.currentTime<=0);const x=null===this.holdTime&&("finished"===this.state||"running"===this.state&&T);return x&&void 0!==s&&(b.value=ht(a,this.options,s)),m&&m(b.value),x&&this.finish(),b}get duration(){const{resolved:t}=this;return t?w(t.calculatedDuration):0}get time(){return w(this.currentTime)}set time(t){t=v(t),this.currentTime=t,null!==this.holdTime||0===this.speed?this.holdTime=t:this.driver&&(this.startTime=this.driver.now()-t/this.speed)}get speed(){return this.playbackSpeed}set speed(t){const e=this.playbackSpeed!==t;this.playbackSpeed=t,e&&(this.time=w(this.currentTime))}play(){if(this.resolver.isScheduled||this.resolver.resume(),!this._resolved)return void(this.pendingPlayState="running");if(this.isStopped)return;const{driver:t=cn,onPlay:e,startTime:n}=this.options;this.driver||(this.driver=t((t=>this.tick(t)))),e&&e();const s=this.driver.now();null!==this.holdTime?this.startTime=s-this.holdTime:this.startTime?"finished"===this.state&&(this.startTime=s):this.startTime=null!=n?n:this.calcStartTime(),"finished"===this.state&&this.updateFinishedPromise(),this.cancelTime=this.startTime,this.holdTime=null,this.state="running",this.driver.start()}pause(){var t;this._resolved?(this.state="paused",this.holdTime=null!==(t=this.currentTime)&&void 0!==t?t:0):this.pendingPlayState="paused"}complete(){"running"!==this.state&&this.play(),this.pendingPlayState=this.state="finished",this.holdTime=null}finish(){this.teardown(),this.state="finished";const{onComplete:t}=this.options;t&&t()}cancel(){null!==this.cancelTime&&this.tick(this.cancelTime),this.teardown(),this.updateFinishedPromise()}teardown(){this.state="idle",this.stopDriver(),this.resolveFinishedPromise(),this.updateFinishedPromise(),this.startTime=this.cancelTime=null,this.resolver.cancel()}stopDriver(){this.driver&&(this.driver.stop(),this.driver=void 0)}sample(t){return this.startTime=0,this.tick(t,!0)}}const fn=new Set(["opacity","clipPath","filter","transform"]),mn={linearEasing:void 0};function gn(t,e){const n=m(t);return()=>{var t;return null!==(t=mn[e])&&void 0!==t?t:n()}}const yn=gn((()=>{try{document.createElement("div").animate({opacity:0},{easing:"linear(0, 1)"})}catch(t){return!1}return!0}),"linearEasing");function vn(t){return Boolean("function"==typeof t&&yn()||!t||"string"==typeof t&&(t in bn||yn())||ze(t)||Array.isArray(t)&&t.every(vn))}const wn=([t,e,n,s])=>`cubic-bezier(${t}, ${e}, ${n}, ${s})`,bn={linear:"linear",ease:"ease",easeIn:"ease-in",easeOut:"ease-out",easeInOut:"ease-in-out",circIn:wn([0,.65,.55,1]),circOut:wn([.55,0,1,.45]),backIn:wn([.31,.01,.66,-.59]),backOut:wn([.33,1.53,.69,.99])};function Tn(t,e){return t?"function"==typeof t&&yn()?((t,e)=>{let n="";const s=Math.max(Math.round(e/10),2);for(let e=0;eTn(t,e)||bn.easeOut)):bn[t]:void 0}function xn(t,e,n,{delay:s=0,duration:i=300,repeat:r=0,repeatType:o="loop",ease:a="easeInOut",times:l}={}){const u={[e]:n};l&&(u.offset=l);const c=Tn(a,i);return Array.isArray(c)&&(u.easing=c),t.animate(u,{delay:s,duration:i,easing:Array.isArray(c)?"linear":c,fill:"both",iterations:r+1,direction:"reverse"===o?"alternate":"normal"})}function Sn(t,e){t.timeline=e,t.onfinish=null}const Vn=m((()=>Object.hasOwnProperty.call(Element.prototype,"animate")));const An={anticipate:wt,backInOut:vt,circInOut:xt};class Mn extends De{constructor(t){super(t);const{name:e,motionValue:n,element:s,keyframes:i}=this.options;this.resolver=new Ie(i,((t,e)=>this.onKeyframesResolved(t,e)),e,n,s),this.resolver.scheduleResolve()}initPlayback(t,e){var n;let{duration:s=300,times:i,ease:r,type:o,motionValue:a,name:l,startTime:u}=this.options;if(!(null===(n=a.owner)||void 0===n?void 0:n.current))return!1;var c;if("string"==typeof r&&yn()&&r in An&&(r=An[r]),z((c=this.options).type)||"spring"===c.type||!vn(c.ease)){const{onComplete:e,onUpdate:n,motionValue:a,element:l,...u}=this.options,c=function(t,e){const n=new pn({...e,keyframes:t,repeat:0,delay:0,isGenerator:!0});let s={done:!1,value:t[0]};const i=[];let r=0;for(;!s.done&&r<2e4;)s=n.sample(r),i.push(s.value),r+=10;return{times:void 0,keyframes:i,duration:r-10,ease:"linear"}}(t,u);1===(t=c.keyframes).length&&(t[1]=t[0]),s=c.duration,i=c.times,r=c.ease,o="keyframes"}const h=xn(a.owner.current,l,t,{...this.options,duration:s,times:i,ease:r});return h.startTime=null!=u?u:this.calcStartTime(),this.pendingTimeline?(Sn(h,this.pendingTimeline),this.pendingTimeline=void 0):h.onfinish=()=>{const{onComplete:n}=this.options;a.set(ht(t,this.options,e)),n&&n(),this.cancel(),this.resolveFinishedPromise()},{animation:h,duration:s,times:i,type:o,ease:r,keyframes:t}}get duration(){const{resolved:t}=this;if(!t)return 0;const{duration:e}=t;return w(e)}get time(){const{resolved:t}=this;if(!t)return 0;const{animation:e}=t;return w(e.currentTime||0)}set time(t){const{resolved:e}=this;if(!e)return;const{animation:n}=e;n.currentTime=v(t)}get speed(){const{resolved:t}=this;if(!t)return 1;const{animation:e}=t;return e.playbackRate}set speed(t){const{resolved:e}=this;if(!e)return;const{animation:n}=e;n.playbackRate=t}get state(){const{resolved:t}=this;if(!t)return"idle";const{animation:e}=t;return e.playState}get startTime(){const{resolved:t}=this;if(!t)return null;const{animation:e}=t;return e.startTime}attachTimeline(t){if(this._resolved){const{resolved:e}=this;if(!e)return i;const{animation:n}=e;Sn(n,t)}else this.pendingTimeline=t;return i}play(){if(this.isStopped)return;const{resolved:t}=this;if(!t)return;const{animation:e}=t;"finished"===e.playState&&this.updateFinishedPromise(),e.play()}pause(){const{resolved:t}=this;if(!t)return;const{animation:e}=t;e.pause()}stop(){if(this.resolver.cancel(),this.isStopped=!0,"idle"===this.state)return;this.resolveFinishedPromise(),this.updateFinishedPromise();const{resolved:t}=this;if(!t)return;const{animation:e,keyframes:n,duration:s,type:i,ease:r,times:o}=t;if("idle"===e.playState||"finished"===e.playState)return;if(this.time){const{motionValue:t,onUpdate:e,onComplete:a,element:l,...u}=this.options,c=new pn({...u,keyframes:n,duration:s,type:i,ease:r,times:o,isGenerator:!0}),h=v(this.time);t.setWithVelocity(c.sample(h-10).value,c.sample(h).value,10)}const{onStop:a}=this.options;a&&a(),this.cancel()}complete(){const{resolved:t}=this;t&&t.animation.finish()}cancel(){const{resolved:t}=this;t&&t.animation.cancel()}static supports(t){const{motionValue:e,name:n,repeatDelay:s,repeatType:i,damping:r,type:o}=t;return Vn()&&n&&fn.has(n)&&e&&e.owner&&e.owner.current instanceof HTMLElement&&!e.owner.getProps().onUpdate&&!s&&"mirror"!==i&&0!==r&&"inertia"!==o}}const Pn=(t,e,n,s={},i,r)=>a=>{const l=ut(s,t)||{},u=l.delay||s.delay||0;let{elapsed:c=0}=s;c-=v(u);let h={keyframes:Array.isArray(n)?n:[null,n],ease:"easeOut",velocity:e.getVelocity(),...l,delay:-c,onUpdate:t=>{e.set(t),l.onUpdate&&l.onUpdate(t)},onComplete:()=>{a(),l.onComplete&&l.onComplete()},name:t,motionValue:e,element:r?void 0:i};(function({when:t,delay:e,delayChildren:n,staggerChildren:s,staggerDirection:i,repeat:r,repeatType:o,repeatDelay:a,from:l,elapsed:u,...c}){return!!Object.keys(c).length})(l)||(h={...h,...lt(t,h)}),h.duration&&(h.duration=v(h.duration)),h.repeatDelay&&(h.repeatDelay=v(h.repeatDelay)),void 0!==h.from&&(h.keyframes[0]=h.from);let d=!1;if((!1===h.type||0===h.duration&&!h.repeatDelay)&&(h.duration=0,0===h.delay&&(d=!0)),d&&!r&&void 0!==e.get()){const t=ht(h.keyframes,l);if(void 0!==t)return o.update((()=>{h.onUpdate(t),h.onComplete()})),new y([])}return!r&&Mn.supports(h)?new Mn(h):new pn(h)},kn=t=>(t=>Array.isArray(t))(t)?t[t.length-1]||0:t;function Fn(t){const e=[{},{}];return null==t||t.values.forEach(((t,n)=>{e[0][n]=t.get(),e[1][n]=t.getVelocity()})),e}function Cn(t,e,n,s){if("function"==typeof e){const[i,r]=Fn(s);e=e(void 0!==n?n:t.custom,i,r)}if("string"==typeof e&&(e=t.variants&&t.variants[e]),"function"==typeof e){const[i,r]=Fn(s);e=e(void 0!==n?n:t.custom,i,r)}return e}function En(t,e,n){t.hasValue(e)?t.getValue(e).set(n):t.addValue(e,f(n))}function On(t,e){const n=function(t,e,n){const s=t.getProps();return Cn(s,e,void 0!==n?n:s.custom,t)}(t,e);let{transitionEnd:s={},transition:i={},...r}=n||{};r={...r,...s};for(const e in r){En(t,e,kn(r[e]))}}const Rn=t=>t.replace(/([a-z])([A-Z])/gu,"$1-$2").toLowerCase(),Bn="data-"+Rn("framerAppearId");function In(t){return t.props[Bn]}function Ln(t,e){const n=t.getValue("willChange");if(s=n,Boolean(N(s)&&s.add))return n.add(e);var s}function Wn({protectedKeys:t,needsAnimating:e},n){const s=t.hasOwnProperty(n)&&!0!==e[n];return e[n]=!1,s}function Dn(t,e,{delay:n=0,transitionOverride:s,type:i}={}){var r;let{transition:a=t.getDefaultTransition(),transitionEnd:l,...u}=e;s&&(a=s);const c=[],h=i&&t.animationState&&t.animationState.getState()[i];for(const e in u){const s=t.getValue(e,null!==(r=t.latestValues[e])&&void 0!==r?r:null),i=u[e];if(void 0===i||h&&Wn(h,e))continue;const l={delay:n,...ut(a||{},e)};let d=!1;if(window.MotionHandoffAnimation){const n=In(t);if(n){const t=window.MotionHandoffAnimation(n,e,o);null!==t&&(l.startTime=t,d=!0)}}Ln(t,e),s.start(Pn(e,s,i,t.shouldReduceMotion&&it.has(e)?{type:!1}:l,t,d));const p=s.animation;p&&c.push(p)}return l&&Promise.all(c).then((()=>{o.update((()=>{l&&On(t,l)}))})),c}const Nn={};function Kn(t,{layout:e,layoutId:n}){return it.has(t)||t.startsWith("origin")||(e||void 0!==n)&&(!!Nn[t]||"opacity"===t)}function $n(t,e,n){var s;const{style:i}=t,r={};for(const o in i)(N(i[o])||e.style&&N(e.style[o])||Kn(o,t)||void 0!==(null===(s=null==n?void 0:n.getValue(o))||void 0===s?void 0:s.liveStyle))&&(r[o]=i[o]);return r}const jn="undefined"!=typeof window,zn={current:null},Hn={current:!1};const Un=["initial","animate","whileInView","whileFocus","whileHover","whileTap","whileDrag","exit"];function Yn(t){return null!==(e=t.animate)&&"object"==typeof e&&"function"==typeof e.start||Un.some((e=>function(t){return"string"==typeof t||Array.isArray(t)}(t[e])));var e}const qn={animation:["animate","variants","whileHover","whileTap","exit","whileInView","whileFocus","whileDrag"],exit:["exit"],drag:["drag","dragControls"],focus:["whileFocus"],hover:["whileHover","onHoverStart","onHoverEnd"],tap:["whileTap","onTap","onTapStart","onTapCancel"],pan:["onPan","onPanStart","onPanSessionStart","onPanEnd"],inView:["whileInView","onViewportEnter","onViewportLeave"],layout:["layout","layoutId"]},Xn={};for(const t in qn)Xn[t]={isEnabled:e=>qn[t].some((t=>!!e[t]))};const Gn=[...Zt,pe,xe],Zn=()=>({x:{min:0,max:0},y:{min:0,max:0}}),_n=["AnimationStart","AnimationComplete","Update","BeforeLayoutMeasure","LayoutMeasure","LayoutAnimationStart","LayoutAnimationComplete"];class Jn{scrapeMotionValuesFromProps(t,e,n){return{}}constructor({parent:t,props:e,presenceContext:n,reducedMotionConfig:s,blockInitialAnimation:i,visualState:r},a={}){this.current=null,this.children=new Set,this.isVariantNode=!1,this.isControllingVariants=!1,this.shouldReduceMotion=null,this.values=new Map,this.KeyframeResolver=se,this.features={},this.valueSubscriptions=new Map,this.prevMotionValues={},this.events={},this.propEventSubscriptions={},this.notifyUpdate=()=>this.notify("Update",this.latestValues),this.render=()=>{this.current&&(this.triggerBuild(),this.renderInstance(this.current,this.renderState,this.props.style,this.projection))},this.renderScheduledAt=0,this.scheduleRender=()=>{const t=d.now();this.renderScheduledAtthis.bindToMotionValue(e,t))),Hn.current||function(){if(Hn.current=!0,jn)if(window.matchMedia){const t=window.matchMedia("(prefers-reduced-motion)"),e=()=>zn.current=t.matches;t.addListener(e),e()}else zn.current=!1}(),this.shouldReduceMotion="never"!==this.reducedMotionConfig&&("always"===this.reducedMotionConfig||zn.current),this.parent&&this.parent.children.add(this),this.update(this.props,this.presenceContext)}unmount(){nt.delete(this.current),this.projection&&this.projection.unmount(),a(this.notifyUpdate),a(this.render),this.valueSubscriptions.forEach((t=>t())),this.valueSubscriptions.clear(),this.removeFromVariantTree&&this.removeFromVariantTree(),this.parent&&this.parent.children.delete(this);for(const t in this.events)this.events[t].clear();for(const t in this.features){const e=this.features[t];e&&(e.unmount(),e.isMounted=!1)}this.current=null}bindToMotionValue(t,e){this.valueSubscriptions.has(t)&&this.valueSubscriptions.get(t)();const n=it.has(t),s=e.on("change",(e=>{this.latestValues[t]=e,this.props.onUpdate&&o.preRender(this.notifyUpdate),n&&this.projection&&(this.projection.isTransformDirty=!0)})),i=e.on("renderRequest",this.scheduleRender);let r;window.MotionCheckAppearSync&&(r=window.MotionCheckAppearSync(this,t,e)),this.valueSubscriptions.set(t,(()=>{s(),i(),r&&r(),e.owner&&e.stop()}))}sortNodePosition(t){return this.current&&this.sortInstanceNodePosition&&this.type===t.type?this.sortInstanceNodePosition(this.current,t.current):0}updateFeatures(){let t="animation";for(t in Xn){const e=Xn[t];if(!e)continue;const{isEnabled:n,Feature:s}=e;if(!this.features[t]&&s&&n(this.props)&&(this.features[t]=new s(this)),this.features[t]){const e=this.features[t];e.isMounted?e.update():(e.mount(),e.isMounted=!0)}}}triggerBuild(){this.build(this.renderState,this.latestValues,this.props)}measureViewportBox(){return this.current?this.measureInstanceViewportBox(this.current,this.props):{x:{min:0,max:0},y:{min:0,max:0}}}getStaticValue(t){return this.latestValues[t]}setStaticValue(t,e){this.latestValues[t]=e}update(t,e){(t.transformTemplate||this.props.transformTemplate)&&this.scheduleRender(),this.prevProps=this.props,this.props=t,this.prevPresenceContext=this.presenceContext,this.presenceContext=e;for(let e=0;e<_n.length;e++){const n=_n[e];this.propEventSubscriptions[n]&&(this.propEventSubscriptions[n](),delete this.propEventSubscriptions[n]);const s=t["on"+n];s&&(this.propEventSubscriptions[n]=this.on(n,s))}this.prevMotionValues=function(t,e,n){for(const s in e){const i=e[s],r=n[s];if(N(i))t.addValue(s,i);else if(N(r))t.addValue(s,f(i,{owner:t}));else if(r!==i)if(t.hasValue(s)){const e=t.getValue(s);!0===e.liveStyle?e.jump(i):e.hasAnimated||e.set(i)}else{const e=t.getStaticValue(s);t.addValue(s,f(void 0!==e?e:i,{owner:t}))}}for(const s in n)void 0===e[s]&&t.removeValue(s);return e}(this,this.scrapeMotionValuesFromProps(t,this.prevProps,this),this.prevMotionValues),this.handleChildMotionValue&&this.handleChildMotionValue()}getProps(){return this.props}getVariant(t){return this.props.variants?this.props.variants[t]:void 0}getDefaultTransition(){return this.props.transition}getTransformPagePoint(){return this.props.transformPagePoint}getClosestVariantNode(){return this.isVariantNode?this:this.parent?this.parent.getClosestVariantNode():void 0}addVariantChild(t){const e=this.getClosestVariantNode();if(e)return e.variantChildren&&e.variantChildren.add(t),()=>e.variantChildren.delete(t)}addValue(t,e){const n=this.values.get(t);e!==n&&(n&&this.removeValue(t),this.bindToMotionValue(t,e),this.values.set(t,e),this.latestValues[t]=e.get())}removeValue(t){this.values.delete(t);const e=this.valueSubscriptions.get(t);e&&(e(),this.valueSubscriptions.delete(t)),delete this.latestValues[t],this.removeValueFromRenderState(t,this.renderState)}hasValue(t){return this.values.has(t)}getValue(t,e){if(this.props.values&&this.props.values[t])return this.props.values[t];let n=this.values.get(t);return void 0===n&&void 0!==e&&(n=f(null===e?void 0:e,{owner:this}),this.addValue(t,n)),n}readValue(t,e){var n;let s=void 0===this.latestValues[t]&&this.current?null!==(n=this.getBaseTargetFromProps(this.props,t))&&void 0!==n?n:this.readValueFromInstance(this.current,t,this.options):this.latestValues[t];var i;return null!=s&&("string"==typeof s&&(Vt(s)||St(s))?s=parseFloat(s):(i=s,!Gn.find(Gt(i))&&xe.test(e)&&(s=Re(t,e))),this.setBaseTarget(t,N(s)?s.get():s)),N(s)?s.get():s}setBaseTarget(t,e){this.baseTarget[t]=e}getBaseTarget(t){var e;const{initial:n}=this.props;let s;if("string"==typeof n||"object"==typeof n){const i=Cn(this.props,n,null===(e=this.presenceContext)||void 0===e?void 0:e.custom);i&&(s=i[t])}if(n&&void 0!==s)return s;const i=this.getBaseTargetFromProps(this.props,t);return void 0===i||N(i)?void 0!==this.initialValues[t]&&void 0===s?void 0:this.baseTarget[t]:i}on(t,n){return this.events[t]||(this.events[t]=new e),this.events[t].add(n)}notify(t,...e){this.events[t]&&this.events[t].notify(...e)}}class Qn extends Jn{constructor(){super(...arguments),this.KeyframeResolver=Ie}sortInstanceNodePosition(t,e){return 2&t.compareDocumentPosition(e)?1:-1}getBaseTargetFromProps(t,e){return t.style?t.style[e]:void 0}removeValueFromRenderState(t,{vars:e,style:n}){delete e[t],delete n[t]}}const ts=(t,e)=>e&&"number"==typeof t?e.transform(t):t,es={x:"translateX",y:"translateY",z:"translateZ",transformPerspective:"perspective"},ns=st.length;function ss(t,e,n){const{style:s,vars:i,transformOrigin:r}=t;let o=!1,a=!1;for(const t in e){const n=e[t];if(it.has(t))o=!0;else if(Mt(t))i[t]=n;else{const e=ts(n,Ce[t]);t.startsWith("origin")?(a=!0,r[t]=e):s[t]=e}}if(e.transform||(o||n?s.transform=function(t,e,n){let s="",i=!0;for(let r=0;r{this.current&&(this.current.textContent=`${t}`)})))}}class ds extends Jn{constructor(){super(...arguments),this.type="object"}readValueFromInstance(t,e){if(function(t,e){return t in e}(e,t)){const n=t[e];if("string"==typeof n||"number"==typeof n)return n}}getBaseTargetFromProps(){}removeValueFromRenderState(t,e){delete e.output[t]}measureInstanceViewportBox(){return{x:{min:0,max:0},y:{min:0,max:0}}}build(t,e){Object.assign(t.output,e)}renderInstance(t,{output:e}){Object.assign(t,e)}sortInstanceNodePosition(){return 0}}function ps(t){const e={presenceContext:null,props:{},visualState:{renderState:{transform:{},transformOrigin:{},style:{},vars:{},attrs:{}},latestValues:{}}},n=function(t){return t instanceof SVGElement&&"svg"!==t.tagName}(t)?new cs(e):new hs(e);n.mount(t),nt.set(t,n)}function fs(t){const e=new ds({presenceContext:null,props:{},visualState:{renderState:{output:{}},latestValues:{}}});e.mount(t),nt.set(t,e)}function ms(t,e,n,s){const i=[];if(function(t,e){return N(t)||"number"==typeof t||"string"==typeof t&&!$(e)}(t,e))i.push(function(t,e,n){const s=N(t)?t:f(t);return s.start(Pn("",s,e,n)),s.animation}(t,$(e)&&e.default||e,n&&n.default||n));else{const r=j(t,e,s),o=r.length;for(let t=0;t{const l=J(t),{delay:u=0,times:c=D(l),type:p="keyframes",...f}=n;let{ease:m=e.ease||"easeOut",duration:y}=n;const w="function"==typeof u?u(o,a):u,b=l.length,T=z(p)?p:null==i?void 0:i[p];if(b<=2&&T){let t=100;if(2===b&&et(l)){const e=l[1]-l[0];t=Math.abs(e)}const e={...f};void 0!==y&&(e.duration=v(y));const n=B(e,t,T);m=n.ease,y=n.duration}null!=y||(y=r);const x=h+w,S=x+y;1===c.length&&0===c[0]&&(c[1]=1);const V=c.length-l.length;V>0&&W(c,V),1===l.length&&l.unshift(null),X(s,l,m,c,x,S),g=Math.max(w+y,g),d=Math.max(S,d)};if(N(p))y(f,m,_("default",Z(p,a)));else{const t=j(p,f,s,l),e=t.length;for(let n=0;n{for(const i in t){const r=t[i];r.sort(G);const a=[],l=[],u=[];for(let t=0;t{s.push(...ms(n,t,e))})),s}function ys(t){return function(e,n,s){let i=[];var r;r=e,i=Array.isArray(r)&&Array.isArray(r[0])?gs(e,n,t):ms(e,n,s,t);const o=new y(i);return t&&t.animations.push(o),o}}const vs=ys();function ws(t,e,n){t.style.setProperty(`--${e}`,n)}function bs(t,e,n){t.style[e]=n}const Ts=m((()=>{try{document.createElement("div").animate({opacity:[1]})}catch(t){return!1}return!0})),xs=new WeakMap;const Ss="easeOut";function Vs(t){const e=xs.get(t)||new Map;return xs.set(t,e),xs.get(t)}class As{constructor(t,e,n,s){const i=e.startsWith("--");this.setValue=i?ws:bs,this.options=s,this.updateFinishedPromise(),x("string"!=typeof s.type);const r=Vs(t).get(e);r&&r.stop();if(Array.isArray(n)||(n=[n]),function(t,e,n){for(let s=0;se.startsWith("--")?t.style.getPropertyValue(e):window.getComputedStyle(t)[e])),z(s.type)){const t=B(s,100,s.type);s.ease=yn()?t.ease:Ss,s.duration=v(t.duration),s.type="keyframes"}else s.ease=s.ease||Ss;this.removeAnimation=()=>{var n;return null===(n=xs.get(t))||void 0===n?void 0:n.delete(e)};const o=()=>{this.setValue(t,e,ht(n,this.options)),this.cancel(),this.resolveFinishedPromise()};Vn()?(this.animation=xn(t,e,n,s),!1===s.autoplay&&this.animation.pause(),this.animation.onfinish=o,this.pendingTimeline&&Sn(this.animation,this.pendingTimeline),Vs(t).set(e,this)):o()}get duration(){return w(this.options.duration||300)}get time(){var t;return this.animation?w((null===(t=this.animation)||void 0===t?void 0:t.currentTime)||0):0}set time(t){this.animation&&(this.animation.currentTime=v(t))}get speed(){return this.animation?this.animation.playbackRate:1}set speed(t){this.animation&&(this.animation.playbackRate=t)}get state(){return this.animation?this.animation.playState:"finished"}get startTime(){return this.animation?this.animation.startTime:null}flatten(){var t;this.animation&&(null===(t=this.animation.effect)||void 0===t||t.updateTiming({easing:"linear"}))}play(){"finished"===this.state&&this.updateFinishedPromise(),this.animation&&this.animation.play()}pause(){this.animation&&this.animation.pause()}stop(){this.animation&&"idle"!==this.state&&"finished"!==this.state&&(this.animation.commitStyles&&this.animation.commitStyles(),this.cancel())}complete(){this.animation&&this.animation.finish()}cancel(){this.removeAnimation();try{this.animation&&this.animation.cancel()}catch(t){}}then(t,e){return this.currentFinishedPromise.then(t,e)}updateFinishedPromise(){this.currentFinishedPromise=new Promise((t=>{this.resolveFinishedPromise=t}))}attachTimeline(t){return this.animation?Sn(this.animation,t):this.pendingTimeline=t,i}}const Ms=t=>function(e,n,s){return new y(function(t,e,n,s){const i=K(t,s),r=i.length,o=[];for(let t=0;t{s({target:t,contentSize:e,get size(){return function(t,e){if(e){const{inlineSize:t,blockSize:n}=e[0];return{width:t,height:n}}return t instanceof SVGElement&&"getBBox"in t?t.getBBox():{width:t.offsetWidth,height:t.offsetHeight}}(t,n)}})}))}function Es(t){t.forEach(Cs)}function Os(t,e){Fs||"undefined"!=typeof ResizeObserver&&(Fs=new ResizeObserver(Es));const n=K(t);return n.forEach((t=>{let n=ks.get(t);n||(n=new Set,ks.set(t,n)),n.add(e),null==Fs||Fs.observe(t)})),()=>{n.forEach((t=>{const n=ks.get(t);null==n||n.delete(e),(null==n?void 0:n.size)||null==Fs||Fs.unobserve(t)}))}}const Rs=new Set;let Bs;function Is(t){return Rs.add(t),Bs||(Bs=()=>{const t={width:window.innerWidth,height:window.innerHeight},e={target:window,size:t,contentSize:t};Rs.forEach((t=>t(e)))},window.addEventListener("resize",Bs)),()=>{Rs.delete(t),!Rs.size&&Bs&&(Bs=void 0)}}const Ls={x:{length:"Width",position:"Left"},y:{length:"Height",position:"Top"}};function Ws(t,e,s,i){const r=s[e],{length:o,position:a}=Ls[e],l=r.current,u=s.time;r.current=t[`scroll${a}`],r.scrollLength=t[`scroll${o}`]-t[`client${o}`],r.offset.length=0,r.offset[0]=0,r.offset[1]=r.scrollLength,r.progress=L(0,r.scrollLength,r.current);const c=i-u;r.velocity=c>50?0:n(r.current-l,c)}const Ds={Enter:[[0,1],[1,1]],Exit:[[0,0],[1,0]],Any:[[1,0],[0,1]],All:[[0,0],[1,1]]},Ns={start:0,center:.5,end:1};function Ks(t,e,n=0){let s=0;if(t in Ns&&(t=Ns[t]),"string"==typeof t){const e=parseFloat(t);t.endsWith("px")?s=e:t.endsWith("%")?t=e/100:t.endsWith("vw")?s=e/100*document.documentElement.clientWidth:t.endsWith("vh")?s=e/100*document.documentElement.clientHeight:t=e}return"number"==typeof t&&(s=e*t),n+s}const $s=[0,0];function js(t,e,n,s){let i=Array.isArray(t)?t:$s,r=0,o=0;return"number"==typeof t?i=[t,t]:"string"==typeof t&&(i=(t=t.trim()).includes(" ")?t.split(" "):[t,Ns[t]?t:"0"]),r=Ks(i[0],n,s),o=Ks(i[1],e),r-o}const zs={x:0,y:0};function Hs(t,e,n){const{offset:s=Ds.All}=n,{target:i=t,axis:r="y"}=n,o="y"===r?"height":"width",a=i!==t?function(t,e){const n={x:0,y:0};let s=t;for(;s&&s!==e;)if(s instanceof HTMLElement)n.x+=s.offsetLeft,n.y+=s.offsetTop,s=s.offsetParent;else if("svg"===s.tagName){const t=s.getBoundingClientRect();s=s.parentElement;const e=s.getBoundingClientRect();n.x+=t.left-e.left,n.y+=t.top-e.top}else{if(!(s instanceof SVGGraphicsElement))break;{const{x:t,y:e}=s.getBBox();n.x+=t,n.y+=e;let i=null,r=s.parentNode;for(;!i;)"svg"===r.tagName&&(i=r),r=s.parentNode;s=i}}return n}(i,t):zs,l=i===t?{width:t.scrollWidth,height:t.scrollHeight}:function(t){return"getBBox"in t&&"svg"!==t.tagName?t.getBBox():{width:t.clientWidth,height:t.clientHeight}}(i),u={width:t.clientWidth,height:t.clientHeight};e[r].offset.length=0;let c=!e[r].interpolate;const h=s.length;for(let t=0;tfunction(t,e=t,n){if(n.x.targetOffset=0,n.y.targetOffset=0,e!==t){let s=e;for(;s&&s!==t;)n.x.targetOffset+=s.offsetLeft,n.y.targetOffset+=s.offsetTop,s=s.offsetParent}n.x.targetLength=e===t?e.scrollWidth:e.clientWidth,n.y.targetLength=e===t?e.scrollHeight:e.clientHeight,n.x.containerLength=t.clientWidth,n.y.containerLength=t.clientHeight}(t,s.target,n),update:e=>{!function(t,e,n){Ws(t,"x",e,n),Ws(t,"y",e,n),e.time=n}(t,n,e),(s.offset||s.target)&&Hs(t,n,s)},notify:()=>e(n)}}const Ys=new WeakMap,qs=new WeakMap,Xs=new WeakMap,Gs=t=>t===document.documentElement?window:t;function Zs(t,{container:e=document.documentElement,...n}={}){let s=Xs.get(e);s||(s=new Set,Xs.set(e,s));const i=Us(e,t,{time:0,x:{current:0,offset:[],progress:0,scrollLength:0,targetOffset:0,targetLength:0,containerLength:0,velocity:0},y:{current:0,offset:[],progress:0,scrollLength:0,targetOffset:0,targetLength:0,containerLength:0,velocity:0}},n);if(s.add(i),!Ys.has(e)){const t=()=>{for(const t of s)t.measure()},n=()=>{for(const t of s)t.update(l.timestamp)},i=()=>{for(const t of s)t.notify()},a=()=>{o.read(t,!1,!0),o.read(n,!1,!0),o.update(i,!1,!0)};Ys.set(e,a);const c=Gs(e);window.addEventListener("resize",a,{passive:!0}),e!==document.documentElement&&qs.set(e,(u=a,"function"==typeof(r=e)?Is(r):Os(r,u))),c.addEventListener("scroll",a,{passive:!0})}var r,u;const c=Ys.get(e);return o.read(c,!1,!0),()=>{var t;a(c);const n=Xs.get(e);if(!n)return;if(n.delete(i),n.size)return;const s=Ys.get(e);Ys.delete(e),s&&(Gs(e).removeEventListener("scroll",s),null===(t=qs.get(e))||void 0===t||t(),window.removeEventListener("resize",s))}}function _s(t,e){let n;const s=()=>{const{currentTime:s}=e,i=(null===s?0:s.value)/100;n!==i&&t(i),n=i};return o.update(s,!0),()=>a(s)}const Js=new Map;function Qs({source:t,container:e=document.documentElement,axis:n="y"}={}){t&&(e=t),Js.has(e)||Js.set(e,{});const s=Js.get(e);return s[n]||(s[n]=g()?new ScrollTimeline({source:e,axis:n}):function({source:t,container:e,axis:n="y"}){t&&(e=t);const s={value:0},i=Zs((t=>{s.value=100*t[n].progress}),{container:e,axis:n});return{currentTime:s,cancel:i}}({source:e,axis:n})),s[n]}function ti(t){return t&&(t.target||t.offset)}function ei(t,{axis:e="y",...n}={}){const s={axis:e,...n};return"function"==typeof t?function(t,e){return function(t){return 2===t.length}(t)||ti(e)?Zs((n=>{t(n[e.axis].progress,n)}),e):_s(t,Qs(e))}(t,s):function(t,e){if(t.flatten(),ti(e))return t.pause(),Zs((n=>{t.time=t.duration*n[e.axis].progress}),e);{const n=Qs(e);return t.attachTimeline?t.attachTimeline(n,(t=>(t.pause(),_s((e=>{t.time=t.duration*e}),n)))):i}}(t,s)}const ni={some:0,all:1};function si(t,e,{root:n,margin:s,amount:i="some"}={}){const r=K(t),o=new WeakMap,a=new IntersectionObserver((t=>{t.forEach((t=>{const n=o.get(t.target);if(t.isIntersecting!==Boolean(n))if(t.isIntersecting){const n=e(t);"function"==typeof n?o.set(t.target,n):a.unobserve(t.target)}else n&&(n(t),o.delete(t.target))}))}),{root:n,rootMargin:s,threshold:"number"==typeof i?i:ni[i]});return r.forEach((t=>a.observe(t))),()=>a.disconnect()}function ii(t,e="end"){return n=>{const s=(n="end"===e?Math.min(n,.999):Math.max(n,.001))*t,i="end"===e?Math.floor(s):Math.ceil(s);return S(0,1,i/t)}}function ri(t=.1,{startDelay:e=0,from:n=0,ease:s}={}){return(i,r)=>{const o="number"==typeof n?n:function(t,e){if("first"===t)return 0;{const n=e-1;return"last"===t?n:n/2}}(n,r),a=Math.abs(o-i);let l=t*a;if(s){const e=r*t;l=Ue(s)(l/e)*e}return e+l}}function oi(...t){const e=!Array.isArray(t[0]),n=e?0:-1,s=t[0+n],i=t[1+n],r=t[2+n],o=t[3+n],a=ln(i,r,{mixer:(l=r[0],(t=>t&&"object"==typeof t&&t.mix)(l)?l.mix:void 0),...o});var l;return e?a(s):a}function ai(t,e){return function(t,e){const n=d.now(),s=({timestamp:i})=>{const r=i-n;r>=e&&(a(s),t(r-e))};return o.read(s,!0),()=>a(s)}(t,v(e))}const li=(t,e)=>Math.abs(t-e);function ui(t,e){const n=li(t.x,e.x),s=li(t.y,e.y);return Math.sqrt(n**2+s**2)}const ci=o,hi=r.reduce(((t,e)=>(t[e]=t=>a(t),t)),{});export{p as MotionValue,vs as animate,Ps as animateMini,wt as anticipate,yt as backIn,vt as backInOut,gt as backOut,a as cancelFrame,hi as cancelSync,bt as circIn,xt as circInOut,Tt as circOut,S as clamp,ys as createScopedAnimate,pt as cubicBezier,ai as delay,li as distance,ui as distance2D,Ke as easeIn,je as easeInOut,$e as easeOut,o as frame,l as frameData,u as frameSteps,si as inView,Ne as inertia,ln as interpolate,x as invariant,un as keyframes,ft as mirrorEasing,an as mix,f as motionValue,qe as pipe,L as progress,mt as reverseEasing,ei as scroll,Zs as scrollInfo,E as spring,ri as stagger,ii as steps,ci as sync,oi as transform,T as warning,U as wrap};export default null; +//# sourceMappingURL=/sm/d5d4bfa5a3f292edc74ce2b856e25f03ebbfa4c4c22aa37e3f75ca1dabe374b0.map \ No newline at end of file diff --git a/docs/showcase/hermes-agent-mastery/ppt/images/04-tools-before-after.svg b/docs/showcase/hermes-agent-mastery/ppt/images/04-tools-before-after.svg new file mode 100644 index 0000000..8d14fcc --- /dev/null +++ b/docs/showcase/hermes-agent-mastery/ppt/images/04-tools-before-after.svg @@ -0,0 +1,42 @@ + + + + + + + + + + WITHOUT TOOLS + 只能建议 + + WITH HERMES + 可以执行 + + + + + 方案 / 建议 / 草稿 + + + + 下一步仍靠人执行 + + + 模型 + + + 工具 + + + Skill + + + + + + + 读取 → 执行 → 检查 → 写回 + + 模式差异:聊天框输出语言;Hermes 输出可验收的工作结果。 + diff --git a/docs/showcase/hermes-agent-mastery/ppt/images/06-context-system.svg b/docs/showcase/hermes-agent-mastery/ppt/images/06-context-system.svg new file mode 100644 index 0000000..9491e21 --- /dev/null +++ b/docs/showcase/hermes-agent-mastery/ppt/images/06-context-system.svg @@ -0,0 +1,18 @@ + + + + + + CONTEXT STACK + 三层上下文进入 Hermes + PROJECT项目级 + README / 架构 / 命令 / 决策 + TASK任务级 + brief / 验收 / 路径 / 失败处理 + PERSONAL个人级 + 偏好 / 语气 / 惯用流程 / 记忆 + + HERMES AGENT带着项目理解处理当前任务 + 稳定输出:文件 / 命令 / 报告 / 下一步 + + diff --git a/docs/showcase/hermes-agent-mastery/ppt/images/07-agent-teams.svg b/docs/showcase/hermes-agent-mastery/ppt/images/07-agent-teams.svg new file mode 100644 index 0000000..46a22a3 --- /dev/null +++ b/docs/showcase/hermes-agent-mastery/ppt/images/07-agent-teams.svg @@ -0,0 +1,19 @@ + + + + + + AGENT TEAMS ORCHESTRATION + 主控、生产、校验形成闭环 + 主 Agent目标判断 · 拆解任务 · 收口质量 + 生产 Agent代码 / PPT / 文档 / 素材 + QA Agent路径 / 内容 / 运行 / 风险 + + + + 输入清洗 + 工具执行 + 状态记录 + 可验收交付 + + \ No newline at end of file diff --git a/docs/showcase/hermes-agent-mastery/ppt/index.html b/docs/showcase/hermes-agent-mastery/ppt/index.html new file mode 100644 index 0000000..a959564 --- /dev/null +++ b/docs/showcase/hermes-agent-mastery/ppt/index.html @@ -0,0 +1,2531 @@ + + + + + +Agent 从入门到精通:Hermes 版 · Guizang Swiss + + + + + + + + + +
← → 翻页 · B 静态 · ESC 索引
+ +
+ + + +
+
+ +
+
Hermes Agent Mastery · Field Note 01
+
SWISS · IKB · 01 / 08
+
+
+
AGENT OPERATING SYSTEM
+

Agent 从入门
精通

+
+
Hermes 版学习路径:从能聊,到能执行;从单次任务,到可复用工作流。
+
+
Humanize PPT × Guizang PPT Skill
+
→ arrow keys
+
+
+
+
+
+ +
+
+
+
CORE SHIFT
+
02 / 08
+
+
+
+

Agent 不是
聊天框,
执行系统

+

Hermes 的价值不在多会说,而在把模型、工具、Skill、上下文与质量门接成一个可验收的工作流。

+
+
+
EXECUTION STACK
+
+
01
+

模型

负责理解、生成与推理。

+
+
+
02
+

工具

把建议变成可执行动作。

+
+
+
03
+

Skill

沉淀可复用工作流。

+
+
+
04
+

上下文

让 Agent 持续认识项目。

+
+
+
05
+

质量门

把输出变成交付,而不是草稿。

+
+
+
+
+
+ +
+
+
+
ENTRY LOOP · REMOTION MATERIAL
+
03 / 08
+
+
+
MINIMUM VIABLE AGENT
+

先跑通一个真实小任务

+

四步闭环已经做成 Remotion 动画:安装、配置模型、Doctor、交付依次点亮。

+
+
+ +
+
VIDEO SLOT · Remotion / 180 frames / 30fps / H.264
+
+
+ +
+
+
+
TOOLS AS LIMBS · GPT-READY DIAGRAM
+
04 / 08
+
+
+
WITHOUT TOOLS / WITH HERMES
+

工具决定 Agent 的执行边界

+
+
+ 没有工具只能建议,接入 Hermes 工具后可以执行 +
+
+

没有工具时,Agent 只能停在建议和草稿。

+

接上 Hermes 工具层后,工作流进入读取、执行、检查、写回。

+
+
+
+ +
+
+
+
SKILL LAYER
+
05 / 08
+
+
+
+
+
REUSABLE WORKFLOWS
+

把经验封装成
Skill

+
+

Skill 不是提示词收藏,而是把一次成功做法变成可复用、可检查、可交付的工作流。

+
+
+
+ 01 +

触发场景

什么时候该调用这个工作流。

+
+
+ 02 +

输入要求

用户需要给什么材料。

+
+
+ 03 +

执行步骤

从理解任务到生产结果。

+
+
+ 04 +

工具边界

哪些动作可做,哪些要确认。

+
+
+ 05 +

检查标准

如何判断输出不是草稿。

+
+
+ 06 +

交付格式

文件、路径、报告和下一步。

+
+
+
+
+
+ +
+
+
+
CONTEXT SYSTEM · MATERIALIZED
+
06 / 08
+
+
+
PROJECT MEMORY
+

让 Hermes 真的认识项目

+
+
+ 项目级、任务级、个人级上下文进入 Hermes Agent +
+
PROJECT · TASK · PERSONAL → HERMES AGENT → DELIVERABLES
+
+
+ +
+
+
+
AGENT TEAMS · ORCHESTRATION MATERIAL
+
07 / 08
+
+
+
DIRECTOR / MAKER / CHECKER
+

从单 Agent 到团队编排

+
+
+ 主 Agent、生产 Agent、QA Agent 的协作闭环 +
+
+

主 Agent 负责方向、拆解和收口。

+

生产 Agent 与 QA Agent 通过状态记录形成可验收闭环。

+
+
+
+ +
+
+
+
+ +
08 / 08
CLOSING
+
+
MANIFESTO
+

让 Agent
成为工作台

+
消息入口接入 Hermes,Skill 按场景触发,工具负责执行,QA 负责验收。
+
+
Hermes Agent Mastery
26.05.26
+
+
+
TAKEAWAYS
03 RULES
+
+
01

先跑闭环

能读、能做、能写回,才算入门。

+
02

沉淀 Skill

把一次经验变成下一次可复用流程。

+
03

始终 QA

没有验收,Agent 只是草稿机。

+
+
→ END OF FIELD NOTE
+
+
+
+
+
+ + + + + + + + + + + + + diff --git a/docs/showcase/hermes-agent-mastery/ppt/videos/03-entry-loop.mp4 b/docs/showcase/hermes-agent-mastery/ppt/videos/03-entry-loop.mp4 new file mode 100644 index 0000000..89daff2 Binary files /dev/null and b/docs/showcase/hermes-agent-mastery/ppt/videos/03-entry-loop.mp4 differ diff --git a/docs/showcase/hermes-agent-mastery/presenter/index.html b/docs/showcase/hermes-agent-mastery/presenter/index.html new file mode 100644 index 0000000..f95b337 --- /dev/null +++ b/docs/showcase/hermes-agent-mastery/presenter/index.html @@ -0,0 +1,532 @@ + + + + + + Presenter · Agent 从入门到精通 Hermes 版 + + + +
+
+
+
+
Presenter Console
+

Agent 从入门到精通 Hermes 版

+
+
+
00:00
+ + +
+
+ +
+ +
+ +
+
+
+
+
02 / 08
+
Agent 不是聊天框,是执行系统
+
Core Shift
+
+
+
+
Next · 02 / 08
+
Agent 不是聊天框,是执行系统
+
+
+
+
+ + +
+
+
+
01 / 08
+
+
+
+
+ + +
+ + + + diff --git a/docs/showcase/hermes-agent-mastery/presenter/notes.json b/docs/showcase/hermes-agent-mastery/presenter/notes.json new file mode 100644 index 0000000..7743573 --- /dev/null +++ b/docs/showcase/hermes-agent-mastery/presenter/notes.json @@ -0,0 +1,102 @@ +{ + "title": "Agent 从入门到精通 Hermes 版", + "deck": "../ppt/index.html", + "slides": [ + { + "number": 1, + "title": "Agent 从入门到精通", + "section": "Opening", + "duration": "1:00", + "beats": [ + "先把 Agent 从聊天框里拿出来。", + "这场分享关注 Hermes 工作台如何让 Agent 变成能交付的系统。", + "听众最后要带走一套可复用的升级路径。" + ], + "script": "开场先定调:今天不是讲一个更会聊天的模型,而是讲一个能接模型、工具、Skill、上下文和质量门的执行系统。Hermes 版的关键词是可操作、可检查、可沉淀。我们会从最小闭环开始,一页页走到工具、Skill、记忆、团队编排,最后落到一个能长期工作的个人 Agent 工作台。" + }, + { + "number": 2, + "title": "Agent 不是聊天框,是执行系统", + "section": "Core Shift", + "duration": "1:40", + "beats": [ + "对比聊天输出和执行系统。", + "强调模型只是第一层,后面需要工具、Skill、上下文和质量门。", + "把 Hermes 定义成执行栈,不是单个聊天窗口。" + ], + "script": "这一页是全场核心转向。普通聊天框擅长给建议,但建议不等于交付。Hermes 的价值在于把模型放进执行栈:模型负责判断和生成,工具负责行动,Skill 负责复用经验,上下文负责理解项目,质量门负责检查输出。这样 Agent 才不会停在一句话,而是能把事情推进到文件、命令、报告和下一步。" + }, + { + "number": 3, + "title": "先跑通一个真实小任务", + "section": "Entry Loop", + "duration": "1:30", + "beats": [ + "从安装、配置模型、Doctor 到交付,形成第一条闭环。", + "视频素材是节奏提示,不重复读标题。", + "强调小任务真实可验收。" + ], + "script": "入门不要先追求复杂自动化,先跑通一个真实小任务。比如装好 Hermes,配置模型,跑 Doctor,最后产出一个明确交付物。重点不是任务多炫,而是每一步都有检查点:启动是否成功、模型是否可用、工具是否能跑、最后有没有可验收结果。这个闭环跑通后,Agent 才从概念变成工作流。" + }, + { + "number": 4, + "title": "工具决定 Agent 的执行边界", + "section": "Tools", + "duration": "1:40", + "beats": [ + "没有工具时 Agent 只能建议。", + "接入工具后才进入读取、执行、检查、写回。", + "工具边界也是权限边界。" + ], + "script": "工具是 Agent 的手脚。没有工具时,它只能停在方案、建议、草稿;有了 Hermes 工具层,流程才进入读取、执行、检查、写回。这里也要提醒:工具不是越多越好,工具边界就是权限边界。一个成熟 Agent 应该知道自己能做什么、不能做什么,以及什么时候要把风险交回给人确认。" + }, + { + "number": 5, + "title": "把经验封装成 Skill", + "section": "Skill Layer", + "duration": "1:50", + "beats": [ + "Skill 是可复用工作流,不是提示词收藏夹。", + "六个模块:触发、输入、步骤、边界、检查、交付。", + "用这页解释如何把一次成功经验变成下次默认能力。" + ], + "script": "Skill 这一层最容易被低估。它不是把提示词存起来,而是把一次成功的工作经验变成可复用流程。一个好 Skill 至少说清楚六件事:什么时候触发,需要什么输入,按什么步骤执行,哪些动作能做,哪些要确认,如何判断不是草稿,以及最后交付成什么格式。做到这里,Agent 才开始积累组织能力。" + }, + { + "number": 6, + "title": "让 Hermes 真的认识项目", + "section": "Context System", + "duration": "1:40", + "beats": [ + "三层上下文:项目级、任务级、个人级。", + "上下文进入 Agent 后,输出才稳定。", + "项目记忆不是堆资料,而是减少重复解释。" + ], + "script": "这一页讲记忆和上下文。项目级让 Hermes 知道仓库、架构、命令和决策;任务级让它知道这一次的 brief、路线、修改和异常;个人级让它理解偏好、语言、审美和交付习惯。三层上下文进入 Agent 后,输出会明显稳定,因为我们不再每次从零解释,也不再靠模型临场猜。" + }, + { + "number": 7, + "title": "从单 Agent 到团队编排", + "section": "Agent Teams", + "duration": "1:40", + "beats": [ + "单 Agent 强在连续性,团队编排强在分工。", + "设计、工程、QA、发布各自负责可验收节点。", + "团队不是并发噱头,而是把质量门拆开。" + ], + "script": "当任务变复杂,单 Agent 会遇到角色混杂的问题。团队编排的价值不是热闹,而是把设计、工程、QA、发布拆成不同责任面。每个 Agent 有自己的输入、产出和检查标准,最后由主流程收束。这样一来,复杂任务不再是一长串聊天,而是一组可以追踪、可以失败重试、可以复盘的节点。" + }, + { + "number": 8, + "title": "让 Agent 成为工作台", + "section": "Closing", + "duration": "1:20", + "beats": [ + "回收四个 takeaway。", + "强调下一步是把工作流产品化和线上化。", + "给听众一个可执行的起点。" + ], + "script": "结尾回到行动。真正的升级路线不是一口气做超级 Agent,而是先跑通小任务,再接工具,再封装 Skill,再沉淀上下文,最后进入团队编排和发布。Hermes 的意义在于把 Agent 放进日常工作台,让它稳定地产出、检查、写回。下一步可以从一个高频任务开始,把它变成可复用 Skill。" + } + ] +} diff --git a/docs/showcase/hermes-agent-mastery/presenter/presenter-screenshot.png b/docs/showcase/hermes-agent-mastery/presenter/presenter-screenshot.png new file mode 100644 index 0000000..f07aecb Binary files /dev/null and b/docs/showcase/hermes-agent-mastery/presenter/presenter-screenshot.png differ diff --git a/docs/showcase/hermes-agent-mastery/presenter/presenter_manifest.json b/docs/showcase/hermes-agent-mastery/presenter/presenter_manifest.json new file mode 100644 index 0000000..ec9c7c1 --- /dev/null +++ b/docs/showcase/hermes-agent-mastery/presenter/presenter_manifest.json @@ -0,0 +1,18 @@ +{ + "title": "Agent 从入门到精通 Hermes 版", + "mode": "presenter", + "status": "rendered", + "deck_path": "../ppt/index.html", + "entry": "index.html", + "notes_path": "notes.json", + "screenshot_path": "presenter-screenshot.png", + "slide_count": 8, + "features": [ + "current-slide-preview", + "next-slide-card", + "speaker-notes", + "timer", + "postmessage-deck-control" + ], + "generated_at": "2026-05-26" +} diff --git a/docs/showcase/hermes-agent-mastery/presenter/render_report.md b/docs/showcase/hermes-agent-mastery/presenter/render_report.md new file mode 100644 index 0000000..23ceb34 --- /dev/null +++ b/docs/showcase/hermes-agent-mastery/presenter/render_report.md @@ -0,0 +1,19 @@ +# Presenter Render Report + +status: pass + +## Outputs + +- `index.html` +- `notes.json` +- `presenter_manifest.json` +- `presenter-screenshot.png` + +## Checks + +- Deck control bridge added to `../ppt/index.html`. +- Presenter shell can control current slide through `postMessage`. +- Speaker notes cover all 8 slides. +- Current slide preview and next slide card are available. +- Timer controls are local-only and do not modify the deck. +- Playwright smoke check passed: clicking next moved the visible notes from slide 1 to slide 2 and the deck iframe reported `window.__currentSlideIndex === 1`. diff --git a/docs/versions/v0.6.1-guizang-material-qa.md b/docs/versions/v0.6.1-guizang-material-qa.md new file mode 100644 index 0000000..8a58c80 --- /dev/null +++ b/docs/versions/v0.6.1-guizang-material-qa.md @@ -0,0 +1,32 @@ +# V0.6.1 Guizang Material QA + +V0.6.1 is a workflow-note release. It records lessons from a full Humanize PPT → guizang-ppt-skill pass that included Swiss HTML rendering, deterministic diagram materials, a Remotion process clip, and visual QA iterations. + +## What Changed + +- Bumped public skill metadata to `0.6.1`. +- Added `references/guizang-material-qa.md`. +- Clarified that guizang completion needs a visual/material QA pass after the first HTML deck exists. +- Clarified that Remotion is a PPT material producer, not a replacement for slide content. +- Clarified that deterministic SVG/HTML is preferred for Chinese text-heavy diagrams, while GPT image generation is better for non-textual visual support. + +## Lessons Captured + +1. Humanize PPT must record downstream artifacts explicitly. + A guizang deck, inserted materials, and Remotion source/output should be visible in manifests instead of living as informal side files. + +2. Layout documentation is not enough. + A class mentioned in a reference document may not exist in the current copied template. Agents must verify class names against the actual template CSS before relying on them. + +3. Materials should not repeat page titles. + The slide owns the title and narrative frame. SVG diagrams and Remotion clips should carry the proof, process, or system relationship. + +4. SVG text needs a local safe area. + Chinese labels can clip or overlap once scaled into deck frames. Increase card height, reduce label size, and keep connectors clear of labels. + +5. Statement pages may need structural anchors. + Swiss whitespace works when it is intentional. If a statement page feels unfinished, add a compact stack, comparison, or supporting evidence rather than filling space randomly. + +## Boundaries + +This release does not add a new automatic guizang material generator. It documents the workflow and QA rules so a future adapter can implement them without re-learning these failure modes. diff --git a/docs/versions/v0.6.2-guizang-presenter-deploy.md b/docs/versions/v0.6.2-guizang-presenter-deploy.md new file mode 100644 index 0000000..8e1d206 --- /dev/null +++ b/docs/versions/v0.6.2-guizang-presenter-deploy.md @@ -0,0 +1,28 @@ +# V0.6.2 Guizang Presenter Deploy + +V0.6.2 fixes the Chinese PPT production path after a full Hermes deck pass. + +## What changed + +1. Chinese stable decks default to the guizang path unless the user explicitly asks for style exploration or another renderer. +2. Guizang output should be treated as a production deck, then followed by material QA, presenter mode, and deploy packaging. +3. Presenter mode uses a separate shell that controls the finalized deck through `postMessage` and a `?slide=` fallback. +4. A public static showcase was added at `docs/showcase/hermes-agent-mastery/`. + +## Public URLs + +After the branch is merged and GitHub Pages publishes: + +- `https://learnprompt.github.io/humanize-ppt/showcase/hermes-agent-mastery/` +- `https://learnprompt.github.io/humanize-ppt/showcase/hermes-agent-mastery/ppt/` +- `https://learnprompt.github.io/humanize-ppt/showcase/hermes-agent-mastery/presenter/` + +## Version boundary + +This release does not make Humanize PPT a renderer. It records a default route and a proven post-processing adapter: + +```text +source -> AST contract -> guizang deck -> material QA -> presenter -> deploy +``` + +Deploy remains a static hosting step. GitHub Pages, Vercel, or any plain file host can serve the package. diff --git a/references/guizang-material-qa.md b/references/guizang-material-qa.md new file mode 100644 index 0000000..1f18a9e --- /dev/null +++ b/references/guizang-material-qa.md @@ -0,0 +1,98 @@ +# Guizang Material QA + +Use this reference when Humanize PPT routes a deck to `guizang-ppt-skill`, especially for Chinese Swiss-style decks that need inserted diagrams, screenshots, generated images, or Remotion clips. + +## Position + +Humanize PPT remains the outline director and route owner. Guizang is the downstream renderer for stable Chinese HTML PPT production. Material generation is a separate pass after the first guizang deck exists. + +Recommended route: + +```text +raw material +→ Humanize PPT AST contract +→ guizang-ppt-skill HTML deck +→ material production pass +→ visual QA pass +→ presenter/export/deploy +``` + +Do not describe a guizang deck as complete just because `index.html` exists. A produced deck needs visual QA after materials are inserted. + +## Material Selection + +Choose materials by page need: + +- If a page feels empty, first decide what is missing: proof, process, system relationship, comparison, screenshot evidence, or emotional anchor. +- Use Remotion for short timed process clips, transition fragments, before/after motion, or explanatory sequences. +- Use deterministic SVG/HTML diagrams for Chinese text-heavy information graphics, exact labels, Swiss grid alignment, and content that must be inspectable. +- Use GPT image generation for non-textual photos, mood images, visual metaphors, or concept art where exact text is not critical. +- Use screenshot framing when preserving a real UI or source image matters more than redesigning it. + +Remotion, GPT images, and SVG diagrams are materials inside PPT pages. They should not replace the page with an empty embedded player or duplicate the page title. + +## Guizang Swiss QA Checklist + +Before reporting completion, check: + +1. `guizang-ppt-skill` validator passes for Swiss decks. +2. Every slide has a registered `data-layout`. +3. Referenced class names exist in the copied template CSS. Do not trust layout docs alone; verify the actual template. +4. No page has unresolved placeholders such as `[必填]`. +5. Text inside inserted SVG/image/video frames has its own safe area and does not clip, overlap, or hug the edge. +6. Inserted materials do not repeat the outer PPT title. The page owns the title; the material should carry the diagram, process, proof, or evidence. +7. Long Chinese labels are either shortened, split into lines, or moved into HTML text outside the image. +8. Video slots have a purpose, duration, source path, and fallback explanation in the manifest. +9. The final `material_manifest.json` records all generated or inserted assets. +10. The downstream route is reflected in `router_plan.json` / `run_manifest.json` when the workflow is being packaged as a Humanize PPT run. + +## Failure Patterns + +### Undefined layout classes + +If a page uses a class from a reference document but the copied template CSS does not define it, the page may collapse into plain vertical text. Fix by switching to classes verified in the actual template, such as `grid-6`, `card-fill`, `card-accent`, `sub-card`, or the registered Sxx skeleton. + +### Text clipped inside SVG + +SVG text can look correct in isolation but clip once scaled into a deck frame. Increase the containing rectangle, reduce text size, move baselines inward, and keep connector lines away from labels. + +### Material repeats the slide title + +If the outer slide title says the concept, the inserted SVG or Remotion clip should not repeat the same large title. Keep only metadata, process nodes, diagrams, or proof inside the material. + +### Over-empty statement pages + +Swiss whitespace is useful, but a statement page can look unfinished when it carries only one sentence and no structural anchor. Add a compact right-side stack, comparison, or supporting proof when the slide needs to be taught rather than merely declared. + +### Image generation with Chinese text + +GPT image generation can be useful for visual concepts, but exact Chinese labels are fragile. Prefer SVG/HTML for Chinese system diagrams, flow charts, and QA-sensitive labels. Use GPT images for non-textual visual support unless the user explicitly accepts text risk. + +## Manifest Pattern + +For materialized guizang runs, write a small manifest: + +```json +{ + "source_workflow": "Humanize PPT AST contract -> guizang-ppt-skill deck -> material production pass", + "style": "Swiss Internationalism / IKB", + "assets": [ + { + "slide": 3, + "file": "ppt/videos/03-entry-loop.mp4", + "type": "remotion-process-video", + "slot": "remotion-entry-loop-16x9", + "purpose": "Explain the entry loop without repeating the slide title" + }, + { + "slide": 6, + "file": "ppt/images/06-context-system.svg", + "type": "deterministic-svg-diagram", + "slot": "s14-context-21x9", + "purpose": "Show how project/task/personal context enters Hermes" + } + ] +} +``` + +Keep generated run artifacts out of the public repo unless they are curated demo assets. diff --git a/references/guizang-presenter-deploy.md b/references/guizang-presenter-deploy.md new file mode 100644 index 0000000..01588a6 --- /dev/null +++ b/references/guizang-presenter-deploy.md @@ -0,0 +1,40 @@ +# Guizang presenter deploy path + +Use this when the task is a Chinese PPT and the user wants a complete, presentable artifact rather than only an outline or draft deck. + +## Default path + +```text +Humanize PPT + -> AST production contract + -> guizang-ppt-skill Chinese stable deck + -> material / visual QA + -> presenter adapter + -> static deploy package +``` + +## Presenter shell requirements + +- Keep presenter mode as a post-processing adapter after the final deck exists. +- The presenter shell should not duplicate the visual renderer. It should provide current slide, next slide, speaker notes, timer, and slide navigation. +- Prefer `postMessage` control with message types: + - `presenter-goto` + - `presenter-next` + - `presenter-prev` + - `presenter-state-request` + - `presenter-state` +- Keep `?slide=` as a fallback for static hosts and older deck runtimes. + +## Deploy requirements + +- Publish only static files needed by the deck and presenter shell. +- Do not include Remotion `node_modules`, raw generation caches, or temporary run directories. +- Public samples should include a root `index.html` that links or redirects to the presenter entry and exposes the raw PPT path. + +## QA checks + +- The deck opens through the deployed URL. +- The presenter entry opens through the deployed URL. +- Clicking next updates both the presenter notes and the deck iframe. +- `notes.json`, `presenter_manifest.json`, and `render_report.md` exist. +- The deck still passes renderer-specific validation when such a validator exists. diff --git a/registry/renderer_registry.json b/registry/renderer_registry.json index ba412c0..dc6e396 100644 --- a/registry/renderer_registry.json +++ b/registry/renderer_registry.json @@ -1,5 +1,5 @@ { - "version": "0.6.0", + "version": "0.6.2", "renderers": [ { "id": "guizang", @@ -9,10 +9,13 @@ "best_for": [ "中文分享", "稳定成稿", + "中文默认生产路径", "杂志风", "瑞士风", "截图美化", - "配图适配" + "配图适配", + "presenter后处理", + "static deploy" ], "inputs": [ "deck_brief.md", @@ -23,7 +26,9 @@ ], "outputs": [ "outputs/guizang/index.html", - "outputs/guizang/render_report.md" + "outputs/guizang/render_report.md", + "outputs/presenter/index.html", + "outputs/export/package/index.html" ], "local_skill_paths": [ "~/.agents/skills/guizang-ppt-skill", diff --git a/scripts/humanize_ppt_v2.py b/scripts/humanize_ppt_v2.py index 993a36a..74f6d02 100755 --- a/scripts/humanize_ppt_v2.py +++ b/scripts/humanize_ppt_v2.py @@ -11,7 +11,7 @@ SKILL_ROOT = Path(__file__).resolve().parents[1] REGISTRY_PATH = SKILL_ROOT / "registry" / "renderer_registry.json" -VERSION = "0.6.0" +VERSION = "0.6.2" BEAUTIFUL_REPO_URL = "https://github.com/zarazhangrui/beautiful-html-templates.git" ROLE_ARC = [ @@ -775,10 +775,20 @@ def write_presenter_adapter(out, title, plan, deck_path): iframe{{width:100%;aspect-ratio:16/9;border:0;border-radius:16px;background:#000;box-shadow:0 20px 80px rgba(0,0,0,.45)}} aside{{border-left:1px solid rgba(255,255,255,.12);padding:22px;display:grid;grid-template-rows:auto auto 1fr auto;gap:16px;background:#171923}} .kicker{{letter-spacing:.12em;color:#e5b65b;font-size:12px;text-transform:uppercase}}h1{{margin:.1em 0;font-size:28px}}.cards{{display:grid;grid-template-columns:1fr 1fr;gap:12px}}.card{{border:1px solid rgba(255,255,255,.14);border-radius:14px;padding:14px;background:rgba(255,255,255,.05)}}.label{{font-size:11px;color:#9aa3b2;letter-spacing:.12em}}#script{{white-space:pre-wrap;font-size:20px;line-height:1.55;overflow:auto}}button{{border:0;border-radius:12px;padding:12px 16px;background:#e5b65b;color:#111;font-weight:700}}.nav{{display:flex;gap:10px;align-items:center}} -
""" presenter = target / "index.html" @@ -1006,6 +1022,35 @@ def slide_sections(title, plan): return "\n\n".join(sections) +def inject_presenter_bridge(html_doc): + """Expose guizang deck navigation to Humanize PPT presenter shells.""" + if "presenter-goto" in html_doc: + return html_doc + bridge = """ +window.__goSlide = go; +addEventListener('message',e=>{ + const msg=e.data||{}; + if(!msg || typeof msg!=='object')return; + if(msg.type==='presenter-goto' && Number.isFinite(msg.index)){lock=false;go(msg.index);} + if(msg.type==='preview-goto' && Number.isFinite(msg.idx)){lock=false;go(msg.idx);} + if(msg.type==='presenter-next'){lock=false;go(idx+1);} + if(msg.type==='presenter-prev'){lock=false;go(idx-1);} + if(msg.type==='presenter-state-request' && parent!==window){ + parent.postMessage({type:'presenter-state',index:idx,total},'*'); + } +}); +""" + marker = "\n\n/* =============== ESC 索引视图 =============== */" + if "function go(n)" in html_doc and marker in html_doc: + html_doc = html_doc.replace(marker, "\n" + bridge + marker, 1) + initial = """const initialSlideParam = new URLSearchParams(location.search).get('slide'); +const initialSlide = initialSlideParam ? Number(initialSlideParam) - 1 : 0; +go(Number.isFinite(initialSlide) ? initialSlide : 0);""" + if "\ngo(0);\n" in html_doc and "initialSlideParam" not in html_doc: + html_doc = html_doc.replace("\ngo(0);\n", "\n" + initial + "\n", 1) + return html_doc + + def write_guizang_output(out, title, plan): target = out / "outputs" / "guizang" target.mkdir(parents=True, exist_ok=True) @@ -1015,6 +1060,7 @@ def write_guizang_output(out, title, plan): template = template_path.read_text(encoding="utf-8", errors="replace") html_doc = template.replace("[必填] 替换为 PPT 标题 · Deck Title", f"{title} · Humanize PPT V0.4") html_doc = html_doc.replace("", sections) + html_doc = inject_presenter_bridge(html_doc) report = f"# Guizang Render Report\n\n- status: rendered\n- template: {template_path}\n- output: {target / 'index.html'}\n- slides: {len(plan)}\n" else: html_doc = fallback_deck(title, plan) @@ -1026,7 +1072,7 @@ def write_guizang_output(out, title, plan): def fallback_deck(title, plan): sections = slide_sections(title, plan) - return f"""{html.escape(title)}{sections}""" + return f"""{html.escape(title)}{sections}""" def write_qa(out, plan, render_issues=None): diff --git a/tests/test_beautiful_preview.py b/tests/test_beautiful_preview.py index 2be3534..b1dbc14 100644 --- a/tests/test_beautiful_preview.py +++ b/tests/test_beautiful_preview.py @@ -1,6 +1,7 @@ import json import sys from pathlib import Path +from types import SimpleNamespace ROOT = Path(__file__).resolve().parents[1] sys.path.insert(0, str(ROOT / "scripts")) @@ -8,6 +9,39 @@ import humanize_ppt_v2 as hp +def test_zh_default_route_uses_guizang_with_presenter_adapter(): + args = SimpleNamespace( + renderer="auto", + style_mode="stable-first", + selected_template=None, + presenter=False, + presenter_adapter=True, + export_adapter=False, + ) + + primary, routes = hp.choose_routes(args, Path("source.md"), "中文 Agent 分享内容", "zh") + + assert primary == "guizang" + assert [route["id"] for route in routes] == ["guizang", "presenter-adapter", "qa"] + assert routes[0]["reason"] == "中文内容且未指定风格探索,优先走guizang稳定路径。" + + +def test_inject_presenter_bridge_adds_guizang_deck_control(): + html = """""" + + bridged = hp.inject_presenter_bridge(html) + + assert "window.__goSlide = go" in bridged + assert "presenter-goto" in bridged + assert "preview-goto" in bridged + assert "initialSlideParam" in bridged + + def make_repo(tmp_path): repo = tmp_path / "beautiful" (repo / "runtime").mkdir(parents=True) @@ -216,7 +250,9 @@ def test_write_presenter_adapter_creates_presenter_shell_with_notes(tmp_path): assert manifest.exists() html = presenter.read_text(encoding="utf-8") assert "Humanize PPT · Presenter Adapter" in html - assert "../beautiful/selected/index.html" in html + assert "../beautiful/selected/index.html?slide=1" in html + assert "presenter-goto" in html + assert "preview-goto" in html assert "CURRENT" in html assert "NEXT" in html assert "SCRIPT" in html diff --git a/tests/test_version_metadata.py b/tests/test_version_metadata.py index 83b92a2..bc9d4fb 100644 --- a/tests/test_version_metadata.py +++ b/tests/test_version_metadata.py @@ -4,7 +4,7 @@ ROOT = Path(__file__).resolve().parents[1] -EXPECTED_VERSION = "0.6.0" +EXPECTED_VERSION = "0.6.2" def test_release_version_metadata_is_consistent(): @@ -12,6 +12,6 @@ def test_release_version_metadata_is_consistent(): script = (ROOT / "scripts" / "humanize_ppt_v2.py").read_text(encoding="utf-8") registry = json.loads((ROOT / "registry" / "renderer_registry.json").read_text(encoding="utf-8")) - assert re.search(r"^version: 0\.6\.0$", skill, re.MULTILINE) + assert re.search(r"^version: 0\.6\.2$", skill, re.MULTILINE) assert f'VERSION = "{EXPECTED_VERSION}"' in script assert registry["version"] == EXPECTED_VERSION