miriad-viz 0.7.2 → 0.7.3

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.
@@ -84,6 +84,22 @@ function generateTiming(script, pacing) {
84
84
  phase: line.phase
85
85
  };
86
86
  });
87
+ const validationErrors = [];
88
+ for (const line of timedLines) {
89
+ const expectedRange = totalProjectTime > 0 ? line.durationSec / totalProjectTime : 0;
90
+ const actualRange = line.progressEnd - line.progressStart;
91
+ if (Math.abs(actualRange - expectedRange) > 1e-3) {
92
+ validationErrors.push(
93
+ `"${line.id}": progress range ${actualRange.toFixed(4)} != expected ${expectedRange.toFixed(4)}`
94
+ );
95
+ }
96
+ }
97
+ if (validationErrors.length > 0) {
98
+ throw new Error(
99
+ `Timing validation failed (${validationErrors.length} clip${validationErrors.length > 1 ? "s" : ""}):
100
+ ${validationErrors.join("\n")}`
101
+ );
102
+ }
87
103
  return {
88
104
  version: 1,
89
105
  totalDurationSec,
package/dist-cli/index.js CHANGED
@@ -1530,7 +1530,7 @@ async function main() {
1530
1530
  const port = typeof flags.port === "string" ? Number.parseInt(flags.port, 10) : void 0;
1531
1531
  if (flags["from-pacing"] === true) {
1532
1532
  const dataDir = resolve3(projectDir, progress.project.dataDir);
1533
- const { runFromPacingChain } = await import("./from-pacing-chain-ZP4XGDJ7.js");
1533
+ const { runFromPacingChain } = await import("./from-pacing-chain-ENCSRNXM.js");
1534
1534
  console.log("\n\u{1F517} Running from-pacing chain: timing \u2192 transform \u2192 preview\n");
1535
1535
  const chainResult = runFromPacingChain(dataDir);
1536
1536
  if (!chainResult.success) {
@@ -1883,40 +1883,6 @@ function Footer({
1883
1883
  (e) => {
1884
1884
  if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) return;
1885
1885
  switch (e.code) {
1886
- case "Space": {
1887
- e.preventDefault();
1888
- toggle();
1889
- break;
1890
- }
1891
- case "ArrowRight": {
1892
- e.preventDefault();
1893
- if (isAuto) {
1894
- onToggleMute?.();
1895
- lastManualSpeed.current = 1;
1896
- setSpeed(1);
1897
- } else {
1898
- const idx = MANUAL_SPEEDS.indexOf(speed);
1899
- if (idx < MANUAL_SPEEDS.length - 1) {
1900
- const next = MANUAL_SPEEDS[idx + 1];
1901
- lastManualSpeed.current = next;
1902
- setSpeed(next);
1903
- }
1904
- }
1905
- break;
1906
- }
1907
- case "ArrowLeft": {
1908
- e.preventDefault();
1909
- if (isAuto) break;
1910
- const idx = MANUAL_SPEEDS.indexOf(speed);
1911
- if (idx === 0 && hasTimingFile) {
1912
- onToggleMute?.();
1913
- } else if (idx > 0) {
1914
- const prev = MANUAL_SPEEDS[idx - 1];
1915
- lastManualSpeed.current = prev;
1916
- setSpeed(prev);
1917
- }
1918
- break;
1919
- }
1920
1886
  case "Home": {
1921
1887
  e.preventDefault();
1922
1888
  scrub(0);
@@ -1944,7 +1910,7 @@ function Footer({
1944
1910
  }
1945
1911
  }
1946
1912
  },
1947
- [toggle, speed, setSpeed, scrub, onToggleMute, onToggleDev, hasTimingFile, isAuto]
1913
+ [scrub, setSpeed, onToggleMute, onToggleDev, hasTimingFile, isAuto]
1948
1914
  );
1949
1915
  react.useEffect(() => {
1950
1916
  window.addEventListener("keydown", handleKeyDown);
@@ -2737,6 +2703,41 @@ function usePlayback(durationSeconds = FALLBACK_DURATION, timingFile = null) {
2737
2703
  progressRef.current = clamped;
2738
2704
  setProgress(clamped);
2739
2705
  }, []);
2706
+ react.useEffect(() => {
2707
+ const SKIP_SECONDS = 5;
2708
+ const handleKeyDown = (e) => {
2709
+ if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) return;
2710
+ if (e.key === " " || e.key === "Space") {
2711
+ e.preventDefault();
2712
+ if (playingRef.current) {
2713
+ setPlaying(false);
2714
+ } else {
2715
+ if (progressRef.current >= 1) {
2716
+ progressRef.current = 0;
2717
+ setProgress(0);
2718
+ }
2719
+ lastTimeRef.current = null;
2720
+ setPlaying(true);
2721
+ }
2722
+ } else if (e.key === "ArrowLeft") {
2723
+ e.preventDefault();
2724
+ const denominator = totalProjectTimeRef.current ?? durationSeconds;
2725
+ const delta = SKIP_SECONDS / denominator;
2726
+ const next = Math.max(0, progressRef.current - delta);
2727
+ progressRef.current = next;
2728
+ setProgress(next);
2729
+ } else if (e.key === "ArrowRight") {
2730
+ e.preventDefault();
2731
+ const denominator = totalProjectTimeRef.current ?? durationSeconds;
2732
+ const delta = SKIP_SECONDS / denominator;
2733
+ const next = Math.min(1, progressRef.current + delta);
2734
+ progressRef.current = next;
2735
+ setProgress(next);
2736
+ }
2737
+ };
2738
+ window.addEventListener("keydown", handleKeyDown);
2739
+ return () => window.removeEventListener("keydown", handleKeyDown);
2740
+ }, [durationSeconds]);
2740
2741
  return { progress, playing, speed, play, pause, toggle, setSpeed, scrub };
2741
2742
  }
2742
2743
  function parseViewportString(raw) {