mcpField
3
3D AR Studio

3D AR Studio

本地服务
nirholas.github.io媒体与设计113 周前更新

关于 3D AR Studio

3D AR Studio 是可嵌入网页的增强现实工作室,可在真实空间中放置和布置多个 3D 模型,面向网页开发者和 Agent。它支持场景链接分享、协作房间,并附带用于模型生成与场景编排的 MCP 服务。

主要功能

  1. 01放置和布置多个 3D 模型
  2. 02根据文本提示生成模型
  3. 03通过链接和二维码分享场景
  4. 04同步协作房间
  5. 05嵌入为网页组件或页面

适用场景

  1. 01在网站中加入 AR 模型工作室
  2. 02编排并分享房间布局
  3. 03让 Agent 生成模型并创建 AR 链接
  4. 04生成独立的 HTML AR 页面

MCP 相关

独立的 3d-ar-studio-mcp 服务提供模型生成、查询生成状态、搜索模型目录、编排场景、导出 AR 链接和创建 HTML 页面等工具。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"nirholas-3d-ar-studio": {
"command": "npx",
"args": [
"-y",
"3d-ar-studio-mcp"
],
"env": {
"AR_STUDIO_PAGE_URL": "<AR_STUDIO_PAGE_URL>",
"AR_STUDIO_ASSETS": "<AR_STUDIO_ASSETS>",
"AR_STUDIO_MCP_ENDPOINT": "<AR_STUDIO_MCP_ENDPOINT>",
"AR_STUDIO_ORIGIN": "<AR_STUDIO_ORIGIN>"
}
}
}
}
启动命令npx -y 3d-ar-studio-mcp
需要配置的环境变量
AR_STUDIO_PAGE_URLThe page that composed AR scenes link to. Defaults to the hosted demo; set it to your own deployment of the studio.
AR_STUDIO_ASSETSCatalogue URL that search_models searches. Defaults to the free CC0 model library.
AR_STUDIO_MCP_ENDPOINTMCP endpoint used for text-to-3D generation. Defaults to the free, keyless three.ws 3D Studio connector.
AR_STUDIO_ORIGINOrigin serving the hosted 'View in your space' launcher and the 3D viewer. Defaults to https://three.ws.

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npm3d-ar-studio-mcp0.3.0

工具

6

收录的工具列表 · 更新于 2 周前

参数类型必填说明
kindenum否model(道具、默认值)、avatar(已绑定骨骼的角色)或 mesh(先优化提示词,再按艺术指导生成)。model | avatar | mesh
tierenum否细节级别。级别越高,生成越慢。draft | standard | high
promptstring是要建模的单个物体或角色。

详细介绍

3D AR Studio

GitHub stars License Last commit PRs welcome AI agent friendly

将完整的增强现实工作室嵌入任意网页。

通过摄像头,在真实房间里放置任意数量的 3D 模型,描述一个新模型并看着它出现,手动布置所有内容,然后将整个场景分享为链接、二维码,或分享一个其他人可以与你一起搭建的实时房间。

在线演示 · npm · MCP 服务

<script type="module" src="https://unpkg.com/3d-ar-studio/dist/ar-studio.min.js"></script>
<ar-studio></ar-studio>

这就是一个可用的 AR 工作室。无需构建步骤、API 密钥或账户。它已接入免费的数百个公有领域模型库,以及免费的免密钥文本转 3D 通道;准备好后,只需一个选项即可连接你自己的目录。


为什么要做这个

