Starting State
Run this from the vizij-web root:
cd path/to/vizij-web
pnpm run dev:tutorial-fullscreen-faceOpen the local Vite URL if it is not already open.
This page assumes you already completed Hello Face Quickstart and have the face rendering locally.
The Two Control Patterns You Are Learning
This app teaches two useful control ideas immediately:
- a held expression: a key fades one of the face standard’s expression weights in, and back out on release
- a played viseme: a key calls one of the face’s methods, which plays a mouth shape once
Both drive the face through its own API. One writes a key the app owns for as long as the key is held; the other asks the face to do something over time, and the face writes the keys itself.
Quick term bridge before you continue:
standard controlmeans a key of the Vizij face standard, such asstandard/vizij/expression/happy, the same on every face.methodmeans a function the face’s device declares, such asplay_viseme, called by name withruntime.invoke(...).pathmeans the runtime address a write lands on, not the visible UI widget itself.
What This Page Is Not Proving Yet
This page proves that the runtime can accept different kinds of control.
It does not yet prove:
- that you have an application integration shell,
- that you have authored new behavior,
- that you have a deployment endpoint,
- that every control category in Vizij behaves the same way.
Walkthrough
1. Confirm runtime readiness before testing control
Do not test control while the app is still loading.
Wait until:
- the face is fully visible
- the loading bar over the face is gone
- moving the pointer over the page shows the key hints
Why this matters:
- the hotkeys bind only once the provider reports the face
ready - the hints list the keys the app bound, so their presence proves the face’s profile was read
- a visible face is not automatically a ready control surface
If you are not confident the app is healthy yet, go back to Hello Face Quickstart or check Validation Checkpoints.
2. Hold an expression key
Hold one of the expression keys (1–0, Q–P, A–J), then release it.
Expected result:
- the expression fades in over about two seconds while the key is held
- it fades back out over the same time once released
- repeated presses work consistently
Open:
vizij-web/apps/tutorial-fullscreen-face/src/hooks/useFaceHotkeys.ts
What to look for:
- the hook reads the face standard’s profile,
vizij-face, and binds its expressions in the profile’s order - a key press tweens
runtime.path("standard/vizij/expression/<name>")to 0.75 withanimateValue(...), and the release tweens it back to 0 - the write targets the standard’s key, not one of this face’s own poses: the face’s standard adaptation maps it onto Quori’s poses
The important mental model is simple: the app owns the expression’s weight, and a tween writes it once per frame.
3. Press a viseme key
Press one of the viseme keys (K, L, Z–M). They play the first nine of the standard’s 15 visemes, sil to nn; the other six have no key.
Expected result:
- the mouth takes the shape once, then returns
- holding the key does not hold the shape
- repeated presses replay it
What to look for in the same hook:
- a key press calls
runtime.invoke("play_viseme", { shape, weight }) - the face’s viseme player writes the standard’s viseme keys (
standard/vizij/viseme/<shape>) through its lipsync envelope, so the app writes no viseme key itself - the release does nothing: a viseme is played, not held
The mental model here is different: a key press asks the face to play something, and the face owns the keys it writes while it plays.
4. Compare the two control styles directly
Use this comparison while the app is open:
| Interaction | What you do | What changes visibly | Runtime meaning |
|---|---|---|---|
| Expression key | hold and release a key | an expression fades in and out | the app tweens a key of the face standard |
| Viseme key | press a key | the mouth takes one shape | the app calls a method; the face writes the viseme keys |
This is the first important control lesson in Vizij:
- not every control is the same kind of write
- writing a key and calling a method are both valid, but they solve different problems
- later pages explain the path grammar and semantics behind these interactions
With ?autoplay added to the URL, the face’s own program also runs from load and moves the face between your key presses: a third writer, which the app commands through the keys the program reads.
5. Inspect the code shape that makes both patterns work
You have already seen the behavior in the browser. Now connect it to the runtime API surface:
useFaceHotkeys.tsusesuseAnimateValue()for the held expressions- the same hook calls
runtime.invoke("play_viseme", …)for the visemes - both depend on the same
VizijRuntimeProvideranduseVizijRuntime()foundation fromFaceApp.tsx
That common foundation matters. Vizij control is not a pile of unrelated tricks. The runtime stays consistent while the control semantics change.
What You Should Be Able To Say Now
By the end of this page, the correct short explanation is:
- an expression key is a held write to a standard control
- a viseme key is a method call the face plays out over time
- both go through the face’s runtime API
- they differ because one writes a key and the other asks the face to write keys
Fast Recovery If It Fails
Use these shortcuts:
- if the face is visible but no hints show, compare the current app state with Hello Face Quickstart
- if hotkeys do nothing, verify the app finished loading before testing
- if you need a route-level definition of healthy behavior, use Validation Checkpoints
- if the runtime reaches an error state, use Troubleshooting Matrix
Recommended Next Steps
Continue to Paths and Standard Controls.
That page names the path vocabulary underneath the expression and viseme interactions you just used.
Use these branch points after that:
- If you want to stay on the fast route toward embedding, continue later to Minimal Web Player.
- If you want to start owning the face after the control model is clear, branch to Tweak an Existing Face.