Add stylizations page

This commit is contained in:
Christopher Oliphant committed 2024-04-10 15:16:24 -04:00
1 parent f20dbc88db
commit 75261f4fa0
42 files changed
+519 -216

No files matched your search

+2 -2
View File
@@ -28,7 +28,7 @@ export const ButtonLink = ({
}
}
const baseClassName =
"text-sm font-medium rounded-lg px-3 py-2 shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 transition-all duration-150";
"text-sm font-medium whitespace-nowrap rounded-lg px-3 py-2 shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 transition-all duration-150";
const variantClassNames = getVariantClassNames(variant);
const className = twMerge(baseClassName, variantClassNames, propsClassName);
// END TODO
@@ -36,7 +36,7 @@ export const ButtonLink = ({
return (
<Link {...rest}>
<button className={className}>
{icon && <FontAwesomeIcon className="mr-2" icon={icon} size="sm"/>}
{icon && <FontAwesomeIcon className="mr-2" icon={icon} size="sm" />}
{children}
</button>
</Link>
File renamed without changes.
+29
View File
@@ -0,0 +1,29 @@
import { ReactNode, useEffect, useState } from "react";
import Editor from "~/pages/PageEnigma/js/editor";
import { EngineContext } from "./EngineContext";
interface Props {
children: ReactNode;
}
export const EngineProvider = ({ children }: Props) => {
const [editor, setEditor] = useState<Editor | null>(null);
useEffect(() => {
setEditor((curr) => {
if (curr !== null) {
console.warn("Editor Engine already exist");
return curr;
} else {
return new Editor();
}
});
// }
}, []);
return (
<EngineContext.Provider value={editor}>{children}</EngineContext.Provider>
);
};
+1 -1
View File
@@ -9,4 +9,4 @@ export const TopBarInnerContext = createContext<{
location: string,
node: React.ReactNode,
} | null)=>void;
} | null>(null);
} | null>(null);
+12 -8
View File
@@ -14,9 +14,10 @@ import { toEngineActions } from "~/pages/PageEnigma/Queue/toEngineActions";
interface LowerPanelPropsI {
children: React.ReactNode;
onStyle?: boolean;
}
export const LowerPanel = ({ children }: LowerPanelPropsI) => {
export const LowerPanel = ({ children, onStyle }: LowerPanelPropsI) => {
const { onPointerDown } = useMouseEventsTimeline();
const displayHeight =
@@ -50,18 +51,21 @@ export const LowerPanel = ({ children }: LowerPanelPropsI) => {
return (
<>
<div
className="absolute w-full cursor-ns-resize bg-ui-panel-border"
style={{ height: 3, zIndex: 1000, bottom: displayHeight }}
onPointerDown={onPointerDown}
/>
{!onStyle && (
<div
className="absolute w-full cursor-ns-resize bg-ui-panel-border"
style={{ height: 3, zIndex: 1000, bottom: displayHeight }}
onPointerDown={onPointerDown}
/>
)}
<div
className={[
"absolute bottom-0",
"w-screen overflow-auto",
"w-screen",
onStyle ? "overflow-x-auto overflow-y-hidden" : "overflow-auto",
"bg-ui-panel",
].join(" ")}
style={{ height: displayHeight }}
style={{ height: onStyle ? 80 : displayHeight }}
onPointerOver={() => {
overTimeline.value = true;
}}
+10 -15
View File
@@ -1,14 +1,17 @@
import { useContext, } from "react";
import { useLocation } from "@remix-run/react";
import { faChevronLeft } from "@fortawesome/pro-solid-svg-icons";
import { TopBarInnerContext } from "~/contexts/TopBarInner";
import { ButtonLink } from "~/components";
import { AuthButtons } from "./AuthButtons";
import { sceneTitle } from "~/store";
export const TopBar = () => {
interface Props {
pageName: string;
}
export const TopBar = ({ pageName }: Props) => {
const currentLocation = useLocation().pathname;
return (
@@ -30,15 +33,16 @@ export const TopBar = () => {
alt="Logo FakeYou StoryTeller.ai"
/>
</a>
{currentLocation !== "/" &&
{currentLocation !== "/" && (
<ButtonLink to={"/"} variant="secondary" icon={faChevronLeft}>
Back to Dashboard
</ButtonLink>
}
)}
</div>
<div className="flex justify-center">
<TopBarInner currentLocation={currentLocation}/>
<span className="opacity-60">{pageName}&nbsp;/</span>&nbsp;
{sceneTitle.value}
</div>
<div className="flex justify-end gap-2">
@@ -49,12 +53,3 @@ export const TopBar = () => {
</header>
);
};
const TopBarInner = ({currentLocation}:{currentLocation:string}) => {
const { TopBarInner } = useContext(TopBarInnerContext) || {};
if(!TopBarInner || TopBarInner.location !== currentLocation){
return null;
}
return TopBarInner.node;
};
+10 -18
View File
@@ -1,17 +1,9 @@
import { useLocation } from "@remix-run/react";
import {
useContext,
useEffect,
useLayoutEffect,
useState,
} from 'react';
import { useContext, useEffect, useLayoutEffect, useState } from "react";
import { TopBarInnerContext } from "~/contexts/TopBarInner";
export const TopBarHelmet = (props:{
children: React.ReactNode | null;
})=>{
export const TopBarHelmet = (props: { children: React.ReactNode | null }) => {
const [showChild, setShowChild] = useState(false);
// Wait until after client-side hydration to show
useEffect(() => {
@@ -23,22 +15,22 @@ export const TopBarHelmet = (props:{
}
return <LazyLoadTopBarInnerContent {...props} />;
}
};
const LazyLoadTopBarInnerContent = (props:{
const LazyLoadTopBarInnerContent = (props: {
children: React.ReactNode | null;
})=>{
}) => {
const { setTopBarInner } = useContext(TopBarInnerContext) || {};
const location = useLocation().pathname;
useLayoutEffect(()=>{
if(setTopBarInner){
useLayoutEffect(() => {
if (setTopBarInner) {
setTopBarInner({
location: location,
node: props.children
node: props.children,
});
}
},[setTopBarInner]);
}, [setTopBarInner]);
return null;
}
};
+13 -31
View File
@@ -1,44 +1,26 @@
import { PageEnigmaComponent } from "./PageEnigmaComponent";
import { TrackProvider } from "~/pages/PageEnigma/contexts/TrackContext/TrackProvider";
import { AppUIProvider } from "~/pages/PageEnigma/contexts/AppUiContext";
import { EngineProvider } from "~/pages/PageEnigma/contexts/EngineProvider";
import { DragComponent } from "~/pages/PageEnigma/comps/DragComponent/DragComponent";
import { useEffect } from "react";
import { useSignals } from "@preact/signals-react/runtime";
import {
pageHeight,
pageWidth,
sidePanelWidth,
timelineHeight,
} from "~/pages/PageEnigma/store";
import { useContext, useEffect } from "react";
import { AppUiContext } from "~/contexts/AppUiContext";
import { EngineContext } from "~/contexts/EngineContext";
export const PageEnigma = () => {
useSignals();
const [_, dispatchAppUiState] = useContext(AppUiContext);
const editor = useContext(EngineContext);
useEffect(() => {
function setPage() {
// TODO address this issue with zooming
pageHeight.value = window.innerHeight;
pageWidth.value = window.innerWidth;
if (editor && editor.can_initialize && dispatchAppUiState !== null) {
console.log("initializing Editor");
editor.initialize({
dispatchAppUiState,
});
}
timelineHeight.value = window.innerHeight * 0.25;
sidePanelWidth.value = 443;
setPage();
window.addEventListener("resize", setPage);
return () => {
window.removeEventListener("resize", setPage);
};
}, []);
}, [editor, dispatchAppUiState]);
return (
<TrackProvider>
<AppUIProvider>
<EngineProvider>
<PageEnigmaComponent />
</EngineProvider>
</AppUIProvider>
<PageEnigmaComponent />
<DragComponent />
</TrackProvider>
);
+7 -23
View File
@@ -1,8 +1,6 @@
import { useContext, useState } from "react";
import { faSparkles } from "@fortawesome/pro-solid-svg-icons";
import React, { useContext } from "react";
import { Button, LoadingBar, LoadingDots } from "~/components";
import { TopBarHelmet } from "~/modules/TopBarHelmet/TopBarHelmet";
import { LoadingBar, LoadingDots } from "~/components";
import { SidePanel } from "~/modules/SidePanel";
import { Controls3D } from "./comps/Controls3D";
@@ -13,24 +11,22 @@ import { PreviewEngineCamera } from "./comps/PreviewEngineCamera";
import { ViewSideBySide } from "./comps/ViewSideBySide";
import { Timeline } from "./comps/Timeline";
import { APPUI_VIEW_MODES } from "./reducers";
import { APPUI_VIEW_MODES } from "../../reducers";
import {
timelineHeight,
sidePanelWidth,
pageWidth,
sidePanelVisible,
pageHeight,
dndSidePanelWidth,
dndTimelineHeight,
} from "~/pages/PageEnigma/store";
import { useSignals } from "@preact/signals-react/runtime";
import { AppUiContext } from "~/pages/PageEnigma/contexts/AppUiContext";
import { EngineContext } from "./contexts/EngineContext";
import { AppUiContext } from "~/contexts/AppUiContext";
import { pageHeight, pageWidth } from "~/store";
import { TopBar } from "~/modules/TopBar";
export const PageEnigmaComponent = () => {
useSignals();
const editorEngine = useContext(EngineContext);
const [appUiState] = useContext(AppUiContext);
//To prevent the click event from propagating to the canvas: TODO: HANDLE THIS BETTER?
@@ -38,14 +34,6 @@ export const PageEnigmaComponent = () => {
event.stopPropagation();
};
const handleGenerateMovieClick = () => {
if (editorEngine != null) {
editorEngine?.generateVideo();
} else {
console.log("Tried to generate movie but editor was null");
}
};
const dndWidth =
dndSidePanelWidth.value > -1
? dndSidePanelWidth.value
@@ -60,11 +48,7 @@ export const PageEnigmaComponent = () => {
return (
<div className="w-screen">
<TopBarHelmet>
<Button icon={faSparkles} onClick={handleGenerateMovieClick}>
Generate Movie
</Button>
</TopBarHelmet>
<TopBar pageName="Edit Scene" />
<div
className="relative flex w-screen"
style={{ height: "calc(100vh - 68px)" }}
@@ -7,12 +7,12 @@ import {
} from "@fortawesome/pro-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { AppUiContext } from "../../contexts/AppUiContext";
import { EngineContext } from "../../contexts/EngineContext";
import { AppUiContext } from "../../../../contexts/AppUiContext";
import { EngineContext } from "../../../../contexts/EngineContext";
import { Button, H5, InputVector } from "~/components";
import { XYZ } from "../../datastructures/common";
import { ACTION_TYPES } from "../../reducers/appUiReducer/types";
import { ACTION_TYPES } from "~/reducers/appUiReducer/types";
import { QueueNames } from "../../Queue/QueueNames";
import Queue from "~/pages/PageEnigma/Queue/Queue";
@@ -1,4 +1,5 @@
import {
faAngleRight,
faArrowsRotate,
faArrowsUpDownLeftRight,
faCube,
@@ -10,9 +11,10 @@ import {
fa3dTorus,
fa3dSphere,
} from "@awesome.me/kit-fde2be5eb0/icons/kit/custom";
import { ButtonIcon, ButtonIconSelect } from "~/components";
import { EngineContext } from "../../contexts/EngineContext";
import { Button, ButtonIcon, ButtonIconSelect, Link } from "~/components";
import { EngineContext } from "../../../../contexts/EngineContext";
import { useContext } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
export const Controls3D = () => {
const editorEngine = useContext(EngineContext);
@@ -66,14 +68,18 @@ export const Controls3D = () => {
<div className="flex justify-center">
<div className="rounded-b-lg border-x border-b border-ui-panel-border bg-ui-controls p-2 text-white">
<div className="flex items-center justify-center gap-2">
<ButtonIcon icon={faPlus} onClick={handlePlus} fill={true} />
<span className="h-4 w-0 border-l border-white/[0.15]" />
<ButtonIconSelect
options={modes}
onOptionChange={handleModeChange}
/>
<span className="h-4 w-0 border-l border-white/[0.15]" />
<Link to="/stylization">
<Button variant="primary">
Stylize <FontAwesomeIcon icon={faAngleRight} />
</Button>
</Link>
</div>
</div>
</div>
@@ -1,9 +1,9 @@
import { useContext, useState } from "react";
import { Button, Input } from "~/components";
import { ButtonDialogue } from "~/modules/ButtonDialogue";
import { EngineContext } from "../../contexts/EngineContext";
import { ToasterContext } from "~/pages/PageEnigma/contexts/ToasterContext";
import { APPUI_ACTION_TYPES } from "~/pages/PageEnigma/reducers";
import { EngineContext } from "../../../../contexts/EngineContext";
import { ToasterContext } from "~/contexts/ToasterContext";
import { APPUI_ACTION_TYPES } from "app/reducers";
export const ControlsTopButtons = () => {
const editorEngine = useContext(EngineContext);
@@ -17,7 +17,7 @@ export const ControlsTopButtons = () => {
const handleButtonSave = async () => {
console.log(`SceneName is ${sceneName}`);
const sceneMediaToken = await editorEngine?.saveScene(sceneName);
if(sceneMediaToken){
if (sceneMediaToken) {
addToast("success", sceneMediaToken);
}
};
@@ -129,9 +129,7 @@ export const ControlsTopButtons = () => {
</ButtonDialogue>
</div>
<div className="flex gap-2">
</div>
<div className="flex gap-2"></div>
<div className="flex gap-2">
{/* <Button onClick={handleButtonSingleFrame}>Render Single Frame</Button>
<Button onClick={handleButtonTakeFrame}>Take Frame</Button> */}
@@ -7,7 +7,7 @@ import {
faPlay,
} from "@fortawesome/pro-solid-svg-icons";
import { ButtonIcon } from "~/components";
import { EngineContext } from "../../contexts/EngineContext";
import { EngineContext } from "../../../../contexts/EngineContext";
export const ControlsVideo = () => {
const editorEngine = useContext(EngineContext);
@@ -1,7 +1,6 @@
import { useContext, useEffect, useState } from "react";
import { EngineContext } from "../../contexts/EngineContext";
import { Button, Input } from "~/components";
import { LoadingDotsTyping } from "~/components";
import { EngineContext } from "../../../../contexts/EngineContext";
import { Button, Input, LoadingDotsTyping } from "~/components";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCameraViewfinder } from "@fortawesome/pro-solid-svg-icons";
@@ -2,11 +2,10 @@ import { useContext, useState } from "react";
import { Button, ItemPicker, Label, Textarea } from "~/components";
import { AppUiContext } from "../../contexts/AppUiContext";
import { APPUI_ACTION_TYPES, APPUI_VIEW_MODES } from "../../reducers";
import { EngineContext } from "../../contexts/EngineContext";
import { AppUiContext } from "~/contexts/AppUiContext";
import { APPUI_ACTION_TYPES, APPUI_VIEW_MODES } from "~/reducers";
import { EngineContext } from "~/contexts/EngineContext";
import { ArtStyle } from "../../js/api_manager";
import { ignoreDelete } from "~/pages/PageEnigma/store";
export const TabStylization = () => {
const [appUiState, dispatchAppUiState] = useContext(AppUiContext);
@@ -3,7 +3,7 @@ import { filmLength, scale, selectedItem } from "~/pages/PageEnigma/store";
import { useMouseEventsKeyframe } from "~/pages/PageEnigma/comps/Timeline/utils/useMouseEventsKeyframe";
import { useSignals } from "@preact/signals-react/runtime";
import { useContext } from "react";
import { ToasterContext } from "~/pages/PageEnigma/contexts/ToasterContext";
import { ToasterContext } from "~/contexts/ToasterContext";
interface Props {
keyframe: Keyframe;
@@ -31,8 +31,6 @@ export const useMouseEventsScrubber = () => {
}
};
console.log("scroll", currentScroll.value);
const onMouseMove = (event: MouseEvent) => {
const delta = Math.round(
(event.clientX - clientX) / 4 / scale.value + currentTime.value,
@@ -1,9 +1,6 @@
import React, { useCallback, useEffect, useState } from "react";
import {
dndTimelineHeight,
pageHeight,
timelineHeight,
} from "~/pages/PageEnigma/store";
import { dndTimelineHeight, timelineHeight } from "~/pages/PageEnigma/store";
import { pageHeight } from "~/store";
export const useMouseEventsTimeline = () => {
const [isActive, setIsActive] = useState(false);
@@ -1,42 +1,45 @@
import { useEffect, useState, useContext } from "react";
import { LoadingDotsBricks } from "~/components";
import { EngineContext } from "../../contexts/EngineContext";
import { EngineContext } from "../../../../contexts/EngineContext";
export const ViewSideBySide = ()=>{
export const ViewSideBySide = () => {
const [showLoader, setShowLoader] = useState(true);
const editorEngine = useContext(EngineContext);
useEffect(()=>{
useEffect(() => {
editorEngine?.generateFrame();
setTimeout(()=>setShowLoader(false), 200);
},[ ]);
setTimeout(() => setShowLoader(false), 200);
}, []);
return (
<div
id="view-side-by-side"
className="absolute top-0 left-0 w-full h-full flex justify-center items-center gap-2 p-2"
className="absolute left-0 top-0 flex h-full w-full items-center justify-center gap-2 p-2"
>
<div className="flex flex-col justify-center items-center">
<div className="flex flex-col items-center justify-center">
<div className="text-white">
<label>Raw Preview</label>
</div>
<div className="relative">
<img className="aspect-video max-h-150 border" id="raw-preview"></img>
<img className="max-h-150 aspect-video border" id="raw-preview"></img>
</div>
</div>
<div className="flex flex-col justify-center items-center">
<div className="flex flex-col items-center justify-center">
<div className="text-white">
<label>Stylized Preview</label>
</div>
<div className="relative">
<img className="aspect-video max-h-150 border" id="stylized-preview"></img>
<img
className="max-h-150 aspect-video border"
id="stylized-preview"
></img>
</div>
</div>
<div className="absolute top-0 left-0 w-full h-full">
<LoadingDotsBricks isShowing={showLoader}/>
<div className="absolute left-0 top-0 h-full w-full">
<LoadingDotsBricks isShowing={showLoader} />
</div>
</div>
)
}
);
};
@@ -1,47 +0,0 @@
import { ReactNode, useContext, useEffect, useState } from "react";
import Editor from "~/pages/PageEnigma/js/editor";
import { EngineContext } from "./EngineContext";
import { AppUiContext } from "./AppUiContext";
interface Props {
children: ReactNode;
}
export const EngineProvider = ({ children }: Props) => {
const [editor, setEditor] = useState<Editor | null>(null);
const [appUiState, dispatchAppUiState] = useContext(AppUiContext);
// To talk to react land.
useEffect(() => {
//componentDidMount
if (document.getElementById("video-scene") === null) {
console.error(
'Editor Engine need a target canvas with the id "video-scene"',
);
} else {
setEditor((curr) => {
if (curr !== null) {
console.warn("Editor Engine already exist");
return curr;
} else {
return new Editor();
}
});
}
}, []);
useEffect(() => {
if (editor && editor.can_initialize && dispatchAppUiState !== null) {
console.log("initializing Editor");
editor.initialize({
dispatchAppUiState,
});
}
}, [editor, dispatchAppUiState]);
return (
<EngineContext.Provider value={editor}>{children}</EngineContext.Provider>
);
};
@@ -13,7 +13,7 @@ import {
deleteCharacterKeyframe,
deleteObjectKeyframe,
} from "~/pages/PageEnigma/store";
import { ToasterContext } from "~/pages/PageEnigma/contexts/ToasterContext";
import { ToasterContext } from "~/contexts/ToasterContext";
const ADD_KEYFRAME: Record<
ClipGroup,
+1 -1
View File
@@ -21,7 +21,7 @@ import { LipSyncEngine } from "./lip_sync_engine.js";
import { AnimationEngine } from "./animation_engine.js";
import { PointerLockControls } from "three/addons/controls/PointerLockControls.js";
import { APPUI_ACTION_TYPES } from "../reducers";
import { APPUI_ACTION_TYPES } from "../../../reducers";
import { ClipGroup } from "~/pages/PageEnigma/models/track";
import { XYZ } from "../datastructures/common";
+2 -1
View File
@@ -1,6 +1,7 @@
import { computed, signal } from "@preact/signals-core";
import { AssetFilterOption, Tab } from "~/pages/PageEnigma/models";
import { pageHeight, timelineHeight } from "~/pages/PageEnigma/store/sizing";
import { timelineHeight } from "~/pages/PageEnigma/store/sizing";
import { pageHeight } from "~/store";
export const sidePanelVisible = signal(true);
-3
View File
@@ -2,9 +2,6 @@ import { signal, computed } from "@preact/signals-core";
import { characterGroups } from "~/pages/PageEnigma/store/characterGroups";
import { objectGroup } from "~/pages/PageEnigma/store/objectGroup";
export const pageHeight = signal(0);
export const pageWidth = signal(0);
// timeline
export const scale = signal(1);
export const filmLength = signal(12);
@@ -0,0 +1,23 @@
import { useSignals } from "@preact/signals-react/runtime";
import { PageStylizationComponent } from "~/pages/PageStylization/PageStylizationComponent";
import { useContext, useEffect } from "react";
import { AppUiContext } from "~/contexts/AppUiContext";
import { EngineContext } from "~/contexts/EngineContext";
export const PageStylization = () => {
useSignals();
const [, dispatchAppUiState] = useContext(AppUiContext);
const editor = useContext(EngineContext);
useEffect(() => {
if (editor && editor.can_initialize && dispatchAppUiState !== null) {
console.log("initializing Editor");
editor.initialize({
dispatchAppUiState,
});
}
}, [editor, dispatchAppUiState]);
return <PageStylizationComponent />;
};
@@ -0,0 +1,50 @@
import { useSignals } from "@preact/signals-react/runtime";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faAngleLeft } from "@fortawesome/pro-solid-svg-icons";
import { Button, Link } from "~/components";
import { StyleSelection } from "~/pages/PageStylization/comps/StyleSelection";
import { LowerPanel } from "~/modules/LowerPanel";
import { TimerGrid } from "~/pages/PageEnigma/comps/TimerGrid/TimerGrid";
import { Scrubber } from "~/pages/PageEnigma/comps/Timeline/Scrubber";
import { PreviewImages } from "~/pages/PageStylization/comps/PreviewImages";
import { TopBar } from "~/modules/TopBar";
export const PageStylizationComponent = () => {
useSignals();
return (
<div className="w-screen">
<TopBar pageName="Stylization" />
<div className="flex w-full justify-center">
<div className="bg-ui-controls p-2">
<Link to="/idealenigma">
<Button variant="action">
<FontAwesomeIcon icon={faAngleLeft} />
Back to Scene
</Button>
</Link>
</div>
</div>
<div className="mt-4 flex flex-col items-center gap-4">
<PreviewImages />
<StyleSelection />
</div>
<div className="fixed bottom-0 left-0 w-full">
<div className="flex h-[62px] w-full items-center justify-center gap-5 bg-ui-panel">
<div>
<Button variant="action">Update Preview</Button>
</div>
<div>
<Button variant="primary">Generate Movie</Button>
</div>
</div>
<div className="relative flex h-[80px] w-full gap-5 border-t border-t-action-600 bg-ui-panel">
<LowerPanel onStyle>
<TimerGrid />
<Scrubber />
</LowerPanel>
</div>
</div>
</div>
);
};
@@ -0,0 +1,44 @@
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faArrowRight } from "@fortawesome/pro-solid-svg-icons";
import { useSignals } from "@preact/signals-react/runtime";
import { pageHeight, pageWidth } from "~/store";
export const PreviewImages = () => {
useSignals();
const imageWidth1 = pageWidth.value > 1340 ? 630 : (pageWidth.value - 80) / 2;
const imageHeight1 = imageWidth1 * 0.56;
const imageHeight2 = pageHeight.value > 1138 ? 354 : pageHeight.value - 620;
const imageWidth2 = imageHeight2 / 0.56;
const imageWidth = imageHeight1 < imageHeight2 ? imageWidth1 : imageWidth2;
const imageHeight = imageHeight1 < imageHeight2 ? imageHeight1 : imageHeight2;
const textClasses = [
"flex items-center justify-center",
"w-full rounded-t-lg bg-ui-controls h-[34px]",
"text-sm font-semibold",
].join(" ");
return (
<div className="flex justify-center gap-2">
<div className="flex flex-col" style={{ width: imageWidth }}>
<div className={textClasses}>Raw Preview</div>
<div
className="block w-full rounded-b-lg bg-gray-300"
style={{ height: imageHeight }}
/>
</div>
<div className="flex w-[40px] flex-col justify-center">
<FontAwesomeIcon icon={faArrowRight} className="text-3xl opacity-60" />
</div>
<div className="flex flex-col" style={{ width: imageWidth }}>
<div className={textClasses}>Styled Preview</div>
<div
className="block w-full rounded-b-lg bg-gray-300"
style={{ height: imageHeight }}
/>
</div>
</div>
);
};
@@ -0,0 +1,123 @@
import { useContext, useState } from "react";
import { ButtonIcon, ItemPicker, Label, Textarea } from "~/components";
import { EngineContext } from "~/contexts/EngineContext";
import { ArtStyle } from "~/pages/PageEnigma/js/api_manager";
import { faAngleLeft, faAngleRight } from "@fortawesome/pro-solid-svg-icons";
import { styleList } from "~/pages/PageStylization/styleList";
export const StyleSelection = () => {
const [selection, setSelection] = useState<ArtStyle>(styleList[0].type);
const [scrollPosition, setScrollPosition] = useState(0);
const editorEngine = useContext(EngineContext);
const handlePickingStylizer = (picked: ArtStyle) => {
console.log(`Picked style: ${picked}`);
setSelection(picked);
if (editorEngine === null) {
console.log("Editor is null");
return;
}
editorEngine.art_style = picked;
};
const onChangeHandlerNegative = (
e: React.ChangeEvent<HTMLTextAreaElement>,
) => {
if (editorEngine == null) {
console.log("Editor is null");
return;
}
editorEngine.negative_prompt = e.target.value;
console.log(e.target.value);
};
const onChangeHandlerPositive = (
e: React.ChangeEvent<HTMLTextAreaElement>,
) => {
if (editorEngine == null) {
console.log("Editor is null");
return;
}
editorEngine.positive_prompt = e.target.value;
console.log(e.target.value);
};
return (
<div className="flex h-[280px] w-[800px] flex-col gap-3 rounded-lg bg-ui-panel p-4">
<div className="flex w-full flex-col">
<Label>Select Base Style</Label>
<div
className="relative overflow-x-hidden"
style={{ width: 768, height: 80 }}
>
<div
className="absolute flex gap-2"
style={{
width: styleList.length * 84 + 26,
left: scrollPosition * -86,
top: 0,
}}
>
{styleList.map((style) => (
<ItemPicker
key={style.type}
label={style.label}
type={style.type}
selected={selection === style.type}
onSelected={handlePickingStylizer}
src={style.image}
width={80}
height={80}
/>
))}
</div>
{scrollPosition > 0 && (
<div className="absolute left-3 top-5">
<ButtonIcon
icon={faAngleLeft}
onClick={() =>
setScrollPosition(Math.max(scrollPosition - 6, 0))
}
/>
</div>
)}
{scrollPosition < styleList.length - 9 && (
<div className="absolute right-3 top-5">
<ButtonIcon
icon={faAngleRight}
onClick={() =>
setScrollPosition(
Math.min(scrollPosition + 6, styleList.length - 9),
)
}
fill
/>
</div>
)}
</div>
</div>
<div className="flex w-full gap-4">
<Textarea
label="Positive Prompt"
className="h-24 w-[376px]"
name="positive-prompt"
placeholder="Type here to describe your scene"
onChange={onChangeHandlerPositive}
resize="none"
/>
<Textarea
label="Negative Prompt"
className="h-24 w-[376px]"
name="negative-prompt"
placeholder="Type here to filter out the things you don't want in the scene"
onChange={onChangeHandlerNegative}
resize="none"
/>
</div>
</div>
);
};
+1
View File
@@ -0,0 +1 @@
export * from "./PageStylization";
+84
View File
@@ -0,0 +1,84 @@
import { ArtStyle } from "~/pages/PageEnigma/js/api_manager";
export const styleList = [
{
label: "1",
type: ArtStyle.Anime2_5D,
image: "/resources/avatars/0.webp",
},
{
label: "2",
type: ArtStyle.Anime2DFlat,
image: "/resources/avatars/1.webp",
},
{
label: "3",
type: ArtStyle.Cartoon3D,
image: "/resources/avatars/2.webp",
},
{
label: "4",
type: ArtStyle.ComicBook,
image: "/resources/avatars/3.webp",
},
{
label: "5",
type: ArtStyle.AnimeGhibli,
image: "/resources/avatars/4.webp",
},
{
label: "6",
type: ArtStyle.InkPunk,
image: "/resources/avatars/5.webp",
},
{
label: "7",
type: ArtStyle.InkSplash,
image: "/resources/avatars/6.webp",
},
{
label: "8",
type: ArtStyle.InkBWStyle,
image: "/resources/avatars/7.webp",
},
{
label: "9",
type: ArtStyle.JojoStyle,
image: "/resources/avatars/8.webp",
},
{
label: "10",
type: ArtStyle.PaperOrigami,
image: "/resources/avatars/9.webp",
},
{
label: "11",
type: ArtStyle.PixelArt,
image: "/resources/avatars/10.webp",
},
{
label: "12",
type: ArtStyle.PopArt,
image: "/resources/avatars/11.webp",
},
{
label: "13",
type: ArtStyle.Realistic1,
image: "/resources/avatars/12.webp",
},
{
label: "14",
type: ArtStyle.Realistic2,
image: "/resources/avatars/13.webp",
},
{
label: "15",
type: ArtStyle.AnimeRetroNeon,
image: "/resources/avatars/14.webp",
},
{
label: "16",
type: ArtStyle.AnimeStandard,
image: "/resources/avatars/15.webp",
},
];
@@ -1,5 +1,5 @@
import { Simple3DVector } from "../../datastructures/common";
import { AssetType, ClipGroup } from "../../models";
import { Simple3DVector } from "../../pages/PageEnigma/datastructures/common";
import { AssetType, ClipGroup } from "../../pages/PageEnigma/models";
export enum VIEW_MODES {
EDITOR = "editor",
SIDE_BY_SIDE = "side-by-side",
File renamed without changes.
+33 -13
View File
@@ -18,13 +18,18 @@ import { LoadingDotsBricks } from "~/components";
import { TopBar } from "./modules/TopBar";
import { TopBarInnerContext } from "~/contexts/TopBarInner";
import { AuthenticationProvider } from "./contexts/Authentication";
import { ToasterProvider } from "~/pages/PageEnigma/contexts/ToasterContext";
import { ToasterProvider } from "~/contexts/ToasterContext";
// The following import prevents a Font Awesome icon server-side rendering bug,
// where the icons flash from a very large icon down to a properly sized one:
import '@fortawesome/fontawesome-svg-core/styles.css';
import "@fortawesome/fontawesome-svg-core/styles.css";
// Prevent fontawesome from adding its CSS since we did it manually above:
import { config } from '@fortawesome/fontawesome-svg-core';
import { config } from "@fortawesome/fontawesome-svg-core";
import { useSignals } from "@preact/signals-react/runtime";
import { pageHeight, pageWidth } from "~/store";
import { sidePanelWidth, timelineHeight } from "~/pages/PageEnigma/store";
import { EngineProvider } from "~/contexts/EngineProvider";
import { AppUIProvider } from "~/contexts/AppUiContext";
config.autoAddCss = false; /* eslint-disable import/first */
export const links: LinksFunction = () => [
@@ -65,6 +70,25 @@ export default function App() {
setTimeout(() => setShowLoader(false), 2500);
}, []);
useSignals();
useEffect(() => {
function setPage() {
// TODO address this issue with zooming
pageHeight.value = window.innerHeight;
pageWidth.value = window.innerWidth;
}
timelineHeight.value = window.innerHeight * 0.25;
sidePanelWidth.value = 443;
setPage();
window.addEventListener("resize", setPage);
return () => {
window.removeEventListener("resize", setPage);
};
}, []);
return (
<html lang="en">
<head>
@@ -78,16 +102,12 @@ export default function App() {
<CookiesProvider defaultSetOptions={{ path: "/" }}>
<AuthenticationProvider>
<ToasterProvider>
<TopBarInnerContext.Provider
value={{
TopBarInner: topBarInnerComponent,
setTopBarInner: setTopBarInnerComponent,
}}
>
<div className="topbar-spacer" />
<Outlet />
<TopBar />
</TopBarInnerContext.Provider>
<AppUIProvider>
<EngineProvider>
<div className="topbar-spacer" />
<Outlet />
</EngineProvider>
</AppUIProvider>
</ToasterProvider>
</AuthenticationProvider>
</CookiesProvider>
+11
View File
@@ -0,0 +1,11 @@
import type { HeadersFunction } from "@remix-run/deno";
import { withProtectionRoute } from "~/modules/withProtectedRoute";
import { PageStylization } from "~/pages/PageStylization";
export const headers: HeadersFunction = () => ({
"Cross-Origin-Embedder-Policy": "require-corp",
"Cross-Origin-Opener-Policy": "same-origin",
});
const Stylization = withProtectionRoute(() => <PageStylization />);
export default Stylization;
+7 -4
View File
@@ -1,8 +1,11 @@
import type { MetaFunction } from "@remix-run/deno";
import { TopBarHelmet } from "~/modules/TopBarHelmet";
import sonic from "./_assets/sonic-the-hedgehog-classic-sonic.gif";
import { useSignals } from "@preact/signals-react/runtime";
import { useEffect } from "react";
import { pageHeight, pageWidth } from "~/store";
import { sidePanelWidth, timelineHeight } from "~/pages/PageEnigma/store";
export const meta: MetaFunction = () => {
return [
@@ -20,10 +23,10 @@ export default function Index() {
src={sonic}
className="
fixed
h-screen w-screen
top-0 left-0
left-0 top-0
-z-10 h-screen
w-screen
object-cover
-z-10
"
/>
</div>
+6
View File
@@ -0,0 +1,6 @@
import { signal } from "@preact/signals-core";
export const sceneTitle = signal("Home Office");
export const pageHeight = signal(0);
export const pageWidth = signal(0);
+1
View File
@@ -0,0 +1 @@
export * from "./global";