每个可嵌入网页的 AR 工具都只会放置一个模型,然后交给原生查看器,导致会话结束。而这个工具会将整个场景保留在你的页面中:

  • 多个模型,同一个房间。 在同一个实时摄像头视图中,按需放置、拖动、捏合缩放、扭转旋转并复制任意数量的模型。
  • 无需离开摄像头即可生成。 在工具栏中输入“一盏黄铜台灯”。生成过程会在实时视图背后运行,完成后模型便会出现在房间里。
  • 在支持的设备上使用真正的 WebXR。 始终待命的命中测试准星、每个已放置模型对应一个 XRAnchor、真实世界光照估算,以及深度遮挡,让模型能隐藏在家具后面。
  • 其他设备上使用真正的 ARKit 和 ARCore。 iPhone 不支持 WebXR,因此点按 放置到你的空间 会真正打开 Apple 的 AR Quick Look:具备真实的平面检测、真实比例、真实遮挡,以及系统自带的“以 AR 查看”弹窗。模型会在设备上转换为 USDZ(通过 three.js 的 USDZExporter 进行真实转换,无需服务器参与);由于导出的是场景中已有的模型副本,因此模型会保持你捏合调整后的大小和原有姿态,并且立在地面上,而不会悬在它建模时恰好设定的高度。没有 WebXR 的 Android 设备会使用 Scene Viewer。桌面设备会显示网格预览,并通过二维码交接到手机。
  • 场景就是链接。 模型、位置、旋转和缩放都能通过 URL 往返传递。在笔记本电脑上编排,扫描二维码后,手机上会原样重新打开。
  • 一起实时搭建。 打开一个房间,分享一个六位字符代码,所有新增和移动操作都会同步给房间中的每个人。
  • 角色会真正动起来。 对于没有内置动画的任何类人 GLB,都会将待机动画片段重定向到其自身骨架。不限制绑定类型,也不会出现 T 姿势。
  • Agent 可以驱动它。 内置的 MCP 服务让 Claude、ChatGPT 或你自己的 Agent 生成模型、编排布局,并向用户提供一个可在其房间中打开的链接。

渲染层级、锚点生命周期、重定向管线、场景格式和共享房间协议均取自 three.ws 上投入生产的 AR 功能,并经过通用化处理,可在你的网站上与自己的模型配合使用。


安装

npm i 3d-ar-studio three

three 是对等依赖,因此你可以只保留一份并选择版本。CDN 包(dist/ar-studio.min.js)内含 three.js,无需其他依赖。

import { createArStudio } from '3d-ar-studio'

const studio = createArStudio('#stage', {
  branding: { title: 'Acme AR', accent: '#00b894' },
})

studio.on('add', ({ placement }) => console.log('placed', placement.title))

工作室会绝对定位并填满其宿主元素,因此请为宿主设置高度(任何具有实际高度的定位框都可以;没有高度的 <div> 会采用合理的 70vh 默认值,而不会渲染成不可见)。

搭建可部署的页面
npx 3d-ar-studio create my-ar-site     # a folder you can publish as-is
cd my-ar-site
npx 3d-ar-studio dev                   # look at it locally
npx 3d-ar-studio deploy                # push it and turn on GitHub Pages

deploy 会在运行每条 git 和 gh 命令前先打印出来。它需要 git 和 GitHub CLI;如果缺少它们,它会告诉你三个手动步骤,而不是悄无声息地失败。

模板:static(单个 HTML 文件,无需构建)、vite、react。

3d-ar-studio 和 ar-studio 都会运行 CLI。MCP 服务是独立软件包中的单独二进制文件,因此 npx 3d-ar-studio-mcp 可以正常解析:请参阅 MCP 服务。


使用自己的模型

托盘默认从 three.ws 加载内容:数百个公有领域(CC0)道具,可免费用于商业用途,并通过开放 CORS 提供服务。使用 assets 选项即可换成自己的内容。

任意位置的 JSON 文件。 无需调整格式即可读取五种常见结构:

createArStudio(el, { assets: 'https://cdn.acme.com/models.json' })
// Any of these work:
[ { "url": "https://cdn.acme.com/chair.glb", "name": "Aero chair" } ]
{ "items":     [ … ] }
{ "objects":   [ … ] }   // three.ws object library
{ "creations": [ … ] }   // three.ws forge gallery
{ "models":    [ … ] }

对于每个条目,模型 URL 会取自首个存在的 src、url、glb、glb_url、 glbUrl、file 或 model;标签取自 title、label、name 或 prompt;缩略图取自 poster、thumb、thumbnail、image 或 preview_image_url。任何非 https(或站点相对)URL 都会被丢弃,不会传给加载器。

