sceneview-mcp 3.4.6 → 3.4.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -11,6 +11,7 @@ import { MIGRATION_GUIDE } from "./migration.js";
11
11
  import { fetchKnownIssues } from "./issues.js";
12
12
  import { parseNodeSections, findNodeSection, listNodeTypes } from "./node-reference.js";
13
13
  import { PLATFORM_ROADMAP, BEST_PRACTICES, AR_SETUP_GUIDE, TROUBLESHOOTING_GUIDE } from "./guides.js";
14
+ import { buildPreviewUrl, validatePreviewInput, formatPreviewResponse } from "./preview.js";
14
15
  const __dirname = dirname(fileURLToPath(import.meta.url));
15
16
  let API_DOCS;
16
17
  try {
@@ -205,24 +206,32 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
205
206
  },
206
207
  {
207
208
  name: "render_3d_preview",
208
- description: "Generates an interactive 3D preview link for a glTF/GLB model. Returns a URL to sceneview.github.io/preview that renders the model in the browser with orbit controls, AR support, and sharing. Use this when you want to show a 3D model to the user — paste the link in your response and they can click to see it live. Also works with any publicly accessible .glb URL.",
209
+ description: "Generates an interactive 3D preview link. Accepts a model URL, a SceneView code snippet, or both. Returns a URL to sceneview.github.io/preview that renders the model in the browser with orbit controls, AR support, and sharing. For model URLs: embeds a model-viewer link directly. For code snippets: shows the 3D preview with the code in a companion panel. Use this when you want to show a 3D model to the user — paste the link in your response and they can click to see it live.",
209
210
  inputSchema: {
210
211
  type: "object",
211
212
  properties: {
212
213
  modelUrl: {
213
214
  type: "string",
214
- description: "Public URL to a .glb or .gltf model file. Must be HTTPS and CORS-enabled.",
215
+ description: "Public URL to a .glb or .gltf model file. Must be HTTPS and CORS-enabled. If omitted, a default model is used.",
216
+ },
217
+ codeSnippet: {
218
+ type: "string",
219
+ description: "SceneView code snippet (Kotlin or Swift) to display alongside the 3D preview in a companion panel. Useful when showing generated code together with a live preview.",
215
220
  },
216
221
  autoRotate: {
217
222
  type: "boolean",
218
- description: "Auto-rotate the model (default: true)",
223
+ description: "Auto-rotate the model (default: true).",
219
224
  },
220
225
  ar: {
221
226
  type: "boolean",
222
- description: "Enable AR mode on supported devices (default: true)",
227
+ description: "Enable AR mode on supported devices (default: true).",
228
+ },
229
+ title: {
230
+ type: "string",
231
+ description: "Custom title shown above the preview.",
223
232
  },
224
233
  },
225
- required: ["modelUrl"],
234
+ required: [],
226
235
  },
227
236
  },
228
237
  ],
@@ -718,41 +727,20 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
718
727
  // ── render_3d_preview ──────────────────────────────────────────────────
