diff --git a/studio-frontend/src/app/api/EnqueueEngineCompositing.ts b/studio-frontend/src/app/api/EnqueueEngineCompositing.ts new file mode 100644 index 0000000..1865982 --- /dev/null +++ b/studio-frontend/src/app/api/EnqueueEngineCompositing.ts @@ -0,0 +1,19 @@ +import MakeRequest from "./MakeRequest"; + +export interface EnqueueEngineCompositingRequest { + uuid_idempotency_token: string, + media_file_token: string, + camera?: string, + camera_speed?: number, + skybox?: string, +} + +export interface EnqueueEngineCompositingResponse { + success: boolean, + inference_job_token?: string +} + +export const EnqueueEngineCompositing = MakeRequest({ + method: "POST", + routingFunction: () => `/v1/conversion/enqueue_render_engine_scene`, +}); \ No newline at end of file diff --git a/studio-frontend/src/app/api/MakeRequest.ts b/studio-frontend/src/app/api/MakeRequest.ts new file mode 100644 index 0000000..b951133 --- /dev/null +++ b/studio-frontend/src/app/api/MakeRequest.ts @@ -0,0 +1,56 @@ +type UrlRoutingFunction = (urlRouteArgs: UrlRouteArgs) => string; + +interface RequestHeaders { + [name: string]: string; +} + +interface RouteSetup { + method: string; + multipart?: boolean; + routingFunction: UrlRoutingFunction; +} + +const METHOD_OMITS_BODY: { [key: string]: boolean } = { + DELETE: false, + GET: true, + OPTIONS: true, + PATCH: false, + POST: false, + PUT: false, +}; + +const MakeRequest = (routeSetup: RouteSetup) : (urlRouteArgs: UrlRouteArgs, request: Request, queries?: UrlParams) => Promise => { + return async function(urlRouteArgs: UrlRouteArgs, request: Request, queries?: any) : Promise { + const newQueries = queries ? Object.keys(queries).map((key, i) => { + return `${ i ? "&" : "" }${ key }=${ Array.isArray(queries[key]) ? queries[key].join(`&${ key }=`) : queries[key] }` + }).join("") : null; + + const endpoint = `${ routeSetup.routingFunction(urlRouteArgs) }${ newQueries ? "?" + newQueries : "" }`; + const method = routeSetup.method; + const methodOmitsBody = METHOD_OMITS_BODY[method] || false; + + console.log("🛼",request) + + return fetch(`https://api.fakeyou.com${ endpoint }`, { + method, + headers: { + "Accept": "application/json", + ...methodOmitsBody? {} : { "Content-Type": "application/json" } + }, + credentials: 'include', + ...methodOmitsBody ? {} : { body: JSON.stringify(request) }, + }) + .then(res => res.json()) + .then(res => { + if (!res.success && res && (res.voice_token || res.dataset_token)) { + return res; + } + else if (res && "success" in res) { + return res; + } else Promise.reject(); + }) + .catch(e => ({ success : false })); + } +}; + +export default MakeRequest; \ No newline at end of file diff --git a/studio-frontend/src/app/bubble-select.element.scss b/studio-frontend/src/app/bubble-select.element.scss new file mode 100644 index 0000000..621a66c --- /dev/null +++ b/studio-frontend/src/app/bubble-select.element.scss @@ -0,0 +1,36 @@ +.studio-bubble-select { + // background: red; + display: flex; + list-style: none; + margin-block-start: 0px; + margin-block-end: 0px; + padding-inline-start: 0px; + + li { + flex: 0 0 auto; + border: 2px solid darken(purple, 3%); + padding: 8px 16px; + border-radius: 0.5rem; + background-color: darken(purple, 3%); + cursor: pointer; + outline: none; + transition: all 0.2s ease; + font-size: 15px; + font-weight: 500; + color: rgba(#fff, 0.75); + white-space: nowrap; + + &.selected-bubble { + color: #fff; + border-color: red; + background-color: lighten(purple, 6%); + + &.fill { + background-color: red; + } + } + } + + + +} \ No newline at end of file diff --git a/studio-frontend/src/app/bubble-select.element.ts b/studio-frontend/src/app/bubble-select.element.ts new file mode 100644 index 0000000..2daf081 --- /dev/null +++ b/studio-frontend/src/app/bubble-select.element.ts @@ -0,0 +1,28 @@ +import { LitElement, html, nothing, unsafeCSS } from "lit"; +import { customElement, property, state } from "lit/decorators.js"; + +import styles from "./bubble-select.element.scss?inline"; + +// const abc = "word"; + +@customElement("sts-bubble-select") +export class BubbleSelect extends LitElement { + static override styles = unsafeCSS(styles); + @property() name = ""; + @property() onChange = (e: any) => {}; + @property() options = []; + @property() value = ""; + + protected override render = () => html` +
    + ${ this.options.map(({ label, value: itemValue },i) => + html`
  • { + this.onChange({ target: { name: this.name, value: itemValue } }); + } } + >${ label }
  • ` + )} +
+ ` +} \ No newline at end of file diff --git a/studio-frontend/src/app/inspector-tabs/style-tab.scss b/studio-frontend/src/app/inspector-tabs/style-tab.scss new file mode 100644 index 0000000..bb22278 --- /dev/null +++ b/studio-frontend/src/app/inspector-tabs/style-tab.scss @@ -0,0 +1,5 @@ +.inspector-input-set { + label { + display: block; + } +} \ No newline at end of file diff --git a/studio-frontend/src/app/inspector-tabs/style-tab.ts b/studio-frontend/src/app/inspector-tabs/style-tab.ts new file mode 100644 index 0000000..922e781 --- /dev/null +++ b/studio-frontend/src/app/inspector-tabs/style-tab.ts @@ -0,0 +1,100 @@ +import { LitElement, html, nothing, unsafeCSS } from "lit"; +import { customElement, property, state } from "lit/decorators.js"; +import styles from "./style-tab.scss?inline"; +import { EnqueueEngineCompositing } from "../api/EnqueueEngineCompositing"; +import { v4 as uuid } from "uuid"; +import { drag, on, provide } from "@storyteller/framework"; + +@customElement("sts-style-tab") +export class StyleTab extends LitElement { + static override styles = unsafeCSS(styles); + @state() vstStyle = "anime_2d_flat"; + @state() posPrompt = ""; + @state() negPrompt = ""; + @property() sceneToken = ""; + + styleOptions = [ + { + label: "2D Anime", + imageUrl: "/images/landing/onboarding/styles/style-2d-anime.webp", + value: "anime_2d_flat", + }, + { + label: "3D Cartoon", + imageUrl: "/images/landing/onboarding/styles/style-3d-cartoon.webp", + value: "cartoon_3d", + }, + { + label: "Ink B&W", + imageUrl: "/images/landing/onboarding/styles/style-ink-bw.webp", + value: "ink_bw_style", + }, + { + label: "Origami", + imageUrl: "/images/landing/onboarding/styles/style-origami.webp", + value: "paper_origami", + }, + ]; + + inputChange = ({ target }: { target: { name: string, value: any } }) => { + // console.log("💁🏼‍♀️", this[target.name]); + // this[target.name] = target.value; // fix later + } + + @on("scene-state") + oAThing(): void { console.log("🍕")}; + + compositorEnqueue = (sceneToken: string) => () => { + console.log("🏎️",this.sceneToken,sceneToken); + EnqueueEngineCompositing("",{ + uuid_idempotency_token: uuid(), + media_file_token: sceneToken, + camera: "zoom", + camera_speed: 0.2, + skybox: "meadow_4k", + }).then((res: any) => { + if (res && res.success) { + console.log("💎",res.inference_job_token); + + window.parent.postMessage( + `studio-scene-composited:compositeJobToken:${ res.inference_job_token }`, + "*" + ); + // compositeJobTokenSet(res.inference_job_token) + } + }); + } + + thingy = ({ target }: any ) => { + console.log("🏎️", this.sceneToken); + } + + protected override render = () => html`
+ ${ this.vstStyle } + + { this.vstStyle = target.value; } } + .options=${this.styleOptions} + .value=${this.vstStyle} + > + + + + + + Generate your movie + +
`; +} \ No newline at end of file diff --git a/studio-frontend/src/app/inspector.element.scss b/studio-frontend/src/app/inspector.element.scss new file mode 100644 index 0000000..5917751 --- /dev/null +++ b/studio-frontend/src/app/inspector.element.scss @@ -0,0 +1,6 @@ +.studio-inspector { + color: #fff; + background: blue; + position: absolute; + top: 50%; +} \ No newline at end of file diff --git a/studio-frontend/src/app/inspector.ts b/studio-frontend/src/app/inspector.ts new file mode 100644 index 0000000..2eb279e --- /dev/null +++ b/studio-frontend/src/app/inspector.ts @@ -0,0 +1,60 @@ +import { LitElement, type PropertyValues, html, nothing, unsafeCSS } from "lit"; +import { customElement, property, state } from "lit/decorators.js"; +import "@storyteller/studio-ui/tree"; +import "./tabs.element"; +import "./bubble-select.element"; +import "./inspector-tabs/style-tab"; +import styles from "./inspector.element.scss?inline"; +import "@storyteller/studio-ui/button"; + +// const abc = "word"; + +enum InspectorMode { + Properties, + Style +} + +@customElement("sts-inspector") +export class Inspector extends LitElement { + static override styles = unsafeCSS(styles); + @state() selectedTab = InspectorMode.Style; + @property() sceneToken = ""; + @property() styleMediaToken = ""; + + tabs = [{ + label: "Properties", + value: InspectorMode.Properties + },{ + label: "Style", + value: InspectorMode.Style + }]; + + thingy = ({ target }: any) => { + console.log("🏎️", this.styleMediaToken); + } + + propertiesTab = html`
Properties
`; + + tabContent = () => { + switch (this.selectedTab) { + case InspectorMode.Properties: return this.propertiesTab; + case InspectorMode.Style: return html``; + } + } + + protected override render = () => html` +
+ + { + this.selectedTab = target.value; + } } + .tabs=${this.tabs} + .value=${this.selectedTab} + > +
+ ${ this.tabContent() } +
+
+ ` +} diff --git a/studio-frontend/src/app/tabs.element.scss b/studio-frontend/src/app/tabs.element.scss new file mode 100644 index 0000000..2093c3c --- /dev/null +++ b/studio-frontend/src/app/tabs.element.scss @@ -0,0 +1,24 @@ +.studio-tabs { + // background: red; + display: flex; + list-style: none; + margin-block-start: 0px; + margin-block-end: 0px; + padding-inline-start: 0px; + + li { + border: none; + padding: 1rem 1.4rem; + border-bottom: 4px solid transparent; + color: rgba(255, 255, 255, 0.5); + font-weight: 500; + white-space: nowrap; + + &.selected-tab { + border-bottom: 4px solid #e66462; + } + } + + + +} \ No newline at end of file diff --git a/studio-frontend/src/app/tabs.element.ts b/studio-frontend/src/app/tabs.element.ts new file mode 100644 index 0000000..5b644f7 --- /dev/null +++ b/studio-frontend/src/app/tabs.element.ts @@ -0,0 +1,26 @@ +import { LitElement, type PropertyValues, html, nothing, unsafeCSS } from "lit"; +import { customElement, property, state } from "lit/decorators.js"; + +import styles from "./tabs.element.scss?inline"; + +@customElement("sts-tabs") +export class Tabs extends LitElement { + static override styles = unsafeCSS(styles); + @property() name = ""; + @property() onChange = (e: any) => {}; + @property() tabs = []; + @property() value = ""; + + protected override render = () => html` +
    + ${ this.tabs.map(({ label, value: itemValue },i) => + html`
  • { + this.onChange({ target: { name: this.name, value: itemValue } }); + } } + >${ label }
  • ` + )} +
+ ` +} \ No newline at end of file diff --git a/studio-ui/src/lib/tabs.element.ts b/studio-ui/src/lib/tabs.element.ts new file mode 100644 index 0000000..d74c486 --- /dev/null +++ b/studio-ui/src/lib/tabs.element.ts @@ -0,0 +1,17 @@ +import { LitElement, type PropertyValues, html, nothing, unsafeCSS } from "lit"; +import { customElement, property, state } from "lit/decorators.js"; + +// import styles from "./button.element.scss?inline"; + +// const abc = "word"; + +@customElement("sts-tabs") +export class Tabs extends LitElement { + @property() tabs = ["hello world"]; + + protected override render = () => html` +
+ ${ this.tabs.map((item,i) => item) } +
+ ` +} \ No newline at end of file