在代码中维护的列表:

import { staticSource } from '3d-ar-studio/sources'

createArStudio(el, {
  assets: staticSource({
    label: 'Our furniture',
    items: [{ src: 'https://cdn.acme.com/chair.glb', title: 'Aero chair', poster: '…' }],
  }),
})

同时显示多个标签页,并按你指定的顺序排列:

createArStudio(el, { assets: ['recent', myCatalogue, 'objects', 'link'] })

内置键:'three.ws'(默认集合)、'recent'、'objects'、'community'、'link'。

其他任意来源。 来源是一个带有 list() 的对象:

createArStudio(el, {
  assets: {
    id: 'search',
    label: 'Search',
    searchable: true,
    async list() {
      const rows = await fetch('/api/models').then((r) => r.json())
      return rows.map((m) => ({ src: m.glb, title: m.name, poster: m.thumb }))
    },
  },
})

list() 抛出异常也没关系:托盘会显示精心设计的错误状态,并提供“重试”按钮。

用户也可以重新指定来源,无需改动你的代码:在页面 URL 中添加 ?assets=https://…/manifest.json。只接受 https URL,并且每个模型来源在交给加载器之前都会重新验证,因此恶意链接可以添加目录,但无法将 javascript: 或 data: 模型偷偷带入场景。设置 allowUrlOverride: false 即可关闭此功能。

CORS

模型由浏览器加载,因此托管 .glb 文件的主机必须允许跨源请求(access-control-allow-origin)。模型加载失败时,几乎总是这个原因;工作室会在状态栏中说明,而不是悄无声息地失败。


选项

选项默认值作用
assets'three.ws'模型来源:预设键、清单 URL、来源对象或它们的数组。
generateenabled{ enabled, endpoint, kind, tier, timeoutMs, pollMs }。endpoint 可以是任何提供兼容生成工具的 MCP 服务。
roomsenabled{ enabled, server }。将 server 指向你自己的 Colyseus 部署,即可自行托管共享房间。
animationsthree.ws idle clip{ enabled, manifestUrl, clip }。将此动画片段重定向到未自带动画的人形模型上。
lighting'studio' HDRI{ preset, urls }。preset: null 仅使用程序化光照,不下载 HDRI。
branding:{ title, accent, backHref, backLabel }。
shareBaseUrl此页面分享链接和 QR 码的指向位置。
originhttps://three.ws托管的“在你的空间中查看”启动器和查看器链接的源。
persistKey'ar-studio:scene:v1'保存场景的 localStorage 键。更改此项即可在同一源上运行两个工作室。
persisttrue加载时恢复上次的场景。
maxPlacements20同时放置的模型数量上限,确保低端手机仍可交互。
fullscreen自动以固定的全屏图层渲染。仅当挂载到 document.body 时,默认值才为 true。
allowUrlOverridetrue接受托管页面 URL 中的 ?assets=、?src=、?room= 和 ?forge= 参数。
onEventnull每发生一项重要操作时,都会以 (event, detail) 为参数调用。可将其接入你的分析工具。
URL 参数
参数效果
?assets=<https url>替换目录。
?src=<glb>&title=<name>将模型加载到场景中。可重复使用。
#s=<payload>重新打开完整布局,包括变换信息。由 shareUrl() 写入。
?room=<code>加入共享房间。
?forge=<prompt>加载时开始生成。
方法
await studio.addModel({ src, title })        // place a model
studio.clear()                               // remove everything; returns what was there
studio.getScene()                            // [{ src, title, x, z, yaw, scale }]
await studio.setScene(items)                 // replace the arrangement
studio.shareUrl()                            // a link that reopens it exactly
await studio.generate('a brass desk lamp')   // text to 3D, into the room
studio.viewInYourSpace(src, title)           // open the hosted launch page for one model
await studio.startCamera()                   // needs a user gesture on iOS
await studio.enterAR()                       // best AR path for this device
studio.openArSheet()                         // the "Place in your space" hand-off sheet
studio.closeArSheet()
await studio.placeInYourSpace()              // straight to the native viewer, no sheet
await studio.toggleImmersive()               // enter or leave WebXR specifically
await studio.openRoom()                      // returns the room code
studio.destroy()                             // releases camera, socket and GPU context
事件

