smithery.ai

vtj-camera-system

Configures third-person camera systems with collision avoidance. Use when adjusting follow behavior, implementing camera modes, or handling cave/obstacle detection.

First seen Mar 20, 2026

Installation

$ npx skills add https://smithery.ai

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 9,161 B
  • docs SUMMARY.md 195 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 2 installs

SKILL.md

vite-threejs Camera System

Overview

本项目采用 第三人称相机系统,核心组件:

  • Camera:主相机类,管理模式切换
  • CameraRig:第三人称跟随逻辑,处理平滑跟随、避障、bobbing 效果

核心原则:相机通过锚点跟随玩家,使用 lerp 平滑过渡,通过方块检测避免穿模。

When to Use

  • 修改相机跟随行为
  • 调整相机偏移和平滑度
  • 实现新的相机模式
  • 处理相机与地形的碰撞

相机架构

┌─────────────────────────────────────────────────────────────┐
│                         Camera                               │
│  - mode: 'third-person' | 'bird-perspective'                │
│  - perspectiveCamera: THREE.PerspectiveCamera                │
│  - orbitControls: OrbitControls (鸟瞰模式用)                 │
│  - rig: CameraRig (第三人称用)                               │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                       CameraRig                              │
│  - group: THREE.Group (跟随玩家位置)                         │
│  - cameraAnchor: THREE.Object3D (相机位置锚点)               │
│  - targetAnchor: THREE.Object3D (看向目标锚点)               │
│  - _smoothedPosition: 平滑后的位置                           │
│  - _smoothedLookAtTarget: 平滑后的看向点                     │
└─────────────────────────────────────────────────────────────┘

CameraRig 工作原理

锚点系统

// 锚点附着在 group 上,group 跟随玩家
this.group = new THREE.Group()
this.cameraAnchor = new THREE.Object3D()   // 相机实际位置
this.targetAnchor = new THREE.Object3D()   // 相机看向的点

// 锚点相对于玩家的偏移
this.cameraAnchor.position.copy(this.config.follow.offset)       // (2, 1.5, 3)
this.targetAnchor.position.copy(this.config.follow.targetOffset) // (0, 1.5, -5.5)

this.group.add(this.cameraAnchor)
this.group.add(this.targetAnchor)

平滑跟随

update() {
  const playerPos = this.target.position
  const facingAngle = this.target.facingAngle
  
  // 平滑位置插值
  this._smoothedPosition.lerp(playerPos, this.config.follow.smoothSpeed)
  this.group.position.copy(this._smoothedPosition)
  
  // 同步角色朝向
  this.group.rotation.y = facingAngle
  
  // 获取世界坐标
  const cameraPos = this.cameraAnchor.getWorldPosition(new THREE.Vector3())
  const targetPos = this.targetAnchor.getWorldPosition(new THREE.Vector3())
  
  // 平滑看向点
  this._smoothedLookAtTarget.lerp(targetPos, this.config.follow.lookAtSmoothSpeed)
  
  return { cameraPos, targetPos: this._smoothedLookAtTarget, fov: this._currentFov }
}

配置参数

// src/js/camera/camera-rig-config.js
export const CAMERA_RIG_CONFIG = {
  follow: {
    offset: new THREE.Vector3(2, 1.5, 3.0),        // 相机位置偏移
    targetOffset: new THREE.Vector3(0, 1.5, -5.5), // 看向点偏移
    smoothSpeed: 0.1,           // 位置平滑系数 (0-1)
    lookAtSmoothSpeed: 0.45,    // 看向平滑系数
    mouseTargetY: {
      sensitivity: 0.030,       // 鼠标 Y 轴灵敏度
      maxOffset: 4.5,           // 最大俯仰偏移
      returnSpeed: 1.5,         // 回中速度
      damping: 3.5,             // 阻尼
    },
  },
  trackingShot: {
    fov: { baseFov: 55, maxFov: 85, speedThreshold: 3.0 },
    bobbing: {
      verticalFrequency: 4.0,
      verticalAmplitude: 0.025,
      horizontalFrequency: 4.0,
      horizontalAmplitude: 0.015,
      rollFrequency: 4.0,
      rollAmplitude: 0.005,
      idleBreathing: { enabled: true, frequency: 0.7, amplitude: 0.015 },
    },
  },
}

洞穴避障(非射线方式)

本项目使用 方块检测 而非射线检测来处理相机穿模:

