steppy-dev 0.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. steppy/CHANGELOG.md +862 -0
  2. steppy/__init__.py +9 -0
  3. steppy/__main__.py +13 -0
  4. steppy/_cli_common.py +183 -0
  5. steppy/_docker/Dockerfile.installed +53 -0
  6. steppy/_parallel/__init__.py +7 -0
  7. steppy/_parallel/compose.py +349 -0
  8. steppy/_parallel/event_bus.py +418 -0
  9. steppy/_parallel/failures.py +267 -0
  10. steppy/_parallel/fingerprint.py +141 -0
  11. steppy/_parallel/image.py +380 -0
  12. steppy/_parallel/lastfailed.py +125 -0
  13. steppy/_parallel/lifecycle.py +90 -0
  14. steppy/_parallel/preauth.py +109 -0
  15. steppy/_parallel/progress.py +101 -0
  16. steppy/_parallel/queue.py +385 -0
  17. steppy/_parallel/renderer.py +489 -0
  18. steppy/_parallel/retry.py +316 -0
  19. steppy/_player_bundle/THIRD_PARTY_LICENSES.txt +158 -0
  20. steppy/_player_bundle/__init__.py +100 -0
  21. steppy/_player_bundle/steppy-cursor-legacy.js +2 -0
  22. steppy/_player_bundle/steppy-cursor-legacy.js.map +1 -0
  23. steppy/_player_bundle/steppy-player.js +5419 -0
  24. steppy/_player_bundle/steppy-player.js.map +1 -0
  25. steppy/_player_bundle/steppy-video.js +472 -0
  26. steppy/_player_bundle/steppy-video.js.map +1 -0
  27. steppy/_templating.py +117 -0
  28. steppy/assertions.py +251 -0
  29. steppy/auth.py +493 -0
  30. steppy/build.py +2798 -0
  31. steppy/build_models.py +669 -0
  32. steppy/buildid.py +134 -0
  33. steppy/bundle/__init__.py +47 -0
  34. steppy/bundle/archive.py +239 -0
  35. steppy/bundle/classify.py +329 -0
  36. steppy/bundle/create.py +490 -0
  37. steppy/bundle/hashing.py +28 -0
  38. steppy/bundle/manifest.py +334 -0
  39. steppy/bundle/results.py +546 -0
  40. steppy/bundle_cli.py +455 -0
  41. steppy/captures.py +207 -0
  42. steppy/cli.py +2489 -0
  43. steppy/cloud/__init__.py +58 -0
  44. steppy/cloud/client.py +267 -0
  45. steppy/cloud/upload.py +497 -0
  46. steppy/compat.py +109 -0
  47. steppy/config.py +231 -0
  48. steppy/config_schema.py +87 -0
  49. steppy/contracts/__init__.py +54 -0
  50. steppy/contracts/bundle.py +215 -0
  51. steppy/contracts/report.py +346 -0
  52. steppy/contracts/tours.py +505 -0
  53. steppy/coordinator.py +1352 -0
  54. steppy/coverage/__init__.py +9 -0
  55. steppy/coverage/gaps.py +190 -0
  56. steppy/coverage/manifest.py +193 -0
  57. steppy/coverage/merge.py +363 -0
  58. steppy/coverage/normalize.py +174 -0
  59. steppy/coverage/report.py +178 -0
  60. steppy/coverage/sourcemap.py +219 -0
  61. steppy/coverage/store.py +473 -0
  62. steppy/coverage/triage.py +151 -0
  63. steppy/coverage_cli.py +265 -0
  64. steppy/durations.py +48 -0
  65. steppy/exclusive.py +178 -0
  66. steppy/flaky_cli.py +169 -0
  67. steppy/generator.py +633 -0
  68. steppy/guide.py +1467 -0
  69. steppy/history.py +352 -0
  70. steppy/init_cli.py +330 -0
  71. steppy/locales.py +282 -0
  72. steppy/migrate/__init__.py +35 -0
  73. steppy/migrate/apply.py +194 -0
  74. steppy/migrate/plan.py +199 -0
  75. steppy/migrate/rules.py +465 -0
  76. steppy/migrate/verify.py +163 -0
  77. steppy/migrate_cli.py +152 -0
  78. steppy/models.py +2539 -0
  79. steppy/naming.py +37 -0
  80. steppy/parser.py +475 -0
  81. steppy/pdf.py +193 -0
  82. steppy/presets.py +284 -0
  83. steppy/record_cli.py +796 -0
  84. steppy/report/__init__.py +37 -0
  85. steppy/report/assets.py +197 -0
  86. steppy/report/build.py +261 -0
  87. steppy/report/coverage_source.py +277 -0
  88. steppy/report/model.py +423 -0
  89. steppy/report/render.py +303 -0
  90. steppy/report/source.py +238 -0
  91. steppy/report_cli.py +173 -0
  92. steppy/runmeta.py +114 -0
  93. steppy/selection.py +183 -0
  94. steppy/sitemap.py +205 -0
  95. steppy/skills/steppy-app-tours/SKILL.md +448 -0
  96. steppy/skills/steppy-ci-report/SKILL.md +567 -0
  97. steppy/skills/steppy-scenario-author/SKILL.md +2176 -0
  98. steppy/skills/steppy-template/SKILL.md +676 -0
  99. steppy/templates/_steppy_events.py +291 -0
  100. steppy/templates/_steppy_tours.py +404 -0
  101. steppy/templates/angular/component-interactive.ts.j2 +109 -0
  102. steppy/templates/angular/component-video.ts.j2 +112 -0
  103. steppy/templates/angular/component.ts.j2 +229 -0
  104. steppy/templates/angular/content.ts.j2 +31 -0
  105. steppy/templates/angular/gitignore.j2 +3 -0
  106. steppy/templates/angular/group.component.ts.j2 +39 -0
  107. steppy/templates/angular/onboarding.component.ts.j2 +43 -0
  108. steppy/templates/angular/routes.ts.j2 +34 -0
  109. steppy/templates/ci/github-actions.yml +284 -0
  110. steppy/templates/ci/gitlab-ci.yml +178 -0
  111. steppy/templates/conftest.py.j2 +2405 -0
  112. steppy/templates/guide.book.html.j2 +145 -0
  113. steppy/templates/guide.fragment.html.j2 +257 -0
  114. steppy/templates/guide.html.j2 +301 -0
  115. steppy/templates/guide.md.j2 +18 -0
  116. steppy/templates/init/config.yaml +124 -0
  117. steppy/templates/init/credentials.yaml.example +30 -0
  118. steppy/templates/init/scenarios/example--first-flow.md +53 -0
  119. steppy/templates/report/_head.html.j2 +14 -0
  120. steppy/templates/report/_mark.html.j2 +3 -0
  121. steppy/templates/report/coverage.html.j2 +124 -0
  122. steppy/templates/report/index.html.j2 +203 -0
  123. steppy/templates/report/report.css +401 -0
  124. steppy/templates/report/scenario.html.j2 +137 -0
  125. steppy/templates/static/_headers.j2 +30 -0
  126. steppy/templates/static/_mode_links.html.j2 +22 -0
  127. steppy/templates/static/_seo_head.html.j2 +37 -0
  128. steppy/templates/static/cursor.js.j2 +10 -0
  129. steppy/templates/static/group.html.j2 +78 -0
  130. steppy/templates/static/guides.css +678 -0
  131. steppy/templates/static/index.html.j2 +79 -0
  132. steppy/templates/static/interactive.html.j2 +100 -0
  133. steppy/templates/static/onboarding.html.j2 +64 -0
  134. steppy/templates/static/page.html.j2 +145 -0
  135. steppy/templates/static/robots.txt.j2 +7 -0
  136. steppy/templates/static/video.html.j2 +135 -0
  137. steppy/templates/test_scenario.py.j2 +767 -0
  138. steppy/testids.py +166 -0
  139. steppy/totp.py +26 -0
  140. steppy/tour_spec.py +163 -0
  141. steppy/tours/__init__.py +22 -0
  142. steppy/tours/actions.py +402 -0
  143. steppy/tours/compiler.py +144 -0
  144. steppy/tours/diagnostics.py +137 -0
  145. steppy/tours/emit.py +239 -0
  146. steppy/tours/ids.py +40 -0
  147. steppy/tours/inference.py +399 -0
  148. steppy/tours/model.py +120 -0
  149. steppy/tours/paths.py +126 -0
  150. steppy/tours/pipeline.py +277 -0
  151. steppy/tours/publish.py +124 -0
  152. steppy/tours/replay.py +234 -0
  153. steppy/tours/routes.py +175 -0
  154. steppy/tours/settings.py +164 -0
  155. steppy/tours/text.py +237 -0
  156. steppy/tours_cli.py +219 -0
  157. steppy/tts/__init__.py +280 -0
  158. steppy/tts/cache.py +185 -0
  159. steppy/tts/presets.py +125 -0
  160. steppy/tts/providers/__init__.py +6 -0
  161. steppy/tts/providers/http.py +184 -0
  162. steppy/tts/providers/local.py +207 -0
  163. steppy/tts/providers/null.py +28 -0
  164. steppy/tts/registry.py +201 -0
  165. steppy/tts/track.py +158 -0
  166. steppy/tts/types.py +94 -0
  167. steppy/update_cli.py +460 -0
  168. steppy/video.py +730 -0
  169. steppy/video_cache.py +239 -0
  170. steppy/video_cli.py +271 -0
  171. steppy/worker.py +301 -0
  172. steppy_dev-0.3.0.dist-info/METADATA +1335 -0
  173. steppy_dev-0.3.0.dist-info/RECORD +177 -0
  174. steppy_dev-0.3.0.dist-info/WHEEL +4 -0
  175. steppy_dev-0.3.0.dist-info/entry_points.txt +2 -0
  176. steppy_dev-0.3.0.dist-info/licenses/LICENSE +202 -0
  177. steppy_dev-0.3.0.dist-info/licenses/NOTICE +13 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"steppy-video.js","sources":["../src/cursor/types.ts","../src/manifest/content.ts","../node_modules/@lit/reactive-element/css-tag.js","../node_modules/@lit/reactive-element/reactive-element.js","../node_modules/lit-html/lit-html.js","../node_modules/lit-element/lit-element.js","../src/ui/tokens.ts","../src/templates/base-styles.ts","../src/cursor/animator.ts","../src/video/easing.ts","../src/video/timeline.ts","../src/video/stage.ts","../src/video/iife.ts"],"sourcesContent":["/**\n * Cursor data shapes — shared by the Lit player, the legacy IIFE bundle, and\n * the manifest validator. Kept dependency-free (no Zod) so the legacy IIFE\n * stays a tiny standalone bundle.\n *\n * The manifest schema in ``../manifest/schema.ts`` produces types that are\n * structurally identical to these — by design.\n */\n\nexport interface Bbox {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface Viewport {\n width: number;\n height: number;\n}\n\nexport interface SingleTarget {\n selector?: string;\n bbox: Bbox;\n}\n\nexport interface MultiTarget extends SingleTarget {\n value?: string;\n}\n\nexport type CursorBehavior =\n | { kind: 'click'; target: SingleTarget }\n | { kind: 'hover'; target: SingleTarget }\n | { kind: 'type'; target: SingleTarget; value?: string }\n | { kind: 'type-multi'; targets: MultiTarget[] };\n\nexport interface CursorTimings {\n pre_action_ms: number;\n action_ms: number;\n post_action_ms: number;\n travel_speed_px_per_ms: number;\n}\n\nexport const DEFAULT_TIMINGS: CursorTimings = {\n pre_action_ms: 200,\n action_ms: 300,\n post_action_ms: 150,\n travel_speed_px_per_ms: 1.5,\n};\n\nexport interface AnimatorFrame {\n cursor: CursorBehavior | null;\n viewport: Viewport | null;\n}\n\n/** A scaled, displayed-space rect derived from a bbox + image size + viewport. */\nexport interface DisplayRect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface DisplayScale {\n sx: number;\n sy: number;\n}\n","import type { CaptureContent, GuideManifest, ManifestStep } from './schema.js';\n\n/**\n * Resolve a step's guide text for one (locale, layout).\n *\n * Two levels, no partials: a `Capture` either carries a full `content`\n * override — the desktop/mobile twin-branch case, where the same logical step\n * is authored once per layout — or it inherits the step-level value.\n *\n * The caller must pass the layout key it also read the *frame* from. Content\n * and frame coming from the same `Capture` is the invariant that keeps a\n * viewer from ever seeing one layout's instructions above another layout's\n * screenshot; see `captureLayoutKey`.\n */\nexport function resolveStepContent(step: ManifestStep, locale: string, layoutKey: string): CaptureContent {\n const override = step.captures[locale]?.[layoutKey]?.content;\n if (override) return override;\n return {\n title: step.title?.[locale] ?? null,\n text: step.text[locale] ?? '',\n subtitle: step.subtitle?.[locale] ?? null,\n };\n}\n\n/**\n * The layout key a render should read `step.captures[locale]` under.\n *\n * Prefers the requested key, then the manifest default, then whatever the bag\n * actually holds. The schema guarantees the full (locale × layout)\n * cross-product, so the first branch is the live path; the rest only matter\n * when a host sets an unrecognised `variant`, and they exist so the fallback\n * lands on the manifest's own default rather than on object insertion order.\n */\nexport function captureLayoutKey(\n step: ManifestStep,\n locale: string,\n requested: string | null,\n manifest: Pick<GuideManifest, 'layouts' | 'defaultLayout'>,\n): string | null {\n const bag = step.captures[locale];\n if (!bag) return null;\n if (requested && requested in bag) return requested;\n const fallback = manifest.defaultLayout ?? manifest.layouts[0] ?? '_';\n if (fallback in bag) return fallback;\n return Object.keys(bag)[0] ?? null;\n}\n","/**\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\nconst t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow)&&\"adoptedStyleSheets\"in Document.prototype&&\"replace\"in CSSStyleSheet.prototype,s=Symbol(),o=new WeakMap;class n{constructor(t,e,o){if(this._$cssResult$=!0,o!==s)throw Error(\"CSSResult is not constructable. Use `unsafeCSS` or `css` instead.\");this.cssText=t,this.t=e}get styleSheet(){let t=this.o;const s=this.t;if(e&&void 0===t){const e=void 0!==s&&1===s.length;e&&(t=o.get(s)),void 0===t&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),e&&o.set(s,t))}return t}toString(){return this.cssText}}const r=t=>new n(\"string\"==typeof t?t:t+\"\",void 0,s),i=(t,...e)=>{const o=1===t.length?t[0]:e.reduce((e,s,o)=>e+(t=>{if(!0===t._$cssResult$)return t.cssText;if(\"number\"==typeof t)return t;throw Error(\"Value passed to 'css' function must be a 'css' function result: \"+t+\". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.\")})(s)+t[o+1],t[0]);return new n(o,t,s)},S=(s,o)=>{if(e)s.adoptedStyleSheets=o.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(const e of o){const o=document.createElement(\"style\"),n=t.litNonce;void 0!==n&&o.setAttribute(\"nonce\",n),o.textContent=e.cssText,s.appendChild(o)}},c=e?t=>t:t=>t instanceof CSSStyleSheet?(t=>{let e=\"\";for(const s of t.cssRules)e+=s.cssText;return r(e)})(t):t;export{n as CSSResult,S as adoptStyles,i as css,c as getCompatibleStyle,e as supportsAdoptingStyleSheets,r as unsafeCSS};\n//# sourceMappingURL=css-tag.js.map\n","import{getCompatibleStyle as t,adoptStyles as s}from\"./css-tag.js\";export{CSSResult,css,supportsAdoptingStyleSheets,unsafeCSS}from\"./css-tag.js\";\n/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */const{is:i,defineProperty:e,getOwnPropertyDescriptor:h,getOwnPropertyNames:r,getOwnPropertySymbols:o,getPrototypeOf:n}=Object,a=globalThis,c=a.trustedTypes,l=c?c.emptyScript:\"\",p=a.reactiveElementPolyfillSupport,d=(t,s)=>t,u={toAttribute(t,s){switch(s){case Boolean:t=t?l:null;break;case Object:case Array:t=null==t?t:JSON.stringify(t)}return t},fromAttribute(t,s){let i=t;switch(s){case Boolean:i=null!==t;break;case Number:i=null===t?null:Number(t);break;case Object:case Array:try{i=JSON.parse(t)}catch(t){i=null}}return i}},f=(t,s)=>!i(t,s),b={attribute:!0,type:String,converter:u,reflect:!1,useDefault:!1,hasChanged:f};Symbol.metadata??=Symbol(\"metadata\"),a.litPropertyMetadata??=new WeakMap;class y extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,s=b){if(s.state&&(s.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(t)&&((s=Object.create(s)).wrapped=!0),this.elementProperties.set(t,s),!s.noAccessor){const i=Symbol(),h=this.getPropertyDescriptor(t,i,s);void 0!==h&&e(this.prototype,t,h)}}static getPropertyDescriptor(t,s,i){const{get:e,set:r}=h(this.prototype,t)??{get(){return this[s]},set(t){this[s]=t}};return{get:e,set(s){const h=e?.call(this);r?.call(this,s),this.requestUpdate(t,h,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this.elementProperties.get(t)??b}static _$Ei(){if(this.hasOwnProperty(d(\"elementProperties\")))return;const t=n(this);t.finalize(),void 0!==t.l&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties)}static finalize(){if(this.hasOwnProperty(d(\"finalized\")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(d(\"properties\"))){const t=this.properties,s=[...r(t),...o(t)];for(const i of s)this.createProperty(i,t[i])}const t=this[Symbol.metadata];if(null!==t){const s=litPropertyMetadata.get(t);if(void 0!==s)for(const[t,i]of s)this.elementProperties.set(t,i)}this._$Eh=new Map;for(const[t,s]of this.elementProperties){const i=this._$Eu(t,s);void 0!==i&&this._$Eh.set(i,t)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(s){const i=[];if(Array.isArray(s)){const e=new Set(s.flat(1/0).reverse());for(const s of e)i.unshift(t(s))}else void 0!==s&&i.push(t(s));return i}static _$Eu(t,s){const i=s.attribute;return!1===i?void 0:\"string\"==typeof i?i:\"string\"==typeof t?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(t=>this.enableUpdating=t),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(t=>t(this))}addController(t){(this._$EO??=new Set).add(t),void 0!==this.renderRoot&&this.isConnected&&t.hostConnected?.()}removeController(t){this._$EO?.delete(t)}_$E_(){const t=new Map,s=this.constructor.elementProperties;for(const i of s.keys())this.hasOwnProperty(i)&&(t.set(i,this[i]),delete this[i]);t.size>0&&(this._$Ep=t)}createRenderRoot(){const t=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return s(t,this.constructor.elementStyles),t}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(t=>t.hostConnected?.())}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach(t=>t.hostDisconnected?.())}attributeChangedCallback(t,s,i){this._$AK(t,i)}_$ET(t,s){const i=this.constructor.elementProperties.get(t),e=this.constructor._$Eu(t,i);if(void 0!==e&&!0===i.reflect){const h=(void 0!==i.converter?.toAttribute?i.converter:u).toAttribute(s,i.type);this._$Em=t,null==h?this.removeAttribute(e):this.setAttribute(e,h),this._$Em=null}}_$AK(t,s){const i=this.constructor,e=i._$Eh.get(t);if(void 0!==e&&this._$Em!==e){const t=i.getPropertyOptions(e),h=\"function\"==typeof t.converter?{fromAttribute:t.converter}:void 0!==t.converter?.fromAttribute?t.converter:u;this._$Em=e;const r=h.fromAttribute(s,t.type);this[e]=r??this._$Ej?.get(e)??r,this._$Em=null}}requestUpdate(t,s,i,e=!1,h){if(void 0!==t){const r=this.constructor;if(!1===e&&(h=this[t]),i??=r.getPropertyOptions(t),!((i.hasChanged??f)(h,s)||i.useDefault&&i.reflect&&h===this._$Ej?.get(t)&&!this.hasAttribute(r._$Eu(t,i))))return;this.C(t,s,i)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(t,s,{useDefault:i,reflect:e,wrapped:h},r){i&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,r??s??this[t]),!0!==h||void 0!==r)||(this._$AL.has(t)||(this.hasUpdated||i||(s=void 0),this._$AL.set(t,s)),!0===e&&this._$Em!==t&&(this._$Eq??=new Set).add(t))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(t){Promise.reject(t)}const t=this.scheduleUpdate();return null!=t&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[t,s]of this._$Ep)this[t]=s;this._$Ep=void 0}const t=this.constructor.elementProperties;if(t.size>0)for(const[s,i]of t){const{wrapped:t}=i,e=this[s];!0!==t||this._$AL.has(s)||void 0===e||this.C(s,void 0,i,e)}}let t=!1;const s=this._$AL;try{t=this.shouldUpdate(s),t?(this.willUpdate(s),this._$EO?.forEach(t=>t.hostUpdate?.()),this.update(s)):this._$EM()}catch(s){throw t=!1,this._$EM(),s}t&&this._$AE(s)}willUpdate(t){}_$AE(t){this._$EO?.forEach(t=>t.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(t)),this.updated(t)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return!0}update(t){this._$Eq&&=this._$Eq.forEach(t=>this._$ET(t,this[t])),this._$EM()}updated(t){}firstUpdated(t){}}y.elementStyles=[],y.shadowRootOptions={mode:\"open\"},y[d(\"elementProperties\")]=new Map,y[d(\"finalized\")]=new Map,p?.({ReactiveElement:y}),(a.reactiveElementVersions??=[]).push(\"2.1.2\");export{y as ReactiveElement,s as adoptStyles,u as defaultConverter,t as getCompatibleStyle,f as notEqual};\n//# sourceMappingURL=reactive-element.js.map\n","/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\nconst t=globalThis,i=t=>t,s=t.trustedTypes,e=s?s.createPolicy(\"lit-html\",{createHTML:t=>t}):void 0,h=\"$lit$\",o=`lit$${Math.random().toFixed(9).slice(2)}$`,n=\"?\"+o,r=`<${n}>`,l=document,c=()=>l.createComment(\"\"),a=t=>null===t||\"object\"!=typeof t&&\"function\"!=typeof t,u=Array.isArray,d=t=>u(t)||\"function\"==typeof t?.[Symbol.iterator],f=\"[ \\t\\n\\f\\r]\",v=/<(?:(!--|\\/[^a-zA-Z])|(\\/?[a-zA-Z][^>\\s]*)|(\\/?$))/g,_=/-->/g,m=/>/g,p=RegExp(`>|${f}(?:([^\\\\s\"'>=/]+)(${f}*=${f}*(?:[^ \\t\\n\\f\\r\"'\\`<>=]|(\"|')|))|$)`,\"g\"),g=/'/g,$=/\"/g,y=/^(?:script|style|textarea|title)$/i,x=t=>(i,...s)=>({_$litType$:t,strings:i,values:s}),b=x(1),w=x(2),T=x(3),E=Symbol.for(\"lit-noChange\"),A=Symbol.for(\"lit-nothing\"),C=new WeakMap,P=l.createTreeWalker(l,129);function V(t,i){if(!u(t)||!t.hasOwnProperty(\"raw\"))throw Error(\"invalid template strings array\");return void 0!==e?e.createHTML(i):i}const N=(t,i)=>{const s=t.length-1,e=[];let n,l=2===i?\"<svg>\":3===i?\"<math>\":\"\",c=v;for(let i=0;i<s;i++){const s=t[i];let a,u,d=-1,f=0;for(;f<s.length&&(c.lastIndex=f,u=c.exec(s),null!==u);)f=c.lastIndex,c===v?\"!--\"===u[1]?c=_:void 0!==u[1]?c=m:void 0!==u[2]?(y.test(u[2])&&(n=RegExp(\"</\"+u[2],\"g\")),c=p):void 0!==u[3]&&(c=p):c===p?\">\"===u[0]?(c=n??v,d=-1):void 0===u[1]?d=-2:(d=c.lastIndex-u[2].length,a=u[1],c=void 0===u[3]?p:'\"'===u[3]?$:g):c===$||c===g?c=p:c===_||c===m?c=v:(c=p,n=void 0);const x=c===p&&t[i+1].startsWith(\"/>\")?\" \":\"\";l+=c===v?s+r:d>=0?(e.push(a),s.slice(0,d)+h+s.slice(d)+o+x):s+o+(-2===d?i:x)}return[V(t,l+(t[s]||\"<?>\")+(2===i?\"</svg>\":3===i?\"</math>\":\"\")),e]};class S{constructor({strings:t,_$litType$:i},e){let r;this.parts=[];let l=0,a=0;const u=t.length-1,d=this.parts,[f,v]=N(t,i);if(this.el=S.createElement(f,e),P.currentNode=this.el.content,2===i||3===i){const t=this.el.content.firstChild;t.replaceWith(...t.childNodes)}for(;null!==(r=P.nextNode())&&d.length<u;){if(1===r.nodeType){if(r.hasAttributes())for(const t of r.getAttributeNames())if(t.endsWith(h)){const i=v[a++],s=r.getAttribute(t).split(o),e=/([.?@])?(.*)/.exec(i);d.push({type:1,index:l,name:e[2],strings:s,ctor:\".\"===e[1]?I:\"?\"===e[1]?L:\"@\"===e[1]?z:H}),r.removeAttribute(t)}else t.startsWith(o)&&(d.push({type:6,index:l}),r.removeAttribute(t));if(y.test(r.tagName)){const t=r.textContent.split(o),i=t.length-1;if(i>0){r.textContent=s?s.emptyScript:\"\";for(let s=0;s<i;s++)r.append(t[s],c()),P.nextNode(),d.push({type:2,index:++l});r.append(t[i],c())}}}else if(8===r.nodeType)if(r.data===n)d.push({type:2,index:l});else{let t=-1;for(;-1!==(t=r.data.indexOf(o,t+1));)d.push({type:7,index:l}),t+=o.length-1}l++}}static createElement(t,i){const s=l.createElement(\"template\");return s.innerHTML=t,s}}function M(t,i,s=t,e){if(i===E)return i;let h=void 0!==e?s._$Co?.[e]:s._$Cl;const o=a(i)?void 0:i._$litDirective$;return h?.constructor!==o&&(h?._$AO?.(!1),void 0===o?h=void 0:(h=new o(t),h._$AT(t,s,e)),void 0!==e?(s._$Co??=[])[e]=h:s._$Cl=h),void 0!==h&&(i=M(t,h._$AS(t,i.values),h,e)),i}class R{constructor(t,i){this._$AV=[],this._$AN=void 0,this._$AD=t,this._$AM=i}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(t){const{el:{content:i},parts:s}=this._$AD,e=(t?.creationScope??l).importNode(i,!0);P.currentNode=e;let h=P.nextNode(),o=0,n=0,r=s[0];for(;void 0!==r;){if(o===r.index){let i;2===r.type?i=new k(h,h.nextSibling,this,t):1===r.type?i=new r.ctor(h,r.name,r.strings,this,t):6===r.type&&(i=new Z(h,this,t)),this._$AV.push(i),r=s[++n]}o!==r?.index&&(h=P.nextNode(),o++)}return P.currentNode=l,e}p(t){let i=0;for(const s of this._$AV)void 0!==s&&(void 0!==s.strings?(s._$AI(t,s,i),i+=s.strings.length-2):s._$AI(t[i])),i++}}class k{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(t,i,s,e){this.type=2,this._$AH=A,this._$AN=void 0,this._$AA=t,this._$AB=i,this._$AM=s,this.options=e,this._$Cv=e?.isConnected??!0}get parentNode(){let t=this._$AA.parentNode;const i=this._$AM;return void 0!==i&&11===t?.nodeType&&(t=i.parentNode),t}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(t,i=this){t=M(this,t,i),a(t)?t===A||null==t||\"\"===t?(this._$AH!==A&&this._$AR(),this._$AH=A):t!==this._$AH&&t!==E&&this._(t):void 0!==t._$litType$?this.$(t):void 0!==t.nodeType?this.T(t):d(t)?this.k(t):this._(t)}O(t){return this._$AA.parentNode.insertBefore(t,this._$AB)}T(t){this._$AH!==t&&(this._$AR(),this._$AH=this.O(t))}_(t){this._$AH!==A&&a(this._$AH)?this._$AA.nextSibling.data=t:this.T(l.createTextNode(t)),this._$AH=t}$(t){const{values:i,_$litType$:s}=t,e=\"number\"==typeof s?this._$AC(t):(void 0===s.el&&(s.el=S.createElement(V(s.h,s.h[0]),this.options)),s);if(this._$AH?._$AD===e)this._$AH.p(i);else{const t=new R(e,this),s=t.u(this.options);t.p(i),this.T(s),this._$AH=t}}_$AC(t){let i=C.get(t.strings);return void 0===i&&C.set(t.strings,i=new S(t)),i}k(t){u(this._$AH)||(this._$AH=[],this._$AR());const i=this._$AH;let s,e=0;for(const h of t)e===i.length?i.push(s=new k(this.O(c()),this.O(c()),this,this.options)):s=i[e],s._$AI(h),e++;e<i.length&&(this._$AR(s&&s._$AB.nextSibling,e),i.length=e)}_$AR(t=this._$AA.nextSibling,s){for(this._$AP?.(!1,!0,s);t!==this._$AB;){const s=i(t).nextSibling;i(t).remove(),t=s}}setConnected(t){void 0===this._$AM&&(this._$Cv=t,this._$AP?.(t))}}class H{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(t,i,s,e,h){this.type=1,this._$AH=A,this._$AN=void 0,this.element=t,this.name=i,this._$AM=e,this.options=h,s.length>2||\"\"!==s[0]||\"\"!==s[1]?(this._$AH=Array(s.length-1).fill(new String),this.strings=s):this._$AH=A}_$AI(t,i=this,s,e){const h=this.strings;let o=!1;if(void 0===h)t=M(this,t,i,0),o=!a(t)||t!==this._$AH&&t!==E,o&&(this._$AH=t);else{const e=t;let n,r;for(t=h[0],n=0;n<h.length-1;n++)r=M(this,e[s+n],i,n),r===E&&(r=this._$AH[n]),o||=!a(r)||r!==this._$AH[n],r===A?t=A:t!==A&&(t+=(r??\"\")+h[n+1]),this._$AH[n]=r}o&&!e&&this.j(t)}j(t){t===A?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,t??\"\")}}class I extends H{constructor(){super(...arguments),this.type=3}j(t){this.element[this.name]=t===A?void 0:t}}class L extends H{constructor(){super(...arguments),this.type=4}j(t){this.element.toggleAttribute(this.name,!!t&&t!==A)}}class z extends H{constructor(t,i,s,e,h){super(t,i,s,e,h),this.type=5}_$AI(t,i=this){if((t=M(this,t,i,0)??A)===E)return;const s=this._$AH,e=t===A&&s!==A||t.capture!==s.capture||t.once!==s.once||t.passive!==s.passive,h=t!==A&&(s===A||e);e&&this.element.removeEventListener(this.name,this,s),h&&this.element.addEventListener(this.name,this,t),this._$AH=t}handleEvent(t){\"function\"==typeof this._$AH?this._$AH.call(this.options?.host??this.element,t):this._$AH.handleEvent(t)}}class Z{constructor(t,i,s){this.element=t,this.type=6,this._$AN=void 0,this._$AM=i,this.options=s}get _$AU(){return this._$AM._$AU}_$AI(t){M(this,t)}}const j={M:h,P:o,A:n,C:1,L:N,R,D:d,V:M,I:k,H,N:L,U:z,B:I,F:Z},B=t.litHtmlPolyfillSupport;B?.(S,k),(t.litHtmlVersions??=[]).push(\"3.3.3\");const D=(t,i,s)=>{const e=s?.renderBefore??i;let h=e._$litPart$;if(void 0===h){const t=s?.renderBefore??null;e._$litPart$=h=new k(i.insertBefore(c(),t),t,void 0,s??{})}return h._$AI(t),h};export{j as _$LH,b as html,T as mathml,E as noChange,A as nothing,D as render,w as svg};\n//# sourceMappingURL=lit-html.js.map\n","import{ReactiveElement as t}from\"@lit/reactive-element\";export*from\"@lit/reactive-element\";import{render as e,noChange as r}from\"lit-html\";export*from\"lit-html\";\n/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */const s=globalThis;class i extends t{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){const t=super.createRenderRoot();return this.renderOptions.renderBefore??=t.firstChild,t}update(t){const r=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(t),this._$Do=e(r,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return r}}i._$litElement$=!0,i[\"finalized\"]=!0,s.litElementHydrateSupport?.({LitElement:i});const o=s.litElementPolyfillSupport;o?.({LitElement:i});const n={_$AK:(t,e,r)=>{t._$AK(e,r)},_$AL:t=>t._$AL};(s.litElementVersions??=[]).push(\"4.2.2\");export{i as LitElement,n as _$LE};\n//# sourceMappingURL=lit-element.js.map\n","/**\n * Default look values shared by the guide player and the in-app tour overlay.\n *\n * Constants only, never data: they are interpolated into the ``css`` tagged\n * templates with ``cssValue`` (Lit's ``unsafeCSS``), which concatenates the\n * value verbatim — ``baseStyles.cssText`` is byte-identical to the literal\n * stylesheet it replaced (guard: ``test/ui/guide-styles-stable.test.ts``).\n */\n\nimport { unsafeCSS, type CSSResult } from 'lit';\n\n/** The guide's palette (``--steppy-*`` defaults in ``templates/base-styles.ts``). */\nexport const PALETTE = {\n bg: '#f4f1ea',\n surface: '#fbf9f4',\n chromeBg: '#efece3',\n fg: '#1f1d1a',\n muted: '#8a857c',\n border: '#e1ddd1',\n accent: '#d24f2c',\n accentWeak: 'rgba(210, 79, 44, 0.35)',\n success: '#3a7d44',\n} as const;\n\n/** System font stacks only: offline, no CDN. */\nexport const FONTS = {\n serif: \"ui-serif, Georgia, 'Times New Roman', serif\",\n sans: \"system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif\",\n mono: 'ui-monospace, SFMono-Regular, Menlo, Consolas, monospace',\n} as const;\n\n/** The dark bubble both players draw next to a target (guide tooltip, tour popover). */\nexport const BUBBLE_LOOK = {\n padding: '8px 12px',\n radius: '6px',\n maxWidth: '280px',\n fontSize: '14px',\n lineHeight: '1.4',\n shadow: '0 4px 12px rgba(0, 0, 0, 0.2)',\n} as const;\n\nexport const BUTTON_LOOK = {\n radius: '4px',\n padding: '4px 10px',\n} as const;\n\n/**\n * Tour overlay defaults. The accent differs from the guide's on purpose:\n * ``#d24f2c`` measures 4.29:1 against white text, below WCAG AA for the\n * overlay's buttons; ``#a8410e`` measures 6.13:1 (guard: ``test/tour/small-modules.test.ts``).\n */\nexport const TOUR_DEFAULTS = {\n bubbleBg: PALETTE.fg,\n bubbleFg: PALETTE.surface,\n muted: '#c9c5bd',\n accent: '#a8410e',\n accentFg: '#ffffff',\n focus: '#f09a6a',\n scrim: 'rgba(31, 29, 26, 0.45)',\n radius: BUBBLE_LOOK.radius,\n} as const;\n\n/** A token value inside a ``css`` template (inserted verbatim, never data). */\nexport const cssValue = (value: string | number): CSSResult => unsafeCSS(value);\n","/**\n * Shared player styles: design tokens, the screenshot stage + cursor/ripple/\n * kbd/hotspot/tooltip, status/error blocks, and the shared chrome control\n * primitives (buttons, selects, segmented control) every template composes.\n *\n * Design language: warm cream surfaces, near-black text, rust-orange accent,\n * green for completed steps. Serif titles, sans body, mono meta/counters. All\n * theming flows through CSS custom properties on ``:host`` so the player stays\n * overridable; fonts use system stacks only (offline, no CDN).\n *\n * The historical engine variable names (``--steppy-hotspot-color`` etc.) are\n * preserved and merely re-pointed at the new palette so existing host overrides\n * keep working.\n */\n\nimport { css } from 'lit';\n\nimport { BUBBLE_LOOK, BUTTON_LOOK, FONTS, PALETTE, cssValue } from '../ui/tokens.js';\n\nexport const baseStyles = css`\n :host {\n display: block;\n position: relative;\n /* palette */\n --steppy-bg: ${cssValue(PALETTE.bg)};\n --steppy-surface: ${cssValue(PALETTE.surface)};\n --steppy-chrome-bg: ${cssValue(PALETTE.chromeBg)};\n --steppy-fg: ${cssValue(PALETTE.fg)};\n --steppy-muted: ${cssValue(PALETTE.muted)};\n --steppy-border: ${cssValue(PALETTE.border)};\n --steppy-accent: ${cssValue(PALETTE.accent)};\n --steppy-accent-weak: ${cssValue(PALETTE.accentWeak)};\n --steppy-success: ${cssValue(PALETTE.success)};\n /* typography */\n --steppy-font-serif: ${cssValue(FONTS.serif)};\n --steppy-font-sans: ${cssValue(FONTS.sans)};\n --steppy-font-mono: ${cssValue(FONTS.mono)};\n --steppy-font-family: var(--steppy-font-sans);\n /* engine vars (names preserved, re-pointed at the palette) */\n --steppy-cursor-size: 24px;\n --steppy-cursor-color: var(--steppy-fg);\n --steppy-ripple-color: rgba(31, 29, 26, 0.25);\n --steppy-hotspot-color: var(--steppy-accent);\n --steppy-hotspot-glow: var(--steppy-accent-weak);\n --steppy-tooltip-bg: var(--steppy-fg);\n --steppy-tooltip-fg: var(--steppy-surface);\n\n font-family: var(--steppy-font-family);\n color: var(--steppy-fg);\n }\n\n .steppy-wrapper {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n /* ── Stage ─────────────────────────────────────────────────────────── */\n .steppy-stage {\n position: relative;\n width: 100%;\n background: var(--steppy-chrome-bg);\n overflow: hidden;\n border-radius: 8px;\n user-select: none;\n }\n .steppy-stage img {\n display: block;\n /* width:auto caps display at the screenshot's intrinsic pixel width (never\n upscales), max-width:100% fills/shrinks within the stage. A dense capture\n (mobile device_scale_factor=3) downscales to fill the stage crisply; a\n low-res capture renders at native size instead of blurred. The img stays\n left-aligned (no centering) so the cursor/hotspot overlay — positioned in\n img-display-space with the stage top-left as origin — stays aligned. */\n width: auto;\n max-width: 100%;\n height: auto;\n pointer-events: none;\n }\n .steppy-cursor {\n position: absolute;\n top: 0;\n left: 0;\n width: var(--steppy-cursor-size);\n height: var(--steppy-cursor-size);\n pointer-events: none;\n opacity: 0;\n transition: opacity 200ms ease-in-out;\n background: var(--steppy-cursor-color);\n clip-path: polygon(0 0, 0 75%, 25% 55%, 45% 95%, 60% 85%, 40% 50%, 75% 40%);\n filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.3));\n transform-origin: 0 0;\n z-index: 4;\n }\n .steppy-cursor.visible {\n opacity: 1;\n }\n .steppy-cursor.pulse {\n animation: steppy-pulse 200ms ease-in-out;\n }\n @keyframes steppy-pulse {\n 0%,\n 100% {\n transform: scale(1);\n }\n 50% {\n transform: scale(1.25);\n }\n }\n .steppy-ripple {\n position: absolute;\n top: 0;\n left: 0;\n width: 12px;\n height: 12px;\n margin: -6px;\n border-radius: 50%;\n background: transparent;\n border: 2px solid var(--steppy-ripple-color);\n pointer-events: none;\n opacity: 0;\n z-index: 3;\n }\n .steppy-ripple.fire {\n animation: steppy-ripple 400ms ease-out forwards;\n }\n @keyframes steppy-ripple {\n 0% {\n transform: scale(0.6);\n opacity: 1;\n }\n 100% {\n transform: scale(3);\n opacity: 0;\n }\n }\n .steppy-kbd {\n position: absolute;\n top: 0;\n left: 0;\n background: var(--steppy-fg);\n color: var(--steppy-surface);\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 12px;\n font-family: var(--steppy-font-mono);\n opacity: 0;\n transition: opacity 120ms;\n pointer-events: none;\n z-index: 5;\n }\n .steppy-kbd.visible {\n opacity: 1;\n }\n .steppy-hotspot {\n position: absolute;\n box-sizing: border-box;\n background: transparent;\n border: 2px solid var(--steppy-hotspot-color);\n border-radius: 4px;\n cursor: pointer;\n padding: 0;\n z-index: 2;\n transition: outline-offset 120ms;\n animation: steppy-hotspot-pulse 1500ms ease-in-out infinite;\n box-shadow: 0 0 0 4px var(--steppy-hotspot-glow);\n }\n .steppy-hotspot:focus-visible {\n outline: 3px solid var(--steppy-hotspot-color);\n outline-offset: 4px;\n }\n .steppy-hotspot.miss {\n animation: steppy-hotspot-shake 400ms;\n }\n @keyframes steppy-hotspot-pulse {\n 0%,\n 100% {\n box-shadow: 0 0 0 4px var(--steppy-hotspot-glow);\n }\n 50% {\n box-shadow: 0 0 0 10px transparent;\n }\n }\n @keyframes steppy-hotspot-shake {\n 0%,\n 100% {\n transform: translateX(0);\n }\n 25% {\n transform: translateX(-6px);\n }\n 75% {\n transform: translateX(6px);\n }\n }\n .steppy-tooltip {\n position: absolute;\n background: var(--steppy-tooltip-bg);\n color: var(--steppy-tooltip-fg);\n padding: ${cssValue(BUBBLE_LOOK.padding)};\n border-radius: ${cssValue(BUBBLE_LOOK.radius)};\n max-width: ${cssValue(BUBBLE_LOOK.maxWidth)};\n font-size: ${cssValue(BUBBLE_LOOK.fontSize)};\n line-height: ${cssValue(BUBBLE_LOOK.lineHeight)};\n z-index: 6;\n pointer-events: none;\n box-shadow: ${cssValue(BUBBLE_LOOK.shadow)};\n }\n .steppy-miss-toast {\n position: absolute;\n left: 50%;\n transform: translateX(-50%);\n bottom: 16px;\n background: var(--steppy-fg);\n color: var(--steppy-surface);\n padding: 6px 14px;\n border-radius: 999px;\n font-size: 13px;\n z-index: 7;\n pointer-events: none;\n animation: steppy-toast 1400ms ease-out forwards;\n }\n @keyframes steppy-toast {\n 0%,\n 80% {\n opacity: 1;\n }\n 100% {\n opacity: 0;\n }\n }\n .steppy-stage-click-catcher {\n position: absolute;\n inset: 0;\n z-index: 1;\n cursor: default;\n }\n\n /* ── Status / error ────────────────────────────────────────────────── */\n .steppy-state {\n padding: 24px;\n text-align: center;\n color: var(--steppy-muted);\n }\n .steppy-state.error {\n color: #b3402a;\n background: #fbeae6;\n border-radius: 6px;\n }\n .steppy-state .steppy-state-detail {\n font-size: 12px;\n margin-top: 8px;\n font-family: var(--steppy-font-mono);\n white-space: pre-wrap;\n text-align: left;\n max-height: 200px;\n overflow: auto;\n }\n\n /* ── Shared chrome controls ────────────────────────────────────────── */\n .steppy-chrome {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-wrap: wrap;\n background: var(--steppy-chrome-bg);\n padding: 8px 12px;\n border-radius: 6px;\n font-size: 14px;\n }\n .steppy-progress {\n margin-right: auto;\n font-family: var(--steppy-font-mono);\n font-variant-numeric: tabular-nums;\n color: var(--steppy-muted);\n }\n .steppy-btn {\n font: inherit;\n background: var(--steppy-surface);\n border: 1px solid var(--steppy-border);\n border-radius: ${cssValue(BUTTON_LOOK.radius)};\n padding: ${cssValue(BUTTON_LOOK.padding)};\n cursor: pointer;\n color: var(--steppy-fg);\n }\n .steppy-btn:hover:not(:disabled) {\n border-color: var(--steppy-muted);\n }\n .steppy-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n .steppy-field {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n color: var(--steppy-muted);\n }\n .steppy-field select {\n font: inherit;\n background: var(--steppy-surface);\n border: 1px solid var(--steppy-border);\n border-radius: 4px;\n padding: 4px 8px;\n cursor: pointer;\n color: var(--steppy-fg);\n }\n /* Segmented control (pill container; active = dark fill + light text). */\n .steppy-seg {\n display: inline-flex;\n background: var(--steppy-bg);\n border: 1px solid var(--steppy-border);\n border-radius: 999px;\n padding: 2px;\n gap: 2px;\n }\n .steppy-seg-btn {\n font: inherit;\n font-size: 13px;\n border: 0;\n background: transparent;\n color: var(--steppy-muted);\n padding: 3px 12px;\n border-radius: 999px;\n cursor: pointer;\n }\n .steppy-seg-btn[aria-current='true'] {\n background: var(--steppy-fg);\n color: var(--steppy-surface);\n }\n .steppy-seg-btn:focus-visible {\n outline: 2px solid var(--steppy-accent);\n outline-offset: 1px;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .steppy-cursor,\n .steppy-cursor.pulse,\n .steppy-ripple.fire,\n .steppy-hotspot,\n .steppy-hotspot.miss,\n .steppy-miss-toast {\n animation: none !important;\n transition: none !important;\n }\n }\n`;\n","/**\n * Cursor animation — canonical TS port of the inline JS that previously lived\n * in ``templates/static/cursor.js.j2`` and ``templates/guide.html.j2``. Both\n * the new ``<steppy-guide>`` Lit element and the legacy stepbystep templates\n * consume this module (the latter via ``legacy-iife.ts``).\n *\n * Two animation modes are supported off the same primitives:\n *\n * - **Full frame** (stepbystep): ``animateFrame(frame)`` walks every target in\n * the frame and runs travel → pre-action → action → post-action without\n * pause. Matches the historical behavior of the inline JS.\n * - **Interactive** (the new player): ``travelToTarget`` /\n * ``playTargetAction`` split the sequence so the player can wait for the\n * user to click a hotspot between phases.\n *\n * The animator owns the cursor / ripple / kbd DOM elements (it does not\n * create them — the host provides them via ``opts.stage`` and the elements\n * inside that stage). Coordinates are scaled at animation time from the\n * frame's capture-space viewport to the displayed image size; this is the\n * single point where capture-space → display-space conversion happens.\n */\n\nimport {\n AnimatorFrame,\n Bbox,\n CursorBehavior,\n CursorTimings,\n DEFAULT_TIMINGS,\n DisplayRect,\n DisplayScale,\n MultiTarget,\n SingleTarget,\n Viewport,\n} from './types.js';\n\nexport type TargetKind = 'click' | 'hover' | 'type';\n\nexport interface NormalizedTarget {\n bbox: Bbox;\n value?: string;\n selector?: string;\n kind: TargetKind;\n}\n\nconst sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));\n\nexport function easeInOut(t: number): number {\n // Smoothstep — symmetric S-curve, matches the legacy inline JS.\n return t * t * (3 - 2 * t);\n}\n\nexport function getDisplayScale(\n img: HTMLElement,\n viewport: Viewport | null | undefined,\n): DisplayScale | null {\n if (!viewport || !viewport.width || !viewport.height) return null;\n const rect = img.getBoundingClientRect();\n if (!rect.width || !rect.height) return null;\n return { sx: rect.width / viewport.width, sy: rect.height / viewport.height };\n}\n\nexport function scaleRect(bbox: Bbox, scale: DisplayScale): DisplayRect {\n return {\n x: bbox.x * scale.sx,\n y: bbox.y * scale.sy,\n width: bbox.width * scale.sx,\n height: bbox.height * scale.sy,\n };\n}\n\nexport function rectCenter(rect: DisplayRect): { x: number; y: number } {\n return { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 };\n}\n\n/**\n * Legacy entry point preserved verbatim for the IIFE bundle: capture-space\n * bbox + image + viewport → display-space center point.\n */\nexport function scaleBbox(\n bbox: Bbox | null | undefined,\n img: HTMLElement,\n viewport: Viewport | null | undefined,\n): { x: number; y: number } | null {\n if (!bbox) return null;\n const scale = getDisplayScale(img, viewport);\n if (!scale) return null;\n return rectCenter(scaleRect(bbox, scale));\n}\n\n/**\n * Quadratic-Bezier travel duration. Pulled out so it's unit-testable\n * without DOM. ``speed`` is in capture-space px per ms.\n */\nexport function travelDuration(\n from: { x: number; y: number },\n to: { x: number; y: number },\n speed: number,\n): number {\n const dx = to.x - from.x;\n const dy = to.y - from.y;\n const dist = Math.hypot(dx, dy);\n return Math.max(150, dist / (speed || 1.5));\n}\n\n/**\n * Compute a quadratic-Bezier control point offset 15% perpendicular to the\n * straight line between ``from`` and ``to``. Same formula the inline JS uses.\n */\nexport function bezierControlPoint(\n from: { x: number; y: number },\n to: { x: number; y: number },\n): { x: number; y: number } {\n const dx = to.x - from.x;\n const dy = to.y - from.y;\n const dist = Math.hypot(dx, dy);\n if (!dist) return { x: from.x, y: from.y };\n const mx = (from.x + to.x) / 2;\n const my = (from.y + to.y) / 2;\n const nx = -dy / dist;\n const ny = dx / dist;\n return { x: mx + nx * dist * 0.15, y: my + ny * dist * 0.15 };\n}\n\nexport interface AnimatorOptions {\n /** The stage element. Must contain ``.steppy-cursor``, ``.steppy-ripple``,\n * ``.steppy-kbd`` descendants and a single ``img`` (the screenshot). */\n stage: HTMLElement;\n timings?: Partial<CursorTimings>;\n /** Hook called when the cursor moves to or fires on a target. Used by the\n * Lit player to broadcast progress events. */\n onPhaseChange?: (phase: 'travel' | 'pre-action' | 'action' | 'post-action' | 'idle', target?: NormalizedTarget) => void;\n}\n\nexport class CursorAnimator {\n private stage: HTMLElement;\n private timings: CursorTimings;\n private onPhaseChange: AnimatorOptions['onPhaseChange'];\n private cursorEl: HTMLElement | null = null;\n private rippleEl: HTMLElement | null = null;\n private kbdEl: HTMLElement | null = null;\n private imgEl: HTMLElement | null = null;\n private currentPos: { x: number; y: number } = { x: 8, y: 8 };\n private aborted = false;\n\n constructor(opts: AnimatorOptions) {\n this.stage = opts.stage;\n this.timings = { ...DEFAULT_TIMINGS, ...(opts.timings ?? {}) };\n this.onPhaseChange = opts.onPhaseChange;\n this.refreshDom();\n }\n\n setTimings(t: Partial<CursorTimings>): void {\n this.timings = { ...this.timings, ...t };\n }\n\n /** Re-point the animator at a (possibly relocated) stage element and re-read\n * its children. Needed when a host re-mounts the stage subtree — e.g. the\n * Lit player switching presentation templates moves ``.steppy-stage`` to a\n * new DOM position, and the cached ``stage`` ref would otherwise go stale. */\n setStage(stage: HTMLElement): void {\n this.stage = stage;\n this.refreshDom();\n }\n\n abort(): void {\n this.aborted = true;\n }\n\n hide(): void {\n if (this.cursorEl) this.cursorEl.classList.remove('visible');\n if (this.kbdEl) this.kbdEl.classList.remove('visible');\n this.onPhaseChange?.('idle');\n }\n\n /** Re-read stage children. Call after the stage's DOM has been re-rendered. */\n refreshDom(): void {\n this.cursorEl = this.stage.querySelector<HTMLElement>('.steppy-cursor');\n this.rippleEl = this.stage.querySelector<HTMLElement>('.steppy-ripple');\n this.kbdEl = this.stage.querySelector<HTMLElement>('.steppy-kbd');\n this.imgEl = this.stage.querySelector<HTMLImageElement>('img');\n }\n\n /**\n * Normalize a frame's cursor behavior into an ordered list of targets.\n * ``type-multi`` expands into N targets of kind ``type``; single-target\n * variants produce a single entry. Returns ``[]`` when there's nothing to\n * animate (cursor is null or no targets).\n */\n static normalizeTargets(behavior: CursorBehavior | null): NormalizedTarget[] {\n if (!behavior) return [];\n if (behavior.kind === 'type-multi') {\n return behavior.targets.map(\n (t: MultiTarget): NormalizedTarget => ({\n bbox: t.bbox,\n value: t.value,\n selector: t.selector,\n kind: 'type',\n }),\n );\n }\n const tgt = behavior.target as SingleTarget;\n const value = behavior.kind === 'type' ? behavior.value : undefined;\n return [\n {\n bbox: tgt.bbox,\n value,\n selector: tgt.selector,\n kind: behavior.kind === 'click' ? 'click' : behavior.kind === 'hover' ? 'hover' : 'type',\n },\n ];\n }\n\n /** Wait for the screenshot ``<img>`` to be ready (load or error). */\n async waitImageReady(): Promise<void> {\n const img = this.imgEl as HTMLImageElement | null;\n if (!img) return;\n if (img.complete && img.naturalWidth) return;\n await new Promise<void>((resolve) => {\n const done = () => resolve();\n img.addEventListener('load', done, { once: true });\n img.addEventListener('error', done, { once: true });\n });\n }\n\n /**\n * Full sequence over every target in ``frame.cursor`` — historical\n * stepbystep behavior. No user interaction.\n */\n async animateFrame(frame: AnimatorFrame): Promise<void> {\n this.aborted = false;\n this.refreshDom();\n if (!this.cursorEl) return;\n if (!frame.cursor) {\n this.hide();\n return;\n }\n await this.waitImageReady();\n const targets = CursorAnimator.normalizeTargets(frame.cursor);\n this.currentPos = { x: 8, y: 8 };\n this.cursorEl.classList.add('visible');\n for (let i = 0; i < targets.length; i++) {\n if (this.aborted) return;\n await this.travelToTargetIndex(frame, targets, i);\n if (this.aborted) return;\n await this.playTargetActionIndex(frame, targets, i);\n if (this.aborted) return;\n await sleep(this.timings.post_action_ms);\n }\n }\n\n /**\n * Interactive mode: move the cursor to ``targetIndex`` and pulse it. Caller\n * waits for user input before invoking ``playTargetAction``.\n */\n async travelToTarget(frame: AnimatorFrame, targetIndex: number): Promise<void> {\n this.aborted = false;\n this.refreshDom();\n if (!this.cursorEl) return;\n if (!frame.cursor) {\n this.hide();\n return;\n }\n await this.waitImageReady();\n const targets = CursorAnimator.normalizeTargets(frame.cursor);\n this.cursorEl.classList.add('visible');\n await this.travelToTargetIndex(frame, targets, targetIndex);\n }\n\n /**\n * Interactive mode: run the action animation for ``targetIndex`` and the\n * post-action settling beat.\n */\n async playTargetAction(frame: AnimatorFrame, targetIndex: number): Promise<void> {\n this.aborted = false;\n this.refreshDom();\n if (!frame.cursor) return;\n const targets = CursorAnimator.normalizeTargets(frame.cursor);\n await this.playTargetActionIndex(frame, targets, targetIndex);\n if (this.aborted) return;\n await sleep(this.timings.post_action_ms);\n }\n\n /**\n * Pure helper: project a capture-space bbox into the displayed coordinate\n * space. Returns ``null`` when the image hasn't laid out yet. Exposed so\n * the Lit player can place hotspots without duplicating the math.\n */\n computeDisplayRect(bbox: Bbox | null | undefined, viewport: Viewport | null | undefined): DisplayRect | null {\n const img = this.imgEl;\n if (!img || !bbox) return null;\n const scale = getDisplayScale(img, viewport);\n if (!scale) return null;\n return scaleRect(bbox, scale);\n }\n\n // ── Internal building blocks ───────────────────────────────────────────\n\n private async travelToTargetIndex(\n frame: AnimatorFrame,\n targets: NormalizedTarget[],\n index: number,\n ): Promise<void> {\n const tgt = targets[index];\n const cursor = this.cursorEl;\n if (!tgt || !cursor) return;\n const center = scaleBbox(tgt.bbox, this.imgEl!, frame.viewport);\n if (!center) return;\n\n this.onPhaseChange?.('travel', tgt);\n await this.travelTo(cursor, this.currentPos, center);\n this.currentPos = center;\n\n this.onPhaseChange?.('pre-action', tgt);\n // Pulse: drop the class, force reflow to restart the animation, re-add.\n cursor.classList.remove('pulse');\n void cursor.offsetWidth;\n cursor.classList.add('pulse');\n await sleep(this.timings.pre_action_ms);\n cursor.classList.remove('pulse');\n }\n\n private async playTargetActionIndex(\n frame: AnimatorFrame,\n targets: NormalizedTarget[],\n index: number,\n ): Promise<void> {\n const tgt = targets[index];\n if (!tgt) return;\n const center = scaleBbox(tgt.bbox, this.imgEl!, frame.viewport) || this.currentPos;\n this.onPhaseChange?.('action', tgt);\n if (tgt.kind === 'click') {\n if (this.rippleEl) this.fireClick(this.rippleEl, center);\n await sleep(this.timings.action_ms);\n } else if (tgt.kind === 'type') {\n if (this.kbdEl) await this.typeValue(this.kbdEl, center, tgt.value);\n } else {\n // hover: linger\n await sleep(this.timings.action_ms);\n }\n this.onPhaseChange?.('post-action', tgt);\n }\n\n private async travelTo(\n cursor: HTMLElement,\n from: { x: number; y: number },\n to: { x: number; y: number },\n ): Promise<void> {\n const duration = travelDuration(from, to, this.timings.travel_speed_px_per_ms);\n const cp = bezierControlPoint(from, to);\n return new Promise<void>((resolve) => {\n const start = performance.now();\n const frame = (now: number) => {\n if (this.aborted) {\n resolve();\n return;\n }\n const raw = Math.min(1, (now - start) / duration);\n const t = easeInOut(raw);\n const x = (1 - t) * (1 - t) * from.x + 2 * (1 - t) * t * cp.x + t * t * to.x;\n const y = (1 - t) * (1 - t) * from.y + 2 * (1 - t) * t * cp.y + t * t * to.y;\n cursor.style.left = `${x}px`;\n cursor.style.top = `${y}px`;\n if (raw < 1) requestAnimationFrame(frame);\n else resolve();\n };\n requestAnimationFrame(frame);\n });\n }\n\n private fireClick(ripple: HTMLElement, to: { x: number; y: number }): void {\n ripple.style.left = `${to.x}px`;\n ripple.style.top = `${to.y}px`;\n ripple.classList.remove('fire');\n void ripple.offsetWidth;\n ripple.classList.add('fire');\n }\n\n private async typeValue(\n kbd: HTMLElement,\n to: { x: number; y: number },\n value: string | undefined,\n ): Promise<void> {\n kbd.style.left = `${to.x + 16}px`;\n kbd.style.top = `${to.y + 16}px`;\n kbd.textContent = '';\n kbd.classList.add('visible');\n const chars = (value ?? '').split('');\n const per = chars.length ? this.timings.action_ms / chars.length : this.timings.action_ms;\n for (const ch of chars) {\n if (this.aborted) break;\n kbd.textContent = (kbd.textContent ?? '') + ch;\n await sleep(per);\n }\n await sleep(80);\n kbd.classList.remove('visible');\n }\n}\n","/**\n * CSS timing-function equivalents, for the video renderer.\n *\n * The live player animates the cursor pulse and the click ripple with CSS\n * ``@keyframes`` (``base-styles.ts``), which are driven by the wall clock. The\n * video renderer steps frame by frame instead, so it recomputes those styles\n * itself — and to look identical it has to apply the *same* easing CSS would.\n *\n * ``.steppy-cursor.pulse`` uses ``ease-in-out`` and ``.steppy-ripple.fire`` uses\n * ``ease-out``; both are cubic Béziers, not the smoothstep in ``cursor/animator.ts``\n * (which eases cursor *travel* and is reused verbatim from there — do not\n * confuse the two).\n *\n * Pure and DOM-free so it unit-tests without a browser.\n */\n\nconst NEWTON_ITERATIONS = 6;\nconst SUBDIVISION_EPSILON = 1e-7;\n\nfunction bezierAt(t: number, a1: number, a2: number): number {\n // Coefficients of the cubic with P0 = 0 and P3 = 1.\n const c = 3 * a1;\n const b = 3 * (a2 - a1) - c;\n const a = 1 - c - b;\n return ((a * t + b) * t + c) * t;\n}\n\nfunction bezierSlopeAt(t: number, a1: number, a2: number): number {\n const c = 3 * a1;\n const b = 3 * (a2 - a1) - c;\n const a = 1 - c - b;\n return (3 * a * t + 2 * b) * t + c;\n}\n\n/**\n * Build a CSS ``cubic-bezier(x1, y1, x2, y2)`` timing function.\n *\n * Solves x(t) = progress by Newton-Raphson, falling back to bisection when the\n * curve is locally flat (zero slope), then evaluates y at that t — the same\n * approach browsers use.\n */\nexport function cubicBezier(\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n): (progress: number) => number {\n // A linear curve needs no solving, and skipping it avoids the flat-slope path.\n if (x1 === y1 && x2 === y2) return (p) => clamp01(p);\n\n return (progress: number): number => {\n const p = clamp01(progress);\n if (p === 0 || p === 1) return p;\n\n let t = p;\n for (let i = 0; i < NEWTON_ITERATIONS; i++) {\n const slope = bezierSlopeAt(t, x1, x2);\n if (slope === 0) break;\n t -= (bezierAt(t, x1, x2) - p) / slope;\n }\n\n // Newton can wander outside [0,1] on flat curves; bisect back into range.\n if (!(t >= 0 && t <= 1)) {\n let lo = 0;\n let hi = 1;\n t = p;\n while (hi - lo > SUBDIVISION_EPSILON) {\n if (bezierAt(t, x1, x2) < p) lo = t;\n else hi = t;\n t = (lo + hi) / 2;\n }\n }\n\n return bezierAt(t, y1, y2);\n };\n}\n\nexport function clamp01(value: number): number {\n if (!(value > 0)) return 0; // also catches NaN\n return value < 1 ? value : 1;\n}\n\n/** CSS ``ease-in-out`` — the cursor pulse keyframes. */\nexport const easeInOutCss = cubicBezier(0.42, 0, 0.58, 1);\n\n/** CSS ``ease-out`` — the click ripple keyframes. */\nexport const easeOutCss = cubicBezier(0, 0, 0.58, 1);\n\n/** Linear interpolation, clamped at both ends. */\nexport function lerp(from: number, to: number, progress: number): number {\n return from + (to - from) * clamp01(progress);\n}\n","/**\n * Video timeline — the deterministic core of `modes: ['video']`.\n *\n * A guide video is a pure function of (manifest, locale, layout, display scale,\n * narration durations, fps). This module computes that function: it lays every\n * step's cursor choreography onto an absolute millisecond timeline, and\n * ``frameAt`` returns the exact render state at any instant. Nothing here\n * touches the DOM or the clock, so the whole thing unit-tests without a browser\n * — and a frame renders identically on a laptop and on a throttled CI runner,\n * which is the property the whole feature rests on.\n *\n * Three things are deliberately *not* derivable and must be passed in:\n *\n * * **``scale``** — the capture-space → display-space ratio. The stage renders\n * its screenshot with ``width:auto; max-width:100%``, so the displayed width\n * is ``min(intrinsicPngWidth, stageWidth)`` and ``intrinsicPngWidth`` is\n * ``captureSize.width × device_scale_factor`` — a factor the manifest does not\n * carry. ``stage.ts`` measures it with the animator's own ``getDisplayScale``\n * and hands it here. (Travel duration is a function of *display* distance —\n * see ``travelDuration`` — so this also means total video duration varies with\n * the configured output width.)\n * * **``narrationMs``** — clip lengths come from the TTS provider, which runs\n * before the browser opens. A step is held at least as long as its voiceover.\n * * **``fps``** — sampling rate; the timeline itself is continuous.\n *\n * Phase durations come from the manifest's ``cursor`` block, matching\n * ``CursorAnimator``'s sequence (travel → pre-action → action → post-action).\n * The click ripple is the one exception: its CSS animation is a hardcoded 400ms\n * (``base-styles.ts``) independent of ``action_ms``, so it is modelled as an\n * overlay that may outlive the action phase rather than as the phase itself.\n */\n\nimport { CursorAnimator, bezierControlPoint, easeInOut, rectCenter, scaleRect, travelDuration } from '../cursor/animator.js';\nimport type { NormalizedTarget, TargetKind } from '../cursor/animator.js';\nimport { DEFAULT_TIMINGS } from '../cursor/types.js';\nimport type { CursorTimings, DisplayScale } from '../cursor/types.js';\nimport { resolveStepContent } from '../manifest/content.js';\nimport type { Frame, GuideManifest, ManifestStep } from '../manifest/schema.js';\nimport { clamp01, easeInOutCss, easeOutCss, lerp } from './easing.js';\n\n/** Layout key used by the build for guides with no layout dimension. */\nexport const LAYOUTLESS_KEY = '_';\n\n/** Where the cursor sits before its first travel, matching ``animateFrame``. */\nexport const CURSOR_ORIGIN: Point = { x: 8, y: 8 };\n\n/** ``.steppy-ripple.fire`` — ``animation: steppy-ripple 400ms ease-out forwards``. */\nexport const RIPPLE_MS = 400;\nexport const RIPPLE_SCALE_FROM = 0.6;\nexport const RIPPLE_SCALE_TO = 3;\n\n/** ``.steppy-cursor.pulse`` — ``animation: steppy-pulse 200ms ease-in-out``. */\nexport const PULSE_MS = 200;\nexport const PULSE_SCALE_PEAK = 1.25;\n\n/** ``.steppy-cursor`` — ``transition: opacity 200ms ease-in-out``. */\nexport const CURSOR_FADE_MS = 200;\n\n/** Trailing beat ``typeValue`` sleeps after the last character. */\nexport const TYPE_TAIL_MS = 80;\n\n/** Offset of the keycap chip from the cursor point, per ``typeValue``. */\nexport const KBD_OFFSET = 16;\n\nexport interface Point {\n x: number;\n y: number;\n}\n\nexport type Phase = 'intro' | 'travel' | 'pre-action' | 'action' | 'post-action' | 'hold' | 'outro';\n\nexport interface Segment {\n phase: Phase;\n startMs: number;\n endMs: number;\n /** Index into ``manifest.steps``; -1 for the intro/outro cards. */\n stepIndex: number;\n /** Index into the step's frames; -1 for the intro/outro cards. */\n frameIndex: number;\n /** Index into the frame's normalized targets; -1 when the phase has no target. */\n targetIndex: number;\n kind?: TargetKind;\n /** Display-space geometry, precomputed so ``frameAt`` only interpolates. */\n from?: Point;\n to?: Point;\n control?: Point;\n value?: string;\n}\n\nexport interface Cue {\n stepId: string;\n stepIndex: number;\n startMs: number;\n endMs: number;\n text: string;\n title: string;\n}\n\n/** A click ripple, tracked separately because it can outlive its action phase. */\nexport interface RippleEvent {\n atMs: number;\n at: Point;\n}\n\n/** A cursor show/hide transition, so the 200ms opacity fade stays computable. */\nexport interface VisibilityChange {\n atMs: number;\n visible: boolean;\n}\n\nexport interface Timeline {\n durationMs: number;\n frameCount: number;\n fps: number;\n segments: Segment[];\n cues: Cue[];\n ripples: RippleEvent[];\n visibility: VisibilityChange[];\n /** Screenshot URL per (stepIndex, frameIndex), flattened for ``frameAt``. */\n screenshots: string[][];\n stepCount: number;\n locale: string;\n layoutKey: string;\n}\n\nexport interface VideoTimelineOptions {\n locale: string;\n /** Layout name, or null/undefined for a guide with no layout dimension. */\n layout?: string | null;\n /** Measured capture-space → display-space ratio. See the module docstring. */\n scale: DisplayScale;\n fps: number;\n /** Per-step voiceover length, keyed by ``ManifestStep.id``. */\n narrationMs?: Record<string, number>;\n /** Settle beat after a step's animation finishes. */\n holdMs?: number;\n /** Floor on any step's on-screen time, so a fast step is still readable. */\n minStepMs?: number;\n /** Breathing room added after a step's voiceover before advancing. */\n narrationPadMs?: number;\n introMs?: number;\n outroMs?: number;\n}\n\nexport interface CursorState {\n x: number;\n y: number;\n opacity: number;\n scale: number;\n}\n\nexport interface RippleState {\n x: number;\n y: number;\n scale: number;\n opacity: number;\n}\n\nexport interface KbdState {\n x: number;\n y: number;\n text: string;\n}\n\nexport interface FrameState {\n timeMs: number;\n /** -1 while an intro/outro card is showing. */\n stepIndex: number;\n frameIndex: number;\n screenshot: string;\n cursor: CursorState | null;\n ripple: RippleState | null;\n kbd: KbdState | null;\n caption: string;\n captionTitle: string;\n /** 0..1 across the whole video, for the progress bar. */\n progress: number;\n card: 'intro' | 'outro' | null;\n}\n\n/**\n * Every segment boundary is a whole millisecond.\n *\n * Travel duration is a distance/speed quotient, so accumulating it raw drifts\n * (2000 becomes 2000.0000000000005) and — worse — makes two frames of an\n * otherwise motionless hold compare unequal, which would defeat the dedup the\n * render budget depends on. Frames are sampled ~33ms apart; sub-millisecond\n * precision cannot reach the screen.\n */\nconst ms = Math.round;\n\nconst DEFAULTS = {\n holdMs: 700,\n minStepMs: 1500,\n narrationPadMs: 400,\n introMs: 1200,\n outroMs: 1500,\n};\n\nfunction targetCenter(target: NormalizedTarget, scale: DisplayScale): Point {\n return rectCenter(scaleRect(target.bbox, scale));\n}\n\n/**\n * How long the action phase lasts for one target.\n *\n * ``typeValue`` appends one character every ``action_ms / n`` and then sleeps a\n * further 80ms, so a typed target runs ``action_ms + 80`` — except for an empty\n * value, where the loop never runs and only the trailing beat remains.\n */\nexport function actionDuration(target: NormalizedTarget, timings: CursorTimings): number {\n if (target.kind !== 'type') return timings.action_ms;\n const chars = (target.value ?? '').length;\n return chars ? timings.action_ms + TYPE_TAIL_MS : TYPE_TAIL_MS;\n}\n\n/** Frames of a step for one (locale, layout), or `[]` when the pair is absent. */\nexport function framesFor(step: ManifestStep, locale: string, layoutKey: string): Frame[] {\n return step.captures?.[locale]?.[layoutKey]?.frames ?? [];\n}\n\nexport function resolveLayoutKey(manifest: GuideManifest, layout?: string | null): string {\n if (layout) return layout;\n return manifest.layouts.length > 0 ? manifest.layouts[0]! : LAYOUTLESS_KEY;\n}\n\n/**\n * Lay the whole guide out on an absolute millisecond timeline.\n *\n * Steps run in manifest order; within a step, every frame runs in order and\n * every target within a frame runs travel → pre-action → action → post-action,\n * exactly as ``CursorAnimator.animateFrame`` does. Two deliberate divergences\n * from the live player, both because a video is watched rather than driven:\n *\n * * the cursor keeps its position across frames *and* steps (``animateFrame``\n * resets to the corner each frame, which reads as a glitch between the\n * progressive frames of a tall ``fill-form``);\n * * ``cursor.mode`` (``hotspot``/``off``) is ignored — those describe click\n * affordances that do not exist here.\n */\nexport function buildTimeline(manifest: GuideManifest, options: VideoTimelineOptions): Timeline {\n const { locale, scale, fps } = options;\n const holdMs = options.holdMs ?? DEFAULTS.holdMs;\n const minStepMs = options.minStepMs ?? DEFAULTS.minStepMs;\n const narrationPadMs = options.narrationPadMs ?? DEFAULTS.narrationPadMs;\n const introMs = options.introMs ?? DEFAULTS.introMs;\n const outroMs = options.outroMs ?? DEFAULTS.outroMs;\n const narrationMs = options.narrationMs ?? {};\n\n const timings: CursorTimings = { ...DEFAULT_TIMINGS, ...manifest.cursor };\n const layoutKey = resolveLayoutKey(manifest, options.layout);\n\n const segments: Segment[] = [];\n const cues: Cue[] = [];\n const ripples: RippleEvent[] = [];\n const visibility: VisibilityChange[] = [];\n const screenshots: string[][] = [];\n\n let cursorAt: Point = { ...CURSOR_ORIGIN };\n let cursorVisible = false;\n let t = 0;\n\n if (introMs > 0) {\n segments.push({ phase: 'intro', startMs: 0, endMs: introMs, stepIndex: -1, frameIndex: -1, targetIndex: -1 });\n t = introMs;\n }\n\n manifest.steps.forEach((step, stepIndex) => {\n const frames = framesFor(step, locale, layoutKey);\n screenshots.push(frames.map((f) => f.screenshot));\n\n const stepStart = t;\n const stepHasCursor = frames.some((f) => f.cursor !== null);\n\n if (cursorVisible !== stepHasCursor) {\n visibility.push({ atMs: stepStart, visible: stepHasCursor });\n cursorVisible = stepHasCursor;\n }\n\n frames.forEach((frame, frameIndex) => {\n const targets = CursorAnimator.normalizeTargets(frame.cursor);\n if (targets.length === 0) {\n // A frame with nothing to animate still has to be on screen long enough\n // to be seen — otherwise a multi-frame step flashes past its own captures.\n segments.push({ phase: 'hold', startMs: t, endMs: t + holdMs, stepIndex, frameIndex, targetIndex: -1 });\n t += holdMs;\n return;\n }\n\n targets.forEach((target, targetIndex) => {\n const to = targetCenter(target, scale);\n const from = cursorAt;\n\n const travelMs = ms(travelDuration(from, to, timings.travel_speed_px_per_ms));\n segments.push({\n phase: 'travel',\n startMs: t,\n endMs: t + travelMs,\n stepIndex,\n frameIndex,\n targetIndex,\n kind: target.kind,\n from,\n to,\n control: bezierControlPoint(from, to),\n });\n t += travelMs;\n cursorAt = to;\n\n segments.push({\n phase: 'pre-action',\n startMs: t,\n endMs: t + timings.pre_action_ms,\n stepIndex,\n frameIndex,\n targetIndex,\n kind: target.kind,\n to,\n });\n t += timings.pre_action_ms;\n\n const actionMs = actionDuration(target, timings);\n if (target.kind === 'click') ripples.push({ atMs: t, at: to });\n segments.push({\n phase: 'action',\n startMs: t,\n endMs: t + actionMs,\n stepIndex,\n frameIndex,\n targetIndex,\n kind: target.kind,\n to,\n value: target.value,\n });\n t += actionMs;\n\n segments.push({\n phase: 'post-action',\n startMs: t,\n endMs: t + timings.post_action_ms,\n stepIndex,\n frameIndex,\n targetIndex,\n kind: target.kind,\n to,\n });\n t += timings.post_action_ms;\n });\n });\n\n // Settle beat, then stretch the step to satisfy every floor: the author's\n // `wait-after`, the readability minimum, and — the one that actually bites —\n // the voiceover, which must never be cut off mid-sentence.\n const animatedMs = t - stepStart;\n const narration = narrationMs[step.id] ?? 0;\n const wanted = ms(\n Math.max(\n animatedMs + Math.max(holdMs, step.waitAfter),\n minStepMs,\n narration > 0 ? narration + narrationPadMs : 0,\n ),\n );\n const lastFrame = Math.max(0, frames.length - 1);\n segments.push({\n phase: 'hold',\n startMs: t,\n endMs: stepStart + wanted,\n stepIndex,\n frameIndex: lastFrame,\n targetIndex: -1,\n });\n t = stepStart + wanted;\n\n // Same layout key the frames came from — a step whose wording is\n // overridden per layout must be captioned with the layout being rendered.\n const content = resolveStepContent(step, locale, layoutKey);\n cues.push({\n stepId: step.id,\n stepIndex,\n startMs: stepStart,\n endMs: t,\n text: content.text,\n title: content.title || content.text,\n });\n });\n\n if (cursorVisible) {\n visibility.push({ atMs: t, visible: false });\n cursorVisible = false;\n }\n\n if (outroMs > 0) {\n segments.push({ phase: 'outro', startMs: t, endMs: t + outroMs, stepIndex: -1, frameIndex: -1, targetIndex: -1 });\n t += outroMs;\n }\n\n const durationMs = t;\n return {\n durationMs,\n frameCount: Math.max(1, Math.ceil((durationMs * fps) / 1000)),\n fps,\n segments,\n cues,\n ripples,\n visibility,\n screenshots,\n stepCount: manifest.steps.length,\n locale,\n layoutKey,\n };\n}\n\n/** Timestamp sampled for frame ``index``. */\nexport function timeAtFrame(timeline: Timeline, index: number): number {\n return (index * 1000) / timeline.fps;\n}\n\nfunction segmentAt(segments: Segment[], timeMs: number): Segment | null {\n if (segments.length === 0) return null;\n let lo = 0;\n let hi = segments.length - 1;\n let found = segments[0]!;\n while (lo <= hi) {\n const mid = (lo + hi) >> 1;\n const seg = segments[mid]!;\n if (seg.startMs <= timeMs) {\n found = seg;\n lo = mid + 1;\n } else {\n hi = mid - 1;\n }\n }\n return found;\n}\n\nfunction cursorOpacityAt(timeline: Timeline, timeMs: number): number {\n let visible = false;\n let changedAt = -Infinity;\n for (const change of timeline.visibility) {\n if (change.atMs > timeMs) break;\n visible = change.visible;\n changedAt = change.atMs;\n }\n const target = visible ? 1 : 0;\n const from = visible ? 0 : 1;\n const elapsed = timeMs - changedAt;\n if (!Number.isFinite(changedAt) || elapsed >= CURSOR_FADE_MS) return target;\n return lerp(from, target, easeInOutCss(elapsed / CURSOR_FADE_MS));\n}\n\n/**\n * Pulse scale at ``elapsed`` into the pre-action phase.\n *\n * The keyframes are 0%/100% ``scale(1)`` with a ``scale(1.25)`` peak at 50%, and\n * CSS applies the timing function *between* each keyframe pair. The animation is\n * a fixed 200ms regardless of ``pre_action_ms``, and has no ``forwards`` fill, so\n * it sits back at 1 once it is over.\n */\nexport function pulseScaleAt(elapsed: number): number {\n if (elapsed < 0 || elapsed >= PULSE_MS) return 1;\n const half = PULSE_MS / 2;\n if (elapsed < half) return lerp(1, PULSE_SCALE_PEAK, easeInOutCss(elapsed / half));\n return lerp(PULSE_SCALE_PEAK, 1, easeInOutCss((elapsed - half) / half));\n}\n\nfunction rippleAt(timeline: Timeline, timeMs: number): RippleState | null {\n let active: RippleEvent | null = null;\n for (const event of timeline.ripples) {\n if (event.atMs > timeMs) break;\n active = event;\n }\n if (!active) return null;\n const elapsed = timeMs - active.atMs;\n if (elapsed >= RIPPLE_MS) return null;\n const p = easeOutCss(elapsed / RIPPLE_MS);\n return {\n x: active.at.x,\n y: active.at.y,\n scale: lerp(RIPPLE_SCALE_FROM, RIPPLE_SCALE_TO, p),\n opacity: 1 - p,\n };\n}\n\n/** Characters visible at ``elapsed`` into a ``type`` action, per ``typeValue``. */\nexport function typedTextAt(value: string, elapsed: number, actionMs: number): string {\n if (!value) return '';\n const per = actionMs / value.length;\n if (per <= 0) return value;\n const shown = Math.min(value.length, Math.floor(elapsed / per) + 1);\n return value.slice(0, Math.max(0, shown));\n}\n\nfunction pointOnCurve(from: Point, control: Point, to: Point, t: number): Point {\n const u = 1 - t;\n return {\n x: u * u * from.x + 2 * u * t * control.x + t * t * to.x,\n y: u * u * from.y + 2 * u * t * control.y + t * t * to.y,\n };\n}\n\n/**\n * The complete render state at ``timeMs`` — everything ``stage.ts`` needs to\n * paint one frame, and nothing it has to decide for itself.\n */\nexport function stateAt(timeline: Timeline, timeMs: number, timings: CursorTimings): FrameState {\n const seg = segmentAt(timeline.segments, timeMs);\n\n if (!seg || seg.phase === 'intro' || seg.phase === 'outro') {\n const outro = seg?.phase === 'outro';\n return {\n timeMs,\n stepIndex: -1,\n frameIndex: -1,\n screenshot: '',\n cursor: null,\n ripple: null,\n kbd: null,\n caption: '',\n captionTitle: '',\n progress: outro ? 1 : 0,\n card: outro ? 'outro' : 'intro',\n };\n }\n\n // Progress advances per *step*, not per millisecond. A bar that creeps every\n // frame would make no two frames identical, which would defeat the dedup that\n // keeps a render affordable — and on a video with a native scrubber, \"step 3\n // of 7\" is the more useful signal anyway.\n const progress = timeline.stepCount > 0 ? clamp01((seg.stepIndex + 1) / timeline.stepCount) : 0;\n\n const cue = timeline.cues[seg.stepIndex];\n const screenshot = timeline.screenshots[seg.stepIndex]?.[Math.max(0, seg.frameIndex)] ?? '';\n const elapsed = timeMs - seg.startMs;\n\n let cursor: CursorState | null = null;\n const opacity = cursorOpacityAt(timeline, timeMs);\n if (opacity > 0) {\n let point: Point;\n let scale = 1;\n if (seg.phase === 'travel' && seg.from && seg.to && seg.control) {\n const span = seg.endMs - seg.startMs;\n point = pointOnCurve(seg.from, seg.control, seg.to, easeInOut(clamp01(span > 0 ? elapsed / span : 1)));\n } else if (seg.to) {\n point = seg.to;\n if (seg.phase === 'pre-action') scale = pulseScaleAt(elapsed);\n } else {\n // A hold after the last target: the cursor stays where it landed.\n point = lastKnownPoint(timeline, timeMs);\n }\n cursor = { x: point.x, y: point.y, opacity, scale };\n }\n\n let kbd: KbdState | null = null;\n if (seg.phase === 'action' && seg.kind === 'type' && seg.to) {\n const text = typedTextAt(seg.value ?? '', elapsed, timings.action_ms);\n if (text) kbd = { x: seg.to.x + KBD_OFFSET, y: seg.to.y + KBD_OFFSET, text };\n }\n\n return {\n timeMs,\n stepIndex: seg.stepIndex,\n frameIndex: Math.max(0, seg.frameIndex),\n screenshot,\n cursor,\n ripple: rippleAt(timeline, timeMs),\n kbd,\n caption: cue?.text ?? '',\n captionTitle: cue?.title ?? '',\n progress,\n card: null,\n };\n}\n\nfunction lastKnownPoint(timeline: Timeline, timeMs: number): Point {\n for (let i = timeline.segments.length - 1; i >= 0; i--) {\n const seg = timeline.segments[i]!;\n if (seg.startMs <= timeMs && seg.to) return seg.to;\n }\n return { ...CURSOR_ORIGIN };\n}\n\n/** Convenience: the state for a frame index. */\nexport function frameAt(timeline: Timeline, index: number, timings: CursorTimings): FrameState {\n return stateAt(timeline, timeAtFrame(timeline, index), timings);\n}\n\nfunction samePoint(a: { x: number; y: number } | null, b: { x: number; y: number } | null): boolean {\n if (a === b) return true;\n if (!a || !b) return false;\n // Sub-pixel differences cannot change the rendered frame, and treating them as\n // changes would defeat the static-frame dedup that makes rendering affordable.\n return Math.round(a.x) === Math.round(b.x) && Math.round(a.y) === Math.round(b.y);\n}\n\nfunction sameAlpha(a: number, b: number): boolean {\n return Math.round(a * 100) === Math.round(b * 100);\n}\n\n/**\n * Would these two states paint the same pixels?\n *\n * Drives the renderer's dedup: holds and voiceover pauses dominate a narrated\n * video, and re-screenshotting an unchanged frame is the single largest\n * avoidable cost in the pipeline.\n */\nexport function frameStateEquals(a: FrameState, b: FrameState): boolean {\n if (a.card !== b.card) return false;\n if (a.screenshot !== b.screenshot) return false;\n if (a.caption !== b.caption || a.captionTitle !== b.captionTitle) return false;\n if (Math.round(a.progress * 1000) !== Math.round(b.progress * 1000)) return false;\n\n if (!!a.cursor !== !!b.cursor) return false;\n if (a.cursor && b.cursor) {\n if (!samePoint(a.cursor, b.cursor)) return false;\n if (!sameAlpha(a.cursor.opacity, b.cursor.opacity)) return false;\n if (Math.round(a.cursor.scale * 100) !== Math.round(b.cursor.scale * 100)) return false;\n }\n\n if (!!a.ripple !== !!b.ripple) return false;\n if (a.ripple && b.ripple) {\n if (!samePoint(a.ripple, b.ripple)) return false;\n if (!sameAlpha(a.ripple.opacity, b.ripple.opacity)) return false;\n if (Math.round(a.ripple.scale * 100) !== Math.round(b.ripple.scale * 100)) return false;\n }\n\n if (!!a.kbd !== !!b.kbd) return false;\n if (a.kbd && b.kbd) {\n if (a.kbd.text !== b.kbd.text) return false;\n if (!samePoint(a.kbd, b.kbd)) return false;\n }\n\n return true;\n}\n","/**\n * Video stage — the DOM half of `modes: ['video']`.\n *\n * Builds a fixed-size, chrome-free surface over the guide's captures and paints\n * exactly one instant of ``timeline.ts`` per call to ``seek``. It is driven from\n * outside (headless Chromium, one screenshot per frame), so nothing here reads\n * the clock: every cursor position, pulse scale, ripple radius and typed\n * substring is computed from the frame index.\n *\n * Two things it deliberately does *not* do, both for pixel parity with the live\n * player:\n *\n * * **It reuses ``baseStyles`` verbatim**, inside a shadow root so the ``:host``\n * rules apply. The cursor's clip-path, the ripple's border, the keycap chip\n * and every design token therefore come from one source — there is no second\n * copy of the look to drift.\n * * **It disables the CSS animations and transitions in that sheet** rather than\n * trying to scrub them. ``animation-delay`` cannot address a ``transition``\n * at all (``.steppy-cursor`` fades opacity over 200ms that way), and\n * ``prefers-reduced-motion`` would silently strip the rest. The timeline\n * supplies the same values as inline styles instead, which is both\n * deterministic and immune to the render host's motion settings.\n *\n * Screenshots are all mounted up front and toggled by opacity — never swapped\n * into one ``<img>``'s ``src``, which would risk capturing a frame mid-decode.\n */\n\nimport { DEFAULT_TIMINGS } from '../cursor/types.js';\nimport type { CursorTimings } from '../cursor/types.js';\nimport { resolveStepContent } from '../manifest/content.js';\nimport type { GuideManifest } from '../manifest/schema.js';\nimport { baseStyles } from '../templates/base-styles.js';\nimport {\n buildTimeline,\n frameAt,\n frameStateEquals,\n framesFor,\n resolveLayoutKey,\n} from './timeline.js';\nimport type { Cue, FrameState, Timeline, VideoTimelineOptions } from './timeline.js';\n\nexport interface VideoStageOptions extends Omit<VideoTimelineOptions, 'scale'> {\n /** Output canvas width in CSS px. Height follows the capture's aspect. */\n width: number;\n /** Optional ceiling on total height; the stage shrinks to fit rather than crop. */\n maxHeight?: number | null;\n captions?: 'band' | 'off';\n /** Card + band copy. All optional; the cards are skipped when empty. */\n title?: string;\n subtitle?: string;\n outroText?: string;\n /** Data URI. Never a remote URL — the page renders offline over file://. */\n logo?: string;\n accent?: string;\n /** Provenance line burned into every frame (e.g. \"v2.14 · 2026-08-05\"). */\n stamp?: string;\n fontFamily?: string;\n /** Per-image load budget. Exceeding it renders the gap instead of hanging. */\n imageTimeoutMs?: number;\n}\n\nexport interface VideoStage {\n readonly timeline: Timeline;\n readonly durationMs: number;\n readonly frameCount: number;\n ready(): Promise<void>;\n size(): { width: number; height: number };\n cues(): Cue[];\n /** Screenshot URLs that never loaded. Non-empty means a gappy video. */\n missingShots(): string[];\n /** Paint frame ``index``. Returns false when the pixels are unchanged. */\n seek(index: number): boolean;\n destroy(): void;\n}\n\n/** libx264 with yuv420p rejects odd dimensions; round down, never up. */\nexport function evenDown(value: number): number {\n const n = Math.max(2, Math.floor(value));\n return n % 2 === 0 ? n : n - 1;\n}\n\nconst VIDEO_CSS = `\n :host {\n display: block;\n position: relative;\n overflow: hidden;\n background: var(--steppy-bg);\n --steppy-video-band-pad: 20px;\n }\n /* The live player animates these with CSS keyframes and transitions, both\n wall-clock driven. The timeline supplies the same values per frame. */\n .steppy-stage img,\n .steppy-cursor,\n .steppy-ripple,\n .steppy-kbd {\n animation: none !important;\n transition: none !important;\n }\n .steppy-video-frame {\n position: relative;\n display: flex;\n justify-content: center;\n align-items: flex-start;\n background: var(--steppy-bg);\n }\n .steppy-stage {\n position: relative;\n overflow: hidden;\n background: var(--steppy-chrome-bg);\n }\n .steppy-stage img {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: auto;\n display: block;\n opacity: 0;\n max-width: none;\n }\n .steppy-stage img.on { opacity: 1; }\n .steppy-cursor, .steppy-ripple, .steppy-kbd { opacity: 0; }\n\n .steppy-video-band {\n box-sizing: border-box;\n padding: var(--steppy-video-band-pad);\n background: var(--steppy-chrome-bg);\n border-top: 1px solid var(--steppy-border);\n display: flex;\n flex-direction: column;\n gap: 12px;\n justify-content: center;\n }\n .steppy-video-progress {\n height: 4px;\n border-radius: 999px;\n background: var(--steppy-border);\n overflow: hidden;\n }\n .steppy-video-progress > i {\n display: block;\n height: 100%;\n width: 0%;\n background: var(--steppy-accent);\n }\n .steppy-video-caption {\n font-family: var(--steppy-font-sans);\n font-size: 20px;\n line-height: 1.45;\n color: var(--steppy-fg);\n margin: 0;\n }\n .steppy-video-caption b { font-weight: 600; }\n\n .steppy-video-card {\n position: absolute;\n inset: 0;\n display: none;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 18px;\n padding: 8%;\n text-align: center;\n background: var(--steppy-bg);\n z-index: 10;\n }\n .steppy-video-card.on { display: flex; }\n .steppy-video-card h1 {\n font-family: var(--steppy-font-serif);\n font-size: 44px;\n line-height: 1.15;\n margin: 0;\n color: var(--steppy-fg);\n }\n .steppy-video-card p {\n font-family: var(--steppy-font-sans);\n font-size: 22px;\n margin: 0;\n color: var(--steppy-muted);\n }\n .steppy-video-card img { max-width: 200px; max-height: 80px; }\n .steppy-video-card .rule {\n width: 72px;\n height: 4px;\n border-radius: 999px;\n background: var(--steppy-accent);\n }\n\n .steppy-video-watermark {\n position: absolute;\n right: 20px;\n top: 16px;\n max-height: 32px;\n opacity: 0.85;\n z-index: 8;\n }\n .steppy-video-stamp {\n position: absolute;\n right: 16px;\n bottom: 10px;\n font-family: var(--steppy-font-mono);\n font-size: 12px;\n color: var(--steppy-muted);\n z-index: 8;\n }\n`;\n\nfunction el<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n cls?: string,\n): HTMLElementTagNameMap[K] {\n const node = document.createElement(tag);\n if (cls) node.className = cls;\n return node;\n}\n\n/**\n * Wait for one screenshot to be usable, but never indefinitely.\n *\n * A 404 over ``file://`` fires ``error`` and settles fine — the dangerous case\n * is a request that neither loads nor errors, which would wedge the whole batch\n * on one guide with no diagnostic. Same call the PDF exporter makes: bound the\n * wait, then render anyway and let the caller report the gap.\n */\nfunction decoded(img: HTMLImageElement, timeoutMs: number): Promise<boolean> {\n if (img.complete && img.naturalWidth) return Promise.resolve(true);\n return new Promise<boolean>((resolve) => {\n let settled = false;\n const done = (ok: boolean) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve(ok);\n };\n const timer = setTimeout(() => done(false), Math.max(0, timeoutMs));\n img.addEventListener('load', () => done(true), { once: true });\n img.addEventListener('error', () => done(false), { once: true });\n });\n}\n\n/**\n * Mount the stage into ``host`` and prepare it for frame-by-frame capture.\n *\n * The timeline is built *after* the images are decoded, because travel duration\n * depends on display-space distance and therefore on the real capture scale —\n * which is ``naturalWidth / captureSize.width``, a factor the manifest does not\n * carry (see ``timeline.ts``).\n */\nexport function mountVideoStage(\n host: HTMLElement,\n manifest: GuideManifest,\n options: VideoStageOptions,\n): VideoStage {\n const captions = options.captions ?? 'band';\n const layoutKey = resolveLayoutKey(manifest, options.layout);\n const timings: CursorTimings = { ...DEFAULT_TIMINGS, ...manifest.cursor };\n\n const root = host.shadowRoot ?? host.attachShadow({ mode: 'open' });\n root.innerHTML = '';\n\n const style = el('style');\n style.textContent = baseStyles.cssText + VIDEO_CSS;\n root.appendChild(style);\n\n if (options.accent) host.style.setProperty('--steppy-accent', options.accent);\n if (options.fontFamily) host.style.setProperty('--steppy-font-family', options.fontFamily);\n\n const frame = el('div', 'steppy-video-frame');\n const stage = el('div', 'steppy-stage');\n frame.appendChild(stage);\n root.appendChild(frame);\n\n // One <img> per distinct capture, stacked and toggled by opacity. Swapping a\n // single src would risk screenshotting a frame mid-decode.\n const shots = new Map<string, HTMLImageElement>();\n const order: string[] = [];\n for (const step of manifest.steps) {\n for (const f of framesFor(step, options.locale, layoutKey)) {\n if (shots.has(f.screenshot)) continue;\n const img = el('img');\n img.src = f.screenshot;\n img.alt = '';\n shots.set(f.screenshot, img);\n order.push(f.screenshot);\n stage.appendChild(img);\n }\n }\n\n const cursor = el('div', 'steppy-cursor');\n const ripple = el('div', 'steppy-ripple');\n const kbd = el('div', 'steppy-kbd');\n stage.append(cursor, ripple, kbd);\n\n const band = el('div', 'steppy-video-band');\n const progress = el('div', 'steppy-video-progress');\n const progressBar = el('i');\n progress.appendChild(progressBar);\n const caption = el('div', 'steppy-video-caption');\n band.append(progress, caption);\n if (captions !== 'off') root.appendChild(band);\n\n const card = el('div', 'steppy-video-card');\n const cardTitle = el('h1');\n const cardRule = el('div', 'rule');\n const cardText = el('p');\n const cardLogo = el('img');\n if (options.logo) {\n cardLogo.src = options.logo;\n card.appendChild(cardLogo);\n }\n card.append(cardTitle, cardRule, cardText);\n root.appendChild(card);\n\n let watermark: HTMLImageElement | null = null;\n if (options.logo) {\n watermark = el('img', 'steppy-video-watermark');\n watermark.src = options.logo;\n root.appendChild(watermark);\n }\n if (options.stamp) {\n const stamp = el('div', 'steppy-video-stamp');\n stamp.textContent = options.stamp;\n root.appendChild(stamp);\n }\n\n const width = evenDown(options.width);\n let height = width;\n let timeline: Timeline | null = null;\n let previous: FrameState | null = null;\n let lastShot = '';\n let missing: string[] = [];\n\n /** Widest caption across every step, so the band height never shifts mid-video. */\n function measureBand(): number {\n if (captions === 'off') return 0;\n let tallest = 0;\n // Must read the same (locale, layout) cell the timeline captions from, or\n // an overridden step sizes the band from text the video never shows.\n const texts = manifest.steps.map((s) => resolveStepContent(s, options.locale, layoutKey).text);\n for (const text of texts.length ? texts : ['']) {\n caption.textContent = text;\n tallest = Math.max(tallest, band.scrollHeight || band.getBoundingClientRect().height || 0);\n }\n caption.textContent = '';\n // happy-dom reports no layout; fall back to a sane fixed band so unit tests\n // exercise the same code path the browser does.\n return Math.ceil(tallest) || 96;\n }\n\n async function ready(): Promise<void> {\n const budget = options.imageTimeoutMs ?? 15000;\n const results = await Promise.all(order.map((src) => decoded(shots.get(src)!, budget)));\n missing = order.filter((_, i) => !results[i]);\n\n // Text is burned into every frame, so a font swapping in mid-render would\n // change the pixels partway through the video.\n const fonts = (document as Document & { fonts?: FontFaceSet }).fonts;\n if (fonts?.ready) await fonts.ready;\n\n const first = order.length ? shots.get(order[0]!)! : null;\n const captureSize = firstCaptureSize(manifest, options.locale, layoutKey);\n // Truth on disk beats the manifest: naturalWidth already includes the\n // capture's device_scale_factor, which the manifest does not record.\n const naturalW = first?.naturalWidth || captureSize.width;\n const naturalH = first?.naturalHeight || captureSize.height;\n\n let stageW = width;\n let stageH = Math.round((naturalH * stageW) / naturalW);\n\n const bandH = measureBand();\n const cap = options.maxHeight ?? null;\n if (cap && stageH + bandH > cap) {\n const avail = Math.max(1, cap - bandH);\n stageW = Math.max(2, Math.round((naturalW * avail) / naturalH));\n stageH = avail;\n }\n\n stage.style.width = `${stageW}px`;\n stage.style.height = `${stageH}px`;\n frame.style.width = `${width}px`;\n frame.style.height = `${stageH}px`;\n if (captions !== 'off') {\n band.style.width = `${width}px`;\n band.style.height = `${bandH}px`;\n }\n\n height = evenDown(stageH + bandH);\n host.style.width = `${width}px`;\n host.style.height = `${height}px`;\n\n const sx = stageW / captureSize.width;\n const sy = stageH / captureSize.height;\n timeline = buildTimeline(manifest, { ...options, scale: { sx, sy } });\n }\n\n function paint(state: FrameState): void {\n if (state.card) {\n card.classList.add('on');\n const isOutro = state.card === 'outro';\n cardTitle.textContent = options.title ?? '';\n cardText.textContent = (isOutro ? options.outroText : options.subtitle) ?? '';\n cardText.style.display = cardText.textContent ? '' : 'none';\n } else {\n card.classList.remove('on');\n }\n\n if (state.screenshot !== lastShot) {\n if (lastShot) shots.get(lastShot)?.classList.remove('on');\n shots.get(state.screenshot)?.classList.add('on');\n lastShot = state.screenshot;\n }\n\n if (state.cursor) {\n cursor.style.opacity = String(state.cursor.opacity);\n cursor.style.left = `${state.cursor.x}px`;\n cursor.style.top = `${state.cursor.y}px`;\n cursor.style.transform = `scale(${state.cursor.scale})`;\n } else {\n cursor.style.opacity = '0';\n }\n\n if (state.ripple) {\n ripple.style.opacity = String(state.ripple.opacity);\n ripple.style.left = `${state.ripple.x}px`;\n ripple.style.top = `${state.ripple.y}px`;\n ripple.style.transform = `scale(${state.ripple.scale})`;\n } else {\n ripple.style.opacity = '0';\n }\n\n if (state.kbd) {\n kbd.style.opacity = '1';\n kbd.style.left = `${state.kbd.x}px`;\n kbd.style.top = `${state.kbd.y}px`;\n kbd.textContent = state.kbd.text;\n } else {\n kbd.style.opacity = '0';\n kbd.textContent = '';\n }\n\n caption.textContent = state.caption;\n progressBar.style.width = `${Math.round(state.progress * 1000) / 10}%`;\n }\n\n return {\n get timeline() {\n return requireTimeline(timeline);\n },\n get durationMs() {\n return requireTimeline(timeline).durationMs;\n },\n get frameCount() {\n return requireTimeline(timeline).frameCount;\n },\n ready,\n size: () => ({ width, height }),\n cues: () => requireTimeline(timeline).cues,\n missingShots: () => [...missing],\n seek(index: number): boolean {\n const tl = requireTimeline(timeline);\n const state = frameAt(tl, index, timings);\n if (previous && frameStateEquals(previous, state)) return false;\n paint(state);\n previous = state;\n return true;\n },\n destroy() {\n root.innerHTML = '';\n previous = null;\n },\n };\n}\n\nfunction requireTimeline(timeline: Timeline | null): Timeline {\n if (!timeline) throw new Error('steppy-video: await ready() before using the stage');\n return timeline;\n}\n\nfunction firstCaptureSize(\n manifest: GuideManifest,\n locale: string,\n layoutKey: string,\n): { width: number; height: number } {\n let size: { width: number; height: number } | null = null;\n for (const step of manifest.steps) {\n for (const frame of framesFor(step, locale, layoutKey)) {\n if (!size) {\n size = frame.captureSize;\n continue;\n }\n // Uniformity holds because one run means one viewport — but nothing\n // validates it when the manifest is built, and a screenshots directory of\n // mixed vintage would silently letterbox or crop half the video.\n if (frame.captureSize.width !== size.width || frame.captureSize.height !== size.height) {\n throw new Error(\n `steppy-video: step ${step.index} was captured at ` +\n `${frame.captureSize.width}x${frame.captureSize.height} but the guide starts at ` +\n `${size.width}x${size.height}. A video needs one fixed stage — recapture this guide ` +\n `(steppy run --guide) so every screenshot shares a viewport.`,\n );\n }\n }\n }\n if (!size) {\n throw new Error(\n `steppy-video: no captures for locale '${locale}' / layout '${layoutKey}'.`,\n );\n }\n return size;\n}\n","/**\n * IIFE entry for the video renderer.\n *\n * Exposes ``window.__STEPPY_VIDEO__`` so the Python side (``steppy/video.py``)\n * can drive frame-by-frame capture over CDP:\n *\n * ```js\n * const stage = window.__STEPPY_VIDEO__.mount(manifest, options);\n * await stage.ready();\n * stage.size(); // -> {width, height}, both even, for the viewport\n * stage.seek(i); // -> false when the frame is pixel-identical\n * ```\n *\n * This bundle is **build-time only**. It is inlined into a throwaway harness\n * page and never copied into a published guide site — which is exactly why it\n * is a separate artifact from ``steppy-player.js`` rather than an export of it:\n * viewers should not download rendering code, and this module needs no Lit.\n */\n\nimport type { GuideManifest } from '../manifest/schema.js';\nimport { mountVideoStage } from './stage.js';\nimport type { VideoStage, VideoStageOptions } from './stage.js';\n\nexport interface SteppyVideoGlobal {\n mount(manifest: GuideManifest, options: VideoStageOptions, host?: HTMLElement): VideoStage;\n /** Set by the mount call so the driver can reach the live stage by name. */\n stage: VideoStage | null;\n}\n\nconst api: SteppyVideoGlobal = {\n stage: null,\n mount(manifest, options, host) {\n const target = host ?? document.getElementById('steppy-video') ?? document.body;\n const stage = mountVideoStage(target as HTMLElement, manifest, options);\n api.stage = stage;\n return stage;\n },\n};\n\ndeclare global {\n interface Window {\n __STEPPY_VIDEO__?: SteppyVideoGlobal;\n }\n}\n\nwindow.__STEPPY_VIDEO__ = api;\n\nexport { mountVideoStage };\nexport type { VideoStage, VideoStageOptions };\n"],"names":["DEFAULT_TIMINGS","resolveStepContent","step","locale","layoutKey","override","t","e","s","o","n$2","r","n","i","S","c","h","a","l","p","d","u","f","b","y$1","y","v","_","m","g","$","E","A","C","P","V","N","x","I","L","z","H","M","R","k","Z","B","D","PALETTE","FONTS","BUBBLE_LOOK","BUTTON_LOOK","cssValue","value","unsafeCSS","baseStyles","css","sleep","ms","resolve","easeInOut","getDisplayScale","img","viewport","rect","scaleRect","bbox","scale","rectCenter","scaleBbox","travelDuration","from","to","speed","dx","dy","dist","bezierControlPoint","mx","my","nx","ny","CursorAnimator","opts","stage","behavior","tgt","done","frame","targets","targetIndex","index","cursor","center","duration","cp","start","now","raw","ripple","kbd","chars","per","ch","NEWTON_ITERATIONS","SUBDIVISION_EPSILON","bezierAt","a1","a2","bezierSlopeAt","cubicBezier","x1","y1","x2","y2","clamp01","progress","slope","lo","hi","easeInOutCss","easeOutCss","lerp","LAYOUTLESS_KEY","CURSOR_ORIGIN","RIPPLE_MS","RIPPLE_SCALE_FROM","RIPPLE_SCALE_TO","PULSE_MS","PULSE_SCALE_PEAK","CURSOR_FADE_MS","TYPE_TAIL_MS","KBD_OFFSET","DEFAULTS","targetCenter","target","actionDuration","timings","framesFor","resolveLayoutKey","manifest","layout","buildTimeline","options","fps","holdMs","minStepMs","narrationPadMs","introMs","outroMs","narrationMs","segments","cues","ripples","visibility","screenshots","cursorAt","cursorVisible","stepIndex","frames","stepStart","stepHasCursor","frameIndex","travelMs","actionMs","animatedMs","narration","wanted","lastFrame","content","durationMs","timeAtFrame","timeline","segmentAt","timeMs","found","mid","seg","cursorOpacityAt","visible","changedAt","change","elapsed","pulseScaleAt","half","rippleAt","active","event","typedTextAt","shown","pointOnCurve","control","stateAt","outro","cue","screenshot","opacity","point","span","lastKnownPoint","text","frameAt","samePoint","sameAlpha","frameStateEquals","evenDown","VIDEO_CSS","el","tag","cls","node","decoded","timeoutMs","settled","ok","timer","mountVideoStage","host","captions","root","style","shots","order","band","progressBar","caption","card","cardTitle","cardRule","cardText","cardLogo","watermark","stamp","width","height","previous","lastShot","missing","measureBand","tallest","texts","ready","budget","results","src","fonts","first","captureSize","firstCaptureSize","naturalW","naturalH","stageW","stageH","bandH","cap","avail","sx","sy","paint","state","isOutro","requireTimeline","tl","size","api"],"mappings":"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","x_google_ignoreList":[2,3,4,5]}
