Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
7d66c9a
Add the Stoa spaces design and the spaces core plan
guohai Oct 7, 2026
805c68f
Add spaces state, actor lookup, and space entitlements
guohai Oct 7, 2026
88db2b3
Add shared map parsing and pathfinding
guohai Oct 7, 2026
d17255d
Add the plaza and room worlds
guohai Oct 7, 2026
b85fa2f
Add space permissions
guohai Oct 7, 2026
a162cfa
Add the space model
guohai Oct 7, 2026
6f3825b
Fix array instance sharing in systemSpaces
guohai Oct 7, 2026
54b0acb
Add entry leases, capacity, and hosting
guohai Oct 7, 2026
3c0d73b
Add decoration validation
guohai Oct 7, 2026
3224218
Add Signaling channel names, space keys, and tokens
guohai Oct 7, 2026
03a6719
Issue RTC tokens for spaces
guohai Oct 7, 2026
970ccba
Add the spaces service
guohai Oct 7, 2026
a700eba
Hide private spaces consistently and evict on privacy change
guohai Oct 7, 2026
6c2d747
Serve the spaces API and Stoa pages
guohai Oct 7, 2026
5cb35ae
Fix review findings: rotate channel on access eviction, idle sweep, l…
guohai Oct 7, 2026
d324913
Record follow-ups for later Stoa plans
guohai Oct 7, 2026
dfa5091
Add the world engine and themes plan
guohai Oct 7, 2026
649e6eb
Share decoration kinds and keep the map's ground layer
guohai Oct 7, 2026
fa22d50
Add the data-only theme contract
guohai Oct 7, 2026
84d7f2e
Reject unknown fields in theme validation and use Number.isFinite
guohai Oct 7, 2026
5b491aa
Add the Agora, Minimal, and Cyberpunk themes
guohai Oct 7, 2026
76028cd
Add camera and walking motion
guohai Oct 7, 2026
4c4fd33
Add the Canvas world renderer
guohai Oct 7, 2026
17fe175
Add the world engine: movement, input, camera, and drawing loop
guohai Oct 7, 2026
4f8d520
Fix engine review findings: destroy, wall clock, mid-walk redirect, i…
guohai Oct 7, 2026
7bc9315
Open the walkable plaza page
guohai Oct 7, 2026
b36cf81
Frame the plaza: wider camera, bounds, and review fixes
guohai Oct 7, 2026
0210721
Fix final review findings: idle redraw, draw cost, resilient room pan…
guohai Oct 7, 2026
41c5c31
Record follow-ups for Plan C
guohai Oct 7, 2026
2169dcd
Add the Stoa live plan and cap the plaza at 200 in the spec
guohai Oct 8, 2026
0521cba
Serve the Signaling SDK and link the Stoa from every page
guohai Oct 8, 2026
9b45586
Add the live Stoa protocol
guohai Oct 8, 2026
c424f78
Encrypt payloads for unlisted and private spaces
guohai Oct 8, 2026
f88ccfc
Share keyboard walks as walk and stop, and add teleport, input contro…
guohai Oct 8, 2026
727307f
Close a code block in the Stoa live plan
guohai Oct 8, 2026
321beb7
Add the Signaling client with encrypted channels and normalized presence
guohai Oct 8, 2026
b6abceb
Track other people on a channel with the receiver rules
guohai Oct 8, 2026
3b6aa18
Wire one channel's presence and movement, and keep entry leases alive
guohai Oct 8, 2026
a50f7fb
Settle peers on the arrival tile, ignore stopped heartbeats, and leav…
guohai Oct 8, 2026
4669897
Open the live Stoa: shared plaza, lot rooms, user spaces, and messages
guohai Oct 8, 2026
9c98f1c
Serialize Stoa transitions, watch a full plaza quietly, and fix statu…
guohai Oct 8, 2026
0deac7d
Run Stoa transitions through one queue
guohai Oct 8, 2026
29636ee
Fix Stoa door arrival to use the queued enter and leave
guohai Oct 8, 2026
fc81c9d
Cap the plaza at 200 people
guohai Oct 8, 2026
0e240f9
Revert plan document to historical state
guohai Oct 8, 2026
ccfaa26
Fix final review findings for Stoa live
guohai Oct 8, 2026
1bce889
Record follow-ups for the Stoa live plan
guohai Oct 8, 2026
25dd4e1
Keep drawing people who walk in from off-screen
guohai Oct 8, 2026
1bcc6a3
Record the live Signaling check
guohai Oct 8, 2026
7c52c62
Plan Stoa rooms: calls, decorating, host tools, your spaces
guohai Oct 8, 2026
1edd2fd
Add decor and rekey notices, on-demand heartbeats, and engine draw an…
guohai Oct 8, 2026
38eedd4
Add a UI-free Agora RTC client for room calls
guohai Oct 8, 2026
3901898
Harden RTC client leave and share races
guohai Oct 8, 2026
ba6c5a7
Report screen-share join failures
guohai Oct 8, 2026
cb4d595
List your spaces and give owners member names
guohai Oct 8, 2026
9e5b3dd
Add calls inside Stoa rooms with theme-chosen video layouts
guohai Oct 8, 2026
640ec5f
Polish Stoa call controls and tiles
guohai Oct 8, 2026
0497b31
Keep strip tiles full size and guard late call resets
guohai Oct 8, 2026
8bd6844
Add decorate mode for room hosts
guohai Oct 8, 2026
bc23916
Tighten decor mode rules and lifecycle
guohai Oct 8, 2026
29bbf1a
Take the host from room refreshes too
guohai Oct 8, 2026
265ac61
Let hosts hand over hosting and remove people
guohai Oct 8, 2026
8ffa3f6
Match removal wording to the room and tidy host tools
guohai Oct 8, 2026
e7172e3
Create, invite to, and manage your own Stoa spaces
guohai Oct 8, 2026
fdf98a9
Keep the space view in step with its settings
guohai Oct 8, 2026
b8c46fe
Retire the meetings page in favour of Stoa spaces
guohai Oct 8, 2026
b98726f
Say spaces in the sign-out notice
guohai Oct 8, 2026
8d22a7f
Close the Stoa rooms review: rekeys, reachable tiles, fresh access
guohai Oct 8, 2026
84d5c5a
Check in at once after tightening a space's access
guohai Oct 8, 2026
51416dc
Keep held-back heartbeats instead of dropping them
guohai Oct 8, 2026
ef90f97
Record the live Stoa rooms check
guohai Oct 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,11 @@ MODEL_REQUESTS_PER_HOUR=60
AGORA_APP_ID=
AGORA_APP_CERTIFICATE=
AGORA_TOKEN_TTL_SECONDS=3600
# Agora Signaling (RTM 2.x) carries movement, presence and live messages, using AGORA_APP_ID and AGORA_APP_CERTIFICATE.
# Enable Signaling for the project in Agora Console.
# At least 32 random characters. Derives private channel names and per-space keys; keep it secret and stable.
SPACE_CHANNEL_SECRET=
# Set to true only after Agora enables per-channel Signaling permissions for this project.
AGORA_RTM_PERMISSIONS=false
# Comma-separated portal account IDs (account:<uuid>) with platform admin rights in spaces.
PLATFORM_ADMINS=
26 changes: 17 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Without `DATABASE_URL`, state is stored in `/app/.data`. Mount a volume there so
- `index.html` / `people.js`: people discovery, skills, natural-language search, and public profiles.
- `activity.js` / `scripts/activity.mjs`: public GitHub events and actual community actions, with timestamps and source links.
- `explore.html` / `explore.js`: 16 verified GitHub projects, categories, search, and sorting.
- `meetings.html` / `meetings.js` / `call.js`: shared group rooms, invite links, member rosters, and embedded Agora audio/video calls.
- `stoa.html` / `stoa.js` / `stoa/` / `world/`: the Stoa — a walkable plaza with first-come rooms and your own spaces, live presence and messages over Agora Signaling, and calls over Agora RTC.
- `radar.html` / `radar.js`: intent-driven web research with source links and reasons.
- `services.html` / `services.js`: language-model and text-to-speech playgrounds, plus verified offers.
- `account.html` / `account.js`: shared identity, credits, membership plans, purchases, and Agora Console connections.
Expand All @@ -53,11 +53,11 @@ Shared navigation, dialogs, sign-in, and browser sessions live in `script.js`; s

