An unofficial, reader-focused rendering of the ECMAScript® Language Specification. It mirrors the source from tc39/ecma262 and restyles it for readability — it is not normative.
Live at https://kt3k.github.io/ecma262/ (the root redirects to the
editor's draft). Every edition from the latest draft down to ES5.1 is served
at /ecma262/<id>/.
A single Lume (Deno) project renders every edition. The
per-edition input is ecma262/<id>/spec.html:
- draft … ES2015 are ecmarkup source;
lume/scripts/build-chapters.mjsre-implements the subset of ecmarkup's build the site needs (numbering, xref resolution, grammar tokenisation, autolinking) with no ecmarkup dependency. - ES5.1 predates ecmarkup, so its already-rendered official HTML goes
through
lume/scripts/build-chapters-es51.mjs, a re-skin ingester (seedocs/es5.1-plan.md).
The whole site — the Lume project and its build scripts — lives under lume/
with a single lume/deno.json. lume/scripts/build-pages.ts adapts the
generated chapters into Lume pages for one edition (driven by EDITION +
BASE_PATH); lume/scripts/assemble-dist.mjs loops over every edition and
folds the results into dist/ for GitHub Pages.
# one edition, locally (from lume/)
EDITION=es2024 BASE_PATH= deno task pages && deno task build
# the full combined site
deno task build # → dist/.
├── ecma262/ # per-edition spec sources (the build inputs)
│ ├── draft/ # git submodule → tc39/ecma262
│ ├── es2026 … es2015/ # vendored ecmarkup snapshots (spec.html + img/)
│ └── es5.1/ # vendored official HTML (re-skinned, not ecmarkup)
│
├── lume/ # the whole site: Lume (Deno) project + build scripts
│ ├── deno.json # the one project config (imports, JSX, tasks)
│ ├── editions.json # single source of truth: id + title, newest-first
│ ├── _config.ts # plugins, static copy, on-this-page TOC
│ ├── _includes/ # site chrome (page/header/sidebar/footer/…)
│ ├── scripts/ # build scripts (run via deno)
│ │ ├── build-pages.ts # EDITION/BASE_PATH → per-edition pages
│ │ ├── build-chapters.mjs # ecmarkup spec.html → per-chapter <Sec> JSX
│ │ ├── build-chapters-*.mjs # ES5.1/ES3/ES1–ES2 re-skin ingesters
│ │ └── assemble-dist.mjs # build every edition → dist/
│ ├── styles.css, fonts/, … # the ecmarkup look + assets
│ └── (lib/, *.mdx, img/, _includes/chapters.json — gitignored, regenerated)
│
├── nextra-poc/ # vendored Nextra comparison build (served at /nextra-poc/)
├── docs/ # design & reference docs
│
├── .github/workflows/deploy.yml # CI: setup-deno → deno task build → GitHub Pages
├── deno.json # thin root: the build task (→ lume) + fmt config
└── AGENTS.md (CLAUDE.md →) # project instructions
Generated per-edition content under lume/ (lib/, *.mdx, img/,
_includes/chapters.json) is gitignored and regenerated per build, so
nothing edition-specific is committed.
- Vendor the spec:
git clone --depth 1 --branch <tag> https://github.com/tc39/ecma262, then copyspec.html+img/intoecma262/<id>/. - Append
{ "id": "<id>", "title": "…" }tolume/editions.json(newest-first).
That's it — the Lume build and assemble-dist pick it up automatically. (ES5.1
is the one exception: it is rendered HTML, not ecmarkup source, and routes
through the re-skin ingester.)
docs/es5.1-plan.md— ES5.1 re-skin architecturedocs/tc39-deviations.md— where the styling intentionally differs from tc39.es (and why)docs/lume_migration_history.md— how the site moved from Nextra to Lumedocs/emu-xref-investigation.md/docs/dl-header-investigation.md—build-chapters.mjsinternalsdocs/typography-proposal.md— typography noteslume/README.md— Lume site internals
This is not the official specification. For the authoritative text see https://tc39.es/ecma262/.