Single-object viewer POC (#14)

This commit implements a Sketchfab-style single-object viewer as a minimal
proof-of-concept.

### `@storyteller/studio-web`
This is a new package to house web components for interfacing with the
`@storyteller/studio` WASM library. It currently includes a single component,
`<sts-viewer />`, which is exported from `@storyteller/studio-web/viewer`.

### `react-frontend`
This is a new application intended as a proof-of-concept and testbed for React
interop with `@storyteller/studio-web`.

Web components are currently a little bit fiddly to use in a React application.
`react-frontend/src/app/studio-viewer.tsx` demonstrates how a React-idiomatic
component can be written as a thin wrapper around a web component, and
`react-frontend/src/app/app.tsx` demonstrates that wrapper component in use.
This commit is contained in:
Danny McGee
2023-12-07 15:46:32 -05:00
committed by GitHub
parent 155272a5ba
commit cba70a62ae
70 changed files with 71793 additions and 1157 deletions
+14
View File
@@ -131,3 +131,17 @@
}
}
}
.loading {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: #222;
color: #FFF;
font: {
family: "Fira Sans", sans-serif;
weight: 700;
}
}
+29 -4
View File
@@ -5,14 +5,15 @@ import {
type EntityMultiSpawnEvent,
type EntitySelectEvent,
type EntitySpawnEvent,
type SceneStateEvent,
TransformSpace,
TransformType,
ViewportSize,
SceneState,
} from "@storyteller/studio";
import { match } from "@storyteller/utility";
import { LitElement, html, unsafeCSS } from "lit";
import { LitElement, html, nothing, unsafeCSS } from "lit";
import { customElement, state } from "lit/decorators.js";
import { classMap } from "lit/directives/class-map.js";
import "./button.element";
import "./help.element";
@@ -30,6 +31,7 @@ export class AppElement extends LitElement {
static override styles = unsafeCSS(styles);
@state() showHelp = false;
@state() loading = true;
@state() transformSpace = TransformSpace.Local;
@state() transformType = TransformType.Translate;
@@ -80,6 +82,16 @@ export class AppElement extends LitElement {
}));
}
@on("window:scene-state")
onSceneStateChange({ detail: state }: SceneStateEvent): void {
console.log("scene state change:", SceneState[state]);
this.loading = match (state, {
[SceneState.Active]: () => false,
_: () => true,
});
}
@on("window:entity-select")
onEntitySelectionChange({ detail: entity }: EntitySelectEvent): void {
const sceneObject = this.#entityMap.get(entity!);
@@ -178,7 +190,13 @@ export class AppElement extends LitElement {
const width = window.innerWidth;
const height = window.innerHeight;
try {
studio.init(new ViewportSize(width, height));
studio.startViewer(
"couch",
"test_scene",
"#studio_canvas",
"Storyteller Studio",
new ViewportSize(width, height),
);
} catch (err) {
if (!(err as Error).message?.startsWith("Using exceptions for control flow"))
throw err;
@@ -259,7 +277,14 @@ export class AppElement extends LitElement {
${this.showHelp ? html`
<sts-help class="help"></sts-help>
` : null}
` : nothing}
${this.loading ? html`
<!-- TODO: Animated spinner or something -- talk to our designers -->
<div class="loading">
<h1>Loading</h1>
</div>
` : nothing}
`;
}