diff --git a/modules/splat/mod.ts b/modules/splat/mod.ts
index 334086c..c8b986b 100644
--- a/modules/splat/mod.ts
+++ b/modules/splat/mod.ts
@@ -429,7 +429,7 @@ routes.get("/", async (c) => {
const html = renderShell({
title: `${spaceSlug} — rSplat | rSpace`,
- moduleId: "splat",
+ moduleId: "rsplat",
spaceSlug,
body: `
`,
modules: getModuleInfoList(),
@@ -464,9 +464,9 @@ routes.get("/view/:id", async (c) => {
if (rows.length === 0) {
const html = renderShell({
title: "Splat not found | rSpace",
- moduleId: "splat",
+ moduleId: "rsplat",
spaceSlug,
- body: `
`,
+ body: `
`,
modules: getModuleInfoList(),
theme: "dark",
});
@@ -481,11 +481,11 @@ routes.get("/view/:id", async (c) => {
[splat.id]
);
- const fileUrl = `/${spaceSlug}/splat/api/splats/${splat.slug}/${splat.slug}.${splat.file_format}`;
+ const fileUrl = `/${spaceSlug}/rsplat/api/splats/${splat.slug}/${splat.slug}.${splat.file_format}`;
const html = renderShell({
title: `${splat.title} | rSplat`,
- moduleId: "splat",
+ moduleId: "rsplat",
spaceSlug,
body: `
{
// ── Module export ──
export const splatModule: RSpaceModule = {
- id: "splat",
+ id: "rsplat",
name: "rSplat",
icon: "🔮",
description: "3D Gaussian splat viewer",
diff --git a/modules/swag/mod.ts b/modules/swag/mod.ts
index 684793d..306fc16 100644
--- a/modules/swag/mod.ts
+++ b/modules/swag/mod.ts
@@ -230,7 +230,7 @@ routes.get("/", (c) => {
const space = c.req.param("space") || "demo";
return c.html(renderShell({
title: `Swag Designer | rSpace`,
- moduleId: "swag",
+ moduleId: "rswag",
spaceSlug: space,
modules: getModuleInfoList(),
theme: "dark",
@@ -241,7 +241,7 @@ routes.get("/", (c) => {
});
export const swagModule: RSpaceModule = {
- id: "swag",
+ id: "rswag",
name: "rSwag",
icon: "\u{1F3A8}",
description: "Design print-ready swag: stickers, posters, tees",
diff --git a/modules/trips/mod.ts b/modules/trips/mod.ts
index 63c311c..8284f15 100644
--- a/modules/trips/mod.ts
+++ b/modules/trips/mod.ts
@@ -240,7 +240,7 @@ routes.get("/routes", (c) => {
const space = c.req.param("space") || "demo";
return c.html(renderShell({
title: `${space} — Route Planner | rTrips`,
- moduleId: "trips",
+ moduleId: "rtrips",
spaceSlug: space,
modules: getModuleInfoList(),
theme: "dark",
@@ -255,7 +255,7 @@ routes.get("/", (c) => {
const space = c.req.param("space") || "demo";
return c.html(renderShell({
title: `${space} — Trips | rSpace`,
- moduleId: "trips",
+ moduleId: "rtrips",
spaceSlug: space,
modules: getModuleInfoList(),
theme: "dark",
@@ -266,7 +266,7 @@ routes.get("/", (c) => {
});
export const tripsModule: RSpaceModule = {
- id: "trips",
+ id: "rtrips",
name: "rTrips",
icon: "\u{2708}\u{FE0F}",
description: "Collaborative trip planner with itinerary, bookings, and expense splitting",
diff --git a/modules/tube/mod.ts b/modules/tube/mod.ts
index aea5863..cac5656 100644
--- a/modules/tube/mod.ts
+++ b/modules/tube/mod.ts
@@ -193,7 +193,7 @@ routes.get("/", (c) => {
const space = c.req.param("space") || "demo";
return c.html(renderShell({
title: `${space} — Tube | rSpace`,
- moduleId: "tube",
+ moduleId: "rtube",
spaceSlug: space,
modules: getModuleInfoList(),
theme: "dark",
@@ -204,7 +204,7 @@ routes.get("/", (c) => {
});
export const tubeModule: RSpaceModule = {
- id: "tube",
+ id: "rtube",
name: "rTube",
icon: "\u{1F3AC}",
description: "Community video hosting & live streaming",
diff --git a/modules/vote/mod.ts b/modules/vote/mod.ts
index d0aadff..6d36285 100644
--- a/modules/vote/mod.ts
+++ b/modules/vote/mod.ts
@@ -329,7 +329,7 @@ routes.get("/", (c) => {
const space = c.req.param("space") || "demo";
return c.html(renderShell({
title: `${space} — Vote | rSpace`,
- moduleId: "vote",
+ moduleId: "rvote",
spaceSlug: space,
modules: getModuleInfoList(),
theme: "dark",
@@ -340,7 +340,7 @@ routes.get("/", (c) => {
});
export const voteModule: RSpaceModule = {
- id: "vote",
+ id: "rvote",
name: "rVote",
icon: "\u{1F5F3}",
description: "Conviction voting engine for collaborative governance",
diff --git a/modules/wallet/mod.ts b/modules/wallet/mod.ts
index 3c435b3..6714ee0 100644
--- a/modules/wallet/mod.ts
+++ b/modules/wallet/mod.ts
@@ -96,7 +96,7 @@ routes.get("/", (c) => {
const spaceSlug = c.req.param("space") || "demo";
return c.html(renderShell({
title: `${spaceSlug} — Wallet | rSpace`,
- moduleId: "wallet",
+ moduleId: "rwallet",
spaceSlug,
modules: getModuleInfoList(),
theme: "dark",
@@ -107,7 +107,7 @@ routes.get("/", (c) => {
});
export const walletModule: RSpaceModule = {
- id: "wallet",
+ id: "rwallet",
name: "rWallet",
icon: "\uD83D\uDCB0",
description: "Multichain Safe wallet visualization and treasury management",
diff --git a/modules/work/mod.ts b/modules/work/mod.ts
index 0ec97e1..ba03d2a 100644
--- a/modules/work/mod.ts
+++ b/modules/work/mod.ts
@@ -219,7 +219,7 @@ routes.get("/", (c) => {
const space = c.req.param("space") || "demo";
return c.html(renderShell({
title: `${space} — Work | rSpace`,
- moduleId: "work",
+ moduleId: "rwork",
spaceSlug: space,
modules: getModuleInfoList(),
theme: "dark",
@@ -230,7 +230,7 @@ routes.get("/", (c) => {
});
export const workModule: RSpaceModule = {
- id: "work",
+ id: "rwork",
name: "rWork",
icon: "\u{1F4CB}",
description: "Kanban workspace boards for collaborative task management",
diff --git a/server/index.ts b/server/index.ts
index 042b568..5e9a7ed 100644
--- a/server/index.ts
+++ b/server/index.ts
@@ -209,7 +209,7 @@ function generateFallbackResponse(
}
if (q.includes("help") || q.includes("what can")) {
- return `rSpace has ${modules.length} apps you can use. Some popular ones: **rSpace** (canvas), **rNotes** (notes), **rChat** (messaging), **rFunds** (community funding), and **rVote** (governance). What would you like to explore?`;
+ return `rSpace has ${modules.length} apps you can use. Some popular ones: **rSpace** (spatial canvas), **rNotes** (notes), **rChat** (messaging), **rFunds** (community funding), and **rVote** (governance). What would you like to explore?`;
}
if (q.includes("search") || q.includes("find")) {
@@ -474,8 +474,14 @@ for (const mod of getAllModules()) {
// ── Page routes ──
-// Landing page: rspace.online/ → redirect to demo canvas (overlay shows there)
-app.get("/", (c) => c.redirect("/demo/canvas", 302));
+// Landing page: rspace.online/ → serve marketing/info page
+app.get("/", async (c) => {
+ const file = Bun.file(resolve(DIST_DIR, "index.html"));
+ if (await file.exists()) {
+ return new Response(file, { headers: { "Content-Type": "text/html" } });
+ }
+ return c.text("rSpace", 200);
+});
// About/info page (full landing content)
app.get("/about", async (c) => {
@@ -507,12 +513,12 @@ app.get("/admin", async (c) => {
return c.text("Admin", 200);
});
-// Space root: /:space → redirect to /:space/canvas
+// Space root: /:space → redirect to /:space/rspace
app.get("/:space", (c) => {
const space = c.req.param("space");
// Don't redirect for static file paths
if (space.includes(".")) return c.notFound();
- return c.redirect(`/${space}/canvas`);
+ return c.redirect(`/${space}/rspace`);
});
// ── WebSocket types ──
@@ -743,9 +749,9 @@ const server = Bun.serve({
if (subdomain) {
const pathSegments = url.pathname.split("/").filter(Boolean);
- // Root: redirect to default module (canvas)
+ // Root: redirect to default module (rspace)
if (pathSegments.length === 0) {
- return Response.redirect(`${url.protocol}//${host}/canvas`, 302);
+ return Response.redirect(`${url.protocol}//${host}/rspace`, 302);
}
// Global routes pass through without subdomain prefix
diff --git a/shared/components/rstack-app-switcher.ts b/shared/components/rstack-app-switcher.ts
index 64b4aa6..6d2440c 100644
--- a/shared/components/rstack-app-switcher.ts
+++ b/shared/components/rstack-app-switcher.ts
@@ -19,76 +19,76 @@ export interface AppSwitcherModule {
// Pastel badge abbreviations & colors for each module
const MODULE_BADGES: Record = {
// Creating
- canvas: { badge: "rS", color: "#5eead4" }, // teal-300
- notes: { badge: "rN", color: "#fcd34d" }, // amber-300
- pubs: { badge: "rP", color: "#fda4af" }, // rose-300
- swag: { badge: "rSw", color: "#fda4af" }, // rose-300
- splat: { badge: "r3", color: "#d8b4fe" }, // purple-300
+ rspace: { badge: "rS", color: "#5eead4" }, // teal-300
+ rnotes: { badge: "rN", color: "#fcd34d" }, // amber-300
+ rpubs: { badge: "rP", color: "#fda4af" }, // rose-300
+ rswag: { badge: "rSw", color: "#fda4af" }, // rose-300
+ rsplat: { badge: "r3", color: "#d8b4fe" }, // purple-300
// Planning
- cal: { badge: "rC", color: "#7dd3fc" }, // sky-300
- trips: { badge: "rT", color: "#6ee7b7" }, // emerald-300
- maps: { badge: "rM", color: "#86efac" }, // green-300
+ rcal: { badge: "rC", color: "#7dd3fc" }, // sky-300
+ rtrips: { badge: "rT", color: "#6ee7b7" }, // emerald-300
+ rmaps: { badge: "rM", color: "#86efac" }, // green-300
// Communicating
- chats: { badge: "rCh", color: "#6ee7b7" }, // emerald-200
- inbox: { badge: "rI", color: "#a5b4fc" }, // indigo-300
- mail: { badge: "rMa", color: "#93c5fd" }, // blue-200
- forum: { badge: "rFo", color: "#fcd34d" }, // amber-200
+ rchats: { badge: "rCh", color: "#6ee7b7" }, // emerald-200
+ rinbox: { badge: "rI", color: "#a5b4fc" }, // indigo-300
+ rmail: { badge: "rMa", color: "#93c5fd" }, // blue-200
+ rforum: { badge: "rFo", color: "#fcd34d" }, // amber-200
// Deciding
- choices: { badge: "rCo", color: "#f0abfc" }, // fuchsia-300
- vote: { badge: "rV", color: "#c4b5fd" }, // violet-300
+ rchoices: { badge: "rCo", color: "#f0abfc" }, // fuchsia-300
+ rvote: { badge: "rV", color: "#c4b5fd" }, // violet-300
// Funding & Commerce
- funds: { badge: "rF", color: "#bef264" }, // lime-300
- wallet: { badge: "rW", color: "#fde047" }, // yellow-300
- cart: { badge: "rCt", color: "#fdba74" }, // orange-300
- auctions: { badge: "rA", color: "#fca5a5" }, // red-300
- providers: { badge: "rPr", color: "#fdba74" }, // orange-300
- tube: { badge: "rTu", color: "#f9a8d4" }, // pink-300
+ rfunds: { badge: "rF", color: "#bef264" }, // lime-300
+ rwallet: { badge: "rW", color: "#fde047" }, // yellow-300
+ rcart: { badge: "rCt", color: "#fdba74" }, // orange-300
+ rauctions: { badge: "rA", color: "#fca5a5" }, // red-300
+ rproviders: { badge: "rPr", color: "#fdba74" }, // orange-300
+ rtube: { badge: "rTu", color: "#f9a8d4" }, // pink-300
// Sharing
- photos: { badge: "rPh", color: "#f9a8d4" }, // pink-200
- network: { badge: "rNe", color: "#93c5fd" }, // blue-300
- socials: { badge: "rSo", color: "#7dd3fc" }, // sky-200
- files: { badge: "rFi", color: "#67e8f9" }, // cyan-300
- books: { badge: "rB", color: "#fda4af" }, // rose-300
+ rphotos: { badge: "rPh", color: "#f9a8d4" }, // pink-200
+ rnetwork: { badge: "rNe", color: "#93c5fd" }, // blue-300
+ rsocials: { badge: "rSo", color: "#7dd3fc" }, // sky-200
+ rfiles: { badge: "rFi", color: "#67e8f9" }, // cyan-300
+ rbooks: { badge: "rB", color: "#fda4af" }, // rose-300
// Observing
- data: { badge: "rD", color: "#d8b4fe" }, // purple-300
+ rdata: { badge: "rD", color: "#d8b4fe" }, // purple-300
// Work & Productivity
- work: { badge: "rWo", color: "#cbd5e1" }, // slate-300
+ rwork: { badge: "rWo", color: "#cbd5e1" }, // slate-300
// Identity & Infrastructure
- ids: { badge: "rId", color: "#6ee7b7" }, // emerald-300
- stack: { badge: "r*", color: "" }, // gradient (handled separately)
+ rids: { badge: "rId", color: "#6ee7b7" }, // emerald-300
+ rstack: { badge: "r*", color: "" }, // gradient (handled separately)
};
// Category definitions for the rApp dropdown (display-only grouping)
const MODULE_CATEGORIES: Record = {
- canvas: "Creating",
- notes: "Creating",
- pubs: "Creating",
- tube: "Creating",
- swag: "Creating",
- splat: "Creating",
- cal: "Planning",
- trips: "Planning",
- maps: "Planning",
- chats: "Communicating",
- inbox: "Communicating",
- mail: "Communicating",
- forum: "Communicating",
- choices: "Deciding",
- vote: "Deciding",
- funds: "Funding & Commerce",
- wallet: "Funding & Commerce",
- cart: "Funding & Commerce",
- auctions: "Funding & Commerce",
- providers: "Funding & Commerce",
- photos: "Sharing",
- network: "Sharing",
- socials: "Sharing",
- files: "Sharing",
- books: "Sharing",
- data: "Observing",
- work: "Work & Productivity",
- ids: "Identity & Infrastructure",
- stack: "Identity & Infrastructure",
+ rspace: "Creating",
+ rnotes: "Creating",
+ rpubs: "Creating",
+ rtube: "Creating",
+ rswag: "Creating",
+ rsplat: "Creating",
+ rcal: "Planning",
+ rtrips: "Planning",
+ rmaps: "Planning",
+ rchats: "Communicating",
+ rinbox: "Communicating",
+ rmail: "Communicating",
+ rforum: "Communicating",
+ rchoices: "Deciding",
+ rvote: "Deciding",
+ rfunds: "Funding & Commerce",
+ rwallet: "Funding & Commerce",
+ rcart: "Funding & Commerce",
+ rauctions: "Funding & Commerce",
+ rproviders: "Funding & Commerce",
+ rphotos: "Sharing",
+ rnetwork: "Sharing",
+ rsocials: "Sharing",
+ rfiles: "Sharing",
+ rbooks: "Sharing",
+ rdata: "Observing",
+ rwork: "Work & Productivity",
+ rids: "Identity & Infrastructure",
+ rstack: "Identity & Infrastructure",
};
const CATEGORY_ORDER = [
@@ -150,15 +150,15 @@ export class RStackAppSwitcher extends HTMLElement {
}
}
- // rStack header
+ // rStack header (clickable)
let html = `
-
+
`;
for (const cat of CATEGORY_ORDER) {
@@ -304,10 +304,13 @@ const STYLES = `
}
/* rStack header */
-.rstack-header {
+a.rstack-header {
display: flex; align-items: center; gap: 10px;
padding: 12px 14px; border-bottom: 1px solid rgba(128,128,128,0.15);
+ text-decoration: none; color: inherit; cursor: pointer;
+ transition: background 0.12s;
}
+a.rstack-header:hover { background: rgba(255,255,255,0.05); }
.rstack-badge {
display: flex; align-items: center; justify-content: center;
width: 28px; height: 28px; border-radius: 8px;
diff --git a/shared/components/rstack-identity.ts b/shared/components/rstack-identity.ts
index 9172528..9d66671 100644
--- a/shared/components/rstack-identity.ts
+++ b/shared/components/rstack-identity.ts
@@ -146,7 +146,7 @@ function _getCurrentSpace(): string {
}
function _getCurrentModule(): string {
const parts = window.location.pathname.split("/").filter(Boolean);
- return _isSubdomain() ? (parts[0] || "canvas") : (parts[1] || "canvas");
+ return _isSubdomain() ? (parts[0] || "rspace") : (parts[1] || "rspace");
}
function _navUrl(space: string, moduleId: string): string {
const h = window.location.host.split(":")[0].split(".");
diff --git a/shared/components/rstack-tab-bar.ts b/shared/components/rstack-tab-bar.ts
index 997f543..2bfb6b5 100644
--- a/shared/components/rstack-tab-bar.ts
+++ b/shared/components/rstack-tab-bar.ts
@@ -25,33 +25,33 @@ import { FLOW_COLORS, FLOW_LABELS } from "../../lib/layer-types";
// Re-export badge info so the tab bar can show module colors
const MODULE_BADGES: Record = {
- canvas: { badge: "rS", color: "#5eead4" },
- notes: { badge: "rN", color: "#fcd34d" },
- pubs: { badge: "rP", color: "#fda4af" },
- swag: { badge: "rSw", color: "#fda4af" },
- splat: { badge: "r3", color: "#d8b4fe" },
- cal: { badge: "rC", color: "#7dd3fc" },
- trips: { badge: "rT", color: "#6ee7b7" },
- maps: { badge: "rM", color: "#86efac" },
- chats: { badge: "rCh", color: "#6ee7b7" },
- inbox: { badge: "rI", color: "#a5b4fc" },
- mail: { badge: "rMa", color: "#93c5fd" },
- forum: { badge: "rFo", color: "#fcd34d" },
- choices: { badge: "rCo", color: "#f0abfc" },
- vote: { badge: "rV", color: "#c4b5fd" },
- funds: { badge: "rF", color: "#bef264" },
- wallet: { badge: "rW", color: "#fde047" },
- cart: { badge: "rCt", color: "#fdba74" },
- auctions: { badge: "rA", color: "#fca5a5" },
- providers: { badge: "rPr", color: "#fdba74" },
- tube: { badge: "rTu", color: "#f9a8d4" },
- photos: { badge: "rPh", color: "#f9a8d4" },
- network: { badge: "rNe", color: "#93c5fd" },
- socials: { badge: "rSo", color: "#7dd3fc" },
- files: { badge: "rFi", color: "#67e8f9" },
- books: { badge: "rB", color: "#fda4af" },
- data: { badge: "rD", color: "#d8b4fe" },
- work: { badge: "rWo", color: "#cbd5e1" },
+ rspace: { badge: "rS", color: "#5eead4" },
+ rnotes: { badge: "rN", color: "#fcd34d" },
+ rpubs: { badge: "rP", color: "#fda4af" },
+ rswag: { badge: "rSw", color: "#fda4af" },
+ rsplat: { badge: "r3", color: "#d8b4fe" },
+ rcal: { badge: "rC", color: "#7dd3fc" },
+ rtrips: { badge: "rT", color: "#6ee7b7" },
+ rmaps: { badge: "rM", color: "#86efac" },
+ rchats: { badge: "rCh", color: "#6ee7b7" },
+ rinbox: { badge: "rI", color: "#a5b4fc" },
+ rmail: { badge: "rMa", color: "#93c5fd" },
+ rforum: { badge: "rFo", color: "#fcd34d" },
+ rchoices: { badge: "rCo", color: "#f0abfc" },
+ rvote: { badge: "rV", color: "#c4b5fd" },
+ rfunds: { badge: "rF", color: "#bef264" },
+ rwallet: { badge: "rW", color: "#fde047" },
+ rcart: { badge: "rCt", color: "#fdba74" },
+ rauctions: { badge: "rA", color: "#fca5a5" },
+ rproviders: { badge: "rPr", color: "#fdba74" },
+ rtube: { badge: "rTu", color: "#f9a8d4" },
+ rphotos: { badge: "rPh", color: "#f9a8d4" },
+ rnetwork: { badge: "rNe", color: "#93c5fd" },
+ rsocials: { badge: "rSo", color: "#7dd3fc" },
+ rfiles: { badge: "rFi", color: "#67e8f9" },
+ rbooks: { badge: "rB", color: "#fda4af" },
+ rdata: { badge: "rD", color: "#d8b4fe" },
+ rwork: { badge: "rWo", color: "#cbd5e1" },
};
export class RStackTabBar extends HTMLElement {
diff --git a/shared/url-helpers.ts b/shared/url-helpers.ts
index 7b01d64..91407f1 100644
--- a/shared/url-helpers.ts
+++ b/shared/url-helpers.ts
@@ -35,9 +35,9 @@ export function getCurrentSpace(): string {
export function getCurrentModule(): string {
const parts = window.location.pathname.split("/").filter(Boolean);
if (isSubdomain()) {
- return parts[0] || "canvas";
+ return parts[0] || "rspace";
}
- return parts[1] || "canvas";
+ return parts[1] || "rspace";
}
/**
diff --git a/website/index.html b/website/index.html
index f0bc8b5..91ffff9 100644
--- a/website/index.html
+++ b/website/index.html
@@ -379,7 +379,7 @@