openalice-anim
[Atlas card](https://atlas.blal.pro/repos/openalice-anim)
Architecture rating
Strong substrate adoption — manifest 100/valid, drift 90, declared docker_image + ws/http endpoints all match; only blemish is MODELS_DIR used but undeclared in env manifest.
Prometheus /metrics and /health probes both exposed in the manifest (good), but 10 console/print statements signal unstructured logging and no tracing is evident; health probe itself currently reports down (no https endpoint).
AGENTS.md + valid manifest with clear summary and 8 @feature annotations (features 84) carry it, but README is a bare Atlas-card stub, 27 docstrings missing, and roadmap is weak (30/100).
PFNN procedural-locomotion fallback gives graceful degradation when ZeroEGGS ONNX fails and warm_session pre-warms inference, but 5 broad excepts, one god-module (max complexity 18), and no evidence of SIGTERM graceful shutdown, request timeouts, or idempotency on the stream.
Stateless by design — owns no tables, no DB/migrations/RLS, no persisted PII; correct for a mel→pose streamer, but there is simply no data-layer surface to credit so graded conservatively.
Internal WS service on :3990 with /health + /metrics but no visible authn/authz on the session stream, no rate-limit, and 5 bare/broad excepts; MODELS_DIR loads model files with no declared validation — low attack surface but zero explicit guards.
Only 2 test files (test_protocol.py, test_zeggs_pipeline.py) against 8 features and gesture/locomotion/lipsync/style modules; 9 unreferenced module classes suggest pipeline wiring and fallback paths are largely untested despite green CI.
source · auto-grader-2026-06-16
Ecosystem manifest
.atlas-deps.ymlMel-spectrogram → VRM pose stream: ZeroEGGS ONNX gesture synthesis + PFNN procedural locomotion fallback, served over WebSocket to openalice-persona.
- via INTERNAL_SECRETPersona renderer connects to /v1/sessions/{sid}/stream to consume PoseFrame + BlendshapeFrame at tick rate.
- via INTERNAL_SECRETRelays LipsyncFrame markers from openalice-voice to anim sessions and forwards IntentFrame / NavigateFrame directives from the agent loop.
- via wsStreams LipsyncFrame tokens (grapheme offset + viseme) into the session so gesture rhythm and mouth blendshapes are driven by the spoken token timeline.
- ANIM_PORT
- INTERNAL_SECRET
- OTEL_EXPORTER_OTLP_ENDPOINT
- OTEL_SERVICE_NAME
- docker_image: openalice-anim
- ws_endpoint: ws://<host>:3990/v1/sessions/{sid}/stream
- http_endpoint: http://<host>:3990/health
- http_endpoint: http://<host>:3990/metrics
Atlas grepped the repo's source for env reads (rust env::var · ts process.env · py os.environ · shell $VAR) and diffed against the manifest's consumes_env. Two lists below: stale declarations and undeclared reads.
- MODELS_DIR
Code composition
tokei · loc- Python95.4%
- Shell2.1%
- TOML1.9%
- Dockerfile0.7%
- Python95.4%
- Shell2.1%
- TOML1.9%
- Dockerfile0.7%
- Python95.4%· 1,440
- Shell2.1%· 31
- TOML1.9%· 29
- Dockerfile0.7%· 10
| Language | % code | code | comments | blanks | files |
|---|---|---|---|---|---|
| Python | 95.4% | 1,440 | 145 | 253 | 16 |
| Shell | 2.1% | 31 | 21 | 6 | 1 |
| TOML | 1.9% | 29 | 8 | 4 | 1 |
| Dockerfile | 0.7% | 10 | 0 | 6 | 1 |
| Markdown | 0.0% | 0 | 165 | 72 | 3 |
Telemetry ribbon · last 90 days
4 eventsanim/audio
1 feature- anim.audio.mel-extractoropenalice_anim/audio_features.py:6Pure-NumPy 81-dim mel feature extractor (80 log-mel bands + per-frame RMS energy) matching ZeroEGGS preprocessing. No librosa/torchaudio dep; cached filter bank; correct STFT hop gives 80 fps feature rate at 16 kHz input.
anim/blend
1 feature- anim.blend.priority-mergeopenalice_anim/blender.py:4Three-layer bone priority merge: locomotion owns the lower body (root + legs), gesture/ZeroEGGS override the upper body (arms, shoulders), lipsync owns mouth + emotion blendshapes. Override wins on key collision — no quaternion averaging — preventing unnatural drift when competing pose sources name the same bone.
anim/core
2 features- anim.core.graceful-stub-degradationopenalice_anim/__init__.py:19Every synthesis module (gesture, locomotion, lipsync) falls back to identity-pose stubs when its ONNX weight file is absent. The WS protocol contract is fully exercisable with zero model files — critical for CI and cold-start scenarios.
- anim.core.ws-pose-streamopenalice_anim/__init__.py:13Real-time avatar animation via WebSocket: inbound audio/intent/ navigate/tick frames are synthesised into VRM-compatible PoseFrame + BlendshapeFrame messages at up to 60 Hz, consumed by openalice-persona's AvatarAnimator without pre-baked clip data.
anim/gesture
2 features- anim.gesture.rest-pose-calibrationopenalice_anim/zeggs_pipeline.py:15Runs the ZeroEGGS decoder for REST_CALIBRATION_FRAMES (16) silent frames at session start to let the GRU settle, then captures per-VRM-bone rest quaternions. Runtime rotations are expressed as q_delta = q_now * q_rest^-1 so the VRM stays in its own bind pose (not ZEGGS's Mixamo rest) when the agent is silent.
- anim.gesture.zeroeggs-pipelineopenalice_anim/zeggs_pipeline.py:8Full ZeroEGGS (Ubisoft La Forge, Apache-2.0) inference pipeline: speech_encoder → style-conditioned decoder → 75-bone Mixamo skeleton retargeted to 18 VRM 1.0 humanoid bones. Per-session stateful GRU hidden state + rest-pose calibration so the avatar returns to its own rest pose during silence.
anim/locomotion
1 feature- anim.locomotion.pfnn-procedural-fallbackopenalice_anim/modules/locomotion.py:3Two-path locomotion: PFNN ONNX (Holden et al. 2017 Phase-Functioned Neural Network) when weights are present; sinusoidal foot-cycle procedural fallback otherwise. Procedural path drives root yaw + hip/knee/ankle pitch from speed and a heading-smoothed root quaternion, giving visible walking motion without any model files.
anim/transport
1 feature- anim.transport.ws-session-securityopenalice_anim/main.py:3WebSocket sessions enforce an optional shared-secret token check (?token=<INTERNAL_SECRET>) matching the live-control auth pattern, plus a 32 KB per-frame size cap that closes the unbounded receive_json DoS vector. Binary frames are rejected with WS 1003; oversized text frames with WS 1009.