The homepage polls `/api/activity` every minute while visible. The server reads public Agora-Build GitHub events at most once every two minutes, shares concurrent requests, uses ETags, and backs off on rate limits. The feed includes real pushes, pull requests, issues, and releases from repositories in the project directory. GitHub can delay event delivery; timestamps show when actions happened, not when they were fetched. `data/activity.json` is a dated GitHub snapshot used when live sync is unavailable, with that state labeled explicitly.

Joining the foundry, changing an intent, creating a room, and joining a room roster also produce public activity entries. Repeated roster joins do not create new entries. Profile removal clears the member's activity and references to their deleted rooms. Activity indicates public work and participation in the directory; it does not imply that someone is online or currently on a call.
Joining the foundry and changing an intent also produce public activity entries. Activity from legacy meeting rooms may remain in the feed. Profile removal clears the member's activity and references to their deleted rooms. Activity indicates public work and participation in the directory; it does not imply that someone is online or currently on a call.

## Profiles and ownership

Joining requires a name, bio, skills, a public contact link, and a real intent. Profiles and meeting rosters are public. Sign-in creates a private account first; nothing is published until the person supplies their intent and saves a profile. Returning to the same provider identity on another device restores the same profile, room ownership, and private radar.
Joining requires a name, bio, skills, a public contact link, and a real intent. Profiles are public. Sign-in creates a private account first; nothing is published until the person supplies their intent and saves a profile. Returning to the same provider identity on another device restores the same profile, room ownership, and private radar.

