`;
+}
diff --git a/modules/cart/mod.ts b/modules/cart/mod.ts
index 66d3bcf..47ca254 100644
--- a/modules/cart/mod.ts
+++ b/modules/cart/mod.ts
@@ -15,6 +15,7 @@ import { getModuleInfoList } from "../../shared/module";
import { depositOrderRevenue } from "./flow";
import type { RSpaceModule } from "../../shared/module";
import { verifyEncryptIDToken, extractToken } from "@encryptid/sdk/server";
+import { renderLanding } from "./landing";
const routes = new Hono();
@@ -460,6 +461,7 @@ export const cartModule: RSpaceModule = {
description: "Cosmolocal print-on-demand shop",
routes,
standaloneDomain: "rcart.online",
+ landingPage: renderLanding,
feeds: [
{
id: "orders",
diff --git a/modules/choices/landing.ts b/modules/choices/landing.ts
new file mode 100644
index 0000000..7c5ad15
--- /dev/null
+++ b/modules/choices/landing.ts
@@ -0,0 +1,120 @@
+/**
+ * rChoices — rich landing page body.
+ * Returned by landingPage() in the module export;
+ * the shell wraps it with header, CSS, and analytics.
+ */
+export function renderLanding(): string {
+ const demo = "https://demo.rspace.online/rchoices";
+
+ return `
+
+
+ rChoices
+
Decide Together, Fairly
+
+ Quadratic voting, ranked choice, and multi-criteria scoring — all as
+ interactive shapes on your canvas. Drop a choice, let members vote,
+ watch results emerge in real time.
+
`;
+}
diff --git a/modules/choices/mod.ts b/modules/choices/mod.ts
index db15100..9a233a9 100644
--- a/modules/choices/mod.ts
+++ b/modules/choices/mod.ts
@@ -11,6 +11,7 @@
import { Hono } from "hono";
import { renderShell } from "../../server/shell";
import type { RSpaceModule } from "../../shared/module";
+import { renderLanding } from "./landing";
import { getModuleInfoList } from "../../shared/module";
import { getDocumentData } from "../../server/community-store";
@@ -67,6 +68,7 @@ export const choicesModule: RSpaceModule = {
description: "Polls, rankings, and multi-criteria scoring",
routes,
standaloneDomain: "rchoices.online",
+ landingPage: renderLanding,
feeds: [
{
id: "poll-results",
diff --git a/modules/data/landing.ts b/modules/data/landing.ts
new file mode 100644
index 0000000..de6fca7
--- /dev/null
+++ b/modules/data/landing.ts
@@ -0,0 +1,120 @@
+/**
+ * rData — rich landing page body.
+ * Returned by landingPage() in the module export;
+ * the shell wraps it with header, CSS, and analytics.
+ */
+export function renderLanding(): string {
+ const demo = "https://demo.rspace.online/rdata";
+
+ return `
+
+
+ rData
+
Privacy-First Analytics
+
+ See how your community engages without tracking individuals.
+ No cookies, no consent banners, no third-party data — just
+ clean, real-time metrics from your own server.
+
`;
+}
diff --git a/modules/funds/mod.ts b/modules/funds/mod.ts
index 7669328..6de9e27 100644
--- a/modules/funds/mod.ts
+++ b/modules/funds/mod.ts
@@ -12,6 +12,7 @@ import { renderShell } from "../../server/shell";
import type { RSpaceModule } from "../../shared/module";
import { getModuleInfoList } from "../../shared/module";
import { verifyEncryptIDToken, extractToken } from "@encryptid/sdk/server";
+import { renderLanding } from "./landing";
const FLOW_SERVICE_URL = process.env.FLOW_SERVICE_URL || "http://payment-flow:3010";
@@ -245,6 +246,7 @@ export const fundsModule: RSpaceModule = {
icon: "\uD83C\uDF0A",
description: "Budget flows, river visualization, and treasury management",
routes,
+ landingPage: renderLanding,
standaloneDomain: "rfunds.online",
feeds: [
{
diff --git a/modules/inbox/landing.ts b/modules/inbox/landing.ts
new file mode 100644
index 0000000..45bfb3d
--- /dev/null
+++ b/modules/inbox/landing.ts
@@ -0,0 +1,153 @@
+/**
+ * Inbox module landing page — static HTML, no React.
+ */
+export function renderLanding(): string {
+ return `
+
+
+ rInbox
+
+ Collaborative Multi-Sig Inbox
+
+
+ A shared email client where teams read, discuss, and approve messages
+ together — with cryptographic multi-signature workflows before anything gets sent.
+
+`;
+}
diff --git a/modules/inbox/mod.ts b/modules/inbox/mod.ts
index cadc7b5..d5559f3 100644
--- a/modules/inbox/mod.ts
+++ b/modules/inbox/mod.ts
@@ -13,6 +13,7 @@ import { renderShell } from "../../server/shell";
import { getModuleInfoList } from "../../shared/module";
import type { RSpaceModule } from "../../shared/module";
import { verifyEncryptIDToken, extractToken } from "@encryptid/sdk/server";
+import { renderLanding } from "./landing";
const routes = new Hono();
@@ -548,6 +549,7 @@ export const inboxModule: RSpaceModule = {
icon: "\u{1F4E8}",
description: "Collaborative email with multisig approval",
routes,
+ landingPage: renderLanding,
standaloneDomain: "rinbox.online",
feeds: [
{
diff --git a/modules/maps/landing.ts b/modules/maps/landing.ts
new file mode 100644
index 0000000..3f22b18
--- /dev/null
+++ b/modules/maps/landing.ts
@@ -0,0 +1,320 @@
+/**
+ * Maps module landing page — static HTML, no React.
+ */
+export function renderLanding(): string {
+ return `
+
+
+ rMaps
+
+ Real-Time Collaborative Maps
+
+
+ Share live locations, navigate indoor and outdoor spaces, coordinate meetups
+ — all from the browser. No app install. No tracking. No data collection.
+
+ Real-time location updates via WebSocket. See everyone on the map
+ as they move, with stale detection and high-accuracy fallback.
+
+
+
+
+
+
+
+
Indoor + Outdoor Nav
+
+ Turn-by-turn routing via OSRM outdoors, seamless switch to c3nav
+ for indoor venues. Multi-floor, level-aware navigation.
+
+
+
+
+
+
+
+
Meeting Points
+
+ Drop waypoints for meetups, events, and points of interest.
+ Search by address, share coordinates, or pin from your location.
+
+
+
+
+
+
+
+
Privacy First
+
+ Ghost mode, precision levels, one-toggle location sharing.
+ Zero tracking, zero data collection. You control who sees you.
+
+
+
+
+
+
+
+
+
+ Beyond Google Maps
+
+ What makes rMaps different
+
+
+
+
+ 🏕️
+
+
+
CCC Event Integration
+
+ Native c3nav integration for 39C3, Camp, and other CCC events. Indoor maps with
+ multi-floor routing, venue bounds detection, and automatic map switching
+ when you walk inside.
+
+
+
+
+
+
+ 📡
+
+
+
Location Pinging
+
+ Request a friend's location with one tap. Push notifications via
+ Web Push API with vibration alerts. Works even when the app is
+ backgrounded via service worker.
+
+
+
+
+
+
+ 📦
+
+
+
Google Maps Import
+
+ Import your saved places from Google Takeout ZIP exports. GeoJSON
+ parsing, auto-emoji mapping by place type, and preview before
+ importing.
+
+
+
+
+
+
+ 📱
+
+
+
PWA & Offline Mode
+
+ Install as a native app. Three-tier service worker caching keeps
+ maps accessible offline with up to 500 cached tiles. Background
+ sync handles location updates.
+
+
+
+
+
+
+ 🔗
+
+
+
Instant Room Sharing
+
+ Generate a QR code or shareable link for any room. Friends scan or tap
+ to join instantly — no account needed, no app download.
+ Native share dialog on mobile.
+
+
+
+
+
+
+ 🔄
+
+
+
Conflict-Free Sync
+
+ Automerge CRDT architecture ensures everyone sees the same map state,
+ even through disconnections. WebSocket real-time sync with automatic
+ reconnection and state recovery.
+
+
+
+
+
+
+
+
+
+
+ How It Works
+
+ Three steps to find your crew
+
+
+
+
1
+
Create a Map Room
+
+ Sign in and name your room. Get a shareable link or a custom slug.
+
+
+
+
2
+
Share with Friends
+
+ Send the link or scan the QR code. Friends join from any browser
+ — no app download, no account creation needed.
+
+
+
+
3
+
Navigate Together
+
+ See everyone in real time. Drop meeting points, get turn-by-turn
+ directions, and ping friends when you need to regroup.
+
+
+
+
+
+
+
+
+
+ Built For
+
+ Maps for every gathering
+
+
+
+
🏕️
+
Festivals & Camps
+
+ Navigate massive venues with indoor maps. Find stages, food courts,
+ and your crew across multi-day events like CCC Camp.
+
+
+
+
+
🏙️
+
City Exploration
+
+ Exploring a new city with friends? Share locations, drop pins at
+ restaurants and landmarks, import your Google Maps saved places.
+
+
+
+
+
🤝
+
Group Coordination
+
+ Conferences, retreats, team offsites. Set meeting points, ping
+ stragglers, and get walking directions to the next session.
+
+
+
+
+ First built for CCC events — now for any gathering.
+
+`;
+}
diff --git a/modules/maps/mod.ts b/modules/maps/mod.ts
index 9897903..569006b 100644
--- a/modules/maps/mod.ts
+++ b/modules/maps/mod.ts
@@ -10,6 +10,7 @@ import { Hono } from "hono";
import { renderShell } from "../../server/shell";
import { getModuleInfoList } from "../../shared/module";
import type { RSpaceModule } from "../../shared/module";
+import { renderLanding } from "./landing";
const routes = new Hono();
@@ -167,6 +168,7 @@ export const mapsModule: RSpaceModule = {
icon: "\u{1F5FA}",
description: "Real-time collaborative location sharing and indoor/outdoor maps",
routes,
+ landingPage: renderLanding,
standaloneDomain: "rmaps.online",
feeds: [
{
diff --git a/modules/notes/landing.ts b/modules/notes/landing.ts
new file mode 100644
index 0000000..2142ade
--- /dev/null
+++ b/modules/notes/landing.ts
@@ -0,0 +1,183 @@
+/**
+ * Notes module landing page — static HTML, no React.
+ */
+export function renderLanding(): string {
+ return `
+
+
+ rNotes
+
+ Capture Everything, Find Anything, and Share your Insights
+
+
+ Notes, clips, voice recordings, and live transcription — all in one place.
+ Speak and watch your words appear in real time, or drop in audio and video files to transcribe offline.
+
Speak and watch your words appear in real time. WebSocket streaming with live timestamps.
+
+
+
2
+
Audio & Video
+
Drop in audio or video files and get a full transcript. Powered by NVIDIA Parakeet — runs entirely in your browser.
+
+
+
3
+
Notebooks & Tags
+
Organize transcripts into notebooks alongside notes, clips, code, and files. Tag freely, search everything.
+
+
+
4
+
Private & Offline
+
Parakeet.js runs entirely in the browser. Your audio never leaves your device — full offline support.
+
+
+
+
+
+
+
+
+
Memory Cards
+
+ Every note is a Memory Card — a typed, structured unit of knowledge with hierarchy,
+ properties, and attachments. Designed for round-trip interoperability with Logseq.
+
+
+
+
+
+
+
+
7 Card Types
+
+ note
+ link
+ task
+ idea
+ person
+ reference
+ file
+
+
Each card type has distinct styling and behavior. Typed notes surface in filtered views and canvas visualizations.
+
+
+
+
+
+
+
+
Hierarchy & Properties
+
+ Nest cards under parents to build knowledge trees. Add structured
+ key:: value
+ properties — compatible with Logseq's property syntax.
+
+
+
type:: idea
+
status:: doing
+
tags:: #research, #web3
+
+
+
+
+
+
+
+
+
Logseq Import & Export
+
+ Export your notebooks as Logseq-compatible ZIP archives. Import a Logseq graph and keep your pages,
+ properties, tags, and hierarchy intact.
+
+
+ Round-trip fidelity: card types, tags, attachments, and parent-child structure all survive the journey.
+
+
+
+
+
+
+
+
+
Dual Format Storage
+
+ Every card stores rich TipTap JSON for editing and portable Markdown for search, export, and interoperability.
+ Write once, read anywhere.
+
+
+
+
+
+
+
+
+
Structured Attachments
+
+ Attach images, PDFs, audio, and files to any card with roles (primary, preview, supporting) and captions.
+ Thumbnails render inline.
+
+
+
+
+
+
+
+
+
FUN, Not CRUD
+
+ Forget,
+ Update,
+ New —
+ nothing is permanently destroyed. Forgotten cards are archived and can be remembered at any time.
+
+
+
+
+
+
+
+
+
+
Start capturing
+
Notes, voice, clips, and code — all in one notebook.
`;
+}
diff --git a/modules/photos/mod.ts b/modules/photos/mod.ts
index 1e0e6fe..58cc623 100644
--- a/modules/photos/mod.ts
+++ b/modules/photos/mod.ts
@@ -10,6 +10,7 @@ import { Hono } from "hono";
import { renderShell } from "../../server/shell";
import { getModuleInfoList } from "../../shared/module";
import type { RSpaceModule } from "../../shared/module";
+import { renderLanding } from "./landing";
const routes = new Hono();
@@ -126,6 +127,7 @@ export const photosModule: RSpaceModule = {
icon: "📸",
description: "Community photo commons",
routes,
+ landingPage: renderLanding,
standaloneDomain: "rphotos.online",
feeds: [
{
diff --git a/modules/pubs/landing.ts b/modules/pubs/landing.ts
new file mode 100644
index 0000000..118f6c1
--- /dev/null
+++ b/modules/pubs/landing.ts
@@ -0,0 +1,221 @@
+/**
+ * rPubs landing page — community pocket press.
+ */
+export function renderLanding(): string {
+ return `
+
+
+ rPubs
+
Write it. Press it. Share it.
+
+ Drop in a markdown document, pick a pocket format, and get a print-ready PDF in seconds.
+ Group up with other authors to unlock bulk pricing through collaborative print runs.
+
Drop in markdown or rich text. Headings, images, footnotes — it all just works.
+
+
+ 2
+
Press it
+
Pick a pocket format. rPubs typesets your document with Typst and generates a print-ready PDF.
+
+
+ 3
+
Print locally
+
Print at home, at a local shop, or list it on rCart for cosmolocal fulfillment.
+
+
+
+
+
+
+
+
+
Four pocket formats
+
From palm-sized zines to digest readers. All print-ready at 300 dpi with bleeds.
+
+
+
+
+
+
A7 Pocket
+
74 × 105 mm — fits in a shirt pocket. Perfect for poems, manifestos, tiny zines.
+
+
+
+
+
+
Quarter Letter
+
4.25 × 5.5" — half a half-sheet. Great for chapbooks and field guides.
+
+
+
+
+
+
A6 Booklet
+
105 × 148 mm — postcard size. The workhorse format for essays and readers.
+
+
+
+
+
+
Digest
+
5.5 × 8.5" — half-letter. Standard trade paperback for longer works.
+
+
+
+
+
+
+
+
+
Group buys — better together
+
Pool orders across titles. The more copies in a run, the cheaper each one gets.
+
+
+
25+ copies
+
Saddle-stitch binding
+
$8
+
per copy
+
+
+
50+ copies
+
Perfect-bind
+
$6
+ Save 25%
+
per copy
+
+
+
100+ copies
+
Trade edition
+
$4.50
+ Save 44%
+
per copy
+
+
+
+
+
+
+
+
+
How collaborative print runs work
+
+
+ 1
+
Authors list titles
+
Publish your print-ready artifact to the rCart catalog.
+
+
+ 2
+
Readers pre-order
+
Buyers add copies to a shared cart. Orders accumulate toward tier thresholds.
+
+
+ 3
+
Threshold met
+
When the combined order hits a tier, the print run triggers automatically.
+
+
+ 4
+
Local fulfillment
+
The nearest cosmolocal provider prints and ships. Revenue splits to creator, community, and provider.
+
+
+
+
+
+
+
+
+
Cross-title batching
+
+ Orders from different titles count toward the same tier. A community reading list
+ can hit trade-edition pricing even if no single title has 100 orders.
+
+
+
Example batch
+
+
+ The Commons35 copies
+
+
+ Mycelial Networks40 copies
+
+
+ Cosmolocal Reader30 copies
+
+
+
combined
+
+ 105 copies
+ = Trade edition @ $4.50/copy
+
+
+
+
+
+
+
+
+
+
+
rCart integration
+
+ Group purchasing is built right into the shop. Every rPubs artifact can be listed,
+ batched, and fulfilled through rCart.
+
+
+
One-click listing — publish to the rCart catalog straight from the press
+
Group carts — space members pool orders automatically
+
Revenue splits — creator, community, and provider shares via rFunds
+
Cosmolocal fulfillment — nearest provider prints and ships
+
Order tracking — real-time status from press to doorstep
+
+
+
+
+
+
+
+
Shop + Press
+
rPubs creates the artifact. rCart sells and fulfills it.
+
+
+
+
+
+
+
+
+
+ rPubs × Cosmolocal
+
Design global, manufacture local
+
+ Every print run is routed to the nearest capable provider. Reduce shipping emissions,
+ support local economies, and still benefit from shared design and pooled demand.
+
`;
+}
diff --git a/modules/pubs/mod.ts b/modules/pubs/mod.ts
index 6456c5e..82bdc2a 100644
--- a/modules/pubs/mod.ts
+++ b/modules/pubs/mod.ts
@@ -16,6 +16,7 @@ import type { BookFormat } from "./formats";
import { renderShell } from "../../server/shell";
import { getModuleInfoList } from "../../shared/module";
import type { RSpaceModule } from "../../shared/module";
+import { renderLanding } from "./landing";
const ARTIFACTS_DIR = process.env.ARTIFACTS_DIR || "/tmp/rpubs-artifacts";
@@ -342,6 +343,7 @@ export const pubsModule: RSpaceModule = {
description: "Drop in a document, get a pocket book",
routes,
standaloneDomain: "rpubs.online",
+ landingPage: renderLanding,
feeds: [
{
id: "publications",
diff --git a/modules/rsocials/landing.ts b/modules/rsocials/landing.ts
new file mode 100644
index 0000000..3879a99
--- /dev/null
+++ b/modules/rsocials/landing.ts
@@ -0,0 +1,165 @@
+/**
+ * rSocials — rich landing page body.
+ * Returned by landingPage() in the module export;
+ * the shell wraps it with header, CSS, and analytics.
+ */
+export function renderLanding(): string {
+ const demo = "https://demo.rspace.online/rsocials";
+
+ return `
+
+
+ rSocials
+
Social Media Under Your Control
+
+ Schedule, publish, and analyze across every major platform — all
+ from your self-hosted rSpace instance. No per-seat pricing, no
+ third-party data mining.
+
+ Describe your dream trip in plain language. We'll structure it into
+ itineraries, budgets, and bookings — then give you a collaborative
+ canvas to plan together in real-time.
+
+ Tell us about your trip in natural language. “Fly from Toronto to Bali
+ for 2 weeks in March, budget $3000.” We parse it into structured data
+ you can refine.
+
+
+
+
2
+
We Structure It
+
+ AI extracts destinations, dates, budgets, and bookings into organized views.
+ Edit itineraries, track expenses, manage packing lists — all structured
+ and searchable.
+
+
+
+
3
+
Collaborate on Canvas
+
+ Open the collaborative canvas to plan visually with your travel partners.
+ Drag destinations, connect itineraries, and brainstorm together in real-time
+ or async.
+
+
+
+
+
+
+
+
+
+
Everything You Need to Travel Together
+
+ rTrips brings every piece of trip planning into one place — so your group
+ spends less time coordinating and more time exploring.
+
+
+
+
+
+
+
Collaborative Itineraries
+
+ Build day-by-day plans together in real-time. Everyone can add destinations,
+ suggest activities, and rearrange the schedule — changes sync instantly.
+
+
+
+
+
+
+
+
Smart Suggestions
+
+ AI-powered recommendations for destinations, restaurants, and activities based
+ on your group's interests, budget, and travel dates.
+
+
+
+
+
+
+
+
Budget Tracking
+
+ Split costs, track expenses across the group, and keep a running total so
+ everyone knows exactly where the money goes. No more messy spreadsheets.
+
+
+
+
+
+
+
+
Map Integration
+
+ Visualize your entire trip on rMaps. See routes between destinations,
+ nearby points of interest, and real-time location sharing during travel days.
+
+
+
+
+
+
+
+
Packing Lists
+
+ Shared checklists so nothing gets forgotten. Assign items to people, mark
+ off as you pack, and see at a glance what the group still needs.
+
+
+
+
+
+
+
+
Offline Access
+
+ Download your full itinerary, maps, and booking confirmations for travel
+ without connectivity. Everything you need, even without a signal.
+
+
+
+
+
+
+
+
+
+
Built for Groups
+
+ Solo trip planners are everywhere. rTrips is purpose-built for the messy, beautiful
+ reality of traveling with other people.
+
+
+
+
+
+
+
Friends & Family
+
+ Family reunions, friend getaways, multi-generational trips. Everyone contributes
+ ideas, votes on restaurants, and stays in sync without endless group chats.
+
+
+
+
+
+
+
+
Teams & Offsites
+
+ Company retreats, conference travel, team offsites. Coordinate logistics,
+ share flight details, and manage group bookings from a single shared workspace.
+
+
+
+
+
+
+
+
Retreats & Events
+
+ Yoga retreats, wedding trips, festival crews. Organize large groups with
+ sub-itineraries, optional activities, and shared costs that stay transparent.
+
+
+
+
+
+
+
+
+
+
Ready to plan your next adventure?
+
Just describe where you want to go. We'll handle the rest.
Each additional vote on the same proposal costs quadratically more credits. One vote = 1 credit, two = 4, three = 9. Prevents plutocratic capture.
+
+
+
+
+
+
Reddit-style Ranking
+
Proposals accumulate conviction score from community votes. The most supported ideas float to the top.
+
+
+
+
+
+
Vote Decay
+
Votes lose weight over 30–60 days. Stale support fades automatically — no need to manually close polls.
+
+
+
+
+
+
+
+
+
What is Quadratic Priority Ranking?
+
+
+
The Problem
+
Traditional voting (1 person = 1 vote) lets small, passionate groups dominate.
+ Token-weighted voting lets whales decide everything. Neither reflects genuine community preference.
+
+
+
The Solution
+
Quadratic voting makes strong preferences expensive. You can signal that you care a lot —
+ but it costs quadratically more. This balances intensity of preference with breadth of support.
+
+
+
+
+
+
+
+
+
Vote cost calculator
+
The cost of conviction grows quadratically.
+
+
+
+
1
+
vote
+
1 credit
+
+
+
2
+
votes
+
4 credits
+
+
+
3
+
votes
+
9 credits
+
+
+
4
+
votes
+
16 credits
+
+
+
5
+
votes
+
25 credits
+
+
+
+
+
+
+
+
+
+
The lifecycle of a proposal
+
+
+ 1
+
Ranking (QPR)
+
Community members spend credits to upvote proposals. Conviction score accumulates with quadratic cost.
+
+
+ 2
+
Score reaches +100
+
When a proposal crosses the promotion threshold (default 100), it automatically enters the final vote.
+
+
+ 3
+
Pass / Fail Vote
+
A time-limited binary vote (Yes / No / Abstain) decides the outcome. Simple majority wins.
+
+
+
+
+
+
+
+
+
Built for real governance
+
+
+
+
+
+
Earn Credits Daily
+
Every verified member receives a daily credit allowance. No pay-to-play.
+
+
+
+
+
+
Vote Decay
+
Votes decay linearly from day 30 to day 60. Stale support fades, keeping rankings fresh.
+
+
+
+
+
+
Sybil Resistant
+
Passkey authentication via EncryptID. One person, one identity, one credit stream.
+
+
+
+
+
+
Auto Promotion
+
Proposals that hit the threshold automatically move to a final pass/fail vote. No admin bottleneck.
+
+
+
+
+
+
+
+
+
Ready to prioritize democratically?
+
+ Create a governance space, submit proposals, and let your community decide what matters most.
+
`;
+}
diff --git a/modules/vote/mod.ts b/modules/vote/mod.ts
index 6d36285..fecabd0 100644
--- a/modules/vote/mod.ts
+++ b/modules/vote/mod.ts
@@ -13,6 +13,7 @@ import { renderShell } from "../../server/shell";
import { getModuleInfoList } from "../../shared/module";
import type { RSpaceModule } from "../../shared/module";
import { verifyEncryptIDToken, extractToken } from "@encryptid/sdk/server";
+import { renderLanding } from "./landing";
const routes = new Hono();
@@ -346,6 +347,7 @@ export const voteModule: RSpaceModule = {
description: "Conviction voting engine for collaborative governance",
routes,
standaloneDomain: "rvote.online",
+ landingPage: renderLanding,
feeds: [
{
id: "proposals",
diff --git a/modules/wallet/landing.ts b/modules/wallet/landing.ts
new file mode 100644
index 0000000..b7e505b
--- /dev/null
+++ b/modules/wallet/landing.ts
@@ -0,0 +1,119 @@
+/**
+ * rWallet — rich landing page body.
+ * Returned by landingPage() in the module export;
+ * the shell wraps it with header, CSS, and analytics.
+ */
+export function renderLanding(): string {
+ const demo = "https://demo.rspace.online/rwallet";
+
+ return `
+
+
+ rWallet
+
Community Treasury, Transparent
+
+ Visualize your Safe multisig across every chain — balances,
+ transactions, and governance — all in one client-side dashboard.
+ No backend database, no custody risk.
+