diff --git a/packages/studio/src/components/editor/propertyPanelFlatLayoutSection.test.tsx b/packages/studio/src/components/editor/propertyPanelFlatLayoutSection.test.tsx
index 827f9fad4..6ecad450f 100644
--- a/packages/studio/src/components/editor/propertyPanelFlatLayoutSection.test.tsx
+++ b/packages/studio/src/components/editor/propertyPanelFlatLayoutSection.test.tsx
@@ -6,6 +6,7 @@ import { afterEach, describe, expect, it, vi } from "vitest";
import {
LayoutFlexBlock,
LayoutGeometryRows,
+ LayoutTransform3DBlock,
LayoutZIndexRow,
} from "./propertyPanelFlatLayoutSection";
@@ -163,3 +164,28 @@ describe("LayoutFlexBlock", () => {
act(() => root.unmount());
});
});
+
+describe("LayoutTransform3DBlock", () => {
+ it("renders the nested 3D transform sub-view", () => {
+ const { host, root } = renderInto(
+ ,
+ );
+ // PropertyPanel3dTransform's own internals aren't this task's concern (it's
+ // reused unmodified) — just confirm the wrapper mounted something.
+ expect(host.children.length).toBeGreaterThan(0);
+ act(() => root.unmount());
+ });
+});
diff --git a/packages/studio/src/components/editor/propertyPanelFlatLayoutSection.tsx b/packages/studio/src/components/editor/propertyPanelFlatLayoutSection.tsx
index 477893d4e..e8e58e77a 100644
--- a/packages/studio/src/components/editor/propertyPanelFlatLayoutSection.tsx
+++ b/packages/studio/src/components/editor/propertyPanelFlatLayoutSection.tsx
@@ -3,6 +3,8 @@ import { KeyframeNavigation } from "./KeyframeNavigation";
import { formatPxMetricValue } from "./propertyPanelHelpers";
import { STUDIO_KEYFRAMES_ENABLED } from "./manualEditingAvailability";
import { resolveValueTier } from "./propertyPanelValueTier";
+import { PropertyPanel3dTransform } from "./propertyPanel3dTransform";
+import type { DomEditSelection } from "./domEditingTypes";
type KeyframeEntry = Array<{
percentage: number;
@@ -235,3 +237,70 @@ export function LayoutFlexBlock({
);
}
+
+export function LayoutTransform3DBlock({
+ gsapRuntimeValues,
+ gsapAnimId,
+ resolveAnimIdForProp,
+ gsapKeyframes,
+ currentPct,
+ elStart,
+ elDuration,
+ element,
+ onCommitAnimatedProperty,
+ onCommitAnimatedProperties,
+ onSeekToTime,
+ onRemoveKeyframe,
+ onConvertToKeyframes,
+ onLivePreviewProps,
+}: {
+ gsapRuntimeValues: Record;
+ gsapAnimId: string | null;
+ resolveAnimIdForProp?: (prop: string) => string | null;
+ gsapKeyframes: Array<{
+ percentage: number;
+ properties: Record;
+ ease?: string;
+ }> | null;
+ currentPct: number;
+ elStart: number;
+ elDuration: number;
+ element: DomEditSelection;
+ onCommitAnimatedProperty?: (
+ element: DomEditSelection,
+ property: string,
+ value: number,
+ ) => Promise;
+ onCommitAnimatedProperties?: (
+ element: DomEditSelection,
+ props: Record,
+ ) => Promise;
+ onSeekToTime?: (time: number) => void;
+ onRemoveKeyframe?: (animId: string, pct: number) => void;
+ onConvertToKeyframes?: (animId: string, duration?: number) => void;
+ onLivePreviewProps?: (element: DomEditSelection, props: Record) => void;
+}) {
+ return (
+
+ );
+}