Underground 2 Revived
Play Need for Speed: Underground 2 (2004) in Chrome and Firefox with WebGPU graphics, Web Audio, up to 120 fps widescreen, controller support, free roam and Online races with friends. Fan project, not
PC 저장 파일에서 KH1·KH2 Final Mix 체크리스트·트로피·남은 항목 확인, 무료 오픈소스, 브라우저에서 실행
Checklists, trophies and what's left for KH1 Final Mix and KH2 Final Mix, read from your PC save. Free, open source, runs in your browser.
게임TypeScript · HTMLGitHub @sagezaugg온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Unofficial 100% completion tracker for Kingdom Hearts Final Mix and Kingdom Hearts II Final Mix, with PC save import. Fan project.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
An unofficial, fan-made 100% completion tracker for Kingdom Hearts Final Mix and Kingdom Hearts II Final Mix,
with save-file import. It's a single-page app (Vite + React 18 + TypeScript, React Router v6, Zustand) styled after
the KH2 pause menu. One site, with a game switcher in the header.README 전문 보기 ↗An unofficial, fan-made 100% completion tracker for Kingdom Hearts Final Mix and Kingdom Hearts II Final Mix, with save-file import. It's a single-page app (Vite + React 19 + TypeScript 6, React Router v7, Zustand) styled after the KH2 pause menu. One site, with a game switcher in the header.
Live site: https://kh-tracker.vercel.app
Each game tracks three definitions of 100% from one checklist: Jiminy's Journal, Trophies (Platinum excluded from the count) and Everything. Importing a PC save fills in most of the checklist; the file never leaves the browser. In Chrome and Edge the tracker can also watch the save file and re-import it every time the game saves (Config, Auto re-import).
| Game | Routes | Save import | Filled in from the save |
|---|---|---|---|
| KH1FM | /kh1/… | KHFM.png / KHFM_WW.png (PC) | 216 chests, most event rewards and story events, 24 Trinity/map prizes, Ansem's Reports, puppies, Sora LV, magic, summons, Keyblades, staves, shields, Ultima materials |
| KH2FM | /kh2/… | KHIIFM.png / KHIIFM_WW.png (PC), PS2 saves, PCSX2 cards | 317 chests, 89 rewards, 52 bosses, Ansem Reports, Drive Forms, magic, summons, Keyblades, superbosses |
There's also a save diff tool at /tools/save-diff: load a save from before and after an in-game event to see
every byte and bit that changed. It's how the remaining unknown flags get mapped.
Unofficial fan tool. Not affiliated with Square Enix or Disney. Item icons, trophy images and world logos are Square Enix and Disney property, shown only to identify items under fair use (see Game images). No game fonts, music or sounds are used.
Requires Node 22.22+ and npm (React Router 8 needs it; CI uses Node 22 and Vercel Node 24).
npm install
npm run dev
The dev server runs at http://localhost:5173. Other scripts:
| Script | What it does |
|---|---|
npm run typecheck | tsc --noEmit (strict) |
npm run lint | ESLint (typescript-eslint, react-hooks) + Prettier check |
npm run format | Prettier write |
npm test | Vitest + React Testing Library (+ axe smoke test) |
npm run build | Typecheck, then a production build into dist/ |
npm run preview | Serve dist/ locally |
src/
core/ game-agnostic engine: types, rules (trophies), progress, importSave, detect (save probes),
store factory (Zustand + persist), backup codes, storage, file handles, save watcher, save diff
games/
types.ts GameDefinition: nav, routes, catalog, store, save support, wallet, backups
context.ts useGame / useTracker / useProgress / useGameHref
registry.ts GAMES, in switcher order
kh1/ data (locations.json, constants, trophies, journal, synthesis), save, model, routes
kh2/ data, save, model, routes, migrations (prototype backup codes)
screens/ screens shared by every game: Status, Worlds, Trophies, Config
shell/ frame, game switcher, home (Choose a Game), game shell, not-found pages, save diff tool
ui/ CommandMenu, HandCursor, HelpBar, Gauge, PartyCard, ChecklistRow, Section, Stepper, TrophyCard, …
styles/ tokens.css (palette, fonts, motion), global.css
reference/ the prototype and designs KH2 was ported from
data/ source copy of the KH2 location data
scripts/ extract_locations.py (KH2), kh1/extract_locations.py (KH1), brand/ (share image and icon sources)
pwa/ service worker template (the build fills in the file list)
public/ favicon, app icons, web app manifest, og.png link preview
Adding a game means adding a games/<id>/ folder that exports a GameDefinition and listing it in the registry.
Trophies are never stored: they're evaluated from progress on every change (memoized per progress object). Each game
has its own store (kh1fm-tracker, kh2fm-tracker in localStorage), backups and save watcher.
npm test
Covers both save parsers (hand-built buffers, original-game saves, a PCSX2 card, empty files, slot labels), detection, trophy rules, scoring, import sync/add with manual overrides, backup codes, storage failures, the watcher, the save diff, every KH2 screen's main interactions, the game switcher, and an axe accessibility pass over every route of both games.
Put real PC saves in tests/fixtures/ (gitignored, never committed). The fixture suites skip when a file is missing.
tests/fixtures/KHIIFM.png: Slot 1, LV 45, 3,779 munny, Critical, saved in TWTNW; chests 272/317, rewards 78/89,
story bosses 50/52, reports 13/13, Keyblades 19/24, forms 5/5/2/4/1, magic 3/2/3/3/3/3, summon LV 1, all charms,
torn pages 5/5, no Proofs, Final Xemnas not detected.tests/fixtures/KHFM.png: Slot 1 LV 100, 23,666 munny, Proud, End of the World (chests 208/216, event rewards
56, story events 95, prizes 18/24, reports 13/13, Keyblades 18/18, puppies 99, magic all LV 3, six summons) and Slot 2 LV 54,
2,479 munny, Proud, Neverland.KH2 is built from the Archipelago KH2 world:
git clone --depth 1 --filter=blob:none --sparse https://github.com/ArchipelagoMW/Archipelago.git ap
(cd ap && git sparse-checkout set worlds/kh2)
python3 scripts/extract_locations.py ap/worlds/kh2 data/kh2fm-locations.json
cp data/kh2fm-locations.json src/games/kh2/data/locations.json
KH1 is built from the Archipelago KH1 world, the KH-1FM-AP-LUA connector and KH1FM-RANDOMIZER's globals.lua,
pinned to the commits the current data came from. The usage line at the top of scripts/kh1/extract_locations.py
has the exact clone commands:
python3 scripts/kh1/extract_locations.py ap/worlds/kh1/Locations.py kh1lua/1fmAPConnector.lua src/games/kh1/data/locations.json "kh1rando/Static Files/scripts/io_packages/globals.lua"
Then run npm test: the data tests check totals and id uniqueness, and the fixture tests check real saves.
public/og.png (the 1200×630 link preview) and the PNG app icons are screenshots of scripts/brand/og.html and
scripts/brand/icon.html. After editing either, regenerate them on Windows with Edge or Chrome installed:
pwsh scripts/brand/render.ps1
Icons, trophy images and world logos are self-hosted copies of KHWiki files. KHWiki hosts them under fair use and doesn't license them for reuse; they're Square Enix and Disney property, used here at icon size only to identify items.
scripts/icons/manifest.json lists which wiki file each item, trophy and world uses.npm run icons:fetch downloads anything new into a gitignored cache (one request at a time, with a pause), then
writes small WebP copies to public/icons/<game>/ (96px squares, 144x48 bars for Keyblades and staves, rotated
level from the diagonal renders, and 80px-tall logos), src/games/<game>/data/icons.json and
public/icons/CREDITS.json. Run npm run format afterwards.src/ui/icons/).public/icons/ and empty the three tables in each icons.json; every screen
falls back to text.Rows with an (i) button open a short note on where to get the item, plus a link to its KHWiki page. The notes live
in src/games/<game>/data/info.json (how is the note, wiki the KHWiki page title). They're written for this
project in our own words from each page's infobox for that game (its "get" line, or the shop price), not copied, so
they aren't under KHWiki's CC BY-SA text licence. An item with only wiki shows just the link: the Mythril Shield,
whose page doesn't say where to find it. Covered: equipment, abilities, collectibles (reports, Torn Pages, Proofs, puzzles, keyholes, materials and
synthesis recipes) and challenges (mini-games, Mushroom XIII, Absent Silhouettes, Data Organization, cups,
superbosses, Journal, Gummi and feat goals). Spell, form and challenge notes come from the prose of their KHWiki pages,
using the Final Mix details where a page notes a difference. Torn Pages share one note per game because the game
doesn't number them. The Promise Charm and a few self-explanatory KH1 feats have no note. Each game's Trophies screen
links its KHWiki trophy list (trophies in info.json). Level steppers take an infoId to show the same button.
One 6-character code keeps every game's progress in step across devices (Config > Sync between devices). It isn't private: anyone with the code can read and change that progress.
api/sync.ts is a Vercel Function; the logic is in server/sync.ts (create a code, read it, save with
the revision you last saw). Data lives in Upstash Redis (server/upstashStore.ts), one hash per code, and a small
Lua script does the compare-and-write atomically. Limits: 100 KB per code, 60 requests a minute per IP, and codes
expire after a year without a save.KV_REST_API_URL / KV_REST_API_TOKEN (or the UPSTASH_REDIS_REST_* names), which the store reads. Without them
the function answers 503 and the app shows that sync is unavailable.npm run dev and npm run preview serve /api/sync from memory (a Vite middleware), and the tests use
the same in-memory store, so no credentials are needed. Two origins such as localhost:5173 and
device2.localhost:5173 act as two devices against one dev server.src/sync/engine.ts. Per game it compares fingerprints of the last synced data, this device and the
server: only one side changed means apply or upload; both changed means ask (Config, with a banner on every page).
Different games changing on two devices merge automatically. Games added in later versions are stored by id and
passed through untouched by older versions. Only playthroughs, the active playthrough and the profile sync; save
watching, NEW! tags and the latest-changes card stay per device. SyncAgent pulls on start, on focus, when back
online and every 5 minutes, and uploads 3 seconds after a change..github/workflows/ci.yml runs lint, typecheck, tests and a production build on every pull request and every push
to main. The real-save fixture suites skip there because the saves aren't in the repo.
.github/dependabot.yml opens dependency PRs monthly: one grouped PR for npm minor and patch bumps, separate PRs
for major versions, and one for GitHub Actions.
The live site is the Vercel project kh-tracker, linked to this repository: every push to main deploys to
production at https://kh-tracker.vercel.app, and other branches get preview URLs.
vercel.json sets the build command (npm run build), the output directory (dist) and an SPA rewrite so deep links
like /kh2/worlds/tt work on a hard refresh.
npm i -g vercel, then vercel login, then vercel for a preview deploy and vercel --prod for
production.Mapping save flags, fixing content and reporting wrong flags are all welcome. See CONTRIBUTING.md for the ground rules, how item ids are protected, and a step-by-step guide to finding a flag with the save diff tool.
1fmAPConnector.lua
(MIT): its Steam memory addresses minus 0x2DE9360 give the save offset. Map prize (Trinity mark, flower, chair)
flags come from KH1FM-RANDOMIZER's globals.lua (MIT).public/icons/CREDITS.json links every file's source page. The spell glyphs
are drawn for this project.MIT, see LICENSE. The MIT license covers this project's code and text only. Kingdom Hearts is a trademark
of its owners, and the game images in public/icons/ belong to Square Enix and Disney (see
Game images).
Nothing below is guessed; each is a manual check or input in the UI.
KH2: see reference/completion-definitions.md. The game-cleared (Final Xemnas) flag, entry lists for six Journal
sections, the full mini-game list, Mushroom XIII count, and save offsets for the Anti Form counter, feats, Gummi ranks,
synthesis materials, Synthesis Notes and Moogle level.
KH1: entry counts for Chronicles, Characters and Mini-games; the Trinity mark
counter; cup wins, solo and time-trial records (outside the save slot by the connector's addresses); synthesis
record; gummi records; whether 0x1400 counts torn pages held or delivered; which staves and shields Master
Magician and Master Defender need.
Choices the brief didn't settle, with the default picked:
ElephantGraveyardMythril… chests with different flags). The first keeps the prototype id; the second
gets -2. A prototype backup with the shared id checks both rows. The real-save fixture still gives 272/317.SaveProbe gains level (clamped byte, optionally gated by an unlock bit), bitCount
(set bits in a range, for KH1's 99 puppies) and listHas (KH1's owned-summon list); an item may list several
probes (any match counts), which is how a Keyblade counts if owned or equipped. Rule gains { section } (a
Journal section complete) and { count, atLeast } ("open 100 chests", "synthesize 15 items").lv.sora, lv.valor, … stored in values.{ app, v: 3, s: Progress & { profile } } with app = kh1fm-100 or kh2fm-100. KH2's
prototype v1/v2 codes still restore.playthroughs[id] with an activeId; the profile
and NEW! flags are per game. Persisted data is validated on load, and storage failures fall back to memory.games/kh2/model/areas.ts). KH1 has a simpler version (Count toward, world groups,
trophies within reach)./kh1 and /kh2; / is a Choose a Game page. No redirects from the old
single-game paths (the site wasn't deployed yet). The switcher keeps you on the same screen when the other game
has it.0x16C40 from 0x10D30,
alternating game data (magic 0x05) and a "KHSQ" preview, so save n is entry 2(n−1). Location flags are
derived from the AP connector's memory addresses (Steam − 0x2DE9360); that base matches three independent fields
and Kingdom Save Editor, but individual flags haven't each been checked in-game.data-game on the frame, and tokens.css overrides the blue colour
family for KH1 (sea teal, after Destiny Islands); KH2 keeps the original blue. The selection red, golds and
oranges stay shared so the KH look carries across. KH1 text pairs were checked at 6:1 or better.write_geppetto_conditions), and a real unmodded
save reads rewards 4/5, all summons, Pinocchio and All Arts as 0 when they were done. Those 11 locations are manual
checks now. The rest of the derived flags were checked against the owner's near-complete save: world-progress
(50), postcards (10) and reports read correctly.globals.lua gives each of the 24 prizes (Trinity
marks, Wonderland flowers and chairs, the Hollow Bastion node) an event-flag byte and bit relative to Steam
0x2DEA168 (save offset 0xE08). Against the owner's saves, every Trinity prize reads set in the finished Slot 1
(including the three Traverse Town ones the owner confirmed) and the earlier Slot 2 is a strict subset. The six
that read unset (the Wonderland flower pot and Tea Party chairs) are ones the owner hasn't done. Cup wins
and the full 46-mark Trinity count still have no documented location.kh-tracker-notice-v1;
bump the key to show a changed notice again) and falls back to hiding for the visit when storage is blocked.public/manifest.webmanifest) and opens
offline after one online visit. pwa/sw.js is a ~60-line hand-written worker, and a small Vite plugin in
vite.config.ts writes dist/sw.js with the build's file list and a content-hash version, rather than pulling
in vite-plugin-pwa/Workbox for one bundle and a few icons. Pages are network-first, so a new deploy shows up on the
next load, and fall back to the cached shell offline. Hashed assets are cache-first, and Google Fonts are
stale-while-revalidate. Progress was never in the worker's caches: it stays in localStorage and IndexedDB. The
worker registers only in production builds, so npm run dev is unaffected.index.html carries a single Open Graph and
Twitter card for the whole site rather than per-game ones; per-page tags would need prerendering.node_modules code goes to a vendor
chunk (about half the JavaScript) that rarely changes between deploys, so a returning visitor usually only
re-downloads the app chunk. Splitting each game into its own chunk was measured and skipped: each game's data
(about 70 KB) is needed by the home page gauges and by every game's save watcher, which run on every page, so
the only deferrable code was ~20 KB gzipped of screens, at the cost of async route loading.