smithery.ai

vtj-state-management

Manages state between Vue and Three.js via Pinia and mitt. Use when synchronizing UI state, emitting events, or implementing cross-layer communication.

First seen Mar 31, 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 11,229 B
  • docs SUMMARY.md 209 B

History

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

SKILL.md

vite-threejs State Management (Pinia + mitt)

Overview

本项目使用 双通道状态管理:

  • Pinia:持久化状态,Vue 和 Three.js 双向同步
  • mitt:即时事件通知,跨层通信

核心原则:Pinia 管状态,mitt 管事件。状态变更通过 Pinia,通知 Three.js 通过 mitt emit。

When to Use

  • 需要在 Vue UI 和 Three.js 之间共享状态
  • 需要从 UI 触发 3D 场景行为
  • 需要从 3D 场景通知 UI 更新
  • 管理游戏设置、用户偏好等持久状态

双通道架构

┌─────────────────────────────────────────────────────────────┐
│                         Vue UI Layer                         │
│  ┌─────────────────┐          ┌─────────────────┐           │
│  │   Components    │◄────────►│   Pinia Stores  │           │
│  └─────────────────┘          └────────┬────────┘           │
└────────────────────────────────────────┼────────────────────┘
                                         │ emitter.emit()
                                         ▼
┌─────────────────────────────────────────────────────────────┐
│                      mitt Event Bus                          │
└─────────────────────────────────────────────────────────────┘
                                         │ emitter.on()
                                         ▼
┌─────────────────────────────────────────────────────────────┐
│                      Three.js Layer                          │
│  ┌─────────────────┐          ┌─────────────────┐           │
│  │   Components    │◄────────►│   Experience    │           │
│  └─────────────────┘          └─────────────────┘           │
└─────────────────────────────────────────────────────────────┘

Pinia Store 模式

Store 定义

// src/pinia/settingsStore.js
import emitter from '@three/utils/event-bus.js'
import { defineStore } from 'pinia'
import { ref } from 'vue'

export const useSettingsStore = defineStore('settings', () => {
  // 状态
  const shadowQuality = ref('high')
  
  // Action:修改状态 + 通知 Three.js
  function setShadowQuality(quality) {
    shadowQuality.value = quality
    emitter.emit('shadow:quality-changed', quality)  // 通知 Three.js
    saveSettings()  // 持久化
  }
  
  return { shadowQuality, setShadowQuality }
})

在 Vue 中使用

<script setup>
import { useSettingsStore } from '@pinia/settingsStore.js'

const settings = useSettingsStore()

function handleQualityChange(quality) {
  settings.setShadowQuality(quality)
}
</script>

<template>
  <select v-model="settings.shadowQuality" @change="handleQualityChange">
    <option value="low">Low</option>
    <option value="medium">Medium</option>
    <option value="high">High</option>
  </select>
</template>

在 Three.js 中使用

// 方式一:监听 mitt 事件(推荐)
import emitter from './utils/event-bus.js'

emitter.on('shadow:quality-changed', (quality) => {
  this.updateShadowQuality(quality)
})

// 方式二:直接读取 Pinia(需要时)
import { useSettingsStore } from '@pinia/settingsStore.js'

const settings = useSettingsStore()
const quality = settings.shadowQuality

mitt Event Bus

事件总线定义

// src/js/utils/event-bus.js
import mitt from 'mitt'
const emitter = mitt()
export default emitter

事件命名规范

前缀 来源 用途 示例
ui: Vue UI UI 状态变化 ui:pause-changed
game: Vue/Three.js 游戏逻辑事件 game:create_world
settings: Pinia Store 设置变更通知 settings:environment-changed
core: Experience 核心系统事件 core:ready, core:resize
shadow: 渲染相关 阴影设置 shadow:quality-changed

事件使用模式

// 发送事件(Vue/Pinia 层)
emitter.emit('game:create_world', { seed, terrain, trees })
emitter.emit('ui:pause-changed', true)
emitter.emit('settings:environment-changed', { skyMode: 'HDR' })

// 监听事件(Three.js 层)
emitter.on('game:create_world', ({ seed, terrain, trees }) => {
  this.world.reset({ seed, terrain, trees })
})

emitter.on('ui:pause-changed', (paused) => {
  this.isPaused = paused
})

// 移除监听(destroy 时)
this._boundHandler = this.handleEvent.bind(this)
emitter.on('some:event', this._boundHandler)
// ...
emitter.off('some:event', this._boundHandler)

通信模式

模式一:UI → Three.js(最常用)

// 1. Pinia Store 中定义 action
function setEnvFogDensity(value) {
  envFogDensity.value = value
  emitter.emit('settings:environment-changed', { fogDensity: value })
  saveSettings()
}

// 2. Three.js 组件监听
emitter.on('settings:environment-changed', (patch) => {
  if (patch.fogDensity !== undefined) {
    this.updateFog(patch.fogDensity)
  }
})

