@ai_wanjia/sdk
v1.0.3
Published
Charx SDK for creator iframe integration
Downloads
497
Readme
@ai_wanjia/sdk
玩家AI 平台的创作者 SDK。
它用于运行在平台 iframe 内的独立页面,通过 postMessage RPC 与平台通信,读取角色信息、读写变量、发送消息、控制界面,并在 React 项目中提供现成的 Hooks 和组件。
适用场景
| 场景 | 是否适合 |
|------|----------|
| 独立 HTML 页面、原生 JS 页面 | ✅ |
| React 独立页面 | ✅ |
| 角色卡里需要完整自定义 UI 的游戏界面 | ✅ |
| 仅在 AI 消息里插一个小卡片 | 更推荐直接用平台注入的 window.$charx |
| Node.js 服务端、后端任务 | ❌ |
官方 Starter
仓库内已经提供两套官方快速开发模板:
| 模板 | 目录 | 适用场景 |
|------|------|----------|
| charx-h5-starter | sdk/examples/charx-h5-starter | 原生 html + css + js,零构建起步 |
| charx-react-starter | sdk/examples/charx-react-starter | Vite + React + TypeScript,适合组件化开发 |
这两套模板都支持:
- 本地开发态自动切到 mock 运行时
- 平台 iframe 内自动切到真实 SDK
- 首页自带
character / variable / storage / chat / ui.toast示例
安装
npm install @ai_wanjia/sdk五分钟上手
原生 JavaScript / TypeScript
import { CharxSdk } from '@ai_wanjia/sdk'
const sdk = CharxSdk.getInstance()
await sdk.init()
const info = await sdk.character.getInfo()
console.log('角色名:', info.name)
const hp = await sdk.variable.get<number>('hp')
console.log('当前 HP:', hp)
sdk.chat.send('总结一下我当前的状态', {
onData: (chunk) => {
console.log('流式片段:', chunk)
},
onComplete: (message) => {
console.log('完整回复:', message.content)
},
onError: (error) => {
console.error(error)
},
})React
import { CharxProvider, useChat, useVariable, useCharacter } from '@ai_wanjia/sdk/react'
export default function App() {
return (
<CharxProvider fallback={<div>连接平台中...</div>}>
<GamePage />
</CharxProvider>
)
}
function GamePage() {
const character = useCharacter()
const { messages, send, status, stop } = useChat()
const [hp, setHp] = useVariable<number>('hp', 100)
return (
<div>
<h1>{character?.name}</h1>
<p>HP: {hp}</p>
{messages.map((message) => (
<div key={message.id}>{message.content}</div>
))}
{status === 'streaming' ? (
<button onClick={stop}>停止</button>
) : (
<button onClick={() => send('继续推进剧情')}>继续</button>
)}
<button onClick={() => setHp(hp + 5)}>恢复 5 点 HP</button>
</div>
)
}运行时规则
1. 必须在平台 iframe 内运行
sdk.init() 会向父窗口发起握手。
const sdk = CharxSdk.getInstance()
await sdk.init()如果页面不是由玩家AI平台加载,而是直接在浏览器里打开,init() 会在超时后抛错。
2. init() 之前不要调用其他 API
推荐做法:
const sdk = CharxSdk.getInstance()
await sdk.init()
// 从这里开始再调用其他模块3. variable 和 storage 不是一回事
| 能力 | 作用域 | 是否随当前对话变化 | 适合存什么 |
|------|--------|--------------------|------------|
| sdk.variable | 当前对话 | 是 | HP、MP、好感度、剧情阶段、当前位置 |
| sdk.storage | user + character | 否 | 设置、成就、已解锁结局、长期背包 |
4. SDK 负责界面层,不负责替代平台 AI 运行时
SDK 能做的事情:
- 发送消息到平台聊天链路
- 读写变量和持久化存储
- 读取角色信息
- 控制当前独立页面 UI
SDK 不做的事情:
- 不直接调用模型
- 不绕开平台上下文组装
- 不替代角色卡、世界书、正则、系统提示词
API 概览
CharxSdk 是单例对象,所有能力都挂在它的模块上:
CharxSdk
├── chat
├── character
├── variable
├── storage
├── ui
├── media
├── game
├── worldbook
└── utilssdk.character
读取当前角色、人设和对话配置。
const info = await sdk.character.getInfo()
const persona = await sdk.character.getPersona()
const settings = await sdk.character.getSettings()sdk.chat
负责发消息、停止生成、切开场白、读取历史消息。
sdk.chat.send('你好', {
onData: (chunk) => console.log(chunk),
onComplete: (message) => console.log(message.content),
})
await sdk.chat.stop()
await sdk.chat.regenerate()
await sdk.chat.continue()
sdk.chat.setInput('帮我润色这句话')
const input = await sdk.chat.getInput()
await sdk.chat.setGreetingIndex(1)
const greetingIndex = await sdk.chat.getGreetingIndex()
const allMessages = await sdk.chat.messages.getAll()
const page = await sdk.chat.messages.list({ limit: 20, offset: 0 })sdk.variable
负责当前对话变量。
const hp = await sdk.variable.get<number>('hp')
const vars = await sdk.variable.getAll()
await sdk.variable.set('hp', 80)
await sdk.variable.setMany({ hp: 80, mp: 50 })
await sdk.variable.increment('hp', 5)
await sdk.variable.decrement('mp', 2)
const unwatch = sdk.variable.watch<number>('hp', (value) => {
console.log('新的 HP:', value)
})sdk.storage
负责跨对话持久化数据。
await sdk.storage.set('preferredTheme', 'deep-sea')
const theme = await sdk.storage.get<string>('preferredTheme')
const settings = await sdk.storage.getOrDefault('settings', { bgm: true })
const keys = await sdk.storage.keys()sdk.ui
负责 Toast、弹窗、主题、滚动和面板控制。
sdk.ui.toast({ text: '获得道具', type: 'success' })
await sdk.ui.alert('任务失败')
const confirmed = await sdk.ui.confirm('确认继续?')
const input = await sdk.ui.prompt('请输入角色名', '默认值')
sdk.ui.scrollToBottom()
sdk.ui.setTheme('dark')
await sdk.ui.openPanel({
url: 'https://your-panel-url',
title: '角色状态',
mode: 'sidebar',
width: 320,
})
await sdk.ui.closePanel()sdk.media
负责 TTS、背景音乐和音效。
await sdk.media.speak('欢迎来到这里', { voice: 'character' })
sdk.media.stopSpeak()
await sdk.media.bgm.play('/assets/bgm.mp3', { loop: true, volume: 0.7 })
await sdk.media.bgm.stop({ fadeOut: 500 })
sdk.media.bgm.pause()
sdk.media.bgm.resume()
sdk.media.bgm.setVolume(0.5)
await sdk.media.sfx.play('/assets/hit.mp3', { volume: 0.8 })
sdk.media.sfx.preload(['/assets/hit.mp3'])sdk.game
负责存档、成就和排行榜。
await sdk.game.save({ slot: 1, description: '第三章开头' })
const saveData = await sdk.game.load({ slot: 1 })
const saves = await sdk.game.listSaves()
await sdk.game.deleteSave(1)
await sdk.game.unlockAchievement('first_victory')
const achievements = await sdk.game.listAchievements()
await sdk.game.submitScore(9800, { category: 'story_mode' })
const top10 = await sdk.game.getTop({ limit: 10, category: 'story_mode' })
const myRank = await sdk.game.getSelfRank({ category: 'story_mode' })sdk.worldbook
负责当前对话内的世界书动态控制。
所有操作只影响当前对话,不会改角色卡模板。
const worldbook = await sdk.worldbook.getAll()
await sdk.worldbook.enable('combat-mode')
await sdk.worldbook.disable('peace-mode')
await sdk.worldbook.batchToggle([
{ entryKey: 'combat-mode', enabled: true },
{ entryKey: 'peace-mode', enabled: false },
])
await sdk.worldbook.setContent('combat-mode', '新的世界书内容')
await sdk.worldbook.clearContent('combat-mode')
await sdk.worldbook.reset()sdk.utils
负责剪贴板和轻量格式处理。
await sdk.utils.clipboard.writeText('复制这段文本')
const text = await sdk.utils.clipboard.readText()
const html = sdk.utils.format.markdown('**加粗** _斜体_ `代码`')
const safeHtml = sdk.utils.format.sanitize('<script>alert(1)</script>')React 集成
导出入口
import { CharxSdk } from '@ai_wanjia/sdk'
import { CharxProvider, useChat, useVariable, useCharacter, usePersona, useStorage } from '@ai_wanjia/sdk/react'CharxProvider
CharxProvider 负责初始化 SDK 并通过 React Context 向下提供实例。
import { CharxProvider } from '@ai_wanjia/sdk/react'
export default function App() {
return (
<CharxProvider
fallback={<div>连接中...</div>}
errorFallback={(error) => <div>初始化失败:{error.message}</div>}
>
<YourApp />
</CharxProvider>
)
}Hooks
| Hook | 作用 |
|------|------|
| useChat() | 管理消息列表、发送、停止、继续、重试 |
| useVariable(key, defaultValue) | 订阅单个变量 |
| useVariables() | 订阅全部变量 |
| useCharacter() | 读取当前角色信息 |
| usePersona() | 读取当前用户人设 |
| useStorage(key, defaultValue) | 读取并同步一个持久化存储值 |
示例:
import { useChat, useVariable, useCharacter, useStorage } from '@ai_wanjia/sdk/react'
function GamePanel() {
const character = useCharacter()
const { messages, send, status } = useChat()
const [hp, setHp] = useVariable<number>('hp', 100)
const [theme, setTheme] = useStorage('preferredTheme', 'deep-sea')
return (
<div>
<h2>{character?.name}</h2>
<p>HP: {hp}</p>
<p>Theme: {theme}</p>
<button onClick={() => setHp(hp + 5)}>恢复 5 点 HP</button>
<button onClick={() => setTheme('mist')}>切换主题</button>
<button disabled={status !== 'idle'} onClick={() => send('继续')}>
继续
</button>
{messages.map((message) => (
<div key={message.id}>{message.content}</div>
))}
</div>
)
}组件
Thread.MessageList
Thread 是一个命名空间对象,当前导出的是 Thread.MessageList 和 Thread.MessageItem。
import { Thread, useChat } from '@ai_wanjia/sdk/react'
function ChatView() {
const { messages, status, loadMore } = useChat()
return (
<Thread.MessageList
messages={messages}
isStreaming={status === 'streaming'}
onLoadMore={loadMore}
/>
)
}MdRenderer
import { MdRenderer } from '@ai_wanjia/sdk/react'
function MessageBody({ content }: { content: string }) {
return <MdRenderer content={content} />
}包导出
| 导出路径 | 内容 |
|----------|------|
| @ai_wanjia/sdk | 核心 SDK、事件常量、类型 |
| @ai_wanjia/sdk/react | React Provider、Hooks、组件 |
| @ai_wanjia/sdk/types | 独立类型导出 |
通信协议
SDK 通过 postMessage 与平台通信。
| 方向 | 消息类型 | 说明 |
|------|----------|------|
| iframe → 平台 | __charx_rpc__ | 方法调用 |
| 平台 → iframe | __charx_ready__ | 初始化握手成功 |
| 平台 → iframe | __charx_rpc_response__ | RPC 响应 |
| 平台 → iframe | __charx_push__ | 平台主动推送事件 |
如果要直接订阅底层推送事件,可以使用:
import { CharxSdk, PUSH } from '@ai_wanjia/sdk'
const sdk = CharxSdk.getInstance()
await sdk.init()
const unwatch = sdk.getRpc().push(PUSH.CHAT_STREAM_CHUNK, (data) => {
console.log(data)
})构建与开发
npm run build
npm run dev
npm run typecheck输出目录为 dist/。
相关文档
- 仓库内创作者教程:
docs/sdk-creator-guide.md - 原生模板:
sdk/examples/charx-h5-starter - React 模板:
sdk/examples/charx-react-starter
许可
内部使用,版权归玩家AI平台所有。
