sceneview-mcp 3.4.9 → 3.4.10

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.
Files changed (3) hide show
  1. package/dist/artifact.js +153 -104
  2. package/llms.txt +2 -2
  3. package/package.json +5 -5
package/dist/artifact.js CHANGED
@@ -3,13 +3,16 @@
3
3
  // Generates complete, self-contained HTML artifacts with interactive 3D content
4
4
  // that Claude can render directly in conversations via artifacts.
5
5
  //
6
+ // Uses Filament.js (Google's PBR renderer, WASM) for real 3D rendering —
7
+ // the same engine as SceneView Android.
8
+ //
6
9
  // Types:
7
- // - model-viewer: interactive 3D model viewer with orbit controls + AR
8
- // - chart-3d: 3D bar/pie charts for data visualization
9
- // - scene: multi-model 3D scene with lighting and environment
10
- // - product-360: product turntable with hotspot annotations + AR
10
+ // - model-viewer: interactive 3D model viewer with orbit controls (Filament.js)
11
+ // - chart-3d: 3D bar/pie charts for data visualization (CSS 3D)
12
+ // - scene: multi-model 3D scene with lighting and environment (Filament.js)
13
+ // - product-360: product turntable with hotspot annotations (Filament.js)
11
14
  // ─── Constants ───────────────────────────────────────────────────────────────
12
- const MODEL_VIEWER_CDN = "https://ajax.googleapis.com/ajax/libs/model-viewer/4.0.0/model-viewer.min.js";
15
+ const FILAMENT_CDN = "https://cdn.jsdelivr.net/npm/filament@1.52.3/filament.js";
13
16
  const DEFAULT_MODEL = "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/main/Models/DamagedHelmet/glTF-Binary/DamagedHelmet.glb";