The sign-in dialog supports Google and GitHub OAuth, Sign in with Apple, and a configurable Agora OIDC identity service. Members can explicitly connect another provider to the same account. An existing browser-only profile can connect a login while preserving its ID and rooms; its old browser token is then invalidated. Accounts are never merged by email. Provider subjects and session hashes stay private. Account sessions last 30 days and logout revokes the current session. Removing a public profile also removes its radar and owned rooms, while the private login account remains available to start a new profile.

Expand Down Expand Up @@ -99,22 +99,30 @@ Shared inference is limited to six calls per minute per client IP and `MODEL_REQ

## Agora group calls

Create an Agora project with App Certificate authentication enabled. Set `AGORA_APP_ID` and `AGORA_APP_CERTIFICATE` in the server's `.env` and restart. Both must be 32-character hexadecimal values. The certificate stays on the server; authenticated room members receive short-lived, channel-specific AccessToken2 credentials from `POST /api/rooms/:id/call`. `AGORA_TOKEN_TTL_SECONDS` defaults to 3600 and is bounded to 60–3600 seconds. The SDK renews credentials before they expire; renewals require the same browser profile and current room membership.
Create an Agora project with App Certificate authentication enabled. Set `AGORA_APP_ID` and `AGORA_APP_CERTIFICATE` in the server's `.env` and restart. Both must be 32-character hexadecimal values. The certificate stays on the server; signed-in people receive short-lived, channel-specific AccessToken2 credentials from `POST /api/spaces/<id>/rtc-token`, and only while they are currently in that room. `AGORA_TOKEN_TTL_SECONDS` defaults to 3600 and is bounded to 60–3600 seconds. The SDK renews credentials before they expire; renewals require the same browser profile and current presence in the room.

Every room has a purpose and a permanent shareable URL, `/meet/<room-id>`. Room creation returns that path and opens the room; its card displays the full invite URL and a copy action. A direct link opens that room, preserves the invitation through login, and lets new members complete their real-intent profile before joining. Existing `meetings.html?room=<id>` invitations remain supported.
Calls happen inside the Stoa's lot rooms and your own spaces. Video layouts follow the theme: over avatars (Agora), a strip (Cyberpunk), or a grid (Minimal). Members choose whether to enable devices, toggle microphone/camera, share a screen, and leave the call. Screen sharing uses a separate Agora publisher so it can run alongside the camera; browser support determines whether screen audio is available. Camera, microphone, and screen tracks close on leave and page exit. Separate tabs get distinct media identities.

Members join audio/video inside Agora.Build, choose whether to enable devices, toggle microphone/camera, share a screen, and leave the call. Screen sharing uses a separate Agora publisher so it can run alongside the camera; browser support determines whether screen audio is available. Camera, microphone, and screen tracks close on leave and page exit. Separate tabs get distinct media identities. The participant count inside a call comes from actual Agora peers; the directory roster refreshes every 15 seconds and is not live call attendance.
Old `/meet/<id>` links and `/meetings.html?room=<id>` redirect to `/stoa/s/<id>`, where legacy rooms now live as spaces with the same ids. The `/api/rooms` routes answer `410 Gone`.

Use HTTPS for remote callers, or `http://localhost:3002` for local development. Browsers restrict media devices on plain remote HTTP. No Agora credentials are bundled in the site. Without valid configuration, rooms and invites remain available and calls show an unavailable state. Existing room IDs and rosters continue working, and old external call URLs are omitted from API responses. Removing a profile or room blocks new tokens and renewal; an already-issued Agora token remains valid until its short expiration.
Use HTTPS for remote callers, or `http://localhost:3002` for local development. Browsers restrict media devices on plain remote HTTP. No Agora credentials are bundled in the site. Without valid configuration, rooms stay usable and calls show an unavailable state. Leaving a room or removing a profile blocks new tokens and renewal; an already-issued Agora token remains valid until its short expiration.

