Skip to content

消息渲染器 vs 应用组件

两种自定义 UI 的方式,看起来很像,但用法完全不同。这篇帮你搞清楚它们的区别,以及什么时候该用哪个。


一句话总结

  • 消息渲染器(在编辑器中称为 Message Template / 消息模板)(surface: "message"):改变每条 AI 消息的样子。用在普通聊天模式。
  • 应用组件surface: "app"):接管整个屏幕,做独立的游戏界面。

两者都存储在同一个 customUI 数组中——由 surface 字段决定组件属于哪种模式。


它们的关系

每个自定义组件都有一个 surface 字段——值为 "message""app"

surface: "message"
  → 玩家看到:普通聊天界面
  → 你的组件用自定义样式渲染每条消息
  → 每个世界只能有一个 message surface 组件

surface: "app"
  → 玩家看到:全屏自定义界面(没有聊天框、没有输入框)
  → 你的组件占满整个屏幕
  → 每个世界仅能有 1 个 app surface 组件

如果任何可见的组件的 surface"app",世界会自动进入全屏模式。否则,使用默认聊天界面,消息渲染器生效。


详细对比

消息渲染器(surface: "message"应用组件(surface: "app"
在编辑器哪里设置编辑器 → 组件 → 添加 → 选择 Message编辑器 → 组件 → 添加 → 选择 App
数量只能有 1 个仅 1 个
什么时候显示普通聊天模式(没有应用组件时)当任何应用组件存在且可见时
显示位置替换每条消息的渲染占满整个屏幕
聊天界面正常显示(消息列表 + 输入框)完全隐藏
能拿到的数据每条消息的 contentrolemessageIndex + useYumina()只有 useYumina()(没有单条消息数据)
典型用途气泡对话、状态面板、战斗日志、交互按钮视觉小说全屏界面、完整游戏 UI

消息渲染器:怎么工作

消息渲染器是一段 TSX 代码,替换默认的 Markdown 渲染。每当 AI 发了一条消息,引擎不再用纯文字显示,而是把消息内容交给你的代码来决定怎么画。

它是逐条调用的。 聊天里有 10 条消息,你的渲染器就会被调用 10 次,每次拿到不同的 contentmessageIndex

收到的数据

tsx
export default function Renderer({
  content,         // 这条消息的文字(已去掉指令)
  role,            // "user" 或 "assistant"
  messageIndex,    // 这是第几条消息(从 0 开始)
  renderMarkdown,  // 内置函数:把 Markdown 转成 HTML
  isStreaming,     // AI 是否正在打字
}) {
  const api = useYumina();  // 还可以拿到游戏状态和交互 API
  // ...
}

适合做什么

  • 在消息上方/下方加状态面板(HP 条、金币显示)
  • 把消息改成气泡对话样式
  • 在第一条消息上放路线选择按钮
  • 在最后一条消息下面放交互输入框
  • 战斗日志、带颜色标记的文字
  • 任何需要和聊天消息共存的 UI

关键限制

  • 只能有 1 个 — 不能同时用多个渲染器
  • 有应用组件时不工作 — 如果任何可见的 surface: "app" 组件存在,渲染器不会被调用
  • 每条消息都调用 — 如果你只想在某条消息上显示内容,需要自己用 messageIndexisLastMsg 判断

应用组件:怎么工作

应用组件是完全独立的 UI 面板。它不替换消息渲染,而是接管整个屏幕——聊天消息列表、输入框、甚至顶部导航栏全部消失,只剩你的组件。

有可见的应用组件时会自动激活。 只要任何组件的 surface"app" 且可见,世界就会进入全屏模式。不需要手动切换。

收到的数据

tsx
export default function MyComponent() {
  const api = useYumina();
  // api.variables     — 游戏状态
  // api.sendMessage() — 发消息(触发 AI 回复)
  // api.setVariable() — 改变量
  // api.executeAction() — 触发行为
  // api.messages      — 所有消息历史
  // api.isStreaming    — AI 是否在打字
  // api.streamingContent — AI 正在打的内容
  // ...
}

注意:它没有 contentrolemessageIndexrenderMarkdown 这些参数。因为它不是在渲染某条消息——它是一个独立的全屏界面。

适合做什么

  • 视觉小说全屏界面(背景 + 立绘 + 对话框 + 选项)
  • 完整的游戏 UI(地图 + 状态栏 + 物品栏 + 聊天窗口全部自己画)
  • 任何不想要默认聊天界面的场景

关键限制

  • 聊天界面消失 — 玩家看不到消息列表和输入框,你需要自己用 api.messagesapi.sendMessage() 来处理聊天
  • ESC 会退出世界 — 全屏模式下按 ESC 不是退出全屏,而是离开这个世界

怎么选?

你想做的事 → 用哪个
─────────────────────
在消息上加 HP 条          → 消息渲染器 (surface: "message")
在消息下加按钮            → 消息渲染器 (surface: "message")
改变消息的外观(气泡、颜色) → 消息渲染器 (surface: "message")
做一个全屏视觉小说        → 应用组件 (surface: "app")
做一个完整的游戏界面      → 应用组件 (surface: "app")
保留聊天界面但加个侧边栏  → 目前不支持(应用组件只有全屏模式)

大多数创作者只需要消息渲染器。 应用组件是给想要完全掌控界面的高级创作者准备的。如果你不确定用哪个,先用消息渲染器。


在编辑器里怎么设置

消息渲染器

  1. 打开编辑器 → 组件 区域
  2. 点击「添加组件」→ 选择 Message
  3. 在代码编辑器里写 TSX 代码
  4. 底部显示「编译状态:正常」就说明语法没问题
  5. 保存,开新会话测试

应用组件

  1. 打开编辑器 → 组件 区域
  2. 点击「添加组件」→ 选择 App
  3. 写 TSX 代码
  4. 当任何应用组件可见时,世界会自动进入全屏模式
  5. 保存,开新会话测试

常见误解

"我写了应用组件但看不到"

检查组件的 visible 开关是否已在编辑器中打开。应用组件只有在存在且标记为可见时才会渲染。同时确认组件的 surface 设置为 "app"——"message" surface 的组件不会触发全屏模式。

"我添加了应用组件后聊天消失了"

这是正常行为。应用组件激活时会接管整个屏幕——聊天界面不再渲染。如果你想保留聊天功能,需要在应用组件里自己用 api.messagesapi.sendMessage() 来实现。

"我能同时用两个吗?"

在当前版本中,不能同时让两者对玩家可见

  • 没有应用组件时 → 消息渲染器生效
  • 有应用组件时 → 只有应用组件渲染

如果你想在全屏游戏界面里嵌入一个聊天窗口,需要在应用组件里自己实现。

"它们用同一个 API 吗?"

是的。两者都可以调用 useYumina(),拿到完全相同的 API:sendMessagesetVariableexecuteActionswitchGreetingplayAudiostopAudiovariablesmessages 等。

唯一的区别是消息渲染器额外收到单条消息的数据contentrolemessageIndexrenderMarkdown),而应用组件没有这些。


速查表

你想做的用什么Surface
改变消息外观消息渲染器"message"
在消息上加按钮/输入框消息渲染器"message"
做气泡对话/战斗日志消息渲染器"message"
做全屏视觉小说应用组件"app"
做完整游戏界面应用组件"app"
加状态面板在消息旁边消息渲染器"message"
自己实现整个聊天界面应用组件"app"