@scenar/cli 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/example-bundle/assets/index-BoIR0_nN.js +147 -0
- package/example-bundle/assets/style-YRMeJPPX.css +1 -0
- package/example-bundle/index.html +2 -2
- package/example-bundle/pack-manifest.json +7 -7
- package/package.json +9 -5
- package/src/__tests__/pack-generate-embed-entry.test.ts +68 -3
- package/src/__tests__/run-shoot.test.ts +270 -0
- package/src/api.d.ts +3 -0
- package/src/api.d.ts.map +1 -1
- package/src/api.js +2 -0
- package/src/api.js.map +1 -1
- package/src/api.ts +5 -0
- package/src/commands/shoot.d.ts +3 -0
- package/src/commands/shoot.d.ts.map +1 -0
- package/src/commands/shoot.js +52 -0
- package/src/commands/shoot.js.map +1 -0
- package/src/commands/shoot.ts +72 -0
- package/src/index.d.ts.map +1 -1
- package/src/index.js +2 -0
- package/src/index.js.map +1 -1
- package/src/index.ts +2 -0
- package/src/pack/generate-embed-entry.d.ts +11 -0
- package/src/pack/generate-embed-entry.d.ts.map +1 -1
- package/src/pack/generate-embed-entry.js +82 -1
- package/src/pack/generate-embed-entry.js.map +1 -1
- package/src/pack/generate-embed-entry.ts +83 -1
- package/src/shoot/playwright-browser.d.ts +9 -0
- package/src/shoot/playwright-browser.d.ts.map +1 -0
- package/src/shoot/playwright-browser.js +92 -0
- package/src/shoot/playwright-browser.js.map +1 -0
- package/src/shoot/playwright-browser.ts +121 -0
- package/src/shoot/run-shoot.d.ts +52 -0
- package/src/shoot/run-shoot.d.ts.map +1 -0
- package/src/shoot/run-shoot.js +172 -0
- package/src/shoot/run-shoot.js.map +1 -0
- package/src/shoot/run-shoot.ts +251 -0
- package/src/shoot/types.d.ts +40 -0
- package/src/shoot/types.d.ts.map +1 -0
- package/src/shoot/types.js +2 -0
- package/src/shoot/types.js.map +1 -0
- package/src/shoot/types.ts +40 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/example-bundle/assets/index-CBaiZ4ek.js +0 -147
- package/example-bundle/assets/style-Ci-h7jik.css +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@source "./**/*.js";@layer scenar{.scenar{--scenar-surface: #ffffff;--scenar-border: #e5e7eb;--scenar-foreground: #0f172a;--scenar-muted-foreground: #64748b;--scenar-card: #ffffff;--scenar-accent: #f1f5f9;--scenar-primary: #0f172a;--scenar-ring: #0f172a;--scenar-chrome: #202124;--scenar-chrome-raised: #35363a;--scenar-chrome-foreground: #bdc1c6;--scenar-cursor-stroke: #ffffff;--scenar-backdrop-glow-1: #b7d4f2;--scenar-backdrop-glow-2: #e3d0ec;--scenar-backdrop-glow-3: #b4c4ea;--scenar-backdrop-base-1: #e4ecf7;--scenar-backdrop-base-2: #e6e1f0;--scenar-backdrop: radial-gradient(120% 100% at 12% 8%, var(--scenar-backdrop-glow-1) 0%, transparent 55%), radial-gradient(110% 95% at 88% 12%, var(--scenar-backdrop-glow-2) 0%, transparent 55%), radial-gradient(130% 110% at 70% 100%, var(--scenar-backdrop-glow-3) 0%, transparent 60%), linear-gradient(135deg, var(--scenar-backdrop-base-1) 0%, var(--scenar-backdrop-base-2) 100%);--scenar-shadow-window: 0 24px 64px -16px rgb(15 23 42 / .35), 0 4px 16px -4px rgb(15 23 42 / .2);--scenar-radius-window: 10px}.scenar.dark{--scenar-surface: #0f172a;--scenar-border: #1e293b;--scenar-foreground: #f8fafc;--scenar-muted-foreground: #94a3b8;--scenar-card: #1e293b;--scenar-accent: #1e293b;--scenar-primary: #f8fafc;--scenar-ring: #f8fafc;--scenar-chrome: #202124;--scenar-chrome-raised: #35363a;--scenar-chrome-foreground: #bdc1c6;--scenar-cursor-stroke: #ffffff;--scenar-backdrop-glow-1: #1c3a63;--scenar-backdrop-glow-2: #372a5e;--scenar-backdrop-glow-3: #142647;--scenar-backdrop-base-1: #101828;--scenar-backdrop-base-2: #14122a;--scenar-shadow-window: 0 24px 64px -16px rgb(0 0 0 / .65), 0 4px 16px -4px rgb(0 0 0 / .4);--scenar-radius-window: 10px}}/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-duration:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-4xl:56rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wider:.05em;--leading-relaxed:1.625;--radius-sm:.25rem;--radius-md:.375rem;--radius-lg:.5rem;--drop-shadow-sm:0 1px 2px #00000026;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-foreground:var(--scenar-foreground);--color-border:var(--scenar-border)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing) * 0)}.inset-x-0{inset-inline:calc(var(--spacing) * 0)}.inset-y-0{inset-block:calc(var(--spacing) * 0)}.start{inset-inline-start:var(--spacing)}.end{inset-inline-end:var(--spacing)}.top-0{top:calc(var(--spacing) * 0)}.top-1{top:calc(var(--spacing) * 1)}.top-1\/2{top:50%}.top-3{top:calc(var(--spacing) * 3)}.-right-px{right:-1px}.right-0{right:calc(var(--spacing) * 0)}.-bottom-px{bottom:-1px}.bottom-0{bottom:calc(var(--spacing) * 0)}.bottom-1{bottom:calc(var(--spacing) * 1)}.bottom-2{bottom:calc(var(--spacing) * 2)}.bottom-full{bottom:100%}.left-0{left:calc(var(--spacing) * 0)}.left-1\/2{left:50%}.left-4{left:calc(var(--spacing) * 4)}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.z-\[15\]{z-index:15}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.mx-auto{margin-inline:auto}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mr-0\.5{margin-right:calc(var(--spacing) * .5)}.mr-1{margin-right:calc(var(--spacing) * 1)}.mr-1\.5{margin-right:calc(var(--spacing) * 1.5)}.mr-3{margin-right:calc(var(--spacing) * 3)}.mb-0\.5{margin-bottom:calc(var(--spacing) * .5)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.ml-0\.5{margin-left:calc(var(--spacing) * .5)}.ml-1{margin-left:calc(var(--spacing) * 1)}.ml-4{margin-left:calc(var(--spacing) * 4)}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2{height:calc(var(--spacing) * 2)}.h-2\.5{height:calc(var(--spacing) * 2.5)}.h-3{height:calc(var(--spacing) * 3)}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-10{height:calc(var(--spacing) * 10)}.h-16{height:calc(var(--spacing) * 16)}.h-\[5px\]{height:5px}.h-\[7px\]{height:7px}.h-\[14px\]{height:14px}.h-\[15px\]{height:15px}.h-full{height:100%}.min-h-0{min-height:calc(var(--spacing) * 0)}.w-0\.5{width:calc(var(--spacing) * .5)}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-1\/3{width:33.3333%}.w-2\.5{width:calc(var(--spacing) * 2.5)}.w-3{width:calc(var(--spacing) * 3)}.w-3\.5{width:calc(var(--spacing) * 3.5)}.w-4{width:calc(var(--spacing) * 4)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-7{width:calc(var(--spacing) * 7)}.w-8{width:calc(var(--spacing) * 8)}.w-9{width:calc(var(--spacing) * 9)}.w-16{width:calc(var(--spacing) * 16)}.w-\[3px\]{width:3px}.w-\[7px\]{width:7px}.w-\[14px\]{width:14px}.w-\[15px\]{width:15px}.w-\[42px\]{width:42px}.w-\[160px\]{width:160px}.w-full{width:100%}.w-px{width:1px}.max-w-4xl{max-width:var(--container-4xl)}.max-w-\[80\%\]{max-width:80%}.max-w-\[180px\]{max-width:180px}.max-w-\[200px\]{max-width:200px}.min-w-0{min-width:calc(var(--spacing) * 0)}.min-w-\[2\.5rem\]{min-width:2.5rem}.flex-1{flex:1}.shrink-0{flex-shrink:0}.-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-x-2{--tw-translate-x:calc(var(--spacing) * -2);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-x-px{--tw-translate-x:-1px;translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-2{--tw-translate-y:calc(var(--spacing) * -2);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-px{--tw-translate-y:-1px;translate:var(--tw-translate-x) var(--tw-translate-y)}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.cursor-pointer{cursor:pointer}.resize{resize:both}.flex-col{flex-direction:column}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-\[5px\]{gap:5px}:where(.space-y-2\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-sm{border-radius:var(--radius-sm)}.rounded-t-lg{border-top-left-radius:var(--radius-lg);border-top-right-radius:var(--radius-lg)}.rounded-r{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.rounded-b-lg{border-bottom-right-radius:var(--radius-lg);border-bottom-left-radius:var(--radius-lg)}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-\[\#1a1a1a\]{border-color:#1a1a1a}.border-\[\#1e1e1e\]{border-color:#1e1e1e}.border-\[\#2a2a2e\]{border-color:#2a2a2e}.border-\[\#2d2d2d\]{border-color:#2d2d2d}.border-\[\#3a3a3a\]{border-color:#3a3a3a}.border-\[\#3a3f47\]{border-color:#3a3f47}.border-\[\#3c4043\]{border-color:#3c4043}.border-\[\#007acc\]{border-color:#007acc}.border-\[\#ff6c37\]{border-color:#ff6c37}.border-\[var\(--scenar-border\)\],.border-border{border-color:var(--scenar-border)}.border-transparent{border-color:#0000}.bg-\[\#0b93f6\]{background-color:#0b93f6}.bg-\[\#1a1a1a\]{background-color:#1a1a1a}.bg-\[\#1a73e8\]{background-color:#1a73e8}.bg-\[\#1c1c1c\]{background-color:#1c1c1c}.bg-\[\#1e1e1e\]{background-color:#1e1e1e}.bg-\[\#2a2a2e\]{background-color:#2a2a2e}.bg-\[\#2c2c2c\]{background-color:#2c2c2c}.bg-\[\#2d2d2d\]{background-color:#2d2d2d}.bg-\[\#3b82f6\]{background-color:#3b82f6}.bg-\[\#3b82f6\]\/10{background-color:#3b82f61a}.bg-\[\#3b82f6\]\/15{background-color:#3b82f626}.bg-\[\#5f6368\]{background-color:#5f6368}.bg-\[\#007acc\]{background-color:#007acc}.bg-\[\#007acc\]\/10{background-color:#007acc1a}.bg-\[\#22c55e\]{background-color:#22c55e}.bg-\[\#22c55e\]\/15{background-color:#22c55e26}.bg-\[\#28c840\]{background-color:#28c840}.bg-\[\#94a3b8\]\/15{background-color:#94a3b826}.bg-\[\#181b1f\]{background-color:#181b1f}.bg-\[\#999\]{background-color:#999}.bg-\[\#3274d9\]{background-color:#3274d9}.bg-\[\#04395e\]{background-color:#04395e}.bg-\[\#6366f1\]{background-color:#6366f1}.bg-\[\#111217\]{background-color:#111217}.bg-\[\#202124\]{background-color:#202124}.bg-\[\#252526\]{background-color:#252526}.bg-\[\#323232\]{background-color:#323232}.bg-\[\#323233\]{background-color:#323233}.bg-\[\#333333\]{background-color:#333}.bg-\[\#404040\]{background-color:#404040}.bg-\[\#eab308\]\/15{background-color:#eab30826}.bg-\[\#ef4444\]\/15{background-color:#ef444426}.bg-\[\#febc2e\]{background-color:#febc2e}.bg-\[\#ff5f57\]{background-color:#ff5f57}.bg-\[var\(--scenar-accent\)\]{background-color:var(--scenar-accent)}.bg-\[var\(--scenar-card\)\]{background-color:var(--scenar-card)}.bg-\[var\(--scenar-chrome\)\]{background-color:var(--scenar-chrome)}.bg-\[var\(--scenar-chrome-raised\)\]{background-color:var(--scenar-chrome-raised)}.bg-\[var\(--scenar-surface\)\]{background-color:var(--scenar-surface)}.bg-black{background-color:var(--color-black)}.bg-black\/50{background-color:#00000080}@supports (color:color-mix(in lab,red,red)){.bg-black\/50{background-color:color-mix(in oklab,var(--color-black) 50%,transparent)}}.bg-black\/60{background-color:#0009}@supports (color:color-mix(in lab,red,red)){.bg-black\/60{background-color:color-mix(in oklab,var(--color-black) 60%,transparent)}}.bg-black\/70{background-color:#000000b3}@supports (color:color-mix(in lab,red,red)){.bg-black\/70{background-color:color-mix(in oklab,var(--color-black) 70%,transparent)}}.bg-card{background-color:var(--scenar-card)}.bg-primary\/25{background-color:var(--scenar-primary)}@supports (color:color-mix(in lab,red,red)){.bg-primary\/25{background-color:color-mix(in oklab,var(--scenar-primary) 25%,transparent)}}.bg-white{background-color:var(--color-white)}.bg-white\/30{background-color:#ffffff4d}@supports (color:color-mix(in lab,red,red)){.bg-white\/30{background-color:color-mix(in oklab,var(--color-white) 30%,transparent)}}.bg-white\/80{background-color:#fffc}@supports (color:color-mix(in lab,red,red)){.bg-white\/80{background-color:color-mix(in oklab,var(--color-white) 80%,transparent)}}.bg-gradient-to-br{--tw-gradient-position:to bottom right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.bg-gradient-to-t{--tw-gradient-position:to top in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.from-\[\#6366f1\]{--tw-gradient-from:#6366f1;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-\[\#ff6600\]{--tw-gradient-from:#f60;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-black\/70{--tw-gradient-from:#000000b3}@supports (color:color-mix(in lab,red,red)){.from-black\/70{--tw-gradient-from:color-mix(in oklab, var(--color-black) 70%, transparent)}}.from-black\/70{--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.via-black\/30{--tw-gradient-via:#0000004d}@supports (color:color-mix(in lab,red,red)){.via-black\/30{--tw-gradient-via:color-mix(in oklab, var(--color-black) 30%, transparent)}}.via-black\/30{--tw-gradient-via-stops:var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.to-\[\#8b5cf6\]{--tw-gradient-to:#8b5cf6;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-\[\#f5a623\]{--tw-gradient-to:#f5a623;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-transparent{--tw-gradient-to:transparent;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-3\.5{padding-inline:calc(var(--spacing) * 3.5)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-6{padding-block:calc(var(--spacing) * 6)}.py-\[2px\]{padding-block:2px}.pt-1{padding-top:calc(var(--spacing) * 1)}.pt-1\.5{padding-top:calc(var(--spacing) * 1.5)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pt-10{padding-top:calc(var(--spacing) * 10)}.pt-\[10px\]{padding-top:10px}.pt-\[14px\]{padding-top:14px}.pr-1{padding-right:calc(var(--spacing) * 1)}.pr-2{padding-right:calc(var(--spacing) * 2)}.pr-3{padding-right:calc(var(--spacing) * 3)}.pr-4{padding-right:calc(var(--spacing) * 4)}.pb-1{padding-bottom:calc(var(--spacing) * 1)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pl-1{padding-left:calc(var(--spacing) * 1)}.pl-1\.5{padding-left:calc(var(--spacing) * 1.5)}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[8px\]{font-size:8px}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.text-\[14px\]{font-size:14px}.text-\[16px\]{font-size:16px}.leading-\[1\.6\]{--tw-leading:1.6;line-height:1.6}.leading-\[18px\]{--tw-leading:18px;line-height:18px}.leading-none{--tw-leading:1;line-height:1}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.whitespace-pre{white-space:pre}.whitespace-pre-wrap{white-space:pre-wrap}.text-\[\#3b82f6\]{color:#3b82f6}.text-\[\#5f6368\]{color:#5f6368}.text-\[\#6e7681\]{color:#6e7681}.text-\[\#9aa0a6\]{color:#9aa0a6}.text-\[\#9d9d9d\]{color:#9d9d9d}.text-\[\#22c55e\]{color:#22c55e}.text-\[\#50fa7b\]{color:#50fa7b}.text-\[\#94a3b8\]{color:#94a3b8}.text-\[\#519aba\]{color:#519aba}.text-\[\#666\]{color:#666}.text-\[\#888\]{color:#888}.text-\[\#64748b\]{color:#64748b}.text-\[\#666666\]{color:#666}.text-\[\#858585\]{color:#858585}.text-\[\#a0a0a0\]{color:#a0a0a0}.text-\[\#bd93f9\]{color:#bd93f9}.text-\[\#bdc1c6\]{color:#bdc1c6}.text-\[\#c6c6c6\]{color:#c6c6c6}.text-\[\#cccccc\]{color:#ccc}.text-\[\#d4d4d4\]{color:#d4d4d4}.text-\[\#dcb67a\]{color:#dcb67a}.text-\[\#e8e8e8\]{color:#e8e8e8}.text-\[\#e8eaed\]{color:#e8eaed}.text-\[\#e6995b\]{color:#e6995b}.text-\[\#eab308\]{color:#eab308}.text-\[\#ef4444\]{color:#ef4444}.text-\[\#f8f8f2\]{color:#f8f8f2}.text-\[\#f8f8f2\]\/70{color:#f8f8f2b3}.text-\[\#ff5555\]{color:#f55}.text-\[\#ffffff\]{color:#fff}.text-\[var\(--scenar-chrome-foreground\)\]{color:var(--scenar-chrome-foreground)}.text-\[var\(--scenar-foreground\)\]{color:var(--scenar-foreground)}.text-\[var\(--scenar-muted-foreground\)\]{color:var(--scenar-muted-foreground)}.text-foreground{color:var(--scenar-foreground)}.text-muted-foreground{color:var(--scenar-muted-foreground)}.text-primary{color:var(--scenar-primary)}.text-white{color:var(--color-white)}.text-white\/40{color:#fff6}@supports (color:color-mix(in lab,red,red)){.text-white\/40{color:color-mix(in oklab,var(--color-white) 40%,transparent)}}.text-white\/70{color:#ffffffb3}@supports (color:color-mix(in lab,red,red)){.text-white\/70{color:color-mix(in oklab,var(--color-white) 70%,transparent)}}.text-white\/90{color:#ffffffe6}@supports (color:color-mix(in lab,red,red)){.text-white\/90{color:color-mix(in oklab,var(--color-white) 90%,transparent)}}.uppercase{text-transform:uppercase}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.opacity-0{opacity:0}.opacity-100{opacity:1}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.drop-shadow-sm{--tw-drop-shadow-size:drop-shadow(0 1px 2px var(--tw-drop-shadow-color,#00000026));--tw-drop-shadow:drop-shadow(var(--drop-shadow-sm));filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[height\]{transition-property:height;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-150{--tw-duration:.15s;transition-duration:.15s}.select-none{-webkit-user-select:none;user-select:none}@media (hover:hover){.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.last\:border-b-0:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}@media (hover:hover){.hover\:h-2:hover{height:calc(var(--spacing) * 2)}.hover\:scale-105:hover{--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x) var(--tw-scale-y)}.hover\:bg-accent:hover{background-color:var(--scenar-accent)}.hover\:text-white:hover{color:var(--color-white)}}}@layer scenar{.scenar{--scenar-surface:#fff;--scenar-border:#e5e7eb;--scenar-foreground:#0f172a;--scenar-muted-foreground:#64748b;--scenar-card:#fff;--scenar-accent:#f1f5f9;--scenar-primary:#0f172a;--scenar-ring:#0f172a;--scenar-chrome:#202124;--scenar-chrome-raised:#35363a;--scenar-chrome-foreground:#bdc1c6;--scenar-cursor-stroke:#fff;--scenar-backdrop-glow-1:#b7d4f2;--scenar-backdrop-glow-2:#e3d0ec;--scenar-backdrop-glow-3:#b4c4ea;--scenar-backdrop-base-1:#e4ecf7;--scenar-backdrop-base-2:#e6e1f0;--scenar-backdrop:radial-gradient(120% 100% at 12% 8%, var(--scenar-backdrop-glow-1) 0%, transparent 55%), radial-gradient(110% 95% at 88% 12%, var(--scenar-backdrop-glow-2) 0%, transparent 55%), radial-gradient(130% 110% at 70% 100%, var(--scenar-backdrop-glow-3) 0%, transparent 60%), linear-gradient(135deg, var(--scenar-backdrop-base-1) 0%, var(--scenar-backdrop-base-2) 100%);--scenar-shadow-window:0 24px 64px -16px #0f172a59, 0 4px 16px -4px #0f172a33;--scenar-radius-window:10px}.scenar.dark{--scenar-surface:#0f172a;--scenar-border:#1e293b;--scenar-foreground:#f8fafc;--scenar-muted-foreground:#94a3b8;--scenar-card:#1e293b;--scenar-accent:#1e293b;--scenar-primary:#f8fafc;--scenar-ring:#f8fafc;--scenar-chrome:#202124;--scenar-chrome-raised:#35363a;--scenar-chrome-foreground:#bdc1c6;--scenar-cursor-stroke:#fff;--scenar-backdrop-glow-1:#1c3a63;--scenar-backdrop-glow-2:#372a5e;--scenar-backdrop-glow-3:#142647;--scenar-backdrop-base-1:#101828;--scenar-backdrop-base-2:#14122a;--scenar-shadow-window:0 24px 64px -16px #000000a6, 0 4px 16px -4px #0006;--scenar-radius-window:10px}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"<length-percentage>";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"<length-percentage>";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"<length-percentage>";inherits:false;initial-value:100%}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
<style>
|
|
9
9
|
html, body { margin: 0; background: transparent; }
|
|
10
10
|
</style>
|
|
11
|
-
<script type="module" crossorigin src="./assets/index-
|
|
12
|
-
<link rel="stylesheet" crossorigin href="./assets/style-
|
|
11
|
+
<script type="module" crossorigin src="./assets/index-BoIR0_nN.js"></script>
|
|
12
|
+
<link rel="stylesheet" crossorigin href="./assets/style-YRMeJPPX.css">
|
|
13
13
|
</head>
|
|
14
14
|
<body>
|
|
15
15
|
<div id="root"></div>
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
"scenarioId": "welcome-tour",
|
|
4
4
|
"files": [
|
|
5
5
|
{
|
|
6
|
-
"path": "assets/index-
|
|
7
|
-
"sha256": "
|
|
8
|
-
"sizeBytes":
|
|
6
|
+
"path": "assets/index-BoIR0_nN.js",
|
|
7
|
+
"sha256": "60f9f26f1c07989ce17e2266c1f1e828006042a300a4d184321a45188dc72b2c",
|
|
8
|
+
"sizeBytes": 382188,
|
|
9
9
|
"contentType": "text/javascript"
|
|
10
10
|
},
|
|
11
11
|
{
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
"contentType": "image/png"
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
|
-
"path": "assets/style-
|
|
19
|
-
"sha256": "
|
|
20
|
-
"sizeBytes":
|
|
18
|
+
"path": "assets/style-YRMeJPPX.css",
|
|
19
|
+
"sha256": "5b8b77d9bb6b9795e7fdad32a88c6b30c889de4065efd25c4622aaf584d4483a",
|
|
20
|
+
"sizeBytes": 33747,
|
|
21
21
|
"contentType": "text/css"
|
|
22
22
|
},
|
|
23
23
|
{
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
"path": "index.html",
|
|
31
|
-
"sha256": "
|
|
31
|
+
"sha256": "72c66787f6db94f0a1240c4afd3ef33fde6fcf106b2cb5e47bf51bb8ffd5d2d8",
|
|
32
32
|
"sizeBytes": 533,
|
|
33
33
|
"contentType": "text/html"
|
|
34
34
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scenar/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Scenar CLI — validate scenarios, generate narration, and render videos.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -39,9 +39,9 @@
|
|
|
39
39
|
}
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@scenar/core": "0.
|
|
43
|
-
"@scenar/embed": "0.
|
|
44
|
-
"@scenar/sdk": "0.
|
|
42
|
+
"@scenar/core": "0.9.0",
|
|
43
|
+
"@scenar/embed": "0.9.0",
|
|
44
|
+
"@scenar/sdk": "0.9.0",
|
|
45
45
|
"commander": "^13.0.0",
|
|
46
46
|
"yaml": "^2.7.0"
|
|
47
47
|
},
|
|
@@ -52,7 +52,8 @@
|
|
|
52
52
|
"@remotion/renderer": "4.0.448",
|
|
53
53
|
"@remotion/bundler": "4.0.448",
|
|
54
54
|
"vite": ">=6.0.0",
|
|
55
|
-
"@vitejs/plugin-react": ">=4.3.0"
|
|
55
|
+
"@vitejs/plugin-react": ">=4.3.0",
|
|
56
|
+
"playwright": ">=1.50.0"
|
|
56
57
|
},
|
|
57
58
|
"peerDependenciesMeta": {
|
|
58
59
|
"echogarden": {
|
|
@@ -75,6 +76,9 @@
|
|
|
75
76
|
},
|
|
76
77
|
"@vitejs/plugin-react": {
|
|
77
78
|
"optional": true
|
|
79
|
+
},
|
|
80
|
+
"playwright": {
|
|
81
|
+
"optional": true
|
|
78
82
|
}
|
|
79
83
|
}
|
|
80
84
|
}
|
|
@@ -48,9 +48,10 @@ describe("generateEmbedEntry", () => {
|
|
|
48
48
|
const src = generateEmbedEntry({ ...BASE, hasNarration: false, providersPath: null });
|
|
49
49
|
expect(src).toContain('import { useCallback, useRef, useState } from "react";');
|
|
50
50
|
// ScenarioPlayer/DemoViewport/SCENAR_CLASS plus Cursor, useStepInteractions,
|
|
51
|
-
// ViewportTransformLayer, VIEWPORT_TRANSFORM_IDENTITY
|
|
51
|
+
// ViewportTransformLayer, VIEWPORT_TRANSFORM_IDENTITY (playback) and
|
|
52
|
+
// ScenarioCaptureMount (the ?shot capture branch) all come from @scenar/react.
|
|
52
53
|
expect(src).toContain(
|
|
53
|
-
'import { ScenarioPlayer, DemoViewport, SCENAR_CLASS, Cursor, useStepInteractions, ViewportTransformLayer, VIEWPORT_TRANSFORM_IDENTITY } from "@scenar/react";',
|
|
54
|
+
'import { ScenarioPlayer, DemoViewport, SCENAR_CLASS, Cursor, useStepInteractions, ViewportTransformLayer, VIEWPORT_TRANSFORM_IDENTITY, ScenarioCaptureMount } from "@scenar/react";',
|
|
54
55
|
);
|
|
55
56
|
});
|
|
56
57
|
|
|
@@ -143,7 +144,7 @@ describe("generateEmbedEntry", () => {
|
|
|
143
144
|
// the manifest from its own relative location, so clip src values resolve
|
|
144
145
|
// against ./narration/ at runtime.
|
|
145
146
|
expect(withNarration).toContain(
|
|
146
|
-
'import { ScenarioPlayer, DemoViewport, SCENAR_CLASS, Cursor, useStepInteractions, ViewportTransformLayer, VIEWPORT_TRANSFORM_IDENTITY, useNarrationManifest } from "@scenar/react";',
|
|
147
|
+
'import { ScenarioPlayer, DemoViewport, SCENAR_CLASS, Cursor, useStepInteractions, ViewportTransformLayer, VIEWPORT_TRANSFORM_IDENTITY, ScenarioCaptureMount, useNarrationManifest } from "@scenar/react";',
|
|
147
148
|
);
|
|
148
149
|
expect(withNarration).toContain('const _resolveManifestUrl = () => "./narration/manifest.json";');
|
|
149
150
|
expect(withNarration).toContain(
|
|
@@ -169,6 +170,70 @@ describe("generateEmbedEntry", () => {
|
|
|
169
170
|
});
|
|
170
171
|
});
|
|
171
172
|
|
|
173
|
+
describe("generateEmbedEntry capture branch (?shot)", () => {
|
|
174
|
+
it("branches on ?shot at module load and keeps the playback mount as the default", () => {
|
|
175
|
+
const src = generateEmbedEntry({ ...BASE, hasNarration: false, providersPath: null });
|
|
176
|
+
// Read once, outside React, exactly like ?theme.
|
|
177
|
+
expect(src).toContain('new URLSearchParams(window.location.search).get("shot")');
|
|
178
|
+
// Bare `?shot` (empty string) must still enter capture mode, so the
|
|
179
|
+
// guard is a null check, not truthiness.
|
|
180
|
+
expect(src).toContain("if (_shotParam !== null) {");
|
|
181
|
+
// The production embed path is untouched: no param means the exact
|
|
182
|
+
// playback mount that shipped before this branch existed.
|
|
183
|
+
expect(src).toContain("createRoot(_rootEl).render(<_App />);");
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it("renders ScenarioCaptureMount with the same inputs as the playback tree", () => {
|
|
187
|
+
const src = generateEmbedEntry({
|
|
188
|
+
...BASE,
|
|
189
|
+
hasNarration: false,
|
|
190
|
+
providersPath: "/proj/.scenar/providers.tsx",
|
|
191
|
+
stage: true,
|
|
192
|
+
});
|
|
193
|
+
expect(src).toContain("<ScenarioCaptureMount");
|
|
194
|
+
expect(src).toContain('scenarioId={"welcome-tour"}');
|
|
195
|
+
expect(src).toContain("steps={_steps}");
|
|
196
|
+
expect(src).toContain("renderStep={renderStep}");
|
|
197
|
+
expect(src).toContain("canonicalWidth={896}");
|
|
198
|
+
expect(src).toContain("shellHeight={480}");
|
|
199
|
+
expect(src).toContain("stage={true}");
|
|
200
|
+
expect(src).toContain("providers={_Providers}");
|
|
201
|
+
// The capture tree carries the theme-derived root class, same as playback.
|
|
202
|
+
expect(src).toContain('<div className={_rootClass}>');
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("omits providers and stage when the scenario has neither", () => {
|
|
206
|
+
const src = generateEmbedEntry({ ...BASE, hasNarration: false, providersPath: null });
|
|
207
|
+
expect(src).toContain("stage={false}");
|
|
208
|
+
expect(src).toContain("providers={undefined}");
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it("wires the window contract scenar shoot consumes", () => {
|
|
212
|
+
const src = generateEmbedEntry({ ...BASE, hasNarration: false, providersPath: null });
|
|
213
|
+
expect(src).toContain("(window as any).__scenarShot = driver;");
|
|
214
|
+
expect(src).toContain("(window as any).__scenarShotError");
|
|
215
|
+
// ?shot=<name> deep-links auto-walk to the named shot; a bad name is a
|
|
216
|
+
// reported error listing what IS declared, not a silent no-op.
|
|
217
|
+
expect(src).toContain("driver.shots.find((s: any) => s.name === _shotParam)");
|
|
218
|
+
expect(src).toContain("void driver.walkTo(_target.timeMs);");
|
|
219
|
+
expect(src).toContain('no shot named');
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it("fetches the narration manifest before mounting and fails loudly", () => {
|
|
223
|
+
// Shot times are narration-driven: capturing without the manifest would
|
|
224
|
+
// silently shoot every frame at the wrong time, so the capture branch
|
|
225
|
+
// must load it itself (never via useNarrationManifest, whose fetch
|
|
226
|
+
// failure is silent) and refuse to mount on failure.
|
|
227
|
+
const withNarration = generateEmbedEntry({ ...BASE, hasNarration: true, providersPath: null });
|
|
228
|
+
expect(withNarration).toContain('await fetch("./narration/manifest.json")');
|
|
229
|
+
expect(withNarration).toContain("refusing to capture without it");
|
|
230
|
+
|
|
231
|
+
const without = generateEmbedEntry({ ...BASE, hasNarration: false, providersPath: null });
|
|
232
|
+
expect(without).toContain("const _captureManifest = undefined;");
|
|
233
|
+
expect(without).not.toContain('await fetch("./narration/manifest.json")');
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
|
|
172
237
|
describe("generateEmbedHtml", () => {
|
|
173
238
|
it("references the entry as an external module script (CSP-safe, no inline code)", () => {
|
|
174
239
|
const html = generateEmbedHtml("welcome-tour", "entry.tsx");
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { mkdtemp, mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { describe, expect, it } from "vitest";
|
|
6
|
+
import type { ScenarioShot } from "@scenar/core";
|
|
7
|
+
import { STILLS_DIR, runShoot } from "../shoot/run-shoot.js";
|
|
8
|
+
import type { PackManifest } from "../pack/pack-manifest.js";
|
|
9
|
+
import type { ShotBrowser, ShotTheme } from "../shoot/types.js";
|
|
10
|
+
|
|
11
|
+
const SHOTS: ScenarioShot[] = [
|
|
12
|
+
{ name: "opening", timeMs: 2999, stepIndex: 0 },
|
|
13
|
+
{ name: "detail-open", timeMs: 6999, stepIndex: 2 },
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
/** Write the minimal three files that make a directory a shootable bundle. */
|
|
17
|
+
async function makeBundle(): Promise<string> {
|
|
18
|
+
const dir = await mkdtemp(join(tmpdir(), "scenar-shoot-"));
|
|
19
|
+
await writeFile(join(dir, "index.html"), "<!doctype html><div id='root'></div>", "utf-8");
|
|
20
|
+
await writeFile(
|
|
21
|
+
join(dir, "scenario.json"),
|
|
22
|
+
JSON.stringify({
|
|
23
|
+
schemaVersion: "1",
|
|
24
|
+
id: "lab-tour",
|
|
25
|
+
generator: "@scenar/cli pack 0.0.1",
|
|
26
|
+
viewport: { width: 896, height: 480 },
|
|
27
|
+
}),
|
|
28
|
+
"utf-8",
|
|
29
|
+
);
|
|
30
|
+
await writeFile(
|
|
31
|
+
join(dir, "pack-manifest.json"),
|
|
32
|
+
JSON.stringify({ schemaVersion: 1, scenarioId: "lab-tour", files: [] }),
|
|
33
|
+
"utf-8",
|
|
34
|
+
);
|
|
35
|
+
return dir;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface FakeKnobs {
|
|
39
|
+
/** Shot list every session reports (default {@link SHOTS}). */
|
|
40
|
+
shots?: ScenarioShot[];
|
|
41
|
+
/** Shot list per theme — for the cross-theme divergence test. */
|
|
42
|
+
shotsFor?: (theme: ShotTheme) => ScenarioShot[];
|
|
43
|
+
/** Error thrown from open() — simulates window.__scenarShotError. */
|
|
44
|
+
openError?: string;
|
|
45
|
+
/** Image bytes per (theme, shot, per-theme session number). */
|
|
46
|
+
imageFor?: (theme: ShotTheme, shotName: string, sessionIndex: number) => Buffer;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface SessionLog {
|
|
50
|
+
theme: ShotTheme;
|
|
51
|
+
url: string;
|
|
52
|
+
walks: number[];
|
|
53
|
+
closed: boolean;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** A ShotBrowser fake that records every interaction for assertions. */
|
|
57
|
+
function makeFakeBrowser(knobs: FakeKnobs = {}) {
|
|
58
|
+
const sessions: SessionLog[] = [];
|
|
59
|
+
const perThemeCount = new Map<ShotTheme, number>();
|
|
60
|
+
let browserClosed = false;
|
|
61
|
+
|
|
62
|
+
const imageFor =
|
|
63
|
+
knobs.imageFor ??
|
|
64
|
+
((theme: ShotTheme, shotName: string) => Buffer.from(`png:${theme}:${shotName}`));
|
|
65
|
+
|
|
66
|
+
const browser: ShotBrowser = {
|
|
67
|
+
async newSession({ theme }) {
|
|
68
|
+
const sessionIndex = perThemeCount.get(theme) ?? 0;
|
|
69
|
+
perThemeCount.set(theme, sessionIndex + 1);
|
|
70
|
+
const log: SessionLog = { theme, url: "", walks: [], closed: false };
|
|
71
|
+
sessions.push(log);
|
|
72
|
+
const shots = knobs.shotsFor?.(theme) ?? knobs.shots ?? SHOTS;
|
|
73
|
+
let lastWalkedShot = "";
|
|
74
|
+
return {
|
|
75
|
+
async open(url) {
|
|
76
|
+
log.url = url;
|
|
77
|
+
if (knobs.openError) throw new Error(`the capture page reported: ${knobs.openError}`);
|
|
78
|
+
return { shots, frameSelector: "[data-scenar-shot-frame]" };
|
|
79
|
+
},
|
|
80
|
+
async walkTo(timeMs) {
|
|
81
|
+
log.walks.push(timeMs);
|
|
82
|
+
lastWalkedShot = shots.find((s) => s.timeMs === timeMs)?.name ?? "unknown";
|
|
83
|
+
},
|
|
84
|
+
async screenshotFrame() {
|
|
85
|
+
return imageFor(theme, lastWalkedShot, sessionIndex);
|
|
86
|
+
},
|
|
87
|
+
async close() {
|
|
88
|
+
log.closed = true;
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
},
|
|
92
|
+
async close() {
|
|
93
|
+
browserClosed = true;
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
return { browser, sessions, isClosed: () => browserClosed };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async function readManifest(bundleDir: string): Promise<PackManifest> {
|
|
101
|
+
return JSON.parse(await readFile(join(bundleDir, "pack-manifest.json"), "utf-8"));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
describe("runShoot", () => {
|
|
105
|
+
it("captures every shot per theme, in timeline order, into stills/", async () => {
|
|
106
|
+
const bundleDir = await makeBundle();
|
|
107
|
+
const fake = makeFakeBrowser();
|
|
108
|
+
|
|
109
|
+
const result = await runShoot({ bundleDir, browserFactory: async () => fake.browser });
|
|
110
|
+
|
|
111
|
+
expect(result.scenarioId).toBe("lab-tour");
|
|
112
|
+
expect(result.shots).toEqual(SHOTS);
|
|
113
|
+
expect(result.files).toEqual([
|
|
114
|
+
"stills/opening.light.png",
|
|
115
|
+
"stills/detail-open.light.png",
|
|
116
|
+
"stills/opening.dark.png",
|
|
117
|
+
"stills/detail-open.dark.png",
|
|
118
|
+
]);
|
|
119
|
+
// One session per theme, each walking the timeline in order.
|
|
120
|
+
expect(fake.sessions.map((s) => s.theme)).toEqual(["light", "dark"]);
|
|
121
|
+
for (const session of fake.sessions) {
|
|
122
|
+
expect(session.walks).toEqual([2999, 6999]);
|
|
123
|
+
expect(session.closed).toBe(true);
|
|
124
|
+
}
|
|
125
|
+
expect(fake.isClosed()).toBe(true);
|
|
126
|
+
// The written bytes are the session's screenshots.
|
|
127
|
+
const opening = await readFile(join(bundleDir, STILLS_DIR, "opening.light.png"));
|
|
128
|
+
expect(opening.toString()).toBe("png:light:opening");
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("passes ?shot to every session and adds ?theme=dark only for dark", async () => {
|
|
132
|
+
const bundleDir = await makeBundle();
|
|
133
|
+
const fake = makeFakeBrowser();
|
|
134
|
+
|
|
135
|
+
await runShoot({ bundleDir, browserFactory: async () => fake.browser });
|
|
136
|
+
|
|
137
|
+
const [light, dark] = fake.sessions;
|
|
138
|
+
expect(light!.url).toMatch(/\?shot$/);
|
|
139
|
+
expect(dark!.url).toMatch(/\?shot&theme=dark$/);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("rebuilds the pack manifest so deploys ship the stills", async () => {
|
|
143
|
+
const bundleDir = await makeBundle();
|
|
144
|
+
const fake = makeFakeBrowser();
|
|
145
|
+
|
|
146
|
+
await runShoot({ bundleDir, browserFactory: async () => fake.browser });
|
|
147
|
+
|
|
148
|
+
const manifest = await readManifest(bundleDir);
|
|
149
|
+
const stillEntries = manifest.files.filter((f) => f.path.startsWith("stills/"));
|
|
150
|
+
expect(stillEntries.map((f) => f.path).sort()).toEqual([
|
|
151
|
+
"stills/detail-open.dark.png",
|
|
152
|
+
"stills/detail-open.light.png",
|
|
153
|
+
"stills/opening.dark.png",
|
|
154
|
+
"stills/opening.light.png",
|
|
155
|
+
]);
|
|
156
|
+
for (const entry of stillEntries) {
|
|
157
|
+
expect(entry.contentType).toBe("image/png");
|
|
158
|
+
}
|
|
159
|
+
// Declared-then-verified: the recorded sha256 is the file's real hash.
|
|
160
|
+
const opening = stillEntries.find((f) => f.path === "stills/opening.light.png")!;
|
|
161
|
+
expect(opening.sha256).toBe(
|
|
162
|
+
createHash("sha256").update(Buffer.from("png:light:opening")).digest("hex"),
|
|
163
|
+
);
|
|
164
|
+
// The bundle's own files are (re)listed too.
|
|
165
|
+
expect(manifest.files.some((f) => f.path === "index.html")).toBe(true);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it("clears stale stills and rebuilds the manifest even when no shots are declared", async () => {
|
|
169
|
+
const bundleDir = await makeBundle();
|
|
170
|
+
await mkdir(join(bundleDir, STILLS_DIR), { recursive: true });
|
|
171
|
+
await writeFile(join(bundleDir, STILLS_DIR, "removed-shot.light.png"), "stale");
|
|
172
|
+
const fake = makeFakeBrowser({ shots: [] });
|
|
173
|
+
|
|
174
|
+
const result = await runShoot({ bundleDir, browserFactory: async () => fake.browser });
|
|
175
|
+
|
|
176
|
+
expect(result.shots).toEqual([]);
|
|
177
|
+
expect(result.files).toEqual([]);
|
|
178
|
+
// The stale still is gone from disk AND from the manifest — a manifest
|
|
179
|
+
// listing a deleted file would fail its existence check at publish.
|
|
180
|
+
expect(await stat(join(bundleDir, STILLS_DIR)).catch(() => null)).toBeNull();
|
|
181
|
+
const manifest = await readManifest(bundleDir);
|
|
182
|
+
expect(manifest.files.some((f) => f.path.startsWith("stills/"))).toBe(false);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it("captures a single theme when asked", async () => {
|
|
186
|
+
const bundleDir = await makeBundle();
|
|
187
|
+
const fake = makeFakeBrowser();
|
|
188
|
+
|
|
189
|
+
const result = await runShoot({
|
|
190
|
+
bundleDir,
|
|
191
|
+
themes: ["light"],
|
|
192
|
+
browserFactory: async () => fake.browser,
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
expect(result.files).toEqual(["stills/opening.light.png", "stills/detail-open.light.png"]);
|
|
196
|
+
expect(fake.sessions).toHaveLength(1);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it("surfaces the capture page's own error (e.g. invalid shot declarations)", async () => {
|
|
200
|
+
const bundleDir = await makeBundle();
|
|
201
|
+
const fake = makeFakeBrowser({
|
|
202
|
+
openError: 'steps 0 and 2 both declare shot "opening"; shot names must be unique within a scenario',
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
await expect(
|
|
206
|
+
runShoot({ bundleDir, browserFactory: async () => fake.browser }),
|
|
207
|
+
).rejects.toThrow(/steps 0 and 2 both declare shot "opening"/);
|
|
208
|
+
// The browser is still torn down on the failure path.
|
|
209
|
+
expect(fake.isClosed()).toBe(true);
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it("verify: passes when a second fresh session reproduces every byte", async () => {
|
|
213
|
+
const bundleDir = await makeBundle();
|
|
214
|
+
// Image content ignores the session index — deterministic.
|
|
215
|
+
const fake = makeFakeBrowser();
|
|
216
|
+
|
|
217
|
+
const result = await runShoot({
|
|
218
|
+
bundleDir,
|
|
219
|
+
verify: true,
|
|
220
|
+
browserFactory: async () => fake.browser,
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
expect(result.verified).toBe(true);
|
|
224
|
+
// Two sessions per theme: capture + verify, all fresh.
|
|
225
|
+
expect(fake.sessions.map((s) => s.theme)).toEqual(["light", "dark", "light", "dark"]);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it("verify: fails naming the differing shot when sessions disagree", async () => {
|
|
229
|
+
const bundleDir = await makeBundle();
|
|
230
|
+
const fake = makeFakeBrowser({
|
|
231
|
+
imageFor: (theme, shotName, sessionIndex) =>
|
|
232
|
+
// "detail-open" renders differently on every session — the exact
|
|
233
|
+
// nondeterminism --verify exists to catch.
|
|
234
|
+
Buffer.from(
|
|
235
|
+
shotName === "detail-open"
|
|
236
|
+
? `png:${theme}:${shotName}:${sessionIndex}`
|
|
237
|
+
: `png:${theme}:${shotName}`,
|
|
238
|
+
),
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
await expect(
|
|
242
|
+
runShoot({ bundleDir, verify: true, browserFactory: async () => fake.browser }),
|
|
243
|
+
).rejects.toThrow(/determinism check failed \(light\): shot\(s\) detail-open differed/);
|
|
244
|
+
// Nothing was written: a failed verify must not leave untrusted stills.
|
|
245
|
+
expect(await stat(join(bundleDir, STILLS_DIR)).catch(() => null)).toBeNull();
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it("fails when themes disagree on the shot list (bundle nondeterminism)", async () => {
|
|
249
|
+
const bundleDir = await makeBundle();
|
|
250
|
+
const fake = makeFakeBrowser({
|
|
251
|
+
shotsFor: (theme) => (theme === "dark" ? SHOTS.slice(0, 1) : SHOTS),
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
await expect(
|
|
255
|
+
runShoot({ bundleDir, browserFactory: async () => fake.browser }),
|
|
256
|
+
).rejects.toThrow(/different shot list/);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it("rejects a directory that is not a packed bundle, with the fix named", async () => {
|
|
260
|
+
const dir = await mkdtemp(join(tmpdir(), "scenar-shoot-notbundle-"));
|
|
261
|
+
await writeFile(join(dir, "index.html"), "<!doctype html>", "utf-8");
|
|
262
|
+
|
|
263
|
+
const fake = makeFakeBrowser();
|
|
264
|
+
await expect(
|
|
265
|
+
runShoot({ bundleDir: dir, browserFactory: async () => fake.browser }),
|
|
266
|
+
).rejects.toThrow(/no scenario\.json in .*Run `scenar pack`/);
|
|
267
|
+
// Validation fails before any browser work.
|
|
268
|
+
expect(fake.sessions).toHaveLength(0);
|
|
269
|
+
});
|
|
270
|
+
});
|
package/src/api.d.ts
CHANGED
|
@@ -12,6 +12,9 @@ export { runNarrate } from "./narrate/run-narrate.js";
|
|
|
12
12
|
export type { RunNarrateOptions, NarrateResult, NarratedScenario } from "./narrate/run-narrate.js";
|
|
13
13
|
export { runRender } from "./render/run-render.js";
|
|
14
14
|
export type { RunRenderOptions, RenderResult } from "./render/run-render.js";
|
|
15
|
+
export { runShoot, STILLS_DIR } from "./shoot/run-shoot.js";
|
|
16
|
+
export type { RunShootOptions, ShootResult } from "./shoot/run-shoot.js";
|
|
17
|
+
export type { ShotBrowser, ShotSession, ShotCaptureInfo, ShotTheme } from "./shoot/types.js";
|
|
15
18
|
export { runServe } from "./serve/run-serve.js";
|
|
16
19
|
export type { RunServeOptions, ServeResult } from "./serve/run-serve.js";
|
|
17
20
|
export { startBundleServer, createBundleServer } from "./serve/static-server.js";
|
package/src/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrE,YAAY,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAG5D,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAGnG,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAG7E,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACzE,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACjF,YAAY,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAG7F,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACpF,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,QAAQ,EACR,OAAO,GACR,MAAM,2BAA2B,CAAC;AACnC,YAAY,EACV,eAAe,EACf,cAAc,EACd,aAAa,GACd,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAG5D,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,cAAc,GACf,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAGvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,YAAY,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACrE,YAAY,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrE,YAAY,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAG5D,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAGnG,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAG7E,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAC5D,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACzE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAG7F,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACzE,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACjF,YAAY,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAG7F,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACpF,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,QAAQ,EACR,OAAO,GACR,MAAM,2BAA2B,CAAC;AACnC,YAAY,EACV,eAAe,EACf,cAAc,EACd,aAAa,GACd,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAG5D,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,cAAc,GACf,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAGvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,YAAY,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACrE,YAAY,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC"}
|
package/src/api.js
CHANGED
|
@@ -11,6 +11,8 @@ export { runPack } from "./pack/run-pack.js";
|
|
|
11
11
|
export { runNarrate } from "./narrate/run-narrate.js";
|
|
12
12
|
// Render
|
|
13
13
|
export { runRender } from "./render/run-render.js";
|
|
14
|
+
// Shoot (render a bundle's declared shots to stills)
|
|
15
|
+
export { runShoot, STILLS_DIR } from "./shoot/run-shoot.js";
|
|
14
16
|
// Serve
|
|
15
17
|
export { runServe } from "./serve/run-serve.js";
|
|
16
18
|
export { startBundleServer, createBundleServer } from "./serve/static-server.js";
|
package/src/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO;AACP,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAI7C,UAAU;AACV,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAGtD,SAAS;AACT,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGnD,QAAQ;AACR,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEhD,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAGjF,yBAAyB;AACzB,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEtD,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,QAAQ,EACR,OAAO,GACR,MAAM,2BAA2B,CAAC;AAMnC,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,qFAAqF;AACrF,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAQtD,WAAW;AACX,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvD,4CAA4C;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO;AACP,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAI7C,UAAU;AACV,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAGtD,SAAS;AACT,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGnD,qDAAqD;AACrD,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAI5D,QAAQ;AACR,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEhD,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAGjF,yBAAyB;AACzB,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEtD,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,QAAQ,EACR,OAAO,GACR,MAAM,2BAA2B,CAAC;AAMnC,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,qFAAqF;AACrF,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAQtD,WAAW;AACX,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvD,4CAA4C;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC"}
|
package/src/api.ts
CHANGED
|
@@ -19,6 +19,11 @@ export type { RunNarrateOptions, NarrateResult, NarratedScenario } from "./narra
|
|
|
19
19
|
export { runRender } from "./render/run-render.js";
|
|
20
20
|
export type { RunRenderOptions, RenderResult } from "./render/run-render.js";
|
|
21
21
|
|
|
22
|
+
// Shoot (render a bundle's declared shots to stills)
|
|
23
|
+
export { runShoot, STILLS_DIR } from "./shoot/run-shoot.js";
|
|
24
|
+
export type { RunShootOptions, ShootResult } from "./shoot/run-shoot.js";
|
|
25
|
+
export type { ShotBrowser, ShotSession, ShotCaptureInfo, ShotTheme } from "./shoot/types.js";
|
|
26
|
+
|
|
22
27
|
// Serve
|
|
23
28
|
export { runServe } from "./serve/run-serve.js";
|
|
24
29
|
export type { RunServeOptions, ServeResult } from "./serve/run-serve.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shoot.d.ts","sourceRoot":"","sources":["../../../src/commands/shoot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYpC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA2D3D"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { runShoot } from "../shoot/run-shoot.js";
|
|
2
|
+
const THEME_CHOICES = ["light", "dark", "both"];
|
|
3
|
+
export function registerShootCommand(program) {
|
|
4
|
+
program
|
|
5
|
+
.command("shoot")
|
|
6
|
+
.description("Render a packed bundle's declared shots to still images.\n\n" +
|
|
7
|
+
"Reads the steps' `shot` names from the running bundle, walks the\n" +
|
|
8
|
+
"timeline sequentially (a deterministic TimeSource walk — the same\n" +
|
|
9
|
+
"model as video export), and screenshots each shot's settled\n" +
|
|
10
|
+
"end-of-step frame into <bundle>/stills/<shot>.<theme>.png, one\n" +
|
|
11
|
+
"image per theme. The pack manifest is rebuilt afterwards, so\n" +
|
|
12
|
+
"`scenar publish` and deploys ship the stills with the bundle.\n\n" +
|
|
13
|
+
"Requires Playwright (optional peer): npm install -D playwright,\n" +
|
|
14
|
+
"then npx playwright install chromium. The bundle must be packed by\n" +
|
|
15
|
+
"the same CLI version (all @scenar packages release in lockstep).\n\n" +
|
|
16
|
+
"Tip: open <bundle-url>?shot=<name> in a browser to eyeball any\n" +
|
|
17
|
+
"declared shot without capturing.")
|
|
18
|
+
.argument("<dir>", "a packed bundle directory (from scenar pack)")
|
|
19
|
+
.option("--theme <theme>", `themes to capture: ${THEME_CHOICES.join(" | ")} (default: both)`, "both")
|
|
20
|
+
.option("--verify", "capture everything twice in fresh browser sessions and fail unless every still is byte-identical")
|
|
21
|
+
.option("--timeout <ms>", "per-page readiness timeout in milliseconds (default: 30000)", "30000")
|
|
22
|
+
.action(async (dir, options) => {
|
|
23
|
+
try {
|
|
24
|
+
if (!THEME_CHOICES.includes(options.theme)) {
|
|
25
|
+
throw new Error(`--theme must be one of: ${THEME_CHOICES.join(", ")}`);
|
|
26
|
+
}
|
|
27
|
+
const themes = options.theme === "both" ? ["light", "dark"] : [options.theme];
|
|
28
|
+
const result = await runShoot({
|
|
29
|
+
bundleDir: dir,
|
|
30
|
+
themes,
|
|
31
|
+
verify: options.verify ?? false,
|
|
32
|
+
timeoutMs: Number(options.timeout) || undefined,
|
|
33
|
+
onLog: (message) => process.stderr.write(`${message}\n`),
|
|
34
|
+
});
|
|
35
|
+
if (result.shots.length === 0) {
|
|
36
|
+
process.stderr.write(`\n\x1b[32m✓\x1b[0m No shots declared in ${result.scenarioId} — nothing captured.\n` +
|
|
37
|
+
` Name a capture point by setting \`shot: "<kebab-name>"\` on a step.\n`);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
process.stderr.write(`\n\x1b[32m✓\x1b[0m Shot ${result.files.length} stills ` +
|
|
41
|
+
`(${result.shots.length} shots x ${result.themes.length} themes)` +
|
|
42
|
+
`${result.verified ? ", byte-identical across sessions" : ""} ` +
|
|
43
|
+
`to ${result.bundleDir}/stills\n`);
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
47
|
+
process.stderr.write(`\x1b[31mError:\x1b[0m ${msg}\n`);
|
|
48
|
+
process.exitCode = 1;
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=shoot.js.map
|