This file provides guidance to Codex (Codex.ai/code) when working with code in this repository.
Static personal website ("This is Eytle") — no build step, no package manager, no framework. Served directly as HTML/CSS/JS. GitHub (origin) stores the source; production eytle.cn is served by Nginx on Tencent Cloud and deployed through the tencent Git remote. See CODEx_DEPLOY_GUIDE.md before deployment.
The museum additionally uses a Python/SQLite guestbook API. Its code, database, secret and backups live outside the public web root. Production service templates are in scripts/production/; see docs/maintenance/museum-guestbook-service.md. A Git push deploys static assets only: backend changes require a separate service update and verification.
The current Linux workspace is /home/yeom/Documents/ChatGPT/thisIsEytle, restored from the PSSD backup of D:\eyt_web. Read docs/maintenance/2026-09-12-recovery.md for the verified baseline, local commands, preserved drafts, and remaining deployment-access checks. The ignored eyt_web_repo/, deploy/, and .claude/worktrees/pensive-robinson/ directories contain historical copies or drafts; continue website work at the repository root.
For server commands, use ssh eytle-server. This machine's ~/.ssh/config provides a dedicated Ed25519 key, a direct network interface to bypass Mihomo, and optional connection sharing. Fresh key authentication and git ls-remote tencent were verified on 2026-09-12. If the active network interface changes from wlp0s20f3, update BindInterface in the local SSH config.
Use one isolated Git worktree (or branch) for each feature task. A feature task may edit, test, and commit only its own scope; it must not publish to origin or tencent. Do not run multiple feature tasks in the repository root at the same time.
The Codex thread titled “Eytle 网站发布会话” is the release thread. It works at the repository root and is the sole owner of the following steps:
- Inspect every completed feature commit and merge or cherry-pick it into
main. - Run the complete test suite and relevant local checks.
- Create the integration/release commit after confirming the worktree is clean.
- Push
mainto GitHub first, then push the identical commit totencent. - Verify local, GitHub, Tencent bare repository, server worktree, and production files all match; keep release verification records outside the public web root.
Before starting a new feature, create its worktree from current main. If a feature needs files changed by another unfinished task, pause that dependent change until the prerequisite commit is available. Keep deployment configuration and internal maintenance files out of the public site using scripts/deploy-excludes.txt.
The site uses sticky top navigation + a rendered stage (index.html + css/style.css + js/main.js), with cinematic birch-forest artwork. Night uses deep blue and amber; day uses ivory and sage. Responsive images/forest-{night,day}[-mobile].webp backgrounds have an optional WebGL2 pond/fog enhancement in js/forest-scene.js.
| Region | Role |
|---|---|
.rail (sticky top header; legacy class name) |
Brand/logo, language switcher, nav (each .nav-i has data-section), lamp (theme); contact links live in the footer |
.stage (#stage) |
Main panel — go(section) re-renders it on every nav click |
#overlay-root |
Patch-log reader + gallery lightbox mount here (mountOverlay), close on ✕ / backdrop / Esc |
The home section (about) is a custom overview: hero + a two-column grid (latest real patch-log entry + message form | gallery preview). Other sections render generic lists/grids into the stage. Shareable routes use /, /projects, /tools, /patchlog, /gallery and /downloads, with History API back/forward support. Legacy hashes are normalized on arrival. Nginx routes only these known paths to index.html; keep missing assets and unknown pages as 404. Use python3 scripts/preview.py for local static preview with clean URLs.
Main-site UI state lives in main.js; forest-scene.js independently manages the optional background animation. There is no framework or build step. Forest and particle rendering stop off the hero, on other sections, in hidden tabs, or under reduced motion; retain the static CSS fallback.
Personal content is no longer tracked here. Eytle-Patch-Log owns logs/ and its index generator;
Eytle-Museum owns images/gallery/, images/gallery-preview/, audio/museum.mp3, their
maintenance scripts and content tests. Website code and interface assets remain here;
files/730.zip is intentionally retained by the user. content-sources.json pins both repositories
to full commit SHAs. Do not add personal content back to this repository.
Read docs/maintenance/content-repositories.md before content updates or deployment.
Use python3 scripts/assemble-site.py --output /tmp/NEW-PREVIEW with sibling content clones
(or explicit --logs-repo/--museum-repo paths), then
python3 scripts/preview.py --root /tmp/NEW-PREVIEW --port 8000 for a complete preview.
Assembly preserves the public URLs below. A plain source preview has no logs/artwork.
The release thread must seed the server's private content repositories and install
scripts/production/post-receive before publishing the first split version. The previous
static-only rsync hook is insufficient. Historical Git content is not rewritten.
DATA (top of main.js) is the single source of truth for static content (projects, tools, downloads, about). Dynamic sections load their data at render time:
- Patch Log —
loadLogs()fetches./logs/index.json(newest-first list ofYYYY-MM-DD) then fetches individual./logs/YYYY-MM-DD.txtwhen a calendar day or the home "read more" is clicked. The home overview shows the most recent entry's real first lines. - Gallery —
loadGallery()fetches./images/gallery/index.json(list of original filenames) plus./images/gallery-preview/index.json(generated lightweight WebP mapping), then buildsDATA.gallery. Grid/home cards use previews; the lightbox keeps the originals. Both loaders cache after first call.
The log, gallery, and gallery-preview index.json files are generated in their owning content repositories — never edit them by hand. These paths exist in assembled previews and production, not in this source tree.
| Script / hook | Repository | Role |
|---|---|---|
scripts/update-index.py |
Eytle-Patch-Log | regenerate the newest-first log index |
scripts/gallery-renamer.js |
Eytle-Museum | normalize image names and gallery index |
scripts/gallery-previews.py |
Eytle-Museum | generate WebP previews and manifest |
.githooks/pre-commit |
this website | reject personal content accidentally staged here |
scripts/assemble-site.py |
this website | validate pinned content and compose a separate public directory |
Trilingual (中文 / English / 한국어). t(zh, en, ko) returns the appropriate string based on lang; pick(obj, base) reads localized fields (name/nameEn/nameKo) off DATA entries. Nav buttons carry data-zh/data-en/data-ko; applyLang() updates labels, persists lang to localStorage, and re-renders the active section. All dynamic text goes through escapeHtml().
data-theme="night|day" is set on <html> ("lights off / on"). Switching swaps the background painting and the whole token set, and updates the lamp button's action label. Theme persists to localStorage. (mc-calc.html is independent and unaffected.)
Home overview has a "给 Eytle 留言" box (140-char limit + live count, fixed height, honeypot anti-spam). Backend is MSG_CONFIG.web3formsKey near the top of main.js: paste a free Web3Forms public submit key to relay messages to the inbox; leave '' and the form explains that sending is unavailable and preserves the draft. This is separate from the museum guestbook. No secret key ever belongs in this file.
- New project: add an entry to
DATA.projectsinmain.js. Setsub: []for direct GitHub link, or populatesubfor a sub-project list. - New tool: add to
DATA.tools. Setexternal: falsefor internal pages (e.g.mc-calc.html).icon(e.g. the Eye of Ender) is shown only on the tool row — keep that image scoped to tools. - New download: add to
DATA.downloads. - New gallery image: use the scripts and
images/gallery/in Eytle-Museum, then commit originals, previews and generated indexes there. - New patch log entry: create
logs/YYYY-MM-DD.txtin Eytle-Patch-Log, run its index generator and commit there. - Publish content changes: update
content-sources.jsonto the desired content commits; the release thread publishes content before the site. Do not copy material into the website repository.
Self-contained Minecraft stronghold finder tool. Separate page, no shared JS with main.js.
Self-contained first-person 3D museum (Three.js via jsDelivr importmap, pinned
to 0.186.0). Reads images/gallery/index.json for order and the generated
images/gallery-preview/index.json for lightweight textures. On the
gallery nav click, main.js routes WebGL2-capable devices here via isMuseumCapable();
coarse pointers use js/museum-touch.js and css/museum-touch.css for joystick / drag
controls without pointer lock, using the same render quality as desktop. The first
entry click requests fullscreen; entrance and touch HUD buttons allow retry and exit. Unsupported
browsers keep the grid + lightbox; /gallery is also the explicit lightweight fallback. The museum
is a fixed dark dramatic hall — it does NOT follow the night/day theme. Exit
returns to / (never /gallery, to avoid a relaunch loop). The public URL is /museum; /museum.html redirects there. No shared JS
with main.js. Interaction and streaming live in js/museum.js; procedural architecture, materials and planar reflections in js/museum-architecture.js; projector light volumes and dust in js/museum-atmosphere.js; instanced lamp rendering in js/museum-fixture-batch.js; styling in css/museum.css.
The Nocturne art direction uses a 6.7 m vaulted hall, champagne metal and dark stone. Keep the half-width at 3 m and structural projections within the existing 0.4 m collision margin. Fog ends at 82 m before the 88 m hidden-retarget boundary. Reflection cameras must have their cloned AudioListener children cleared. Ceiling projectors, their light volumes and floor pools share js/museum-lighting-layout.js; opaque bloom occlusion lives in js/museum-bloom-occlusion.js. Keep pier/intrados light channels centered on each rib and stop longitudinal rails before the 0.45 m plinths. Use museum.html?perf=walk for automatic visual/performance verification; the entrance is hidden in this diagnostic mode.