## Stoa spaces

The Stoa is a walkable plaza (`/stoa/`) with first-come rooms (`/stoa/room/<slug>`) and unlisted or private spaces (`/stoa/s/<id>`). Calls use Agora RTC; movement, presence, and live messages use Agora Signaling. Enable Signaling for the Agora project and set `SPACE_CHANNEL_SECRET` to at least 32 random characters. The built-in maps in `worlds/` are generated by `npm run maps`.

Built-in themes live in `themes/` (Agora, Minimal, Cyberpunk) and are validated at startup. Hosts can hand over hosting, remove people from the room, and decorate it. Signed-in people can start their own spaces (`/stoa/?start=<title>` opens the dialog with a title filled in), invite others with links, manage members, change settings, and delete a space. Free accounts can own up to 3 spaces; premium plans can own up to 20.

Visitors can switch their own view to Minimal; `/stoa/?theme=cyberpunk` previews a theme. Movement works with click or tap and with the arrow keys or WASD; the side panel offers the same actions for keyboard and screen reader users.

## The physical forge

Demo days, hackathons, and whiteboard sessions are core community activities. The homepage offers a session-planning entry point for each. Create a room with your real intent, include a place and time in the session purpose, and share the invite with collaborators. Use the same workspace to prepare online and reconnect after meeting in person. These are planning tools; the site does not advertise invented events, venues, or attendees.
Demo days, hackathons, and whiteboard sessions are core community activities. The homepage offers a session-planning entry point for each. Start a space in the Stoa with your real intent, include a place and time in the session purpose, and share the invite with collaborators. Use the same workspace to prepare online and reconnect after meeting in person. These are planning tools; the site does not advertise invented events, venues, or attendees.

## Community offers

`data/offers.json` starts empty. Add only confirmed offers with `provider`, `title`, `description`, `url`, optional `eligibility`, and optional ISO `expiresAt`. Expired offers are hidden. No discounts are implied before a partnership is confirmed.

## Verification

