Skip to content

Add keyframe animation pipeline and translation quality improvements - #2

Merged
mrlucas679 merged 8 commits into
mainfrom
claude/festive-cannon
Jul 5, 2026
Merged

Add keyframe animation pipeline and translation quality improvements#2
mrlucas679 merged 8 commits into
mainfrom
claude/festive-cannon

Conversation

@mrlucas679

Copy link
Copy Markdown
Owner

Summary

  • Keyframe animation engine: signs_library.js and avatar.js now support real motion-capture keyframe sequences via signWithFrames(). The TransitionEngine plays through multi-frame curves when data is available, falling back to the existing SLERP path for all 284 hand-crafted signs (fully backward-compatible).
  • Data pipeline: convert_signs.py upgraded to extract full frame sequences using angular-displacement keyframe selection (30fps → 8–12 keyframes). Two new scripts: scripts/record_signs.py (MediaPipe webcam recorder) and scripts/merge_sign_data.py (merge tool that generates signs_library_generated.js without touching the source library).
  • Translation quality: 5 new SASL grammar rules added (classifier predicates, SASSes, topicalization, plurality via MANY, spatial loci). LLM translation now scores sign coverage and retries with a conservative prompt when <70% of tokens have known signs. sign_coverage and fingerspelled_words are now surfaced in API responses and WebSocket broadcasts.

Test plan

  • Load the app — all existing signs animate as before (SLERP path unchanged)
  • Add a test sign via signWithFrames() with 3 keyframes and verify the avatar traces through the intermediate pose
  • Run python convert_signs.py --inspect <pkl> against a SignAvatars .pkl and confirm output has frames array with 8–12 entries
  • Run python scripts/record_signs.py, record a sign, confirm output JSON matches the converter format
  • Run python scripts/merge_sign_data.py --data poses.json --output signs_library_generated.js --report and verify the coverage table
  • Send "I need help" via the hearing window and confirm sign_coverage ≥ 0.7 in the response (no retry logged)
  • Send a sentence with rare medical vocabulary and confirm the conservative retry is logged and fingerspelled_words is populated

🤖 Generated with Claude Code

Animation engine (signs_library.js, avatar.js):
- Add signWithFrames() factory, prebakeFrameQuats(), findFrame(), and
  slerpBetweenFrames() to support real motion-capture keyframe sequences
- TransitionEngine.tick() now has a dual path: plays through keyframe
  curves when .frames is present, falls back to SLERP for existing signs
- avatar.js respects per-sign .duration and wires sign-level NMM data
  (browLift, headNod, etc.) through existing setNMMs() automatically
- All 284 hand-crafted signs are fully backward-compatible

Data pipeline (convert_signs.py, scripts/):
- convert_signs.py v2.0 extracts full frame sequences (not just peak frame)
  using angular-displacement keyframe selection (30fps → 8–12 keyframes)
- scripts/record_signs.py: new MediaPipe Holistic webcam recorder that
  outputs keyframes in the same format as the converter
- scripts/merge_sign_data.py: merge tool that generates
  signs_library_generated.js from real data without touching the source

Translation (sasl_transformer/, backend/):
- grammar_rules.py: 5 new SASL rules (classifiers, SASSes, topicalization,
  plurality via MANY, spatial loci) + uncertain token flag
- models.py: GlossToken.uncertain field; TranslationResponse gains
  sign_coverage and fingerspelled_words
- transformer.py: coverage scoring + conservative LLM retry when <70%
  of tokens have known signs
- backend/main.py and WebSocket broadcast now surface sign_coverage and
  fingerspelled_words to the frontend

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 5, 2026 12:02

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds support for real keyframed sign animation (motion-capture/recorded sequences) and improves SASL translation quality/metadata surfaced to clients.

Changes:

  • Added keyframe-capable sign factory/utilities and extended TransitionEngine to play sign-internal frame sequences when available.
  • Introduced data tooling: upgraded convert_signs.py to output keyframes + duration, plus new record_signs.py (MediaPipe recorder) and merge_sign_data.py (override generator).
  • Improved translation robustness: added new grammar rules, introduced uncertain tokens, computed sign_coverage, and exposed fingerspelled_words via REST/WebSocket.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