studio.on(name, fn) 会返回一个取消订阅函数。同一事件也会在已挂载的元素上触发 ar-studio:<name> DOM 事件。

事件详情
add{ placement, remote }
remove{ src, title }
select{ placement }(取消选择时为 null)
clear{ items }
generate{ model }
generate-error{ error, prompt }
camera{ active }
xr{ active }
native-ar{ src, title, viewer },其中 viewer 为 quicklook、sceneviewer 或 none
native-ar-error{ error, src }
ar-sheet{ open },在交接面板打开或关闭时触发
room{ status, code }
share{ url }

Web 组件

<ar-studio
  assets="https://cdn.acme.com/models.json"
  title="Acme AR"
  accent="#00b894"
  generate="true"
  rooms="true"
></ar-studio>

element.studio 是当前实例。导入 3d-ar-studio/auto(CDN 包所做的操作)会自动注册该元素。


键盘与无障碍

每个控件都是真正的按钮,并带有无障碍名称;来源选项卡实现了完整的 ARIA tablist 规范;每个对话框都会接收并归还焦点。

按键操作
方向键相对于摄像头轻推选中的模型。按住 Shift 可进行微调。
R旋转 45°。
D复制。
Delete / Backspace移除,并在状态栏中提供撤销操作。
Escape关闭打开的面板,或取消选择。

prefers-reduced-motion 会移除入场动画和所有过渡效果。


MCP 服务

npx 3d-ar-studio-mcp
{
  "mcpServers": {
    "3d-ar-studio": {
      "command": "npx",
      "args": ["-y", "3d-ar-studio-mcp"]
    }
  }
}

无需 API 密钥。所有工具均免费且无需密钥。

工具功能
generate_3d_model将文本提示词转换为带纹理的 GLB。返回模型以及可在 AR 中打开模型的链接。
check_generation获取首次调用返回时仍在渲染的生成结果。
search_models按名称、类别和标签搜索免费的 CC0 库(或你配置的任意目录)。
compose_ar_scene将多个模型编排到同一场景中,并返回一个可精确还原该场景的链接。
export_ar将任意 GLB URL 转换为适配设备的“在你的空间中查看”链接。
create_ar_page生成完整、独立的 HTML 页面,其中嵌入工作室,可直接提交。
环境变量默认值更改内容
AR_STUDIO_PAGE_URL托管演示页面compose_ar_scene 链接到的页面。将其设置为你自己的部署地址。
AR_STUDIO_ASSETS免费的 CC0 库search_models 搜索的目录。
AR_STUDIO_MCP_ENDPOINTthree.ws 3D Studio用于生成的 MCP 端点。
AR_STUDIO_ORIGINhttps://three.ws托管的 AR 启动链接和查看器链接的来源地址。

会话示例如下:

> Put a mid-century lamp and a potted fern in my living room.

  generate_3d_model  { prompt: "a brass mid-century desk lamp" }   → lamp.glb
  search_models      { query: "potted plant" }                     → fern.glb
  compose_ar_scene   { models: [{ src: lamp.glb, x: 0,   z: -1.4 },
                                { src: fern.glb, x: 0.9, z: -1.2 }] }

  → one link; open it on a phone and both objects stand in the room.

设备支持

设备路径效果
Android ChromeWebXR immersive-ar将整个场景呈现在房间中:通过命中测试放置、为每个模型设置锚点、估算光照、进行深度遮挡。
iOS SafariAR Quick Look一次查看一个模型,使用 Apple 自带的查看器,并支持真实的 ARKit 跟踪、比例和遮挡。模型会在设备上转换为 USDZ。通过陀螺仪实现世界锁定的摄像头透视效果,可在页面内与之组合呈现多模型场景。
不支持 WebXR 的 Android 设备Scene Viewer一次通过 ARCore 查看一个模型;若缺少 ARCore,则回退到浏览器。
桌面设备预览网格地面、拖动环视、通过 QR 码转交到手机。
头显WebXR与 Android Chrome 相同。