_checkBlockAbovePlayer(playerPos) {
  const checkHeights = [2, 3]        // 玩家头顶上方
  const checkRange = [-1, 0, 1]      // 3x3 XZ 区域
  let blockCount = 0
  
  for (const heightOffset of checkHeights) {
    for (const dx of checkRange) {
      for (const dz of checkRange) {
        const block = terrainManager.getBlockWorld(
          playerPos.x + dx,
          playerPos.y + heightOffset,
          playerPos.z + dz
        )
        if (block && block.id !== 0) blockCount++
        if (blockCount >= 4) return true  // 判定为在洞穴中
      }
    }
  }
  return false
}

洞穴模式处理

if (isInCave) {
  // 切换到近距离偏移
  this._caveOffset = new THREE.Vector3(0.0, 1.5, 1.0)
  this._caveTargetOffset = new THREE.Vector3(0, 1.5, -1.5)
  
  // 淡化玩家模型
  this.target.setOpacity(0.1)
} else {
  // 恢复正常偏移
  this.target.setOpacity(1.0)
}

肩膀切换(左右视角)

toggleSide() {
  this._currentSide *= -1  // 1 → -1 或 -1 → 1
  
  gsap.to(this, {
    _sideFactor: this._currentSide,
    duration: 0.6,
    ease: 'power2.inOut',
  })
}

// 应用到 X 偏移
this.config.follow.offset.x = this._targetOffset.x * this._sideFactor

触发方式:

emitter.on('input:toggle_camera_side', () => this.toggleSide())

动态 FOV(速度感)

_updateDynamicFov(speed) {
  const { baseFov, maxFov, speedThreshold } = this.config.trackingShot.fov
  
  const speedRatio = Math.min(speed / speedThreshold, 1.0)
  const targetFov = baseFov + (maxFov - baseFov) * speedRatio
  
  this._currentFov += (targetFov - this._currentFov) * smoothSpeed
}

事件监听

CameraRig 监听以下事件:

constructor() {
  emitter.on('input:mouse_move', ({ movementY }) => {
    this.mouseYVelocity += movementY * this.config.sensitivity
  })
  
  emitter.on('input:wheel', ({ deltaY }) => {
    this._normalOffset.y += deltaY * sensitivity
  })
  
  emitter.on('input:toggle_camera_side', () => this.toggleSide())
  
  emitter.on('settings:camera-rig-changed', ({ fov, bobbing }) => {
    // 更新配置
  })
}

访问相机

// 在组件中
this.camera = this.experience.camera           // Camera 类实例
this.cameraInstance = this.experience.camera.instance  // THREE.Camera

// Camera 类提供的方法
this.experience.camera.switchMode('bird-perspective')
this.experience.camera.attachRig(player)

添加新相机模式

Step 1: 定义模式

// camera.js
this.cameraModes = {
  THIRD_PERSON: 'third-person',
  BIRD_PERSPECTIVE: 'bird-perspective',
  FIRST_PERSON: 'first-person',  // 新增
}

Step 2: 实现切换逻辑

switchMode(mode) {
  this.currentMode = mode
  
  switch (mode) {
    case 'first-person':
      this.rig?.disable()
      this.orbitControls.enabled = false
      // 第一人称特殊处理
      break
    // ...
  }
}

Common Mistakes

❌ 直接操作相机位置

// BAD: 直接设置相机位置
this.camera.instance.position.set(0, 5, 10)

// GOOD: 通过 CameraRig 控制
this.camera.rig.setOffset(new THREE.Vector3(0, 5, 10))

❌ 忘记平滑过渡

// BAD: 直接赋值(相机会跳跃)
this.group.position.copy(playerPos)

// GOOD: 使用 lerp 平滑
this._smoothedPosition.lerp(playerPos, smoothSpeed)
this.group.position.copy(this._smoothedPosition)

❌ 使用射线检测碰撞

// BAD: 复杂的射线碰撞检测
this.raycaster.set(cameraPos, direction)
const intersects = this.raycaster.intersectObjects(terrain)

// GOOD: 使用方块检测(本项目特有)
const isInCave = this._checkBlockAbovePlayer(playerPos)

Quick Reference

需求 方法
获取相机实例 this.experience.camera.instance
切换相机模式 this.experience.camera.switchMode('mode')
调整跟随平滑度 修改 config.follow.smoothSpeed
切换左右肩膀 rig.toggleSide()
响应设置变化 监听 settings:camera-rig-changed
配置项 说明
follow.offset 相机相对玩家的位置偏移
follow.targetOffset 看向点相对玩家的偏移
follow.smoothSpeed 位置平滑系数 (0-1)
trackingShot.fov 动态 FOV 配置
trackingShot.bobbing 行走晃动配置