bible-strong-avatar-lab/packages/avatar-react
Eric Cappannelli 99300b3b30 feat(runtime): ship semantic avatar packages and Studio export
- add the v1 AvatarDefinition schema, bounded parser, strict validation, semantic catalog, pure geometry, scene generation, and deterministic playback to @bible-strong/avatar-core
- add the React 19 renderer with semantic controls, SSR-safe embedded/floating layouts, direct frame updates, pointer and keyboard movement, constraints, callbacks, and accessible controls
- add real tarball packaging and a clean React/Vite consumer using the exported Strobi definition
- add Studio semantic-key authoring, runtime readiness, JSON download/copy, bundled-key recovery, concise errors, targeted local-project clearing, npm guidance, syntax highlighting, and a runnable package preview
- preserve the historical ZIP and Studio project exports, regenerate the standalone engine, and synchronize English, French, and Simplified Chinese copy
- add focused contract, playback, renderer, interaction, persistence, export, and localization coverage
- archive the completed runtime and semantic-curation specs, retain the Vite performance draft, and record the engineering session in TIMELOG.md

Validation:
- pnpm check: 19 test files, 162 tests, typecheck, engine freshness, package builds, and Studio production build passed
- npm pack dry runs: 30 core files and 10 React files
- package smoke: real tarballs installed, typechecked, and built outside the workspace
- browser checks: semantic playback, embedded/floating render, drag, mobile overflow, runtime export recovery, formatted copy, syntax colors, and live package preview

Publication remains disabled: both packages stay private and AGPL-3.0-only pending licensing and repository metadata approval. Vue and Angular adapters remain deferred.
2026-08-16 10:18:39 +02:00
..
src feat(runtime): ship semantic avatar packages and Studio export 2026-08-16 10:18:39 +02:00
LICENSE feat(runtime): ship semantic avatar packages and Studio export 2026-08-16 10:18:39 +02:00
package.json feat(runtime): ship semantic avatar packages and Studio export 2026-08-16 10:18:39 +02:00
README.md feat(runtime): ship semantic avatar packages and Studio export 2026-08-16 10:18:39 +02:00
tsconfig.build.json feat(runtime): ship semantic avatar packages and Studio export 2026-08-16 10:18:39 +02:00
tsconfig.json feat(runtime): ship semantic avatar packages and Studio export 2026-08-16 10:18:39 +02:00
vite.config.ts feat(runtime): ship semantic avatar packages and Studio export 2026-08-16 10:18:39 +02:00

@bible-strong/avatar-react

React 19 renderer for a validated Bible Strong AvatarDefinition. React and React DOM 19 are peer dependencies; @bible-strong/avatar-core is installed as a normal dependency.

Install

pnpm add @bible-strong/avatar-react react react-dom

Import the package stylesheet once in the application entry point:

import { Avatar, type AvatarController } from '@bible-strong/avatar-react'
import type { AvatarDefinition } from '@bible-strong/avatar-core'
import '@bible-strong/avatar-react/styles.css'
import { useRef } from 'react'

export function Assistant({ definition }: { definition: AvatarDefinition }) {
  const avatar = useRef<AvatarController>(null)
  return (
    <>
      <Avatar ref={avatar} definition={definition} defaultAnimation="idle" />
      <button onClick={() => avatar.current?.play('happy')}>Play happy</button>
      <button onClick={() => avatar.current?.setExpression('neutral')}>Neutral</button>
    </>
  )
}

play and setExpression return { ok: true } or a typed error with one of unknown_animation, unavailable_standard_animation, unknown_expression or controlled_by_props. pause freezes the exact timeline position, calling play with the paused key resumes it, and stop returns an uncontrolled avatar to neutral.

Playback props

  • animation and expression are mutually exclusive controlled targets. They take priority over defaults and imperative target changes.
  • defaultAnimation and defaultExpression initialize uncontrolled use. Animation autoplay is on by default when defaultAnimation is present; set autoplay={false} to show its first expression statically.
  • onAnimationEnd fires once when a once animation completes naturally.
  • onExpressionChange reports semantic expression changes.
  • size, className, style and ariaLabel customize layout without changing the definition.

The definition is validated once per immutable object reference and revalidated/reinitialized when that reference changes.

Embedded and floating layout

Embedded mode is the default and stays in the caller's layout:

<div className="assistant-zone">
  <Avatar definition={definition} animation="idle" />
</div>

Floating mode uses fixed positioning and portals to document.body after hydration. Supply portalContainer for a dedicated overlay root. Server rendering emits a neutral fixed-size placeholder before the portal handoff.

<Avatar
  definition={definition}
  mode="floating"
  draggable
  initialPosition={{ right: 24, bottom: 24 }}
  constrainTo="viewport"
  zIndex={1000}
/>

initialPosition accepts { x, y } or top/right/bottom/left anchors. A controlled position wins over it. constrainTo accepts none, viewport or parent; floating defaults to viewport, while embedded defaults to none. A constrained embedded parent needs a definite rendered size.

Dragging uses Pointer Events and direct transforms. onPositionPreview is limited to one callback per animation frame and onPositionCommit reports the final clamped point. onDragStart and onDragEnd bracket pointer movement. In controlled position mode callbacks report suggestions but the supplied position remains authoritative. When resized bounds invalidate a controlled position, onPositionChange reports the clamped suggestion. Resize re-clamping never emits a movement commit.

When draggable is enabled, arrow keys move by 10 px, Shift+Arrow by 1 px, and Escape cancels an active pointer drag. Accessible directional and reset buttons provide the same movement without a pointer.

Styling hooks

The stylesheet exposes .bs-avatar, .bs-avatar--embedded, .bs-avatar--floating, .bs-avatar--draggable, .bs-avatar--dragging, .bs-avatar__svg and .bs-avatar__move-controls. Consumer className and style are applied to the outer wrapper.

The public component never exposes Studio IDs or document types. This package is private while copyright ownership, Apache-2.0 relicensing and repository metadata are confirmed. Local tarballs are for verification only and must not be published.