AgentSkillsCN

annotation-camera

熟练运用 3D 注释相机系统。当您需要添加注释、调整相机行为、创建标记点,或优化相机对骨骼/网格的聚焦方式时,可调用此技能。该技能涵盖 AnnotationCameraController、AnnotationMarkers、Annotation3DMarkers 以及各类注释预设。

SKILL.md
--- frontmatter
name: annotation-camera
description: Work with the 3D annotation camera system. Use when adding annotations, modifying camera behavior, creating markers, or adjusting how the camera focuses on bones/meshes. Covers AnnotationCameraController, AnnotationMarkers, Annotation3DMarkers, and annotation presets.
allowed-tools: Read, Write, Edit, Glob, Grep

Annotation Camera System

The annotation camera system provides interactive 3D navigation for character models, with clickable markers that focus the camera on specific body parts.

Architecture Overview

code
AnnotationCameraController (main orchestrator)
├── OrbitControls (mouse interaction)
├── AnnotationMarkers (HTML-based labels) OR Annotation3DMarkers (3D geometry)
├── CameraDOMControls (dropdown selector)
└── Annotations config (per-character presets)

Key Files

FilePurpose
src/camera/AnnotationCameraController.tsMain controller - camera animation, focus logic, marker coordination
src/camera/Annotation3DMarkers.ts3D geometry markers with spheres and lines on mesh surface
src/camera/DOMControls.tsDropdown UI for annotation selection
src/camera/types.tsTypeScript interfaces for annotations and config
src/presets/annotations.tsCharacter-specific annotation definitions

Annotation Interface

typescript
interface Annotation {
  name: string;              // Display name (snake_case recommended)
  bones?: string[];          // Bone names to focus on
  meshes?: string[];         // Mesh names to focus on
  objects?: string[];        // Any object names (use ['*'] for all)
  paddingFactor?: number;    // Zoom padding (1.0 = tight, 2.0 = loose)
  cameraAngle?: number;      // Y-axis rotation (0=front, 90=right, 180=back, 270=left)
  cameraOffset?: { x?, y?, z? }; // Fine-tune camera position
}

Adding a New Annotation

  1. Open src/presets/annotations.ts
  2. Find the character config (e.g., JONATHAN_ANNOTATIONS)
  3. Add to the annotations array:
typescript
{
  name: 'left_shoulder',
  bones: ['CC_Base_L_Clavicle', 'CC_Base_L_Upperarm'],
  paddingFactor: 1.4,
  cameraAngle: 270,  // View from left side
}

3D Markers

All markers are pure 3D geometry (no HTML overlays):

  • Sphere dots placed on mesh surface via raycasting
  • 3D lines extending outward from the surface
  • Sprite labels (canvas-rendered text billboards) at line endpoints
  • Markers rotate with the model and have proper depth
  • Click detection via 3D raycasting

Camera Focus Methods

typescript
// Focus on named annotation
controller.focusAnnotation('left_eye', 800);

// Focus on specific bones
controller.focusBones(['CC_Base_L_Hand'], 800);

// Focus on meshes
controller.focusMeshes(['CC_Base_Eye'], 800);

// Focus on full body
controller.focusFullBody(800);

Camera Angle Convention

AngleView Direction
0Front (default)
90Right side
180Back
270Left side

Padding Factor Guidelines

Target SizeRecommended Padding
Eyes, mouth1.2 - 1.5
Head, hands1.3 - 1.6
Upper body1.5 - 1.8
Full body2.0 - 2.5

CRITICAL: Skinned Mesh Positioning

Skinned meshes (eyes, teeth, tongue, etc.) have their geometry at world origin (0,0,0). The mesh is positioned by the skeleton bones at runtime.

Consequence for Annotations

  • NEVER use meshes alone for skinned mesh parts - the marker will appear at model origin (usually the feet)
  • NEVER mix meshes with bones if the meshes are skinned - the skinned mesh origin (0,0,0) will skew the center calculation
  • ALWAYS use bones for accurate marker positioning on body parts controlled by skeleton

Examples

typescript
// WRONG - marker will appear at feet/origin
{
  name: 'left_eye',
  meshes: ['CC_Base_Eye'],  // BAD: skinned mesh at origin
  paddingFactor: 1.2,
}