`npm test` uses the Node test runner with isolated temporary data and mocked providers. It covers public-file restrictions, profiles and ownership, cross-device sign-in, OAuth state/PKCE/JWT verification, Apple's POST callback, safe account linking, session expiry and logout, direct meeting URLs, persistence, search, sourced research, service limits, Agora token signatures/renewal, provider migration, activity caching/deletion, and production output. For UI changes, check all pages on desktop and mobile, keyboard navigation, reduced motion, dialogs, empty states, filters, sourced activity, provider availability, and two browser sessions joining one room. With configured provider registrations, verify live logins and Agora media, token renewal, and device release on leave.
`npm test` uses the Node test runner with isolated temporary data and mocked providers. It covers public-file restrictions, profiles and ownership, cross-device sign-in, OAuth state/PKCE/JWT verification, Apple's POST callback, safe account linking, session expiry and logout, old meeting-link redirects, persistence, search, sourced research, service limits, Agora token signatures/renewal, provider migration, activity caching/deletion, and production output. For UI changes, check all pages on desktop and mobile, keyboard navigation, reduced motion, dialogs, empty states, filters, sourced activity, provider availability, and two browser sessions entering one room. With configured provider registrations, verify live logins and Agora media, token renewal, and device release on leave.
7 changes: 1 addition & 6 deletions account.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<div class="workspace">
<header class="site-header">
<a class="wordmark" href="/index.html" aria-label="Agora Build home"><span class="brand-symbol" aria-hidden="true">b_</span><span>agora<span class="brand-dot">.</span>build<small>THE BUILDER'S FOUNDRY</small></span></a>
<nav id="site-nav" class="site-nav" aria-label="Main navigation"><a href="/index.html">The floor</a><a href="/explore.html">Projects</a><a href="/meetings.html">Rooms</a><a href="/radar.html">Radar</a><a href="/services.html">Services</a><a href="/account.html" class="is-active" aria-current="page">Account</a><a class="nav-github" href="https://github.com/Agora-Build" target="_blank" rel="noopener noreferrer">GitHub <span aria-hidden="true">&#8599;</span></a></nav>
<nav id="site-nav" class="site-nav" aria-label="Main navigation"><a href="/index.html">The floor</a><a href="/explore.html">Projects</a><a href="/stoa/">Stoa</a><a href="/radar.html">Radar</a><a href="/services.html">Services</a><a href="/account.html" class="is-active" aria-current="page">Account</a><a class="nav-github" href="https://github.com/Agora-Build" target="_blank" rel="noopener noreferrer">GitHub <span aria-hidden="true">&#8599;</span></a></nav>
<div class="header-actions"><button class="button button-small" type="button" data-join data-guest-label="Take a seat" data-member-label="Your profile">Take a seat <span aria-hidden="true">+</span></button><button type="button" class="nav-toggle" aria-controls="site-nav" aria-expanded="false" aria-label="Toggle navigation"><span></span><span></span></button></div>
</header>
<main id="main" class="main-content account-page">
Expand Down Expand Up @@ -49,11 +49,6 @@ <h2 id="join-title">Pull up a chair.</h2>
</form>
</dialog>
<dialog id="person-dialog" aria-labelledby="person-title"><div class="dialog-head"><span class="kicker">BUILDER PROFILE</span><button class="close-button" type="button" data-close aria-label="Close builder profile">&times;</button></div><div id="profile-content"></div></dialog>
<dialog id="room-dialog" aria-labelledby="room-title">
<div class="dialog-head"><span class="kicker">MAKE ROOM FOR A CONVERSATION</span><button class="close-button" type="button" data-close aria-label="Close room form">&times;</button></div>
<h2 id="room-title">Meet around a purpose.</h2><p class="dialog-intro">Create a group room, share the invite, and open a video call together.</p>
<form id="room-form" class="stack-form"><label>Room name<input name="title" required minlength="2" maxlength="80" placeholder="Voice agents build session"></label><label>What are we meeting for?<textarea name="intent" required minlength="2" maxlength="300" rows="3" placeholder="Debug a problem, plan a demo day, or bring a whiteboard session into the next sprint."></textarea></label><p class="form-note">Room names, purposes, and rosters are public. Audio, video, and screen sharing stay in this workspace, powered by Agora.</p><p id="room-error" class="form-error" role="alert"></p><button type="submit" class="button">Create meeting room <span aria-hidden="true">&#8599;</span></button></form>
</dialog>
<div id="toast" role="status" aria-live="polite"></div>
</body>
</html>
Loading
Loading