尚未检测到更新。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.