This PR fixes two issues that can cause a degraded user experience under
certain conditions:
### Focus-stealing
When focus lands on the `document.body`, it's typically bad for
accessibility and a sign of improper input handling. This generally
occurs when the currently-focused element is removed from the DOM. In
our particular case, it also prevents the Bevy application from
correctly handling keyboard events.
Previously, the problem of `document.body` focus had been fixed by
checking the `document.activeElement` every frame, and redirecting focus
to the Bevy canvas whenever it landed on the `document.body`. However,
when running in an iframe embedded on https://fakeyou.com, our
application will report `document.body` as the `document.activeElement`
whenever the parent application has focus, effectively stealing focus
from the parent application and making it impossible for the user to,
e.g., interact with text fields in the parent app.
This PR removes that focus-stealing behavior. Instead, we should
properly implement the ARIA specifications for any elements that may
disappear from the DOM so that user focus is managed in a precise and
predictable way. That will be addressed in follow-up PRs.
### "Stuck" input states
In certain circumstances, the browser window hosting our application may
lose focus while certain keys/buttons are held down which are bound to
long-running actions in the Bevy application, like camera manipulation.
When that occurs, Bevy is unable to detect when the bound keys/buttons
are released, causing the input state to become "stuck" reading those
keys/buttons as being pressed.
As a workaround, this PR introduces a listener for "blur" events on the
`window`, which dispatches synthetic "keyup"/"pointerup" events to the
Bevy canvas for all affected keyboard keys and mouse buttons.
This PR updates the Transform > Rotation section of the Entity Inspector
to display Euler angles in degrees instead of the vector component of
the input quaternion.
Additionally, this updates the `studio/ui/inspector` module to add a
special-case function for updating the selected entity's rotation from
the inspector in a way that's consistent with the behavior of the
rotation gizmo.
### Known Issues
The values displayed for the angles in the inspector are not always
intuitive, especially while actively manipulating them. To some extent
this is just the nature of Euler angles (e.g., Unreal Engine exhibits
similar issues), but I suspect there's room for improvement of our
implementation (e.g., Unreal's rotation display is typically _more_ sane
than ours).
Regardless, fixing this requires a firmer grasp of the math than I
possess, so a fix for this issue is not currently planned.
Issue turned out to be that in some circumstances, the `group_by` iterator will create multiple groups for a single key - and sometimes those groups can be empty. This lead to situations where an animation track will end up empty until enough changed to re-shuffle things in the query iterator.
The fix is switching to `into_group_map_by` - which will put all grouped items into a hashmap instead, ensuring no duplicate keys.
This PR adds Material component inspection to the frontend Entity
Inspector, and adds functional editing capabilities for the Transform
and Material inspectors.
### Changes
* Added a `ScalarFieldElement` for numeric form fields, with a hybrid
slider/text-input UX inspired by Blender, Unreal Engine, etc.
* Added `MaterialInspectorElement` for inspecting the Bevy
`StandardMaterial` component
* Wired up the `TransformInspectorElement` and
`MaterialInspectorElement` to apply changes made in the UI to the Bevy
scene
* Refactored the `studio/ui/inspector` module to output `Result::Err`s
to the dev console
* Refactored the `studio/interaction/selection` module to use only the
`Selection` resource, removing the redundant `Selected` component which
added some unnecessary complexity. This fixes#39
* Fixed primitive shapes not receiving a selection outline when selected
### To-Do
These tasks will be addressed in a forthcoming PR:
* The **Transform** > **Rotation** section in the inspector is still not
displaying sensible values. Currently it's just displaying the raw
quaternion `xyz` vector rather than displaying the orientation in
human-readable terms (e.g., as Euler angles).
* We're currently ignoring the Primitive Shape component, which would
allow the user to configure some additional geometric properties of the
shape or replace it with a different one.
---------
Co-authored-by: rewin <rewin1996@gmail.com>
…to avoid re-processing timeline info
- move generating animation to first thing in a frame, and notifying
about timeline changes to last, to ensure that it happens before the
time updates
- re-generate the animation tweens whenever you start playing or
manually seek a new time in the timeline to prevent inconsistencies
The `window.showSaveFilePicker()` is used in development to save
`scn.ron` files. Since it's not defined in the source, it's breaking
Netlify production builds. I'm commenting this out for now so we can
unblock production builds, but feel free to restore this
code/functionality for local testing.
This PR adds a system to find animation clips in imported glTF scenes
and auto-play them on their associated entities.
The new system runs only in "Viewer" mode, for the purposes of
previewing a scene import on its Storyteller.ai Media File page. In
"Editor" mode, we will eventually expose animation clips to the user
through some other mechanism (TDB -- needs design work, grooming,
etc.).
This PR overhauls the Dialog abstractions in `studio-ui` to be more
flexible for a wider variety of use cases, and adds a placeholder
"Import Asset" sub-dialog to the Media Library dialog.
Problems with the previous code:
- `async-compat` is necessary for headless mode (cli server rendering)
to load remote scenes from the API without blowing up. Without it, the
code complains about the lack of a Tokio runtime.
- Unfortunately, `async-compat` doesn't work with WASM and the entire
web build is broken by its presence.
This change introduces conditional compilation so `async-compat` is only
leveraged in headless mode.
This PR adds an initial animation timeline.
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Danny McGee <dannymcgee@gmail.com>
This PR adds a new "Add to Scene" dropdown menu for adding elements to
the current scene, and a new Media Library dialog for importing and/or
adding Storyteller Engine assets (characters, scenes, animations, etc.)
associated with the user's Storyteller.ai account.
The scope of this PR is limited to the UI — actual asset importing
behavior, and adding elements other than primitive shapes to the current
scene, will be implemented in follow-up PRs.
### Technical Details
In order to facilitate these changes, a new "overlay" abstraction has
been added to `@storyteller/studio-ui` (loosely modeled after
[`@angular/cdk/overlay`](https://material.angular.io/cdk/overlay/overview))
for managing DOM elements which should render in a self-contained
stacking context "above" the rest of the application.
Two new base UI components — `<sts-menu>` and `<sts-dialog>`
— have also been added to make use of this overlay system, but
it's worth noting that these new components have not yet been
exhaustively tested or thoroughly fleshed out, so they may require
significant changes in order to accommodate future use cases or address
unforeseen bugs.
### Testing
The Media Library makes some API calls which will run into CORS errors
in a normal browser. This can be bypassed by running Chrome with the
following command-line flags:
```
--disable-web-security --ignore-certificate-errors --user-data-dir=path/to/some/temporary/directory
```
Verify all of the following:
* The "Add to Scene" menu opens and closes as expected
* The primitive-shape menu items (Cube, Sphere, etc.) add the
corresponding elements to the scene
* The "Media Library..." menu item correctly opens the Media Library
dialog
* The Media Library's search bar and category filters work as expected
* A single asset can be selected by clicking on it
* Multiple assets can be selected by holding the "Ctrl" or "Cmd" key
* The selection can be cleared by clicking in an empty space in the
results grid
* An "Add to Scene" button appears if (and only if) one or more assets
are selected
* The Media Library dialog can be closed by:
- Clicking the "X" in the upper right-hand corner
- Pressing the "Esc" key
- Clicking anywhere outside of the dialog boundaries
Additionally, ensure that the Media Library dialog handles all of the
following situations gracefully:
* User is not logged in to fakeyou.com
* User is logged in but does not have any engine-compatible assets
uploaded (this can be tested by selecting any of the categories from the
sidebar, since the database has not yet been migrated to use the new
`media_file_class` field, so all of those categories should currently
yield an empty list)
* User is logged in and there are engine-compatible assets to list (this
can be tested by pressing the "Save" button in the main application
toolbar to save the current scene to your account, and selecting the
"Home" entry from the Media Library sidebar)
This PR adds the camera motions to the composite mode. There are
currently 4 camera motion modes: `Orbit`, `Static`, `Pan`, `Zoom`. They
are accessed by using the `--camera-motion [motion]` argument. For
example, if I want to render a scene with an orbiting motion, I would do
the following:
`studio-headless scene --camera-motion orbit scene.ron `
Some things to note:
- The argument `--orbit` no longer is there. It has been deprecated!
- Currently the speed is hard coded. This can be set as a command arg
later.
- This only works with scenes, as this is intended for the `sample-room`
scene. May not work great for other scenes
Let me know if there is anything that I can fix!
This PR attempts to avoid bankrupting the company by running 15 minutes
of unit tests on unchanged code or re-downloading
`@fortawesome/fontawesome-pro` 5 times for every PR commit.
This PR adds the Scaling Gizmo to the StoryTeller Engine.
Features
- Objects can now be scaled by Axis or Plane
Limitations
- Currently there is no implementation for combining the scale gizmo
with any of the other gizmo. This should be amended with further PRs.
Let me know if there is anything that I missed!
---------
Co-authored-by: Danny McGee <dannymcgee@gmail.com>