mirror of
https://github.com/storytold/storyteller-bevy.git
synced 2026-10-18 07:35:19 +00:00
UI styling, main workspace layout (#119)
This commit is contained in:
@@ -3,12 +3,9 @@
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--padding);
|
||||
gap: 1rem;
|
||||
overflow: auto;
|
||||
|
||||
--background-color: var(--color-panel-background);
|
||||
|
||||
color: #FFFC;
|
||||
color: #FFF;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 0.5rem;
|
||||
@@ -32,13 +29,3 @@
|
||||
*, *::before, *::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.container {
|
||||
background-color: var(--background-color);
|
||||
border-radius: var(--corner-radius);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
padding: var(--padding);
|
||||
gap: var(--padding);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { inject } from "@storyteller/framework";
|
||||
import { LitElement, type PropertyValues, html, unsafeCSS, nothing } from "lit";
|
||||
import { inject, observe } from "@storyteller/framework";
|
||||
import { LitElement, html, unsafeCSS, nothing } from "lit";
|
||||
import { customElement } from "lit/decorators.js";
|
||||
|
||||
import { SCENE_DATA_PROVIDER, type SceneDataProvider } from "../scene-data-provider.element";
|
||||
@@ -16,89 +16,69 @@ import styles from "./entity-inspector.element.scss?inline";
|
||||
export class EntityInspectorElement extends LitElement {
|
||||
static override styles = unsafeCSS(styles);
|
||||
|
||||
@observe(["selectionComponents"])
|
||||
@inject(SCENE_DATA_PROVIDER)
|
||||
_sceneData?: SceneDataProvider;
|
||||
_sceneData!: SceneDataProvider;
|
||||
|
||||
override connectedCallback(): void {
|
||||
this._sceneData?.addEventListener("property-changes", this.onProviderChanges);
|
||||
super.connectedCallback();
|
||||
}
|
||||
protected override render = () => html`
|
||||
${this._sceneData
|
||||
?.selectionComponents
|
||||
.slice()
|
||||
.sort((a, b) => {
|
||||
const ordA = COMPONENT_SORT_ORDER.indexOf(a.name);
|
||||
const ordB = COMPONENT_SORT_ORDER.indexOf(b.name);
|
||||
|
||||
override disconnectedCallback(): void {
|
||||
this._sceneData?.removeEventListener("property-changes", this.onProviderChanges);
|
||||
super.disconnectedCallback();
|
||||
}
|
||||
if (ordA === -1) return Infinity;
|
||||
if (ordB === -1) return -Infinity;
|
||||
|
||||
onProviderChanges = ({ detail: changes }: CustomEvent<PropertyValues<SceneDataProvider>>) => {
|
||||
if (changes.has("selectionComponents"))
|
||||
this.requestUpdate();
|
||||
}
|
||||
return ordA - ordB;
|
||||
})
|
||||
.map(({ name, value }) => {
|
||||
switch (name) {
|
||||
// TODO?
|
||||
// case "bevy_core::name::Name": {
|
||||
// return html`
|
||||
// <sts-name-inspector
|
||||
// .value=${value.name}
|
||||
// ></sts-name-inspector>
|
||||
// `;
|
||||
// }
|
||||
case "bevy_transform::components::transform::Transform": {
|
||||
return html`
|
||||
<sts-transform-inspector
|
||||
.translation=${value.translation}
|
||||
.rotation=${value.rotation}
|
||||
.scale=${value.scale}
|
||||
></sts-transform-inspector>
|
||||
`;
|
||||
}
|
||||
case "bevy_pbr::pbr_material::StandardMaterial": {
|
||||
const { colorSpace, baseColor } = isLinear(value.base_color)
|
||||
? { colorSpace: "linear", baseColor: value.base_color.RgbaLinear }
|
||||
: { colorSpace: "srgb", baseColor: value.base_color.Rgba };
|
||||
|
||||
protected override render () {
|
||||
let components = this._sceneData
|
||||
?.selectionComponents
|
||||
.slice()
|
||||
.sort((a, b) => {
|
||||
const ordA = COMPONENT_SORT_ORDER.indexOf(a.name);
|
||||
const ordB = COMPONENT_SORT_ORDER.indexOf(b.name);
|
||||
|
||||
if (ordA === -1) return Infinity;
|
||||
if (ordB === -1) return -Infinity;
|
||||
|
||||
return ordA - ordB;
|
||||
})
|
||||
.map(({ name, value }) => {
|
||||
switch (name) {
|
||||
case "bevy_core::name::Name": {
|
||||
return html`
|
||||
<sts-name-inspector
|
||||
.value=${value.name}
|
||||
></sts-name-inspector>
|
||||
`;
|
||||
return html`
|
||||
<sts-material-inspector
|
||||
.baseColor=${baseColor}
|
||||
.colorSpace=${colorSpace}
|
||||
.roughness=${value.perceptual_roughness}
|
||||
.metallic=${value.metallic}
|
||||
.reflectance=${value.reflectance}
|
||||
></sts-material-inspector>
|
||||
`;
|
||||
}
|
||||
default: {
|
||||
return nothing;
|
||||
// return html`
|
||||
// <h3>Unknown Component: ${name}</h3>
|
||||
// <pre>${JSON.stringify({ name, value }, null, " ")}</pre>
|
||||
// `;
|
||||
}
|
||||
}
|
||||
case "bevy_transform::components::transform::Transform": {
|
||||
return html`
|
||||
<sts-transform-inspector
|
||||
.translation=${value.translation}
|
||||
.rotation=${value.rotation}
|
||||
.scale=${value.scale}
|
||||
></sts-transform-inspector>
|
||||
`;
|
||||
}
|
||||
case "bevy_pbr::pbr_material::StandardMaterial": {
|
||||
const { colorSpace, baseColor } = isLinear(value.base_color)
|
||||
? { colorSpace: "linear", baseColor: value.base_color.RgbaLinear }
|
||||
: { colorSpace: "srgb", baseColor: value.base_color.Rgba };
|
||||
|
||||
return html`
|
||||
<sts-material-inspector
|
||||
.baseColor=${baseColor}
|
||||
.colorSpace=${colorSpace}
|
||||
.roughness=${value.perceptual_roughness}
|
||||
.metallic=${value.metallic}
|
||||
.reflectance=${value.reflectance}
|
||||
></sts-material-inspector>
|
||||
`;
|
||||
}
|
||||
default: {
|
||||
return nothing;
|
||||
// return html`
|
||||
// <h3>Unknown Component: ${name}</h3>
|
||||
// <pre>${JSON.stringify({ name, value }, null, " ")}</pre>
|
||||
// `;
|
||||
}
|
||||
}
|
||||
}).filter((value) => value !== nothing) || [];
|
||||
if (components?.length === 0) {
|
||||
return nothing;
|
||||
})
|
||||
?? nothing
|
||||
}
|
||||
return html`
|
||||
<div class="container">
|
||||
${components
|
||||
}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
const COMPONENT_SORT_ORDER: Array<InspectorComponent["name"]> = [
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
h4 {
|
||||
font-weight: 500;
|
||||
margin: 0 0 1rem;
|
||||
margin: 0 0 0.5rem;
|
||||
}
|
||||
|
||||
.fields {
|
||||
|
||||
@@ -2,30 +2,41 @@
|
||||
|
||||
:host {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.field {
|
||||
display: flex;
|
||||
width: math.div(1, 3) * 100%;
|
||||
border-radius: 0.5rem;
|
||||
overflow: hidden;
|
||||
outline: transparent 2px solid {
|
||||
offset: -2px;
|
||||
}
|
||||
transition: outline-color 100ms linear;
|
||||
|
||||
&--x:focus-within { outline-color: var(--axis-red) }
|
||||
&--y:focus-within { outline-color: var(--axis-green) }
|
||||
&--z:focus-within { outline-color: var(--axis-blue) }
|
||||
}
|
||||
|
||||
.label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 0.375rem;
|
||||
font: {
|
||||
size: math.div(14, 16) * 1rem;
|
||||
weight: 500;
|
||||
}
|
||||
|
||||
&--x { background: var(--axis-red) }
|
||||
&--y { background: var(--axis-green) }
|
||||
&--z { background: var(--axis-blue) }
|
||||
}
|
||||
|
||||
.input {
|
||||
padding: 0.5rem;
|
||||
width: math.div(1, 3) * 100%;
|
||||
border-left-width: 4px;
|
||||
|
||||
&:nth-of-type(1) {
|
||||
border-left-color: rgb(220, 53, 69);
|
||||
&:focus {
|
||||
border-left-color: rgb(255, 48, 68);
|
||||
}
|
||||
}
|
||||
&:nth-of-type(2) {
|
||||
border-left-color: rgb(25, 135, 84);
|
||||
&:focus {
|
||||
border-left-color: rgb(0, 187, 100);
|
||||
}
|
||||
}
|
||||
&:nth-of-type(3) {
|
||||
border-left-color: rgb(13, 110, 253);
|
||||
&:focus {
|
||||
border-left-color: rgb(47, 131, 255);
|
||||
}
|
||||
}
|
||||
flex: 1 0 0;
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
@@ -46,36 +46,44 @@ export class QuatInspectorElement extends LitElement {
|
||||
}
|
||||
|
||||
protected override render = (): TemplateResult => html`
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
aria-label="X"
|
||||
format="1.1-2 °"
|
||||
emitOn="change"
|
||||
.step=${1}
|
||||
.microStep=${0.1}
|
||||
.value=${this._eulerX}
|
||||
@value-change=${this.#emitUpdate(RotationAxis.X)}
|
||||
></sts-scalar-field>
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
aria-label="Y"
|
||||
format="1.1-2 °"
|
||||
emitOn="change"
|
||||
.step=${1}
|
||||
.microStep=${0.1}
|
||||
.value=${this._eulerY}
|
||||
@value-change=${this.#emitUpdate(RotationAxis.Y)}
|
||||
></sts-scalar-field>
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
aria-label="Z"
|
||||
format="1.1-2 °"
|
||||
emitOn="change"
|
||||
.step=${1}
|
||||
.microStep=${0.1}
|
||||
.value=${this._eulerZ}
|
||||
@value-change=${this.#emitUpdate(RotationAxis.Z)}
|
||||
></sts-scalar-field>
|
||||
<label class="field field--x">
|
||||
<span class="label label--x">X</span>
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
format="1.2-2 °"
|
||||
emitOn="change"
|
||||
.step=${1}
|
||||
.microStep=${0.1}
|
||||
.value=${this._eulerX}
|
||||
@value-change=${this.#emitUpdate(RotationAxis.X)}
|
||||
></sts-scalar-field>
|
||||
</label>
|
||||
|
||||
<label class="field field--y">
|
||||
<span class="label label--y">Y</span>
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
format="1.2-2 °"
|
||||
emitOn="change"
|
||||
.step=${1}
|
||||
.microStep=${0.1}
|
||||
.value=${this._eulerY}
|
||||
@value-change=${this.#emitUpdate(RotationAxis.Y)}
|
||||
></sts-scalar-field>
|
||||
</label>
|
||||
|
||||
<label class="field field--z">
|
||||
<span class="label label--z">Z</span>
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
format="1.2-2 °"
|
||||
emitOn="change"
|
||||
.step=${1}
|
||||
.microStep=${0.1}
|
||||
.value=${this._eulerZ}
|
||||
@value-change=${this.#emitUpdate(RotationAxis.Z)}
|
||||
></sts-scalar-field>
|
||||
</label>
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,43 +22,57 @@ h4 {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding: 0 {
|
||||
block-start: math.div(14, 16) + 0.333rem !important;
|
||||
block-start: math.div(17, 16) + 0.25rem !important;
|
||||
}
|
||||
margin: 0;
|
||||
gap: 0.25rem;
|
||||
gap: 0.5rem;
|
||||
border: none;
|
||||
|
||||
legend {
|
||||
position: absolute;
|
||||
inset-block-start: 0;
|
||||
margin-block-end: 0.333rem;
|
||||
color: #FFF9;
|
||||
font-size: math.div(14, 16) * 1rem;
|
||||
padding: 0;
|
||||
color: #FFF;
|
||||
font: {
|
||||
size: math.div(14, 16) * 1rem;
|
||||
weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.field {
|
||||
display: flex;
|
||||
width: math.div(1, 3) * 100%;
|
||||
border-radius: 0.5rem;
|
||||
overflow: hidden;
|
||||
outline: transparent 2px solid {
|
||||
offset: -2px;
|
||||
}
|
||||
transition: outline-color 100ms linear;
|
||||
|
||||
&--x:focus-within { outline-color: var(--axis-red) }
|
||||
&--y:focus-within { outline-color: var(--axis-green) }
|
||||
&--z:focus-within { outline-color: var(--axis-blue) }
|
||||
}
|
||||
|
||||
.label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 0.375rem;
|
||||
font: {
|
||||
size: math.div(14, 16) * 1rem;
|
||||
weight: 500;
|
||||
}
|
||||
|
||||
&--x { background: var(--axis-red) }
|
||||
&--y { background: var(--axis-green) }
|
||||
&--z { background: var(--axis-blue) }
|
||||
}
|
||||
|
||||
.input {
|
||||
padding: 0.5rem;
|
||||
width: math.div(1, 3) * 100%;
|
||||
border-left-width: 4px;
|
||||
|
||||
&:nth-of-type(1) {
|
||||
border-left-color: rgb(220, 53, 69);
|
||||
&:focus {
|
||||
border-left-color: rgb(255, 48, 68);
|
||||
}
|
||||
}
|
||||
&:nth-of-type(2) {
|
||||
border-left-color: rgb(25, 135, 84);
|
||||
&:focus {
|
||||
border-left-color: rgb(0, 187, 100);
|
||||
}
|
||||
}
|
||||
&:nth-of-type(3) {
|
||||
border-left-color: rgb(13, 110, 253);
|
||||
&:focus {
|
||||
border-left-color: rgb(47, 131, 255);
|
||||
}
|
||||
}
|
||||
flex: 1 0 0;
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
outline: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@ export class TransformInspectorElement extends LitElement {
|
||||
}
|
||||
|
||||
protected override render = () => html`
|
||||
<h4>Transform</h4>
|
||||
<div
|
||||
class="fieldset"
|
||||
role="group"
|
||||
@@ -48,31 +47,44 @@ export class TransformInspectorElement extends LitElement {
|
||||
<legend id=${this.#positionLabelId}>
|
||||
Position
|
||||
</legend>
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
aria-label="X"
|
||||
.step=${0.01}
|
||||
.microStep=${0.001}
|
||||
.value=${this.translation.x}
|
||||
@value-change=${this.updateField("translation.x")}
|
||||
></sts-scalar-field>
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
aria-label="Y"
|
||||
.step=${0.01}
|
||||
.microStep=${0.001}
|
||||
.value=${this.translation.y}
|
||||
@value-change=${this.updateField("translation.y")}
|
||||
></sts-scalar-field>
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
aria-label="Z"
|
||||
.step=${0.01}
|
||||
.microStep=${0.001}
|
||||
.value=${this.translation.z}
|
||||
@value-change=${this.updateField("translation.z")}
|
||||
></sts-scalar-field>
|
||||
|
||||
<label class="field field--x">
|
||||
<span class="label label--x">X</span>
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
format="1.3"
|
||||
.step=${0.01}
|
||||
.microStep=${0.001}
|
||||
.value=${this.translation.x}
|
||||
@value-change=${this.updateField("translation.x")}
|
||||
></sts-scalar-field>
|
||||
</label>
|
||||
|
||||
<label class="field field--y">
|
||||
<span class="label label--y">Y</span>
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
format="1.3"
|
||||
.step=${0.01}
|
||||
.microStep=${0.001}
|
||||
.value=${this.translation.y}
|
||||
@value-change=${this.updateField("translation.y")}
|
||||
></sts-scalar-field>
|
||||
</label>
|
||||
|
||||
<label class="field field--z">
|
||||
<span class="label label--z">Z</span>
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
format="1.3"
|
||||
.step=${0.01}
|
||||
.microStep=${0.001}
|
||||
.value=${this.translation.z}
|
||||
@value-change=${this.updateField("translation.z")}
|
||||
></sts-scalar-field>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="fieldset"
|
||||
role="group"
|
||||
@@ -86,6 +98,7 @@ export class TransformInspectorElement extends LitElement {
|
||||
@value-change=${this.updateField("rotation")}
|
||||
></sts-quat-inspector>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="fieldset"
|
||||
role="group"
|
||||
@@ -94,30 +107,42 @@ export class TransformInspectorElement extends LitElement {
|
||||
<legend id=${this.#scaleLabelId}>
|
||||
Scale
|
||||
</legend>
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
aria-label="X"
|
||||
.step=${0.1}
|
||||
.microStep=${0.01}
|
||||
.value=${this.scale.x}
|
||||
@value-change=${this.updateField("scale.x")}
|
||||
></sts-scalar-field>
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
aria-label="Y"
|
||||
.step=${0.1}
|
||||
.microStep=${0.01}
|
||||
.value=${this.scale.y}
|
||||
@value-change=${this.updateField("scale.y")}
|
||||
></sts-scalar-field>
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
aria-label="Z"
|
||||
.step=${0.1}
|
||||
.microStep=${0.01}
|
||||
.value=${this.scale.z}
|
||||
@value-change=${this.updateField("scale.z")}
|
||||
></sts-scalar-field>
|
||||
|
||||
<label class="field field--x">
|
||||
<span class="label label--x">X</span>
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
format="1.3"
|
||||
.step=${0.1}
|
||||
.microStep=${0.01}
|
||||
.value=${this.scale.x}
|
||||
@value-change=${this.updateField("scale.x")}
|
||||
></sts-scalar-field>
|
||||
</label>
|
||||
|
||||
<label class="field field--y">
|
||||
<span class="label label--y">Y</span>
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
format="1.3"
|
||||
.step=${0.1}
|
||||
.microStep=${0.01}
|
||||
.value=${this.scale.y}
|
||||
@value-change=${this.updateField("scale.y")}
|
||||
></sts-scalar-field>
|
||||
</label>
|
||||
|
||||
<label class="field field--z">
|
||||
<span class="label label--z">Z</span>
|
||||
<sts-scalar-field
|
||||
class="input"
|
||||
format="1.3"
|
||||
.step=${0.1}
|
||||
.microStep=${0.01}
|
||||
.value=${this.scale.z}
|
||||
@value-change=${this.updateField("scale.z")}
|
||||
></sts-scalar-field>
|
||||
</label>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as studio from "@storyteller/studio";
|
||||
import { SceneElement } from "@storyteller/studio";
|
||||
import { bind, inject } from "@storyteller/framework";
|
||||
import { bind, inject, observe } from "@storyteller/framework";
|
||||
import { DialogBaseElement, DialogElement } from "@storyteller/studio-ui/dialog";
|
||||
import {
|
||||
type MediaFile as IMediaFile,
|
||||
@@ -56,6 +56,7 @@ export class MediaLibraryDialogElement extends DialogBaseElement {
|
||||
@inject(StorytellerApi)
|
||||
_api!: StorytellerApi;
|
||||
|
||||
@observe(["selectedObject"])
|
||||
@inject(SCENE_DATA_PROVIDER)
|
||||
_sceneData!: SceneDataProvider;
|
||||
|
||||
@@ -104,22 +105,6 @@ export class MediaLibraryDialogElement extends DialogBaseElement {
|
||||
return oneAnimationSelected && skeletonSelected;
|
||||
}
|
||||
|
||||
override connectedCallback(): void {
|
||||
this._sceneData?.addEventListener("property-changes", this.onProviderChanges);
|
||||
this.loadResults();
|
||||
super.connectedCallback();
|
||||
}
|
||||
|
||||
override disconnectedCallback(): void {
|
||||
this._sceneData?.removeEventListener("property-changes", this.onProviderChanges);
|
||||
super.disconnectedCallback();
|
||||
}
|
||||
|
||||
onProviderChanges = ({ detail: changes }: CustomEvent<PropertyValues<SceneDataProvider>>) => {
|
||||
if (changes.has("selectedObject"))
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
protected override willUpdate(changes: PropertyValues<this>): void {
|
||||
if (changes.has("_activeCategory") || changes.has("_searchTerm")) {
|
||||
this._filters = [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { inject } from "@storyteller/framework";
|
||||
import { inject, observe } from "@storyteller/framework";
|
||||
import * as studio from "@storyteller/studio";
|
||||
import { LitElement, type PropertyValues, html, unsafeCSS } from "lit";
|
||||
import { LitElement, html, unsafeCSS } from "lit";
|
||||
import { customElement } from "lit/decorators.js";
|
||||
|
||||
import { SCENE_DATA_PROVIDER, type SceneDataProvider } from "./scene-data-provider.element";
|
||||
@@ -13,23 +13,9 @@ import styles from "./scene-hierarchy.element.scss?inline";
|
||||
export class SceneHierarchyElement extends LitElement {
|
||||
static override styles = unsafeCSS(styles);
|
||||
|
||||
@observe(["tree"])
|
||||
@inject(SCENE_DATA_PROVIDER)
|
||||
_sceneData?: SceneDataProvider;
|
||||
|
||||
override connectedCallback(): void {
|
||||
this._sceneData?.addEventListener("property-changes", this.onProviderChanges);
|
||||
super.connectedCallback();
|
||||
}
|
||||
|
||||
override disconnectedCallback(): void {
|
||||
this._sceneData?.removeEventListener("property-changes", this.onProviderChanges);
|
||||
super.disconnectedCallback();
|
||||
}
|
||||
|
||||
onProviderChanges = ({ detail: changes }: CustomEvent<PropertyValues<SceneDataProvider>>) => {
|
||||
if (changes.has("tree"))
|
||||
this.requestUpdate();
|
||||
}
|
||||
_sceneData!: SceneDataProvider;
|
||||
|
||||
protected override render = () => html`
|
||||
${this._sceneData?.tree.map(obj => html`
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { UniqueToken } from "@storyteller/framework";
|
||||
import { StudioMode } from "@storyteller/studio";
|
||||
import { match } from "@storyteller/utility";
|
||||
|
||||
export const STUDIO_PARAMS = UniqueToken.create<StudioParams>();
|
||||
|
||||
/**
|
||||
* A thin wrapper around
|
||||
* {@linkcode https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams URLSearchParams}
|
||||
@@ -26,42 +29,37 @@ import { match } from "@storyteller/utility";
|
||||
* - **remote://<media-token>.<file-extension>** - A token for a
|
||||
* media file that can be fetched from the Storyteller.ai API
|
||||
*/
|
||||
export class StudioURLParams {
|
||||
#_nativeParams?: URLSearchParams;
|
||||
get #nativeParams() {
|
||||
return this.#_nativeParams ??= new URLSearchParams(document.location.search);
|
||||
}
|
||||
|
||||
export interface StudioParams {
|
||||
/**
|
||||
* Initialize the application from an asset in the "bundled" asset library.
|
||||
* Takes a filename, including the extension, that can be found under
|
||||
* `studio/assets/gltf` (e.g., "base-human-female.gltf").
|
||||
*/
|
||||
get objectId() { return this.#nativeParams.get("objectId") ?? undefined; }
|
||||
readonly objectId?: string;
|
||||
|
||||
/**
|
||||
* Initialize the application by retargeting a BVH animation (currently only
|
||||
* supports the MocapNET skeleton) onto the bundled `Mannequin.gltf` model.
|
||||
*/
|
||||
get bvh() { return this.#nativeParams.get("bvh") ?? undefined; }
|
||||
readonly bvh?: string;
|
||||
|
||||
/**
|
||||
* Initialize the application by retargeting a Mixamo animation onto the
|
||||
* bundled `Mannequin.gltf` model.
|
||||
*/
|
||||
get mixamo() { return this.#nativeParams.get("mixamo") ?? undefined; }
|
||||
readonly mixamo?: string;
|
||||
|
||||
/**
|
||||
* Initialize the application by loading an arbitrary glTF scene from any
|
||||
* source.
|
||||
*/
|
||||
get sceneImport() { return this.#nativeParams.get("sceneImport") ?? undefined; }
|
||||
readonly sceneImport?: string;
|
||||
|
||||
/**
|
||||
* Initialize the application by loading a previously saved Storyteller
|
||||
* Studio scene in `*.scn.ron` format.
|
||||
*/
|
||||
get scene() { return this.#nativeParams.get("scene") ?? undefined; }
|
||||
readonly scene?: string;
|
||||
|
||||
/**
|
||||
* One of:
|
||||
@@ -70,7 +68,7 @@ export class StudioURLParams {
|
||||
* "specular" qualifiers (e.g., "gum_trees_4k").
|
||||
* - A hex-formatted color, without the leading `#` (e.g., "1A1A27")
|
||||
*/
|
||||
get skybox() { return this.#nativeParams.get("skybox") ?? undefined; }
|
||||
readonly skybox?: string;
|
||||
|
||||
/**
|
||||
* Determines whether the app initializes in a minimal, read-only "viewer"
|
||||
@@ -82,6 +80,27 @@ export class StudioURLParams {
|
||||
*
|
||||
* @default StudioMode.Viewer
|
||||
*/
|
||||
readonly mode: StudioMode;
|
||||
}
|
||||
|
||||
export class StudioURLParams implements StudioParams {
|
||||
#_nativeParams?: URLSearchParams;
|
||||
get #nativeParams() {
|
||||
return this.#_nativeParams ??= new URLSearchParams(document.location.search);
|
||||
}
|
||||
|
||||
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") ?? undefined; }
|
||||
|
||||
get mode(): StudioMode {
|
||||
return match(this.#nativeParams.get("mode"), {
|
||||
"studio": () => StudioMode.Editor,
|
||||
|
||||
Reference in New Issue
Block a user