关于 xrift-world
xrift-world 是用于创建和修改 XRift WebXR 世界的开发指南,为 React Three Fiber 开发者提供平台实现规范、设备支持要求、配置说明和代码参考。
主要功能
- 01XRift API 与类型参考
- 02资源加载和目录规则
- 03PC 与移动设备支持指南
- 043D 交互与界面模式
- 05物理和摄像机配置
适用场景
- 01创建 XRift WebXR 世界
- 02调整移动端和 VR 交互
- 03配置世界物理与摄像机
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ webxr-jp/ xrift-skills --skill xrift-world安装后在 Claude Code 中输入/xrift-world确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/api-reference.mdcode-templates.mdtype-definitions.md详细介绍
XRift World 开发指南
用于创建和修改 XRift 平台 WebXR 世界的指南。
参考资料
- API 参考 -
@xrift/world-components中所有 Hook、组件和常量的完整规范 - 代码模板 - GLB 模型、纹理、Skybox、交互等的实现模式
- 类型定义 - User、PlayerMovement、VRTrackingData、TeleportDestination、WorldInfo、InstanceInfo、ConfirmOptions、Tag、VideoState、LogEntry、PhysicsConfig、CameraConfig、VoiceVolumeOverrideContextValue 的类型定义
关键规则(必须遵守)
- 加载资源时,始终使用
useXRift()中的baseUrl - 将资源文件放在
public/目录中 baseUrl末尾包含/,因此请使用${baseUrl}path拼接(${baseUrl}/path是错误的)
// Correct
const { baseUrl } = useXRift()
const model = useGLTF(`${baseUrl}robot.glb`)
// Wrong
const model = useGLTF('/robot.glb') // Absolute path - NG
const model = useGLTF(`${baseUrl}/robot.glb`) // Extra / - NG
设备支持(必须遵守)
访客可以通过 PC、移动设备(智能手机和平板电脑)和 VR 头显加入同一实例。世界必须至少同时支持 PC 和移动设备。 尽可能支持 VR。
| 设备 | 支持要求 | 控制方式 |
|---|---|---|
| PC | 必须 | 鼠标 + 键盘、中心准星 + 点击 |
| 移动设备 | 必须 | 触控、虚拟摇杆 |
| VR | 尽力支持 | 控制器、射线 + 扳机 |
开发服务器(npm run dev)只会测试 PC 控制,因此以下问题可能不会被发现:
- 不要使用自定义键盘快捷键构建功能(
window.addEventListener('keydown'))。移动设备和 VR 没有键盘,因此这些功能将无法使用。W/A/S/D、Space、Q/E、G、H 和 Esc 等按键也已被平台占用。- 按钮和开关:使用
Interactable包裹(PC 上点击、移动设备上触控、VR 中使用控制器) - 载具:在
Seat/Vehicle上使用onControlInput(键盘、虚拟摇杆和摇杆帽会以相同形式传入) - 文本输入:使用
TextInput。确认操作:使用useConfirm - 只有在某个操作也能通过
Interactable完成时,才可以将快捷键作为 PC 端的便捷方式
- 按钮和开关:使用
- 不要使用 DOM 元素构建 HUD 或 UI。 DOM 覆盖层在较小或旋转后的移动设备屏幕上会出现问题,还会与平台的虚拟摇杆和按钮重叠。在 VR 中只会渲染 3D 场景,因此完全不会显示 DOM UI。
- 将 UI 作为对象放置在 3D 空间中:使用
@react-three/drei中的Text,并使用@react-three/uikit构建面板和菜单 - 加载
useDefaultFont以显示日语文本,使用BillboardY包裹以面向玩家,再使用Interactable包裹以使其可点击
- 将 UI 作为对象放置在 3D 空间中:使用
- 不要让进度仅依赖
Grabbable。 目前抓取功能仅在 PC 上可用(指针锁定 + 准星)。
项目概览
- 用途:适用于 XRift 平台的 WebXR 世界
- 技术栈:React Three Fiber + Rapier 物理引擎 + Module Federation
- 工作原理:上传至 CDN,再由前端动态加载
项目结构
xrift-world-template/
├── public/ # Asset files (place directly, no subdirectories needed)
│ ├── model.glb
│ ├── texture.jpg
│ └── skybox.jpg
├── src/
│ ├── components/ # 3D components
│ ├── World.tsx # Main world component
│ ├── dev.tsx # Development entry point
│ ├── index.tsx # Production export
│ └── constants.ts # Constants
├── .triplex/ # Triplex (3D editor) config
├── xrift.json # XRift CLI config
├── vite.config.ts # Build config (Module Federation)
└── package.json
xrift.json 配置
physics(物理设置)
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
gravity | number | 9.81 | 重力强度(正值;地球 = 9.81、月球 = 1.62、木星 = 24.79) |
allowInfiniteJump | boolean | true | 是否允许无限跳跃 |
{
"physics": {
"gravity": 9.81,
"allowInfiniteJump": true
}
}
示例:
- 障碍赛世界:设置
"allowInfiniteJump": false以增加坠落风险 - 低重力世界:设置
"gravity": 1.62(月球重力),实现轻飘飘的移动 - 高重力世界:设置
"gravity": 24.79(木星重力),实现沉重的移动
camera(相机设置)
| 字段 | 类型 | 说明 |
|---|---|---|
near | number | 近裁剪距离(隐藏距离小于此值的物体) |
far | number | 远裁剪距离(隐藏距离大于此值的物体) |
{
"camera": {
"near": 0.1,
"far": 1000
}
}
示例:
- 广阔世界:设置
"far": 5000以渲染远处物体 - 精细世界:设置
"near": 0.01以提高近距离渲染精度
outputBufferType(输出缓冲区类型)
指定 WebGLRenderer 的输出缓冲区类型。会影响后期处理和 HDR 渲染精度。
| 值 | 描述 |
|---|---|
UnsignedByteType | 8 位整数(默认,标准渲染) |
HalfFloatType | 16 位浮点数(HDR 和后期处理) |
FloatType | 32 位浮点数(最高精度,但 GPU 开销更高) |
{
"outputBufferType": "HalfFloatType"
}
items(从开始时放置的物品)
使用 <Item itemId> 放置在世界中的用户创建物品的 ID。生产环境中只会加载此处列出的 ID(进入时预加载;访客会根据此列表解析资源包 URL)。你只能声明自己创建的物品,或已添加到个人库中的物品(从市场获取)。最多 50 个。
{
"items": [
"2a69ded4-d913-4359-8c1f-eac83a982b0c"
]
}
本地开发:在 vite.config.ts 中从 @xrift/sdk/vite 添加 xriftDev(),并运行 xrift login;随后,DevEnvironment 会通过开发服务器代理(/__xrift)加载与生产环境相同的资源包。若要同时开发物品和世界,请通过 <DevEnvironment items={{ [itemId]: Component }}> 传入本地组件。
permissions(权限设置)
声明世界所需的权限。进入实例时,声明的权限会以审批界面的形式展示给用户。
| 字段 | 类型 | 描述 |
|---|---|---|
allowedDomains | string[] | 世界通信所需的外部域名 |
allowedCodeRules | string[] | 要放宽限制的代码安全规则 |
{
"permissions": {
"allowedDomains": ["api.example.com", "cdn.example.com"],
"allowedCodeRules": ["no-storage-access", "no-network-without-permission"]
}
}
allowedCodeRules
由 @xrift/code-security 分析器定义的规则。默认情况下会阻止不安全操作,但在需要时可以放宽限制。
| 类别 | 规则 | 描述 |
|---|---|---|
| 动态代码 | no-eval | 允许使用 eval() |
| 动态代码 | no-new-function | 允许使用 Function 构造函数 |
| 动态代码 | no-string-timeout | 允许使用字符串参数调用 setTimeout/setInterval |
| 动态代码 | no-javascript-blob | 允许创建 JavaScript Blob |
| 混淆 | no-obfuscation | 允许使用混淆代码模式 |
| 网络 | no-network-without-permission | 允许使用 fetch、WebSocket 等 |
| 网络 | no-unauthorized-domain | 允许连接 allowedDomains 以外的域名 |
| 网络 | no-rtc-connection | 允许建立 WebRTC 对等连接 |
| 网络 | no-external-import | 允许导入外部 JS 模块 |
| 存储 | no-storage-access | 允许访问 localStorage/sessionStorage |
| 存储 | no-cookie-access | 允许读取/写入 Cookie |
| 存储 | no-indexeddb-access | 允许访问 IndexedDB |
| 存储 | no-storage-event | 允许监听存储事件 |
| DOM | no-dangerous-dom | 允许使用 innerHTML 和注入脚本 |
| 浏览器 API | no-navigator-access | 允许使用地理位置、摄像头、麦克风和剪贴板 |
| 全局 | no-sensitive-api-override | 允许覆盖 fetch 等对象 |
| 全局 | no-global-override | 允许覆盖 window、document |
| 全局 | no-prototype-pollution | 允许修改原型 |
命令参考
# Development
npm run dev # Start dev server (http://localhost:5173)
npm run build # Production build
npm run typecheck # Type checking
# XRift CLI
xrift login # Authenticate
xrift create world # Create new world project
xrift upload # Upload (auto-detect from xrift.json)
xrift whoami # Check logged-in user
xrift logout # Log out
开发环境
运行 npm run dev 启动开发服务器。你可以在第一人称视角中浏览并测试世界。
| 操作 | 按键 |
|---|---|
| 环顾四周 | 点击以锁定鼠标,然后移动鼠标 |
| 移动 | W / A / S / D |
| 上升 / 下降 | E 或 Space / Q |
| 交互 | 瞄准准星并点击 |
| 释放鼠标锁定 | ESC |
也可以在开发环境中测试 Interactable 组件的点击行为(中心的 Raycaster 会检测 LAYERS.INTERACTABLE 层)。Grabbable 也可用——按 G 抓取和放置,滚动鼠标滚轮调整距离,点击确认。
Seat 和 Vehicle 只会在开发环境中注册;坐下需要化身、摄像机和物理系统,因此在世界运行于 XRift 之前不会执行任何操作。
dev.tsx 结构
src/dev.tsx 是仅用于开发的入口点,不会包含在生产构建中。
注意:生产环境不需要 XRiftProvider(前端会自动将其包装起来)。
依赖项
必需项(peerDependencies)
react/react-dom^19.0.0three^0.182.0@react-three/fiber^9.3.0@react-three/drei^10.7.3@react-three/rapier^2.1.0
XRift 专用
@xrift/world-components- XRift hooks 和组件
Module Federation 共享包
与宿主(xrift.net)共享的包。在世界的 vite.config.ts 中将包声明为 shared 后,它们不会打包进世界的 chunk,而是由宿主提供。
| 包 | 版本要求 |
|---|---|
react | ^19.0.0 |
react-dom | ^19.0.0 |
react-dom/client | - |
react/jsx-runtime | ^19.0.0 |
three | ^0.176.0 |
three/addons/loaders/GLTFLoader.js | - |
three/addons/loaders/DRACOLoader.js | - |
three/addons/loaders/KTX2Loader.js | - |
@react-three/fiber | ^9.0.0 |
@react-three/rapier | ^2.0.0 |
@react-three/drei | ^10.0.0 |
@react-three/uikit | ^1.0.0 |
@pmndrs/uikit | ^1.0.0 |
@xrift/world-components | ^0.1.0 |
关于 three/addons 的注意事项
- 如果将
three/addonsbarrel 声明为 shared,打包内容会包含源自 Lottie 的eval,因此按子路径声明为 shared - 世界端也应按子路径导入并声明为 shared,例如
three/addons/loaders/DRACOLoader.js
// vite.config.ts — shared の設定例(xrift-world-template 準拠)
federation({
name: 'xrift_world_template',
filename: 'remoteEntry.js',
exposes: {
'./World': './src/index.tsx',
},
shared: {
react: { singleton: true, requiredVersion: '^19.0.0' },
'react-dom': { singleton: true, requiredVersion: '^19.0.0' },
'react-dom/client': { singleton: true },
'react/jsx-runtime': { singleton: true },
three: { singleton: true, requiredVersion: '^0.176.0' },
// three/addons はバレルではなくサブパス単位で宣言する
'three/addons/loaders/DRACOLoader.js': { singleton: true },
'@react-three/fiber': { singleton: true, requiredVersion: '^9.3.0' },
'@react-three/rapier': { singleton: true, requiredVersion: '^2.1.0' },
'@react-three/drei': { singleton: true, requiredVersion: '^10.7.3' },
'@xrift/world-components': { singleton: true, requiredVersion: '^0.1.0' },
},
}),
故障排除
“useXRift must be used within XRiftProvider”
原因:未使用 XRiftProvider 包装
解决方案:
- 检查
src/dev.tsx是否使用了XRiftProvider - 使用 Triplex 时:检查
.triplex/provider.tsx
资源加载失败
原因:未使用 baseUrl,或路径拼接错误
解决方案:
// Correct
const { baseUrl } = useXRift()
const model = useGLTF(`${baseUrl}robot.glb`)
// Wrong
const model = useGLTF('/robot.glb')
const model = useGLTF(`${baseUrl}/robot.glb`)
物理效果不起作用
原因:未使用 Physics 组件包装,或缺少 RigidBody
解决方案:
<Physics>
<RigidBody type="fixed"> {/* or "dynamic" */}
<mesh>...</mesh>
</RigidBody>
</Physics>
链接
示例实现
- GLB 模型:
src/components/Duck/index.tsx - 天空盒:
src/components/Skybox/index.tsx - 动画:
src/components/RotatingObject/index.tsx - 交互:
src/components/InteractableButton/index.tsx - 用户追踪:
src/components/RemoteUserHUDs/index.tsx - 传送:
src/components/TeleportPortal/index.tsx - 主世界:
src/World.tsx