顶部栏中的 AR 按钮始终选择设备支持的最佳路径,显示清晰标签,不会误导用户,并会作用于选中的模型(或最近放置的模型)。

摄像头和 WebXR 都需要安全上下文:https:// 或 localhost。

将一个模型放进某人的真实房间

在支持 WebXR 的设备上,AR 按钮会直接进入沉浸式会话。在其他设备上,它会打开交接面板:显示要放置的模型;如果场景中有多个模型,则提供选择器;并提供一个主按钮,用于打开设备自带的 AR 查看器。

该面板的存在有一个特定原因。如果你要基于此包构建自己的 UI,值得了解这一点:

只有在页面仍保留触发操作的用户手势时,iOS 才会打开 AR Quick Look。 将 GLB 转换为 USDZ 需要一两秒。如果在点击处理程序中启动转换,那么等到点击 <a rel="ar"> 时,用户手势就已失效,Safari 会悄无声息地拒绝操作,按钮看起来就像坏了一样。这是 iPhone 上“在 AR 中查看”按钮毫无反应最常见的原因。

紧接着还有第二个陷阱,而且更棘手,因为失败看起来像是成功:

Safari 根据 URL 的文件扩展名判断它是否为 AR 资源。 blob: URL 没有路径,因此也没有扩展名。将它交给 <a rel="ar">,但不提供文件名,Safari 仍会打开 Quick Look,不过会将其作为通用 3D 预览:查看器会进入对象模式,且无法使用 AR。在锚点上设置 download="something.usdz",就能为 Safari 提供它用于判断的文件名,Quick Look 也会进入 AR 模式。openQuickLook() 会替你完成这一操作。

因此,该包将准备和打开分开处理,绝不会在一次点击中同时完成:

import { prepareNativeAr, isQuickLookReady } from '3d-ar-studio';

// Ahead of the tap: convert, cache, and keep the result.
const handoff = await prepareNativeAr({
  src: 'https://example.com/chair.glb',
  title: 'Chair',
  key: '[email protected]',            // cache identity; include the scale if you bake one in
});

// Inside the tap, synchronously. No await between the click and open().
button.addEventListener('click', () => handoff?.open());

在没有原生 AR 查看器的设备上,prepareNativeAr 会解析为 null;在 USDZ 已准备好、可通过 blob: 打开的 iOS 设备上,会解析为 { viewer: 'quicklook' };在无需转换任何内容的 Android 设备上,则会解析为 { viewer: 'sceneviewer' }。转换结果会被缓存(同时最多缓存四项,采用最近最少使用策略;淘汰时会撤销对象 URL);你可以通过 isQuickLookReady(key)、 releaseQuickLook(key) 和 clearQuickLookCache() 自行管理缓存。

工作室会在后台预热按钮将要发送的模型对应的缓存,因此当天第二次点击时即可立即打开。placeInYourSpace() 仍然可用,也仍会在一次调用中完成这两步:如果 USDZ 已缓存,或者你从自己已准备好的按钮调用它,就可以使用该方法。

从实时场景而非重新获取 GLB 来导出,也是有意为之:无需再次下载,也无需再次进行 CORS 往返,而且用户看到的姿势和尺寸会保持不变。如果你想在自己的 three.js 场景中使用该功能,也可以使用导出的 objectToUsdzBlob(object3D)。

为什么模型会悬在空中,而不是落在地面上

第三个陷阱,也是前两个问题都解决后仍然存在的问题:

AR Quick Look 会将场景的 ORIGIN 锚定到它检测到的平面上,而不会检查几何体。 以边界框中心为基准创作的 GLB 会有一半埋在地里;以远处场景原点为基准创作的模型,则会按照建模时的高度,漂浮在房间里的某个位置。这两种情况看起来都像跟踪失效,而且任何锚定属性都无法修复:必须移动内容。

