尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗This is an application for viewing character data in the Elin.
npm run dev for development servernpm run build for production buildnpm run check:archive -- <archive-dir> parses every archived version with the app's schemas (defaults to tmp/archive)npm run check:history holds the change history's PROVENANCE to the modelsnpm run check:hidden verifies Chara#isHidden's id list against the game data; see docs/hidden-charas.mdThe site is a static export (output: 'export') served by Cloudflare Workers
static assets, with no Worker script. Workers Builds builds and deploys it from
this repository.
npm run build, deploy command npx wrangler deploy;
non-production branches use the preview command npx wrangler preview, which
creates or updates a Preview per branch. The Worker name must match name in
wrangler.toml.npm run build runs script/prune-export.cjs afterwards. It deletes the
__next.*.txt segment files, which are most of the export and only serve
prefetching (NoPrefetchLink never prefetches), and fails the build when
out/ still holds 20,000 files or more, the Workers Free limit per version.public/_headers sets the Cache-Control values and public/_redirects
holds the redirects and the rewrites for past versions (below).npx wrangler dev serves out/ locally the way Cloudflare does, including
_redirects and _headers. npm run dev rewrites past version URLs itself.NEXT_PUBLIC_ARCHIVE_BASE_URL: the archive host (see below). Required when
building on Workers Builds (WORKERS_CI=1)..next/cache between builds, which holds Turbopack's build cache
(turbopackFileSystemCacheForBuild, about 320MB). Locally a build of a new
commit on a warm cache compiles in about 1s instead of 30s. The cache is
shared by every branch, including dependabot's, so a dependency's install
script can write to the cache a production build reads. Clear the cache from
the same page when the build output looks stale or the cache keeps growing.next build skips its type check on Workers Builds (WORKERS_CI=1). The
Build step of the GitHub Actions CI type checks the same code, and master
requires that check to pass. The ruleset does not require branches to be up
to date, so two pull requests that pass separately can still deploy a master
that fails the type check. A branch pushed without a pull request gets a
Preview that nothing has type checked.elin.pocke.me:
Cloudflare injects the beacon into the HTML it serves on that hostname, so the
site does not embed it.Only the two current versions live in db/ and are bundled into the build. Every
past version lives in elin-chara-viewer-data
and is fetched by the browser, so the build produces no pages for them.
A past version's URL is /<lang>/<slug>/{charas,charas/<id>,feats,feats/<alias>,sources}
with a slug such as EA-23.306. public/_redirects rewrites each of them
(status 200) to a shell page under src/app/[lang]/archive/, which reads the
slug and the id from the URL, looks the slug up in index.json and renders
the page in the browser. Clicking a link between past version pages reloads the whole page, because the
router's <url>.txt request is answered with the shell HTML. A slug or id that does not exist shows "not found"
with status 200. Slugs always start with EA-, which keeps EA and
Nightly out of the rewrites.
/versions also reads index.json in the browser, so a release shows up
without rebuilding the site.
NEXT_PUBLIC_ARCHIVE_BASE_URL points at the archive. Production must set it:
the default is the repository on raw.githubusercontent.com, which is meant
for development and is not a CDN to serve readers from. The data repository
syncs itself to Cloudflare R2 and that is what production points at; the
bucket needs the CORS policy kept in that repository, because the browser
reads the CSVs directly.
Nothing reads the archive at build time, so a build never depends on the archive host.
.github/workflows/archive.yml adds the versions named in versions/ to the
data repository on every push to master, rebuilds the change history there,
and pushes both as one commit. It needs an ARCHIVE_REPO_TOKEN secret with
write access there.
To add a version by hand — an export made outside these scripts:
$ ruby script/archive_release.rb ../elin-chara-viewer-data 'EA 23.306' \
--channel stable --release-date 2026-05-10 --db /path/to/exported/csv
$ ruby script/extract_feat.rb --archive ../elin-chara-viewer-data --version 'EA 23.306'
$ npm run build:history -- ../elin-chara-viewer-data
--db points at the directory holding <version>/*.csv, and --channel is
required for a version that no versions/ file names.
script/restore_archive_from_history.rb imported the versions that only
existed in this repository's git history. It was a one-shot; the release flow
above is what keeps the archive current.
The versions older than that were restored from Steam itself, by downloading each build of depot 2135153 and running it so the exporter writes its CSVs. That sweep was a one-shot; its scripts and the manifest list it worked from are attached to #303.
The character detail pages show what changed about a character, version by
version. Computing that from every archived version on request is out of the
question, so npm run build:history -- <archive-dir> does it offline and writes
one file per character page to history/charas/ in the data repository; the
page fetches its own when the accordion is opened. The whole history is rebuilt
from scratch on every release, so a version archived out of order or a corrected
release date needs nothing else done.
src/lib/history/viewModel.ts holds PROVENANCE, which says what each raw
column feeds. The history hides a raw column once the display group it feeds
has already reported the change, so a column that quietly starts feeding a
group would show the same change twice. npm run check:history sets each
column to another value the game uses and checks that nothing moves
undeclared.KNOWN_NEW_COLUMNS stops the build instead.--allow-large-change says the difference is meant.MIT License for the source code.
Note that the files under db/ are not covered by this license. They are imported from the Elin game. Also, the files under src/generated/ are generated files from the Elin source code and are not covered by this license.
script/export-build.sh is the part of it that stays: it launches a build
that was downloaded rather than installed, waits for the export to finish,
and stops the game. script/depot-export.sh wraps it together with the
download and the exporter mod, and both update.sh and backfill.sh go
through that.
A release that was missed entirely — the next one shipped before update.sh
ran — is archived by backfill.sh. It shows up as a build that SteamDB lists
and the archive's index.json does not; SteamDB is also the only place that
gives a manifest id for a build that is no longer current, along with the
date it shipped: https://steamdb.info/depot/2135153/manifests/
$ ./backfill.sh 686887586342766718 --channel nightly --release-date 2026-05-10
It downloads that build, exports it, checks the export against the archived
version below it, and commits and pushes the result to the archive checkout
at ../elin-chara-viewer-data; --archive DIR points at one somewhere else.
It needs what update.sh needs — WSL, DepotDownloader signed in to Steam,
and an Elin installed with ElinMiscMod — and the archive checkout has to be
on main, with nothing uncommitted and nothing left unpushed.
Nothing in the build says which branch it shipped on, so --channel is
written into the version's metadata as given.
db/ and versions/ are left alone, because a missed release is not what
either branch points at. That is also why this pushes to the archive itself
instead of going through a release: .github/workflows/archive.yml archives
the versions versions/ names and nothing else.
It takes one manifest per run; for a longer gap, run it once per missed build, oldest first, so that each export is checked against the one before it. A run that stops before it commits says what to do next, and keeps the export it made, so the by-hand flow above can finish from it without downloading the build again.
npm run check:export -- <export-dir> --baseline <dir> checks an export for
the ways the exporter fails quietly — the column order is reconstructed from
the IL of CreateRow(), and a build it cannot follow writes a
plausible-looking CSV with the wrong columns. --archive <dir> sweeps every
archived version instead.