src/windows/deaf/avatar.js Applies sign-level NMM markers and uses sign-provided duration for hold time.
signs_library.js Adds keyframe interpolation helpers and keyframe playback mode in TransitionEngine.
scripts/record_signs.py New webcam recorder producing keyframe JSON compatible with the keyframe sign format.
scripts/merge_sign_data.py New tool to generate a JS overrides layer for real-data frames/durations.
sasl_transformer/transformer.py Adds coverage-based conservative retry + uncertain handling and coverage/fingerspell metadata.
sasl_transformer/models.py Extends response/token models with uncertain, sign_coverage, fingerspelled_words.
sasl_transformer/grammar_rules.py Adds new SASL grammar guidance and JSON output schema updates (uncertain flag).
convert_signs.py Upgrades converter to extract all frames and downsample to keyframes with durations.
backend/requirements.txt Adds MediaPipe/OpenCV deps for recording script usage.
backend/main.py Surfaces sign_coverage and fingerspelled_words in API and WebSocket payloads.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread signs_library.js Outdated
Comment thread signs_library.js Outdated
Comment thread signs_library.js
Comment thread scripts/merge_sign_data.py
Comment thread scripts/merge_sign_data.py
Comment thread scripts/merge_sign_data.py
Comment thread convert_signs.py
Comment thread sasl_transformer/transformer.py
mrlucas679 and others added 7 commits April 5, 2026 14:12
Five jobs:
  - python-lint: ruff on backend/, sasl_transformer/, scripts/ and convert_signs.py
  - python-tests: pytest tests/ (rule-based tests, no API key required)
  - python-imports: smoke-import of all new modules (sasl_transformer, convert_signs)
  - js-syntax: node --check on signs_library.js, avatar.js, src/main.js
  - signs-library-check: Node script that verifies all required exports exist,
    sign count ≥ 200, TransitionEngine methods, and findFrame() correctness

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rors

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Ignore E402/F601/W292 — pre-existing issues in backend files not
  introduced by this PR
- Write check_lib.js to GITHUB_WORKSPACE instead of /tmp so
  require('./signs_library.js') resolves correctly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- convert_signs.py: remove unused 'os' import, fix bare f-strings (F541)
- merge_sign_data.py: fix bare f-strings (F541)
- record_signs.py: remove unused 'os'/'time' imports (F401), remove
  assigned-but-never-used body_front variable (F841)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Merge resolution:
- Take main's modular backend (routers/, services/, ws/) as base of truth
- Port sign_coverage + fingerspelled_words into sasl_pipeline, ws handler,
  and speech router (previously in the old monolithic backend/main.py)
- Rewrite conservative coverage retry to use Ollama (main removed Gemini;
  the old settings.gemini_api_key access would have crashed translate())
- Enrich rule-based translations via translate_with_rules() so coverage
  metadata is accurate on the fallback path
- backend/requirements.txt deleted (main moved deps to root); mediapipe +
  opencv-python appended to root requirements.txt for the sign recorder

Copilot review fixes:
- TransitionEngine: transition INTO the first keyframe before playing
  frames, then mark done (was: frames first, then SLERP backwards)
- TransitionEngine._interpolate: target first-keyframe handshape when
  entering a keyframed sign (was lerping toward the last frame's hand)
- findFrame(): clamp t beyond first/last frame; clamp localT to [0,1]
- signWithFrames(): validate durationMs > 0, frame shape; sort by t
- merge_sign_data: generated overrides now retarget R/L and _Rq/_Lq
  start/end from first/last keyframes and sort frames before prebake
- merge_sign_data: fix invalid '}},'  emitted per sign (broken JS output)
- convert_signs: propagate .pkl basename into output 'source' metadata
- write_generated_library docstring matches actual behaviour
- print_coverage_report uses all_sign_names as fallback name set
- tests/test_coverage_enrichment.py: 7 tests for uncertain-token
  fingerspelling and sign_coverage ratios

Windows + CI robustness:
- Scripts reconfigure stdout to UTF-8 on cp1252 consoles (crash fix)
- test_e2e_pipeline skips with clear message when a stale backend
  without /auth/session-secret occupies port 8000
- CI: sign-count threshold 200 -> 100 (main consolidated the library),
  lint tests/ too, read scripts with explicit utf-8
- Remove dead imports / bare f-strings across backend and scripts (ruff)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mrlucas679
mrlucas679 merged commit 49e761b into main Jul 5, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants