Skip to main content
Glama
IzzyFuller

intentional-masking

by IzzyFuller
README.md
# intentional-masking

MCP server for rendering Ready Player Me avatars with lip-sync using Remotion and React Three Fiber.

## Features

- **render_frame** - Render a single still image of an avatar with expression, pose, camera, and lighting options
- **render_speaking_video** - Render a video of an avatar speaking with real phoneme-based lip-sync from audio

## Requirements

- Node.js 18+
- macOS, Linux, or Windows

## Installation

```bash
cd intentional-masking
npm install
npm run build
```

## Usage

### As MCP Server

Add to your Claude Code configuration (`~/.claude.json` or project `.claude/settings.local.json`):

```json
{
  "mcpServers": {
    "intentional-masking": {
      "command": "node",
      "args": ["/path/to/intentional-masking/dist/server/index.js"],
      "env": {
        "INTENTIONAL_MASKING_ROOT": "/path/to/intentional-masking"
      }
    }
  }
}
```

### MCP Tools

#### render_frame

Render a single still frame of an avatar.

```json
{
  "avatar_path": "/path/to/avatar.glb",
  "expression": "happy",
  "pose": "greeting",
  "camera_preset": "closeup",
  "lighting_preset": "soft",
  "background": "#1a1a2e"
}
```

**Options:**
- `expression`: `neutral` | `happy` | `thinking` | `surprised`
- `pose`: `default` | `greeting` | `listening`
- `camera_preset`: `closeup` | `medium` | `full`
- `lighting_preset`: `soft` | `dramatic` | `natural`
- `background`: Hex color (default: `#1a1a2e`)

Returns: `{ "success": true, "image_path": "/path/to/output.png" }`

#### render_speaking_video

Render an avatar speaking with lip-sync from audio.

```json
{
  "avatar_path": "/path/to/avatar.glb",
  "audio_path": "/path/to/speech.wav",
  "camera_preset": "closeup",
  "lighting_preset": "soft",
  "background": "#1a1a2e"
}
```

**Audio requirements:**
- 16kHz 16-bit mono PCM WAV (as produced by [info-dump](https://github.com/IzzyFuller/info-dump))

Returns: `{ "success": true, "video_path": "/path/to/output.mp4", "duration_seconds": 5.2 }`

## Architecture

```
src/
├── server/
│   ├── index.ts              # MCP server entry point
│   ├── services/
│   │   └── lip-sync.ts       # Rhubarb lip-sync integration
│   └── tools/
│       ├── render-frame.ts   # Still image rendering
│       └── render-speaking-video.ts  # Video rendering
├── config/
│   └── viseme-map.ts         # Rhubarb → RPM morph target mapping
└── remotion/
    ├── index.ts              # Remotion entry point
    ├── Root.tsx              # Composition registration
    ├── AvatarFrame.tsx       # Still frame composition
    ├── AvatarSpeaking.tsx    # Speaking video composition
    └── components/
        ├── Avatar.tsx        # GLB model loader
        ├── Scene.tsx         # Three.js scene setup
        └── LipSyncController.tsx  # Morph target application
```

### Lip-Sync Pipeline

1. **Audio analysis**: [rhubarb-lip-sync-wasm](https://github.com/danieloquelis/rhubarb-lip-sync-wasm) analyzes 16kHz audio
2. **Phoneme mapping**: Rhubarb shapes (A-H, X) → Ready Player Me viseme morph targets
3. **Frame interpolation**: Smooth blending between viseme shapes
4. **Video rendering**: Remotion captures Three.js scene frame-by-frame

### Rhubarb Shape Mapping

| Shape | Phonemes | RPM Morph Targets |
|-------|----------|-------------------|
| A | P, B, M (closed) | viseme_PP |
| B | K, S, T (teeth) | viseme_kk, viseme_nn |
| C | EH, AE (vowels) | viseme_I, viseme_E |
| D | AA (wide open) | viseme_aa |
| E | AO, ER (rounded) | viseme_O, viseme_aa |
| F | UW, OW, W (puckered) | viseme_U |
| G | F, V (teeth-on-lip) | viseme_FF |
| H | L sound | viseme_TH, viseme_nn |
| X | Silence | viseme_sil |

## Integration with info-dump

This server pairs with [info-dump](https://github.com/IzzyFuller/info-dump) for complete TTS → avatar rendering:

```
info-dump generate_audio("Hello!", voice, output_path)
    ↓
intentional-masking render_speaking_video(avatar_path, audio_path)
    ↓
MP4 video with lip-synced avatar
```

## Avatar Requirements

Avatars must be Ready Player Me GLB files with standard viseme morph targets:
- `viseme_aa`, `viseme_E`, `viseme_I`, `viseme_O`, `viseme_U`
- `viseme_PP`, `viseme_FF`, `viseme_TH`, `viseme_DD`, `viseme_kk`, `viseme_nn`, `viseme_sil`

Create avatars at [readyplayer.me](https://readyplayer.me)

## Development

```bash
# Run tests
npm test

# Watch mode
npm run dev

# Preview Remotion compositions
npm run remotion:preview
```

## Environment Variables

- `INTENTIONAL_MASKING_ROOT` - Project root directory (default: cwd)
- `INTENTIONAL_MASKING_OUTPUT` - Output directory for rendered files (default: `{root}/output`)

## License

MIT

TDQS

A3.6/5.0

Scored across 1 tool

Disambiguation5/5

With only one tool, there is no possibility of confusion between tools. The single tool has a clearly defined purpose of rendering an avatar with lip sync.

Naming Consistency5/5

The tool name 'render_video' follows a clear verb_noun pattern, and with only one tool, there are no inconsistencies to evaluate.

Tool Count2/5

The server has only one tool, which feels too few given the implied scope from the server name 'intentional-masking' and the tool's rendering functionality. A single tool is unlikely to cover the expected domain.

Completeness1/5

The server name suggests a broader purpose (e.g., masking), but the only tool is a video renderer. There are no supporting tools for managing, previewing, or configuring renders, leaving the surface severely incomplete for the stated purpose.

Maintenance

ActivityInactive
ResponsivenessNo issues