World Vibe Web
The distributed app store for vibe-coded projects. Browse, discover, and install open-source apps from across GitHub.
翻譯準備中
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 README。 以下為已儲存的摘錄。
A B2B catalogue of everything the Forge founder brands sell. Company buyers (HR,
admin, procurement) browse it, shortlist products with rough quantities, and
send a request with just their name, company, work email and phone. There are no accounts
and no checkout. Each request lands in a Google Sheet, and the Mesa team calls back.
With SHEETS_WEBHOOK_URL empty, submitted requests go to .data/requests.jsonl,
so you can test the whole flow without touching the sheet.檢視完整 README ↗A B2B catalogue of everything the Forge founder brands sell. Company buyers (HR, admin, procurement) browse it, shortlist products with rough quantities, and send a request with just their name, company, work email and phone. There are no accounts and no checkout. Each request lands in a Google Sheet, and the Mesa team calls back.
POS Postgres ──(read-only, every 10 min)──► Next.js site ──POST /api/request──► Apps Script ──► Google Sheet
│ ▲ (Requests + Items)
└──(npm run catalog:sync)──► data/catalog.json (fallback if the POS is unreachable)
npm install
cp .env.example .env.local # fill POS_DATABASE_URL to be able to re-sync
npm run dev # http://localhost:3000
With SHEETS_WEBHOOK_URL empty, submitted requests go to .data/requests.jsonl,
so you can test the whole flow without touching the sheet.
Nothing to do. The site reads the POS directly (inside a READ ONLY
transaction) and refreshes every 10 minutes. When a team adds a product,
changes a price or photo, sets up sizes/flavours, uploads their logo, or archives
something, buyers see it within 10 minutes, with no sync and no redeploy.
data/brands.json.GET /api/catalog-status shows when the catalogue was last read and how many products it has.npm run catalog:sync refreshes data/catalog.json, the snapshot the site falls
back on if the POS database can't be reached. Run it now and then and commit it.
POS_DATABASE_URL uses a read-only login, mesa_b2b_reader (created 2026-10-01). It can
SELECT the five catalogue tables and nothing else. On Team it sees only id, code, logoUrl
and isActive, never student names. Every session it opens is read-only, with a 20-second statement
limit. It has BYPASSRLS because Supabase switches row-level security on for those tables; the
grants above are what fence it in. On the Supabase pooler, the username is
mesa_b2b_reader.<project-ref>. This is what was run:
create role mesa_b2b_reader login password '<secret>' bypassrls noinherit connection limit 10;
alter role mesa_b2b_reader set default_transaction_read_only = on;
alter role mesa_b2b_reader set statement_timeout = '20s';
grant usage on schema public to mesa_b2b_reader;
grant select ("id", "code", "logoUrl", "isActive") on public."Team" to mesa_b2b_reader;
grant select on public."Product", public."ProductImage", public."ProductVariantGroup", public."ProductVariantOption" to mesa_b2b_reader;
If the POS adds a column this site needs from Team, grant it here too. To revoke access entirely:
drop role mesa_b2b_reader;
What gets shown is controlled by two hand-edited files:
| File | What it controls |
|---|---|
data/brands.json | Maps team code → brand name, tagline, default collection, website and Instagram. A team missing from here is left off the site. |
data/curation.json | hide: brand + title pattern, each with a reason. This keeps things that aren't workplace-appropriate off a corporate catalogue (alcohol/tobacco branding, drug references, profanity), plus test and internal-discount items. collectionRules: files products under a different shelf than their brand's default (cookies from a cocoa brand go to Sweet Treats; anything called a hamper, combo or pack goes to Gift Hampers). featured: pins products to the home page. |
The build also tidies what the POS gives it, because the POS is shaped for a till rather than a shop:
npm run catalog:sync prints exactly what was hidden and merged, and why.
Photos come straight from the POS's public Supabase bucket (POS_MEDIA_BASE_URL), not
through the POS API. The API limits each network to 600 requests a minute, and the tills share
that allowance, so buyers browsing photos must never use it up. Photos are resized by next/image
and shown whole, never cropped: src/components/fit-image.tsx places each photo inside its frame
over a blurred copy of itself, so 9:16 phone shots and 16:9 banners both sit cleanly in square tiles.
apps-script/Code.gs.WEBHOOK_SECRET with a long random value
(openssl rand -hex 24)./exec URL..env.local (and later in the hosting env), set SHEETS_WEBHOOK_URL to that URL
and SHEETS_WEBHOOK_SECRET to the same secret.If you edit Code.gs, re-deploy it (Manage deployments → Edit → New version), or the
old code keeps running.
npm run dev | Dev server |
npm run build / npm start | Production build (all product and brand pages are prerendered) |
npm run check | Typecheck + lint |
npm run format | Prettier |
npm run catalog:sync | Refresh the fallback snapshot from the POS |
The pitch comes first. The site argues before it sells: every gift here is someone's
first company. Founders' faces and names are everywhere a product is (portraits are the
cohort's own cut-outs, copied from the leaderboard into public/founders/, with
data/founders.json holding names and the leaderboard's line-up order). Live revenue and
reels come from the BYOB master's published feeds (src/lib/impact.ts, src/lib/reels.ts).
Look. Warm paper and aubergine ink, inside the Mesa Forge palette: Royal Purple for
type, Orchid for marks, Vivid Violet only where you act. Fraunces (with its SOFT and WONK
axes) is the voice; Manrope (Mesa's typeface) is the interface. The Mesa lockup in
public/brand/ is the official artwork, unmodified; phones show only the "m" tile.
Drawings. Every icon is from one hand-drawn set in src/components/doodles.tsx: ink
outlines over an off-register colour shape, on one 96-unit grid with one stroke weight.
<Doodle> (src/components/doodle.tsx) draws them in on first view and redraws on hover.
To add one, add an entry to DOODLES; to change a category's drawing, change its icon
in src/lib/catalog-types.ts.
Motion. GSAP (ScrollTrigger, SplitText, Draggable, MotionPath, DrawSVG) with Lenis for
smooth scrolling. Everything stands down for prefers-reduced-motion, touch screens keep
native scrolling, and anything hidden until animated shows itself after 2.5s if scripts
never run (.js-reveal in globals.css). Scroll triggers never use once: true: it broke the
home page in Safari on phones (why, in src/components/motion/gsap.ts).
Gift list. One flow in one place (src/components/request/gift-list-flow.tsx): the
list, then "Who's gifting?", then sent, sliding in place with nothing shown twice. Phones
get a quick-commerce bar at the bottom that added photos fly into and that opens the list
as a bottom sheet (drag it down to close); wider screens get the header pill and a panel
from the right (gift-list-sheet.tsx). /request renders the same flow as a page, which
is where shared list links land.
Copy. Quick-commerce voice: short, warm, a bit cheeky. No em dashes anywhere,
including product titles from the POS, which the catalogue build rewrites
("Aroma Oil · Cinnamon"). No small all-caps labels above headings. Curly apostrophes (’), and
a number never ends a line apart from its noun (a non-breaking space: 37 brands).
Names come from the BYOB master (Team Links / the leaderboard feed), written with every
word capitalised (src/lib/venture-name.ts). When a team renames its brand, change name
and slug in data/brands.json and keep the old slug in aliases: old links redirect,
and gift lists saved or shared under the old name keep working. Renamed so far: BizFits →
Pehchaan, NUTflix → Savore, WeKrave Healthy → WeKrave.