BeamNG.Earth
BeamNG.drive용 1:1 비율 실시간 지구, 실제 고도·위성 이미지·부동 원점·보조 서버에서 LOD 스트리밍
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기An immersive 1920s Prohibition-era Halloween masquerade mystery, archive terminal, RSVP ledger, and pre-event CTF.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
The Black Veil is an immersive historical-fiction invitation and archive for a real All Hallows’ Eve event. The public story is set in Manchester, New Hampshire, from 1921 to 1926, with fictional proprietor Cassandra “Cassie” Castello at the center of an unresolved 1924 disappearance.
The club, Cassandra, its alleged crimes, and all witness accounts are fictional. Manchester, Prohibition, the Amoskeag industrial setting, the Merrimack River, Elm Street, and the 1922 strike provide documented historical context. Every archive record carries provenance metadata that distinguishes those layers.README 전문 보기 ↗The Black Veil is an immersive historical-fiction invitation and archive for a real masquerade on October 23, 2026. The public story is set in Manchester, New Hampshire, from 1921 to 1926, with fictional proprietor Cassandra “Cassie” Castello at the center of an unresolved 1924 disappearance.
The club, Cassandra, its alleged crimes, and all witness accounts are fictional. Manchester, Prohibition, the Amoskeag industrial setting, the Merrimack River, Elm Street, and the 1922 strike provide documented historical context. Every archive record carries provenance metadata that distinguishes those layers.
npm install
npm run dev
Open http://localhost:3000.
Quality checks:
npm run lint
npm run typecheck
npm run build
/ — 1926 invitation entry and the early Cassandra newspaper hook/archive — archive drawers organized by year, 1921–1926/archive/[slug] — full-size physical artifact view with prior/next record navigation/guest-ledger — real-name RSVP, persisted to Postgres and signed in for this device/invitation — private invitation revealed after archive access and RSVP/game — the guest's night: three-tab character card ("Characters coming very soon" until the host presses Start game), objectives, final answers, results. See docs/game/README.md/black-frog — the seven-trial CTF (server-verified flags) and in-person point claims/postscript — the unlisted bonus flag (footer link once the register is unsealed; the flag is in the unlocked terminal ledger)/bench/[ticket] — one restoration bench: a graded engineering exercise (RST-01 … RST-12)/resume — request a magic-link sign-in to restore your register on a new device/admin — staff-only, passcode-gated cast page: who is coming, their character, sign in as them, and the one Start game button that releases every card and objective (linked from the footer)src/data/archive.ts defines typed newspaper pages, clippings, photographs, police documents, telegrams, notices, invitations, images, catalog numbers, and provenance. Real images and articles carry a sourceUrl, which surfaces on the record page as a "Learn more about this record" link; fictional artifacts do not show a provenance panel.
Important newspaper copy is deterministic HTML/CSS rather than text baked into generated images. This keeps headlines readable at full size while preserving a scanned-newspaper appearance. Photographs can be inspected in a native dialog.
public/archive/fictional/cassandra-castello-portrait.png — canonical Cassandra portrait; a privately supplied photograph, not AI-generatedpublic/archive/fictional/cassandra-society-cigarette-holder.png — society portrait using the same canonical likenesspublic/archive/fictional/cassandra-arrival-by-carriage.png — Cassandra's carriage arrival before the society desk's cameraspublic/archive/fictional/cassandra-masquerade-evidence.png — fictional 1924 masquerade evidence photograph using the same likenesspublic/archive/fictional/black-veil-passage.png — fictional Manchester mill-passage photographpublic/archive/real/elm-street-manchester-c1908.jpg — Library of Congress, Detroit Publishing Company Collection; no known restrictionspublic/archive/real/amoskeag-strike-picket-1922.jpg — Manchester Historic Association image, public domain in the United States, accessed via Wikimedia CommonsGenerated images are never described as authentic historical photographs. The real Elm Street image is explicitly captioned as context and not as a depiction of The Black Veil.
The original archive-to-terminal-to-ledger flow is preserved. The 1926 invitation record contains a hidden seal that opens the simulated archival terminal; solving it unlocks the real-name RSVP, private invitation, and Black Frog trials. The terminal is client-side fiction and never executes commands on the visitor’s device.
RSVPs use a guest’s real name and do not assign a fictional character. src/lib/rsvp-service.ts defines the persistence boundary. remoteRsvpService (used by GuestLedger) POSTs to /api/rsvp, which upserts a guests row by email, writes to rsvps, and signs the visitor's device in (see "Guest accounts and resuming" below). localRsvpService remains for local development without a database connection. Submissions are also mirrored to localStorage purely so the visitor's device can render "you already RSVP'd" without a login step; the database, not localStorage, is the source of truth.
Black Frog flags are checked server-side in POST /api/ctf/submit against src/data/ctf-flags.ts, a module never imported by client code — only src/lib/ctf-scoring.ts and the intentionally source-revealing /secret page (challenge VII) import it. src/data/ctf.ts holds public challenge copy (title, briefing, clue, points) with no flag field, safe for "use client" components. Each solve is written to ctf_solves, keyed by guest, so a correct flag can never be re-derived by reading client JS.
Not advertised for launch: while eventConfig.benchPromoted is false (src/config/event.ts) there is no footer link, no link from the trials, and no conservation slips in the newspapers. /bench still answers if typed.
/black-frog carries two tracks. The Manchester trials (I–VII) are the original in-world puzzles, answered with a VEIL{…} flag. The Restoration Bench (RST-01 … RST-12) is an engineering track: twelve labs where the flag is a receipt for work the server actually checked, not a string to be guessed.
The fiction is the present-day team digitising the archive. Every newspaper record carries exactly one conservation slip in its right-hand column, naming the ticket open against that paper — src/components/newspaper-artifact.tsx renders it from getBenchLabForRecord(record.slug), so the slip and the lab can never drift apart.
Each lab is one of three shapes, or a combination: a console (RST-01 replays a real-ish git history; RST-08 drives a deliberately vulnerable vault sandbox), files to edit (a Dockerfile, a pipeline config, an IAM policy, SQL, a conflicted register), and findings to report (error-budget arithmetic, review line numbers, characterization values).
The split of responsibility mirrors the trials:
src/data/bench.ts — public copy, starting material, and the published datasets. Client-safe; contains no answers. Deliberately broken starting files live here.src/lib/bench/graders.ts — server-only. Every expected answer is here or derived here from the published data. Graders return named checks, so a rejected submission reads like a build log.src/lib/bench/git-repo.ts, src/lib/bench/vault-sandbox.ts — server-only console fixtures. The register entry RST-01 asks for, and the record RST-08 asks for, exist only here, so they can only be reached by running commands.src/data/bench-flags.ts — server-only receipts, issued after the checks pass.POST /api/bench/[ticket] — action: "run" replays a console history; action: "submit" grades and, on a pass, writes the solve to ctf_solves under bench-<lab id>.RST-10 executes guest-written SQL. It runs in an ephemeral in-memory PGlite instance created and discarded per request, seeded from ledgerSchemaSql, never against DATABASE_URL; submissions are limited to a single read-only statement with a statement timeout. PGlite is listed in serverExternalPackages (next.config.ts) because its wasm files do not survive bundling.
Both tracks score into the same ctf_solves table and the same totalScore in GET /api/me.
npm run bench:check
scripts/bench-selftest.ts works all twelve labs correctly and then submits all twelve untouched, asserting that the first passes and the second fails. Run it after touching any lab's starting material or grader.
A guest's identity is a guests row keyed by email, created on first RSVP. Saving an RSVP signs that device in with an httpOnly session cookie (src/lib/auth/session.ts, HMAC-signed, no session table). To resume on a different device — or after clearing storage — a guest visits /resume, enters their email, and gets a one-time sign-in link (src/lib/auth/magic-link.ts, POST /api/auth/request-link → GET /api/auth/verify). Clicking it sets the session cookie and lands on /resume/restored, which calls GET /api/me and rehydrates the localStorage mirrors the rest of the UI already reads (RSVP, CTF progress), then redirects into /guest-ledger.
Sign-in links are emailed via Resend if RESEND_API_KEY is set (src/lib/email.ts); without it, the link is logged to the server console — fine for local development, not for production.
Sealed for launch: while eventConfig.charactersReleased is false, GET /api/me never returns a character (whatever guests.characterId holds), the Guest Ledger shows a compact "Sealed" strip, and POST /api/admin/characters refuses assign with a 409. Flip it and redeploy to release the cast.
guests.characterId links a guest to a row in characters (public profile + private dossier fields, per the shapes src/features/game/models.ts already sketched). Once assigned, GET /api/me returns the public fields (characterName, occupation, publicBiography, factions) and, because that route only ever answers for the signed-in guest, their own dossier (privateBiography, secrets, objectives). CharacterCard shows both on /guest-ledger, with the dossier behind a seal. Murderer/victim flags never leave the server except to /admin. Character content is authored as part of the game design (docs/mystery/) and entered into the characters table with npm run db:studio or the /admin Database panel. Staff deal or cast characters from /admin (see below).
Digital flags self-score, but not everything can be auto-checked — an in-person objective, a piece of roleplay. POST /api/claims lets a signed-in guest submit a claim (label + optional note); it stays pending until a staff member reviews it at /admin, gated by a shared ADMIN_SECRET passphrase (no per-staff accounts). Approving sets the points awarded; GET /api/me sums approved claim points into totalScore alongside the CTF score, which ChallengeStandings displays.
The same passphrase opens the rest of the Staff Office at /admin. GET /api/admin/overview feeds headline counts, solves per challenge, every guest, and the cast. POST /api/admin/characters with action: "assign" deals each attending guest without a character a random unheld one; "clear" takes them all back. Casting a specific guest to a specific character is done in the Database panel. POST /api/admin/impersonate signs the staff browser in as any guest, as their magic link would, so staff can see the site as that guest does. The Database panel edits or deletes any guest, RSVP, character, claim or solve (GET/POST /api/admin/db, with a whitelist of editable fields per table). The unlock form calls GET /api/admin/session, which reports a wrong passphrase, a missing ADMIN_SECRET, and an unreachable database as three different errors.
.env.example to .env.local and fill in DATABASE_URL (Supabase's pooled "Transaction" connection string for serverless/Next.js), SESSION_SECRET (openssl rand -hex 32), and ADMIN_SECRET. RESEND_API_KEY/EMAIL_FROM are optional (see above).npm run db:migrate to apply the migrations in drizzle/ (creates rsvps, guests, magic_links, characters, ctf_solves, point_claims). Bench solves reuse ctf_solves, so no additional migration is needed for them.npm run db:generate regenerates migrations after schema changes in src/lib/db/schema.ts; npm run db:studio opens Drizzle Studio against the configured database — also how character content gets entered for now.DATABASE_URL, SESSION_SECRET, and ADMIN_SECRET in the host's environment (for every environment that serves the site, preview builds included — .env.local is not deployed), and run step 3 against that database before the first RSVP. Skipping either leaves POST /api/rsvp returning a 503 and the register refusing names.GET /api/standings ranks every guest by the same score as GET /api/me (solves plus approved claims) for the Guest Ledger leaderboard. It is signed-in only; other guests appear by first name and initial. The leaderboard and the /admin dashboard poll every five seconds, so flags submitted anywhere show up on open screens without a reload.
The model supports a primary 1926 murder and an optional advanced investigation into Cassandra and the 1924 masquerade without choosing how those mysteries connect.
The party game (the old man, Cassie, the five survivors, the Butler's vial) is specified in docs/game/ and implemented under src/data/game (the bible, server-only), src/lib/game (grading, scoring, services, tests) and src/app/api/game / src/app/api/admin/game. Run npm run game:check, npm run game:test, npm run game:docs, and at the end of the night npm run game:grade -- --help-style commands (see docs/game/README.md).
The public site does not establish what happened during the 1924 masquerade, whether Cassandra was victim or suspect, who reportedly died, what became of Cassandra, who protected the club, who sent the 1926 invitations, who will die in 1926, who will kill them, or how the two mysteries ultimately connect.