模式二:Three.js → UI

// 1. Three.js 中发送事件
emitter.emit('game:player-health-changed', { health: 80, maxHealth: 100 })

// 2. Vue 组件监听
import emitter from '@three/utils/event-bus.js'
import { onMounted, onUnmounted, ref } from 'vue'

const health = ref(100)

onMounted(() => {
  emitter.on('game:player-health-changed', handleHealthChange)
})

onUnmounted(() => {
  emitter.off('game:player-health-changed', handleHealthChange)
})

function handleHealthChange({ health: newHealth }) {
  health.value = newHealth
}

模式三:状态同步(双向)

// Pinia Store 持有状态
const isPaused = ref(false)

function toPauseMenu() {
  isPaused.value = true
  emitter.emit('ui:pause-changed', true)
}

function toPlaying() {
  isPaused.value = false
  emitter.emit('ui:pause-changed', false)
}

// Three.js 层响应
emitter.on('ui:pause-changed', (paused) => {
  this.isPaused = paused
})

现有 Stores

Store 文件 职责
useUiStore uiStore.js 屏幕状态、菜单导航、世界管理
useSettingsStore settingsStore.js 游戏设置、持久化、Three.js 通知
useHudStore hudStore.js HUD 状态(血量、快捷栏等)
useSkinStore skinStore.js 皮肤选择状态

现有事件

core: 系统事件

事件 数据 触发时机
core:ready - 所有资源加载完成
core:resize - 窗口尺寸变化
core:tick - 每帧更新

ui: UI 事件

事件 数据 触发时机
ui:pause-changed boolean 暂停/恢复

game: 游戏事件

事件 数据 触发时机
game:create_world { seed, terrain, trees } 创建新世界
game:reset_world { seed, terrain, trees } 重置世界
game:requestpointerlock - 请求锁定鼠标

settings: 设置事件

事件 数据 触发时机
settings:environment-changed { skyMode?, sunIntensity?, ... } 环境设置变更
settings:postprocess-changed { speedLines } 后期处理变更
settings:camera-rig-changed { fov, bobbing } 相机设置变更
settings:chunks-changed { viewDistance?, unloadPadding? } 区块设置变更
settings:front-view-changed { enabled } 前视图开关
settings:mouse-sensitivity-changed number 鼠标灵敏度变更

shadow: 阴影事件

事件 数据 触发时机
shadow:quality-changed string 阴影质量变更

Common Mistakes

❌ 直接在 Vue 中操作 Three.js

// BAD: Vue 组件直接操作 Three.js
import Experience from '@three/experience.js'

function handleClick() {
  const exp = new Experience()
  exp.world.player.setPosition(0, 0, 0)  // ❌ 直接操作
}

// GOOD: 通过 mitt 事件
function handleClick() {
  emitter.emit('game:player-teleport', { x: 0, y: 0, z: 0 })
}

❌ 忘记清理事件监听

// BAD: 没有清理
constructor() {
  emitter.on('some:event', (data) => this.handle(data))
}

// GOOD: 保存引用并清理
constructor() {
  this._boundHandler = this.handle.bind(this)
  emitter.on('some:event', this._boundHandler)
}

destroy() {
  emitter.off('some:event', this._boundHandler)
}

❌ 在 Three.js 中直接修改 Pinia 状态

// BAD: Three.js 直接写 Pinia
import { useUiStore } from '@pinia/uiStore.js'

function onPlayerDeath() {
  const ui = useUiStore()
  ui.screen = 'gameOver'  // ❌ 直接写状态
}

// GOOD: 通过事件让 Vue 层处理
function onPlayerDeath() {
  emitter.emit('game:player-died')
}

// Vue 层响应
emitter.on('game:player-died', () => {
  ui.toGameOver()
})

❌ 事件命名不规范

// BAD: 无前缀、大小写混乱
emitter.emit('pauseChanged', true)
emitter.emit('CreateWorld', data)

// GOOD: 使用规范前缀
emitter.emit('ui:pause-changed', true)
emitter.emit('game:create_world', data)

❌ 事件数据结构不一致

// BAD: 有时传对象,有时传原始值
emitter.emit('settings:fog-changed', 0.01)
emitter.emit('settings:fog-changed', { density: 0.01 })

// GOOD: 统一使用对象(可扩展)
emitter.emit('settings:environment-changed', { fogDensity: 0.01 })

Quick Reference

场景 使用
持久化状态 Pinia Store
UI → Three.js 通知 Pinia action + emitter.emit()
Three.js → UI 通知 emitter.emit()
Three.js 读取状态 Pinia Store 或 emitter.on()
事件清理 destroy() 中 emitter.off()
事件前缀 用途
core: 系统级(ready/resize/tick)
ui: UI 状态变化
game: 游戏逻辑
settings: 设置变更
shadow: 渲染相关