- Reference Images
+ Reference Media
{contextImages.map((contextImage, index) => {
+ const isAudio = contextImage.semantic === "audioref";
+ const isVideoRef = contextImage.semantic === "vid_ref";
const { thumbnail, fullSize } =
getContextImageThumbnail(contextImage, {
size: THUMBNAIL_SIZES.SMALL,
});
+ const isPlayingThis = playingAudioToken === contextImage.media_token;
return (
- {
- e.stopPropagation();
- setRefPreviewUrl(fullSize);
- }}
- >
-
- Preview image
-
+ {!isAudio && !isVideoRef && (
+ {
+ e.stopPropagation();
+ setRefPreviewUrl(fullSize);
+ }}
+ >
+
+ Preview image
+
+ )}
{onNavigateToMedia && (
setRefPreviewUrl(fullSize)}
+ onClick={() => {
+ if (isAudio) {
+ handleAudioToggle(contextImage.media_token, contextImage.media_links.cdn_url);
+ } else if (!isVideoRef) {
+ setRefPreviewUrl(fullSize);
+ }
+ }}
>
-
+ {isAudio ? (
+
+
+
+ ) : (
+ <>
+
+ {isVideoRef && (
+
+
+
+ )}
+ >
+ )}
);
diff --git a/frontend/libs/components/pagescene/src/lib/Stage3D.tsx b/frontend/libs/components/pagescene/src/lib/Stage3D.tsx
index c9b7f1ff5f..7a873f8936 100644
--- a/frontend/libs/components/pagescene/src/lib/Stage3D.tsx
+++ b/frontend/libs/components/pagescene/src/lib/Stage3D.tsx
@@ -49,6 +49,15 @@ export interface Stage3DProps {
* "See other demo scenes" affordance so the button stacks above
* the prompt input instead of floating loose over the canvas. */
promptboxAboveStackSlot?: React.ReactNode;
+ /** Optional content rendered in the top toolbar's left cluster, right
+ * after the File/Outliner/Shortcuts buttons. Tauri leaves this unset;
+ * the webapp uses it for the editable scene title. */
+ topBarStartSlot?: React.ReactNode;
+ /** Optional content rendered in the top toolbar's right cluster
+ * (before the anonymous hint chip). Tauri leaves this unset; the
+ * webapp uses it to host the relocated nav actions (pricing, credits,
+ * task queue, profile) since its global header is hidden here. */
+ topBarEndSlot?: React.ReactNode;
}
export const Stage3D = ({
@@ -61,6 +70,8 @@ export const Stage3D = ({
showHelpMenu = true,
modelSelectorPlacement = "bottom-left",
promptboxAboveStackSlot,
+ topBarStartSlot,
+ topBarEndSlot,
}: Stage3DProps) => {
// Engine's remountEngine() gate reads is3DPageMounted. With Stage3D
// mounting only when the host's tab/route puts us on screen, the
@@ -86,6 +97,8 @@ export const Stage3D = ({
showHelpMenu={showHelpMenu}
modelSelectorPlacement={modelSelectorPlacement}
promptboxAboveStackSlot={promptboxAboveStackSlot}
+ topBarStartSlot={topBarStartSlot}
+ topBarEndSlot={topBarEndSlot}
/>
diff --git a/frontend/libs/components/pagescene/src/lib/Stage3DBody.tsx b/frontend/libs/components/pagescene/src/lib/Stage3DBody.tsx
index 7157d5bf92..6219ce33db 100644
--- a/frontend/libs/components/pagescene/src/lib/Stage3DBody.tsx
+++ b/frontend/libs/components/pagescene/src/lib/Stage3DBody.tsx
@@ -89,6 +89,14 @@ export interface Stage3DBodyProps {
* "See other demo scenes" affordance so the button stacks above
* the prompt input instead of floating loose over the canvas. */
promptboxAboveStackSlot?: React.ReactNode;
+ /** Optional content rendered in the top toolbar's left cluster, right
+ * after the File/Outliner/Shortcuts buttons. Used by the webapp for
+ * the editable scene title; Tauri leaves it unset. */
+ topBarStartSlot?: React.ReactNode;
+ /** Optional content rendered in the top toolbar's right cluster, before
+ * the anonymous hint chip. Used by the webapp to host the relocated
+ * nav actions; Tauri leaves it unset. */
+ topBarEndSlot?: React.ReactNode;
}
export const Stage3DBody = ({
@@ -97,6 +105,8 @@ export const Stage3DBody = ({
showHelpMenu = true,
modelSelectorPlacement = "bottom-left",
promptboxAboveStackSlot,
+ topBarStartSlot,
+ topBarEndSlot,
}: Stage3DBodyProps = {}) => {
const camAspect = usePageSceneStore((s) => s.cameraAspectRatio);
const outlinerShowing = usePageSceneStore((s) => s.outlinerShowing);
@@ -431,9 +441,15 @@ export const Stage3DBody = ({
onClick={handleOverlayClick}
>
-
+
+
+ {topBarStartSlot && (
+
{topBarStartSlot}
+ )}
+
-
@@ -474,7 +490,7 @@ export const Stage3DBody = ({
uploadImage={
editor
? (((arg: Parameters
[0]) =>
- editor.adapter.uploadImage(arg)) as never)
+ editor.adapter.uploadImage(arg)) as never)
: undefined
}
handleCameraSelect={handleCameraSelect}
diff --git a/frontend/libs/components/pagescene/src/lib/comps/Controls3D/Controls3D.tsx b/frontend/libs/components/pagescene/src/lib/comps/Controls3D/Controls3D.tsx
index c6d2c64c93..ba05a63402 100644
--- a/frontend/libs/components/pagescene/src/lib/comps/Controls3D/Controls3D.tsx
+++ b/frontend/libs/components/pagescene/src/lib/comps/Controls3D/Controls3D.tsx
@@ -25,10 +25,7 @@ import { twMerge } from "tailwind-merge";
import { EngineContext } from "../../contexts/EngineContext/EngineContext";
import { setTransformMode } from "../../actions";
-import {
- usePageSceneStore,
- type TransformMode,
-} from "../../PageSceneStore";
+import { usePageSceneStore, type TransformMode } from "../../PageSceneStore";
import { AssetModal } from "../AssetMenu";
export interface Controls3DProps {
@@ -168,8 +165,8 @@ export const Controls3D = ({
return (
<>
-
-
+
+
@@ -252,10 +249,11 @@ export const Controls3D = ({
]}
onPanelAction={handleAddAssetAction}
showIconsInList
- buttonClassName={`h-9 w-9 rounded-xl text-lg ${showEmptySceneTooltip
- ? "bg-primary/90 hover:bg-primary/70"
- : "border-transparent bg-primary/90 hover:bg-primary/70"
- }`}
+ buttonClassName={`h-9 w-9 rounded-xl text-lg ${
+ showEmptySceneTooltip
+ ? "bg-primary/90 hover:bg-primary/70"
+ : "border-transparent bg-primary/90 hover:bg-primary/70"
+ }`}
triggerIcon={
}
diff --git a/frontend/libs/components/pagescene/src/lib/comps/ControlsTopButtons/ControlsTopButtons.tsx b/frontend/libs/components/pagescene/src/lib/comps/ControlsTopButtons/ControlsTopButtons.tsx
index 16765d5ec1..59bc911682 100644
--- a/frontend/libs/components/pagescene/src/lib/comps/ControlsTopButtons/ControlsTopButtons.tsx
+++ b/frontend/libs/components/pagescene/src/lib/comps/ControlsTopButtons/ControlsTopButtons.tsx
@@ -12,7 +12,10 @@ import { Modal } from "@storyteller/ui-modal";
import { twMerge } from "tailwind-merge";
import { EngineContext } from "../../contexts/EngineContext/EngineContext";
-import { usePageSceneStore, useIsVisitingOthersScene } from "../../PageSceneStore";
+import {
+ usePageSceneStore,
+ useIsVisitingOthersScene,
+} from "../../PageSceneStore";
import { CameraAspectRatio, ToastTypes } from "../../enums";
import { getSceneGenerationMetaData } from "../../sceneMetadata";
import { LoadUserScenes } from "./LoadUserScenes";
@@ -240,7 +243,7 @@ export const ControlsTopButtons = () => {
};
return (
-
+
{
// to the inline confirm dialog.
...(editor?.adapter.onRequestNewSceneSelector
? {
- onClick: () =>
- editor.adapter.onRequestNewSceneSelector?.(),
+ onClick: () => editor.adapter.onRequestNewSceneSelector?.(),
}
: {
dialogProps: {
@@ -359,12 +361,11 @@ export const ControlsTopButtons = () => {
dialogProps: {
title: "Reset scene to original?",
content: (
-
- This will discard every change you've made
- in this session and restore the scene to the
- version the author shared. This cannot be
- undone.
-
+
+ This will discard every change you've made in
+ this session and restore the scene to the version the
+ author shared. This cannot be undone.
+
),
confirmButtonProps: {
label: "Reset",