More refactor/cleanup

This commit is contained in:
FromTheLOLAshes committed 2024-04-04 08:27:08 +02:00
1 parent 76192c782b
commit 4898233e52
21 files changed
+209 -167

No files matched your search

@@ -1,5 +1,5 @@
import { useCallback, useContext, useEffect } from "react";
import { MediaClip } from "~/pages/PageEnigma/models/track";
import { ClipType, MediaClip } from "~/pages/PageEnigma/models/track";
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: "animations" | "audio";
type: ClipType;
}
export const AnimationElement = ({ clip, type }: Props) => {
@@ -3,6 +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";
export const AnimationElements = () => {
const { animationClips } = useContext(TrackContext);
@@ -17,7 +18,11 @@ export const AnimationElements = () => {
<div className="flex flex-wrap gap-3 overflow-y-auto" style={{ height }}>
{animationClips.map((clip) => {
return (
<AnimationElement key={clip.media_id} clip={clip} type="animations" />
<AnimationElement
key={clip.media_id}
clip={clip}
type={ClipType.ANIMATION}
/>
);
})}
</div>
@@ -1,5 +1,5 @@
import { useCallback, useContext, useEffect } from "react";
import { MediaClip } from "~/pages/PageEnigma/models/track";
import { ClipType, MediaClip } from "~/pages/PageEnigma/models/track";
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: "animations" | "audio";
type: ClipType;
}
export const AudioElement = ({ clip, type }: Props) => {
@@ -7,10 +7,11 @@ import {
updateCharacters,
} from "~/pages/PageEnigma/store";
import { TrackKeyFrames } from "~/pages/PageEnigma/comps/Timeline/TrackKeyFrames";
import { ClipGroup, ClipType } from "~/pages/PageEnigma/models/track";
function buildUpdaters(
updateCharacters: (options: {
type: "animations" | "positions" | "lipSync";
type: ClipType;
id: string;
length: number;
offset: number;
@@ -21,17 +22,17 @@ function buildUpdaters(
length: number;
offset: number;
}) {
updateCharacters({ ...options, type: "animations" });
updateCharacters({ ...options, type: ClipType.ANIMATION });
}
function updateClipPosition(options: { id: string; offset: number }) {
updateCharacters({ ...options, length: 0, type: "positions" });
updateCharacters({ ...options, length: 0, type: ClipType.TRANSFORM });
}
function updateClipLipSync(options: {
id: string;
length: number;
offset: number;
}) {
updateCharacters({ ...options, type: "lipSync" });
updateCharacters({ ...options, type: ClipType.AUDIO });
}
return { updateClipLipSync, updateClipPosition, updateClipAnimations };
}
@@ -68,15 +69,15 @@ export const Character = ({ characterId }: Props) => {
clips={animationClips}
title="Animation"
updateClip={updateClipAnimations}
style="character"
type="animations"
group={ClipGroup.CHARACTER}
type={ClipType.ANIMATION}
/>
<TrackKeyFrames
id={character.id}
keyframes={positionKeyframes}
title="Character Position/Rotation"
updateKeyframe={updateClipPosition}
style="character"
group={ClipGroup.CHARACTER}
/>
<TrackClips
id={character.id}
@@ -85,8 +86,8 @@ export const Character = ({ characterId }: Props) => {
updateClip={updateClipLipSync}
muted={character.muted}
toggleMute={toggleCharacterLipSyncMute}
style="character"
type="lipSync"
group={ClipGroup.CHARACTER}
type={ClipType.AUDIO}
/>
</div>
</div>
@@ -1,5 +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";
export const ObjectTrack = () => {
return (
@@ -17,7 +18,7 @@ export const ObjectTrack = () => {
keyframes={object.keyframes}
title={`${object.name} Position/Rotation`}
updateKeyframe={updateObject}
style="objects"
group={ClipGroup.OBJECT}
/>
</div>
))}
@@ -13,7 +13,7 @@ import {
import { useQueueHandler } from "~/pages/PageEnigma/comps/Timeline/utils/useQueueHandler";
import { useSignals } from "@preact/signals-react/runtime";
import { TimerGrid } from "~/pages/PageEnigma/comps/TimerGrid/TimerGrid";
import { Scrubber } from "~/pages/PageEnigma/comps/Scrubber/Scrubber";
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";
@@ -1,17 +1,17 @@
import { useMouseEventsClip } from "./utils/useMouseEventsClip";
import { useState } from "react";
import { scale, selectedItem } from "~/pages/PageEnigma/store";
import { Clip } from "~/pages/PageEnigma/models/track";
import { Clip, ClipGroup } from "~/pages/PageEnigma/models/track";
interface Props {
min: number;
max: number;
style: "character" | "camera" | "audio" | "objects";
group: ClipGroup;
clip: Clip;
updateClip: (options: { id: string; offset: number; length: number }) => void;
}
export const TrackClip = ({ clip, min, max, style, updateClip }: Props) => {
export const TrackClip = ({ clip, min, max, group, updateClip }: Props) => {
const [state, setState] = useState({
length: clip.length,
offset: clip.offset,
@@ -31,8 +31,8 @@ export const TrackClip = ({ clip, min, max, style, updateClip }: Props) => {
const classes = [
"absolute",
clip.clip_uuid === selectedClipId
? `bg-${style}-selected`
: `bg-${style}-clip`,
? `bg-${group}-selected`
: `bg-${group}-clip`,
];
return (
@@ -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 } from "~/pages/PageEnigma/models/track";
import { Clip, ClipGroup, ClipType } from "~/pages/PageEnigma/models/track";
import { PointerEvent } from "react";
import {
canDrop,
@@ -17,13 +17,38 @@ interface Props {
id: string;
clips: Clip[];
title: string;
style: "character" | "audio" | "camera" | "objects";
type?: "animations" | "positions" | "lipSync";
group: ClipGroup;
type?: ClipType;
toggleMute?: () => void;
muted?: boolean;
updateClip: (options: { id: string; length: number; offset: number }) => void;
}
function getCanBuild({
dragType,
type,
group,
}: {
dragType: ClipType | null;
type?: ClipType;
group: ClipGroup;
}) {
if (dragType === ClipType.ANIMATION) {
if (dragType === type) {
return true;
}
}
if (dragType === ClipType.AUDIO) {
if (group === ClipGroup.CHARACTER && type === ClipType.AUDIO) {
return true;
}
if (group === ClipGroup.GLOBAL_AUDIO) {
return true;
}
}
return false;
}
export const TrackClips = ({
id,
clips,
@@ -31,36 +56,22 @@ export const TrackClips = ({
updateClip,
muted,
title,
style,
group,
type,
}: Props) => {
const trackType = type ?? style;
const trackType = (type ?? group) as ClipType;
function onPointerOver() {
if (dragType.value === "animations") {
if (dragType.value !== trackType) {
return;
}
if (getCanBuild({ dragType: dragType.value, type, group })) {
dropId.value = id;
}
if (dragType.value === "audio") {
if (["lipSync", "audio"].indexOf(trackType) === -1) {
return;
}
}
dropId.value = id;
}
function onPointerMove(event: PointerEvent<HTMLDivElement>) {
if (dragType.value === "animations") {
if (dragType.value !== trackType) {
return;
}
}
if (dragType.value === "audio") {
if (["lipSync", "audio"].indexOf(trackType) === -1) {
return;
}
if (!getCanBuild({ dragType: dragType.value, type, group })) {
return;
}
const track = document.getElementById(`track-${trackType}-${id}`);
if (!track) {
return;
@@ -101,7 +112,7 @@ export const TrackClips = ({
<div className="pl-16">
<div
id={`track-${trackType}-${id}`}
className={`relative mt-4 block h-9 w-full rounded-lg bg-${style}-unselected`}
className={`relative mt-4 block h-9 w-full rounded-lg bg-${group}-unselected`}
onPointerOver={onPointerOver}
onPointerLeave={onPointerLeave}
onPointerMove={onPointerMove}
@@ -117,7 +128,7 @@ export const TrackClips = ({
? clips[index + 1].offset
: filmLength.value * 60
}
style={style}
group={group}
updateClip={updateClip}
clip={clip}
/>
@@ -1,28 +1,21 @@
import { Keyframe } from "~/pages/PageEnigma/models/track";
import { useState } from "react";
import { scale, selectedItem } from "~/pages/PageEnigma/store";
import { filmLength, scale, selectedItem } from "~/pages/PageEnigma/store";
import { useMouseEventsKeyframe } from "~/pages/PageEnigma/comps/Timeline/utils/useMouseEventsKeyframe";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faSortUpDown } from "@fortawesome/pro-solid-svg-icons";
import { useSignals } from "@preact/signals-react/runtime";
interface Props {
min: number;
max: number;
keyframe: Keyframe;
updateKeyframe: (options: { id: string; offset: number }) => void;
}
export const TrackKeyFrame = ({
keyframe,
min,
max,
updateKeyframe,
}: Props) => {
export const TrackKeyFrame = ({ keyframe, updateKeyframe }: Props) => {
useSignals();
const [offset, setOffset] = useState(keyframe.offset);
const { onPointerDown } = useMouseEventsKeyframe({
keyframe,
max,
min,
max: filmLength.value * 60,
min: 0,
updateKeyframe,
setOffset,
});
@@ -1,15 +1,18 @@
import { Keyframe } from "~/pages/PageEnigma/models/track";
import { filmLength } from "~/pages/PageEnigma/store";
import { ClipGroup, Keyframe } from "~/pages/PageEnigma/models/track";
import { TrackKeyFrame } from "~/pages/PageEnigma/comps/Timeline/TrackKeyFrame";
interface Props {
id: string;
keyframes: Keyframe[];
title: string;
style: "character" | "audio" | "camera" | "objects";
group: ClipGroup;
toggleMute?: () => void;
muted?: boolean;
updateKeyframe: (options: { id: string; offset: number }) => void;
updateKeyframe: (options: {
id: string;
offset: number;
force?: boolean;
}) => void;
}
export const TrackKeyFrames = ({
@@ -17,23 +20,17 @@ export const TrackKeyFrames = ({
keyframes,
updateKeyframe,
title,
style,
group,
}: Props) => {
return (
<div className="pl-16">
<div
id={`track-${style}-${id}`}
className={`relative mt-4 block h-9 w-full rounded-lg bg-${style}-unselected`}
id={`track-${group}-${id}`}
className={`relative mt-4 block h-9 w-full rounded-lg bg-${group}-unselected`}
>
{keyframes.map((keyframe, index) => (
{keyframes.map((keyframe) => (
<TrackKeyFrame
key={keyframe.keyframe_uuid}
min={index > 0 ? keyframes[index - 1].offset + 1 : 0}
max={
index < keyframes.length - 1
? keyframes[index + 1].offset
: filmLength.value * 60
}
updateKeyframe={updateKeyframe}
keyframe={keyframe}
/>
@@ -37,13 +37,11 @@ export const useMouseEventsClip = (
if (isActive.current === "drag") {
if (deltaOffset < min) {
currOffset.current = min;
return;
} else if (deltaOffset + currLength.current > max) {
currOffset.current = max;
} else {
currOffset.current = deltaOffset;
}
if (deltaOffset + currLength.current > max) {
currOffset.current = max - currLength.current;
return;
}
currOffset.current = deltaOffset;
}
if (isActive.current === "left") {
if (initLength.current - delta < 30 || deltaOffset < min) {
@@ -1,6 +1,10 @@
import React, { Dispatch, useCallback, useEffect, useRef } from "react";
import { Keyframe } from "~/pages/PageEnigma/models/track";
import { canDrop, scale } from "~/pages/PageEnigma/store";
import {
canDrop,
scale,
showDuplicateOffsetWarning,
} from "~/pages/PageEnigma/store";
import { useSignals } from "@preact/signals-react/runtime";
export const useMouseEventsKeyframe = ({
@@ -40,15 +44,13 @@ export const useMouseEventsKeyframe = ({
if (isActive.current === "drag") {
if (deltaOffset < min) {
currOffset.current = min;
return;
}
if (deltaOffset > max) {
} else if (deltaOffset > max) {
currOffset.current = max;
return;
} else {
currOffset.current = deltaOffset;
}
currOffset.current = deltaOffset;
setOffset(currOffset.current);
}
setOffset(currOffset.current);
},
[max, min, setOffset],
);
@@ -3,6 +3,7 @@ import {
MediaClip,
Keyframe,
QueueKeyframe,
ClipType,
} from "~/pages/PageEnigma/models/track";
export const TrackContext = createContext<{
@@ -15,7 +16,7 @@ export const TrackContext = createContext<{
audioClips: MediaClip[];
// drag and drop
startDrag: (type: "animations" | "audio", id: string, length: number) => void;
startDrag: (type: ClipType, id: string, length: number) => void;
endDrag: () => void;
}>({
addKeyframe: () => {},
@@ -1,47 +1,49 @@
// 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";
export class ClipUI {
version: number
type: "transform" | "audio" | "animation" | "lipsync"
group: "character" | "object" | "camera" | "global_audio"
name: string
media_id: string
object_uuid: string
offset: number // in frames
length: number // in frames
version: number;
type: ClipType;
group: ClipGroup;
name: string;
media_id: string;
object_uuid: string;
offset: number; // in frames
length: number; // in frames
constructor(
version: number,
type: "transform" | "audio" | "animation" | "lipsync",
group: "character" | "object" | "camera" | "global_audio",
type: ClipType,
group: ClipGroup,
name: string,
media_id: string,
object_uuid: string,
offset: number,
length: number,
) {
this.version = version
this.group = group // Only needed for UI
this.version = version;
this.group = group; // Only needed for UI
this.name = name // UI
this.type = type // UI and Animation / Audio / Lipsync / : Engine
this.name = name; // UI
this.type = type; // UI and Animation / Audio / Lipsync / : Engine
this.object_uuid = object_uuid // Animation / Audio / Lipsync / : Engine
this.media_id = media_id // Animation / Audio / Lipsync / : Engine
this.offset = offset
this.length = length
this.object_uuid = object_uuid; // Animation / Audio / Lipsync / : Engine
this.media_id = media_id; // Animation / Audio / Lipsync / : Engine
this.offset = offset;
this.length = length;
}
toJSON(): string {
return JSON.stringify({
version: this.version,
group:this.group,
group: this.group,
name: this.name,
type: this.type,
object_uuid: this.object_uuid,
media_id: this.media_id,
start_offset: this.offset,
ending_offset: this.length
})
ending_offset: this.length,
});
}
}
+30 -30
View File
@@ -54,9 +54,9 @@ export enum Visibility {
*/
type Data = { [key: string]: any };
class APIManagerResponseSuccess {
public user_message: String;
public user_message: string;
public data: Data | null;
constructor(user_message: String = "", data: Data | null = null) {
constructor(user_message: string = "", data: Data | null = null) {
this.data = data;
this.user_message = user_message;
}
@@ -74,7 +74,7 @@ class APIManagerResponseError extends Error {
}
export class APIManager {
baseUrl: String;
baseUrl: string;
constructor() {
this.baseUrl = "https://api.fakeyou.com";
@@ -139,9 +139,9 @@ export class APIManager {
throw new APIManagerResponseError("Failed to download file");
}
// Convert the response from a blob to json text
let blob = await file_response.blob();
const blob = await file_response.blob();
const json_result: string = await new Promise((resolve, reject) => {
let reader = new FileReader();
const reader = new FileReader();
reader.onloadend = () => resolve(JSON.parse(reader.result as string));
reader.onerror = reject;
reader.readAsText(blob);
@@ -156,7 +156,7 @@ export class APIManager {
scene_glb_media_file_token,
);
console.log(`GLB ${media_bucket_path}`);
let glbLoader = new GLTFLoader();
const glbLoader = new GLTFLoader();
// promisify this
const loadGlb = (
bucket_path: string,
@@ -188,13 +188,13 @@ export class APIManager {
* @returns
*/
private async getMediaFile(media_file_token: string): Promise<string> {
let api_base_url = "https://api.fakeyou.com";
let url = `${api_base_url}/v1/media_files/file/${media_file_token}`;
let response = await fetch(url);
let json = await JSON.parse(await response.text());
let bucketPath = json["media_file"]["public_bucket_path"];
let media_base_url = "https://storage.googleapis.com/vocodes-public";
let media_url = `${media_base_url}${bucketPath}`; // gets you a bucket path
const api_base_url = "https://api.fakeyou.com";
const url = `${api_base_url}/v1/media_files/file/${media_file_token}`;
const response = await fetch(url);
const json = await JSON.parse(await response.text());
const bucketPath = json["media_file"]["public_bucket_path"];
const media_base_url = "https://storage.googleapis.com/vocodes-public";
const media_url = `${media_base_url}${bucketPath}`; // gets you a bucket path
return media_url;
}
@@ -218,7 +218,7 @@ export class APIManager {
scene_glb_media_file_token: string | null,
): Promise<string> {
const url = `${this.baseUrl}/v1/media_files/write/engine_asset`;
let uuid = uuidv4();
const uuid = uuidv4();
const form_data = new FormData();
form_data.append("uuid_idempotency_token", uuid);
@@ -257,7 +257,7 @@ export class APIManager {
timeline_state: TimelineDataState | null, // only for now.
): Promise<string> {
const url = `${this.baseUrl}/v1/media_files/write/scene_file`;
let uuid = uuidv4();
const uuid = uuidv4();
console.log(
`Saving Scene scene_media_file_token:${scene_media_file_token} | scene_glb_media_file_token:${scene_glb_media_file_token}`,
@@ -311,7 +311,7 @@ export class APIManager {
fileName: string,
): Promise<APIManagerResponseSuccess> {
const url = `${this.baseUrl}/v1/media_uploads/upload`;
let uuid = uuidv4();
const uuid = uuidv4();
const formData = new FormData();
formData.append("uuid_idempotency_token", uuid);
@@ -346,11 +346,11 @@ export class APIManager {
negative_prompt: string,
): Promise<string> {
const url = `https://funnel.tailce84f.ts.net/preview/`;
const payload = {
style: style,
positive_prompt: positive_prompt,
negative_prompt: negative_prompt
negative_prompt: negative_prompt,
};
const formData = new FormData();
@@ -393,14 +393,15 @@ export class APIManager {
return result;
}
public async stylizeVideo(media_token: string,
style: ArtStyle,
positive_prompt:string,
negative_prompt:string,
visibility:Visibility) {
let uuid = uuidv4();
public async stylizeVideo(
media_token: string,
style: ArtStyle,
positive_prompt: string,
negative_prompt: string,
visibility: Visibility,
) {
const uuid = uuidv4();
const data = {
uuid_idempotency_token: uuid,
style: style,
@@ -410,10 +411,10 @@ export class APIManager {
trim_start_millis: 0,
trim_end_millis: 3000,
enable_lipsync: true,
creator_set_visibility: visibility
}
creator_set_visibility: visibility,
};
const json_data = JSON.stringify(data)
const json_data = JSON.stringify(data);
const response = await fetch(`${this.baseUrl}/v1/video/enqueue_vst`, {
method: "POST",
@@ -435,4 +436,3 @@ export class APIManager {
return await response.json();
}
}
+3 -2
View File
@@ -11,6 +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 { ClipType } from "~/pages/PageEnigma/models/track";
// Every object uuid / entity has a track.
export class TimelineCurrentState {
@@ -169,10 +170,10 @@ export class TimeLine {
);
switch (type) {
case "animation":
case ClipType.ANIMATION:
this.animation_engine.load_object(object_uuid, media_id, name);
break;
case "transform":
case ClipType.TRANSFORM:
this.transform_engine.loadObject(object_uuid, data["data"]["length"]);
break;
}
+9 -2
View File
@@ -13,6 +13,11 @@ export const cameraGroup = signal<CameraGroup>({ id: "CG1", keyframes: [] });
export function updateCamera({ id, offset }: { id: string; offset: number }) {
const oldCameraGroup = cameraGroup.value;
if (oldCameraGroup.keyframes.some((row) => row.offset === offset)) {
return;
}
const newKeyframes = [...oldCameraGroup.keyframes];
const keyframe = newKeyframes.find((row) => row.keyframe_uuid === id);
if (!keyframe) {
@@ -33,7 +38,10 @@ export function updateCamera({ id, offset }: { id: string; offset: number }) {
}
export function addCameraKeyframe(keyframe: QueueKeyframe, offset: number) {
console.log("cam", keyframe);
const oldCameraGroup = cameraGroup.value;
if (oldCameraGroup.keyframes.some((row) => row.offset === offset)) {
return;
}
const newKeyframe = {
version: keyframe.version,
keyframe_uuid: uuid.v4(),
@@ -46,7 +54,6 @@ export function addCameraKeyframe(keyframe: QueueKeyframe, offset: number) {
selected: false,
} as Keyframe;
const oldCameraGroup = cameraGroup.value;
cameraGroup.value = {
...oldCameraGroup,
keyframes: [...oldCameraGroup.keyframes, newKeyframe].sort(
+21 -8
View File
@@ -28,14 +28,16 @@ export function updateCharacters({
id,
offset,
length,
force,
}: {
type: "animations" | "positions" | "lipSync";
type: ClipType;
id: string;
length: number;
length?: number;
offset: number;
force?: boolean;
}) {
const oldCharacterGroups = characterGroups.value;
if (type === "animations") {
if (type === ClipType.ANIMATION) {
characterGroups.value = oldCharacterGroups.map((character) => {
const newAnimationClips = [...character.animationClips];
const clipIndex = newAnimationClips.findIndex(
@@ -46,7 +48,7 @@ export function updateCharacters({
}
const clip = newAnimationClips[clipIndex];
clip.offset = offset;
clip.length = length;
clip.length = length!;
Queue.publish({
queueName: QueueNames.TO_ENGINE,
@@ -61,7 +63,7 @@ export function updateCharacters({
});
}
if (type === "positions") {
if (type === ClipType.TRANSFORM) {
characterGroups.value = oldCharacterGroups.map((character) => {
const newPositionKeyframes = [...character.positionKeyframes];
const keyframeIndex = newPositionKeyframes.findIndex(
@@ -85,7 +87,7 @@ export function updateCharacters({
};
});
}
if (type === "lipSync") {
if (type === ClipType.AUDIO) {
characterGroups.value = oldCharacterGroups.map((character) => {
const newLipSyncClips = [...character.lipSyncClips];
const clipIndex = newLipSyncClips.findIndex(
@@ -96,7 +98,7 @@ export function updateCharacters({
}
const clip = newLipSyncClips[clipIndex];
clip.offset = offset;
clip.length = length;
clip.length = length!;
Queue.publish({
queueName: QueueNames.TO_ENGINE,
@@ -204,6 +206,18 @@ export function addCharacterAudio({
}
export function addCharacterKeyframe(keyframe: QueueKeyframe, offset: number) {
const oldCharacterGroups = characterGroups.value;
if (
oldCharacterGroups.some((characterGroup) => {
return characterGroup.positionKeyframes.some(
(row) => row.offset === offset,
);
})
) {
return;
}
const newKeyframe = {
version: keyframe.version,
keyframe_uuid: uuid.v4(),
@@ -216,7 +230,6 @@ export function addCharacterKeyframe(keyframe: QueueKeyframe, offset: number) {
selected: false,
} as Keyframe;
const oldCharacterGroups = characterGroups.value;
characterGroups.value = oldCharacterGroups.map((character) => {
if (character.id !== keyframe.object_uuid) {
return { ...character };
+2 -1
View File
@@ -1,6 +1,7 @@
import { signal } from "@preact/signals-core";
import { ClipType } from "~/pages/PageEnigma/models/track";
export const dragType = signal<"animations" | "audio" | null>(null);
export const dragType = signal<ClipType | null>(null);
export const dragId = signal<string | null>(null);
export const canDrop = signal(false);
export const overTimeline = signal(false);
+24 -15
View File
@@ -15,16 +15,24 @@ export const objectGroup = signal<ObjectGroup>({
});
export function updateObject({ id, offset }: { id: string; offset: number }) {
const oldObject = objectGroup.value;
const oldObjectGroup = objectGroup.value;
const obj = oldObjectGroup.objects.find((objectTrack) =>
objectTrack.keyframes.some((row) => row.keyframe_uuid === id),
);
if (obj && obj.keyframes.some((row) => row.offset === offset)) {
return;
}
objectGroup.value = {
id: oldObject.id,
objects: oldObject.objects.map((object) => ({
id: oldObjectGroup.id,
objects: oldObjectGroup.objects.map((object) => ({
object_uuid: object.object_uuid,
name: object.name,
keyframes: object.keyframes.map((keyFrame) => {
if (keyFrame.keyframe_uuid !== id) {
keyframes: object.keyframes.map((keyframe) => {
if (keyframe.keyframe_uuid !== id) {
return {
...keyFrame,
...keyframe,
};
}
@@ -32,13 +40,13 @@ export function updateObject({ id, offset }: { id: string; offset: number }) {
queueName: QueueNames.TO_ENGINE,
action: toEngineActions.UPDATE_KEYFRAME,
data: {
...keyFrame,
...keyframe,
offset,
},
});
return {
...keyFrame,
...keyframe,
offset,
};
}),
@@ -52,6 +60,10 @@ export function addObjectKeyframe(keyframe: QueueKeyframe, offset: number) {
(row) => row.object_uuid === keyframe.object_uuid,
);
if (obj && obj.keyframes.some((row) => row.offset === offset)) {
return;
}
const newObject = obj ?? {
object_uuid: keyframe.object_uuid,
name: keyframe.object_name ?? "unknown",
@@ -69,19 +81,16 @@ export function addObjectKeyframe(keyframe: QueueKeyframe, offset: number) {
selected: false,
} as Keyframe;
newObject.keyframes.push(newKeyframe);
console.log(newObject);
newObject.keyframes.sort(
(keyframeA, keyframeB) => keyframeA.offset - keyframeB.offset,
);
objectGroup.value = {
...oldObjectGroup,
objects: [
...oldObjectGroup.objects.filter(
(object) => object.object_uuid !== keyframe.object_uuid,
),
newObject,
].sort((objA, objB) => (objA.object_uuid < objB.object_uuid ? -1 : 1)),
objects: [...oldObjectGroup.objects, newObject].sort((objA, objB) =>
objA.object_uuid < objB.object_uuid ? -1 : 1,
),
};
Queue.publish({
queueName: QueueNames.TO_ENGINE,