steppy/_templating.py ADDED
@@ -0,0 +1,117 @@
1
+ """Shared Jinja template location + environment construction.
2
+
3
+ **One precedence rule for every command** (`generate`, `guide`, `build`):
4
+
5
+ 1. an explicit ``templates_dir`` — hard error if it does not exist
6
+ 2. ``<project_root>/templates`` — used when the directory exists
7
+ 3. the bundled package templates — always the final fallback
8
+
9
+ The three consumers used to implement this three different ways, which produced
10
+ two user-visible traps:
11
+
12
+ * ``build`` resolved the local override against ``project_root`` while
13
+ ``generate`` and ``guide`` used ``Path.cwd()`` — so running steppy from
14
+ anywhere but the project root applied a project's ``templates/``
15
+ customisation to ``steppy build`` and silently not to the other two;
16
+ * ``generate`` additionally required the directory to contain top-level
17
+ ``*.j2`` files, so a project overriding only subdirectory templates
18
+ (``templates/static/guides.css``, ``templates/angular/component.ts.j2``)
19
+ had those honoured by ``build``/``guide`` and silently ignored by
20
+ ``generate``;
21
+ * an explicit-but-missing ``templates_dir`` was a hard error for ``generate``
22
+ and a silent fallback to bundled templates for the other two — dropping the
23
+ user's entire customisation while reporting success.
24
+
25
+ Callers register their own filters and globals on the returned environment; the
26
+ environment options themselves (``trim_blocks`` / ``lstrip_blocks`` /
27
+ ``keep_trailing_newline``) are load-bearing for generated-output byte stability
28
+ and are set here so they cannot drift between consumers.
29
+
30
+ A leaf module: it imports ``jinja2`` (which all three consumers already import)
31
+ and nothing else from ``steppy``, so the lazy-import guards
32
+ (``tests/test_no_parallel_import_on_default_path.py`` and siblings) are
33
+ unaffected.
34
+ """
35
+
36
+ import importlib.resources
37
+ from pathlib import Path
38
+ from typing import Optional
39
+
40
+ import jinja2
41
+
42
+
43
+ def bundled_templates_dir() -> Path:
44
+ """Path to the templates bundled with the installed ``steppy`` package.
45
+
46
+ This tree is *generated* from the repo-root ``templates/`` by the hatchling
47
+ build hook (see CLAUDE.md, "Single template source") and is the fallback
48
+ used when a project has no local ``templates/`` of its own.
49
+ """
50
+ return Path(importlib.resources.files("steppy") / "templates")
51
+
52
+
53
+ def template_search_paths(
54
+ templates_dir: Optional[Path],
55
+ project_root: Optional[Path] = None,
56
+ ) -> list[Path]:
57
+ """Resolve the template search path, most specific first.
58
+
59
+ See the module docstring for the rule. ``project_root`` defaults to the
60
+ current working directory, which is what every CLI invocation wants.
61
+
62
+ Raises:
63
+ ValueError: if ``templates_dir`` is given but does not exist. Silently
64
+ falling back would ship bundled templates while the user believes
65
+ their customisation is in effect.
66
+ """
67
+ root = project_root if project_root is not None else Path.cwd()
68
+ paths: list[Path] = []
69
+
70
+ if templates_dir is not None:
71
+ if not templates_dir.is_dir():
72
+ raise ValueError(
73
+ f"Templates directory not found: {templates_dir}. "
74
+ "Remove the option to use the project's templates/ directory "
75
+ "or the bundled defaults."
76
+ )
77
+ paths.append(templates_dir)
78
+
79
+ local = root / "templates"
80
+ if local.is_dir() and local not in paths:
81
+ paths.append(local)
82
+
83
+ paths.append(bundled_templates_dir())
84
+ return paths
85
+
86
+
87
+ def make_template_env(
88
+ templates_dir: Optional[Path] = None,
89
+ project_root: Optional[Path] = None,
90
+ *,
91
+ autoescape: bool = False,
92
+ ) -> jinja2.Environment:
93
+ """Build a Jinja environment over the unified template search path.
94
+
95
+ The options set here are the ones generated output depends on — changing
96
+ any of them changes every generated test file, so they live in exactly one
97
+ place. Callers add their own filters/globals afterwards.
98
+
99
+ ``autoescape`` defaults to **False**, and that default is load-bearing rather
100
+ than merely historical: the guide templates inject markdown-rendered HTML
101
+ through plain ``{{ }}``, so turning it on globally would silently escape every
102
+ ``<em>`` in every guide. It is opt-in for the one consumer whose input is
103
+ genuinely hostile — ``steppy report`` renders failure tails, which are
104
+ arbitrary page content — where escaping-by-default is the only safe posture
105
+ and a missed ``| e`` would be a hole rather than a cosmetic bug.
106
+
107
+ Note it applies to *every* template the environment loads, including CSS
108
+ rendered through it: a stylesheet under an autoescaping environment must
109
+ contain no ``{{ }}``, or a colour would come out HTML-escaped.
110
+ """
111
+ return jinja2.Environment(
112
+ loader=jinja2.FileSystemLoader([str(p) for p in template_search_paths(templates_dir, project_root)]),
113
+ trim_blocks=True,
114
+ lstrip_blocks=True,
115
+ keep_trailing_newline=True,
116
+ autoescape=autoescape,
117
+ )