Start side panel redesign
No files matched your search
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 621 B |
@@ -4,7 +4,7 @@ import {
|
||||
QueueClip,
|
||||
QueueKeyframe,
|
||||
UpdateTime,
|
||||
} from "~/pages/PageEnigma/models/track";
|
||||
} from "~/pages/PageEnigma/models";
|
||||
import { toTimelineActions } from "./toTimelineActions";
|
||||
|
||||
class Queue {
|
||||
|
||||
@@ -17,7 +17,7 @@ import { ACTION_TYPES } from "../../reducers/appUiReducer/types";
|
||||
import { QueueNames } from "../../Queue/QueueNames";
|
||||
import Queue from "~/pages/PageEnigma/Queue/Queue";
|
||||
import { toTimelineActions } from "../../Queue/toTimelineActions";
|
||||
import { QueueKeyframe } from "~/pages/PageEnigma/models/track";
|
||||
import { QueueKeyframe } from "~/pages/PageEnigma/models";
|
||||
|
||||
export const ControlPanelSceneObject = () => {
|
||||
const editorEngine = useContext(EngineContext);
|
||||
@@ -33,9 +33,13 @@ export const ControlPanelSceneObject = () => {
|
||||
const scale = appUiState.controlPanel.currentSceneObject.objectVectors.scale;
|
||||
const currentSceneObject = appUiState.controlPanel.currentSceneObject;
|
||||
|
||||
useEffect(()=>{
|
||||
const vectors = appUiState.controlPanel.currentSceneObject.objectVectors
|
||||
editorEngine?.setSelectedObject(vectors.position, vectors.rotation, vectors.scale)
|
||||
useEffect(() => {
|
||||
const vectors = appUiState.controlPanel.currentSceneObject.objectVectors;
|
||||
editorEngine?.setSelectedObject(
|
||||
vectors.position,
|
||||
vectors.rotation,
|
||||
vectors.scale,
|
||||
);
|
||||
}, [appUiState.controlPanel.currentSceneObject]);
|
||||
|
||||
const handlePositionChange = (xyz: XYZ) => {
|
||||
@@ -141,9 +145,9 @@ export const ControlPanelSceneObject = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeleteObject = () =>{
|
||||
const handleDeleteObject = () => {
|
||||
console.log("TELL EDITOR TO DELETE HERE");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Transition
|
||||
@@ -159,7 +163,9 @@ export const ControlPanelSceneObject = () => {
|
||||
<div className="flex justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<FontAwesomeIcon icon={faCube} />
|
||||
<p className="font-semibold">{appUiState.controlPanel.currentSceneObject.object_name}</p>
|
||||
<p className="font-semibold">
|
||||
{appUiState.controlPanel.currentSceneObject.object_name}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-xs font-medium opacity-60">
|
||||
<FontAwesomeIcon icon={faArrowRightArrowLeft} />
|
||||
|
||||
@@ -4,7 +4,7 @@ import { ButtonDialogue } from "~/modules/ButtonDialogue";
|
||||
import { AppUiContext } from "../../contexts/AppUiContext";
|
||||
import { EngineContext } from "../../contexts/EngineContext";
|
||||
import { APPUI_ACTION_TYPES } from "../../reducers";
|
||||
import { ClipGroup } from "~/pages/PageEnigma/models/track";
|
||||
import { ClipGroup } from "~/pages/PageEnigma/models";
|
||||
|
||||
export const ControlsTopButtons = () => {
|
||||
const editorEngine = useContext(EngineContext);
|
||||
@@ -173,9 +173,9 @@ export const ControlsTopButtons = () => {
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleObjectPanelTest}
|
||||
className="bg-brand-tertiary hover:bg-brand-teriary-400 focus-visible:outline-brand-tertiary"
|
||||
className="hover:bg-brand-teriary-400 bg-brand-tertiary focus-visible:outline-brand-tertiary"
|
||||
>
|
||||
Show Object Panel
|
||||
Test Button 2
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
@@ -186,7 +186,7 @@ export const ControlsTopButtons = () => {
|
||||
<Button onClick={handleButtonRender}>Render</Button> */}
|
||||
<Button
|
||||
onClick={handleButtonTest}
|
||||
className="bg-brand-tertiary hover:bg-brand-teriary-400 focus-visible:outline-brand-tertiary"
|
||||
className="hover:bg-brand-teriary-400 bg-brand-tertiary focus-visible:outline-brand-tertiary"
|
||||
style={{ zIndex: 9001 }}
|
||||
>
|
||||
Test
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useCallback, useContext, useEffect } from "react";
|
||||
import { ClipType, MediaClip } from "~/pages/PageEnigma/models/track";
|
||||
import { AssetType, MediaClip } from "~/pages/PageEnigma/models";
|
||||
import { TrackContext } from "~/pages/PageEnigma/contexts/TrackContext/TrackContext";
|
||||
import {
|
||||
canDrop,
|
||||
@@ -11,7 +11,7 @@ import { useSignals } from "@preact/signals-react/runtime";
|
||||
|
||||
interface Props {
|
||||
clip: MediaClip;
|
||||
type: ClipType;
|
||||
type: AssetType;
|
||||
}
|
||||
|
||||
export const AnimationElement = ({ clip, type }: Props) => {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { AnimationElement } from "./AnimationElement";
|
||||
import { TrackContext } from "~/pages/PageEnigma/contexts/TrackContext/TrackContext";
|
||||
import { useSignals } from "@preact/signals-react/runtime";
|
||||
import { timelineHeight } from "~/pages/PageEnigma/store";
|
||||
import { ClipType } from "~/pages/PageEnigma/models/track";
|
||||
import { AssetType } from "~/pages/PageEnigma/models";
|
||||
|
||||
export const AnimationElements = () => {
|
||||
const { animationClips } = useContext(TrackContext);
|
||||
@@ -21,7 +21,7 @@ export const AnimationElements = () => {
|
||||
<AnimationElement
|
||||
key={clip.media_id}
|
||||
clip={clip}
|
||||
type={ClipType.ANIMATION}
|
||||
type={AssetType.ANIMATION}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useCallback, useContext, useEffect } from "react";
|
||||
import { ClipType, MediaClip } from "~/pages/PageEnigma/models/track";
|
||||
import { AssetType, MediaClip } from "~/pages/PageEnigma/models";
|
||||
import { TrackContext } from "~/pages/PageEnigma/contexts/TrackContext/TrackContext";
|
||||
import {
|
||||
canDrop,
|
||||
@@ -11,7 +11,7 @@ import { useSignals } from "@preact/signals-react/runtime";
|
||||
|
||||
interface Props {
|
||||
clip: MediaClip;
|
||||
type: ClipType;
|
||||
type: AssetType;
|
||||
}
|
||||
|
||||
export const AudioElement = ({ clip, type }: Props) => {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { AnimationElement } from "./AnimationElement";
|
||||
import { TrackContext } from "~/pages/PageEnigma/contexts/TrackContext/TrackContext";
|
||||
import { useSignals } from "@preact/signals-react/runtime";
|
||||
import { timelineHeight } from "~/pages/PageEnigma/store";
|
||||
import { ClipType } from "~/pages/PageEnigma/models/track";
|
||||
import { AssetType } from "~/pages/PageEnigma/models";
|
||||
|
||||
export const AudioElements = () => {
|
||||
const { audioClips } = useContext(TrackContext);
|
||||
@@ -21,7 +21,7 @@ export const AudioElements = () => {
|
||||
<AnimationElement
|
||||
key={clip.media_id}
|
||||
clip={clip}
|
||||
type={ClipType.AUDIO}
|
||||
type={AssetType.AUDIO}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import { useCallback, useContext, useEffect } from "react";
|
||||
import { AssetType, ObjectItem } from "~/pages/PageEnigma/models";
|
||||
import { TrackContext } from "~/pages/PageEnigma/contexts/TrackContext/TrackContext";
|
||||
import {
|
||||
canDrop,
|
||||
currPosition,
|
||||
dragId,
|
||||
initPosition,
|
||||
} from "~/pages/PageEnigma/store";
|
||||
import { useSignals } from "@preact/signals-react/runtime";
|
||||
|
||||
interface Props {
|
||||
item: ObjectItem;
|
||||
type: AssetType;
|
||||
}
|
||||
|
||||
export const ObjectElement = ({ item, type }: Props) => {
|
||||
useSignals();
|
||||
const { startDrag, endDrag } = useContext(TrackContext);
|
||||
const { initX, initY } = initPosition.value;
|
||||
|
||||
useEffect(() => {
|
||||
const onPointerUp = () => {
|
||||
if (dragId.value) {
|
||||
endDrag();
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseMove = (event: MouseEvent) => {
|
||||
if (dragId) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
const deltaX = event.pageX - initX;
|
||||
const deltaY = event.pageY - initY;
|
||||
currPosition.value = { currX: initX + deltaX, currY: initY + deltaY };
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("pointerup", onPointerUp);
|
||||
window.addEventListener("pointermove", onMouseMove);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("pointerup", onPointerUp);
|
||||
window.removeEventListener("pointermove", onMouseMove);
|
||||
};
|
||||
}, [startDrag, endDrag, initX, initY]);
|
||||
|
||||
const onPointerDown = useCallback(
|
||||
(event: React.PointerEvent<HTMLDivElement>) => {
|
||||
if (event.button === 0) {
|
||||
startDrag(type, item.media_id, 0);
|
||||
currPosition.value = {
|
||||
currX: event.pageX,
|
||||
currY: event.pageY,
|
||||
};
|
||||
initPosition.value = {
|
||||
initX: event.pageX,
|
||||
initY: event.pageY,
|
||||
};
|
||||
canDrop.value = false;
|
||||
}
|
||||
},
|
||||
[type, item.media_id, startDrag, 0],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="relative rounded-lg" style={{ width: 91, height: 114 }}>
|
||||
<img src={item.thumbnail} alt={item.name} className="rounded-t-lg" />
|
||||
<div
|
||||
className="w-full rounded-b-lg py-1 text-center text-sm"
|
||||
style={{ backgroundColor: "#39394D" }}
|
||||
>
|
||||
{item.name}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { TrackContext } from "~/pages/PageEnigma/contexts/TrackContext/TrackContext";
|
||||
import { useSignals } from "@preact/signals-react/runtime";
|
||||
import { timelineHeight } from "~/pages/PageEnigma/store";
|
||||
import { AssetType } from "~/pages/PageEnigma/models";
|
||||
import { ObjectElement } from "~/pages/PageEnigma/comps/SidePanelTabs/ObjectElement";
|
||||
|
||||
interface Props {
|
||||
type: AssetType;
|
||||
}
|
||||
|
||||
export const ObjectElements = ({ type }: Props) => {
|
||||
const { characterItems } = useContext(TrackContext);
|
||||
useSignals();
|
||||
const [height, setHeight] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
setHeight(window.outerHeight - timelineHeight.value);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="flex flex-wrap gap-3 overflow-y-auto" style={{ height }}>
|
||||
{characterItems.map((item) => {
|
||||
return <ObjectElement key={item.media_id} item={item} type={type} />;
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,29 +1,133 @@
|
||||
import { Tabs } from "~/modules/Tabs";
|
||||
import { TabStylization } from "./TabStylization";
|
||||
import { AnimationElements } from "./AnimationElements";
|
||||
import { AudioElements } from "~/pages/PageEnigma/comps/SidePanelTabs/AudioElements";
|
||||
import { AssetType } from "~/pages/PageEnigma/models";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useSignals } from "@preact/signals-react/runtime";
|
||||
import { timelineHeight } from "~/pages/PageEnigma/store";
|
||||
|
||||
const TABS = [
|
||||
{
|
||||
icon: "resources/icons/animations.png",
|
||||
title: "Animation",
|
||||
value: AssetType.ANIMATION,
|
||||
},
|
||||
{
|
||||
icon: "resources/icons/objects.png",
|
||||
title: "Objects",
|
||||
value: AssetType.OBJECT,
|
||||
},
|
||||
{
|
||||
icon: "resources/icons/characters.png",
|
||||
title: "Characters",
|
||||
value: AssetType.CHARACTER,
|
||||
},
|
||||
{
|
||||
icon: "resources/icons/camera.png",
|
||||
title: "Camera",
|
||||
value: AssetType.CAMERA,
|
||||
},
|
||||
{
|
||||
icon: "resources/icons/audios.png",
|
||||
title: "Audio",
|
||||
value: AssetType.AUDIO,
|
||||
},
|
||||
];
|
||||
|
||||
export const SidePanelTabs = () => {
|
||||
const [selectedTab, setSelectedTab] = useState(TABS[0].value);
|
||||
useSignals();
|
||||
const [height, setHeight] = useState(0);
|
||||
const [selectedButton, setSelectedButton] = useState("all");
|
||||
|
||||
useEffect(() => {
|
||||
setHeight(window.innerHeight - timelineHeight.value - 68);
|
||||
console.log(
|
||||
window.outerHeight - timelineHeight.value - 68,
|
||||
window.outerHeight,
|
||||
timelineHeight.value,
|
||||
);
|
||||
}, [timelineHeight.value]);
|
||||
|
||||
return (
|
||||
<Tabs
|
||||
tabs={[
|
||||
{
|
||||
header: "Animation",
|
||||
children: <AnimationElements />,
|
||||
},
|
||||
{
|
||||
header: "Camera",
|
||||
children: <p>Camera Tab</p>,
|
||||
},
|
||||
{
|
||||
header: "Audio",
|
||||
children: <AudioElements />,
|
||||
},
|
||||
{
|
||||
header: "Stylization",
|
||||
children: <TabStylization />,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<div>
|
||||
<div className="flex h-full">
|
||||
<div
|
||||
className="flex w-full flex-col justify-start"
|
||||
style={{ height, width: "calc(100% - 80px)" }}
|
||||
>
|
||||
<div className="w-full overflow-x-auto">
|
||||
<div style={{ width: 300 }}>
|
||||
<div className="mb-4 mt-2 flex justify-start gap-2 px-2">
|
||||
<button
|
||||
className={[
|
||||
"bg-assets-background rounded-lg px-3 py-1 text-sm",
|
||||
selectedButton === "all"
|
||||
? "border-2 border-brand-primary"
|
||||
: "",
|
||||
].join(" ")}
|
||||
onClick={() => setSelectedButton("all")}
|
||||
>
|
||||
All
|
||||
</button>
|
||||
<button
|
||||
className={[
|
||||
"bg-assets-background rounded-lg px-3 py-1 text-sm",
|
||||
selectedButton === "mine"
|
||||
? "border-2 border-brand-primary"
|
||||
: "",
|
||||
].join(" ")}
|
||||
onClick={() => setSelectedButton("mine")}
|
||||
>
|
||||
My Animations
|
||||
</button>
|
||||
<button
|
||||
className={[
|
||||
"bg-assets-background rounded-lg px-3 py-1 text-sm",
|
||||
selectedButton === "bookmarked"
|
||||
? "border-2 border-brand-primary"
|
||||
: "",
|
||||
].join(" ")}
|
||||
onClick={() => setSelectedButton("bookmarked")}
|
||||
>
|
||||
Bookmarked
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="px-2">
|
||||
<button className="bg-assets-background w-full rounded-lg py-2">
|
||||
Upload Animation
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-3 px-2"></div>
|
||||
</div>
|
||||
<div
|
||||
className={[
|
||||
"bg-assets-background",
|
||||
"mr-2 px-2 py-4",
|
||||
"overflow-y-auto",
|
||||
].join(" ")}
|
||||
style={{ height, minWidth: 80 }}
|
||||
>
|
||||
<div className="flex w-full flex-col gap-2">
|
||||
{TABS.map((tab) => (
|
||||
<button
|
||||
key={tab.value}
|
||||
className={[
|
||||
"flex flex-col items-center rounded-lg px-2 py-3",
|
||||
tab.value === selectedTab ? "bg-assets-selectedTab" : "",
|
||||
].join(" ")}
|
||||
onClick={() => setSelectedTab(tab.value)}
|
||||
>
|
||||
<div>
|
||||
<img src={tab.icon} alt={tab.title} width={20} height={20} />
|
||||
</div>
|
||||
<div className="" style={{ fontSize: 11 }}>
|
||||
{tab.title}
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
toggleAudioMute,
|
||||
updateAudio,
|
||||
} from "~/pages/PageEnigma/store";
|
||||
import { ClipGroup } from "~/pages/PageEnigma/models/track";
|
||||
import { ClipGroup } from "~/pages/PageEnigma/models";
|
||||
|
||||
export const Audio = () => {
|
||||
const { clips } = audioGroup.value;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { cameraGroup, fullWidth, updateCamera } from "~/pages/PageEnigma/store";
|
||||
import { TrackKeyFrames } from "~/pages/PageEnigma/comps/Timeline/TrackKeyFrames";
|
||||
import { useSignals } from "@preact/signals-react/runtime";
|
||||
import { ClipGroup } from "~/pages/PageEnigma/models/track";
|
||||
import { ClipGroup } from "~/pages/PageEnigma/models";
|
||||
|
||||
export const Camera = () => {
|
||||
useSignals();
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
updateCharacters,
|
||||
} from "~/pages/PageEnigma/store";
|
||||
import { TrackKeyFrames } from "~/pages/PageEnigma/comps/Timeline/TrackKeyFrames";
|
||||
import { ClipGroup, ClipType } from "~/pages/PageEnigma/models/track";
|
||||
import { ClipGroup, ClipType } from "~/pages/PageEnigma/models";
|
||||
|
||||
function buildUpdaters(
|
||||
updateCharacters: (options: {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { fullWidth, objectGroup, updateObject } from "~/pages/PageEnigma/store";
|
||||
import { TrackKeyFrames } from "~/pages/PageEnigma/comps/Timeline/TrackKeyFrames";
|
||||
import { ClipGroup } from "~/pages/PageEnigma/models/track";
|
||||
import { ClipGroup } from "~/pages/PageEnigma/models";
|
||||
|
||||
export const ObjectTrack = () => {
|
||||
return (
|
||||
|
||||
@@ -17,7 +17,7 @@ import { Scrubber } from "~/pages/PageEnigma/comps/Timeline/Scrubber";
|
||||
import { Characters } from "~/pages/PageEnigma/comps/Timeline/Characters";
|
||||
import { ObjectGroups } from "~/pages/PageEnigma/comps/Timeline/ObjectGroups";
|
||||
import useUpdateKeyframe from "~/pages/PageEnigma/contexts/TrackContext/utils/useUpdateKeyframe";
|
||||
import { Clip, Keyframe } from "~/pages/PageEnigma/models/track";
|
||||
import { Clip, Keyframe } from "~/pages/PageEnigma/models";
|
||||
|
||||
function getItemType(item: Clip | Keyframe | null) {
|
||||
if (!item) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useMouseEventsClip } from "./utils/useMouseEventsClip";
|
||||
import { useState } from "react";
|
||||
import { scale, selectedItem } from "~/pages/PageEnigma/store";
|
||||
import { Clip, ClipGroup } from "~/pages/PageEnigma/models/track";
|
||||
import { Clip, ClipGroup } from "~/pages/PageEnigma/models";
|
||||
|
||||
interface Props {
|
||||
min: number;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { TrackClip } from "~/pages/PageEnigma/comps/Timeline/TrackClip";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faVolume, faVolumeSlash } from "@fortawesome/pro-solid-svg-icons";
|
||||
import { Clip, ClipGroup, ClipType } from "~/pages/PageEnigma/models/track";
|
||||
import { Clip, ClipGroup, ClipType } from "~/pages/PageEnigma/models";
|
||||
import { PointerEvent } from "react";
|
||||
import {
|
||||
canDrop,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Keyframe } from "~/pages/PageEnigma/models/track";
|
||||
import { Keyframe } from "~/pages/PageEnigma/models";
|
||||
import { filmLength, scale, selectedItem } from "~/pages/PageEnigma/store";
|
||||
import { useMouseEventsKeyframe } from "~/pages/PageEnigma/comps/Timeline/utils/useMouseEventsKeyframe";
|
||||
import { useSignals } from "@preact/signals-react/runtime";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ClipGroup, Keyframe } from "~/pages/PageEnigma/models/track";
|
||||
import { ClipGroup, Keyframe } from "~/pages/PageEnigma/models";
|
||||
import { TrackKeyFrame } from "~/pages/PageEnigma/comps/Timeline/TrackKeyFrame";
|
||||
|
||||
interface Props {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { Dispatch, useCallback, useEffect, useRef } from "react";
|
||||
import { Clip } from "~/pages/PageEnigma/models/track";
|
||||
import { Clip } from "~/pages/PageEnigma/models";
|
||||
import { canDrop, scale } from "~/pages/PageEnigma/store";
|
||||
import { useSignals } from "@preact/signals-react/runtime";
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { Keyframe } from "~/pages/PageEnigma/models/track";
|
||||
import { Keyframe } from "~/pages/PageEnigma/models";
|
||||
import { canDrop, scale } from "~/pages/PageEnigma/store";
|
||||
import { useSignals } from "@preact/signals-react/runtime";
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
QueueClip,
|
||||
QueueKeyframe,
|
||||
UpdateTime,
|
||||
} from "~/pages/PageEnigma/models/track";
|
||||
} from "~/pages/PageEnigma/models";
|
||||
import { TrackContext } from "~/pages/PageEnigma/contexts/TrackContext/TrackContext";
|
||||
import { toTimelineActions } from "~/pages/PageEnigma/Queue/toTimelineActions";
|
||||
|
||||
|
||||
@@ -4,7 +4,9 @@ import {
|
||||
Keyframe,
|
||||
QueueKeyframe,
|
||||
ClipType,
|
||||
} from "~/pages/PageEnigma/models/track";
|
||||
ObjectItem,
|
||||
AssetType,
|
||||
} from "~/pages/PageEnigma/models";
|
||||
|
||||
export const TrackContext = createContext<{
|
||||
// keyframes
|
||||
@@ -14,9 +16,10 @@ export const TrackContext = createContext<{
|
||||
// sidebar clips
|
||||
animationClips: MediaClip[];
|
||||
audioClips: MediaClip[];
|
||||
characterItems: ObjectItem[];
|
||||
|
||||
// drag and drop
|
||||
startDrag: (type: ClipType, id: string, length: number) => void;
|
||||
startDrag: (type: AssetType, id: string, length: number) => void;
|
||||
endDrag: () => void;
|
||||
}>({
|
||||
addKeyframe: () => {},
|
||||
@@ -24,6 +27,7 @@ export const TrackContext = createContext<{
|
||||
|
||||
animationClips: [],
|
||||
audioClips: [],
|
||||
characterItems: [],
|
||||
|
||||
startDrag: () => {},
|
||||
endDrag: () => {},
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { TrackContext } from "~/pages/PageEnigma/contexts/TrackContext/TrackContext";
|
||||
import { ReactNode, useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { ClipType, MediaClip } from "~/pages/PageEnigma/models/track";
|
||||
import {
|
||||
AssetType,
|
||||
ClipType,
|
||||
MediaClip,
|
||||
ObjectItem,
|
||||
} from "~/pages/PageEnigma/models";
|
||||
import useUpdateDragDrop from "~/pages/PageEnigma/contexts/TrackContext/utils/useUpdateDragDrop";
|
||||
import {
|
||||
addCharacterAnimation,
|
||||
@@ -26,6 +31,7 @@ export const TrackProvider = ({ children }: Props) => {
|
||||
|
||||
const [animationClips, setAnimationClips] = useState<MediaClip[]>([]);
|
||||
const [audioClips, setAudioClips] = useState<MediaClip[]>([]);
|
||||
const [characterItems, setCharacterItems] = useState<ObjectItem[]>([]);
|
||||
|
||||
const [scale, setScale] = useState(1);
|
||||
const [length, setLength] = useState(1);
|
||||
@@ -48,7 +54,7 @@ export const TrackProvider = ({ children }: Props) => {
|
||||
// cross group functions
|
||||
const dropClip = useCallback(() => {
|
||||
if (canDrop.value) {
|
||||
if (dragType.value === ClipType.ANIMATION) {
|
||||
if (dragType.value === AssetType.ANIMATION) {
|
||||
addCharacterAnimation({
|
||||
clipId: dragId.value!,
|
||||
characterId: dropId.value,
|
||||
@@ -56,7 +62,7 @@ export const TrackProvider = ({ children }: Props) => {
|
||||
offset: dropOffset.value,
|
||||
});
|
||||
}
|
||||
if (dragType.value === ClipType.AUDIO) {
|
||||
if (dragType.value === AssetType.AUDIO) {
|
||||
addCharacterAudio({
|
||||
clipId: dragId.value!,
|
||||
characterId: dropId.value,
|
||||
@@ -139,6 +145,80 @@ export const TrackProvider = ({ children }: Props) => {
|
||||
name: "Yell",
|
||||
},
|
||||
]);
|
||||
setCharacterItems([
|
||||
{
|
||||
version: 1,
|
||||
media_id: uuid.v4(),
|
||||
name: "Block Stance",
|
||||
thumbnail: "resources/characters/img01.png",
|
||||
},
|
||||
{
|
||||
version: 1,
|
||||
media_id: uuid.v4(),
|
||||
name: "Elbow",
|
||||
thumbnail: "resources/characters/img02.png",
|
||||
},
|
||||
{
|
||||
version: 1,
|
||||
media_id: uuid.v4(),
|
||||
name: "Stand Up",
|
||||
thumbnail: "resources/characters/img03.png",
|
||||
},
|
||||
{
|
||||
version: 1,
|
||||
media_id: uuid.v4(),
|
||||
name: "Wave Sitting",
|
||||
thumbnail: "resources/characters/img04.png",
|
||||
},
|
||||
{
|
||||
version: 1,
|
||||
media_id: uuid.v4(),
|
||||
name: "Idle",
|
||||
thumbnail: "resources/characters/img05.png",
|
||||
},
|
||||
{
|
||||
version: 1,
|
||||
media_id: uuid.v4(),
|
||||
name: "Dancing",
|
||||
thumbnail: "resources/characters/img06.png",
|
||||
},
|
||||
{
|
||||
version: 1,
|
||||
media_id: uuid.v4(),
|
||||
name: "Start Walking",
|
||||
thumbnail: "resources/characters/img07.png",
|
||||
},
|
||||
{
|
||||
version: 1,
|
||||
media_id: uuid.v4(),
|
||||
name: "Start Fight",
|
||||
thumbnail: "resources/characters/img08.png",
|
||||
},
|
||||
{
|
||||
version: 1,
|
||||
media_id: uuid.v4(),
|
||||
name: "",
|
||||
thumbnail: "resources/characters/img09.png",
|
||||
},
|
||||
{
|
||||
version: 1,
|
||||
media_id: uuid.v4(),
|
||||
name: "Dancing 2",
|
||||
thumbnail: "resources/characters/img10.png",
|
||||
},
|
||||
{
|
||||
version: 1,
|
||||
media_id: uuid.v4(),
|
||||
name: "Start Fight 2",
|
||||
thumbnail: "resources/characters/img11.png",
|
||||
},
|
||||
{
|
||||
version: 1,
|
||||
media_id: uuid.v4(),
|
||||
name: "Dancing 3",
|
||||
thumbnail: "resources/characters/img12.png",
|
||||
},
|
||||
]);
|
||||
setScale(1);
|
||||
setLength(12);
|
||||
}, []);
|
||||
@@ -152,6 +232,7 @@ export const TrackProvider = ({ children }: Props) => {
|
||||
|
||||
animationClips,
|
||||
audioClips,
|
||||
characterItems,
|
||||
|
||||
scale,
|
||||
currentTime: time,
|
||||
@@ -169,6 +250,7 @@ export const TrackProvider = ({ children }: Props) => {
|
||||
|
||||
animationClips,
|
||||
audioClips,
|
||||
characterItems,
|
||||
|
||||
updateCurrentTime,
|
||||
time,
|
||||
|
||||
@@ -5,11 +5,11 @@ import {
|
||||
dragId,
|
||||
dragType,
|
||||
} from "~/pages/PageEnigma/store";
|
||||
import { ClipType } from "~/pages/PageEnigma/models/track";
|
||||
import { AssetType } from "~/pages/PageEnigma/models";
|
||||
|
||||
export default function useUpdateDragDrop() {
|
||||
const startDrag = useCallback(
|
||||
(type: ClipType, id: string, length: number) => {
|
||||
(type: AssetType, id: string, length: number) => {
|
||||
dragId.value = id;
|
||||
dragType.value = type;
|
||||
clipLength.value = length;
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import { useCallback } from "react";
|
||||
import {
|
||||
ClipGroup,
|
||||
QueueKeyframe,
|
||||
Keyframe,
|
||||
} from "~/pages/PageEnigma/models/track";
|
||||
import { ClipGroup, QueueKeyframe, Keyframe } from "~/pages/PageEnigma/models";
|
||||
import {
|
||||
addCameraKeyframe,
|
||||
addCharacterKeyframe,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Clip offsets represent the state of the clip on the timeline as well as what type of clip it is.
|
||||
// it is created from a media id.
|
||||
import { ClipGroup, ClipType } from "~/pages/PageEnigma/models/track";
|
||||
import { ClipGroup, ClipType } from "~/pages/PageEnigma/models";
|
||||
|
||||
export class ClipUI {
|
||||
version: number;
|
||||
|
||||
@@ -161,7 +161,7 @@ export class APIManager {
|
||||
const loadGlb = (
|
||||
bucket_path: string,
|
||||
): Promise<APIManagerResponseSuccess> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise((resolve) => {
|
||||
glbLoader.load(bucket_path, (glb) => {
|
||||
if (glb) {
|
||||
const scene: THREE.Scene = glb.scene;
|
||||
|
||||
@@ -22,9 +22,9 @@ import { AnimationEngine } from "./animation_engine.js";
|
||||
|
||||
import { PointerLockControls } from "three/addons/controls/PointerLockControls.js";
|
||||
import { APPUI_ACTION_TYPES } from "../reducers";
|
||||
import { ClipGroup } from "~/pages/PageEnigma/models/track";
|
||||
import { ClipGroup, ClipType } from "~/pages/PageEnigma/models";
|
||||
import { XYZ } from "~/pages/PageEnigma/datastructures/common";
|
||||
|
||||
import { XYZ } from "../../datastructures/common";
|
||||
class EditorState {
|
||||
// {
|
||||
// action: "ShowLoadingIndicator"
|
||||
@@ -340,7 +340,7 @@ class Editor {
|
||||
if (this.cam_obj) {
|
||||
this.addTransformClipBase(
|
||||
"Camera Object",
|
||||
"camera",
|
||||
ClipGroup.CAMERA,
|
||||
this.cam_obj,
|
||||
0,
|
||||
150,
|
||||
@@ -442,24 +442,21 @@ class Editor {
|
||||
}
|
||||
|
||||
// TO UPDATE selected objects in the scene might want to add to the scene ...
|
||||
async setSelectedObject(position:XYZ,rotation:XYZ,scale:XYZ) {
|
||||
if (this.selected !=null) {
|
||||
async setSelectedObject(position: XYZ, rotation: XYZ, scale: XYZ) {
|
||||
if (this.selected != null) {
|
||||
this.selected.position.x = position.x;
|
||||
this.selected.position.y = position.y;
|
||||
this.selected.position.z = position.z;
|
||||
|
||||
this.selected.position.x = position.x
|
||||
this.selected.position.y = position.y
|
||||
this.selected.position.z = position.z
|
||||
|
||||
this.selected.rotation.x = rotation.x
|
||||
this.selected.rotation.y = rotation.y
|
||||
this.selected.rotation.z = rotation.z
|
||||
|
||||
this.selected.scale.x = scale.x
|
||||
this.selected.scale.y = scale.y
|
||||
this.selected.scale.z = scale.z
|
||||
this.selected.rotation.x = rotation.x;
|
||||
this.selected.rotation.y = rotation.y;
|
||||
this.selected.rotation.z = rotation.z;
|
||||
|
||||
this.selected.scale.x = scale.x;
|
||||
this.selected.scale.y = scale.y;
|
||||
this.selected.scale.z = scale.z;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public async saveScene(name: string) {
|
||||
// remove controls when saving scene.
|
||||
@@ -535,8 +532,8 @@ class Editor {
|
||||
this.timeline.addPlayableClip(
|
||||
new ClipUI(
|
||||
1.0,
|
||||
"lipsync",
|
||||
"character",
|
||||
ClipType.AUDIO,
|
||||
ClipGroup.CHARACTER,
|
||||
"clip1",
|
||||
"m_f1jxx4zwy4da2zn0cvdqhha7kqkj72",
|
||||
object.uuid,
|
||||
@@ -549,8 +546,8 @@ class Editor {
|
||||
this.timeline.addPlayableClip(
|
||||
new ClipUI(
|
||||
1.0,
|
||||
"transform",
|
||||
"character",
|
||||
ClipType.TRANSFORM,
|
||||
ClipGroup.CHARACTER,
|
||||
"clip2",
|
||||
object.uuid,
|
||||
object.uuid,
|
||||
@@ -563,8 +560,8 @@ class Editor {
|
||||
this.timeline.addPlayableClip(
|
||||
new ClipUI(
|
||||
1.0,
|
||||
"animation",
|
||||
"character",
|
||||
ClipType.ANIMATION,
|
||||
ClipGroup.CHARACTER,
|
||||
"clip3",
|
||||
"/resources/models/fox/fox_idle.glb",
|
||||
object.uuid,
|
||||
@@ -628,7 +625,7 @@ class Editor {
|
||||
|
||||
async addTransformClipBase(
|
||||
name: string = "New Clip",
|
||||
group: "object" | "character" | "camera" | "global_audio",
|
||||
group: ClipGroup,
|
||||
object: THREE.Object3D,
|
||||
offset: number,
|
||||
length: number,
|
||||
@@ -636,7 +633,7 @@ class Editor {
|
||||
this.timeline.addPlayableClip(
|
||||
new ClipUI(
|
||||
1.0,
|
||||
"transform",
|
||||
ClipType.TRANSFORM,
|
||||
group,
|
||||
name,
|
||||
object.uuid, // object id here ...
|
||||
@@ -823,7 +820,7 @@ class Editor {
|
||||
if (this.cam_obj) {
|
||||
this.addTransformClipBase(
|
||||
"Camera Object",
|
||||
"camera",
|
||||
ClipGroup.CAMERA,
|
||||
this.cam_obj,
|
||||
0,
|
||||
150,
|
||||
@@ -844,11 +841,11 @@ class Editor {
|
||||
|
||||
if (this.cameraViewControls && this.camera_person_mode) {
|
||||
this.cameraViewControls.update(5 * delta_time);
|
||||
if(this.cam_obj){
|
||||
if (this.cam_obj) {
|
||||
if (this.last_scrub != this.timeline.scrubber_frame_position) {
|
||||
this.camera.position.copy(this.cam_obj.position);
|
||||
this.camera.rotation.copy(this.cam_obj.rotation);
|
||||
} else if(this.timeline.is_playing == false) {
|
||||
} else if (this.timeline.is_playing == false) {
|
||||
this.cam_obj.position.copy(this.camera.position);
|
||||
this.cam_obj.rotation.copy(this.camera.rotation);
|
||||
} else {
|
||||
@@ -865,7 +862,7 @@ class Editor {
|
||||
|
||||
this.updateSelectedUI();
|
||||
|
||||
if(this.timeline.is_playing){
|
||||
if (this.timeline.is_playing) {
|
||||
this.timeline.update();
|
||||
}
|
||||
|
||||
@@ -1002,7 +999,7 @@ class Editor {
|
||||
|
||||
if (compile_audio) {
|
||||
for (const clip of this.timeline.timeline_items) {
|
||||
if (clip.type == "lipsync" || clip.type == "audio") {
|
||||
if (clip.type === ClipType.AUDIO) {
|
||||
await this.convertAudioClip(itteration, ffmpeg, clip);
|
||||
itteration += 1;
|
||||
}
|
||||
@@ -1024,7 +1021,6 @@ class Editor {
|
||||
|
||||
const data = await this.api_manager.uploadMedia(blob, "render.mp4");
|
||||
// Create a link to download the file
|
||||
|
||||
}
|
||||
|
||||
async generateFrame() {
|
||||
|
||||
@@ -11,7 +11,7 @@ import Queue from "~/pages/PageEnigma/Queue/Queue";
|
||||
import { QueueNames } from "../Queue/QueueNames";
|
||||
import { toEngineActions } from "../Queue/toEngineActions";
|
||||
import { fromEngineActions } from "../Queue/fromEngineActions";
|
||||
import { ClipGroup, ClipType } from "~/pages/PageEnigma/models/track";
|
||||
import { ClipGroup, ClipType } from "~/pages/PageEnigma/models";
|
||||
|
||||
// Every object uuid / entity has a track.
|
||||
export class TimelineCurrentState {
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import { ClipType } from "~/pages/PageEnigma/models";
|
||||
|
||||
export interface MediaClip {
|
||||
version: number;
|
||||
type: ClipType;
|
||||
media_id: string;
|
||||
name: string;
|
||||
length: number;
|
||||
}
|
||||
|
||||
export interface ObjectItem {
|
||||
version: number;
|
||||
media_id: string;
|
||||
name: string;
|
||||
thumbnail: string;
|
||||
}
|
||||
|
||||
export enum AssetType {
|
||||
CHARACTER = "character",
|
||||
OBJECT = "object",
|
||||
AUDIO = "audio",
|
||||
ANIMATION = "animation",
|
||||
CAMERA = "camera",
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from "./assets";
|
||||
export * from "./message";
|
||||
export * from "./track";
|
||||
@@ -0,0 +1,28 @@
|
||||
import { ClipGroup, ClipType } from "~/pages/PageEnigma/models";
|
||||
import { XYZ } from "~/pages/PageEnigma/datastructures/common";
|
||||
|
||||
export interface QueueClip {
|
||||
version: number;
|
||||
type: ClipType;
|
||||
group: ClipGroup;
|
||||
object_uuid?: string;
|
||||
clip_uuid?: string;
|
||||
media_id?: string;
|
||||
name?: string;
|
||||
offset?: number;
|
||||
length?: number;
|
||||
selected?: boolean;
|
||||
}
|
||||
|
||||
export interface QueueKeyframe {
|
||||
version: number;
|
||||
keyframe_uuid?: string;
|
||||
group: ClipGroup;
|
||||
object_uuid: string;
|
||||
object_name?: string;
|
||||
offset?: number;
|
||||
position: XYZ;
|
||||
rotation: XYZ;
|
||||
scale: XYZ;
|
||||
selected?: boolean;
|
||||
}
|
||||
@@ -1,26 +1,5 @@
|
||||
import { XYZ } from "../datastructures/common";
|
||||
|
||||
export interface QueueClip {
|
||||
version: number;
|
||||
type: ClipType;
|
||||
group: ClipGroup;
|
||||
object_uuid?: string;
|
||||
clip_uuid?: string;
|
||||
media_id?: string;
|
||||
name?: string;
|
||||
offset?: number;
|
||||
length?: number;
|
||||
selected?: boolean;
|
||||
}
|
||||
|
||||
export interface MediaClip {
|
||||
version: number;
|
||||
type: ClipType;
|
||||
media_id: string;
|
||||
name: string;
|
||||
length: number;
|
||||
}
|
||||
|
||||
export interface Clip {
|
||||
version: number;
|
||||
clip_uuid: string;
|
||||
@@ -59,19 +38,6 @@ export interface Keyframe {
|
||||
selected?: boolean;
|
||||
}
|
||||
|
||||
export interface QueueKeyframe {
|
||||
version: number;
|
||||
keyframe_uuid?: string;
|
||||
group: ClipGroup;
|
||||
object_uuid: string;
|
||||
object_name?: string;
|
||||
offset?: number;
|
||||
position: XYZ;
|
||||
rotation: XYZ;
|
||||
scale: XYZ;
|
||||
selected?: boolean;
|
||||
}
|
||||
|
||||
export interface CharacterGroup {
|
||||
id: string;
|
||||
muted: boolean;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Simple3DVector } from "../../datastructures/common";
|
||||
import { ClipGroup } from "../../models/track";
|
||||
import { AssetType, ClipGroup } from "../../models";
|
||||
export enum VIEW_MODES {
|
||||
EDITOR = "editor",
|
||||
SIDE_BY_SIDE = "side-by-side",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { State, VIEW_MODES } from "./types";
|
||||
import { ClipGroup } from "~/pages/PageEnigma/models/track";
|
||||
import { ClipGroup } from "~/pages/PageEnigma/models";
|
||||
|
||||
export const initialStateValues: State = {
|
||||
timelineHeight: 260,
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
ClipGroup,
|
||||
ClipType,
|
||||
MediaClip,
|
||||
} from "~/pages/PageEnigma/models/track";
|
||||
} from "~/pages/PageEnigma/models";
|
||||
import Queue from "~/pages/PageEnigma/Queue/Queue";
|
||||
import { QueueNames } from "~/pages/PageEnigma/Queue/QueueNames";
|
||||
import { toEngineActions } from "~/pages/PageEnigma/Queue/toEngineActions";
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
CameraGroup,
|
||||
Keyframe,
|
||||
QueueKeyframe,
|
||||
} from "~/pages/PageEnigma/models/track";
|
||||
} from "~/pages/PageEnigma/models";
|
||||
import Queue from "~/pages/PageEnigma/Queue/Queue";
|
||||
import { QueueNames } from "~/pages/PageEnigma/Queue/QueueNames";
|
||||
import { toEngineActions } from "~/pages/PageEnigma/Queue/toEngineActions";
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
Keyframe,
|
||||
MediaClip,
|
||||
QueueKeyframe,
|
||||
} from "~/pages/PageEnigma/models/track";
|
||||
} from "~/pages/PageEnigma/models";
|
||||
import { signal } from "@preact/signals-core";
|
||||
import Queue from "~/pages/PageEnigma/Queue/Queue";
|
||||
import { QueueNames } from "~/pages/PageEnigma/Queue/QueueNames";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { signal } from "@preact/signals-core";
|
||||
import { ClipType } from "~/pages/PageEnigma/models/track";
|
||||
import { AssetType } from "~/pages/PageEnigma/models";
|
||||
|
||||
export const dragType = signal<ClipType | null>(null);
|
||||
export const dragType = signal<AssetType | null>(null);
|
||||
export const dragId = signal<string | null>(null);
|
||||
export const canDrop = signal(false);
|
||||
export const overTimeline = signal(false);
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
Keyframe,
|
||||
ObjectGroup,
|
||||
QueueKeyframe,
|
||||
} from "~/pages/PageEnigma/models/track";
|
||||
} from "~/pages/PageEnigma/models";
|
||||
import * as uuid from "uuid";
|
||||
import Queue from "~/pages/PageEnigma/Queue/Queue";
|
||||
import { QueueNames } from "~/pages/PageEnigma/Queue/QueueNames";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { signal } from "@preact/signals-core";
|
||||
import { Clip, Keyframe } from "~/pages/PageEnigma/models/track";
|
||||
import { Clip, Keyframe } from "~/pages/PageEnigma/models";
|
||||
|
||||
export const selectedItem = signal<Clip | Keyframe | null>(null);
|
||||
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 621 B |
|
After Width: | Height: | Size: 562 B |
|
After Width: | Height: | Size: 617 B |
|
After Width: | Height: | Size: 610 B |
|
After Width: | Height: | Size: 610 B |
|
After Width: | Height: | Size: 520 B |
@@ -122,6 +122,10 @@ export default {
|
||||
unselected: "#EEEEEE",
|
||||
selected: "#FFDE67",
|
||||
},
|
||||
assets: {
|
||||
background: "#39394D",
|
||||
selectedTab: "#55556B",
|
||||
},
|
||||
|
||||
"ui-background": "#1a1a27",
|
||||
"ui-panel": "#242433",
|
||||
|
||||