14
17
  const DEFAULT_COLORS = [
15
18
  "#4285F4", "#EA4335", "#FBBC04", "#34A853", "#FF6D01",
@@ -26,7 +29,7 @@ function htmlShell(title, body, extraHead = "") {
26
29
  <title>${escapeHtml(title)}</title>
27
30
  <style>
28
31
  *{margin:0;padding:0;box-sizing:border-box}
29
- html,body{width:100%;height:100%;overflow:hidden;background:#1a1a2e;color:#e0e0e0;font-family:system-ui,-apple-system,sans-serif}
32
+ html,body{width:100%;height:100%;overflow:hidden;background:#0d1117;color:#e0e0e0;font-family:system-ui,-apple-system,sans-serif}
30
33
  </style>
31
34
  ${extraHead}
32
35
  </head>
@@ -74,44 +77,125 @@ export function generateArtifact(input) {
74
77
  return generateProduct360(input);
75
78
  }
76
79
  }
80
+ // ─── Filament.js renderer core ──────────────────────────────────────────────
81
+ //
82
+ // Shared inline script that sets up the Filament engine, scene, camera,
83
+ // lights, orbit controls, and render loop. Used by model-viewer, scene,
84
+ // and product-360 artifact types.
85
+ function filamentRendererScript(options) {
86
+ const { modelUrl, bgColor, autoRotate, orbitRadius = 3.5, orbitHeight = 0.8, sunIntensity = 110000, fillIntensity = 30000, } = options;
87
+ return `<script src="${FILAMENT_CDN}"><\/script>
88
+ <script>
89
+ Filament.init(['${modelUrl}'], function() {
90
+ try {
91
+ var canvas = document.getElementById('viewer');
92
+ canvas.width = canvas.clientWidth * devicePixelRatio;
93
+ canvas.height = canvas.clientHeight * devicePixelRatio;
94
+
95
+ var engine = Filament.Engine.create(canvas);
96
+ var scene = engine.createScene();
97
+ var renderer = engine.createRenderer();
98
+ var cam = engine.createCamera(Filament.EntityManager.get().create());
99
+ var view = engine.createView();
100
+ var sc = engine.createSwapChain();
101
+
102
+ view.setCamera(cam);
103
+ view.setScene(scene);
104
+ view.setViewport([0, 0, canvas.width, canvas.height]);
105
+ renderer.setClearOptions({ clearColor: [${bgColor.join(",")}], clear: true });
106
+ cam.setProjectionFov(45, canvas.width / canvas.height, 0.1, 100, Filament.Camera$Fov.VERTICAL);
107
+
108
+ // Sun light (warm key light)
109
+ var sun = Filament.EntityManager.get().create();
110
+ Filament.LightManager.Builder(Filament.LightManager$Type.SUN)
111
+ .color([0.98, 0.92, 0.89]).intensity(${sunIntensity}).direction([0.6, -1, -0.8])
112
+ .sunAngularRadius(1.9).sunHaloSize(10).sunHaloFalloff(80)
113
+ .build(engine, sun);
114
+ scene.addEntity(sun);
115
+
116
+ // Fill light (cool)
117
+ var fill = Filament.EntityManager.get().create();
118
+ Filament.LightManager.Builder(Filament.LightManager$Type.DIRECTIONAL)
119
+ .color([0.6, 0.65, 0.8]).intensity(${fillIntensity}).direction([-0.5, 0.5, 1])
120
+ .build(engine, fill);
121
+ scene.addEntity(fill);
122
+
123
+ // Load model
124
+ var loader = engine.createAssetLoader();
125
+ var asset = loader.createAsset(Filament.assets['${modelUrl}']);
126
+ if (asset) {
127
+ asset.loadResources();
128
+ scene.addEntity(asset.getRoot());
129
+ scene.addEntities(asset.getRenderableEntities());
130
+ }
131
+
132
+ // Orbit controls
133
+ var angle = 0, orbitR = ${orbitRadius}, orbitH = ${orbitHeight};
134
+ var dragging = false, lastX = 0, lastY = 0, autoRotate = ${autoRotate};
135
+
136
+ canvas.addEventListener('mousedown', function(e) { dragging = true; lastX = e.clientX; lastY = e.clientY; autoRotate = false; });
137
+ canvas.addEventListener('mousemove', function(e) { if (!dragging) return; angle += (e.clientX - lastX) * 0.005; orbitH += (e.clientY - lastY) * 0.01; lastX = e.clientX; lastY = e.clientY; });
138
+ canvas.addEventListener('mouseup', function() { dragging = false; });
139
+ canvas.addEventListener('mouseleave', function() { dragging = false; });
140
+ canvas.addEventListener('wheel', function(e) { e.preventDefault(); orbitR *= (1 + e.deltaY * 0.001); orbitR = Math.max(0.5, Math.min(20, orbitR)); }, { passive: false });
141
+ canvas.addEventListener('touchstart', function(e) { if (e.touches.length === 1) { dragging = true; lastX = e.touches[0].clientX; lastY = e.touches[0].clientY; autoRotate = false; } });
142
+ canvas.addEventListener('touchmove', function(e) { if (!dragging) return; e.preventDefault(); angle += (e.touches[0].clientX - lastX) * 0.005; orbitH += (e.touches[0].clientY - lastY) * 0.01; lastX = e.touches[0].clientX; lastY = e.touches[0].clientY; }, { passive: false });
143
+ canvas.addEventListener('touchend', function() { dragging = false; });
144
+
145
+ // Handle resize
146
+ new ResizeObserver(function() {
147
+ canvas.width = canvas.clientWidth * devicePixelRatio;
148
+ canvas.height = canvas.clientHeight * devicePixelRatio;
149
+ view.setViewport([0, 0, canvas.width, canvas.height]);
150
+ cam.setProjectionFov(45, canvas.width / canvas.height, 0.1, 100, Filament.Camera$Fov.VERTICAL);
151
+ }).observe(canvas);
152
+
153
+ // Render loop
154
+ function render() {
155
+ if (autoRotate) angle += 0.006;
156
+ cam.lookAt([Math.sin(angle) * orbitR, orbitH, Math.cos(angle) * orbitR], [0, 0, 0], [0, 1, 0]);
157
+ if (renderer.beginFrame(sc)) { renderer.render(sc, view); renderer.endFrame(); }
158
+ engine.execute();
159
+ requestAnimationFrame(render);
160
+ }
161
+ render();
162
+
163
+ // Update status
164
+ var statusEl = document.getElementById('status');
165
+ if (statusEl) { statusEl.textContent = 'Drag to rotate \\u00b7 Scroll to zoom'; statusEl.style.color = '#34a853'; }
166
+
167
+ } catch(e) {
168
+ var statusEl = document.getElementById('status');
169
+ if (statusEl) { statusEl.textContent = 'Error: ' + e.message; statusEl.style.color = '#ea4335'; }
170
+ console.error(e);
171
+ }
172
+ });
173
+ <\/script>`;
174
+ }
175
+ /** Convert hex color to Filament RGBA [0-1] range */
176
+ function hexToBgColor(hex) {
177
+ const rgb = hexToRgb(hex);
178
+ return [rgb.r / 255, rgb.g / 255, rgb.b / 255, 1.0];
179
+ }
77
180
  // ── model-viewer ─────────────────────────────────────────────────────────────
78
181
  function generateModelViewer(input) {
79
182
  const model = input.modelUrl || DEFAULT_MODEL;
80
183
  const title = input.title || "3D Model Viewer";
81
184
  const opts = input.options || {};
82
- const bg = opts.backgroundColor || "#1a1a2e";
83
- const orbit = opts.cameraOrbit || "0deg 75deg 105%";
185
+ const bg = opts.backgroundColor || "#0d1117";
84
186
  const autoRotate = opts.autoRotate !== false;
85
- const ar = opts.ar !== false;
86
- const arAttrs = ar
87
- ? `ar ar-modes="webxr scene-viewer quick-look"`
88
- : "";
89
- const rotateAttr = autoRotate ? `auto-rotate auto-rotate-delay="0"` : "";
90
187
  const body = `
91
188
  <style>
92
- model-viewer{width:100%;height:100%;background:${bg};--poster-color:${bg}}
189
+ canvas{width:100%;height:100%;cursor:grab;display:block}
190
+ canvas:active{cursor:grabbing}
93
191
  .title{position:absolute;top:16px;left:16px;font-size:18px;font-weight:600;color:#fff;text-shadow:0 2px 8px rgba(0,0,0,0.5);z-index:10}
94
- .ar-btn{position:absolute;bottom:16px;left:50%;transform:translateX(-50%);padding:10px 24px;background:rgba(66,133,244,0.9);color:#fff;border:none;border-radius:24px;font-size:14px;font-weight:500;cursor:pointer;backdrop-filter:blur(8px);z-index:10}
95
- .ar-btn:hover{background:rgba(66,133,244,1)}
192
+ #status{position:absolute;top:44px;left:16px;font-size:12px;color:#8ab4f8;z-index:10}
96
193
  </style>
97
- <script type="module" src="${MODEL_VIEWER_CDN}"></script>
98
194
  <div class="title">${escapeHtml(title)}</div>
99
- <model-viewer
100
- src="${escapeHtml(model)}"
101
- camera-controls
102
- touch-action="pan-y"
103
- camera-orbit="${escapeHtml(orbit)}"
104
- shadow-intensity="1"
105
- shadow-softness="0.5"
106
- exposure="1"
107
- environment-image="neutral"
108
- ${rotateAttr}
109
- ${arAttrs}
110
- style="width:100%;height:100%"
111
- >
112
- ${ar ? `<button slot="ar-button" class="ar-btn">View in AR</button>` : ""}
113
- </model-viewer>
114
- ${BRANDING}`;
195
+ <div id="status">Loading Filament.js WASM...</div>
196
+ <canvas id="viewer"></canvas>
197
+ ${BRANDING}
198
+ ${filamentRendererScript({ modelUrl: model, bgColor: hexToBgColor(bg), autoRotate })}`;
115
199
  return {
116
200
  html: htmlShell(title, body),
117
201
  title,
@@ -122,7 +206,7 @@ ${BRANDING}`;
122
206
  function generateChart3D(input) {
123
207
  const title = input.title || "3D Data Visualization";
124
208
  const data = input.data;
125
- const bg = input.options?.backgroundColor || "#1a1a2e";
209
+ const bg = input.options?.backgroundColor || "#0d1117";
126
210
  const maxVal = Math.max(...data.map((d) => d.value));
127
211
  const bars = data
128
212
  .map((d, i) => {
@@ -177,41 +261,24 @@ function generateScene(input) {
177
261
  const model = input.modelUrl || DEFAULT_MODEL;
178
262
  const title = input.title || "3D Scene";
179
263
  const opts = input.options || {};
180
- const bg = opts.backgroundColor || "#1a1a2e";
264
+ const bg = opts.backgroundColor || "#0d1117";
181
265
  const autoRotate = opts.autoRotate !== false;
182
- const ar = opts.ar !== false;
183
- const orbit = opts.cameraOrbit || "0deg 75deg 150%";
184
- const arAttrs = ar ? `ar ar-modes="webxr scene-viewer quick-look"` : "";
185
- const rotateAttr = autoRotate ? `auto-rotate auto-rotate-delay="0"` : "";
186
266
  const body = `
187
267
  <style>
188
- model-viewer{width:100%;height:100%;background:${bg};--poster-color:${bg}}
268
+ canvas{width:100%;height:100%;cursor:grab;display:block}
269
+ canvas:active{cursor:grabbing}
189
270
  .scene-title{position:absolute;top:16px;left:16px;font-size:20px;font-weight:700;color:#fff;text-shadow:0 2px 12px rgba(0,0,0,0.6);z-index:10;letter-spacing:-0.3px}
190
271
  .scene-info{position:absolute;top:44px;left:16px;font-size:12px;color:#aaa;z-index:10}
272
+ #status{position:absolute;top:64px;left:16px;font-size:11px;color:#8ab4f8;z-index:10}
191
273
  .controls-hint{position:absolute;bottom:16px;left:16px;font-size:11px;color:#666;z-index:10}
192
- .ar-btn{position:absolute;bottom:16px;right:16px;padding:10px 20px;background:rgba(66,133,244,0.9);color:#fff;border:none;border-radius:24px;font-size:13px;font-weight:500;cursor:pointer;z-index:10}
193
274
  </style>
194
- <script type="module" src="${MODEL_VIEWER_CDN}"></script>
195
275
  <div class="scene-title">${escapeHtml(title)}</div>
196
276
  <div class="scene-info">Interactive 3D Scene</div>
197
- <model-viewer
198
- src="${escapeHtml(model)}"
199
- camera-controls
200
- touch-action="pan-y"
201
- camera-orbit="${escapeHtml(orbit)}"
202
- shadow-intensity="1.5"
203
- shadow-softness="0.8"
204
- exposure="1.1"
205
- environment-image="neutral"
206
- tone-mapping="commerce"
207
- ${rotateAttr}
208
- ${arAttrs}
209
- style="width:100%;height:100%"
210
- >
211
- ${ar ? `<button slot="ar-button" class="ar-btn">View in AR</button>` : ""}
212
- </model-viewer>
277
+ <div id="status">Loading Filament.js WASM...</div>
278
+ <canvas id="viewer"></canvas>
213
279
  <div class="controls-hint">Drag to orbit &bull; Scroll to zoom &bull; Two-finger to pan</div>
214
- ${BRANDING}`;
280
+ ${BRANDING}
281
+ ${filamentRendererScript({ modelUrl: model, bgColor: hexToBgColor(bg), autoRotate, sunIntensity: 120000, fillIntensity: 35000, orbitRadius: 4.0, orbitHeight: 1.0 })}`;
215
282
  return {
216
283
  html: htmlShell(title, body),
217
284
  title,
@@ -223,67 +290,49 @@ function generateProduct360(input) {
223
290
  const model = input.modelUrl || DEFAULT_MODEL;
224
291
  const title = input.title || "Product 360\u00B0 View";
225
292
  const opts = input.options || {};
226
- const bg = opts.backgroundColor || "#1a1a2e";
227
- const orbit = opts.cameraOrbit || "0deg 75deg 105%";
228
- const ar = opts.ar !== false;
293
+ const bg = opts.backgroundColor || "#0d1117";
229
294
  const hotspots = input.hotspots || [];
230
- const hotspotHtml = hotspots
231
- .map((h, i) => `
232
- <button class="hotspot" slot="hotspot-${i}"
233
- data-position="${escapeHtml(h.position)}"
234
- data-normal="${escapeHtml(h.normal)}"
235
- data-visibility-attribute="visible">
295
+ // Product-360 always auto-rotates (with a slower speed handled in the core script)
296
+ const autoRotate = true;
297
+ const hotspotHtml = hotspots.length > 0 ? `
298
+ <div class="hotspots-overlay" id="hotspots">
299
+ ${hotspots.map((h, i) => `
300
+ <div class="hotspot" id="hotspot-${i}" data-position="${escapeHtml(h.position)}" data-normal="${escapeHtml(h.normal)}">
301
+ <div class="hotspot-dot"></div>
236
302
  <div class="hotspot-annotation">
237
303
  <div class="hotspot-title">${escapeHtml(h.label)}</div>
238
304
  ${h.description ? `<div class="hotspot-desc">${escapeHtml(h.description)}</div>` : ""}
239
305
  </div>
240
- </button>`)
241
- .join("\n");
306
+ </div>`).join("\n")}
307
+ </div>` : "";
242
308
  const body = `
243
309
  <style>
244
- model-viewer{width:100%;height:100%;background:${bg};--poster-color:${bg}}
310
+ canvas{width:100%;height:100%;cursor:grab;display:block}
311
+ canvas:active{cursor:grabbing}
245
312
  .product-header{position:absolute;top:0;left:0;right:0;padding:16px 20px;background:linear-gradient(180deg,rgba(0,0,0,0.6),transparent);z-index:10}
246
313
  .product-title{font-size:20px;font-weight:700;color:#fff}
247
314
  .product-subtitle{font-size:12px;color:#aaa;margin-top:2px}
248
- .hotspot{display:block;width:24px;height:24px;border-radius:50%;border:2px solid #fff;background:rgba(66,133,244,0.8);cursor:pointer;box-shadow:0 2px 8px rgba(0,0,0,0.4);transition:transform 0.2s}
249
- .hotspot:hover{transform:scale(1.3)}
315
+ #status{position:absolute;top:70px;left:20px;font-size:11px;color:#8ab4f8;z-index:10}
316
+ .hotspots-overlay{position:absolute;top:0;left:0;right:0;bottom:0;pointer-events:none;z-index:5}
317
+ .hotspot{position:absolute;pointer-events:auto;cursor:pointer}
318
+ .hotspot-dot{width:24px;height:24px;border-radius:50%;border:2px solid #fff;background:rgba(66,133,244,0.8);box-shadow:0 2px 8px rgba(0,0,0,0.4);transition:transform 0.2s}
319
+ .hotspot:hover .hotspot-dot{transform:scale(1.3)}
250
320
  .hotspot-annotation{position:absolute;bottom:32px;left:50%;transform:translateX(-50%);background:rgba(30,30,50,0.95);border:1px solid rgba(255,255,255,0.1);border-radius:8px;padding:8px 12px;white-space:nowrap;pointer-events:none;opacity:0;transition:opacity 0.2s}
251
321
  .hotspot:hover .hotspot-annotation{opacity:1}
252
322
  .hotspot-title{font-size:13px;font-weight:600;color:#fff}
253
323
  .hotspot-desc{font-size:11px;color:#aaa;margin-top:2px}
254
- .ar-strip{position:absolute;bottom:0;left:0;right:0;padding:12px 20px;background:linear-gradient(0deg,rgba(0,0,0,0.6),transparent);display:flex;align-items:center;justify-content:space-between;z-index:10}
255
- .ar-btn{padding:10px 24px;background:rgba(66,133,244,0.9);color:#fff;border:none;border-radius:24px;font-size:14px;font-weight:500;cursor:pointer}
256
- .ar-btn:hover{background:rgba(66,133,244,1)}
257
- .rotate-hint{font-size:11px;color:#666}
324
+ .rotate-hint{position:absolute;bottom:16px;left:20px;font-size:11px;color:#666;z-index:10}
258
325
  </style>
259
- <script type="module" src="${MODEL_VIEWER_CDN}"></script>
260
326
  <div class="product-header">
261
327
  <div class="product-title">${escapeHtml(title)}</div>
262
328
  <div class="product-subtitle">Drag to rotate &bull; Pinch to zoom${hotspots.length > 0 ? " &bull; Tap hotspots for details" : ""}</div>
263
329
  </div>
264
- <model-viewer
265
- src="${escapeHtml(model)}"
266
- camera-controls
267
- touch-action="pan-y"
268
- camera-orbit="${escapeHtml(orbit)}"
269
- auto-rotate
270
- auto-rotate-delay="3000"
271
- shadow-intensity="1"
272
- shadow-softness="0.5"
273
- exposure="1"
274
- environment-image="neutral"
275
- tone-mapping="commerce"
276
- interaction-prompt="auto"
277
- ${ar ? `ar ar-modes="webxr scene-viewer quick-look"` : ""}
278
- style="width:100%;height:100%"
279
- >
280
- ${hotspotHtml}
281
- ${ar ? `<button slot="ar-button" class="ar-btn">View in Your Space</button>` : ""}
282
- </model-viewer>
283
- <div class="ar-strip">
284
- <div class="rotate-hint">360&deg; interactive view</div>
285
- </div>
286
- ${BRANDING}`;
330
+ <div id="status">Loading Filament.js WASM...</div>
331
+ <canvas id="viewer"></canvas>
332
+ ${hotspotHtml}
333
+ <div class="rotate-hint">360&deg; interactive view</div>
334
+ ${BRANDING}
335
+ ${filamentRendererScript({ modelUrl: model, bgColor: hexToBgColor(bg), autoRotate })}`;
287
336
  return {
288
337
  html: htmlShell(title, body),
289
338
  title,
@@ -324,7 +373,7 @@ export function formatArtifactResponse(result) {
324
373
  const lines = [
325
374
  `## ${result.title}`,
326
375
  ``,
327
- `Here is your interactive 3D ${result.type === "chart-3d" ? "chart" : "content"}:`,
376
+ `Here is your interactive 3D ${result.type === "chart-3d" ? "chart" : "content"} powered by Filament.js (same engine as SceneView Android):`,
328
377
  ``,
329
378
  `\`\`\`html`,
330
379
  result.html,
@@ -333,11 +382,11 @@ export function formatArtifactResponse(result) {
333
382
  `**How to use this:**`,
334
383
  `- Copy the HTML above into a file and open in a browser`,
335
384
  `- Or paste into any HTML preview tool`,
336
- `- On mobile: tap "View in AR" to see it in your space`,
337
385
  `- Drag to orbit, scroll/pinch to zoom`,
386
+ `- Uses Filament.js WASM for real-time PBR rendering`,
338
387
  ``,
339
388
  `---`,
340
- `*Powered by SceneView \u2014 3D & AR for every platform*`,
389
+ `*Powered by SceneView + Filament.js \u2014 3D & AR for every platform*`,
341
390
  ];
342
391
  return lines.join("\n");
343
392
  }
package/llms.txt CHANGED
@@ -7,7 +7,7 @@ SceneView is a declarative 3D and AR SDK for Android (Jetpack Compose, Filament,
7
7
  - AR + 3D: `io.github.sceneview:arsceneview:3.3.0`
8
8
 
9
9
  **Apple (iOS 17+ / macOS 14+ / visionOS 1+) — Swift Package:**
10
- - `https://github.com/SceneView/SceneViewSwift.git` (from: "3.3.0")
10
+ - `https://github.com/sceneview/sceneview-swift.git` (from: "3.3.0")
11
11
 
12
12
  **Min SDK:** 24 | **Target SDK:** 36 | **Kotlin:** 2.3.10 | **Compose BOM compatible**
13
13
 
@@ -1176,7 +1176,7 @@ React Native (Turbo Module / Fabric), KMP Compose iOS (UIKitView).
1176
1176
  ```swift
1177
1177
  // Package.swift
1178
1178
  dependencies: [
1179
- .package(url: "https://github.com/SceneView/SceneViewSwift.git", from: "3.3.0")
1179
+ .package(url: "https://github.com/sceneview/sceneview-swift.git", from: "3.3.0")
1180
1180
  ]
1181
1181
  ```
1182
1182
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sceneview-mcp",
3
- "version": "3.4.9",
3
+ "version": "3.4.10",
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": [
@@ -22,15 +22,15 @@
22
22
  "ai"
23
23
  ],
24
24
  "license": "MIT",
25
- "author": "SceneView (https://github.com/SceneView)",
25
+ "author": "SceneView (https://github.com/sceneview)",
26
26
  "repository": {
27
27
  "type": "git",
28
- "url": "https://github.com/SceneView/sceneview.git",
28
+ "url": "https://github.com/sceneview/sceneview.git",
29
29
  "directory": "mcp"
30
30
  },
31
- "homepage": "https://github.com/SceneView/sceneview/tree/main/mcp#readme",
31
+ "homepage": "https://github.com/sceneview/sceneview/tree/main/mcp#readme",
32
32
  "bugs": {
33
- "url": "https://github.com/SceneView/sceneview/issues"
33
+ "url": "https://github.com/sceneview/sceneview/issues"
34
34
  },
35
35
  "type": "module",
36
36
  "bin": {