@chocodrop/mcp 0.1.0-alpha.0

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 (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +19 -0
  3. package/bin/chocodrop-mcp.js +13 -0
  4. package/package.json +42 -0
  5. package/runtime/.chocodrop-mcp-runtime +1 -0
  6. package/runtime/asset-bridge.js +460 -0
  7. package/runtime/mcp-server.js +107 -0
  8. package/runtime/site/examples/basic/README.md +38 -0
  9. package/runtime/site/examples/basic/index.html +1730 -0
  10. package/runtime/site/examples/bookmarklet-v2.html +141 -0
  11. package/runtime/site/examples/bookmarklet.html +126 -0
  12. package/runtime/site/examples/lofi-room/index.html +2570 -0
  13. package/runtime/site/examples/lofi-room/sandbox-lite.html +124 -0
  14. package/runtime/site/examples/music-garden/index.html +2150 -0
  15. package/runtime/site/examples/pixel-ocean/index.html +1780 -0
  16. package/runtime/site/examples/react-three-fiber/AdvancedExample.jsx +338 -0
  17. package/runtime/site/examples/react-three-fiber/App.jsx +97 -0
  18. package/runtime/site/examples/react-three-fiber/README.md +294 -0
  19. package/runtime/site/examples/react-three-fiber/package.json +25 -0
  20. package/runtime/site/examples/sdk-test/README.md +70 -0
  21. package/runtime/site/examples/space/index.html +1975 -0
  22. package/runtime/site/examples/toy-city/index.html +2288 -0
  23. package/runtime/site/examples/wabi-sabi/index.html +2515 -0
  24. package/runtime/site/getting-started.html +84 -0
  25. package/runtime/site/index.html +1370 -0
  26. package/runtime/site/public/CommandUI.js +6341 -0
  27. package/runtime/site/public/LiveCommandClient.js +432 -0
  28. package/runtime/site/public/SceneManager.js +5493 -0
  29. package/runtime/site/public/bookmarklet.js +206 -0
  30. package/runtime/site/public/bootstrap.js +50 -0
  31. package/runtime/site/public/chocodrop-demo.umd.js +24020 -0
  32. package/runtime/site/public/chocodrop-demo.umd.min.js +24020 -0
  33. package/runtime/site/public/chocodrop.esm.js +2 -0
  34. package/runtime/site/public/html-sandbox/frame.js +865 -0
  35. package/runtime/site/public/icons/icon-192.png +0 -0
  36. package/runtime/site/public/icons/icon-512.png +0 -0
  37. package/runtime/site/public/icons/icon-maskable-512.png +0 -0
  38. package/runtime/site/public/immersive-launcher.js +175 -0
  39. package/runtime/site/public/immersive.html +165 -0
  40. package/runtime/site/public/index.html +1011 -0
  41. package/runtime/site/public/index.js +9 -0
  42. package/runtime/site/public/load-chocodrop.js +25 -0
  43. package/runtime/site/public/load-three.js +26 -0
  44. package/runtime/site/public/manifest.webmanifest +59 -0
  45. package/runtime/site/public/pwa-bootstrap.js +128 -0
  46. package/runtime/site/public/sample-card.svg +15 -0
  47. package/runtime/site/public/service-worker.js +117 -0
  48. package/runtime/site/public/translation-dictionary.js +257 -0
  49. package/runtime/site/public/xr/xr-ui.css +338 -0
  50. package/runtime/site/public/xr-viewer.html +263 -0
  51. package/runtime/site/src/client/local-bridge.js +83 -0
@@ -0,0 +1,175 @@
1
+ import ensureThree from './load-three.js';
2
+ import { ensureChocoDrop } from './load-chocodrop.js';
3
+
4
+ const statusEl = document.getElementById('statusMessage');
5
+ const startButton = document.getElementById('startXR');
6
+ const backButton = document.getElementById('backToDashboard');
7
+ const canvasContainer = document.getElementById('canvasContainer');
8
+ const chocoPWA = window.chocoPWA || null;
9
+
10
+ let renderer = null;
11
+ let scene = null;
12
+ let camera = null;
13
+ let dropInstance = null;
14
+ let xrSession = null;
15
+
16
+ function updateStatus(message) {
17
+ if (statusEl) {
18
+ statusEl.textContent = message;
19
+ }
20
+ }
21
+
22
+ function logImmersive(tag, details = {}) {
23
+ if (!chocoPWA || typeof chocoPWA.appendLog !== 'function') {
24
+ return;
25
+ }
26
+ const entry = { tag, ...details };
27
+ chocoPWA.appendLog(entry).catch((error) => {
28
+ console.warn('⚠️ XRログ書き込みに失敗しました', error);
29
+ });
30
+ }
31
+
32
+ async function prepareScene() {
33
+ if (renderer) {
34
+ return;
35
+ }
36
+
37
+ const THREE = await ensureThree;
38
+ renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
39
+ renderer.setPixelRatio(Math.min(window.devicePixelRatio, 1.8));
40
+ renderer.setSize(canvasContainer.clientWidth, canvasContainer.clientHeight);
41
+ renderer.xr.enabled = true;
42
+
43
+ canvasContainer.innerHTML = '';
44
+ canvasContainer.appendChild(renderer.domElement);
45
+
46
+ scene = new THREE.Scene();
47
+ scene.background = new THREE.Color('#05070d');
48
+
49
+ camera = new THREE.PerspectiveCamera(
50
+ 65,
51
+ canvasContainer.clientWidth / canvasContainer.clientHeight,
52
+ 0.1,
53
+ 100
54
+ );
55
+ camera.position.set(0, 1.6, 3);
56
+
57
+ const hemiLight = new THREE.HemisphereLight(0xffffff, 0x1f2937, 1.2);
58
+ scene.add(hemiLight);
59
+
60
+ const dirLight = new THREE.DirectionalLight(0xffffff, 0.8);
61
+ dirLight.position.set(4, 6, 2);
62
+ scene.add(dirLight);
63
+
64
+ const grid = new THREE.GridHelper(12, 24, 0x6f35bc, 0x312663);
65
+ scene.add(grid);
66
+
67
+ const { createChocoDrop } = await ensureChocoDrop();
68
+ dropInstance = createChocoDrop(scene, {
69
+ camera,
70
+ renderer,
71
+ sceneOptions: {
72
+ enableMouseInteraction: false,
73
+ showLocationIndicator: false,
74
+ defaultObjectScale: 1.2
75
+ },
76
+ uiOptions: {
77
+ skipServiceDialog: true,
78
+ enableServerHealthCheck: false,
79
+ showGuidedOnboarding: false
80
+ }
81
+ });
82
+
83
+ renderer.setAnimationLoop(() => {
84
+ renderer.render(scene, camera);
85
+ });
86
+
87
+ updateStatus('準備完了。XR体験を開始できます。');
88
+ }
89
+
90
+ async function startXRSession(autoTriggered = false) {
91
+ if (!navigator.xr) {
92
+ updateStatus('XR API をサポートしていない環境です。Quest 3 または対応ブラウザで再度お試しください。');
93
+ startButton.disabled = true;
94
+ logImmersive('xr-unsupported', { userAgent: navigator.userAgent });
95
+ return;
96
+ }
97
+
98
+ if (xrSession) {
99
+ updateStatus('XR セッションは既に実行中です。');
100
+ return;
101
+ }
102
+
103
+ startButton.disabled = true;
104
+ updateStatus('XR セッションを初期化しています...');
105
+
106
+ try {
107
+ await prepareScene();
108
+ const session = await navigator.xr.requestSession('immersive-vr', {
109
+ optionalFeatures: ['local-floor', 'bounded-floor', 'hand-tracking', 'layers']
110
+ });
111
+
112
+ session.addEventListener('end', () => {
113
+ xrSession = null;
114
+ startButton.disabled = false;
115
+ updateStatus('XR セッションが終了しました。再開するにはもう一度タップしてください。');
116
+ logImmersive('xr-session-ended', {});
117
+ });
118
+
119
+ await renderer.xr.setSession(session);
120
+ xrSession = session;
121
+ updateStatus('XR セッションを開始しました。ヘッドセットで体験をお楽しみください。');
122
+ logImmersive('xr-session-started', { autoTriggered });
123
+ } catch (error) {
124
+ console.error('XR session failed', error);
125
+ startButton.disabled = false;
126
+ updateStatus(`XR 開始に失敗しました: ${error.message}`);
127
+ logImmersive('xr-start-error', { message: error.message });
128
+ }
129
+ }
130
+
131
+ function handleResize() {
132
+ if (!renderer || !camera) return;
133
+ const width = canvasContainer.clientWidth;
134
+ const height = canvasContainer.clientHeight;
135
+ renderer.setSize(width, height);
136
+ camera.aspect = width / height;
137
+ camera.updateProjectionMatrix();
138
+ }
139
+
140
+ function navigateBack() {
141
+ window.location.href = '/index.html';
142
+ }
143
+
144
+ async function recordLaunchTimestamp() {
145
+ if (!chocoPWA || typeof chocoPWA.saveSession !== 'function') return;
146
+ try {
147
+ const existing = (await chocoPWA.loadSession()) || {};
148
+ await chocoPWA.saveSession({
149
+ ...existing,
150
+ lastXRLaunchAt: new Date().toISOString()
151
+ });
152
+ } catch (error) {
153
+ console.warn('⚠️ XR 起動時刻の保存に失敗しました', error);
154
+ }
155
+ }
156
+
157
+ function init() {
158
+ startButton.addEventListener('click', () => {
159
+ startXRSession(false);
160
+ recordLaunchTimestamp();
161
+ });
162
+
163
+ backButton.addEventListener('click', navigateBack);
164
+ window.addEventListener('resize', handleResize);
165
+
166
+ if (window.location.hash.includes('autoplay')) {
167
+ // ブラウザ制約によりユーザー操作が必要な場合あり
168
+ setTimeout(() => startXRSession(true), 350);
169
+ recordLaunchTimestamp();
170
+ } else {
171
+ updateStatus('没入準備が整いました。ヘッドセットを装着して「XR体験を開始する」をタップしてください。');
172
+ }
173
+ }
174
+
175
+ init();
@@ -0,0 +1,165 @@
1
+ <!DOCTYPE html>
2
+ <html lang="ja">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
6
+ <title>ChocoDrop Immersive</title>
7
+ <link rel="manifest" href="/manifest.webmanifest">
8
+ <meta name="theme-color" content="#0f172a">
9
+ <link rel="apple-touch-icon" href="/icons/icon-192.png">
10
+ <meta name="apple-mobile-web-app-capable" content="yes">
11
+ <meta name="mobile-web-app-capable" content="yes">
12
+ <link rel="icon" href="/icons/icon-192.png">
13
+ <script type="importmap">
14
+ {
15
+ "imports": {
16
+ "three": "https://cdn.jsdelivr.net/npm/three@0.170.0/build/three.module.js"
17
+ }
18
+ }
19
+ </script>
20
+ <script type="module" src="/pwa-bootstrap.js"></script>
21
+ <style>
22
+ :root {
23
+ color-scheme: dark;
24
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
25
+ background: radial-gradient(circle at top, rgba(111, 53, 188, 0.35), #020617 65%);
26
+ min-height: 100%;
27
+ }
28
+
29
+ body {
30
+ margin: 0;
31
+ padding: 0;
32
+ min-height: 100vh;
33
+ display: grid;
34
+ place-items: center;
35
+ color: #e2e8f0;
36
+ }
37
+
38
+ main {
39
+ width: min(640px, 90vw);
40
+ padding: 32px;
41
+ border-radius: 24px;
42
+ background: rgba(15, 23, 42, 0.72);
43
+ backdrop-filter: blur(18px);
44
+ box-shadow: 0 30px 80px rgba(15, 23, 42, 0.45);
45
+ display: grid;
46
+ gap: 24px;
47
+ }
48
+
49
+ h1 {
50
+ margin: 0;
51
+ font-size: clamp(1.5rem, 2.6vw, 2.2rem);
52
+ font-weight: 700;
53
+ display: flex;
54
+ align-items: center;
55
+ gap: 12px;
56
+ color: #f8fafc;
57
+ }
58
+
59
+ #statusMessage {
60
+ margin: 0;
61
+ font-size: 0.95rem;
62
+ line-height: 1.6;
63
+ color: #cbd5f5;
64
+ }
65
+
66
+ .actions {
67
+ display: grid;
68
+ gap: 12px;
69
+ }
70
+
71
+ button {
72
+ border: none;
73
+ border-radius: 16px;
74
+ padding: 18px 24px;
75
+ font-size: 1.05rem;
76
+ font-weight: 600;
77
+ cursor: pointer;
78
+ transition: transform 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease;
79
+ }
80
+
81
+ button.primary {
82
+ background: linear-gradient(135deg, #6f35bc, #7c3aed);
83
+ color: white;
84
+ box-shadow: 0 20px 40px rgba(111, 53, 188, 0.35);
85
+ }
86
+
87
+ button.secondary {
88
+ background: rgba(148, 163, 184, 0.15);
89
+ color: #f8fafc;
90
+ border: 1px solid rgba(148, 163, 184, 0.3);
91
+ }
92
+
93
+ button:disabled {
94
+ opacity: 0.55;
95
+ cursor: not-allowed;
96
+ }
97
+
98
+ button:not(:disabled):hover {
99
+ transform: translateY(-2px);
100
+ }
101
+
102
+ .tips {
103
+ border-radius: 16px;
104
+ border: 1px solid rgba(148, 163, 184, 0.15);
105
+ padding: 16px 20px;
106
+ background: rgba(30, 41, 59, 0.55);
107
+ font-size: 0.9rem;
108
+ line-height: 1.5;
109
+ }
110
+
111
+ .tips h2 {
112
+ margin: 0 0 8px 0;
113
+ font-size: 1rem;
114
+ color: #f8fafc;
115
+ }
116
+
117
+ .tips ul {
118
+ margin: 0;
119
+ padding-left: 20px;
120
+ color: #cbd5f5;
121
+ }
122
+
123
+ #canvasContainer {
124
+ position: relative;
125
+ width: 100%;
126
+ height: 320px;
127
+ border-radius: 18px;
128
+ overflow: hidden;
129
+ border: 1px solid rgba(148, 163, 184, 0.12);
130
+ background: rgba(15, 23, 42, 0.8);
131
+ }
132
+
133
+ @media (max-width: 520px) {
134
+ main {
135
+ padding: 24px;
136
+ border-radius: 20px;
137
+ }
138
+
139
+ #canvasContainer {
140
+ height: 240px;
141
+ }
142
+ }
143
+ </style>
144
+ </head>
145
+ <body>
146
+ <main>
147
+ <h1>🚀 Immersive Launcher</h1>
148
+ <p id="statusMessage">XR デバイスを検出しています...</p>
149
+ <div class="actions">
150
+ <button id="startXR" class="primary">XR体験を開始する</button>
151
+ <button id="backToDashboard" class="secondary">サーバーダッシュボードへ戻る</button>
152
+ </div>
153
+ <section class="tips">
154
+ <h2>実機テストのポイント</h2>
155
+ <ul>
156
+ <li>Quest 3 は最新のシステムアップデートを適用してください。</li>
157
+ <li>初回はヘッドセット内のブラウザで HTTPS URL を直接入力し、インストール登録します。</li>
158
+ <li>再訪時はホームアイコンから開き、表示された「XR体験を開始する」をタップするだけです。</li>
159
+ </ul>
160
+ </section>
161
+ <div id="canvasContainer" aria-hidden="true"></div>
162
+ </main>
163
+ <script type="module" src="./immersive-launcher.js"></script>
164
+ </body>
165
+ </html>