diff --git a/packages/fakeyou.com/public/videos/face-animator-instruction-en.mp4 b/packages/fakeyou.com/public/videos/face-animator-instruction-en.mp4
new file mode 100644
index 0000000000..9b839fe748
Binary files /dev/null and b/packages/fakeyou.com/public/videos/face-animator-instruction-en.mp4 differ
diff --git a/packages/fakeyou.com/src/components/common/BasicVideo/BasicVideo.scss b/packages/fakeyou.com/src/components/common/BasicVideo/BasicVideo.scss
new file mode 100644
index 0000000000..52baadeff5
--- /dev/null
+++ b/packages/fakeyou.com/src/components/common/BasicVideo/BasicVideo.scss
@@ -0,0 +1,48 @@
+@import "scss/colours.scss";
+
+.fy-basic-video {
+ overflow: hidden;
+ width: 100%;
+ margin: 0;
+ height: fit-content;
+ position: relative;
+
+ video, .video-overlay {
+ border-radius: .5rem;
+ width: 100%;
+ height: 100%;
+ }
+
+ video {object-fit: cover; }
+
+ .video-overlay {
+ background: linear-gradient(rgba($primary,0.5) 0%, rgba($secondary,0.75) 75%);
+ cursor: pointer;
+ padding: 2rem;
+ position: absolute;
+ top: 0px;
+
+ h6 {
+ color: #fff;
+ filter: drop-shadow(0 3px 3px rgba($primary-dark,.25));
+ font-size: 1.5rem;
+ text-align: center;
+ }
+
+ svg {
+ filter: drop-shadow(0 3px 7px rgba($primary-dark,.45));
+ position: absolute;
+ width: 3rem;
+ height: 3rem;
+ inset: 50%;
+ transform: translate(-50%, -50%);
+ }
+
+ .video-play-button {
+ background-color: green;
+ width: 4rem;
+ height: 4rem;
+ stroke: white;
+ }
+ }
+};
\ No newline at end of file
diff --git a/packages/fakeyou.com/src/components/common/BasicVideo/BasicVideo.tsx b/packages/fakeyou.com/src/components/common/BasicVideo/BasicVideo.tsx
new file mode 100644
index 0000000000..31bebbc534
--- /dev/null
+++ b/packages/fakeyou.com/src/components/common/BasicVideo/BasicVideo.tsx
@@ -0,0 +1,35 @@
+import React, { useState } from "react";
+import { a, useSpring } from "@react-spring/web";
+import { useVideo } from "hooks";
+import makeClass from "resources/makeClass";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faPlay } from "@fortawesome/free-solid-svg-icons";
+import "./BasicVideo.scss"
+
+interface Props {
+ className?: string;
+ src?: string;
+}
+
+export default function BasicVideo({ className, src }: Props) {
+ const [tint,tintSet] = useState(true);
+ const [{ playCtrl },vidProps] = useVideo({ onEnded: () => tintSet(true) });
+ const style = useSpring({
+ onRest: () => { if (!tint) { playCtrl!(tintSet) }},
+ opacity: tint ? 1 : 0
+ });
+ const onClick = () => {
+ tintSet(!tint)
+ if (!tint) playCtrl!();
+ };
+
+ return
+
+
+ Face Animator Sample
+
+
+
;
+};
\ No newline at end of file
diff --git a/packages/fakeyou.com/src/components/common/BasicVideo/index.ts b/packages/fakeyou.com/src/components/common/BasicVideo/index.ts
new file mode 100644
index 0000000000..006a41e25a
--- /dev/null
+++ b/packages/fakeyou.com/src/components/common/BasicVideo/index.ts
@@ -0,0 +1 @@
+export { default } from './BasicVideo';
\ No newline at end of file
diff --git a/packages/fakeyou.com/src/components/common/ImageInput/ImageInput.scss b/packages/fakeyou.com/src/components/common/ImageInput/ImageInput.scss
index e9804a0ae8..c6a2169d5d 100644
--- a/packages/fakeyou.com/src/components/common/ImageInput/ImageInput.scss
+++ b/packages/fakeyou.com/src/components/common/ImageInput/ImageInput.scss
@@ -4,9 +4,9 @@
.image-upload-frame {
// aspect-ratio: 4/3;
- // @include breakpoint(min-width 992px) {
- // aspect-ratio: 1/1;
- // }
+ @include breakpoint(min-width 992px) {
+ aspect-ratio: 1/1;
+ }
}
.fy-image-uploader {
diff --git a/packages/fakeyou.com/src/components/common/index.tsx b/packages/fakeyou.com/src/components/common/index.tsx
index 63363e3f37..0401d60177 100644
--- a/packages/fakeyou.com/src/components/common/index.tsx
+++ b/packages/fakeyou.com/src/components/common/index.tsx
@@ -1,29 +1,31 @@
-import AudioInput from './AudioInput';
-import Check from './Check';
-import Checkbox from './Checkbox';
-import FileActions from './FileActions';
-import FileDetails from './FileDetails';
-import FileWrapper from './FileWrapper';
-import FileLabel from './FileLabel';
-import ImageInput from './ImageInput';
-import NumberSlider from './NumberSlider';
-import Radio from './Radio';
-import SegmentButtons from './SegmentButtons';
-import Slider from './Slider';
-import Spinner from './Spinner';
+import AudioInput from "./AudioInput";
+import BasicVideo from "./BasicVideo";
+import Check from "./Check";
+import Checkbox from "./Checkbox";
+import FileActions from "./FileActions";
+import FileDetails from "./FileDetails";
+import FileWrapper from "./FileWrapper";
+import FileLabel from "./FileLabel";
+import ImageInput from "./ImageInput";
+import NumberSlider from "./NumberSlider";
+import Radio from "./Radio";
+import SegmentButtons from "./SegmentButtons";
+import Slider from "./Slider";
+import Spinner from "./Spinner";
export {
- AudioInput,
- Check,
- Checkbox,
- FileActions,
- FileDetails,
- FileWrapper,
- FileLabel,
- ImageInput,
- NumberSlider,
- Radio,
- SegmentButtons,
- Slider,
- Spinner
+ AudioInput,
+ BasicVideo,
+ Check,
+ Checkbox,
+ FileActions,
+ FileDetails,
+ FileWrapper,
+ FileLabel,
+ ImageInput,
+ NumberSlider,
+ Radio,
+ SegmentButtons,
+ Slider,
+ Spinner
};
\ No newline at end of file
diff --git a/packages/fakeyou.com/src/hooks/index.tsx b/packages/fakeyou.com/src/hooks/index.tsx
index 142e5b804d..180f81aab4 100644
--- a/packages/fakeyou.com/src/hooks/index.tsx
+++ b/packages/fakeyou.com/src/hooks/index.tsx
@@ -3,5 +3,6 @@ import useHover from './useHover';
import useId from './useId';
import useIdempotency from './useIdempotency';
import useLocalize from './useLocalize';
+import useVideo from './useVideo';
-export { useFile, useHover, useId, useIdempotency, useLocalize };
+export { useFile, useHover, useId, useIdempotency, useLocalize, useVideo };
diff --git a/packages/fakeyou.com/src/hooks/useVideo/index.ts b/packages/fakeyou.com/src/hooks/useVideo/index.ts
new file mode 100644
index 0000000000..9eb5a944ae
--- /dev/null
+++ b/packages/fakeyou.com/src/hooks/useVideo/index.ts
@@ -0,0 +1 @@
+export { default } from './useVideo';
\ No newline at end of file
diff --git a/packages/fakeyou.com/src/hooks/useVideo/useVideo.tsx b/packages/fakeyou.com/src/hooks/useVideo/useVideo.tsx
new file mode 100644
index 0000000000..a89c7a7746
--- /dev/null
+++ b/packages/fakeyou.com/src/hooks/useVideo/useVideo.tsx
@@ -0,0 +1,23 @@
+import { useRef } from 'react';
+
+interface Props {
+ onEnded?: any;
+}
+
+export default function useVideo({ onEnded }: Props) {
+ const ref = useRef(null);
+ const playCtrl = (toDo = (b:any) => {}) => {
+ if (ref.current) {
+ let isPlaying = !!(ref.current.currentTime > 0 && !ref.current.paused && !ref.current.ended && ref.current.readyState > 2);
+ if (!isPlaying) {
+ toDo(false);
+ ref.current.play();
+ } else {
+ toDo(true);
+ ref.current.pause();
+ }
+ }
+ };
+
+ return [{ playCtrl },{ onEnded, ref }];
+};
\ No newline at end of file
diff --git a/packages/fakeyou.com/src/v2/view/pages/lipsync/LipsyncEditor/FaceAnimatorInput.tsx b/packages/fakeyou.com/src/v2/view/pages/lipsync/LipsyncEditor/FaceAnimatorInput.tsx
new file mode 100644
index 0000000000..1e58d19a1f
--- /dev/null
+++ b/packages/fakeyou.com/src/v2/view/pages/lipsync/LipsyncEditor/FaceAnimatorInput.tsx
@@ -0,0 +1,63 @@
+import React from "react";
+import { animated } from "@react-spring/web";
+import { AudioInput, BasicVideo, Checkbox, ImageInput, SegmentButtons } from "components/common";
+import { FaceAnimatorSlide } from "./FaceAnimatorTypes";
+
+export default function FaceAnimatorInput({
+ audioProps,
+ imageProps,
+ frameDimensions,
+ frameDimensionsChange,
+ disableFaceEnhancement,
+ disableFaceEnhancementChange,
+ still,
+ stillChange,
+ toggle,
+ style,
+ t,
+ removeWatermark,
+ removeWatermarkChange, }: FaceAnimatorSlide) {
+ return
+
+
{t("headings.image")}
+ toggle.image(imageProps.file ? true : false),
+ }}
+ />
+
+
+
{t("headings.audio")}
+
{
+ toggle.audio(!!audioProps.file);
+ },
+ hideActions: true,
+ }}
+ />
+
+
+
+
+
+
+
+ ;
+};
\ No newline at end of file
diff --git a/packages/fakeyou.com/src/v2/view/pages/lipsync/LipsyncEditor/FaceAnimatorSuccess.tsx b/packages/fakeyou.com/src/v2/view/pages/lipsync/LipsyncEditor/FaceAnimatorSuccess.tsx
index d76fce1c44..5d57ca41f5 100644
--- a/packages/fakeyou.com/src/v2/view/pages/lipsync/LipsyncEditor/FaceAnimatorSuccess.tsx
+++ b/packages/fakeyou.com/src/v2/view/pages/lipsync/LipsyncEditor/FaceAnimatorSuccess.tsx
@@ -11,20 +11,11 @@ import { JobState } from "@storyteller/components/src/jobs/JobStates";
import { Analytics } from "common/Analytics";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faDownload } from "@fortawesome/free-solid-svg-icons";
-
-interface Props {
- audioProps: any;
- imageProps: any;
- style: any;
- enqueueInferenceJob: any;
- sessionSubscriptionsWrapper: any;
- inferenceJobsByCategory: any;
- t: any;
-}
+import { FaceAnimatorSlide } from "./FaceAnimatorTypes";
const DEFAULT_QUEUE_REFRESH_INTERVAL_MILLIS = 15000;
-export default function FaceAnimatorSuccess({ audioProps, imageProps, style, enqueueInferenceJob, sessionSubscriptionsWrapper, inferenceJobsByCategory, t }: Props) {
+export default function FaceAnimatorSuccess({ audioProps, imageProps, style, enqueueInferenceJob, sessionSubscriptionsWrapper, inferenceJobsByCategory, t }: FaceAnimatorSlide) {
const [pending, pendingSet] = useState({
success: true,
pending_job_count: 0,
diff --git a/packages/fakeyou.com/src/v2/view/pages/lipsync/LipsyncEditor/FaceAnimatorTypes.ts b/packages/fakeyou.com/src/v2/view/pages/lipsync/LipsyncEditor/FaceAnimatorTypes.ts
new file mode 100644
index 0000000000..86db526447
--- /dev/null
+++ b/packages/fakeyou.com/src/v2/view/pages/lipsync/LipsyncEditor/FaceAnimatorTypes.ts
@@ -0,0 +1,33 @@
+import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper";
+import { FrontendInferenceJobType, InferenceJob } from "@storyteller/components/src/jobs/InferenceJob";
+
+export interface FaceAnimatorSlide {
+ audioProps: any;
+ children?: any;
+ imageProps: any;
+ frameDimensions: any;
+ frameDimensionsChange: any;
+ disableFaceEnhancement: any;
+ disableFaceEnhancementChange: any;
+ index: number;
+ still: any;
+ stillChange: any;
+ style: any;
+ toggle: any;
+ enqueueInferenceJob: any;
+ sessionSubscriptionsWrapper: any;
+ t: any;
+ inferenceJobsByCategory: any;
+ removeWatermark: any;
+ removeWatermarkChange: any;
+}
+
+export interface FaceAnimatorCore {
+ sessionSubscriptionsWrapper: SessionSubscriptionsWrapper;
+ enqueueInferenceJob: (
+ jobToken: string,
+ frontendInferenceJobType: FrontendInferenceJobType
+ ) => void;
+ inferenceJobs: Array;
+ inferenceJobsByCategory: Map>;
+}
\ No newline at end of file
diff --git a/packages/fakeyou.com/src/v2/view/pages/lipsync/LipsyncEditor/FaceAnimatorWorking.tsx b/packages/fakeyou.com/src/v2/view/pages/lipsync/LipsyncEditor/FaceAnimatorWorking.tsx
new file mode 100644
index 0000000000..fdfd242941
--- /dev/null
+++ b/packages/fakeyou.com/src/v2/view/pages/lipsync/LipsyncEditor/FaceAnimatorWorking.tsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import { a, useTransition } from "@react-spring/web";
+import { Spinner } from "components/common";
+import { springs } from "resources";
+import { FaceAnimatorSlide } from "./FaceAnimatorTypes";
+
+export default function FaceAnimatorWorking({ audioProps, imageProps, index, style, t }: FaceAnimatorSlide) {
+ const workStatus = [
+ "",
+ t("status.uploadingAudio"),
+ t("status.uploadingImage"),
+ t("status.requestingAnimation"),
+ "",
+ ];
+
+ const transitions = useTransition(index, {
+ ...springs.soft,
+ from: { opacity: 0, position: "absolute" },
+ enter: { opacity: 1, position: "relative" },
+ leave: { opacity: 0, position: "absolute" },
+ });
+ return
+
+
+ {" "}
+ {transitions(({ opacity, position }, i) => {
+ return (
+
+ {workStatus[index]} ...
+
+ );
+ })}
+
+
+
+ ;
+};
\ No newline at end of file
diff --git a/packages/fakeyou.com/src/v2/view/pages/lipsync/LipsyncEditor/LipsyncEditor.scss b/packages/fakeyou.com/src/v2/view/pages/lipsync/LipsyncEditor/LipsyncEditor.scss
index 0592b46ec6..f4b01ae774 100644
--- a/packages/fakeyou.com/src/v2/view/pages/lipsync/LipsyncEditor/LipsyncEditor.scss
+++ b/packages/fakeyou.com/src/v2/view/pages/lipsync/LipsyncEditor/LipsyncEditor.scss
@@ -1,5 +1,8 @@
@import "scss/_breakpoint.scss";
+@import "scss/colours.scss";
+
$under992: max-width 992px;
+$over992: min-width 992px;
.lipsync-editor {
padding-top: 2rem;
@@ -13,13 +16,18 @@ $under992: max-width 992px;
}
}
- .sub-title {
- display: block;
- margin-top: 1rem;
+ .audio-input-column {
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+
+ .fy-audio-uploder {
+ flex: 1 0 auto;
+ }
}
.animation-configure-panel {
- margin: 1rem 0 -.5rem;
+ margin: 1.5rem 0 -.5rem;
padding: 1rem;
display: flex;
flex-wrap: wrap;
@@ -123,3 +131,22 @@ $under992: max-width 992px;
font-size: 0.75rem;
}
}
+
+ .face-animator-mobile-sample {
+ padding: 1rem;
+
+ @include breakpoint($over992) {
+ display: none;
+ }
+ }
+
+ .face-animator-wide-sample {
+ flex: 1;
+ height: auto;
+
+ @include breakpoint($under992) {
+ display: none;
+ }
+
+ video { position: absolute ;}
+ }
diff --git a/packages/fakeyou.com/src/v2/view/pages/lipsync/LipsyncEditor/LipsyncEditor.tsx b/packages/fakeyou.com/src/v2/view/pages/lipsync/LipsyncEditor/LipsyncEditor.tsx
index 8bc50a6e9e..daf0ea63d9 100644
--- a/packages/fakeyou.com/src/v2/view/pages/lipsync/LipsyncEditor/LipsyncEditor.tsx
+++ b/packages/fakeyou.com/src/v2/view/pages/lipsync/LipsyncEditor/LipsyncEditor.tsx
@@ -1,8 +1,7 @@
import React, { useState } from "react";
-import { animated, useTransition } from "@react-spring/web";
+import { useTransition } from "@react-spring/web";
import { v4 as uuidv4 } from "uuid";
import { useFile, useLocalize } from "hooks";
-import { AudioInput, Checkbox, ImageInput, SegmentButtons, Spinner } from "components/common";
import { springs } from "resources";
import {
UploadAudio,
@@ -19,162 +18,21 @@ import {
// EnqueueFaceAnimationIsSuccess,
// EnqueueFaceAnimationRequest,
} from "@storyteller/components/src/api/face_animation/EnqueueFaceAnimation";
-// import { FrontendInferenceJobType } from "@storyteller/components/src/jobs/InferenceJob";
import FaceAnimatorTitle from "./FaceAnimatorTitle";
+import FaceAnimatorInput from './FaceAnimatorInput';
+import FaceAnimatorWorking from './FaceAnimatorWorking';
import FaceAnimatorSuccess from "./FaceAnimatorSuccess";
+import { FaceAnimatorCore } from "./FaceAnimatorTypes";
+import { BasicVideo } from "components/common";
import "./LipsyncEditor.scss";
-import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper";
-import {
- FrontendInferenceJobType,
- InferenceJob,
-} from "@storyteller/components/src/jobs/InferenceJob";
-
-interface LipSyncProps {
- // animationChange: any;
- // animationStyle: any;
- audioProps: any;
- children?: any;
- // cropChange: any;
- // cropping: any;
- imageProps: any;
- frameDimensions: any;
- frameDimensionsChange: any;
- disableFaceEnhancement: any;
- disableFaceEnhancementChange: any;
- index: number;
- still: any;
- stillChange: any;
- style: any;
- toggle: any;
- enqueueInferenceJob: any;
- sessionSubscriptionsWrapper: any;
- t: any;
- inferenceJobsByCategory: any;
- removeWatermark: any;
- removeWatermarkChange: any;
-}
-interface EditorProps {
- sessionSubscriptionsWrapper: SessionSubscriptionsWrapper;
- enqueueInferenceJob: (
- jobToken: string,
- frontendInferenceJobType: FrontendInferenceJobType
- ) => void;
- inferenceJobs: Array;
- inferenceJobsByCategory: Map>;
-}
-
-const softSpring = { config: { mass: 1, tension: 80, friction: 10 } };
-
-const InputPage = ({
- // animationChange,
- // animationStyle,
- audioProps,
- // cropping,
- // cropChange,
- imageProps,
- frameDimensions,
- frameDimensionsChange,
- disableFaceEnhancement,
- disableFaceEnhancementChange,
- still,
- stillChange,
- toggle,
- style,
- t,
- removeWatermark,
- removeWatermarkChange,
-}: LipSyncProps) => {
-
- return
-
-
{t("headings.image")}
- toggle.image(imageProps.file ? true : false),
- }}
- />
-
-
-
-
{t("headings.audio")}
-
{
- toggle.audio(!!audioProps.file);
- },
- hideActions: true,
- }}
- />
-
-
-
-
-
-
-
- ;
-};
-
-const Working = ({ audioProps, imageProps, index, style, t }: LipSyncProps) => {
- const workStatus = [
- "",
- t("status.uploadingAudio"),
- t("status.uploadingImage"),
- t("status.requestingAnimation"),
- "",
- ];
- const transitions = useTransition(index, {
- ...springs.soft,
- from: { opacity: 0, position: "absolute" },
- enter: { opacity: 1, position: "relative" },
- leave: { opacity: 0, position: "absolute" },
- });
- return (
-
-
-
- {" "}
- {transitions(({ opacity, position }, i) => {
- return (
-
- {workStatus[index]} ...
-
- );
- })}
-
-
-
-
- );
-};
+import { FrontendInferenceJobType } from "@storyteller/components/src/jobs/InferenceJob";
export default function LipsyncEditor({
enqueueInferenceJob,
sessionSubscriptionsWrapper,
inferenceJobsByCategory,
...rest
-}: EditorProps) {
+}: FaceAnimatorCore) {
const { t } = useLocalize("FaceAnimator");
// the ready states are set by functions which run after the upload input animation is completed, which then illuminates the respective checkmark in a staggered way to draw attention to the workflow, and reduces concurrent animations
@@ -234,10 +92,6 @@ export default function LipsyncEditor({
if ("upload_token" in responses.image) {
indexSet(3); // set face animator API working page
return EnqueueFaceAnimation({
- // backend_animation_key: animationStyle,
- // backend_cropping_key: cropping === "cropped",
- // backend_orientation_key: orientation === "landscape",
- // backend_watermark_key: watermark,
uuid_idempotency_token: uuidv4(),
audio_source: {
maybe_media_upload_token: responses.audio.upload_token,
@@ -279,7 +133,7 @@ export default function LipsyncEditor({
};
const transitions = useTransition(index, {
- ...softSpring,
+ ...springs.soft,
from: { opacity: 0, position: "absolute" },
enter: { opacity: 1, position: "relative" },
leave: { opacity: 0, position: "absolute" },
@@ -290,7 +144,7 @@ export default function LipsyncEditor({
{transitions((style, i) => {
- const Page = [InputPage, Working, FaceAnimatorSuccess][page];
+ const Page = [FaceAnimatorInput, FaceAnimatorWorking, FaceAnimatorSuccess][page];
return Page ? (
+
+
+
);
}