versioncam 0.5.3 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/CHANGELOG.md +103 -0
  2. package/README.md +108 -6
  3. package/dist/cli/commands/check.js +25 -0
  4. package/dist/cli/commands/check.js.map +1 -1
  5. package/dist/cli/commands/doctor.js +54 -1
  6. package/dist/cli/commands/doctor.js.map +1 -1
  7. package/dist/cli/commands/preview.js +4 -2
  8. package/dist/cli/commands/preview.js.map +1 -1
  9. package/dist/cli/commands/record.d.ts +6 -0
  10. package/dist/cli/commands/record.js +24 -3
  11. package/dist/cli/commands/record.js.map +1 -1
  12. package/dist/cli/commands/stability.js +10 -3
  13. package/dist/cli/commands/stability.js.map +1 -1
  14. package/dist/cli/usage.d.ts +1 -1
  15. package/dist/cli/usage.js +2 -0
  16. package/dist/cli/usage.js.map +1 -1
  17. package/dist/config.d.ts +45 -4
  18. package/dist/config.js +134 -8
  19. package/dist/config.js.map +1 -1
  20. package/dist/core/cursor.d.ts +22 -0
  21. package/dist/core/cursor.js +6 -0
  22. package/dist/core/cursor.js.map +1 -1
  23. package/dist/core/motion-defaults.d.ts +8 -0
  24. package/dist/core/motion-defaults.js +8 -0
  25. package/dist/core/motion-defaults.js.map +1 -1
  26. package/dist/core/timeline.d.ts +24 -0
  27. package/dist/core/timeline.js.map +1 -1
  28. package/dist/driver/clip.d.ts +6 -0
  29. package/dist/driver/clip.js +33 -2
  30. package/dist/driver/clip.js.map +1 -1
  31. package/dist/driver/file-window.d.ts +66 -0
  32. package/dist/driver/file-window.js +245 -0
  33. package/dist/driver/file-window.js.map +1 -0
  34. package/dist/driver/page-hooks.d.ts +23 -1
  35. package/dist/driver/page-hooks.js +36 -1
  36. package/dist/driver/page-hooks.js.map +1 -1
  37. package/dist/driver/replay.d.ts +263 -0
  38. package/dist/driver/replay.js +558 -0
  39. package/dist/driver/replay.js.map +1 -0
  40. package/dist/driver/session.d.ts +70 -4
  41. package/dist/driver/session.js +267 -29
  42. package/dist/driver/session.js.map +1 -1
  43. package/dist/driver/settle.js +6 -0
  44. package/dist/driver/settle.js.map +1 -1
  45. package/dist/index.d.ts +4 -2
  46. package/dist/index.js.map +1 -1
  47. package/dist/page/assets/index-CnRDAiUz.js +2 -0
  48. package/dist/page/index.html +1 -1
  49. package/dist/publish/protocol.d.ts +12 -1
  50. package/dist/publish/protocol.js.map +1 -1
  51. package/dist/render/render.d.ts +7 -1
  52. package/dist/render/render.js +51 -17
  53. package/dist/render/render.js.map +1 -1
  54. package/dist/render/sequence.d.ts +10 -5
  55. package/dist/render/sequence.js +44 -29
  56. package/dist/render/sequence.js.map +1 -1
  57. package/dsl.md +68 -1
  58. package/package.json +1 -1
  59. package/plugin/.claude-plugin/plugin.json +1 -1
  60. package/plugin/skills/versioncam/authoring.md +15 -1
  61. package/plugin/skills/versioncam/onboarding.md +9 -3
  62. package/dist/page/assets/index-BtUbUEdN.js +0 -2
@@ -160,9 +160,15 @@ What you may fix, in the config:
160
160
  already fixed (`clock.time`), so a timestamp that still moves came from an
161
161
  API, and that is the next item.
162
162
 
163
- What you may not: **live data** — a feed, a count that changes, a model's
164
- answer. That needs recorded network replay, which versioncam does not have
165
- yet. Say so, and ask whether to go on regardless.
163
+ - **Live data**: a feed, a count that changes, a map's tiles, a model's
164
+ answer. When the two pictures differ where the app fetched something, name
165
+ the requests in the config's `replay.record` (a URL glob each, as the
166
+ README's *Live data* shows) and run `stability` again: the first run
167
+ records the answers into `replay/`, and every run after serves them. A
168
+ stream the page reads over time also goes in `replay.pace`. Say which
169
+ requests you named and why. The replay holds the server's answers of the
170
+ day it was recorded; tell the person it belongs in the repository, and
171
+ that it may hold what those answers held.
166
172
 
