mirror of
https://github.com/storytold/storyteller-bevy.git
synced 2026-10-25 08:30:24 +00:00
Refactor Studio entry-points (#54)
This PR heavily refactors the entry-point functions in `studio/src/lib.rs` to simplify and consolidate. Additionally, the frontend application should now be configurable as expected with any valid combination of the following URL parameters: * `objectId` : A pre-bundled library object to load (e.g., "couch.gltf") * `bvh` : Any resolvable path to a BVH animation with a MocapNET skeleton (e.g., "mocap/shuffle.bvh") * `mixamo` : Any resolvable path to a glTF animation with the Mixamo skeleton (e.g., "mocap/hip-hop-dancing.gltf") * `sceneImport` : Any resolvable path to an arbitrary glTF scene (untested, but should theoretically work) * `scene` : Any resolvable path to a previously saved Storyteller Studio scene in `*.scn.ron` format * `skybox` : The ID of a pre-bundled skybox asset. Valid options are: - "gum_trees_4k" - "kloofenfal_28d_misty_4k" - "meadow_4k" - "promenade_de_vidy_4k" - "scythian_tombs_4k" - "test_scene" (this is the default if not specified) * `mode` : One of "studio" or "viewer" (the default if not specified) "Validity" rules are as follows: * `objectId`, `bvh`, `mixamo`, `sceneImport` and `scene` are mutually exclusive * `skybox` is not supported for `scene` (the skybox should be saved and loaded as part of the scene description, though this is not currently working) * Both `mode` options are valid for all other parameters
This commit is contained in:
@@ -1,8 +1,5 @@
|
||||
export * from "./lib/bvh-viewer.element";
|
||||
export * from "./lib/canvas-provider.element";
|
||||
export * from "./lib/editor.element";
|
||||
export * from "./lib/mixamo-viewer.element";
|
||||
export * from "./lib/scene-hierarchy.element";
|
||||
export * from "./lib/studio.element";
|
||||
export * from "./lib/transform-toolbar.element";
|
||||
export * from "./lib/url-params";
|
||||
export * from "./lib/viewer.element";
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
import * as studio from "@storyteller/studio";
|
||||
import { ViewportSize } from "@storyteller/studio";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
|
||||
import { StudioBaseElement } from "./studio-base.element";
|
||||
import { PropertyValues } from "lit";
|
||||
|
||||
@customElement("sts-bvh-viewer")
|
||||
export class BvhViewerElement extends StudioBaseElement {
|
||||
@property() bvhPath?: string;
|
||||
@property() skyboxId?: string;
|
||||
|
||||
onStart(viewportSize: ViewportSize): void {
|
||||
if (!this.bvhPath) return;
|
||||
if (!this.skyboxId) return;
|
||||
|
||||
studio.startBvhViewer(
|
||||
this.bvhPath,
|
||||
this.skyboxId,
|
||||
`#${this._canvasProvider!.canvasId}`,
|
||||
"Storyteller Studio",
|
||||
viewportSize,
|
||||
);
|
||||
}
|
||||
|
||||
onChanges(changes: PropertyValues<this>): void {
|
||||
if (changes.has("bvhPath") && !!this.bvhPath) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
if (changes.has("skyboxId") && !!this.skyboxId)
|
||||
studio.setSkybox(this.skyboxId);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import * as studio from "@storyteller/studio";
|
||||
import { ViewportSize } from "@storyteller/studio";
|
||||
import { PropertyValues } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
|
||||
import { StudioBaseElement } from "./studio-base.element";
|
||||
|
||||
@customElement("sts-editor")
|
||||
export class EditorElement extends StudioBaseElement {
|
||||
@property() scenePath?: string;
|
||||
|
||||
onStart(viewportSize: ViewportSize): void {
|
||||
if (!this.scenePath) return;
|
||||
|
||||
studio.startEditor(
|
||||
this.scenePath,
|
||||
`#${this._canvasProvider!.canvasId}`,
|
||||
"Storyteller Studio",
|
||||
viewportSize,
|
||||
);
|
||||
}
|
||||
|
||||
onChanges(changes: PropertyValues<this>): void {
|
||||
if (changes.has("scenePath") && !!this.scenePath) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
import * as studio from "@storyteller/studio";
|
||||
import { ViewportSize } from "@storyteller/studio";
|
||||
import { PropertyValues } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
|
||||
import { StudioBaseElement } from "./studio-base.element";
|
||||
|
||||
@customElement("sts-mixamo-viewer")
|
||||
export class MixamoViewerElement extends StudioBaseElement {
|
||||
@property() mixamoPath?: string;
|
||||
@property() skyboxId?: string;
|
||||
|
||||
onStart(viewportSize: ViewportSize): void {
|
||||
if (!this.mixamoPath) return;
|
||||
if (!this.skyboxId) return;
|
||||
|
||||
studio.startMixamoViewer(
|
||||
this.mixamoPath,
|
||||
this.skyboxId,
|
||||
`#${this._canvasProvider!.canvasId}`,
|
||||
"Storyteller Studio",
|
||||
viewportSize,
|
||||
);
|
||||
}
|
||||
|
||||
onChanges(changes: PropertyValues<this>): void {
|
||||
if (changes.has("mixamoPath") && !!this.mixamoPath) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
if (changes.has("skyboxId") && !!this.skyboxId)
|
||||
studio.setSkybox(this.skyboxId);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,28 @@
|
||||
import { inject } from "@storyteller/framework";
|
||||
import * as studio from "@storyteller/studio";
|
||||
import { ViewportSize } from "@storyteller/studio";
|
||||
import { LitElement, PropertyValues, html, unsafeCSS } from "lit";
|
||||
|
||||
import {
|
||||
type InitOptions,
|
||||
type SkyboxId,
|
||||
StudioMode,
|
||||
ViewportSize,
|
||||
} from "@storyteller/studio";
|
||||
import { LitElement, type PropertyValues, html, unsafeCSS } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
import { CANVAS_PROVIDER, type CanvasProvider } from "./canvas-provider.element";
|
||||
|
||||
import styles from "./studio-base.element.scss?inline";
|
||||
import styles from "./studio.element.scss?inline";
|
||||
|
||||
export abstract class StudioBaseElement extends LitElement {
|
||||
@customElement("sts-studio")
|
||||
export class StudioElement extends LitElement {
|
||||
static override styles = unsafeCSS(styles);
|
||||
|
||||
get canvas() { return this.#canvas; }
|
||||
@property() objectId?: string;
|
||||
@property() bvhPath?: string;
|
||||
@property() mixamoPath?: string;
|
||||
@property() sceneImport?: string;
|
||||
@property() storytellerScene?: string;
|
||||
@property() skyboxId?: SkyboxId;
|
||||
@property({ type: Number }) mode?: StudioMode;
|
||||
|
||||
@inject(CANVAS_PROVIDER)
|
||||
_canvasProvider?: CanvasProvider;
|
||||
@@ -19,9 +31,6 @@ export abstract class StudioBaseElement extends LitElement {
|
||||
#resizeObserver?: ResizeObserver;
|
||||
#frameRequest?: number;
|
||||
|
||||
abstract onStart(viewportSize: ViewportSize): void;
|
||||
abstract onChanges?(changes: PropertyValues<this>): void;
|
||||
|
||||
override connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
|
||||
@@ -53,7 +62,7 @@ export abstract class StudioBaseElement extends LitElement {
|
||||
if (!studio.isInitialized()) {
|
||||
this.#start();
|
||||
} else {
|
||||
this.onChanges?.(changes);
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,10 +84,36 @@ export abstract class StudioBaseElement extends LitElement {
|
||||
|
||||
#start(): void {
|
||||
if (!this.#canvas) return;
|
||||
if (this.mode == null) return;
|
||||
|
||||
const { width, height } = this.getBoundingClientRect();
|
||||
const options: InitOptions = {
|
||||
mode: this.mode,
|
||||
canvasSelector: `#${this._canvasProvider?.canvasId}`,
|
||||
canvasAlt: "Storyteller Studio",
|
||||
viewportSize: new ViewportSize(width, height),
|
||||
};
|
||||
|
||||
try {
|
||||
this.onStart(new ViewportSize(width, height));
|
||||
if (
|
||||
this.skyboxId
|
||||
&& (this.objectId || this.bvhPath || this.mixamoPath || this.sceneImport)
|
||||
) {
|
||||
options.skyboxId = this.skyboxId;
|
||||
|
||||
if (this.objectId) {
|
||||
studio.initFromLibrary(this.objectId, options);
|
||||
} else if (this.bvhPath) {
|
||||
studio.initFromBvh(this.bvhPath, options);
|
||||
} else if (this.mixamoPath) {
|
||||
studio.initFromMixamo(this.mixamoPath, options);
|
||||
} else if (this.sceneImport) {
|
||||
studio.initFromSceneImport(this.sceneImport, options);
|
||||
}
|
||||
}
|
||||
else if (this.storytellerScene) {
|
||||
studio.initFromStorytellerScene(this.storytellerScene, options);
|
||||
}
|
||||
} catch (err) {
|
||||
if (!(err as Error).message?.startsWith("Using exceptions for control flow"))
|
||||
throw err;
|
||||
@@ -1,4 +1,4 @@
|
||||
import { StudioMode } from "@storyteller/studio";
|
||||
import { type SkyboxId, StudioMode } from "@storyteller/studio";
|
||||
import { match } from "@storyteller/utility";
|
||||
|
||||
export class StudioURLParams {
|
||||
@@ -7,9 +7,14 @@ export class StudioURLParams {
|
||||
return this.#_nativeParams ??= new URLSearchParams(document.location.search);
|
||||
}
|
||||
|
||||
get bvh() { return this.#nativeParams.get("bvh"); }
|
||||
get mixamo() { return this.#nativeParams.get("mixamo"); }
|
||||
get scene() { return this.#nativeParams.get("scene"); }
|
||||
get objectId() { return this.#nativeParams.get("objectId") ?? undefined; }
|
||||
get bvh() { return this.#nativeParams.get("bvh") ?? undefined; }
|
||||
get mixamo() { return this.#nativeParams.get("mixamo") ?? undefined; }
|
||||
get sceneImport() { return this.#nativeParams.get("sceneImport") ?? undefined; }
|
||||
get scene() { return this.#nativeParams.get("scene") ?? undefined; }
|
||||
get skybox() {
|
||||
return this.#nativeParams.get("skybox") as SkyboxId ?? undefined;
|
||||
}
|
||||
get mode(): StudioMode {
|
||||
return match(this.#nativeParams.get("mode"), {
|
||||
"studio": () => StudioMode.Editor,
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
import * as studio from "@storyteller/studio";
|
||||
import { StudioMode, ViewportSize } from "@storyteller/studio";
|
||||
import { PropertyValues } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
|
||||
import { StudioBaseElement } from "./studio-base.element";
|
||||
|
||||
@customElement("sts-viewer")
|
||||
export class ViewerElement extends StudioBaseElement {
|
||||
@property() objectId?: string;
|
||||
@property() skyboxId?: string;
|
||||
@property({ type: Number }) mode?: StudioMode;
|
||||
|
||||
onStart(viewportSize: ViewportSize): void {
|
||||
if (!this.objectId) return;
|
||||
if (!this.skyboxId) return;
|
||||
if (this.mode == null) return;
|
||||
|
||||
studio.start(
|
||||
this.objectId,
|
||||
this.skyboxId,
|
||||
`#${this._canvasProvider!.canvasId}`,
|
||||
"Storyteller Studio",
|
||||
viewportSize,
|
||||
this.mode,
|
||||
);
|
||||
}
|
||||
|
||||
onChanges(changes: PropertyValues<this>): void {
|
||||
if (changes.has("objectId") && !!this.objectId)
|
||||
studio.loadObject(this.objectId);
|
||||
|
||||
if (changes.has("skyboxId") && !!this.skyboxId)
|
||||
studio.setSkybox(this.skyboxId);
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
export interface HTMLElementTagNameMap {
|
||||
"sts-viewer": ViewerElement;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user