@jlongo78/agent-spaces 0.7.6 → 0.8.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.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-path-routes-manifest.json +6 -0
- package/.next/standalone/.next/build-manifest.json +2 -2
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/required-server-files.json +19 -19
- package/.next/standalone/.next/routes-manifest.json +38 -0
- package/.next/standalone/.next/server/app/(desktop)/admin/analytics/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/admin/users/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/analytics/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/cortex/page/react-loadable-manifest.json +1 -1
- package/.next/standalone/.next/server/app/(desktop)/cortex/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(desktop)/cortex/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/network/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/sessions/[id]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(desktop)/sessions/[id]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/sessions/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/terminal/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(desktop)/terminal/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/terminal/pane/[id]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(desktop)/terminal/pane/[id]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/terminal/remote/[nodeId]/[workspaceId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(desktop)/terminal/remote/[nodeId]/[workspaceId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/workspaces/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +2 -2
- package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/admin/analytics.html +1 -1
- package/.next/standalone/.next/server/app/admin/analytics.rsc +6 -7
- package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin/analytics/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin/analytics.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/admin/analytics.segments/_full.segment.rsc +6 -7
- package/.next/standalone/.next/server/app/admin/analytics.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/admin/analytics.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/admin/analytics.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/admin/users.html +1 -1
- package/.next/standalone/.next/server/app/admin/users.rsc +2 -2
- package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin/users/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin/users.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/admin/users.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/admin/users.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/admin/users.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/admin/users.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/analytics.html +1 -1
- package/.next/standalone/.next/server/app/analytics.rsc +3 -3
- package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap/analytics/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap/analytics.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/analytics.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/analytics.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/analytics.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/analytics.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/api/analytics/overview/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/benchmark/lobes/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/benchmark/lobes/route/build-manifest.json +11 -0
- package/.next/standalone/.next/server/app/api/benchmark/lobes/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/benchmark/lobes/route.js +7 -0
- package/.next/standalone/.next/server/app/api/benchmark/lobes/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/benchmark/lobes/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/benchmark/lobes/route_client-reference-manifest.js +2 -0
- package/.next/standalone/.next/server/app/api/benchmark/run/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/benchmark/run/route/build-manifest.json +11 -0
- package/.next/standalone/.next/server/app/api/benchmark/run/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/benchmark/run/route.js +7 -0
- package/.next/standalone/.next/server/app/api/benchmark/run/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/benchmark/run/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/benchmark/run/route_client-reference-manifest.js +2 -0
- package/.next/standalone/.next/server/app/api/benchmark/runs/[id]/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/benchmark/runs/[id]/route/build-manifest.json +11 -0
- package/.next/standalone/.next/server/app/api/benchmark/runs/[id]/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/benchmark/runs/[id]/route.js +7 -0
- package/.next/standalone/.next/server/app/api/benchmark/runs/[id]/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/benchmark/runs/[id]/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/benchmark/runs/[id]/route_client-reference-manifest.js +2 -0
- package/.next/standalone/.next/server/app/api/benchmark/runs/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/benchmark/runs/route/build-manifest.json +11 -0
- package/.next/standalone/.next/server/app/api/benchmark/runs/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/benchmark/runs/route.js +7 -0
- package/.next/standalone/.next/server/app/api/benchmark/runs/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/benchmark/runs/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/benchmark/runs/route_client-reference-manifest.js +2 -0
- package/.next/standalone/.next/server/app/api/benchmark/status/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/benchmark/status/route/build-manifest.json +11 -0
- package/.next/standalone/.next/server/app/api/benchmark/status/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/benchmark/status/route.js +7 -0
- package/.next/standalone/.next/server/app/api/benchmark/status/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/benchmark/status/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/benchmark/status/route_client-reference-manifest.js +2 -0
- package/.next/standalone/.next/server/app/api/bulk/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/config/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/context/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/curation/assess/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/curation/publish/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/curation/refine/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/curation/review/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/curation/seed/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/export/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/federation/pending/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/federation/resolve/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/federation/search/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/federation/teach/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/graph/edges/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/graph/entities/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/graph/entities/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/graph/populate/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/import/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/import/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/ingest/bootstrap/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/ingest/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/knowledge/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/knowledge/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/lobes/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/lobes/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/lobes/share/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/mcp/call/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/mcp/tools/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/search/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/settings/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/timeline/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/usage/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/workspace/[id]/context/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/events/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/files/route.js +1 -1
- package/.next/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/folders/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/handshake/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/projects/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/search/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/sessions/[id]/messages/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/sessions/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/sessions/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/workspaces/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/workspaces/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/panes/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/panes/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/search/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/sessions/[id]/chat/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/sessions/[id]/messages/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/sessions/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/sync/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/tags/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/tier/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/whisper/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/whisper/route/build-manifest.json +11 -0
- package/.next/standalone/.next/server/app/api/whisper/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/whisper/route.js +7 -0
- package/.next/standalone/.next/server/app/api/whisper/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/whisper/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/whisper/route_client-reference-manifest.js +2 -0
- package/.next/standalone/.next/server/app/api/workspaces/[id]/context/[key]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/workspaces/[id]/context/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/workspaces/[id]/messages/[msgId]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/workspaces/[id]/messages/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/workspaces/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/workspaces/[id]/sessions/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/workspaces/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/cortex.html +1 -1
- package/.next/standalone/.next/server/app/cortex.rsc +3 -3
- package/.next/standalone/.next/server/app/cortex.segments/!KGRlc2t0b3Ap/cortex/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/cortex.segments/!KGRlc2t0b3Ap/cortex.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/cortex.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/cortex.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/cortex.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/cortex.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/cortex.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/login.html +1 -1
- package/.next/standalone/.next/server/app/login.rsc +2 -2
- package/.next/standalone/.next/server/app/login.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/login.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/login.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/login.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/login.segments/login/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/login.segments/login.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/m/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/m/projects.html +1 -1
- package/.next/standalone/.next/server/app/m/projects.rsc +2 -2
- package/.next/standalone/.next/server/app/m/projects.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/projects.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/projects.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/projects.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/projects.segments/m/projects/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/projects.segments/m/projects.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/projects.segments/m.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/sessions/[id]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/m/sessions/[id]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/m/sessions/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/m/sessions.html +1 -1
- package/.next/standalone/.next/server/app/m/sessions.rsc +2 -2
- package/.next/standalone/.next/server/app/m/sessions.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/sessions.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/sessions.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/sessions.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/sessions.segments/m/sessions/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/sessions.segments/m/sessions.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/sessions.segments/m.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/m/settings.html +1 -1
- package/.next/standalone/.next/server/app/m/settings.rsc +2 -2
- package/.next/standalone/.next/server/app/m/settings.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/settings.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/settings.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/settings.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/settings.segments/m/settings/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/settings.segments/m/settings.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/settings.segments/m.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/terminal/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/m/terminal/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/m/terminal.html +1 -1
- package/.next/standalone/.next/server/app/m/terminal.rsc +3 -3
- package/.next/standalone/.next/server/app/m/terminal.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/m/terminal.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/terminal.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/terminal.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/terminal.segments/m/terminal/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/terminal.segments/m/terminal.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/terminal.segments/m.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m.html +1 -1
- package/.next/standalone/.next/server/app/m.rsc +2 -2
- package/.next/standalone/.next/server/app/m.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m.segments/m/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m.segments/m.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/network.html +1 -1
- package/.next/standalone/.next/server/app/network.rsc +2 -2
- package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap/network/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap/network.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/network.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/network.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/network.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/network.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/projects.html +1 -1
- package/.next/standalone/.next/server/app/projects.rsc +2 -2
- package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap/projects/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap/projects.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/projects.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/projects.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/projects.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/projects.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/sessions.html +1 -1
- package/.next/standalone/.next/server/app/sessions.rsc +2 -2
- package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap/sessions/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap/sessions.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/sessions.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/sessions.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/sessions.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/sessions.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/settings.html +1 -1
- package/.next/standalone/.next/server/app/settings.rsc +2 -2
- package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap/settings/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap/settings.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/settings.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/settings.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/terminal.html +1 -1
- package/.next/standalone/.next/server/app/terminal.rsc +3 -3
- package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap/terminal/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap/terminal.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/terminal.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/terminal.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/terminal.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/terminal.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/vr/page/react-loadable-manifest.json +3 -3
- package/.next/standalone/.next/server/app/vr/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/vr.html +1 -1
- package/.next/standalone/.next/server/app/vr.rsc +3 -3
- package/.next/standalone/.next/server/app/vr.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/vr.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/vr.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/vr.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/vr.segments/vr/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/vr.segments/vr.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/workspaces.html +1 -1
- package/.next/standalone/.next/server/app/workspaces.rsc +2 -2
- package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap/workspaces/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap/workspaces.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/workspaces.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/workspaces.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/workspaces.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/workspaces.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app-paths-manifest.json +6 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0041efe4._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__00bf0ace._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0a837dd9._.js +98 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e71d908._.js +3 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e9142f3._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__10e47926._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1665dc78._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__175cbabf._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1adae357._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1d359752._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1e8fabeb._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1f8deca0._.js +8 -8
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__253fdda1._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__28e6434f._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__2a386564._.js +3 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__2c20fb38._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__309132cd._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__33fec964._.js +3 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__3786d8ae._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__3ae92407._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__3beda9fe._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__4619e9bd._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__4a051043._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__508002e4._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__5086c373._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__5913e097._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__5b5f68d2._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__5c1f2459._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__5ec8c977._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__63cebc6c._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__64d30d4d._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__6c54fc2e._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__6dc1fb7e._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__6e568102._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__6faa04c0._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__74a34dc3._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__7819e4cf._.js +98 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__7e7250a4._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__8309e0a4._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__86cc0e2b._.js +6 -6
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__89c2565a._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__8d178ad9._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__93ee06f3._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__9e1f0137._.js +98 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__9e4c154a._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__a9d2e1d3._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__ae53d343._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__b3a04cef._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__b4270b77._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__b6b6ce60._.js +3 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__c0757773._.js +98 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__c24cfa91._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__c7c47529._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__c88b63f7._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__cba5f007._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__cbf4ceb0._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__cefdba2f._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__cf9e82bb._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__d2897392._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__d3b2d856._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__d73273ca._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__d8417eb6._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__dc2a55de._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__e0d4690b._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__e3ea8547._.js +98 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__e678dd53._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__e9223f55._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__ea630076._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__f26ca49d._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__f33e1101._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__f515f865._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__fceb5d60._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__fed41403._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__ff2e98c2._.js +2 -2
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_benchmark_lobes_route_actions_ea7beadb.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_benchmark_run_route_actions_9ed0ba41.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_benchmark_runs_[id]_route_actions_39f90307.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_benchmark_runs_route_actions_37cf958b.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_benchmark_status_route_actions_009e2cba.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_whisper_route_actions_be9a633d.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{_c1cfdd09._.js → [root-of-the-server]__16621ac5._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__66aca5d4._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__9c81bd86._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__e3bf6054._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/{_81abf587._.js → _31ada310._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_648a8a2d._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_999dae61._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_c48c91e5._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_f8959434._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/src_app_(desktop)_cortex_page_tsx_0f33d8b3._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_components_terminal_terminal-pane_tsx_803c5e2c._.js +9 -0
- package/.next/standalone/.next/server/edge/chunks/[root-of-the-server]__32a0045c._.js +1 -1
- package/.next/standalone/.next/server/edge/chunks/_d73df637._.js +1 -1
- package/.next/standalone/.next/server/middleware-manifest.json +5 -5
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +2 -2
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/static/chunks/157826a3253f8ccf.js +7 -0
- package/.next/standalone/.next/static/chunks/{396eac60f496f178.js → 2f9f09924ff9d447.js} +1 -1
- package/.next/standalone/.next/static/chunks/{e23f20b51a75a5bb.js → 4ced66ef12d91b38.js} +35 -12
- package/.next/standalone/.next/static/chunks/57d04d161b8a01b3.js +7 -0
- package/.next/standalone/.next/static/chunks/709c4608e5b935e8.js +1 -0
- package/.next/standalone/.next/static/chunks/{7424664c6ffa94bd.js → 7b14d4e609b55b9b.js} +1 -1
- package/.next/standalone/.next/static/chunks/7be37f4a56b8f575.js +1 -0
- package/.next/standalone/.next/static/chunks/8021d5a2269ff113.js +1 -0
- package/.next/standalone/.next/static/chunks/a3fd93a9dde3cacc.js +1 -0
- package/.next/standalone/.next/static/chunks/{412140a02893327a.js → afee31c7399daf2a.js} +1 -1
- package/.next/standalone/.next/static/chunks/b92fdbf858aeb0b3.js +1 -0
- package/.next/standalone/.next/static/chunks/c17274c2f95d4ba2.js +5 -0
- package/.next/standalone/.next/static/chunks/e116953dc83d4eec.js +1 -0
- package/.next/standalone/.next/static/chunks/e82f4414650587cf.js +7 -0
- package/.next/standalone/.next/static/chunks/f6464729e7aa0da0.css +3 -0
- package/.next/standalone/LICENSE +661 -0
- package/.next/standalone/NOTICE +5 -0
- package/.next/standalone/README.md +131 -0
- package/.next/standalone/bin/cortex-hook.sh +62 -62
- package/.next/standalone/bin/cortex-mcp.js +60 -60
- package/.next/standalone/bin/fix-standalone-externals.js +79 -0
- package/.next/standalone/bin/lib/auto-setup.js +110 -0
- package/.next/standalone/bin/mdns-service.js +171 -0
- package/.next/standalone/bin/postinstall.js +35 -0
- package/.next/standalone/bin/setup-admin.js +195 -0
- package/.next/standalone/bin/spaces-dev.js +247 -0
- package/.next/standalone/bin/spaces-install.js +638 -0
- package/.next/standalone/bin/spaces-reset-totp.js +50 -0
- package/.next/standalone/bin/spaces-service.js +1020 -0
- package/.next/standalone/bin/spaces-setup.js +253 -0
- package/.next/standalone/bin/spaces.js +788 -0
- package/.next/standalone/bin/ssh-auth-keys.sh +68 -0
- package/.next/standalone/bin/terminal-server.js +1807 -0
- package/.next/standalone/docker-compose.yml +28 -0
- package/.next/standalone/docs/architecture.md +387 -0
- package/.next/standalone/docs/cortex.md +293 -0
- package/.next/standalone/docs/getting-started.md +96 -0
- package/.next/standalone/docs/plans/2026-02-24-multi-agent-sessions-design.md +133 -0
- package/.next/standalone/docs/plans/2026-02-24-multi-agent-sessions-plan.md +959 -0
- package/.next/standalone/docs/plans/2026-03-07-service-command-design.md +146 -0
- package/.next/standalone/docs/plans/2026-03-07-service-command-plan.md +254 -0
- package/.next/standalone/docs/server-install.md +564 -0
- package/.next/standalone/docs/social-card.html +150 -0
- package/.next/standalone/docs/superpowers/plans/2026-03-12-spaces-cortex.md +5270 -0
- package/.next/standalone/docs/superpowers/plans/2026-03-13-cortex-wiring.md +1387 -1387
- package/.next/standalone/docs/superpowers/plans/2026-03-14-cortex-v2-entity-graph.md +1923 -1923
- package/.next/standalone/docs/superpowers/plans/2026-03-14-cortex-v2-knowledge-evolution.md +1113 -1113
- package/.next/standalone/docs/superpowers/plans/2026-03-15-cortex-v2-boundary-engine.md +853 -853
- package/.next/standalone/docs/superpowers/plans/2026-03-15-cortex-v2-context-engine.md +1274 -1274
- package/.next/standalone/docs/superpowers/plans/2026-03-15-cortex-v2-signal-ingestion.md +933 -933
- package/.next/standalone/docs/superpowers/plans/2026-03-16-cortex-lobes.md +1080 -1080
- package/.next/standalone/docs/superpowers/plans/2026-03-16-cortex-v2-gravity-system.md +768 -768
- package/.next/standalone/docs/superpowers/plans/2026-03-16-cortex-v2-ui.md +1108 -1108
- package/.next/standalone/docs/superpowers/plans/2026-03-18-cortex-ui-integration.md +1846 -1846
- package/.next/standalone/docs/superpowers/plans/2026-03-19-vr-phase1-shell.md +1639 -0
- package/.next/standalone/docs/superpowers/specs/2026-03-11-universe-view-design.md +320 -0
- package/.next/standalone/docs/superpowers/specs/2026-03-12-spaces-brain-design.md +720 -0
- package/.next/standalone/docs/superpowers/specs/2026-03-13-cortex-wiring-design.md +268 -268
- package/.next/standalone/docs/superpowers/specs/2026-03-14-cortex-v2-design.md +623 -623
- package/.next/standalone/docs/superpowers/specs/2026-03-16-cortex-lobes-design.md +263 -263
- package/.next/standalone/docs/superpowers/specs/2026-03-16-cortex-v2-ui-design.md +240 -240
- package/.next/standalone/docs/superpowers/specs/2026-03-16-pane-ux-design.md +77 -0
- package/.next/standalone/docs/superpowers/specs/2026-03-18-cortex-ui-integration-design.md +341 -341
- package/.next/standalone/docs/superpowers/specs/2026-03-19-vr-phase1-shell-design.md +288 -0
- package/.next/standalone/docs/tiers.md +104 -0
- package/.next/standalone/eslint.config.mjs +18 -0
- package/.next/standalone/next.config.ts +20 -0
- package/.next/standalone/nginx.conf +53 -0
- package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/README.md +46 -0
- package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/lib/glib-2.0/include/glibconfig.h +221 -0
- package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/lib/index.js +1 -0
- package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/lib/libvips-cpp.so.8.17.3 +0 -0
- package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/package.json +42 -0
- package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/README.md +46 -0
- package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/glib-2.0/include/glibconfig.h +221 -0
- package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/index.js +1 -0
- package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/libvips-cpp.so.8.17.3 +0 -0
- package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/package.json +42 -0
- package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/versions.json +30 -0
- package/.next/standalone/node_modules/@img/sharp-linux-x64/lib/sharp-linux-x64.node +0 -0
- package/.next/standalone/node_modules/@img/{sharp-win32-x64 → sharp-linux-x64}/package.json +46 -39
- package/.next/standalone/node_modules/@img/sharp-linuxmusl-x64/lib/sharp-linuxmusl-x64.node +0 -0
- package/.next/standalone/node_modules/@img/sharp-linuxmusl-x64/package.json +46 -0
- package/.next/standalone/package-lock.json +14154 -0
- package/.next/standalone/package.json +104 -103
- package/.next/standalone/postcss.config.mjs +7 -0
- package/.next/standalone/scripts/rebuild.cmd +65 -0
- package/.next/standalone/scripts/rebuild.sh +59 -0
- package/.next/standalone/server.js +1 -1
- package/.next/standalone/src/app/(desktop)/admin/analytics/page.tsx +266 -0
- package/.next/standalone/src/app/(desktop)/admin/users/page.tsx +399 -0
- package/.next/standalone/src/app/(desktop)/analytics/page.tsx +166 -0
- package/.next/standalone/src/app/(desktop)/cortex/page.tsx +81 -78
- package/.next/standalone/src/app/(desktop)/dashboard-client.tsx +56 -0
- package/.next/standalone/src/app/(desktop)/layout.tsx +18 -0
- package/.next/standalone/src/app/(desktop)/network/page.tsx +137 -0
- package/.next/standalone/src/app/(desktop)/page.tsx +17 -0
- package/.next/standalone/src/app/(desktop)/projects/page.tsx +68 -0
- package/.next/standalone/src/app/(desktop)/sessions/[id]/page.tsx +519 -0
- package/.next/standalone/src/app/(desktop)/sessions/page.tsx +145 -0
- package/.next/standalone/src/app/(desktop)/settings/page.tsx +446 -0
- package/.next/standalone/src/app/(desktop)/terminal/layout.tsx +7 -0
- package/.next/standalone/src/app/(desktop)/terminal/page.tsx +1151 -0
- package/.next/standalone/src/app/(desktop)/terminal/pane/[id]/page.tsx +211 -0
- package/.next/standalone/src/app/(desktop)/terminal/remote/[nodeId]/[workspaceId]/page.tsx +192 -0
- package/.next/standalone/src/app/(desktop)/workspaces/page.tsx +12 -0
- package/.next/standalone/src/app/api/admin/analytics/route.ts +10 -0
- package/.next/standalone/src/app/api/admin/users/[id]/route.ts +20 -0
- package/.next/standalone/src/app/api/admin/users/route.ts +15 -0
- package/.next/standalone/src/app/api/analytics/overview/route.ts +80 -0
- package/.next/standalone/src/app/api/auth/login/route.ts +10 -0
- package/.next/standalone/src/app/api/auth/logout/route.ts +9 -0
- package/.next/standalone/src/app/api/auth/me/route.ts +22 -0
- package/.next/standalone/src/app/api/auth/totp/setup/route.ts +10 -0
- package/.next/standalone/src/app/api/auth/totp/status/route.ts +10 -0
- package/.next/standalone/src/app/api/auth/totp/verify/route.ts +10 -0
- package/.next/standalone/src/app/api/benchmark/lobes/route.ts +16 -0
- package/.next/standalone/src/app/api/benchmark/run/route.ts +92 -0
- package/.next/standalone/src/app/api/benchmark/runs/[id]/route.ts +26 -0
- package/.next/standalone/src/app/api/benchmark/runs/route.ts +16 -0
- package/.next/standalone/src/app/api/benchmark/status/route.ts +35 -0
- package/.next/standalone/src/app/api/bulk/route.ts +34 -0
- package/.next/standalone/src/app/api/chat/route.ts +85 -0
- package/.next/standalone/src/app/api/config/route.ts +30 -0
- package/.next/standalone/src/app/api/cortex/context/route.ts +78 -78
- package/.next/standalone/src/app/api/cortex/curation/assess/route.ts +27 -27
- package/.next/standalone/src/app/api/cortex/curation/publish/route.ts +23 -23
- package/.next/standalone/src/app/api/cortex/curation/refine/route.ts +23 -23
- package/.next/standalone/src/app/api/cortex/curation/review/route.ts +29 -29
- package/.next/standalone/src/app/api/cortex/curation/seed/route.ts +23 -23
- package/.next/standalone/src/app/api/cortex/export/route.ts +40 -40
- package/.next/standalone/src/app/api/cortex/federation/pending/route.ts +20 -20
- package/.next/standalone/src/app/api/cortex/federation/resolve/route.ts +43 -43
- package/.next/standalone/src/app/api/cortex/federation/search/route.ts +35 -35
- package/.next/standalone/src/app/api/cortex/federation/teach/route.ts +76 -76
- package/.next/standalone/src/app/api/cortex/graph/edges/route.ts +112 -112
- package/.next/standalone/src/app/api/cortex/graph/entities/[id]/route.ts +73 -73
- package/.next/standalone/src/app/api/cortex/graph/entities/route.ts +75 -75
- package/.next/standalone/src/app/api/cortex/graph/populate/route.ts +203 -203
- package/.next/standalone/src/app/api/cortex/import/route.ts +75 -75
- package/.next/standalone/src/app/api/cortex/import/status/route.ts +15 -15
- package/.next/standalone/src/app/api/cortex/ingest/bootstrap/route.ts +29 -29
- package/.next/standalone/src/app/api/cortex/ingest/status/route.ts +15 -15
- package/.next/standalone/src/app/api/cortex/knowledge/[id]/route.ts +91 -91
- package/.next/standalone/src/app/api/cortex/knowledge/route.ts +93 -93
- package/.next/standalone/src/app/api/cortex/lobes/[id]/route.ts +67 -67
- package/.next/standalone/src/app/api/cortex/lobes/route.ts +22 -22
- package/.next/standalone/src/app/api/cortex/lobes/share/route.ts +80 -80
- package/.next/standalone/src/app/api/cortex/marketplace/browse/route.ts +43 -43
- package/.next/standalone/src/app/api/cortex/marketplace/preview/route.ts +46 -46
- package/.next/standalone/src/app/api/cortex/mcp/call/route.ts +11 -11
- package/.next/standalone/src/app/api/cortex/mcp/tools/route.ts +6 -6
- package/.next/standalone/src/app/api/cortex/search/route.ts +43 -43
- package/.next/standalone/src/app/api/cortex/settings/route.ts +33 -33
- package/.next/standalone/src/app/api/cortex/status/route.ts +169 -169
- package/.next/standalone/src/app/api/cortex/timeline/route.ts +42 -42
- package/.next/standalone/src/app/api/cortex/usage/route.ts +31 -31
- package/.next/standalone/src/app/api/cortex/workspace/[id]/context/route.ts +41 -41
- package/.next/standalone/src/app/api/events/route.ts +40 -0
- package/.next/standalone/src/app/api/files/route.ts +187 -0
- package/.next/standalone/src/app/api/folders/route.ts +97 -0
- package/.next/standalone/src/app/api/network/connect-callback/route.ts +11 -0
- package/.next/standalone/src/app/api/network/connect-request/[id]/route.ts +11 -0
- package/.next/standalone/src/app/api/network/connect-request/route.ts +17 -0
- package/.next/standalone/src/app/api/network/discovered/route.ts +9 -0
- package/.next/standalone/src/app/api/network/handshake/route.ts +25 -0
- package/.next/standalone/src/app/api/network/health/route.ts +10 -0
- package/.next/standalone/src/app/api/network/identity/route.ts +15 -0
- package/.next/standalone/src/app/api/network/keys/[id]/route.ts +10 -0
- package/.next/standalone/src/app/api/network/keys/route.ts +15 -0
- package/.next/standalone/src/app/api/network/nodes/[id]/route.ts +15 -0
- package/.next/standalone/src/app/api/network/nodes/check/route.ts +9 -0
- package/.next/standalone/src/app/api/network/nodes/route.ts +15 -0
- package/.next/standalone/src/app/api/network/projects/route.ts +25 -0
- package/.next/standalone/src/app/api/network/proxy/[nodeId]/[...path]/route.ts +15 -0
- package/.next/standalone/src/app/api/network/search/route.ts +38 -0
- package/.next/standalone/src/app/api/network/sessions/[id]/messages/route.ts +36 -0
- package/.next/standalone/src/app/api/network/sessions/[id]/route.ts +34 -0
- package/.next/standalone/src/app/api/network/sessions/route.ts +43 -0
- package/.next/standalone/src/app/api/network/terminal/token/route.ts +10 -0
- package/.next/standalone/src/app/api/network/workspaces/[id]/route.ts +34 -0
- package/.next/standalone/src/app/api/network/workspaces/route.ts +61 -0
- package/.next/standalone/src/app/api/panes/[id]/route.ts +60 -0
- package/.next/standalone/src/app/api/panes/route.ts +39 -0
- package/.next/standalone/src/app/api/projects/route.ts +13 -0
- package/.next/standalone/src/app/api/search/route.ts +47 -0
- package/.next/standalone/src/app/api/sessions/[id]/chat/route.ts +120 -0
- package/.next/standalone/src/app/api/sessions/[id]/messages/route.ts +28 -0
- package/.next/standalone/src/app/api/sessions/[id]/route.ts +73 -0
- package/.next/standalone/src/app/api/sessions/route.ts +64 -0
- package/.next/standalone/src/app/api/sync/route.ts +24 -0
- package/.next/standalone/src/app/api/tags/route.ts +35 -0
- package/.next/standalone/src/app/api/tier/route.ts +16 -0
- package/.next/standalone/src/app/api/updates/route.ts +53 -0
- package/.next/standalone/src/app/api/whisper/route.ts +90 -0
- package/.next/standalone/src/app/api/workspaces/[id]/context/[key]/route.ts +39 -0
- package/.next/standalone/src/app/api/workspaces/[id]/context/route.ts +28 -0
- package/.next/standalone/src/app/api/workspaces/[id]/messages/[msgId]/route.ts +17 -0
- package/.next/standalone/src/app/api/workspaces/[id]/messages/route.ts +39 -0
- package/.next/standalone/src/app/api/workspaces/[id]/route.ts +47 -0
- package/.next/standalone/src/app/api/workspaces/[id]/sessions/route.ts +62 -0
- package/.next/standalone/src/app/api/workspaces/route.ts +79 -0
- package/.next/standalone/src/app/globals.css +85 -0
- package/.next/standalone/src/app/icon.png +0 -0
- package/.next/standalone/src/app/layout.tsx +33 -0
- package/.next/standalone/src/app/login/layout.tsx +7 -0
- package/.next/standalone/src/app/login/page.tsx +315 -0
- package/.next/standalone/src/app/m/layout.tsx +16 -0
- package/.next/standalone/src/app/m/page.tsx +118 -0
- package/.next/standalone/src/app/m/projects/page.tsx +64 -0
- package/.next/standalone/src/app/m/sessions/[id]/page.tsx +168 -0
- package/.next/standalone/src/app/m/sessions/page.tsx +177 -0
- package/.next/standalone/src/app/m/settings/page.tsx +230 -0
- package/.next/standalone/src/app/m/terminal/page.tsx +413 -0
- package/.next/standalone/src/app/vr/page.tsx +21 -0
- package/.next/standalone/src/app/vr/vr-app.tsx +163 -0
- package/.next/standalone/src/app/vr/vr-controls.tsx +139 -0
- package/.next/standalone/src/app/vr/vr-door.tsx +82 -0
- package/.next/standalone/src/app/vr/vr-environment.tsx +71 -0
- package/.next/standalone/src/app/vr/vr-gaze.tsx +89 -0
- package/.next/standalone/src/app/vr/vr-layout.ts +49 -0
- package/.next/standalone/src/app/vr/vr-lobby.tsx +97 -0
- package/.next/standalone/src/app/vr/vr-pane.tsx +195 -0
- package/.next/standalone/src/app/vr/vr-room.tsx +79 -0
- package/.next/standalone/src/app/vr/vr-terminal.tsx +303 -0
- package/.next/standalone/src/components/auth/totp-gate.tsx +183 -0
- package/.next/standalone/src/components/bus/activity-panel.tsx +261 -0
- package/.next/standalone/src/components/common/color-picker.tsx +35 -0
- package/.next/standalone/src/components/common/dev-directory-picker.tsx +339 -0
- package/.next/standalone/src/components/common/folder-picker.tsx +200 -0
- package/.next/standalone/src/components/common/tag-picker.tsx +190 -0
- package/.next/standalone/src/components/common/workspace-picker.tsx +113 -0
- package/.next/standalone/src/components/cortex/benchmark-tab.tsx +880 -0
- package/.next/standalone/src/components/cortex/constants.ts +29 -29
- package/.next/standalone/src/components/cortex/cortex-dashboard.tsx +304 -304
- package/.next/standalone/src/components/cortex/cortex-indicator.tsx +44 -44
- package/.next/standalone/src/components/cortex/cortex-panel.tsx +140 -140
- package/.next/standalone/src/components/cortex/cortex-settings.tsx +221 -221
- package/.next/standalone/src/components/cortex/curation-tab.tsx +810 -810
- package/.next/standalone/src/components/cortex/entity-detail.tsx +101 -101
- package/.next/standalone/src/components/cortex/entity-graph.tsx +382 -382
- package/.next/standalone/src/components/cortex/import-dialog.tsx +212 -212
- package/.next/standalone/src/components/cortex/injection-badge.tsx +72 -72
- package/.next/standalone/src/components/cortex/knowledge-card.tsx +109 -109
- package/.next/standalone/src/components/cortex/knowledge-tab.tsx +158 -158
- package/.next/standalone/src/components/cortex/lobe-settings.tsx +215 -215
- package/.next/standalone/src/components/cortex/marketplace-card.tsx +126 -126
- package/.next/standalone/src/components/cortex/marketplace-tab.tsx +113 -113
- package/.next/standalone/src/components/dashboard/activity-chart.tsx +41 -0
- package/.next/standalone/src/components/dashboard/model-usage-chart.tsx +61 -0
- package/.next/standalone/src/components/dashboard/recent-sessions.tsx +68 -0
- package/.next/standalone/src/components/dashboard/stats-cards.tsx +36 -0
- package/.next/standalone/src/components/files/file-explorer.tsx +703 -0
- package/.next/standalone/src/components/layout/providers.tsx +38 -0
- package/.next/standalone/src/components/layout/sidebar.tsx +170 -0
- package/.next/standalone/src/components/layout/tier-provider.tsx +53 -0
- package/.next/standalone/src/components/layout/update-banner.tsx +92 -0
- package/.next/standalone/src/components/mobile/bottom-nav.tsx +46 -0
- package/.next/standalone/src/components/mobile/mobile-chat-input.tsx +244 -0
- package/.next/standalone/src/components/mobile/mobile-header.tsx +44 -0
- package/.next/standalone/src/components/mobile/mobile-session-card.tsx +56 -0
- package/.next/standalone/src/components/mobile/mobile-terminal-input.tsx +71 -0
- package/.next/standalone/src/components/mobile/mobile-terminal-pane.tsx +300 -0
- package/.next/standalone/src/components/mobile/mobile-terminal-toolbar.tsx +53 -0
- package/.next/standalone/src/components/mobile/pull-to-refresh.tsx +82 -0
- package/.next/standalone/src/components/mobile/voice-input.tsx +53 -0
- package/.next/standalone/src/components/network/api-key-list.tsx +190 -0
- package/.next/standalone/src/components/network/connection-requests.tsx +94 -0
- package/.next/standalone/src/components/network/node-add-dialog.tsx +131 -0
- package/.next/standalone/src/components/network/node-badge.tsx +26 -0
- package/.next/standalone/src/components/network/node-list.tsx +207 -0
- package/.next/standalone/src/components/network/node-selector.tsx +49 -0
- package/.next/standalone/src/components/sessions/session-filters.tsx +116 -0
- package/.next/standalone/src/components/sessions/session-list.tsx +485 -0
- package/.next/standalone/src/components/terminal/terminal-pane.tsx +874 -0
- package/.next/standalone/src/components/viewer/chat-input.tsx +275 -0
- package/.next/standalone/src/components/viewer/message-renderer.tsx +551 -0
- package/.next/standalone/src/components/workspace/universe-cluster.tsx +131 -0
- package/.next/standalone/src/components/workspace/universe-orb.tsx +128 -0
- package/.next/standalone/src/components/workspace/universe-types.ts +22 -0
- package/.next/standalone/src/components/workspace/universe-utils.ts +11 -0
- package/.next/standalone/src/components/workspace/universe-view.tsx +397 -0
- package/.next/standalone/src/components/workspace/workspace-chooser.tsx +616 -0
- package/.next/standalone/src/hooks/use-benchmark.ts +71 -0
- package/.next/standalone/src/hooks/use-bus.ts +147 -0
- package/.next/standalone/src/hooks/use-idle-detection.ts +79 -0
- package/.next/standalone/src/hooks/use-network.ts +229 -0
- package/.next/standalone/src/hooks/use-sessions.ts +437 -0
- package/.next/standalone/src/hooks/use-speech-recognition.ts +113 -0
- package/.next/standalone/src/hooks/use-sse.ts +35 -0
- package/.next/standalone/src/hooks/use-tier.ts +39 -0
- package/.next/standalone/src/lib/agents.ts +70 -0
- package/.next/standalone/src/lib/aider/parser.ts +111 -0
- package/.next/standalone/src/lib/api.ts +19 -0
- package/.next/standalone/src/lib/auth.ts +47 -0
- package/.next/standalone/src/lib/claude/parser.ts +212 -0
- package/.next/standalone/src/lib/claude/stats.ts +204 -0
- package/.next/standalone/src/lib/codex/parser.ts +265 -0
- package/.next/standalone/src/lib/config.ts +115 -0
- package/.next/standalone/src/lib/cortex/benchmark.ts +67 -0
- package/.next/standalone/src/lib/cortex/config.ts +40 -40
- package/.next/standalone/src/lib/cortex/debug.ts +10 -10
- package/.next/standalone/src/lib/cortex/distillation/usage-store.ts +18 -18
- package/.next/standalone/src/lib/cortex/graph/resolver.ts +10 -10
- package/.next/standalone/src/lib/cortex/graph/types.ts +22 -22
- package/.next/standalone/src/lib/cortex/index.ts +56 -56
- package/.next/standalone/src/lib/cortex/ingestion/bootstrap.ts +14 -14
- package/.next/standalone/src/lib/cortex/knowledge/compat.ts +14 -14
- package/.next/standalone/src/lib/cortex/knowledge/contradiction.ts +10 -10
- package/.next/standalone/src/lib/cortex/knowledge/types.ts +67 -67
- package/.next/standalone/src/lib/cortex/lobes/config.ts +16 -16
- package/.next/standalone/src/lib/cortex/lobes/resolver.ts +8 -8
- package/.next/standalone/src/lib/cortex/lobes/shares.ts +14 -14
- package/.next/standalone/src/lib/cortex/mcp/server.ts +8 -8
- package/.next/standalone/src/lib/cortex/portability/exporter.ts +6 -6
- package/.next/standalone/src/lib/cortex/portability/importer.ts +10 -10
- package/.next/standalone/src/lib/cortex/retrieval/context-engine.ts +10 -10
- package/.next/standalone/src/lib/cortex/types.ts +39 -39
- package/.next/standalone/src/lib/cost-calculator.ts +48 -0
- package/.next/standalone/src/lib/db/init.ts +71 -0
- package/.next/standalone/src/lib/db/queries.ts +718 -0
- package/.next/standalone/src/lib/db/schema.ts +202 -0
- package/.next/standalone/src/lib/events/sse.ts +36 -0
- package/.next/standalone/src/lib/gemini/parser.ts +216 -0
- package/.next/standalone/src/lib/license.ts +56 -0
- package/.next/standalone/src/lib/pro.ts +31 -0
- package/.next/standalone/src/lib/sync/indexer.ts +429 -0
- package/.next/standalone/src/lib/sync/watcher.ts +64 -0
- package/.next/standalone/src/lib/teams.ts +31 -0
- package/.next/standalone/src/lib/telemetry.ts +75 -0
- package/.next/standalone/src/lib/terminal/server.ts +128 -0
- package/.next/standalone/src/lib/tier.ts +38 -0
- package/.next/standalone/src/lib/utils.ts +72 -0
- package/.next/standalone/src/middleware.ts +133 -0
- package/.next/standalone/src/types/claude.ts +208 -0
- package/.next/standalone/src/types/network.ts +61 -0
- package/.next/standalone/tests/setup.ts +8 -0
- package/.next/standalone/tsconfig.json +34 -34
- package/.next/standalone/vitest.config.ts +24 -0
- package/LICENSE +661 -661
- package/README.md +131 -131
- package/bin/cortex-hook.sh +62 -62
- package/bin/cortex-mcp.js +60 -60
- package/bin/fix-standalone-externals.js +79 -79
- package/bin/lib/auto-setup.js +110 -110
- package/bin/mdns-service.js +171 -171
- package/bin/postinstall.js +35 -35
- package/bin/setup-admin.js +195 -195
- package/bin/spaces-dev.js +247 -208
- package/bin/spaces-install.js +638 -599
- package/bin/spaces-reset-totp.js +50 -50
- package/bin/spaces-service.js +1020 -1020
- package/bin/spaces-setup.js +253 -253
- package/bin/spaces.js +788 -776
- package/bin/ssh-auth-keys.sh +68 -68
- package/bin/terminal-server.js +1807 -1683
- package/package.json +104 -103
- package/.next/standalone/.claude/settings.local.json +0 -55
- package/.next/standalone/.claude/spaces-env.json +0 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__eb8acb65._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__e921fdfc._.js +0 -5
- package/.next/standalone/.next/server/chunks/ssr/_2230ad2d._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_5cf334fd._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_db0abd0a._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_db2fec84._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_f4e57187._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/src_40fa36ce._.js +0 -7
- package/.next/standalone/.next/static/chunks/003e7aa1adfe577d.js +0 -1
- package/.next/standalone/.next/static/chunks/232d8aae4fefab70.js +0 -1
- package/.next/standalone/.next/static/chunks/5325351ef49cb65f.js +0 -1
- package/.next/standalone/.next/static/chunks/559735e598ca3cbb.js +0 -1
- package/.next/standalone/.next/static/chunks/5d5d7b0095dd52ae.js +0 -1
- package/.next/standalone/.next/static/chunks/7a7c0d9d875332a3.js +0 -1
- package/.next/standalone/.next/static/chunks/898f380eba90427a.js +0 -1
- package/.next/standalone/.next/static/chunks/95339e55722bb4ca.js +0 -5
- package/.next/standalone/.next/static/chunks/9cd594813c539df9.js +0 -1
- package/.next/standalone/.next/static/chunks/aae9e0fa485bd835.js +0 -5
- package/.next/standalone/.next/static/chunks/c1a95aebf6725f64.css +0 -3
- package/.next/standalone/.next/static/chunks/c515eb77d9410aa0.js +0 -5
- package/.next/standalone/.next/static/chunks/d9ae203a7f123546.js +0 -5
- package/.next/standalone/.next/static/chunks/f9f2628207848ac2.js +0 -1
- package/.next/standalone/.spaces/cortex-context.md +0 -70
- package/.next/standalone/node_modules/@img/sharp-win32-x64/lib/sharp-win32-x64.node +0 -0
- /package/.next/standalone/.next/static/{ncDe4k4gvD0788HAnq_3G → PcpzUspSK8QDdwzAJz8br}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{ncDe4k4gvD0788HAnq_3G → PcpzUspSK8QDdwzAJz8br}/_clientMiddlewareManifest.json +0 -0
- /package/.next/standalone/.next/static/{ncDe4k4gvD0788HAnq_3G → PcpzUspSK8QDdwzAJz8br}/_ssgManifest.js +0 -0
- /package/.next/standalone/node_modules/@img/{sharp-win32-x64 → sharp-libvips-linux-x64}/versions.json +0 -0
|
@@ -0,0 +1,1639 @@
|
|
|
1
|
+
# Spaces VR Phase 1: Shell + Static Rooms — Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
4
|
+
|
|
5
|
+
**Goal:** Build a native Meta Quest 3 VR app that connects to a running Spaces server and renders workspace rooms with pane placeholders, navigable via eye tracking and hand tracking.
|
|
6
|
+
|
|
7
|
+
**Architecture:** Unity project (`C:\projects\spaces-vr`) with Meta XR SDK. HTTP client polls Spaces server API. Two scenes: Lobby (doors per workspace) and WorkspaceRoom (pane placeholders in semicircle). Eye tracking for gaze focus, hand tracking for grab/move/resize.
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** Unity 2022.3 LTS, C#, Meta XR SDK v68+, Meta Interaction SDK, TextMeshPro, UnityWebRequest
|
|
10
|
+
|
|
11
|
+
**Spec:** `docs/superpowers/specs/2026-03-19-vr-phase1-shell-design.md`
|
|
12
|
+
|
|
13
|
+
**Important:** This is a Unity project. Many steps involve Unity Editor operations (creating scenes, configuring components, building prefabs) that cannot be fully automated via code. The plan provides exact C# scripts and documents which Editor steps are needed.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
### Task 0: Server-Side — Add workspace_id Filter to Panes API
|
|
18
|
+
|
|
19
|
+
**Context:** The VR client needs to fetch panes for a specific workspace. The current `GET /api/panes` route only returns panes for the active workspace. We need to support `?workspace_id=N`.
|
|
20
|
+
|
|
21
|
+
**Files:**
|
|
22
|
+
- Modify: `C:\projects\spaces\src\app\api\panes\route.ts`
|
|
23
|
+
|
|
24
|
+
- [ ] **Step 1: Update the GET handler to accept workspace_id query param**
|
|
25
|
+
|
|
26
|
+
Replace the GET handler in `src/app/api/panes/route.ts`:
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
export async function GET(request: NextRequest) {
|
|
30
|
+
const user = getAuthUser(request);
|
|
31
|
+
return withUser(user, async () => {
|
|
32
|
+
await ensureInitialized();
|
|
33
|
+
const url = new URL(request.url);
|
|
34
|
+
const workspaceId = url.searchParams.get('workspace_id');
|
|
35
|
+
if (workspaceId) {
|
|
36
|
+
const { getPanesByWorkspace } = await import('@/lib/db/queries');
|
|
37
|
+
return NextResponse.json(getPanesByWorkspace(parseInt(workspaceId, 10)));
|
|
38
|
+
}
|
|
39
|
+
return NextResponse.json(getActivePanes());
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Add `getPanesByWorkspace` to the imports if not already imported:
|
|
45
|
+
```typescript
|
|
46
|
+
import { getActivePanes, createPane, getPanesByWorkspace } from '@/lib/db/queries';
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
- [ ] **Step 2: Verify the change**
|
|
50
|
+
|
|
51
|
+
Run: `npx tsc --noEmit 2>&1 | head -5`
|
|
52
|
+
Expected: No errors
|
|
53
|
+
|
|
54
|
+
- [ ] **Step 3: Commit**
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
cd C:\projects\spaces
|
|
58
|
+
git add src/app/api/panes/route.ts
|
|
59
|
+
git commit -m "feat: add workspace_id filter to GET /api/panes for VR client"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
### Task 1: Unity Project Setup
|
|
65
|
+
|
|
66
|
+
**Context:** Create the Unity project and configure it for Quest 3 development. This task is mostly Unity Editor work.
|
|
67
|
+
|
|
68
|
+
- [ ] **Step 1: Create the Unity project**
|
|
69
|
+
|
|
70
|
+
Open Unity Hub → New Project → 3D (URP) template → Project name: `spaces-vr` → Location: `C:\projects\` → Create Project
|
|
71
|
+
|
|
72
|
+
- [ ] **Step 2: Initialize git**
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
cd C:\projects\spaces-vr
|
|
76
|
+
git init
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Create `.gitignore`:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
# Unity
|
|
83
|
+
[Ll]ibrary/
|
|
84
|
+
[Tt]emp/
|
|
85
|
+
[Oo]bj/
|
|
86
|
+
[Bb]uild/
|
|
87
|
+
[Bb]uilds/
|
|
88
|
+
[Ll]ogs/
|
|
89
|
+
[Uu]ser[Ss]ettings/
|
|
90
|
+
*.csproj
|
|
91
|
+
*.unityproj
|
|
92
|
+
*.sln
|
|
93
|
+
*.suo
|
|
94
|
+
*.tmp
|
|
95
|
+
*.user
|
|
96
|
+
*.userprefs
|
|
97
|
+
*.pidb
|
|
98
|
+
*.booproj
|
|
99
|
+
*.svd
|
|
100
|
+
*.pdb
|
|
101
|
+
*.mdb
|
|
102
|
+
*.opendb
|
|
103
|
+
*.VC.db
|
|
104
|
+
*.pidb.meta
|
|
105
|
+
*.pdb.meta
|
|
106
|
+
*.mdb.meta
|
|
107
|
+
crashlytics-buildid.txt
|
|
108
|
+
sysinfo.txt
|
|
109
|
+
*.apk
|
|
110
|
+
*.aab
|
|
111
|
+
*.unitypackage
|
|
112
|
+
*.unitypackage.meta
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
git add .gitignore
|
|
117
|
+
git commit -m "chore: initialize spaces-vr Unity project"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
- [ ] **Step 3: Configure build settings for Quest 3**
|
|
121
|
+
|
|
122
|
+
In Unity Editor:
|
|
123
|
+
1. File → Build Settings → Switch Platform to **Android**
|
|
124
|
+
2. Player Settings:
|
|
125
|
+
- Other Settings → Scripting Backend: **IL2CPP**
|
|
126
|
+
- Other Settings → Target Architectures: check **ARM64** only
|
|
127
|
+
- Other Settings → Minimum API Level: **Android 12.0 (API 32)**
|
|
128
|
+
- Other Settings → Graphics APIs: **Vulkan** only (remove OpenGLES)
|
|
129
|
+
- Company Name: `Spaces`
|
|
130
|
+
- Product Name: `Spaces VR`
|
|
131
|
+
- Package Name: `com.spaces.vr`
|
|
132
|
+
|
|
133
|
+
- [ ] **Step 4: Install Meta XR SDK packages**
|
|
134
|
+
|
|
135
|
+
In Unity: Window → Package Manager → + → Add by name:
|
|
136
|
+
- `com.meta.xr.sdk.all` (Meta XR All-in-One SDK)
|
|
137
|
+
|
|
138
|
+
This pulls in OVR, Interaction SDK, and all Quest features.
|
|
139
|
+
|
|
140
|
+
After import, accept any "Fix All" prompts from the Meta Project Setup Tool.
|
|
141
|
+
|
|
142
|
+
- [ ] **Step 5: Configure OVR settings**
|
|
143
|
+
|
|
144
|
+
1. In Hierarchy, delete the default Main Camera
|
|
145
|
+
2. Add: right-click → XR → OVR Camera Rig
|
|
146
|
+
3. On the OVRCameraRig, in OVRManager:
|
|
147
|
+
- Target Devices: Quest 3
|
|
148
|
+
- Tracking Origin Type: Floor Level
|
|
149
|
+
- Hand Tracking Support: Controllers and Hands
|
|
150
|
+
- Eye Tracking Support: Supported (check "Required" = false for fallback)
|
|
151
|
+
4. Edit → Project Settings → XR Plug-in Management → check **Oculus**
|
|
152
|
+
5. Edit → Project Settings → Meta XR → check: Eye Tracking, Hand Tracking
|
|
153
|
+
|
|
154
|
+
- [ ] **Step 6: Create folder structure**
|
|
155
|
+
|
|
156
|
+
In Unity Project window, create these folders:
|
|
157
|
+
```
|
|
158
|
+
Assets/
|
|
159
|
+
├── Scenes/
|
|
160
|
+
├── Scripts/
|
|
161
|
+
│ ├── Core/
|
|
162
|
+
│ ├── Lobby/
|
|
163
|
+
│ ├── Room/
|
|
164
|
+
│ ├── Interaction/
|
|
165
|
+
│ └── UI/
|
|
166
|
+
├── Prefabs/
|
|
167
|
+
├── Materials/
|
|
168
|
+
└── Shaders/
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
- [ ] **Step 7: Commit**
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
cd C:\projects\spaces-vr
|
|
175
|
+
git add -A
|
|
176
|
+
git commit -m "feat: configure Unity project for Quest 3 with Meta XR SDK"
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
### Task 2: Data Models and Server Connection
|
|
182
|
+
|
|
183
|
+
**Files:**
|
|
184
|
+
- Create: `Assets/Scripts/Core/WorkspaceData.cs`
|
|
185
|
+
- Create: `Assets/Scripts/Core/SpacesConnection.cs`
|
|
186
|
+
- Create: `Assets/Scripts/Core/SessionManager.cs`
|
|
187
|
+
|
|
188
|
+
- [ ] **Step 1: Create data models**
|
|
189
|
+
|
|
190
|
+
```csharp
|
|
191
|
+
// Assets/Scripts/Core/WorkspaceData.cs
|
|
192
|
+
using System;
|
|
193
|
+
using System.Collections.Generic;
|
|
194
|
+
|
|
195
|
+
[Serializable]
|
|
196
|
+
public class WorkspaceData
|
|
197
|
+
{
|
|
198
|
+
public int id;
|
|
199
|
+
public string name;
|
|
200
|
+
public string color;
|
|
201
|
+
public int paneCount;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
[Serializable]
|
|
205
|
+
public class PaneData
|
|
206
|
+
{
|
|
207
|
+
public string id;
|
|
208
|
+
public string agentType;
|
|
209
|
+
public string title;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
[Serializable]
|
|
213
|
+
public class WorkspaceListResponse
|
|
214
|
+
{
|
|
215
|
+
public List<WorkspaceData> items;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Helper to deserialize JSON array (Unity's JsonUtility doesn't handle top-level arrays)
|
|
219
|
+
public static class JsonArrayHelper
|
|
220
|
+
{
|
|
221
|
+
public static List<T> FromJson<T>(string json)
|
|
222
|
+
{
|
|
223
|
+
string wrapped = "{\"items\":" + json + "}";
|
|
224
|
+
var wrapper = UnityEngine.JsonUtility.FromJson<Wrapper<T>>(wrapped);
|
|
225
|
+
return wrapper.items;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
[Serializable]
|
|
229
|
+
private class Wrapper<T>
|
|
230
|
+
{
|
|
231
|
+
public List<T> items;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
- [ ] **Step 2: Create session manager**
|
|
237
|
+
|
|
238
|
+
```csharp
|
|
239
|
+
// Assets/Scripts/Core/SessionManager.cs
|
|
240
|
+
using UnityEngine;
|
|
241
|
+
|
|
242
|
+
public class SessionManager : MonoBehaviour
|
|
243
|
+
{
|
|
244
|
+
public static SessionManager Instance { get; private set; }
|
|
245
|
+
|
|
246
|
+
public string ServerUrl { get; set; } = "http://localhost:3457";
|
|
247
|
+
public string SessionCookie { get; private set; }
|
|
248
|
+
public bool IsAuthenticated => !string.IsNullOrEmpty(SessionCookie);
|
|
249
|
+
|
|
250
|
+
private void Awake()
|
|
251
|
+
{
|
|
252
|
+
if (Instance != null) { Destroy(gameObject); return; }
|
|
253
|
+
Instance = this;
|
|
254
|
+
DontDestroyOnLoad(gameObject);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
public void SetCookie(string cookie)
|
|
258
|
+
{
|
|
259
|
+
SessionCookie = cookie;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
public void ClearSession()
|
|
263
|
+
{
|
|
264
|
+
SessionCookie = null;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
- [ ] **Step 3: Create HTTP connection client**
|
|
270
|
+
|
|
271
|
+
```csharp
|
|
272
|
+
// Assets/Scripts/Core/SpacesConnection.cs
|
|
273
|
+
using System;
|
|
274
|
+
using System.Collections;
|
|
275
|
+
using System.Collections.Generic;
|
|
276
|
+
using UnityEngine;
|
|
277
|
+
using UnityEngine.Networking;
|
|
278
|
+
|
|
279
|
+
public class SpacesConnection : MonoBehaviour
|
|
280
|
+
{
|
|
281
|
+
public static SpacesConnection Instance { get; private set; }
|
|
282
|
+
|
|
283
|
+
[SerializeField] private float workspacePollingInterval = 30f;
|
|
284
|
+
[SerializeField] private float panePollingInterval = 10f;
|
|
285
|
+
[SerializeField] private float requestTimeout = 5f;
|
|
286
|
+
[SerializeField] private int maxConsecutiveFailures = 3;
|
|
287
|
+
|
|
288
|
+
public event Action<List<WorkspaceData>> OnWorkspacesUpdated;
|
|
289
|
+
public event Action<List<PaneData>> OnPanesUpdated;
|
|
290
|
+
public event Action<bool> OnConnectionStateChanged;
|
|
291
|
+
|
|
292
|
+
private int consecutiveFailures;
|
|
293
|
+
private bool isConnected;
|
|
294
|
+
|
|
295
|
+
private void Awake()
|
|
296
|
+
{
|
|
297
|
+
if (Instance != null) { Destroy(gameObject); return; }
|
|
298
|
+
Instance = this;
|
|
299
|
+
DontDestroyOnLoad(gameObject);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
private string BaseUrl => SessionManager.Instance.ServerUrl;
|
|
303
|
+
|
|
304
|
+
public IEnumerator FetchWorkspaces(Action<List<WorkspaceData>> callback)
|
|
305
|
+
{
|
|
306
|
+
using var req = UnityWebRequest.Get($"{BaseUrl}/api/workspaces");
|
|
307
|
+
req.timeout = (int)requestTimeout;
|
|
308
|
+
if (SessionManager.Instance.IsAuthenticated)
|
|
309
|
+
req.SetRequestHeader("Cookie", SessionManager.Instance.SessionCookie);
|
|
310
|
+
|
|
311
|
+
yield return req.SendWebRequest();
|
|
312
|
+
|
|
313
|
+
if (req.result == UnityWebRequest.Result.Success)
|
|
314
|
+
{
|
|
315
|
+
consecutiveFailures = 0;
|
|
316
|
+
if (!isConnected) { isConnected = true; OnConnectionStateChanged?.Invoke(true); }
|
|
317
|
+
|
|
318
|
+
var workspaces = JsonArrayHelper.FromJson<WorkspaceData>(req.downloadHandler.text);
|
|
319
|
+
callback?.Invoke(workspaces);
|
|
320
|
+
OnWorkspacesUpdated?.Invoke(workspaces);
|
|
321
|
+
}
|
|
322
|
+
else
|
|
323
|
+
{
|
|
324
|
+
HandleFailure();
|
|
325
|
+
callback?.Invoke(null);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
public IEnumerator FetchPanes(int workspaceId, Action<List<PaneData>> callback)
|
|
330
|
+
{
|
|
331
|
+
using var req = UnityWebRequest.Get($"{BaseUrl}/api/panes?workspace_id={workspaceId}");
|
|
332
|
+
req.timeout = (int)requestTimeout;
|
|
333
|
+
if (SessionManager.Instance.IsAuthenticated)
|
|
334
|
+
req.SetRequestHeader("Cookie", SessionManager.Instance.SessionCookie);
|
|
335
|
+
|
|
336
|
+
yield return req.SendWebRequest();
|
|
337
|
+
|
|
338
|
+
if (req.result == UnityWebRequest.Result.Success)
|
|
339
|
+
{
|
|
340
|
+
consecutiveFailures = 0;
|
|
341
|
+
var panes = JsonArrayHelper.FromJson<PaneData>(req.downloadHandler.text);
|
|
342
|
+
callback?.Invoke(panes);
|
|
343
|
+
OnPanesUpdated?.Invoke(panes);
|
|
344
|
+
}
|
|
345
|
+
else
|
|
346
|
+
{
|
|
347
|
+
HandleFailure();
|
|
348
|
+
callback?.Invoke(null);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
public IEnumerator TryConnect(Action<bool> callback)
|
|
353
|
+
{
|
|
354
|
+
// Try unauthenticated first
|
|
355
|
+
using var req = UnityWebRequest.Get($"{BaseUrl}/api/workspaces");
|
|
356
|
+
req.timeout = (int)requestTimeout;
|
|
357
|
+
yield return req.SendWebRequest();
|
|
358
|
+
|
|
359
|
+
if (req.result == UnityWebRequest.Result.Success)
|
|
360
|
+
{
|
|
361
|
+
isConnected = true;
|
|
362
|
+
OnConnectionStateChanged?.Invoke(true);
|
|
363
|
+
callback?.Invoke(true);
|
|
364
|
+
}
|
|
365
|
+
else if (req.responseCode == 401)
|
|
366
|
+
{
|
|
367
|
+
// Auth required — need login UI (Phase 1: show message)
|
|
368
|
+
Debug.Log("[SpacesVR] Server requires authentication");
|
|
369
|
+
callback?.Invoke(false);
|
|
370
|
+
}
|
|
371
|
+
else
|
|
372
|
+
{
|
|
373
|
+
HandleFailure();
|
|
374
|
+
callback?.Invoke(false);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
private void HandleFailure()
|
|
379
|
+
{
|
|
380
|
+
consecutiveFailures++;
|
|
381
|
+
if (consecutiveFailures >= maxConsecutiveFailures && isConnected)
|
|
382
|
+
{
|
|
383
|
+
isConnected = false;
|
|
384
|
+
OnConnectionStateChanged?.Invoke(false);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Coroutine-based polling helpers
|
|
389
|
+
public IEnumerator PollWorkspaces()
|
|
390
|
+
{
|
|
391
|
+
while (true)
|
|
392
|
+
{
|
|
393
|
+
yield return FetchWorkspaces(null);
|
|
394
|
+
yield return new WaitForSeconds(workspacePollingInterval);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
public IEnumerator PollPanes(int workspaceId)
|
|
399
|
+
{
|
|
400
|
+
while (true)
|
|
401
|
+
{
|
|
402
|
+
yield return FetchPanes(workspaceId, null);
|
|
403
|
+
yield return new WaitForSeconds(panePollingInterval);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
- [ ] **Step 4: Commit**
|
|
410
|
+
|
|
411
|
+
```bash
|
|
412
|
+
cd C:\projects\spaces-vr
|
|
413
|
+
git add Assets/Scripts/Core/
|
|
414
|
+
git commit -m "feat: add data models and HTTP connection client"
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
---
|
|
418
|
+
|
|
419
|
+
### Task 3: Gaze Manager (Eye Tracking + Fallback)
|
|
420
|
+
|
|
421
|
+
**Files:**
|
|
422
|
+
- Create: `Assets/Scripts/Interaction/GazeManager.cs`
|
|
423
|
+
- Create: `Assets/Scripts/Interaction/GazeFocusHighlight.cs`
|
|
424
|
+
|
|
425
|
+
- [ ] **Step 1: Create GazeManager**
|
|
426
|
+
|
|
427
|
+
```csharp
|
|
428
|
+
// Assets/Scripts/Interaction/GazeManager.cs
|
|
429
|
+
using UnityEngine;
|
|
430
|
+
|
|
431
|
+
public class GazeManager : MonoBehaviour
|
|
432
|
+
{
|
|
433
|
+
public static GazeManager Instance { get; private set; }
|
|
434
|
+
|
|
435
|
+
[SerializeField] private float focusDelay = 0.3f; // 300ms sustained gaze
|
|
436
|
+
[SerializeField] private float unfocusDelay = 0.2f;
|
|
437
|
+
[SerializeField] private float maxRayDistance = 20f;
|
|
438
|
+
[SerializeField] private LayerMask gazeLayerMask = ~0;
|
|
439
|
+
|
|
440
|
+
public GameObject FocusedObject { get; private set; }
|
|
441
|
+
public RaycastHit? LastHit { get; private set; }
|
|
442
|
+
public event System.Action<GameObject> OnFocusChanged;
|
|
443
|
+
|
|
444
|
+
private OVREyeGaze leftEyeGaze;
|
|
445
|
+
private OVREyeGaze rightEyeGaze;
|
|
446
|
+
private bool useEyeTracking;
|
|
447
|
+
private Transform centerEye;
|
|
448
|
+
|
|
449
|
+
private GameObject candidateObject;
|
|
450
|
+
private float candidateTime;
|
|
451
|
+
private float unfocusTime;
|
|
452
|
+
|
|
453
|
+
private void Awake()
|
|
454
|
+
{
|
|
455
|
+
if (Instance != null) { Destroy(gameObject); return; }
|
|
456
|
+
Instance = this;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
private void Start()
|
|
460
|
+
{
|
|
461
|
+
// Try to find eye tracking components
|
|
462
|
+
var eyeGazes = FindObjectsOfType<OVREyeGaze>();
|
|
463
|
+
foreach (var eg in eyeGazes)
|
|
464
|
+
{
|
|
465
|
+
if (eg.Eye == OVREyeGaze.EyeId.Combined || eg.Eye == OVREyeGaze.EyeId.Left)
|
|
466
|
+
leftEyeGaze = eg;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// Find center eye anchor for fallback
|
|
470
|
+
var rig = FindObjectOfType<OVRCameraRig>();
|
|
471
|
+
if (rig != null) centerEye = rig.centerEyeAnchor;
|
|
472
|
+
|
|
473
|
+
// Check if eye tracking is available
|
|
474
|
+
useEyeTracking = OVRPlugin.eyeTrackingEnabled;
|
|
475
|
+
if (!useEyeTracking)
|
|
476
|
+
Debug.Log("[GazeManager] Eye tracking unavailable, using head-gaze fallback");
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
private void Update()
|
|
480
|
+
{
|
|
481
|
+
Ray gazeRay = GetGazeRay();
|
|
482
|
+
RaycastHit hit;
|
|
483
|
+
bool didHit = Physics.Raycast(gazeRay, out hit, maxRayDistance, gazeLayerMask);
|
|
484
|
+
|
|
485
|
+
if (didHit)
|
|
486
|
+
{
|
|
487
|
+
LastHit = hit;
|
|
488
|
+
var hitObj = hit.collider.gameObject;
|
|
489
|
+
|
|
490
|
+
if (hitObj == FocusedObject)
|
|
491
|
+
{
|
|
492
|
+
// Still looking at focused object — reset unfocus timer
|
|
493
|
+
unfocusTime = 0f;
|
|
494
|
+
}
|
|
495
|
+
else if (hitObj == candidateObject)
|
|
496
|
+
{
|
|
497
|
+
// Still looking at candidate — accumulate focus time
|
|
498
|
+
candidateTime += Time.deltaTime;
|
|
499
|
+
if (candidateTime >= focusDelay)
|
|
500
|
+
{
|
|
501
|
+
SetFocus(hitObj);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
else
|
|
505
|
+
{
|
|
506
|
+
// New candidate
|
|
507
|
+
candidateObject = hitObj;
|
|
508
|
+
candidateTime = 0f;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
else
|
|
512
|
+
{
|
|
513
|
+
LastHit = null;
|
|
514
|
+
candidateObject = null;
|
|
515
|
+
candidateTime = 0f;
|
|
516
|
+
|
|
517
|
+
if (FocusedObject != null)
|
|
518
|
+
{
|
|
519
|
+
unfocusTime += Time.deltaTime;
|
|
520
|
+
if (unfocusTime >= unfocusDelay)
|
|
521
|
+
{
|
|
522
|
+
SetFocus(null);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
private Ray GetGazeRay()
|
|
529
|
+
{
|
|
530
|
+
if (useEyeTracking && leftEyeGaze != null)
|
|
531
|
+
{
|
|
532
|
+
return new Ray(leftEyeGaze.transform.position, leftEyeGaze.transform.forward);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// Head-gaze fallback
|
|
536
|
+
if (centerEye != null)
|
|
537
|
+
{
|
|
538
|
+
return new Ray(centerEye.position, centerEye.forward);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
return new Ray(Camera.main.transform.position, Camera.main.transform.forward);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
private void SetFocus(GameObject obj)
|
|
545
|
+
{
|
|
546
|
+
if (FocusedObject == obj) return;
|
|
547
|
+
|
|
548
|
+
// Notify old object
|
|
549
|
+
if (FocusedObject != null)
|
|
550
|
+
{
|
|
551
|
+
var highlight = FocusedObject.GetComponent<GazeFocusHighlight>();
|
|
552
|
+
if (highlight != null) highlight.OnUnfocus();
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
FocusedObject = obj;
|
|
556
|
+
unfocusTime = 0f;
|
|
557
|
+
candidateObject = null;
|
|
558
|
+
candidateTime = 0f;
|
|
559
|
+
|
|
560
|
+
// Notify new object
|
|
561
|
+
if (FocusedObject != null)
|
|
562
|
+
{
|
|
563
|
+
var highlight = FocusedObject.GetComponent<GazeFocusHighlight>();
|
|
564
|
+
if (highlight != null) highlight.OnFocus();
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
OnFocusChanged?.Invoke(FocusedObject);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
- [ ] **Step 2: Create GazeFocusHighlight**
|
|
573
|
+
|
|
574
|
+
```csharp
|
|
575
|
+
// Assets/Scripts/Interaction/GazeFocusHighlight.cs
|
|
576
|
+
using UnityEngine;
|
|
577
|
+
|
|
578
|
+
public class GazeFocusHighlight : MonoBehaviour
|
|
579
|
+
{
|
|
580
|
+
[SerializeField] private float highlightScale = 1.02f;
|
|
581
|
+
[SerializeField] private float transitionSpeed = 8f;
|
|
582
|
+
[SerializeField] private Color highlightColor = new Color(0.5f, 0.3f, 1f, 0.3f); // purple glow
|
|
583
|
+
|
|
584
|
+
private Vector3 originalScale;
|
|
585
|
+
private bool isFocused;
|
|
586
|
+
private float focusLerp; // 0 = unfocused, 1 = focused
|
|
587
|
+
private Renderer[] renderers;
|
|
588
|
+
private MaterialPropertyBlock propBlock;
|
|
589
|
+
|
|
590
|
+
private void Awake()
|
|
591
|
+
{
|
|
592
|
+
originalScale = transform.localScale;
|
|
593
|
+
renderers = GetComponentsInChildren<Renderer>();
|
|
594
|
+
propBlock = new MaterialPropertyBlock();
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
private void Update()
|
|
598
|
+
{
|
|
599
|
+
float target = isFocused ? 1f : 0f;
|
|
600
|
+
focusLerp = Mathf.MoveTowards(focusLerp, target, Time.deltaTime * transitionSpeed);
|
|
601
|
+
|
|
602
|
+
// Scale
|
|
603
|
+
transform.localScale = Vector3.Lerp(originalScale, originalScale * highlightScale, focusLerp);
|
|
604
|
+
|
|
605
|
+
// Emission glow
|
|
606
|
+
foreach (var r in renderers)
|
|
607
|
+
{
|
|
608
|
+
r.GetPropertyBlock(propBlock);
|
|
609
|
+
propBlock.SetColor("_EmissionColor", highlightColor * focusLerp);
|
|
610
|
+
r.SetPropertyBlock(propBlock);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
public void OnFocus()
|
|
615
|
+
{
|
|
616
|
+
isFocused = true;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
public void OnUnfocus()
|
|
620
|
+
{
|
|
621
|
+
isFocused = false;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
- [ ] **Step 3: Commit**
|
|
627
|
+
|
|
628
|
+
```bash
|
|
629
|
+
cd C:\projects\spaces-vr
|
|
630
|
+
git add Assets/Scripts/Interaction/GazeManager.cs Assets/Scripts/Interaction/GazeFocusHighlight.cs
|
|
631
|
+
git commit -m "feat: add gaze manager with eye tracking and head-gaze fallback"
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
---
|
|
635
|
+
|
|
636
|
+
### Task 4: Pane Layout Math and Pane Surface
|
|
637
|
+
|
|
638
|
+
**Files:**
|
|
639
|
+
- Create: `Assets/Scripts/Room/PaneLayout.cs`
|
|
640
|
+
- Create: `Assets/Scripts/Room/PaneSurface.cs`
|
|
641
|
+
- Create: `Assets/Scripts/UI/PaneHeader.cs`
|
|
642
|
+
- Create: `Assets/Scripts/UI/StatusIndicator.cs`
|
|
643
|
+
|
|
644
|
+
- [ ] **Step 1: Create PaneLayout (semicircle positioning)**
|
|
645
|
+
|
|
646
|
+
```csharp
|
|
647
|
+
// Assets/Scripts/Room/PaneLayout.cs
|
|
648
|
+
using UnityEngine;
|
|
649
|
+
|
|
650
|
+
public static class PaneLayout
|
|
651
|
+
{
|
|
652
|
+
public static Vector3[] ComputePositions(int paneCount, float radius = 2f, float eyeHeight = 1.6f)
|
|
653
|
+
{
|
|
654
|
+
if (paneCount <= 0) return new Vector3[0];
|
|
655
|
+
|
|
656
|
+
var positions = new Vector3[paneCount];
|
|
657
|
+
|
|
658
|
+
if (paneCount == 1)
|
|
659
|
+
{
|
|
660
|
+
positions[0] = new Vector3(0, eyeHeight, radius);
|
|
661
|
+
return positions;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// Arc grows with pane count
|
|
665
|
+
float totalArcDeg;
|
|
666
|
+
if (paneCount <= 2) totalArcDeg = 40f;
|
|
667
|
+
else if (paneCount <= 4) totalArcDeg = 80f;
|
|
668
|
+
else if (paneCount <= 6) totalArcDeg = 120f;
|
|
669
|
+
else totalArcDeg = 160f;
|
|
670
|
+
|
|
671
|
+
float startAngle = 90f - totalArcDeg / 2f; // center the arc at 90° (forward)
|
|
672
|
+
float step = totalArcDeg / (paneCount - 1);
|
|
673
|
+
|
|
674
|
+
for (int i = 0; i < paneCount; i++)
|
|
675
|
+
{
|
|
676
|
+
float angleDeg = startAngle + step * i;
|
|
677
|
+
float angleRad = angleDeg * Mathf.Deg2Rad;
|
|
678
|
+
float x = Mathf.Cos(angleRad) * radius;
|
|
679
|
+
float z = Mathf.Sin(angleRad) * radius;
|
|
680
|
+
positions[i] = new Vector3(x, eyeHeight, z);
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
return positions;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
public static Quaternion ComputeRotation(Vector3 panePosition)
|
|
687
|
+
{
|
|
688
|
+
// Face inward toward room center (Y-axis billboard only)
|
|
689
|
+
Vector3 toCenter = -new Vector3(panePosition.x, 0, panePosition.z).normalized;
|
|
690
|
+
return Quaternion.LookRotation(toCenter, Vector3.up);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
- [ ] **Step 2: Create StatusIndicator**
|
|
696
|
+
|
|
697
|
+
```csharp
|
|
698
|
+
// Assets/Scripts/UI/StatusIndicator.cs
|
|
699
|
+
using UnityEngine;
|
|
700
|
+
|
|
701
|
+
public enum PaneStatus
|
|
702
|
+
{
|
|
703
|
+
Idle, // gray
|
|
704
|
+
Active, // green
|
|
705
|
+
Waiting, // amber
|
|
706
|
+
Error // red
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
public class StatusIndicator : MonoBehaviour
|
|
710
|
+
{
|
|
711
|
+
[SerializeField] private Renderer dotRenderer;
|
|
712
|
+
|
|
713
|
+
private static readonly Color IdleColor = new Color(0.4f, 0.4f, 0.4f);
|
|
714
|
+
private static readonly Color ActiveColor = new Color(0.2f, 0.8f, 0.2f);
|
|
715
|
+
private static readonly Color WaitingColor = new Color(0.9f, 0.7f, 0.1f);
|
|
716
|
+
private static readonly Color ErrorColor = new Color(0.9f, 0.2f, 0.2f);
|
|
717
|
+
|
|
718
|
+
private MaterialPropertyBlock propBlock;
|
|
719
|
+
|
|
720
|
+
private void Awake()
|
|
721
|
+
{
|
|
722
|
+
propBlock = new MaterialPropertyBlock();
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
public void SetStatus(PaneStatus status)
|
|
726
|
+
{
|
|
727
|
+
Color c = status switch
|
|
728
|
+
{
|
|
729
|
+
PaneStatus.Active => ActiveColor,
|
|
730
|
+
PaneStatus.Waiting => WaitingColor,
|
|
731
|
+
PaneStatus.Error => ErrorColor,
|
|
732
|
+
_ => IdleColor,
|
|
733
|
+
};
|
|
734
|
+
|
|
735
|
+
if (dotRenderer != null)
|
|
736
|
+
{
|
|
737
|
+
dotRenderer.GetPropertyBlock(propBlock);
|
|
738
|
+
propBlock.SetColor("_Color", c);
|
|
739
|
+
propBlock.SetColor("_EmissionColor", c * 0.5f);
|
|
740
|
+
dotRenderer.SetPropertyBlock(propBlock);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
- [ ] **Step 3: Create PaneHeader**
|
|
747
|
+
|
|
748
|
+
```csharp
|
|
749
|
+
// Assets/Scripts/UI/PaneHeader.cs
|
|
750
|
+
using TMPro;
|
|
751
|
+
using UnityEngine;
|
|
752
|
+
|
|
753
|
+
public class PaneHeader : MonoBehaviour
|
|
754
|
+
{
|
|
755
|
+
[SerializeField] private TextMeshPro titleText;
|
|
756
|
+
[SerializeField] private TextMeshPro subtitleText;
|
|
757
|
+
[SerializeField] private Renderer accentBar;
|
|
758
|
+
|
|
759
|
+
private MaterialPropertyBlock propBlock;
|
|
760
|
+
|
|
761
|
+
private void Awake()
|
|
762
|
+
{
|
|
763
|
+
propBlock = new MaterialPropertyBlock();
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
public void SetInfo(string agentType, string title, Color workspaceColor)
|
|
767
|
+
{
|
|
768
|
+
if (titleText != null)
|
|
769
|
+
titleText.text = string.IsNullOrEmpty(title) ? agentType : title;
|
|
770
|
+
|
|
771
|
+
if (subtitleText != null)
|
|
772
|
+
subtitleText.text = agentType;
|
|
773
|
+
|
|
774
|
+
if (accentBar != null)
|
|
775
|
+
{
|
|
776
|
+
accentBar.GetPropertyBlock(propBlock);
|
|
777
|
+
propBlock.SetColor("_Color", workspaceColor);
|
|
778
|
+
accentBar.SetPropertyBlock(propBlock);
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
- [ ] **Step 4: Create PaneSurface**
|
|
785
|
+
|
|
786
|
+
```csharp
|
|
787
|
+
// Assets/Scripts/Room/PaneSurface.cs
|
|
788
|
+
using TMPro;
|
|
789
|
+
using UnityEngine;
|
|
790
|
+
|
|
791
|
+
[RequireComponent(typeof(BoxCollider))]
|
|
792
|
+
[RequireComponent(typeof(GazeFocusHighlight))]
|
|
793
|
+
public class PaneSurface : MonoBehaviour
|
|
794
|
+
{
|
|
795
|
+
[SerializeField] private TextMeshPro contentText;
|
|
796
|
+
[SerializeField] private PaneHeader header;
|
|
797
|
+
[SerializeField] private StatusIndicator statusIndicator;
|
|
798
|
+
|
|
799
|
+
public string PaneId { get; private set; }
|
|
800
|
+
public PaneData Data { get; private set; }
|
|
801
|
+
|
|
802
|
+
private static readonly Vector3 DefaultSize = new Vector3(1.2f, 0.8f, 0.01f);
|
|
803
|
+
private static readonly Vector3 MinSize = new Vector3(0.6f, 0.4f, 0.01f);
|
|
804
|
+
private static readonly Vector3 MaxSize = new Vector3(2.4f, 1.6f, 0.01f);
|
|
805
|
+
|
|
806
|
+
public void Initialize(PaneData data, Color workspaceColor)
|
|
807
|
+
{
|
|
808
|
+
Data = data;
|
|
809
|
+
PaneId = data.id;
|
|
810
|
+
|
|
811
|
+
header?.SetInfo(data.agentType, data.title, workspaceColor);
|
|
812
|
+
statusIndicator?.SetStatus(PaneStatus.Idle); // Phase 1: always idle
|
|
813
|
+
|
|
814
|
+
if (contentText != null)
|
|
815
|
+
contentText.text = $"<color=#666>{data.agentType}\nConnecting...</color>";
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
public void SetSize(Vector3 newSize)
|
|
819
|
+
{
|
|
820
|
+
newSize.x = Mathf.Clamp(newSize.x, MinSize.x, MaxSize.x);
|
|
821
|
+
newSize.y = Mathf.Clamp(newSize.y, MinSize.y, MaxSize.y);
|
|
822
|
+
newSize.z = DefaultSize.z;
|
|
823
|
+
transform.localScale = newSize;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
```
|
|
827
|
+
|
|
828
|
+
- [ ] **Step 5: Commit**
|
|
829
|
+
|
|
830
|
+
```bash
|
|
831
|
+
cd C:\projects\spaces-vr
|
|
832
|
+
git add Assets/Scripts/Room/ Assets/Scripts/UI/
|
|
833
|
+
git commit -m "feat: add pane layout, surface, header, and status indicator"
|
|
834
|
+
```
|
|
835
|
+
|
|
836
|
+
---
|
|
837
|
+
|
|
838
|
+
### Task 5: Hand Tracking — Grab and Resize
|
|
839
|
+
|
|
840
|
+
**Files:**
|
|
841
|
+
- Create: `Assets/Scripts/Interaction/HandGrabHandler.cs`
|
|
842
|
+
|
|
843
|
+
- [ ] **Step 1: Create HandGrabHandler**
|
|
844
|
+
|
|
845
|
+
```csharp
|
|
846
|
+
// Assets/Scripts/Interaction/HandGrabHandler.cs
|
|
847
|
+
using UnityEngine;
|
|
848
|
+
|
|
849
|
+
public class HandGrabHandler : MonoBehaviour
|
|
850
|
+
{
|
|
851
|
+
[SerializeField] private OVRHand leftHand;
|
|
852
|
+
[SerializeField] private OVRHand rightHand;
|
|
853
|
+
[SerializeField] private float grabDistance = 0.15f;
|
|
854
|
+
[SerializeField] private float smoothing = 15f;
|
|
855
|
+
[SerializeField] private float minDistFromCenter = 1f;
|
|
856
|
+
[SerializeField] private float maxDistFromCenter = 4f;
|
|
857
|
+
[SerializeField] private float minHeight = 0.5f;
|
|
858
|
+
[SerializeField] private float maxHeight = 3f;
|
|
859
|
+
|
|
860
|
+
private PaneSurface grabbedPane;
|
|
861
|
+
private Transform grabbingHand;
|
|
862
|
+
private Vector3 grabOffset;
|
|
863
|
+
|
|
864
|
+
// Two-hand resize state
|
|
865
|
+
private bool isResizing;
|
|
866
|
+
private float initialPinchDistance;
|
|
867
|
+
private Vector3 initialPaneScale;
|
|
868
|
+
|
|
869
|
+
private void Update()
|
|
870
|
+
{
|
|
871
|
+
bool leftPinch = leftHand != null && leftHand.GetFingerIsPinching(OVRHand.HandFinger.Index);
|
|
872
|
+
bool rightPinch = rightHand != null && rightHand.GetFingerIsPinching(OVRHand.HandFinger.Index);
|
|
873
|
+
|
|
874
|
+
// Two-hand resize
|
|
875
|
+
if (leftPinch && rightPinch && grabbedPane != null)
|
|
876
|
+
{
|
|
877
|
+
HandleResize();
|
|
878
|
+
return;
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
if (isResizing)
|
|
882
|
+
{
|
|
883
|
+
isResizing = false;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
// Single-hand grab
|
|
887
|
+
if (!leftPinch && !rightPinch)
|
|
888
|
+
{
|
|
889
|
+
grabbedPane = null;
|
|
890
|
+
grabbingHand = null;
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
Transform activeHand = leftPinch ? leftHand.transform : rightHand.transform;
|
|
895
|
+
|
|
896
|
+
if (grabbedPane == null)
|
|
897
|
+
{
|
|
898
|
+
// Try to grab
|
|
899
|
+
TryGrab(activeHand);
|
|
900
|
+
}
|
|
901
|
+
else if (grabbingHand == activeHand)
|
|
902
|
+
{
|
|
903
|
+
// Move grabbed pane
|
|
904
|
+
MoveGrabbedPane();
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
private void TryGrab(Transform hand)
|
|
909
|
+
{
|
|
910
|
+
Collider[] hits = Physics.OverlapSphere(hand.position, grabDistance);
|
|
911
|
+
foreach (var hit in hits)
|
|
912
|
+
{
|
|
913
|
+
var pane = hit.GetComponent<PaneSurface>();
|
|
914
|
+
if (pane != null)
|
|
915
|
+
{
|
|
916
|
+
grabbedPane = pane;
|
|
917
|
+
grabbingHand = hand;
|
|
918
|
+
grabOffset = pane.transform.position - hand.position;
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
private void MoveGrabbedPane()
|
|
925
|
+
{
|
|
926
|
+
Vector3 targetPos = grabbingHand.position + grabOffset;
|
|
927
|
+
|
|
928
|
+
// Constrain position
|
|
929
|
+
float dist = new Vector2(targetPos.x, targetPos.z).magnitude;
|
|
930
|
+
if (dist < minDistFromCenter || dist > maxDistFromCenter)
|
|
931
|
+
{
|
|
932
|
+
Vector2 dir = new Vector2(targetPos.x, targetPos.z).normalized;
|
|
933
|
+
dist = Mathf.Clamp(dist, minDistFromCenter, maxDistFromCenter);
|
|
934
|
+
targetPos.x = dir.x * dist;
|
|
935
|
+
targetPos.z = dir.y * dist;
|
|
936
|
+
}
|
|
937
|
+
targetPos.y = Mathf.Clamp(targetPos.y, minHeight, maxHeight);
|
|
938
|
+
|
|
939
|
+
grabbedPane.transform.position = Vector3.Lerp(
|
|
940
|
+
grabbedPane.transform.position, targetPos, Time.deltaTime * smoothing);
|
|
941
|
+
|
|
942
|
+
// Re-orient to face center
|
|
943
|
+
grabbedPane.transform.rotation = PaneLayout.ComputeRotation(grabbedPane.transform.position);
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
private void HandleResize()
|
|
947
|
+
{
|
|
948
|
+
float currentDist = Vector3.Distance(leftHand.transform.position, rightHand.transform.position);
|
|
949
|
+
|
|
950
|
+
if (!isResizing)
|
|
951
|
+
{
|
|
952
|
+
isResizing = true;
|
|
953
|
+
initialPinchDistance = currentDist;
|
|
954
|
+
initialPaneScale = grabbedPane.transform.localScale;
|
|
955
|
+
return;
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
float scaleFactor = currentDist / initialPinchDistance;
|
|
959
|
+
Vector3 newScale = initialPaneScale * scaleFactor;
|
|
960
|
+
grabbedPane.SetSize(newScale);
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
```
|
|
964
|
+
|
|
965
|
+
- [ ] **Step 2: Commit**
|
|
966
|
+
|
|
967
|
+
```bash
|
|
968
|
+
cd C:\projects\spaces-vr
|
|
969
|
+
git add Assets/Scripts/Interaction/HandGrabHandler.cs
|
|
970
|
+
git commit -m "feat: add hand tracking grab-to-move and pinch-to-resize"
|
|
971
|
+
```
|
|
972
|
+
|
|
973
|
+
---
|
|
974
|
+
|
|
975
|
+
### Task 6: Lobby Scene — Door Spawning and Navigation
|
|
976
|
+
|
|
977
|
+
**Files:**
|
|
978
|
+
- Create: `Assets/Scripts/Lobby/LobbyManager.cs`
|
|
979
|
+
- Create: `Assets/Scripts/Lobby/WorkspaceDoor.cs`
|
|
980
|
+
- Create: `Assets/Scripts/Lobby/DoorInteraction.cs`
|
|
981
|
+
|
|
982
|
+
- [ ] **Step 1: Create WorkspaceDoor**
|
|
983
|
+
|
|
984
|
+
```csharp
|
|
985
|
+
// Assets/Scripts/Lobby/WorkspaceDoor.cs
|
|
986
|
+
using TMPro;
|
|
987
|
+
using UnityEngine;
|
|
988
|
+
|
|
989
|
+
public class WorkspaceDoor : MonoBehaviour
|
|
990
|
+
{
|
|
991
|
+
[SerializeField] private TextMeshPro nameLabel;
|
|
992
|
+
[SerializeField] private TextMeshPro infoLabel;
|
|
993
|
+
[SerializeField] private Renderer frameRenderer;
|
|
994
|
+
[SerializeField] private Renderer glowRenderer;
|
|
995
|
+
|
|
996
|
+
public WorkspaceData Data { get; private set; }
|
|
997
|
+
|
|
998
|
+
private MaterialPropertyBlock propBlock;
|
|
999
|
+
|
|
1000
|
+
private void Awake()
|
|
1001
|
+
{
|
|
1002
|
+
propBlock = new MaterialPropertyBlock();
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
public void Initialize(WorkspaceData data)
|
|
1006
|
+
{
|
|
1007
|
+
Data = data;
|
|
1008
|
+
|
|
1009
|
+
if (nameLabel != null) nameLabel.text = data.name;
|
|
1010
|
+
if (infoLabel != null) infoLabel.text = $"{data.paneCount} pane{(data.paneCount != 1 ? "s" : "")}";
|
|
1011
|
+
|
|
1012
|
+
Color wsColor;
|
|
1013
|
+
if (!ColorUtility.TryParseHtmlString(data.color, out wsColor))
|
|
1014
|
+
wsColor = new Color(0.4f, 0.3f, 0.9f); // default purple
|
|
1015
|
+
|
|
1016
|
+
if (frameRenderer != null)
|
|
1017
|
+
{
|
|
1018
|
+
frameRenderer.GetPropertyBlock(propBlock);
|
|
1019
|
+
propBlock.SetColor("_Color", wsColor);
|
|
1020
|
+
frameRenderer.SetPropertyBlock(propBlock);
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
if (glowRenderer != null)
|
|
1024
|
+
{
|
|
1025
|
+
glowRenderer.GetPropertyBlock(propBlock);
|
|
1026
|
+
propBlock.SetColor("_EmissionColor", wsColor * 0.3f);
|
|
1027
|
+
glowRenderer.SetPropertyBlock(propBlock);
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
```
|
|
1032
|
+
|
|
1033
|
+
- [ ] **Step 2: Create DoorInteraction (gaze-to-enter)**
|
|
1034
|
+
|
|
1035
|
+
```csharp
|
|
1036
|
+
// Assets/Scripts/Lobby/DoorInteraction.cs
|
|
1037
|
+
using UnityEngine;
|
|
1038
|
+
|
|
1039
|
+
[RequireComponent(typeof(GazeFocusHighlight))]
|
|
1040
|
+
public class DoorInteraction : MonoBehaviour
|
|
1041
|
+
{
|
|
1042
|
+
[SerializeField] private float confirmTime = 1.5f;
|
|
1043
|
+
[SerializeField] private Renderer confirmRing; // a progress ring UI element
|
|
1044
|
+
|
|
1045
|
+
private float gazeTimer;
|
|
1046
|
+
private bool isGazed;
|
|
1047
|
+
private WorkspaceDoor door;
|
|
1048
|
+
private MaterialPropertyBlock propBlock;
|
|
1049
|
+
|
|
1050
|
+
private void Awake()
|
|
1051
|
+
{
|
|
1052
|
+
door = GetComponent<WorkspaceDoor>();
|
|
1053
|
+
propBlock = new MaterialPropertyBlock();
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
private void OnEnable()
|
|
1057
|
+
{
|
|
1058
|
+
if (GazeManager.Instance != null)
|
|
1059
|
+
GazeManager.Instance.OnFocusChanged += HandleFocusChanged;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
private void OnDisable()
|
|
1063
|
+
{
|
|
1064
|
+
if (GazeManager.Instance != null)
|
|
1065
|
+
GazeManager.Instance.OnFocusChanged -= HandleFocusChanged;
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
private void HandleFocusChanged(GameObject focused)
|
|
1069
|
+
{
|
|
1070
|
+
isGazed = (focused == gameObject);
|
|
1071
|
+
if (!isGazed)
|
|
1072
|
+
{
|
|
1073
|
+
gazeTimer = 0f;
|
|
1074
|
+
UpdateRing(0f);
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
private void Update()
|
|
1079
|
+
{
|
|
1080
|
+
if (!isGazed) return;
|
|
1081
|
+
|
|
1082
|
+
gazeTimer += Time.deltaTime;
|
|
1083
|
+
UpdateRing(gazeTimer / confirmTime);
|
|
1084
|
+
|
|
1085
|
+
if (gazeTimer >= confirmTime)
|
|
1086
|
+
{
|
|
1087
|
+
gazeTimer = 0f;
|
|
1088
|
+
EnterWorkspace();
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
private void UpdateRing(float progress)
|
|
1093
|
+
{
|
|
1094
|
+
if (confirmRing != null)
|
|
1095
|
+
{
|
|
1096
|
+
confirmRing.gameObject.SetActive(progress > 0f);
|
|
1097
|
+
confirmRing.GetPropertyBlock(propBlock);
|
|
1098
|
+
propBlock.SetFloat("_Progress", Mathf.Clamp01(progress));
|
|
1099
|
+
confirmRing.SetPropertyBlock(propBlock);
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
private void EnterWorkspace()
|
|
1104
|
+
{
|
|
1105
|
+
if (door?.Data != null)
|
|
1106
|
+
{
|
|
1107
|
+
LobbyManager.Instance?.EnterWorkspace(door.Data);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
```
|
|
1112
|
+
|
|
1113
|
+
- [ ] **Step 3: Create LobbyManager**
|
|
1114
|
+
|
|
1115
|
+
```csharp
|
|
1116
|
+
// Assets/Scripts/Lobby/LobbyManager.cs
|
|
1117
|
+
using System.Collections;
|
|
1118
|
+
using System.Collections.Generic;
|
|
1119
|
+
using UnityEngine;
|
|
1120
|
+
|
|
1121
|
+
public class LobbyManager : MonoBehaviour
|
|
1122
|
+
{
|
|
1123
|
+
public static LobbyManager Instance { get; private set; }
|
|
1124
|
+
|
|
1125
|
+
[SerializeField] private GameObject doorPrefab;
|
|
1126
|
+
[SerializeField] private float doorRadius = 4f;
|
|
1127
|
+
[SerializeField] private float doorHeight = 0f;
|
|
1128
|
+
[SerializeField] private GameObject offlinePanel;
|
|
1129
|
+
[SerializeField] private RoomManager roomManager;
|
|
1130
|
+
|
|
1131
|
+
private List<GameObject> spawnedDoors = new List<GameObject>();
|
|
1132
|
+
private Coroutine pollCoroutine;
|
|
1133
|
+
|
|
1134
|
+
private void Awake()
|
|
1135
|
+
{
|
|
1136
|
+
Instance = this;
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
private IEnumerator Start()
|
|
1140
|
+
{
|
|
1141
|
+
// Initial connection attempt
|
|
1142
|
+
bool connected = false;
|
|
1143
|
+
yield return SpacesConnection.Instance.TryConnect(result => connected = result);
|
|
1144
|
+
|
|
1145
|
+
if (connected)
|
|
1146
|
+
{
|
|
1147
|
+
yield return SpacesConnection.Instance.FetchWorkspaces(SpawnDoors);
|
|
1148
|
+
pollCoroutine = StartCoroutine(SpacesConnection.Instance.PollWorkspaces());
|
|
1149
|
+
}
|
|
1150
|
+
else
|
|
1151
|
+
{
|
|
1152
|
+
ShowOffline();
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
SpacesConnection.Instance.OnConnectionStateChanged += OnConnectionChanged;
|
|
1156
|
+
SpacesConnection.Instance.OnWorkspacesUpdated += SpawnDoors;
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
private void OnDestroy()
|
|
1160
|
+
{
|
|
1161
|
+
if (SpacesConnection.Instance != null)
|
|
1162
|
+
{
|
|
1163
|
+
SpacesConnection.Instance.OnConnectionStateChanged -= OnConnectionChanged;
|
|
1164
|
+
SpacesConnection.Instance.OnWorkspacesUpdated -= SpawnDoors;
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
private void OnConnectionChanged(bool connected)
|
|
1169
|
+
{
|
|
1170
|
+
if (connected)
|
|
1171
|
+
{
|
|
1172
|
+
HideOffline();
|
|
1173
|
+
if (pollCoroutine == null)
|
|
1174
|
+
pollCoroutine = StartCoroutine(SpacesConnection.Instance.PollWorkspaces());
|
|
1175
|
+
}
|
|
1176
|
+
else
|
|
1177
|
+
{
|
|
1178
|
+
ShowOffline();
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
private void SpawnDoors(List<WorkspaceData> workspaces)
|
|
1183
|
+
{
|
|
1184
|
+
if (workspaces == null) return;
|
|
1185
|
+
|
|
1186
|
+
// Clear existing doors
|
|
1187
|
+
foreach (var d in spawnedDoors) Destroy(d);
|
|
1188
|
+
spawnedDoors.Clear();
|
|
1189
|
+
|
|
1190
|
+
if (workspaces.Count == 0) return;
|
|
1191
|
+
|
|
1192
|
+
float angleStep = 360f / workspaces.Count;
|
|
1193
|
+
|
|
1194
|
+
for (int i = 0; i < workspaces.Count; i++)
|
|
1195
|
+
{
|
|
1196
|
+
float angleDeg = angleStep * i;
|
|
1197
|
+
float angleRad = angleDeg * Mathf.Deg2Rad;
|
|
1198
|
+
|
|
1199
|
+
Vector3 pos = new Vector3(
|
|
1200
|
+
Mathf.Sin(angleRad) * doorRadius,
|
|
1201
|
+
doorHeight,
|
|
1202
|
+
Mathf.Cos(angleRad) * doorRadius
|
|
1203
|
+
);
|
|
1204
|
+
|
|
1205
|
+
Quaternion rot = Quaternion.LookRotation(-pos.normalized, Vector3.up);
|
|
1206
|
+
|
|
1207
|
+
var doorObj = Instantiate(doorPrefab, pos, rot, transform);
|
|
1208
|
+
var door = doorObj.GetComponent<WorkspaceDoor>();
|
|
1209
|
+
door?.Initialize(workspaces[i]);
|
|
1210
|
+
|
|
1211
|
+
spawnedDoors.Add(doorObj);
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
public void EnterWorkspace(WorkspaceData workspace)
|
|
1216
|
+
{
|
|
1217
|
+
// Stop lobby polling
|
|
1218
|
+
if (pollCoroutine != null)
|
|
1219
|
+
{
|
|
1220
|
+
StopCoroutine(pollCoroutine);
|
|
1221
|
+
pollCoroutine = null;
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
// Hide lobby objects
|
|
1225
|
+
foreach (var d in spawnedDoors) d.SetActive(false);
|
|
1226
|
+
|
|
1227
|
+
// Activate room
|
|
1228
|
+
roomManager?.LoadWorkspace(workspace);
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
public void ReturnToLobby()
|
|
1232
|
+
{
|
|
1233
|
+
roomManager?.UnloadWorkspace();
|
|
1234
|
+
foreach (var d in spawnedDoors) d.SetActive(true);
|
|
1235
|
+
pollCoroutine = StartCoroutine(SpacesConnection.Instance.PollWorkspaces());
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
private void ShowOffline()
|
|
1239
|
+
{
|
|
1240
|
+
if (offlinePanel != null) offlinePanel.SetActive(true);
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
private void HideOffline()
|
|
1244
|
+
{
|
|
1245
|
+
if (offlinePanel != null) offlinePanel.SetActive(false);
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
```
|
|
1249
|
+
|
|
1250
|
+
- [ ] **Step 4: Commit**
|
|
1251
|
+
|
|
1252
|
+
```bash
|
|
1253
|
+
cd C:\projects\spaces-vr
|
|
1254
|
+
git add Assets/Scripts/Lobby/
|
|
1255
|
+
git commit -m "feat: add lobby with workspace doors and gaze-to-enter navigation"
|
|
1256
|
+
```
|
|
1257
|
+
|
|
1258
|
+
---
|
|
1259
|
+
|
|
1260
|
+
### Task 7: Room Manager — Pane Spawning and Room Scaling
|
|
1261
|
+
|
|
1262
|
+
**Files:**
|
|
1263
|
+
- Create: `Assets/Scripts/Room/RoomManager.cs`
|
|
1264
|
+
|
|
1265
|
+
- [ ] **Step 1: Create RoomManager**
|
|
1266
|
+
|
|
1267
|
+
```csharp
|
|
1268
|
+
// Assets/Scripts/Room/RoomManager.cs
|
|
1269
|
+
using System.Collections;
|
|
1270
|
+
using System.Collections.Generic;
|
|
1271
|
+
using UnityEngine;
|
|
1272
|
+
|
|
1273
|
+
public class RoomManager : MonoBehaviour
|
|
1274
|
+
{
|
|
1275
|
+
[SerializeField] private GameObject panePrefab;
|
|
1276
|
+
[SerializeField] private Light roomLight;
|
|
1277
|
+
[SerializeField] private Transform roomContainer;
|
|
1278
|
+
|
|
1279
|
+
private List<GameObject> spawnedPanes = new List<GameObject>();
|
|
1280
|
+
private WorkspaceData currentWorkspace;
|
|
1281
|
+
private Coroutine pollCoroutine;
|
|
1282
|
+
|
|
1283
|
+
// Room scaling light presets
|
|
1284
|
+
private static readonly Color WarmLight = new Color(1f, 0.9f, 0.8f);
|
|
1285
|
+
private static readonly Color NeutralLight = new Color(0.9f, 0.9f, 1f);
|
|
1286
|
+
private static readonly Color CoolLight = new Color(0.7f, 0.8f, 1f);
|
|
1287
|
+
|
|
1288
|
+
public void LoadWorkspace(WorkspaceData workspace)
|
|
1289
|
+
{
|
|
1290
|
+
currentWorkspace = workspace;
|
|
1291
|
+
if (roomContainer != null) roomContainer.gameObject.SetActive(true);
|
|
1292
|
+
|
|
1293
|
+
StartCoroutine(FetchAndSpawnPanes());
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
public void UnloadWorkspace()
|
|
1297
|
+
{
|
|
1298
|
+
if (pollCoroutine != null)
|
|
1299
|
+
{
|
|
1300
|
+
StopCoroutine(pollCoroutine);
|
|
1301
|
+
pollCoroutine = null;
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
foreach (var p in spawnedPanes) Destroy(p);
|
|
1305
|
+
spawnedPanes.Clear();
|
|
1306
|
+
|
|
1307
|
+
currentWorkspace = null;
|
|
1308
|
+
if (roomContainer != null) roomContainer.gameObject.SetActive(false);
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
private IEnumerator FetchAndSpawnPanes()
|
|
1312
|
+
{
|
|
1313
|
+
yield return SpacesConnection.Instance.FetchPanes(currentWorkspace.id, SpawnPanes);
|
|
1314
|
+
pollCoroutine = StartCoroutine(SpacesConnection.Instance.PollPanes(currentWorkspace.id));
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
private void SpawnPanes(List<PaneData> panes)
|
|
1318
|
+
{
|
|
1319
|
+
if (panes == null) return;
|
|
1320
|
+
|
|
1321
|
+
// Clear existing
|
|
1322
|
+
foreach (var p in spawnedPanes) Destroy(p);
|
|
1323
|
+
spawnedPanes.Clear();
|
|
1324
|
+
|
|
1325
|
+
// Compute positions
|
|
1326
|
+
var positions = PaneLayout.ComputePositions(panes.Count);
|
|
1327
|
+
|
|
1328
|
+
// Parse workspace color
|
|
1329
|
+
Color wsColor;
|
|
1330
|
+
if (!ColorUtility.TryParseHtmlString(currentWorkspace.color, out wsColor))
|
|
1331
|
+
wsColor = new Color(0.4f, 0.3f, 0.9f);
|
|
1332
|
+
|
|
1333
|
+
// Scale room lighting based on pane count
|
|
1334
|
+
SetRoomLighting(panes.Count);
|
|
1335
|
+
|
|
1336
|
+
// Spawn panes
|
|
1337
|
+
for (int i = 0; i < panes.Count; i++)
|
|
1338
|
+
{
|
|
1339
|
+
Vector3 pos = positions[i];
|
|
1340
|
+
Quaternion rot = PaneLayout.ComputeRotation(pos);
|
|
1341
|
+
|
|
1342
|
+
Transform parent = roomContainer != null ? roomContainer : transform;
|
|
1343
|
+
var paneObj = Instantiate(panePrefab, pos, rot, parent);
|
|
1344
|
+
var surface = paneObj.GetComponent<PaneSurface>();
|
|
1345
|
+
surface?.Initialize(panes[i], wsColor);
|
|
1346
|
+
|
|
1347
|
+
spawnedPanes.Add(paneObj);
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
private void SetRoomLighting(int paneCount)
|
|
1352
|
+
{
|
|
1353
|
+
if (roomLight == null) return;
|
|
1354
|
+
|
|
1355
|
+
if (paneCount <= 2)
|
|
1356
|
+
{
|
|
1357
|
+
roomLight.color = WarmLight;
|
|
1358
|
+
roomLight.intensity = 0.6f;
|
|
1359
|
+
}
|
|
1360
|
+
else if (paneCount <= 5)
|
|
1361
|
+
{
|
|
1362
|
+
roomLight.color = NeutralLight;
|
|
1363
|
+
roomLight.intensity = 0.8f;
|
|
1364
|
+
}
|
|
1365
|
+
else
|
|
1366
|
+
{
|
|
1367
|
+
roomLight.color = CoolLight;
|
|
1368
|
+
roomLight.intensity = 1.0f;
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
```
|
|
1373
|
+
|
|
1374
|
+
- [ ] **Step 2: Commit**
|
|
1375
|
+
|
|
1376
|
+
```bash
|
|
1377
|
+
cd C:\projects\spaces-vr
|
|
1378
|
+
git add Assets/Scripts/Room/RoomManager.cs
|
|
1379
|
+
git commit -m "feat: add room manager with pane spawning and adaptive lighting"
|
|
1380
|
+
```
|
|
1381
|
+
|
|
1382
|
+
---
|
|
1383
|
+
|
|
1384
|
+
### Task 8: Palm Menu (Return to Lobby)
|
|
1385
|
+
|
|
1386
|
+
**Files:**
|
|
1387
|
+
- Create: `Assets/Scripts/Interaction/PalmMenu.cs`
|
|
1388
|
+
|
|
1389
|
+
- [ ] **Step 1: Create PalmMenu**
|
|
1390
|
+
|
|
1391
|
+
```csharp
|
|
1392
|
+
// Assets/Scripts/Interaction/PalmMenu.cs
|
|
1393
|
+
using UnityEngine;
|
|
1394
|
+
|
|
1395
|
+
public class PalmMenu : MonoBehaviour
|
|
1396
|
+
{
|
|
1397
|
+
[SerializeField] private OVRHand hand; // left hand
|
|
1398
|
+
[SerializeField] private OVRSkeleton skeleton;
|
|
1399
|
+
[SerializeField] private GameObject menuPanel; // small floating UI
|
|
1400
|
+
[SerializeField] private Renderer homeButton;
|
|
1401
|
+
[SerializeField] private float palmUpThreshold = 0.7f; // dot product with up vector
|
|
1402
|
+
[SerializeField] private float gazeConfirmTime = 1.0f;
|
|
1403
|
+
|
|
1404
|
+
private bool menuVisible;
|
|
1405
|
+
private float gazeTimer;
|
|
1406
|
+
private bool isGazingHome;
|
|
1407
|
+
private MaterialPropertyBlock propBlock;
|
|
1408
|
+
|
|
1409
|
+
private void Awake()
|
|
1410
|
+
{
|
|
1411
|
+
propBlock = new MaterialPropertyBlock();
|
|
1412
|
+
if (menuPanel != null) menuPanel.SetActive(false);
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
private void Update()
|
|
1416
|
+
{
|
|
1417
|
+
UpdateMenuVisibility();
|
|
1418
|
+
if (menuVisible) UpdateGazeConfirm();
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
private void UpdateMenuVisibility()
|
|
1422
|
+
{
|
|
1423
|
+
if (hand == null || skeleton == null)
|
|
1424
|
+
{
|
|
1425
|
+
SetMenuVisible(false);
|
|
1426
|
+
return;
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
// Check if palm is facing up
|
|
1430
|
+
if (skeleton.Bones == null || skeleton.Bones.Count == 0)
|
|
1431
|
+
{
|
|
1432
|
+
SetMenuVisible(false);
|
|
1433
|
+
return;
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
// Use wrist bone orientation to determine palm facing
|
|
1437
|
+
Transform wrist = skeleton.Bones[(int)OVRSkeleton.BoneId.Hand_WristRoot]?.Transform;
|
|
1438
|
+
if (wrist == null) { SetMenuVisible(false); return; }
|
|
1439
|
+
|
|
1440
|
+
float palmDot = Vector3.Dot(wrist.up, Vector3.up);
|
|
1441
|
+
bool palmUp = palmDot > palmUpThreshold;
|
|
1442
|
+
|
|
1443
|
+
// Also check if user is looking at their palm
|
|
1444
|
+
bool lookingAtPalm = false;
|
|
1445
|
+
if (GazeManager.Instance?.LastHit != null)
|
|
1446
|
+
{
|
|
1447
|
+
float distToHand = Vector3.Distance(
|
|
1448
|
+
GazeManager.Instance.LastHit.Value.point, wrist.position);
|
|
1449
|
+
lookingAtPalm = distToHand < 0.2f;
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
SetMenuVisible(palmUp && lookingAtPalm);
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
private void SetMenuVisible(bool visible)
|
|
1456
|
+
{
|
|
1457
|
+
if (menuVisible == visible) return;
|
|
1458
|
+
menuVisible = visible;
|
|
1459
|
+
if (menuPanel != null) menuPanel.SetActive(visible);
|
|
1460
|
+
if (!visible) gazeTimer = 0f;
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
private void UpdateGazeConfirm()
|
|
1464
|
+
{
|
|
1465
|
+
// Check if gaze is on the home button
|
|
1466
|
+
var focused = GazeManager.Instance?.FocusedObject;
|
|
1467
|
+
if (focused != null && focused == homeButton?.gameObject)
|
|
1468
|
+
{
|
|
1469
|
+
gazeTimer += Time.deltaTime;
|
|
1470
|
+
|
|
1471
|
+
// Update progress ring
|
|
1472
|
+
if (homeButton != null)
|
|
1473
|
+
{
|
|
1474
|
+
homeButton.GetPropertyBlock(propBlock);
|
|
1475
|
+
propBlock.SetFloat("_Progress", gazeTimer / gazeConfirmTime);
|
|
1476
|
+
homeButton.SetPropertyBlock(propBlock);
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
if (gazeTimer >= gazeConfirmTime)
|
|
1480
|
+
{
|
|
1481
|
+
gazeTimer = 0f;
|
|
1482
|
+
ReturnToLobby();
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
else
|
|
1486
|
+
{
|
|
1487
|
+
gazeTimer = 0f;
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
private void ReturnToLobby()
|
|
1492
|
+
{
|
|
1493
|
+
LobbyManager.Instance?.ReturnToLobby();
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
```
|
|
1497
|
+
|
|
1498
|
+
- [ ] **Step 2: Commit**
|
|
1499
|
+
|
|
1500
|
+
```bash
|
|
1501
|
+
cd C:\projects\spaces-vr
|
|
1502
|
+
git add Assets/Scripts/Interaction/PalmMenu.cs
|
|
1503
|
+
git commit -m "feat: add palm menu with gaze-confirm return to lobby"
|
|
1504
|
+
```
|
|
1505
|
+
|
|
1506
|
+
---
|
|
1507
|
+
|
|
1508
|
+
### Task 9: Scene Setup and Prefab Assembly (Unity Editor)
|
|
1509
|
+
|
|
1510
|
+
**Context:** This task is done entirely in the Unity Editor. It connects all the scripts to GameObjects and creates the prefabs and scenes.
|
|
1511
|
+
|
|
1512
|
+
- [ ] **Step 1: Create PaneSurface prefab**
|
|
1513
|
+
|
|
1514
|
+
1. In Scene, create: 3D Object → Quad. Name it `PaneSurface`.
|
|
1515
|
+
2. Scale: (1.2, 0.8, 1). This is the pane surface.
|
|
1516
|
+
3. Create a dark material (`PaneSurface.mat`): Shader = URP/Lit, Base Color = `#0a0a0f`, Metallic = 0, Smoothness = 0.1.
|
|
1517
|
+
4. Add a child: 3D Object → Sphere (scale 0.02) for the status dot. Position top-left corner.
|
|
1518
|
+
5. Add child TextMeshPro objects for header (top of quad) and content (body).
|
|
1519
|
+
6. Add components to the root:
|
|
1520
|
+
- `PaneSurface.cs`
|
|
1521
|
+
- `GazeFocusHighlight.cs`
|
|
1522
|
+
- `BoxCollider` (auto-added by PaneSurface RequireComponent)
|
|
1523
|
+
7. Wire serialized fields: `contentText`, `header`, `statusIndicator` → child objects.
|
|
1524
|
+
8. Drag to `Assets/Prefabs/PaneSurface.prefab`.
|
|
1525
|
+
|
|
1526
|
+
- [ ] **Step 2: Create WorkspaceDoor prefab**
|
|
1527
|
+
|
|
1528
|
+
1. Create an empty GameObject named `WorkspaceDoor`.
|
|
1529
|
+
2. Add child: Cube scaled to (1.2, 2.2, 0.1) — the door frame. Apply `DoorFrame.mat`.
|
|
1530
|
+
3. Add child: TextMeshPro for name label (above frame).
|
|
1531
|
+
4. Add child: TextMeshPro for info label (inside frame).
|
|
1532
|
+
5. Add child: Point Light (range 2, intensity 0.5) for glow.
|
|
1533
|
+
6. Add components to root:
|
|
1534
|
+
- `WorkspaceDoor.cs`
|
|
1535
|
+
- `DoorInteraction.cs`
|
|
1536
|
+
- `GazeFocusHighlight.cs`
|
|
1537
|
+
- `BoxCollider` (size matching the door frame)
|
|
1538
|
+
7. Wire serialized fields.
|
|
1539
|
+
8. Drag to `Assets/Prefabs/WorkspaceDoor.prefab`.
|
|
1540
|
+
|
|
1541
|
+
- [ ] **Step 3: Set up the main scene**
|
|
1542
|
+
|
|
1543
|
+
1. Open the default scene (or create `Assets/Scenes/Main.unity`).
|
|
1544
|
+
2. Ensure OVRCameraRig is present (from Task 1).
|
|
1545
|
+
3. Create empty GameObjects:
|
|
1546
|
+
- `[Managers]` — add `SessionManager.cs`, `SpacesConnection.cs`, `GazeManager.cs`
|
|
1547
|
+
- `[Lobby]` — add `LobbyManager.cs`. Wire `doorPrefab` to the WorkspaceDoor prefab.
|
|
1548
|
+
- `[Room]` — add `RoomManager.cs`. Wire `panePrefab` to the PaneSurface prefab. Add a Directional Light child for room lighting.
|
|
1549
|
+
- `[Interaction]` — add `HandGrabHandler.cs`. Wire `leftHand` and `rightHand` to OVRHandPrefab instances.
|
|
1550
|
+
- `[PalmMenu]` — add `PalmMenu.cs` with a small floating Canvas child for the home button.
|
|
1551
|
+
4. Add OVRHandPrefab for left and right hands (from Meta XR SDK samples).
|
|
1552
|
+
5. Set Room container initially inactive.
|
|
1553
|
+
6. Create an "Offline Panel" — a TextMeshPro world-space canvas at center, initially inactive. Wire to LobbyManager's `offlinePanel` field.
|
|
1554
|
+
7. Wire cross-references: LobbyManager.roomManager → RoomManager, etc.
|
|
1555
|
+
|
|
1556
|
+
- [ ] **Step 4: Test in editor Play Mode**
|
|
1557
|
+
|
|
1558
|
+
Press Play in Unity Editor. With Meta XR Simulator:
|
|
1559
|
+
1. Verify lobby spawns — should see "Offline" panel if no server is running.
|
|
1560
|
+
2. Start Spaces server (`node bin/spaces.js --port 3457`). Hit Play again.
|
|
1561
|
+
3. Doors should appear for each workspace.
|
|
1562
|
+
4. Simulated gaze → door → should trigger confirm ring and enter room.
|
|
1563
|
+
5. Panes should spawn in semicircle with correct names.
|
|
1564
|
+
|
|
1565
|
+
- [ ] **Step 5: Commit**
|
|
1566
|
+
|
|
1567
|
+
```bash
|
|
1568
|
+
cd C:\projects\spaces-vr
|
|
1569
|
+
git add -A
|
|
1570
|
+
git commit -m "feat: assemble scenes, prefabs, and wire all components"
|
|
1571
|
+
```
|
|
1572
|
+
|
|
1573
|
+
---
|
|
1574
|
+
|
|
1575
|
+
### Task 10: Quest 3 Build and Deploy
|
|
1576
|
+
|
|
1577
|
+
- [ ] **Step 1: Configure Android build**
|
|
1578
|
+
|
|
1579
|
+
In Unity:
|
|
1580
|
+
1. File → Build Settings → ensure Android platform is selected
|
|
1581
|
+
2. Player Settings → verify: IL2CPP, ARM64, Vulkan, API 32 (from Task 1)
|
|
1582
|
+
3. XR Plug-in Management → verify Oculus checked
|
|
1583
|
+
4. Meta XR → verify Eye Tracking + Hand Tracking enabled
|
|
1584
|
+
|
|
1585
|
+
- [ ] **Step 2: Build APK**
|
|
1586
|
+
|
|
1587
|
+
File → Build Settings → Build → save as `Build/SpacesVR.apk`
|
|
1588
|
+
|
|
1589
|
+
Expected: Build succeeds. First build takes 5-10 minutes.
|
|
1590
|
+
|
|
1591
|
+
- [ ] **Step 3: Deploy to Quest 3 (when you have one)**
|
|
1592
|
+
|
|
1593
|
+
Option A — Quest Link:
|
|
1594
|
+
1. Connect Quest via USB-C or Air Link
|
|
1595
|
+
2. In Unity: File → Build and Run (deploys and launches automatically)
|
|
1596
|
+
|
|
1597
|
+
Option B — SideQuest:
|
|
1598
|
+
1. Install SideQuest on PC
|
|
1599
|
+
2. Connect Quest via USB
|
|
1600
|
+
3. Drag `Build/SpacesVR.apk` into SideQuest
|
|
1601
|
+
4. On Quest: Unknown Sources → Spaces VR
|
|
1602
|
+
|
|
1603
|
+
- [ ] **Step 4: Commit final build config**
|
|
1604
|
+
|
|
1605
|
+
```bash
|
|
1606
|
+
cd C:\projects\spaces-vr
|
|
1607
|
+
git add -A
|
|
1608
|
+
git commit -m "chore: finalize Quest 3 build configuration"
|
|
1609
|
+
```
|
|
1610
|
+
|
|
1611
|
+
---
|
|
1612
|
+
|
|
1613
|
+
### Summary: File Map
|
|
1614
|
+
|
|
1615
|
+
```
|
|
1616
|
+
C:\projects\spaces-vr\Assets\Scripts\
|
|
1617
|
+
├── Core\
|
|
1618
|
+
│ ├── WorkspaceData.cs # Task 2 — data models + JSON helpers
|
|
1619
|
+
│ ├── SpacesConnection.cs # Task 2 — HTTP client + polling
|
|
1620
|
+
│ └── SessionManager.cs # Task 2 — auth token management
|
|
1621
|
+
├── Interaction\
|
|
1622
|
+
│ ├── GazeManager.cs # Task 3 — eye tracking + head-gaze fallback
|
|
1623
|
+
│ ├── GazeFocusHighlight.cs # Task 3 — visual focus feedback
|
|
1624
|
+
│ ├── HandGrabHandler.cs # Task 5 — grab/move/resize
|
|
1625
|
+
│ └── PalmMenu.cs # Task 8 — palm-up home button
|
|
1626
|
+
├── Lobby\
|
|
1627
|
+
│ ├── LobbyManager.cs # Task 6 — spawn doors, manage transitions
|
|
1628
|
+
│ ├── WorkspaceDoor.cs # Task 6 — door rendering
|
|
1629
|
+
│ └── DoorInteraction.cs # Task 6 — gaze-to-enter
|
|
1630
|
+
├── Room\
|
|
1631
|
+
│ ├── RoomManager.cs # Task 7 — spawn panes, room lighting
|
|
1632
|
+
│ ├── PaneSurface.cs # Task 4 — pane placeholder
|
|
1633
|
+
│ └── PaneLayout.cs # Task 4 — semicircle math
|
|
1634
|
+
└── UI\
|
|
1635
|
+
├── PaneHeader.cs # Task 4 — agent name/type label
|
|
1636
|
+
└── StatusIndicator.cs # Task 4 — colored status dot
|
|
1637
|
+
|
|
1638
|
+
C:\projects\spaces\src\app\api\panes\route.ts # Task 0 — workspace_id filter
|
|
1639
|
+
```
|