// WRONG - mixing bones and skinned meshes skews center toward origin
{
  name: 'mouth',
  bones: ['CC_Base_JawRoot'],
  meshes: ['CC_Base_Teeth', 'CC_Base_Tongue'],  // BAD: these are at (0,0,0)
  paddingFactor: 1.5,
}

// CORRECT - marker appears at actual eye position
{
  name: 'left_eye',
  bones: ['CC_Base_L_Eye'],  // GOOD: bone has correct world position
  paddingFactor: 1.2,
}

// CORRECT - mouth uses only bones
{
  name: 'mouth',
  bones: ['CC_Base_JawRoot'],  // GOOD: bone only, no skinned meshes
  paddingFactor: 1.5,
}

CC4 Skinned Meshes to Avoid

  • CC_Base_Eye, CC_Base_Eye_1 → Use CC_Base_L_Eye, CC_Base_R_Eye bones
  • CC_Base_Teeth, CC_Base_Tongue → Use CC_Base_JawRoot bone

Bone Names by Character

CC4 Characters (Jonathan)

  • Head: CC_Base_Head, CC_Base_JawRoot
  • Eyes: CC_Base_L_Eye, CC_Base_R_Eye (use bones, NOT mesh names)
  • Spine: CC_Base_Spine01, CC_Base_Spine02
  • Arms: CC_Base_L_Clavicle, CC_Base_L_Upperarm, CC_Base_L_Hand
  • Legs: CC_Base_L_Thigh, CC_Base_L_Foot, CC_Base_L_ToeBase

Skeletal Models (Betta Fish)

  • Use armature bone names: Bone001_Armature, Bone002_Armature, etc.

Customizing 3D Markers

Edit DEFAULT_CONFIG in Annotation3DMarkers.ts:

typescript
const DEFAULT_CONFIG = {
  markerRadius: 0.012,           // Size of sphere on mesh surface
  markerColor: 0x4299e1,         // Blue color
  lineColor: 0x4299e1,           // Line color
  lineLength: 0.12,              // Line extension from surface
  labelColor: '#ffffff',         // Text color
  labelBackground: 'rgba(0, 0, 0, 0.75)', // Label background
  labelFontSize: 48,             // Font size for texture (higher = sharper)
  labelScale: 0.04,              // Label size in world units
};

Outward Direction for Markers

The direction markers point is determined semantically based on annotation name:

Annotation TypeOutward Direction
eye, face, mouth, headForward (+Z)
full_body, body, upper_bodyForward (+Z)
backBackward (-Z) via cameraAngle: 180
left_handLeft (-X) via cameraAngle: 270
right_handRight (+X) via cameraAngle: 90
footDown and forward
dorsal_finUp (+Y)
ventral_finDown (-Y)
pectoral_fin_leftLeft (-X)
pectoral_fin_rightRight (+X)
tailBackward (-Z)

Important: For face-related markers (eyes, mouth, head), the outward direction must be FORWARD (+Z), not the direction from model center, because model center is typically at waist level and pointing from there to the face would hit the top of the head.

Surface Point Detection

3D markers use raycasting to place spheres on the mesh surface:

  1. Calculate annotation center from bones/meshes
  2. Determine semantic outward direction based on annotation type
  3. Cast ray from outside model toward center along that direction
  4. Use first intersection point as marker position
  5. Offset slightly along surface normal to prevent z-fighting

Animation System

Camera transitions use spherical interpolation for smooth orbital motion:

  • toSpherical() / fromSpherical() - coordinate conversion
  • Pullback arc for large rotations (avoids passing through model)
  • Ease-in-out timing function

Common Tasks

Add annotation for new body part

  1. Identify bone/mesh names (check model in Three.js inspector)
  2. Add annotation entry in annotations.ts
  3. Set appropriate paddingFactor and cameraAngle

Adjust marker appearance

Edit Annotation3DMarkers.ts DEFAULT_CONFIG

Change animation timing

Modify transitionDuration in controller config or pass duration to focus methods

Debug camera positioning

Watch console logs prefixed with [Camera] - they show bounding boxes, positions, and angles