167
173
  **Never author on an unstable app without saying so** — in the report now,
168
174
  and in `summary.json` at the end, as `"stable": false`. A clip written against
@@ -1,2 +0,0 @@
1
- (function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),t.credentials=e.crossOrigin===`use-credentials`?`include`:e.crossOrigin===`anonymous`?`omit`:`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();function e(e){let n=t(e);return n*n*n*(10+n*(-15+6*n))}function t(e){return e<=0?0:e>=1?1:e}function n(e,t,n){return e+(t-e)*n}function r(e,t,r){let i=e.x+e.w/2,a=e.y+e.h/2,o=t.x+t.w/2,s=t.y+t.h/2,c=e.w*(t.w/e.w)**+r,l=e.h*(t.h/e.h)**+r,u=n(i,o,r),d=n(a,s,r);return{x:u-c/2,y:d-l/2,w:c,h:l}}function i(e,t,r){return{x:n(e.x,t.x,r),y:n(e.y,t.y,r),w:n(e.w,t.w,r),h:n(e.h,t.h,r)}}function a(t,n){if(t.length===0)throw Error(`evalCamera called with no keys`);if(n<=t[0].t)return t[0].rect;for(let a=1;a<t.length;a+=1){let o=t[a-1],s=t[a];if(n>=s.t)continue;if(s.ease===`hold`)return o.rect;let c=s.t-o.t,l=c<=0?1:(n-o.t)/c;return s.ease===`linear`?i(o.rect,s.rect,l):r(o.rect,s.rect,e(l))}return t[t.length-1].rect}function o(e,t,n,r){let i=1-r,a=i*i,o=2*i*r,s=r*r;return[a*e[0]+o*t[0]+s*n[0],a*e[1]+o*t[1]+s*n[1]]}function s(t,n){if(t.length===0)return[0,0];let r=t[0];if(n<=r.t0)return r.kind===`move`?r.from:r.at;for(let r of t){if(n>r.t1)continue;if(r.kind===`hold`)return r.at;let t=r.t1-r.t0,i=t<=0?1:(n-r.t0)/t;return o(r.from,r.ctrl,r.to,e(i))}let i=t[t.length-1];return i.kind===`move`?i.to:i.at}function c(e,t,n){let r=n.w/t.w;return[n.x+(e[0]-t.x)*r,n.y+(e[1]-t.y)*r]}function l(e,t,n){let r=n.w/t.w;return{x:n.x+(e.x-t.x)*r,y:n.y+(e.y-t.y)*r,w:e.w*r,h:e.h*r}}function u(e,t){return{x:e.x*t,y:e.y*t,w:e.w*t,h:e.h*t}}function d(e,t,n){let r=Math.min(e.width,e.height)*n,i=e.width-r*2,a=e.height-r*2,o=t.width/t.height,s=i,c=s/o;return c>a&&(c=a,s=c*o),{x:(e.width-s)/2,y:(e.height-c)/2,w:s,h:c}}function f(e,n,r){return r<=0?1:t((e-n+1)/r)}function p(e,t,n){let r=e.frames[t],i=null;for(let a of e.cuts)t>a&&t<=a+n&&e.frames[a]!==r&&(i===null||a>i)&&(i=a);return i===null?{current:r,previous:null,alpha:1}:{current:r,previous:e.frames[i],alpha:f(t,i+1,n)}}function m(e,n,r,i){return e<=n||e>=r?0:i<=0?1:Math.min(t((e-n)/i),t((r-e)/i))}function ee(e,t){return e/t}function te(e,t,n){let r=n?.padding??0;return!n||r<=0?{x:0,y:0,w:e.width,h:e.height}:d(e,t,r)}function h(e){let t=e?.caption??`auto`;return t===`none`?`none`:t===`below`||t===`overlay`?t:(e?.padding??0)>0?`below`:`overlay`}function ne(e,t){let n=e?.captionInset;return n?.right===void 0?{x:n?.left??40,align:`left`}:{x:t-n.right,align:`right`}}var g={radius:16,hairline:`rgba(255, 255, 255, 0.16)`,shadow:`rgba(0, 0, 0, 0.45)`,shadowBlur:60,shadowOffsetY:18,captionFont:`600 30px "Helvetica Neue", Helvetica, Arial, "Liberation Sans", sans-serif`,captionColor:`rgba(255, 255, 255, 0.94)`,captionShadow:`rgba(0, 0, 0, 0.5)`,captionScrim:`rgba(0, 0, 0, 0.45)`,captionScrimHeight:86,cursorFill:`#ffffff`,cursorStroke:`rgba(0, 0, 0, 0.55)`,cursorShadow:`rgba(0, 0, 0, 0.35)`,ringWidth:3,ringRadius:10,spotlightDim:.55,spotlightTint:`6, 2, 16`};function re(e,t){let n=/^#([0-9a-f]{6})$/i.exec(e.trim());if(!n)return e;let r=Number.parseInt(n[1],16);return`rgba(${r>>16&255}, ${r>>8&255}, ${r&255}, ${t})`}function _(e,t,n){let r=Math.min(n,t.w/2,t.h/2);e.beginPath(),e.moveTo(t.x+r,t.y),e.arcTo(t.x+t.w,t.y,t.x+t.w,t.y+t.h,r),e.arcTo(t.x+t.w,t.y+t.h,t.x,t.y+t.h,r),e.arcTo(t.x,t.y+t.h,t.x,t.y,r),e.arcTo(t.x,t.y,t.x+t.w,t.y,r),e.closePath()}function ie(e,t,n){if(typeof n==`string`)e.fillStyle=n;else{let r=e.createLinearGradient(0,0,t.width,t.height);r.addColorStop(0,n[0]),r.addColorStop(1,n[1]),e.fillStyle=r}e.fillRect(0,0,t.width,t.height)}function v(e,t,n,r,i,a,o){let s=u(i,t.viewport.dpr),{current:c,previous:l,alpha:d}=p(t,r,o.motion.crossfadeFrames),f=o.theme.presentation?.frame??!1;e.save(),f&&(_(e,a,g.radius),e.clip());let m=(t,r)=>{let i=n.images[t];i&&(e.globalAlpha=r,e.drawImage(i,s.x,s.y,s.w,s.h,a.x,a.y,a.w,a.h))};l!==null&&m(l,1),m(c,l===null?1:d),e.globalAlpha=1,e.restore()}function y(e,t){e.save(),e.shadowColor=g.shadow,e.shadowBlur=g.shadowBlur,e.shadowOffsetY=g.shadowOffsetY,e.fillStyle=`rgba(0,0,0,1)`,_(e,t,g.radius),e.fill(),e.restore()}function b(e,t){e.save(),e.strokeStyle=g.hairline,e.lineWidth=1,_(e,t,g.radius),e.stroke(),e.restore()}function x(e,t){return{x:e.x-t,y:e.y-t,w:e.w+t*2,h:e.h+t*2}}function S(e,t,n,r,i,a){let o=a.theme.presentation?.frame??!1;for(let s of t.highlights){let t=m(n,s.t0,s.t1,.25);if(t<=0)continue;let c=l(s.rect,r,i);e.save(),e.globalAlpha=t,s.style===`spotlight`?(e.save(),_(e,i,o?g.radius:0),e.clip(),e.fillStyle=`rgba(${g.spotlightTint}, ${g.spotlightDim})`,e.fillRect(i.x,i.y,i.w,i.h),e.globalCompositeOperation=`destination-out`,_(e,x(c,8),g.ringRadius),e.fill(),e.restore()):(e.strokeStyle=a.theme.accent,e.lineWidth=g.ringWidth,e.shadowColor=re(a.theme.accent,.35),e.shadowBlur=18,_(e,x(c,6),g.ringRadius),e.stroke()),e.restore()}}function C(e,t,n){let r=!1,i=[],a=0;for(let o of e.pointer){if(o.t>t)break;if(o.kind===`down`)r=!0,a=o.t;else{r=!1;let e=t-o.t;e>=0&&e<=n.motion.rippleMs/1e3&&i.push({at:o.at,age:e})}}let o=r?t-a:0,s=r?Math.min(1,o/(n.motion.pressScaleMs/1e3)):0;return{scale:1-(1-n.motion.pressScale)*s,ripples:i}}function w(e,t,n,r,i){for(let a of t){let t=a.age/(i.motion.rippleMs/1e3),[o,s]=c(a.at,n,r);e.save(),e.globalAlpha=(1-t)*.55,e.strokeStyle=i.theme.accent,e.lineWidth=2.5,e.beginPath(),e.arc(o,s,6+t*i.motion.rippleRadius,0,Math.PI*2),e.stroke(),e.restore()}}function T(e,t,n,r){let i=r*n;e.save(),e.translate(t[0],t[1]),e.scale(i,i),e.shadowColor=g.cursorShadow,e.shadowBlur=6/i,e.shadowOffsetY=2/i,e.beginPath(),e.moveTo(0,0),e.lineTo(0,16.6),e.lineTo(4.1,12.9),e.lineTo(6.9,18.9),e.lineTo(9.6,17.6),e.lineTo(6.9,11.8),e.lineTo(12.1,11.5),e.closePath(),e.fillStyle=g.cursorFill,e.fill(),e.shadowColor=`transparent`,e.strokeStyle=g.cursorStroke,e.lineWidth=1/i,e.stroke(),e.restore()}function E(e,t,n,r,i,a){let o=h(a.theme.presentation);if(o!==`none`)for(let s of t.captions){let t=m(n,s.t0,s.t1,a.motion.captionFadeS);if(t<=0)continue;if(e.save(),e.globalAlpha=t,o===`overlay`){let t=g.captionScrimHeight,n=e.createLinearGradient(0,i.height-t,0,i.height);n.addColorStop(0,`rgba(0, 0, 0, 0)`),n.addColorStop(1,g.captionScrim),e.fillStyle=n,e.fillRect(0,i.height-t,i.width,t)}e.font=g.captionFont,e.fillStyle=g.captionColor,e.textBaseline=`middle`,e.shadowColor=g.captionShadow,e.shadowBlur=8;let c=r.x,l=(r.y+r.h+i.height)/2;if(o===`overlay`){let t=ne(a.theme.presentation,i.width);e.textAlign=t.align,c=t.x,l=i.height-g.captionScrimHeight/2+4}e.fillText(s.text,c,l),e.restore()}}function ae(e,t,n,r,i,o){let l=ee(r,t.fps),u=a(t.camera,l),d=o.theme.presentation,f=te(i,t.viewport,d);d?.backdrop&&ie(e,i,d.backdrop),d?.frame&&y(e,f),v(e,t,n,r,u,f,o),d?.frame&&b(e,f),S(e,t,l,u,f,o);let{scale:p,ripples:m}=C(t,l,o);w(e,m,u,f,o),T(e,c(s(t.cursor,l),u,f),p,o.theme.cursorScale),E(e,t,l,f,i,o)}var D="versioncam reads scenes from a module's default export: a Record<string, Scene> keyed by scene id, as in `export default { [intro.id]: intro }`.";function O(e){return e==null?String(e):Array.isArray(e)?`an array`:`a ${typeof e}`}function k(e){return typeof e==`string`?JSON.stringify(e):String(e)}function A(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function oe(e,t){if(!A(t))return`"${e}" is ${O(t)}, not a scene`;let{draw:n,durationFrames:r,fps:i}=t;return typeof n==`function`?!Number.isInteger(r)||r<1?`"${e}" has durationFrames ${k(r)}, where a whole number of frames, 1 or more, belongs`:typeof i!=`number`||!Number.isFinite(i)||i<=0?`"${e}" has fps ${k(i)}, where a number above 0 belongs`:null:`"${e}" has no draw(ctx, frame, canvas)`}function j(e){if(!A(e))return O(e);if(typeof e.draw==`function`)return`a single scene rather than a record of them`;for(let[t,n]of Object.entries(e)){let e=oe(t,n);if(e)return`a record in which ${e}`}return null}function M(e,t){if(e.default===void 0){let n=Object.keys(e).filter(e=>e!=="default"),r=[`${t} has no default export.`+(n.length>0?` It exports ${n.join(`, `)}.`:``),D],i=n.filter(t=>j(e[t])===null&&Object.keys(e[t]).length>0);return i.length===1&&r.push(`${i[0]} is one: add \`export default ${i[0]}\`.`),{error:r.join(`
2
- `)}}let n=j(e.default);return n?{error:`${t} default-exports ${n}.\n${D}`}:{scenes:e.default}}function N(e,t,n){let r=e.map(e=>`"${e}"`).join(`, `),i=`No scene${e.length===1?``:`s`} called ${r}.`;return n===null?`${i} The config names no \`scenes\` module.`:`${i} ${n} defines ${t.length>0?t.join(`, `):`none`}.`}var P=`modulepreload`,F=function(e,t){return new URL(e,t).href},I={},L=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e=document.getElementsByTagName(`link`),i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?import.meta.resolve(e):new URL(e,import.meta.url).href}r=o(t.map(t=>{if(t=F(t,n),t=s(t),t in I)return;I[t]=!0;let r=t.endsWith(`.css`);for(let n=e.length-1;n>=0;n--){let i=e[n];if(i.href===t&&(!r||i.rel===`stylesheet`))return}let i=document.createElement(`link`);if(i.rel=r?`stylesheet`:P,r||(i.as=`script`),i.crossOrigin=``,i.href=t,a&&i.setAttribute(`nonce`,a),document.head.appendChild(i),r)return new Promise((e,n)=>{i.addEventListener(`load`,e),i.addEventListener(`error`,()=>n(Error(`Unable to preload CSS for ${t}`)))})}).filter(e=>e!==void 0))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})},R=new URLSearchParams(location.search),z=R.has(`recording`),B=R.get(`scene`),V=R.get(`headless`)===`1`;V&&document.body.classList.add(`headless`);var H=document.getElementById(`stage`),U=document.getElementById(`scrub`),W=document.getElementById(`status`),G=document.getElementById(`play`),K=document.getElementById(`error`);function q(e){throw K.textContent=e,Error(e)}async function J(e,t){let n=await fetch(e);return n.ok||q(`Could not load ${t} (${e}): ${n.status}`),await n.json()}async function se(e){let t=await fetch(e);return t.ok||q(`Could not load ${e}: ${t.status}`),createImageBitmap(await t.blob())}function Y(e){H.width=e.output.width,H.height=e.output.height,V?(H.style.width=`${e.output.width}px`,H.style.height=`${e.output.height}px`):(H.style.width=`min(100%, 1280px)`,H.style.height=`auto`);let t=H.getContext(`2d`,{alpha:!1});return t||q(`No 2D context`),t.imageSmoothingEnabled=!0,t.imageSmoothingQuality=`high`,t}function X(e,t,n,r){let i=!1;G.addEventListener(`click`,()=>{i=!i,G.textContent=i?`Pause`:`Play`;let a=performance.now(),o=s=>{i&&(s-a>=1e3/e&&(a=s,r((n()+1)%t)),requestAnimationFrame(o))};requestAnimationFrame(o)})}function Z(e,t,n,r){e.durationFrames=t,e.fps=n,e.setFrame=e=>new Promise(t=>{r(e),requestAnimationFrame(()=>requestAnimationFrame(()=>t()))})}async function Q(e,t){let n=await J(`/recording/timeline.json`,`the recording`),r=Y(t),i={images:await Promise.all(n.states.map(e=>se(`/recording/states/${e}`)))};await document.fonts.ready;let a=-1,o=e=>{let o=Math.max(0,Math.min(n.durationFrames-1,e));ae(r,n,i,o,H,t),a=o,V||(U.value=String(o),W.textContent=`${o+1} / ${n.durationFrames} · ${(o/n.fps).toFixed(2)}s · state ${n.frames[o]}`)};U.max=String(n.durationFrames-1),U.addEventListener(`input`,()=>o(Number(U.value))),X(n.fps,n.durationFrames,()=>a,o),o(Number(R.get(`frame`)??0)),Z(e,n.durationFrames,n.fps,o)}async function ce(e,t,n){t.scenes===null&&q(N([n],[],null));let r=M(await L(()=>import(`/scenes.js`),[],import.meta.url),t.scenes);`error`in r&&q(r.error);let i=r.scenes[n];i||q(N([n],Object.keys(r.scenes),t.scenes));let a=Y(t);await document.fonts.ready;let o=-1,s=e=>{let t=Math.max(0,Math.min(i.durationFrames-1,e));i.draw(a,t,H),o=t,V||(U.value=String(t),W.textContent=`${t+1} / ${i.durationFrames} · ${(t/i.fps).toFixed(2)}s`)};U.max=String(i.durationFrames-1),U.addEventListener(`input`,()=>s(Number(U.value))),X(i.fps,i.durationFrames,()=>o,s),s(Number(R.get(`frame`)??0)),Z(e,i.durationFrames,i.fps,s)}async function le(e){let t=await J(`/render-config.json`,`the render config`);if(B)return ce(e,t,B);if(z)return Q(e,t);q(`Pass ?recording or ?scene=<id>.`)}var $={ready:Promise.resolve(),setFrame:async()=>{},durationFrames:0,fps:60};window.__render=$,$.ready=le($);