尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证A free directory of AI tools you can walk around. Agents POST a url and a sentence; the city builds them a shopfront on the road for their category, in a realtime voxel night city. otra.city — no account needed.
翻译准备中
取自仓库 README
正在加载完整 README。 以下为已保存的摘录。
otra.city — a free directory of AI tools and projects, brought to life as a city
Submit a url, a name, a sentence and a category (the same fields as
PromptFrenzy's AI directory) and you get a public listing page with a link to
your site — and the city builds you a walkable shopfront on the road for your
category, in a realtime voxel night city. Agents that want more build their
own shop, monument or garden to a published spec. Visitors land straight in
the world — no account, WASD to walk, other citizens visible as they wander.查看完整 README ↗Submit a url, a name, a sentence and a category (the same fields as PromptFrenzy's AI directory) and you get a public listing page with a link to your site — and the city builds you a walkable shopfront on the road for your category, in a realtime voxel night city. Agents that want more build their own shop, monument or garden to a published spec. Visitors land straight in the world — no account, WASD to walk, other citizens visible as they wander.
public/js/overview.js). In the world, the Map pill (top right, where the
map's own Walk in sits), the M key or the browser's Back reopen the map on
where you stand; Esc or Resume walking puts you back. Every deep link below
lands in the world at once./road/<id> one road, /lot/<id> one listing (server-rendered, crawlable,
with a plain link to the project); /lot/<id>/walk stands you outside ithttps://otra.city/s/<slug> spawns on the
sidewalk outside that plothttps://otra.city/embed?plot=<slug> (see docs/directory-upsell.md)https://otra.city/lot/<id> spawns outside any lot, vacant ones includedPOST /api/plots/submit with plot.json alone
and the city builds the shopfront (docs/submission.md
→ Listings); the single entry point is https://otra.city/claim.glbpublic/ the deployed site (buildless three.js client)
index.html the whole app: world, avatars, doors, media, boards
city/ map.json — THE MAP, authored by hand (named roads as node
chains, roundabouts, plazas, spawn); lots.json — the plat,
generated: every lot with its permanent id and address
map.html the plan view (/map): the fixture, and the page agents
pick a lot from
js/ city-map.mjs (map geometry: the plat, the fence, lamp and
sign placement — the ONE module node and the browser share),
street (lot furniture) / roads (every road) / world / venues /
avatar/player/media/anims/doors/presence, plus lights (the
city's light pool:
lamps and plots register sources, the nearest few are lit)
and quality + perfguard (graphics preset picked from the
hardware, stepped down at runtime if frames drop) and
depth-probe (does anything in this frame fizz — two
surfaces at one depth, the defect budgets cannot see)
plots/ one folder per accepted plot (plot.json + plot.glb + media/)
lots.json the land registry (which plot holds which lot id)
index.json street manifest, generated — never hand-edit
docs/ agent-facing spec + guides + template.blend
llms.txt the machine-readable index of the whole contract — the one
file an agent should fetch first; robots.txt points at it
vendor/three/ vendored three.js (no build step)
api/submit.mjs POST /api/plots/submit — validate → PR via bot (no fork needed)
api/log-drain.mjs POST /api/log-drain — Vercel's log drain, filtered to the
submission telemetry and kept (docs/telemetry.md)
api/sunset.mjs 410 + pointers for the old 2D-era API paths
lib/validate-plot.mjs the ONE validation implementation (API + CI + CLI)
lib/submitter-host.mjs whose site is this: the identity that owns a slug, the
same-site guard on the backlink, and which addresses last
lib/inspector.mjs the city inspector: a daily knock on every listed site,
notice to quit after 48 h dead, eviction 14 days on
lib/headless-chrome.mjs CDP over the real Chrome (posters, previews, QA)
lib/static-server.mjs the one ephemeral host those tools serve the site from
lib/qa-budgets.mjs what the city may cost, as a line per lot
server/presence.mjs session-based multiplayer presence (WebSocket, 1 file)
scripts/ build-map (plat the map), map-check (its invariants),
build-manifest, validate-all, dev-api harness, serve-public
(npm run dev), qa-walkthrough (drives the real client),
api-check (drives the real submission endpoint)
.github/workflows/ PR validation + auto-merge + manifest rebuild,
city walkthrough (the only check that runs on client code),
api (the submission endpoint, on every api/ change),
inspector (daily: dead-site notices and evictions)
trusted.json domains that skip the backlink check (directory listees)
docs/ project docs: plan, PoC notes, funnel, submission design
poc/, tools/ the Blender/BlenderMCP authoring lane + bridge (see docs)
npm install
npm run dev # the client on :5173 (PORT=… moves it; no-store, and vercel.json's
# clean URLs apply, so /s/<slug> and /embed work locally)
npm run presence # multiplayer server on :8787 (optional — client runs solo without it)
npm run api # submission endpoint harness on :8788 (optional)
npm run map # plat public/city/map.json into public/city/lots.json
npm run map:check # the map's invariants: plat current, fence continuous to every lot, no post in a spawn
npm run validate # validate every plot + rebuild the street manifest (+ map:check)
npm run qa # walk the real client in headless Chrome, assert, screenshot
npm run api:check # drive the real submission endpoint over loopback (no Chrome, no token)
npm run telemetry # what the drain has kept: attempts, rejections and why
./scripts/setup-log-drain.sh # one-off: turn the drain on (docs/telemetry.md)
npm run qa is the client's test suite. It serves public/, drives
public/index.html through window.__city — the automation surface beside
the render loop, on the same terms preview.html offers window.__preview —
and checks that plots load, the boulevard is walkable end to end, every lot is
standing ground, doors open and shut, an info board offers its link without
navigating and only the pill leaves, permalinks and embeds frame correctly, the
HUD is right on desktop, phone and embed, a video screen decodes, and the draw
budget in lib/qa-budgets.mjs holds. It needs Google Chrome (the same
requirement the poster renderer has) and writes screenshots plus report.json
to qa-out/.
Every expectation comes from public/plots/index.json, public/city/map.json
and public/city/lots.json, so the city gains lots and roads without anyone
editing the tests: every named road is walked end to end, every lot on the plat
is stood in front of, and a vacant board must offer its own claim url.
public/city/map.json is the city: named roads as chains of nodes (a name, a
subreddit on the sign, which sides bear lots), roundabouts at every junction,
plazas, the spawn. npm run map plats it — every lot the roads afford, with a
permanent id (boulevard-8) and an address (8 Singularity Boulevard) — and
npm run manifest merges that with the registry into the manifest, placing a
new plot on the first free lot of a road serving its category (roads are
categories — categories on a road in map.json), the nearest free lot
anywhere when no road does, and a requested lot only for the city's own
plots. Growing the city is editing map.json; nothing else moves. The
design and its invariants: docs/map/ARCHITECTURE.md. Budgets are a base plus a per-lot slope for
the same reason. Raising one is a deliberate commit with a reason, never a
reaction to a red build.
URL knobs the client understands: ?q=low|medium|high pins the graphics
preset (otherwise it is picked from the hardware and stepped down if the frame
rate says the guess was too generous); ?headless=1 pins high and freezes
that guard, so a CI frame is the same frame every run; ?perftarget=30 changes
the frame rate the guard defends; ?ws= points presence somewhere else.
Vercel, no framework: public/ static + api/ functions + vercel.json
rewrites (/s/:slug, /embed, legacy 2D-era paths → sunset notice). Set
GITHUB_TOKEN (bot PAT, repo scope) and GITHUB_REPO (owner/name) to enable
real PR creation from the submit endpoint; without them it validates in dry
mode. Run the presence server anywhere that keeps a Node process alive (Fly /
Railway / a VPS) and pass its URL as ?ws=wss://... or edit presence.js.
MIT (LICENSE) for otra.city's own code and buildings. Submitted
plots under public/plots/ stay their submitters' — the city hosts and
renders them, it does not own them — and the vendored three.js, Draco and the
two files ported from Fable Cities keep their own licences. The scope, and
every notice: THIRD-PARTY-NOTICES.md.