719
728
  case "render_3d_preview": {
720
729
  const modelUrl = request.params.arguments?.modelUrl;
721
- const autoRotate = request.params.arguments?.autoRotate ?? true;
722
- const ar = request.params.arguments?.ar ?? true;
723
- if (!modelUrl) {
730
+ const codeSnippet = request.params.arguments?.codeSnippet;
731
+ const autoRotate = request.params.arguments?.autoRotate;
732
+ const ar = request.params.arguments?.ar;
733
+ const title = request.params.arguments?.title;
734
+ const validationError = validatePreviewInput(modelUrl, codeSnippet);
735
+ if (validationError) {
724
736
  return {
725
- content: [{ type: "text", text: "Error: modelUrl is required. Provide a public HTTPS URL to a .glb or .gltf file." }],
737
+ content: [{ type: "text", text: `Error: ${validationError}` }],
726
738
  isError: true,
727
739
  };
728
740
  }
729
- const params = new URLSearchParams();
730
- params.set("model", modelUrl);
731
- if (!autoRotate)
732
- params.set("rotate", "false");
733
- if (!ar)
734
- params.set("ar", "false");
735
- const previewUrl = `https://sceneview.github.io/preview?${params.toString()}`;
736
- return {
737
- content: [{
738
- type: "text",
739
- text: `## 3D Preview
740
-
741
- **[Click to view the 3D model interactively →](${previewUrl})**
742
-
743
- The link opens an interactive 3D viewer where you can:
744
- - 🖱️ Drag to orbit, scroll to zoom
745
- - 📱 "View in AR" on mobile devices (ARCore/ARKit)
746
- - 🔗 Share the link with anyone
747
-
748
- **Preview URL:** ${previewUrl}
749
-
750
- **Model:** ${modelUrl}
751
-
752
- ---
753
- *Powered by SceneView — 3D & AR for every platform*`,
754
- }],
755
- };
741
+ const result = buildPreviewUrl({ modelUrl, codeSnippet, autoRotate, ar, title });
742
+ const text = formatPreviewResponse(result);
743
+ return { content: [{ type: "text", text }] };
756
744
  }
757
745
  default:
758
746
  return {
@@ -0,0 +1,78 @@
1
+ // ─── 3D Preview Link Generator ───────────────────────────────────────────────
2
+ //
3
+ // Generates embeddable preview URLs for sceneview.github.io/preview.
4
+ // Two modes:
5
+ // 1. Model URL → direct model-viewer embed link
6
+ // 2. Code snippet → embed link with default model + code panel
7
+ const PREVIEW_BASE = "https://sceneview.github.io/preview";
8
+ const DEFAULT_MODEL_URL = "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/DamagedHelmet/glTF-Binary/DamagedHelmet.glb";
9
+ /**
10
+ * Build a sceneview.github.io/preview URL from the given options.
11
+ *
12
+ * - If `modelUrl` is supplied it is embedded directly.
13
+ * - If only `codeSnippet` is supplied a default model is used and the code is
14
+ * passed via the `code` query parameter so the preview page can show it in a
15
+ * companion panel.
16
+ * - If both are supplied the model URL takes priority and the code is included.
17
+ */
18
+ export function buildPreviewUrl(options) {
19
+ const model = options.modelUrl || DEFAULT_MODEL_URL;
20
+ const hasCode = Boolean(options.codeSnippet?.trim());
21
+ const title = options.title || (hasCode && !options.modelUrl ? "SceneView Code Preview" : "3D Model Preview");
22
+ const params = new URLSearchParams();
23
+ params.set("model", model);
24
+ if (options.autoRotate === false)
25
+ params.set("rotate", "false");
26
+ if (options.ar === false)
27
+ params.set("ar", "false");
28
+ if (options.title)
29
+ params.set("title", options.title);
30
+ if (hasCode)
31
+ params.set("code", options.codeSnippet.trim());
32
+ const previewUrl = `${PREVIEW_BASE}?${params.toString()}`;
33
+ return { previewUrl, modelUrl: model, hasCode, title };
34
+ }
35
+ /**
36
+ * Validate preview input — at least one of modelUrl or codeSnippet must be provided.
37
+ */
38
+ export function validatePreviewInput(modelUrl, codeSnippet) {
39
+ if (!modelUrl && !codeSnippet) {
40
+ return "At least one of `modelUrl` or `codeSnippet` is required.";
41
+ }
42
+ if (modelUrl) {
43
+ if (!modelUrl.startsWith("https://") && !modelUrl.startsWith("http://")) {
44
+ return "modelUrl must be an HTTP(S) URL.";
45
+ }
46
+ if (!/\.(glb|gltf)(\?|$)/i.test(modelUrl)) {
47
+ return "modelUrl should point to a .glb or .gltf file.";
48
+ }
49
+ }
50
+ return null;
51
+ }
52
+ /**
53
+ * Format the preview result as a rich text response for the MCP tool.
54
+ */
55
+ export function formatPreviewResponse(result) {
56
+ const lines = [
57
+ `## ${result.title}`,
58
+ ``,
59
+ `**[Click to view the 3D model interactively \u2192](${result.previewUrl})**`,
60
+ ``,
61
+ `The link opens an interactive 3D viewer where you can:`,
62
+ `- Drag to orbit, scroll to zoom`,
63
+ `- "View in AR" on mobile devices (ARCore/ARKit)`,
64
+ `- Share the link with anyone`,
65
+ ``,
66
+ `**Preview URL:** ${result.previewUrl}`,
67
+ ``,
68
+ `**Model:** ${result.modelUrl}`,
69
+ ];
70
+ if (result.hasCode) {
71
+ lines.push(``);
72
+ lines.push(`*The code snippet is included in the preview page as a companion panel.*`);
73
+ }
74
+ lines.push(``);
75
+ lines.push(`---`);
76
+ lines.push(`*Powered by SceneView \u2014 3D & AR for every platform*`);
77
+ return lines.join("\n");
78
+ }
package/llms.txt CHANGED
@@ -2247,12 +2247,123 @@ ARSceneView.checkSupport { supported ->
2247
2247
 
2248
2248
  ---
2249
2249
 
2250
+ ## Android XR (Planned)
2251
+
2252
+ SceneView can be used inside Android XR's spatial layout system via the Jetpack XR SDK
2253
+ (Developer Preview). The integration embeds SceneView's `Scene {}` composable inside a
2254
+ `SpatialPanel`, giving full Filament rendering inside an XR spatial panel.
2255
+
2256
+ **Dependencies (in addition to SceneView):**
2257
+ ```kotlin
2258
+ implementation("androidx.xr.scenecore:scenecore:1.0.0-alpha12")
2259
+ implementation("androidx.xr.compose:compose:1.0.0-alpha12")
2260
+ ```
2261
+
2262
+ **Basic pattern:**
2263
+ ```kotlin
2264
+ Subspace {
2265
+ SpatialPanel(SubspaceModifier.width(1200.dp).height(800.dp)) {
2266
+ val engine = rememberEngine()
2267
+ val modelLoader = rememberModelLoader(engine)
2268
+ Scene(modifier = Modifier.fillMaxSize(), engine = engine, modelLoader = modelLoader) {
2269
+ rememberModelInstance(modelLoader, "models/helmet.glb")?.let {
2270
+ ModelNode(modelInstance = it)
2271
+ }
2272
+ }
2273
+ }
2274
+ }
2275
+ ```
2276
+
2277
+ Key XR composables: `Subspace`, `SpatialPanel`, `SpatialRow`, `SpatialColumn`, `Orbiter`,
2278
+ `SceneCoreEntity`. SceneCore entities: `GltfModelEntity`, `PanelEntity`, `AnchorEntity`,
2279
+ `SpatialEnvironment`. Status: **experimental / planned** — Jetpack XR SDK is alpha.
2280
+
2281
+ ---
2282
+
2283
+ ## visionOS Spatial Computing (Planned)
2284
+
2285
+ SceneViewSwift targets visionOS 1+ via RealityKit. Spatial features are planned for future
2286
+ releases, building on the existing `SceneView` and node types.
2287
+
2288
+ ### Scene Types
2289
+
2290
+ | Type | Style | Description | SceneViewSwift |
2291
+ |---|---|---|---|
2292
+ | Window | 2D | Standard SwiftUI window in shared space | `SceneView { }` (existing) |
2293
+ | Volume | 3D bounded | Fixed-size 3D container in shared space | `VolumetricSceneView` (planned) |
2294
+ | Immersive Space | `.mixed` | Virtual content blends with passthrough | `ImmersiveSceneView` (planned) |
2295
+ | Immersive Space | `.progressive` | Partial passthrough replacement | `ImmersiveSceneView` (planned) |
2296
+ | Immersive Space | `.full` | Fully virtual, passthrough off | `ImmersiveSceneView` (planned) |
2297
+
2298
+ ### Hand Tracking (visionOS 1+, Full Space required)
2299
+
2300
+ ARKit `HandTrackingProvider` tracks 27 joints per hand at display refresh rate.
2301
+ Requires `NSHandsTrackingUsageDescription` in Info.plist and a `SpatialTrackingSession`.
2302
+
2303
+ **Planned API:**
2304
+ ```swift
2305
+ ImmersiveSceneView { root in /* content */ }
2306
+ .handTracking(enabled: true)
2307
+ .onHandUpdate { hands in
2308
+ if let d = hands.jointDistance(.thumbTip, .indexFingerTip, hand: .right), d < 0.02 {
2309
+ // Pinch detected
2310
+ }
2311
+ }
2312
+ ```
2313
+
2314
+ ### Spatial Anchors
2315
+
2316
+ `SpatialTrackingSession` (visionOS 2.0+) unlocks ARKit data in RealityKit: anchor
2317
+ geometry extents, real-world offset, and scene understanding mesh.
2318
+
2319
+ **Planned API:**
2320
+ ```swift
2321
+ // World anchor
2322
+ SpatialAnchorNode.world(position: SIMD3<Float>(0, 1, -2))
2323
+
2324
+ // Plane anchor (on detected surface)
2325
+ SpatialAnchorNode.plane(alignment: .horizontal)
2326
+
2327
+ // Hand anchor (attached to a joint)
2328
+ SpatialAnchorNode.hand(.right, joint: .indexFingerTip)
2329
+ ```
2330
+
2331
+ ### Scene Understanding
2332
+
2333
+ Real-time mesh of surroundings enabling collision, physics, surface classification
2334
+ (floor, wall, ceiling, table, seat, door, window), and environment occlusion.
2335
+
2336
+ ### Object Manipulation (visionOS 26)
2337
+
2338
+ `ManipulationComponent` enables look, tap, drag, rotate, scale on entities with a
2339
+ single call. `EnvironmentBlendingComponent` for real-world occlusion.
2340
+ `MeshInstancesComponent` for efficient GPU instanced rendering.
2341
+
2342
+ **Planned API:**
2343
+ ```swift
2344
+ let model = try await ModelNode.load("models/chair.usdz")
2345
+ model.enableManipulation() // look + grab + drag + rotate + scale via system gestures
2346
+ ```
2347
+
2348
+ ### Cross-Platform Mapping (visionOS <-> Android XR)
2349
+
2350
+ | Feature | visionOS | Android XR |
2351
+ |---|---|---|
2352
+ | Spatial container | Volume (`.volumetric`) | `SpatialPanel` |
2353
+ | Immersive mode | `ImmersiveSpace` | `SpatialEnvironment` |
2354
+ | Hand tracking | `HandTrackingProvider` | Jetpack XR hand tracking |
2355
+ | Spatial anchors | `WorldAnchor` | `AnchorEntity` (SceneCore) |
2356
+ | Scene understanding | Scene mesh + classification | Perception APIs |
2357
+
2358
+ ---
2359
+
2250
2360
  ## Platform Coverage Summary
2251
2361
 
2252
2362
  | Platform | Renderer | Framework | Sample | Status |
2253
2363
  |---|---|---|---|---|
2254
2364
  | Android | Filament | Jetpack Compose | `samples/android-demo` | Stable |
2255
2365
  | Android TV | Filament | Compose TV | `samples/android-tv-demo` | Alpha |
2366
+ | Android XR | Filament + SceneCore | Compose for XR | — | Planned |
2256
2367
  | iOS | RealityKit | SwiftUI | `samples/ios-demo` | Alpha |
2257
2368
  | macOS | RealityKit | SwiftUI | via SceneViewSwift | Alpha |
2258
2369
  | visionOS | RealityKit | SwiftUI | via SceneViewSwift | Alpha |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sceneview-mcp",
3
- "version": "3.4.6",
3
+ "version": "3.4.7",
4
4
  "mcpName": "io.github.sceneview/mcp",
5
5
  "description": "MCP server for SceneView — cross-platform 3D & AR SDK for Android and iOS. Give Claude the full SceneView SDK so it writes correct, compilable code.",
6
6
  "keywords": [
@@ -43,6 +43,7 @@
43
43
  "dist/migration.js",
44
44
  "dist/node-reference.js",
45
45
  "dist/samples.js",
46
+ "dist/preview.js",
46
47
  "dist/validator.js",
47
48
  "llms.txt"
48
49
  ],