因此,本软件包导出的所有内容在写入前,都会将模型放置在 y = 0 上,并让其占地范围以原点为中心。如果你想对自己的场景进行同样的处理,可以使用导出的 groundOnFloor()。

还有两个较小的问题也一并处理了:

USDZExporter 会遍历 scene.children 并写入每个节点的局部矩阵,因此你交给它的对象变换根本不会写入。若在根节点上设置缩放,导出的文件会保持原始大小,而且不会发出警告。usdzExportRoot() 会将内容包装在一个恒等根节点和一个 Model 阶段节点中,本软件包应用的所有放置变换都会施加到阶段节点上,而该节点确实会写入文件。

USDZ 使用米制单位(metersPerUnit = 1)。以厘米为单位创作的 75 cm 道具,导入后会高达 75 m,任何室内 ARKit 检测到的平面都无法容纳它,因此模型会在用户周围漂移。将 { fit: true } 传给 sceneToUsdzBlob()(glbUrlToUsdzBlob() 已经会这样做),即可直接将从网络加载的模型规范化。任何尺寸已在可信现实尺寸的 2 倍范围内的模型,都会保持创作时的原样。

最后,还有一个最像跟踪失效的问题:

Quick Look 要等 ARKit 找到足以容纳模型的平面后,才会放置模型。 在此之前,模型会与相机对齐并随手机移动。模型尺寸超过一定范围后,普通房间里就不会有足够大的平面,因此它永远不会落地。所有导出内容都会通过 clampToPlaceableSize() 限制在 MAX_AR_FOOTPRINT_M(2.5 m)和 MAX_AR_HEIGHT_M(2.5 m)以内。这只是上限,并非规范化处理:家具、人物和道具都会保持原样。

相机一次只能供一个客户端使用

进入设备的 AR 查看器时,工作室会释放其 getUserMedia 直通流,返回后再重新启动。如果让页面的视频流继续运行,ARKit 启动时就会发现摄像头已被另一个进程占用:模型会出现,但世界跟踪和平面检测始终无法收敛,因此模型会随着手机漂移,而不是稳定下来。如果你要从自己的相机 UI 控制交接,请在调用 open() 前停止所有轨道。

直通模式本质上是在视频流上叠加陀螺仪效果:画面会随你转动,仅此而已。它没有平面检测或位置跟踪,因此永远无法让模型固定在真实地面的某个位置上。在 iOS 上,这正是 Quick Look 的用途,工作室的状态栏也会对此作出说明。


开发

npm install
npm test                 # 75 unit tests, no browser needed
npm run build            # dist/ bundles
npm run build:site       # docs/ (the GitHub Pages site)
npm run test:browser     # 35 end-to-end checks in a real browser (needs Playwright)
npm run inspect          # MCP Inspector against the local server

已发布的网站提交在 docs/ 下,并由 GitHub Pages 从 main 分支提供服务。没有 CI 工作流:npm run build && npm run build:site,然后提交并推送。


许可与致谢

Apache-2.0。

此软件包包含 three.js(MIT)和 colyseus.js(MIT)。默认模型库采用来自 Poly Haven 的 CC0 内容,默认的生成和动画通道由 three.ws 托管。它们都不是必需的:每一项都可以替换为你指定的 URL。

Star 历史

Star 历史图表

支持该项目

如果 3D-AR-Studio 为你节省了时间,请在 GitHub 上为它点星。星标能帮助其他开发者和 AI Agent 找到值得信赖的代码仓库,而且只需点击一下。

认识可能会用到它的人吗?在 X 上发布 · 在 Bluesky 上分享 · 在 LinkedIn 上分享 · 提交到 Hacker News · 在 Reddit 上分享

同样为 AI Agent 打造

编码 Agent 和大模型工具可以直接读取此代码仓库:AGENTS.md、llms.txt、llms-full.txt。将 https://github.com/nirholas/3D-AR-Studio 提供给 Agent,它就能获取所需的上下文。

作者的更多项目

贡献者

贡献者

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。