hyperframes 0.8.72 → 0.8.73

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.
@@ -326,12 +326,25 @@ interface PlayerProps {
326
326
  */
327
327
  declare const Player: react.ForwardRefExoticComponent<PlayerProps & react.RefAttributes<HTMLIFrameElement>>;
328
328
 
329
+ interface ShortcutHint {
330
+ key: string;
331
+ label: string;
332
+ }
333
+ interface ShortcutSection {
334
+ title: string;
335
+ hints: readonly ShortcutHint[];
336
+ }
337
+ /** What PlayerControls' shortcuts panel lists unless an embedder passes its own sections. */
338
+ declare const DEFAULT_SHORTCUT_SECTIONS: readonly ShortcutSection[];
339
+
329
340
  interface PlayerControlsProps {
330
341
  onTogglePlay: () => void;
331
342
  onSeek: (time: number) => void;
332
343
  disabled?: boolean;
333
344
  isFullscreen?: boolean;
334
345
  onToggleFullscreen?: () => void;
346
+ /** Replaces the shortcuts panel's list, e.g. DEFAULT_SHORTCUT_SECTIONS with entries dropped or relabelled. */
347
+ shortcutSections?: readonly ShortcutSection[];
335
348
  }
336
349
  declare const PlayerControls: react.NamedExoticComponent<PlayerControlsProps>;
337
350
 
@@ -2887,4 +2900,4 @@ declare function TimelineEditProvider({ value, children, }: {
2887
2900
  children: ReactNode;
2888
2901
  }): react_jsx_runtime.JSX.Element;
2889
2902
 
2890
- export { type AgentModalAnchorPoint, type AgentPromptElementInfo, AskAgentModal, type AskAgentModalProps, AudioWaveform, type AudioWaveformProps, type BlockedTimelineEditIntent, Button, type ButtonSize, type ButtonVariant, type CanEditTimelineElement, CompositionBreadcrumb, type CompositionDimensions, type CompositionLevel, CompositionThumbnail, ContextMenu, type EditHistoryHandle, EditorShell, type EditorShellProps, type ExternalFileChangeBlockedState, type ExternalFileChangeCoordinatorHandle, ExternalFileConflictBanner, type FfmpegStatus, FileTree, GridOverlay, HyperframesLoader, type HyperframesLoaderProps, HyperframesLogo, IconButton, ImageThumbnail, type ImageThumbnailProps, Input, type InputProps, Menu, MenuItem, type MenuItemTone, MenuRadioGroup, MenuRadioItem, MenuSeparator, MenuShortcut, NLEPreview, NumberField, type NumberFieldProps, type PatchOperation, type PersistedRenderSettings, type PickedElement, Player, PlayerControls, type PlayerHandle, type PlayerHandleElement, type PlayerHandleListener, type PlayerHandleTimeListener, Popover, type PopupPreviewState, type DomEditCompositionRect as PreviewCompositionRect, PreviewGuides, PreviewOverlayProvider, type PreviewOverlayProviderProps, type PreviewSnapPreferences, type PreviewState, PropertyPanel, type RenderJob, RenderQueue, type RenderQueueProps, type ResolutionPreset, Select, type SelectOption, type SelectProps, Slider, type SliderProps, SnapToolbar, SourceEditor, type StartRenderOptions, StudioApp, StudioFileConflictError, type StudioPendingEditsDrainResult, Tab, TabPanel, Tabs, TabsList, type ThumbnailPriority, Timeline, TimelineClipMenu, type TimelineClipRenderContext, type TimelineEditCallbacks, type TimelineEditPermission, TimelineEditPopover, TimelineEditProvider, type TimelineElement, TimelineEmptyStatePart, TimelineFrame, TimelineGapMenu, TimelineKeyframeMenu, TimelineLanes, TimelineOverlays, TimelinePane, type TimelinePaneProps, TimelinePlayhead, TimelineProvider, TimelineRazorGuide, TimelineRuler, TimelineShortcutHint, type TimelineTheme, type TimelineTimeRange$1 as TimelineTimeRange, Toggle, type ToggleProps, Tooltip, type UseEditHistoryActionsOptions, type UsePersistentEditHistoryOptions, type UseProjectFileWriterOptions, type UseRenderClipContentOptions, type UseTimelineEditingOptions, VideoThumbnail, applyPatch, buildPickerAgentContextPreview, buildPickerAgentPrompt, buttonBase, buttonSizes, buttonVariants, cn, fieldBase, fieldText, findElementBlock, flushStudioPendingEdits, formatTime, getPersistedRenderSettings, liveTime, mergeStyleIntoTag, parseStyleString, persistRenderSettings, popupSurface, resolveIframe, resolveSourceFile, useEditHistoryActions, useElementPicker, usePersistentEditHistory, usePlayerHandle, usePlayerStore, usePreviewCompositionRect, usePreviewGuidesStore, usePreviewOverlayContext, useProjectFileWriter, useRenderClipContent, useRenderQueue, useTimelineContext, useTimelineEditing, useTimelinePlayer };
2903
+ export { type AgentModalAnchorPoint, type AgentPromptElementInfo, AskAgentModal, type AskAgentModalProps, AudioWaveform, type AudioWaveformProps, type BlockedTimelineEditIntent, Button, type ButtonSize, type ButtonVariant, type CanEditTimelineElement, CompositionBreadcrumb, type CompositionDimensions, type CompositionLevel, CompositionThumbnail, ContextMenu, DEFAULT_SHORTCUT_SECTIONS, type EditHistoryHandle, EditorShell, type EditorShellProps, type ExternalFileChangeBlockedState, type ExternalFileChangeCoordinatorHandle, ExternalFileConflictBanner, type FfmpegStatus, FileTree, GridOverlay, HyperframesLoader, type HyperframesLoaderProps, HyperframesLogo, IconButton, ImageThumbnail, type ImageThumbnailProps, Input, type InputProps, Menu, MenuItem, type MenuItemTone, MenuRadioGroup, MenuRadioItem, MenuSeparator, MenuShortcut, NLEPreview, NumberField, type NumberFieldProps, type PatchOperation, type PersistedRenderSettings, type PickedElement, Player, PlayerControls, type PlayerHandle, type PlayerHandleElement, type PlayerHandleListener, type PlayerHandleTimeListener, Popover, type PopupPreviewState, type DomEditCompositionRect as PreviewCompositionRect, PreviewGuides, PreviewOverlayProvider, type PreviewOverlayProviderProps, type PreviewSnapPreferences, type PreviewState, PropertyPanel, type RenderJob, RenderQueue, type RenderQueueProps, type ResolutionPreset, Select, type SelectOption, type SelectProps, type ShortcutHint, type ShortcutSection, Slider, type SliderProps, SnapToolbar, SourceEditor, type StartRenderOptions, StudioApp, StudioFileConflictError, type StudioPendingEditsDrainResult, Tab, TabPanel, Tabs, TabsList, type ThumbnailPriority, Timeline, TimelineClipMenu, type TimelineClipRenderContext, type TimelineEditCallbacks, type TimelineEditPermission, TimelineEditPopover, TimelineEditProvider, type TimelineElement, TimelineEmptyStatePart, TimelineFrame, TimelineGapMenu, TimelineKeyframeMenu, TimelineLanes, TimelineOverlays, TimelinePane, type TimelinePaneProps, TimelinePlayhead, TimelineProvider, TimelineRazorGuide, TimelineRuler, TimelineShortcutHint, type TimelineTheme, type TimelineTimeRange$1 as TimelineTimeRange, Toggle, type ToggleProps, Tooltip, type UseEditHistoryActionsOptions, type UsePersistentEditHistoryOptions, type UseProjectFileWriterOptions, type UseRenderClipContentOptions, type UseTimelineEditingOptions, VideoThumbnail, applyPatch, buildPickerAgentContextPreview, buildPickerAgentPrompt, buttonBase, buttonSizes, buttonVariants, cn, fieldBase, fieldText, findElementBlock, flushStudioPendingEdits, formatTime, getPersistedRenderSettings, liveTime, mergeStyleIntoTag, parseStyleString, persistRenderSettings, popupSurface, resolveIframe, resolveSourceFile, useEditHistoryActions, useElementPicker, usePersistentEditHistory, usePlayerHandle, usePlayerStore, usePreviewCompositionRect, usePreviewGuidesStore, usePreviewOverlayContext, useProjectFileWriter, useRenderClipContent, useRenderQueue, useTimelineContext, useTimelineEditing, useTimelinePlayer };
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
6
6
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
7
7
  <title>HyperFrames Studio</title>
8
- <script type="module" crossorigin src="/assets/index-BqUGSWqN.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-DxIHGgGZ.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/assets/index-0w6iIlwZ.css">
10
10
  </head>
11
11
  <body>
@@ -3500,11 +3500,15 @@ function isHtmlElement2(el) {
3500
3500
  const HtmlElementCtor = el.ownerDocument.defaultView?.HTMLElement ?? globalThis.HTMLElement;
3501
3501
  return typeof HtmlElementCtor !== "undefined" && el instanceof HtmlElementCtor;
3502
3502
  }
3503
+ function isCompositionHost(el) {
3504
+ return el.hasAttribute("data-composition-id") || el.hasAttribute("data-composition-src") || el.hasAttribute("data-composition-file");
3505
+ }
3503
3506
  function resolveMediaElement(el) {
3504
3507
  const win = el.ownerDocument.defaultView ?? window;
3505
3508
  const MediaElementCtor = win.HTMLMediaElement ?? globalThis.HTMLMediaElement;
3506
3509
  const ImageElementCtor = win.HTMLImageElement ?? globalThis.HTMLImageElement;
3507
3510
  if (el instanceof MediaElementCtor || el instanceof ImageElementCtor) return el;
3511
+ if (isCompositionHost(el)) return null;
3508
3512
  const candidate = el.querySelector("video, audio, img");
3509
3513
  return candidate instanceof MediaElementCtor || candidate instanceof ImageElementCtor ? candidate : null;
3510
3514
  }
@@ -4309,9 +4313,10 @@ function useContextMenuDismiss(onClose) {
4309
4313
  return menuRef;
4310
4314
  }
4311
4315
 
4312
- // src/player/components/ShortcutsPanel.tsx
4313
- import { Fragment, jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
4314
- var SHORTCUT_SECTIONS = [
4316
+ // src/player/components/studioShortcuts.ts
4317
+ var STUDIO_PLAIN_KEYS = { fullscreen: "f", split: "s", record: "r" };
4318
+ var hintKey = (key2) => key2.toUpperCase();
4319
+ var DEFAULT_SHORTCUT_SECTIONS = [
4315
4320
  {
4316
4321
  title: "Playback",
4317
4322
  hints: [
@@ -4323,7 +4328,7 @@ var SHORTCUT_SECTIONS = [
4323
4328
  { key: "\u21E7L", label: "Toggle loop" },
4324
4329
  { key: "\u2190/\u2192", label: "Step 1 frame" },
4325
4330
  { key: "\u21E7\u2190/\u21E7\u2192", label: "Step 10 frames" },
4326
- { key: "F", label: "Toggle fullscreen" }
4331
+ { key: hintKey(STUDIO_PLAIN_KEYS.fullscreen), label: "Toggle fullscreen" }
4327
4332
  ]
4328
4333
  },
4329
4334
  {
@@ -4333,7 +4338,7 @@ var SHORTCUT_SECTIONS = [
4333
4338
  { key: "Del", label: "Delete selected keyframe" },
4334
4339
  { key: "H", label: "Toggle hold / bezier" },
4335
4340
  { key: "U", label: "Expand / collapse properties" },
4336
- { key: "R", label: "Record gesture" }
4341
+ { key: hintKey(STUDIO_PLAIN_KEYS.record), label: "Record gesture" }
4337
4342
  ]
4338
4343
  },
4339
4344
  {
@@ -4344,7 +4349,7 @@ var SHORTCUT_SECTIONS = [
4344
4349
  { key: "\u2318C", label: "Copy element" },
4345
4350
  { key: "\u2318V", label: "Paste element" },
4346
4351
  { key: "\u2318X", label: "Cut element" },
4347
- { key: "S", label: "Split clip at playhead" },
4352
+ { key: hintKey(STUDIO_PLAIN_KEYS.split), label: "Split clip at playhead" },
4348
4353
  { key: "\u21E7Click", label: "Razor tool: split all tracks" },
4349
4354
  { key: "\u2318G", label: "Group elements" },
4350
4355
  { key: "\u2318\u21E7G", label: "Ungroup" },
@@ -4396,6 +4401,9 @@ var SHORTCUT_SECTIONS = [
4396
4401
  ]
4397
4402
  }
4398
4403
  ];
4404
+
4405
+ // src/player/components/ShortcutsPanel.tsx
4406
+ import { Fragment, jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
4399
4407
  var ShortcutsPanel = memo(function ShortcutsPanel2({
4400
4408
  disabled,
4401
4409
  duration,
@@ -4403,7 +4411,8 @@ var ShortcutsPanel = memo(function ShortcutsPanel2({
4403
4411
  outPoint,
4404
4412
  setInPoint,
4405
4413
  setOutPoint,
4406
- onSeek
4414
+ onSeek,
4415
+ sections = DEFAULT_SHORTCUT_SECTIONS
4407
4416
  }) {
4408
4417
  const [showShortcuts, setShowShortcuts] = useState7(false);
4409
4418
  const [jumpFrame, setJumpFrame] = useState7("");
@@ -4597,9 +4606,9 @@ var ShortcutsPanel = memo(function ShortcutsPanel2({
4597
4606
  ] })
4598
4607
  ] }),
4599
4608
  /* @__PURE__ */ jsx23("div", { style: { borderTop: "1px solid rgba(255,255,255,0.06)" } }),
4600
- /* @__PURE__ */ jsx23("div", { className: "px-3 pt-2.5 pb-3 flex flex-col gap-3", children: SHORTCUT_SECTIONS.map((section) => /* @__PURE__ */ jsxs16("div", { children: [
4609
+ /* @__PURE__ */ jsx23("div", { className: "px-3 pt-2.5 pb-3 flex flex-col gap-3", children: sections.map((section, sectionIndex) => /* @__PURE__ */ jsxs16("div", { children: [
4601
4610
  /* @__PURE__ */ jsx23("p", { className: "text-[9px] font-medium text-neutral-500 uppercase tracking-wider mb-1.5", children: section.title }),
4602
- /* @__PURE__ */ jsx23("div", { className: "flex flex-col gap-1", children: section.hints.map((hint) => /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-3", children: [
4611
+ /* @__PURE__ */ jsx23("div", { className: "flex flex-col gap-1", children: section.hints.map((hint, hintIndex) => /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-3", children: [
4603
4612
  /* @__PURE__ */ jsx23(
4604
4613
  "span",
4605
4614
  {
@@ -4609,8 +4618,8 @@ var ShortcutsPanel = memo(function ShortcutsPanel2({
4609
4618
  }
4610
4619
  ),
4611
4620
  /* @__PURE__ */ jsx23("span", { className: "text-[10px] text-neutral-400", children: hint.label })
4612
- ] }, hint.key)) })
4613
- ] }, section.title)) })
4621
+ ] }, hintIndex)) })
4622
+ ] }, sectionIndex)) })
4614
4623
  ]
4615
4624
  }
4616
4625
  )
@@ -4878,7 +4887,8 @@ var PlayerControls = memo4(function PlayerControls2({
4878
4887
  onSeek,
4879
4888
  disabled = false,
4880
4889
  isFullscreen = false,
4881
- onToggleFullscreen
4890
+ onToggleFullscreen,
4891
+ shortcutSections
4882
4892
  }) {
4883
4893
  const isPlaying = usePlayerStore((s) => s.isPlaying);
4884
4894
  const duration = usePlayerStore((s) => s.duration);
@@ -5002,7 +5012,8 @@ var PlayerControls = memo4(function PlayerControls2({
5002
5012
  outPoint,
5003
5013
  setInPoint,
5004
5014
  setOutPoint,
5005
- onSeek
5015
+ onSeek,
5016
+ sections: shortcutSections
5006
5017
  }
5007
5018
  )
5008
5019
  ] })
@@ -6561,7 +6572,7 @@ function useTimelinePlayhead({
6561
6572
  previousAnchorPpsRef.current = pps;
6562
6573
  const skip = skipCenterAnchorRef.current;
6563
6574
  skipCenterAnchorRef.current = false;
6564
- if (!scroll || pps === prevPps || skip) return;
6575
+ if (!scroll || pps === prevPps || skip || scroll.scrollLeft < 1) return;
6565
6576
  const nextScrollLeft = getTimelineScrollLeftForZoomAnchor({
6566
6577
  pointerX: scroll.clientWidth / 2,
6567
6578
  currentScrollLeft: scroll.scrollLeft,
@@ -27575,10 +27586,10 @@ function parseTimelineFromDOM(doc, rootDuration, timelines) {
27575
27586
  if (compSrc) {
27576
27587
  entry2.compositionSrc = compSrc;
27577
27588
  } else if (compId && compId !== rootComp?.getAttribute("data-composition-id")) {
27578
- const innerVideo = el.querySelector("video[src]");
27579
- if (innerVideo) {
27580
- entry2.src = innerVideo.getAttribute("src") || void 0;
27581
- entry2.tag = "video";
27589
+ const innerMedia = el.querySelector("video[src], img[src]");
27590
+ if (innerMedia) {
27591
+ entry2.src = innerMedia.getAttribute("src") || void 0;
27592
+ entry2.tag = innerMedia.tagName === "IMG" ? "img" : "video";
27582
27593
  }
27583
27594
  }
27584
27595
  if (entry2.kind === "composition") {
@@ -28068,6 +28079,7 @@ var logReload = makeStudioDebugLogger("reload");
28068
28079
 
28069
28080
  // src/player/hooks/useShadowPreviewReload.ts
28070
28081
  var SHADOW_READY_TIMEOUT_MS = 15e3;
28082
+ var SHADOW_READY_BUDGETS = 3;
28071
28083
  function isDocumentHidden() {
28072
28084
  return typeof document !== "undefined" && document.visibilityState === "hidden";
28073
28085
  }
@@ -28096,6 +28108,7 @@ function useShadowPreviewReload({
28096
28108
  const onReloadFailedRef = useRef51(onReloadFailed);
28097
28109
  onReloadFailedRef.current = onReloadFailed;
28098
28110
  const readyTimerRef = useRef51(void 0);
28111
+ const budgetsSpentRef = useRef51(0);
28099
28112
  const budgetGenRef = useRef51(null);
28100
28113
  const cancelPendingLoadRef = useRef51(() => {
28101
28114
  });
@@ -28187,10 +28200,16 @@ function useShadowPreviewReload({
28187
28200
  (gen) => {
28188
28201
  clearTimeout(readyTimerRef.current);
28189
28202
  if (isDocumentHidden()) return;
28190
- readyTimerRef.current = setTimeout(
28191
- () => failShadow(gen, "it took too long to load"),
28192
- SHADOW_READY_TIMEOUT_MS
28193
- );
28203
+ readyTimerRef.current = setTimeout(() => {
28204
+ if (gen !== shadowGenRef.current) return;
28205
+ budgetsSpentRef.current += 1;
28206
+ if (budgetsSpentRef.current < SHADOW_READY_BUDGETS) {
28207
+ logReload("shadow-slow", { budgetsSpent: budgetsSpentRef.current });
28208
+ armReadyTimerRef.current(gen);
28209
+ return;
28210
+ }
28211
+ failShadow(gen, "it took too long to load");
28212
+ }, SHADOW_READY_TIMEOUT_MS);
28194
28213
  },
28195
28214
  [failShadow]
28196
28215
  );
@@ -28202,6 +28221,7 @@ function useShadowPreviewReload({
28202
28221
  const gen = shadowGenRef.current;
28203
28222
  stopPendingShadow();
28204
28223
  budgetGenRef.current = gen;
28224
+ budgetsSpentRef.current = 0;
28205
28225
  armReadyTimer(gen);
28206
28226
  setPreviewSlots((prev) => planShadowReload(prev, gen, url));
28207
28227
  thumbnailScheduler.setPreviewReloading(true);
@@ -81011,14 +81031,14 @@ function dispatchModifierKey(event, key2, cb) {
81011
81031
  return false;
81012
81032
  }
81013
81033
  function dispatchPlainKey(event, key2, cb) {
81014
- if (key2 === "f" && !event.shiftKey && !event.altKey) {
81034
+ if (key2 === STUDIO_PLAIN_KEYS.fullscreen && !event.shiftKey && !event.altKey) {
81015
81035
  event.preventDefault();
81016
81036
  if (document.fullscreenElement) void document.exitFullscreen();
81017
81037
  else
81018
81038
  document.querySelector("[data-studio-fullscreen-target]")?.requestFullscreen();
81019
81039
  return;
81020
81040
  }
81021
- if (event.key === "s" && !event.altKey) {
81041
+ if (event.key === STUDIO_PLAIN_KEYS.split && !event.altKey) {
81022
81042
  event.preventDefault();
81023
81043
  if (cb.readOnlyPreview) return;
81024
81044
  const { selectedElementId, elements, currentTime } = usePlayerStore.getState();
@@ -81095,7 +81115,7 @@ function dispatchPlainKey(event, key2, cb) {
81095
81115
  }
81096
81116
  return;
81097
81117
  }
81098
- if (event.key === "r" && !event.shiftKey && !event.altKey && cb.onToggleRecording) {
81118
+ if (event.key === STUDIO_PLAIN_KEYS.record && !event.shiftKey && !event.altKey && cb.onToggleRecording) {
81099
81119
  event.preventDefault();
81100
81120
  cb.onToggleRecording();
81101
81121
  }
@@ -86508,7 +86528,7 @@ var TAG_ICONS = {
86508
86528
  function getTagBadge(tagName) {
86509
86529
  return TAG_ICONS[tagName] ?? tagName.slice(0, 2).toUpperCase();
86510
86530
  }
86511
- function isCompositionHost(el) {
86531
+ function isCompositionHost2(el) {
86512
86532
  return el.hasAttribute("data-composition-src") || el.hasAttribute("data-composition-file");
86513
86533
  }
86514
86534
  function createRafThrottle(run, throttleMs = 100) {
@@ -86810,7 +86830,7 @@ var LayersPanel = memo44(function LayersPanel2() {
86810
86830
  const draggable = isLayerDraggable(layer);
86811
86831
  const isCollapsed = collapsed[layer.key] ?? false;
86812
86832
  const hasChildren = layer.childCount > 0;
86813
- const isCompHost = isCompositionHost(layer.element);
86833
+ const isCompHost = isCompositionHost2(layer.element);
86814
86834
  return /* @__PURE__ */ jsxs172(
86815
86835
  "div",
86816
86836
  {
@@ -93135,6 +93155,7 @@ export {
93135
93155
  CompositionBreadcrumb,
93136
93156
  CompositionThumbnail,
93137
93157
  ContextMenu,
93158
+ DEFAULT_SHORTCUT_SECTIONS,
93138
93159
  EditorShell,
93139
93160
  ExternalFileConflictBanner,
93140
93161
  FileTree,