diff --git a/.gitignore b/.gitignore
index 4c41ce2..8edec37 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
.DS_Store
node_modules
+.worktrees
/build
/.svelte-kit
/package
@@ -16,4 +17,4 @@ __pycache__
params_output
-static/consent-form.pdf
\ No newline at end of file
+static/consent-form.pdf
diff --git a/docs/superpowers/plans/2026-05-16-chinese-localization.md b/docs/superpowers/plans/2026-05-16-chinese-localization.md
new file mode 100644
index 0000000..267946d
--- /dev/null
+++ b/docs/superpowers/plans/2026-05-16-chinese-localization.md
@@ -0,0 +1,542 @@
+# Chinese Localization Implementation Plan
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** Build a Chinese-first version of Transformer Explainer with professional English terminology preserved where useful.
+
+**Architecture:** Add a small static localization module for short reusable UI labels and glossary terms, while translating rich article/tutorial HTML in place to avoid risky Svelte restructuring. Add a lightweight Node-based localization check that grows with each task and guards against accidental regression to the original English UI copy.
+
+**Tech Stack:** SvelteKit, Svelte 5, TypeScript, Node.js scripts, existing `~` alias from `svelte.config.js`.
+
+---
+
+## File Structure
+
+- Modify `package.json` and `package-lock.json`: restore a buildable baseline by aligning Vite with `@sveltejs/vite-plugin-svelte`.
+- Create `src/utils/i18n.ts`: Chinese UI strings and glossary constants for short labels reused by Svelte components.
+- Create `scripts/check-localization.mjs`: static text assertions for required Chinese strings and banned original English strings.
+- Modify `package.json`: add `localization:check`.
+- Modify `src/app.html`: set `lang="zh-CN"` and Chinese title/meta descriptions.
+- Modify core UI components:
+ - `src/components/InputForm.svelte`
+ - `src/components/Topbar.svelte`
+ - `src/components/Header.svelte`
+ - `src/components/Sampling.svelte`
+ - `src/components/Temperature.svelte`
+ - `src/components/Embedding.svelte`
+ - `src/components/Attention.svelte`
+ - `src/components/AttentionMatrix.svelte`
+ - `src/components/BlockTransition.svelte`
+ - `src/components/HeadStack.svelte`
+ - `src/components/LinearSoftmax.svelte`
+ - `src/components/Mlp.svelte`
+ - `src/components/Operation.svelte`
+ - `src/components/SubsequentBlocks.svelte`
+ - selected `src/components/Popovers/*.svelte`
+- Modify `src/utils/textbookPages.ts`: translate guided tutorial cards while preserving `id`, selectors, and analytics event names.
+- Modify `src/components/article/Article.svelte`: translate long explanatory article while preserving links, formulas, component imports, classes, and IDs.
+
+## Task 0: Restore Build Baseline
+
+**Files:**
+- Modify: `package.json`
+- Modify: `package-lock.json`
+
+- [ ] **Step 1: Verify the current build fails from dependency incompatibility**
+
+Run: `PATH=/Users/jiangxu/.nvm/versions/node/v22.14.0/bin:$PATH npm run build`
+
+Expected: FAIL with `Cannot read properties of undefined (reading 'config')` from `@sveltejs/vite-plugin-svelte`.
+
+- [ ] **Step 2: Update Vite to the lowest compatible major range**
+
+Run:
+
+```bash
+PATH=/Users/jiangxu/.nvm/versions/node/v22.14.0/bin:$PATH npm install vite@^6.3.0 --save-dev --legacy-peer-deps --registry=https://registry.npmjs.org
+```
+
+Expected: `package.json` changes `vite` from `^5.4.21` to `^6.3.0`, and `package-lock.json` resolves a Vite 6 release compatible with `@sveltejs/vite-plugin-svelte@6.2.4`.
+
+- [ ] **Step 3: Verify package install consistency**
+
+Run:
+
+```bash
+PATH=/Users/jiangxu/.nvm/versions/node/v22.14.0/bin:$PATH npm ci --legacy-peer-deps --registry=https://registry.npmjs.org
+```
+
+Expected: install completes successfully.
+
+- [ ] **Step 4: Verify build baseline**
+
+Run: `PATH=/Users/jiangxu/.nvm/versions/node/v22.14.0/bin:$PATH npm run build`
+
+Expected: PASS or, if unrelated pre-existing Svelte/TypeScript errors remain, the Vite plugin `reading 'config'` crash must be gone and the new failure must be documented.
+
+- [ ] **Step 5: Commit**
+
+Run:
+
+```bash
+git add --sparse package.json package-lock.json
+git commit -m "fix: align vite with svelte plugin"
+```
+
+## Task 1: Localization Guard And Metadata
+
+**Files:**
+- Create: `src/utils/i18n.ts`
+- Create: `scripts/check-localization.mjs`
+- Modify: `package.json`
+- Modify: `src/app.html`
+
+- [ ] **Step 1: Write the failing localization check**
+
+Create `scripts/check-localization.mjs` with this content:
+
+```js
+import { readFileSync } from 'node:fs';
+import { join } from 'node:path';
+
+const root = process.cwd();
+
+function read(path) {
+ return readFileSync(join(root, path), 'utf8');
+}
+
+function assertIncludes(path, expected) {
+ const content = read(path);
+ if (!content.includes(expected)) {
+ throw new Error(`${path} should include: ${expected}`);
+ }
+}
+
+function assertExcludes(path, banned) {
+ const content = read(path);
+ if (content.includes(banned)) {
+ throw new Error(`${path} should not include original English copy: ${banned}`);
+ }
+}
+
+assertIncludes('src/app.html', '');
+assertIncludes('src/app.html', 'Transformer Explainer:可视化理解 LLM Transformer 模型');
+assertExcludes('src/app.html', 'LLM Transformer Model Visually Explained');
+
+assertIncludes('src/utils/i18n.ts', '多层感知机(MLP, Multi-Layer Perceptron)');
+assertIncludes('src/utils/i18n.ts', '词元(Token)');
+assertIncludes('src/utils/i18n.ts', '自注意力(Self-Attention)');
+
+console.log('Localization checks passed.');
+```
+
+- [ ] **Step 2: Run the check and verify it fails**
+
+Run: `node scripts/check-localization.mjs`
+
+Expected: FAIL with an error that `src/app.html` does not include `` or that `src/utils/i18n.ts` does not exist.
+
+- [ ] **Step 3: Add the localization module**
+
+Create `src/utils/i18n.ts`:
+
+```ts
+export const zhCN = {
+ app: {
+ title: 'Transformer Explainer:可视化理解 LLM Transformer 模型',
+ description:
+ '一个交互式可视化工具,帮助你理解 GPT 等大语言模型(LLM)中的 Transformer 模型如何工作。'
+ },
+ controls: {
+ examples: '示例',
+ generate: '生成',
+ inputPlaceholder: '输入你自己的英文提示词',
+ mobileExampleOnly: '请先试试示例。自定义输入建议在桌面端使用。',
+ modelDownloading: 'GPT-2 模型正在下载(600MB),你可以先试试示例。',
+ wordLimit: (limit: number) => `最多可输入 ${limit} 个英文单词。`,
+ temperature: 'Temperature',
+ sampling: 'Sampling'
+ },
+ glossary: {
+ token: '词元(Token)',
+ selfAttention: '自注意力(Self-Attention)',
+ multiHeadSelfAttention: '多头自注意力(Multi-Head Self-Attention)',
+ mlp: '多层感知机(MLP, Multi-Layer Perceptron)',
+ transformerBlock: 'Transformer Block',
+ positionalEncoding: '位置编码(Positional Encoding)',
+ tokenEmbedding: '词元嵌入(Token Embedding)',
+ outputProbabilities: '输出概率(Output Probabilities)'
+ }
+} as const;
+```
+
+- [ ] **Step 4: Translate app metadata**
+
+Change `src/app.html`:
+
+```html
+
+```
+
+Use this title everywhere title content appears:
+
+```html
+Transformer Explainer:可视化理解 LLM Transformer 模型
+```
+
+Use this description everywhere description content appears:
+
+```html
+一个交互式可视化工具,帮助你理解 GPT 等大语言模型(LLM)中的 Transformer 模型如何工作。
+```
+
+- [ ] **Step 5: Add the npm script**
+
+Modify `package.json` scripts:
+
+```json
+"localization:check": "node scripts/check-localization.mjs"
+```
+
+- [ ] **Step 6: Run the check and verify it passes**
+
+Run: `npm run localization:check`
+
+Expected: PASS with `Localization checks passed.`
+
+- [ ] **Step 7: Commit**
+
+Run:
+
+```bash
+git add --sparse src/utils/i18n.ts scripts/check-localization.mjs package.json src/app.html
+git commit -m "test: add chinese localization guard"
+```
+
+## Task 2: Core UI And Visualization Labels
+
+**Files:**
+- Modify: `scripts/check-localization.mjs`
+- Modify: core UI component files listed in File Structure
+
+- [ ] **Step 1: Extend the failing check for core UI**
+
+Append these assertions to `scripts/check-localization.mjs` before the final `console.log`:
+
+```js
+assertIncludes('src/components/InputForm.svelte', '生成');
+assertIncludes('src/components/InputForm.svelte', '示例');
+assertIncludes('src/components/InputForm.svelte', '输入你自己的英文提示词');
+assertExcludes('src/components/InputForm.svelte', 'Test your own input text');
+assertExcludes('src/components/InputForm.svelte', 'Generate');
+
+assertIncludes('src/components/Embedding.svelte', 'Embedding');
+assertIncludes('src/components/Embedding.svelte', 'Tokenization');
+assertIncludes('src/components/Embedding.svelte', 'Token Embedding');
+assertIncludes('src/components/Attention.svelte', '多头自注意力');
+assertIncludes('src/components/LinearSoftmax.svelte', '输出概率');
+assertIncludes('src/components/SubsequentBlocks.svelte', '个相同的');
+assertIncludes('src/components/Operation.svelte', 'Layer Normalization');
+```
+
+- [ ] **Step 2: Run the check and verify it fails**
+
+Run: `npm run localization:check`
+
+Expected: FAIL on `InputForm.svelte` or another core UI assertion because the old English labels are still present.
+
+- [ ] **Step 3: Import reusable strings where it helps**
+
+In `src/components/InputForm.svelte`, add:
+
+```ts
+import { zhCN } from '~/utils/i18n';
+```
+
+Replace visible strings:
+
+```svelte
+{zhCN.controls.examples}
+placeholder={zhCN.controls.inputPlaceholder}
+{zhCN.controls.generate}
+{zhCN.controls.mobileExampleOnly}
+{zhCN.controls.modelDownloading}
+{zhCN.controls.wordLimit(wordLimit)}
+```
+
+- [ ] **Step 4: Translate compact component labels**
+
+Use these exact label choices:
+
+```text
+Topbar logo: Transformer Explainer
+Header link: Transformer Explainer
+Temperature control label: Temperature
+Sampling control label: Sampling
+Embedding title: Embedding
+Tokenization label: Tokenization
+Token Embedding label: Token Embedding
+Positional Encoding label: Positional Encoding
+Multi-head Self Attention title: 多头自注意力
+Subsequent blocks guide: {count} 个相同的 Transformer Blocks
+Probabilities title: 输出概率
+Tokens: Tokens
+Scaled logits: 缩放后的 logits
+Dot product: 点积(Dot Product)
+Scaling · Mask: 缩放 · Mask
+Softmax: Softmax
+Normalization: 归一化(Normalization)
+```
+
+Keep `Q`, `K`, `V`, `Query`, `Key`, `Value`, `Out`, `Softmax`, `MLP`, `GeLU`, `Dropout`, `Layer Normalization`, and `Residual` where labels are too narrow or already standard technical labels.
+
+- [ ] **Step 5: Run checks**
+
+Run: `npm run localization:check`
+
+Expected: PASS.
+
+Run: `npm run check`
+
+Expected: PASS with no Svelte or TypeScript errors.
+
+- [ ] **Step 6: Commit**
+
+Run:
+
+```bash
+git add --sparse scripts/check-localization.mjs src/components src/utils/i18n.ts
+git commit -m "feat: localize core interface labels"
+```
+
+## Task 3: Guided Textbook Cards
+
+**Files:**
+- Modify: `scripts/check-localization.mjs`
+- Modify: `src/utils/textbookPages.ts`
+
+- [ ] **Step 1: Extend the failing check for textbook cards**
+
+Append:
+
+```js
+const textbook = read('src/utils/textbookPages.ts');
+for (const expected of [
+ "title: '什么是 Transformer?'",
+ "title: 'Transformer 如何工作?'",
+ "title: 'Transformer 架构'",
+ "title: 'Embedding'",
+ "title: 'Token Embedding'",
+ "title: 'Positional Encoding'",
+ "title: '重复堆叠的 Transformer Blocks'",
+ "title: '多头自注意力(Multi-Head Self-Attention)'",
+ "title: 'Query、Key、Value'",
+ "title: 'Multi-head'",
+ "title: 'Masked Self-Attention'",
+ "title: 'Attention 输出与拼接'",
+ "title: 'MLP(Multi-Layer Perceptron)'",
+ "title: '输出 Logit'",
+ "title: '输出概率'",
+ "title: 'Temperature'",
+ "title: 'Sampling 策略'",
+ "title: '残差连接(Residual Connection)'",
+ "title: 'Layer Normalization'",
+ "title: 'Dropout'"
+]) {
+ if (!textbook.includes(expected)) {
+ throw new Error(`src/utils/textbookPages.ts should include: ${expected}`);
+ }
+}
+
+assertExcludes('src/utils/textbookPages.ts', 'What is Transformer?');
+assertExcludes('src/utils/textbookPages.ts', 'How Transformers Work?');
+assertExcludes('src/utils/textbookPages.ts', 'Transformer Architecture');
+```
+
+- [ ] **Step 2: Run the check and verify it fails**
+
+Run: `npm run localization:check`
+
+Expected: FAIL on the first missing Chinese textbook title.
+
+- [ ] **Step 3: Translate textbook titles and contents**
+
+Translate each `title` exactly as listed in Step 1. Translate each `content` HTML string into Chinese while preserving:
+
+```ts
+id: 'existing-id'
+on: () => {}
+out: () => {}
+complete: () => {}
+highlightElements([...])
+expandedBlock.set({ id: '...' })
+window.dataLayer?.push(...)
+```
+
+Use these recurring terminology forms in the card bodies:
+
+```text
+Transformer
+GPT-2(small)
+词元(Token)
+Tokenization
+Token Embedding
+Positional Encoding
+Multi-Head Self-Attention
+Query、Key、Value
+Masked Self-Attention
+Attention scores
+Softmax
+MLP(Multi-Layer Perceptron)
+logits
+Temperature
+top-k
+top-p
+Residual Connection
+Layer Normalization
+Dropout
+```
+
+- [ ] **Step 4: Run checks**
+
+Run: `npm run localization:check`
+
+Expected: PASS.
+
+Run: `npm run check`
+
+Expected: PASS.
+
+- [ ] **Step 5: Commit**
+
+Run:
+
+```bash
+git add --sparse scripts/check-localization.mjs src/utils/textbookPages.ts
+git commit -m "feat: localize guided textbook"
+```
+
+## Task 4: Long Article
+
+**Files:**
+- Modify: `scripts/check-localization.mjs`
+- Modify: `src/components/article/Article.svelte`
+
+- [ ] **Step 1: Extend the failing check for the long article**
+
+Append:
+
+```js
+for (const expected of [
+ '
什么是 Transformer? ',
+ 'Transformer 架构 ',
+ 'Embedding ',
+ 'Transformer Block ',
+ 'Multi-Head Self-Attention ',
+ 'MLP:Multi-Layer Perceptron ',
+ '输出概率 ',
+ '辅助架构特性 ',
+ '交互功能 ',
+ '视频教程 ',
+ 'Transformer Explainer 是如何实现的? ',
+ '谁开发了 Transformer Explainer? '
+]) {
+ assertIncludes('src/components/article/Article.svelte', expected);
+}
+
+assertExcludes('src/components/article/Article.svelte', 'What is a Transformer? ');
+assertExcludes('src/components/article/Article.svelte', 'Interactive Features ');
+assertExcludes('src/components/article/Article.svelte', 'Output Probabilities ');
+```
+
+- [ ] **Step 2: Run the check and verify it fails**
+
+Run: `npm run localization:check`
+
+Expected: FAIL on `什么是 Transformer? `.
+
+- [ ] **Step 3: Translate the article**
+
+Translate visible prose, list items, headings, and captions in `Article.svelte`. Preserve all of these exactly:
+
+```svelte
+
+```
+
+Preserve all `href`, `target`, `title`, `id`, `data-click`, `class`, `Katex math={...}`, image paths, and code examples. Translate text around inline code and links. Keep library names, model names, author names, paper title `"Attention is All You Need"`, and project name `Transformer Explainer` in English.
+
+- [ ] **Step 4: Run checks**
+
+Run: `npm run localization:check`
+
+Expected: PASS.
+
+Run: `npm run check`
+
+Expected: PASS.
+
+- [ ] **Step 5: Commit**
+
+Run:
+
+```bash
+git add --sparse scripts/check-localization.mjs src/components/article/Article.svelte
+git commit -m "feat: localize explanatory article"
+```
+
+## Task 5: Final Verification
+
+**Files:**
+- No production file changes expected unless verification reveals a concrete issue.
+
+- [ ] **Step 1: Run static localization check**
+
+Run: `npm run localization:check`
+
+Expected: PASS.
+
+- [ ] **Step 2: Run Svelte/TypeScript check**
+
+Run: `npm run check`
+
+Expected: PASS.
+
+- [ ] **Step 3: Run production build**
+
+Run: `npm run build`
+
+Expected: PASS and output written to `build/`.
+
+- [ ] **Step 4: Start local dev server**
+
+Run: `npm run dev -- --host 127.0.0.1`
+
+Expected: Vite prints a local URL such as `http://127.0.0.1:5173/`.
+
+- [ ] **Step 5: Browser smoke check**
+
+Open the local URL and verify:
+
+```text
+The metadata title is Chinese.
+The input controls show 示例 and 生成.
+The tutorial card titles are Chinese.
+The article headings are Chinese.
+Narrow labels such as Q/K/V/MLP/Softmax remain readable.
+No obvious text overlaps appear in the first viewport.
+```
+
+- [ ] **Step 6: Commit final fixes if any**
+
+If Step 5 required fixes, run:
+
+```bash
+git add --sparse src scripts package.json
+git commit -m "fix: polish chinese localization"
+```
+
+If no fixes were required, do not create an empty commit.
diff --git a/docs/superpowers/specs/2026-05-16-chinese-localization-design.md b/docs/superpowers/specs/2026-05-16-chinese-localization-design.md
new file mode 100644
index 0000000..be87f58
--- /dev/null
+++ b/docs/superpowers/specs/2026-05-16-chinese-localization-design.md
@@ -0,0 +1,79 @@
+# Transformer Explainer 中文汉化设计
+
+## 背景
+
+本项目是 `poloclub/transformer-explainer` 的 fork,当前页面文案以英文为主。目标是面向中文技术读者提供中文界面和中文讲解,同时保留关键技术术语的英文表达,避免翻译后失去专业语境或与模型可视化标签脱节。
+
+仓库是 SvelteKit 应用。主要英文来源包括:
+
+- `src/components/article/Article.svelte`:页面下方长文章正文。
+- `src/utils/textbookPages.ts`:交互式教程卡片标题与内容。
+- `src/components/*.svelte`:按钮、控件、图表短标签、popover 标签、提示语。
+- `src/store/index.ts`:示例 prompt 文本。
+- `src/app.html`:页面标题、meta 描述和分享文案。
+
+## 用户需求
+
+中文应自然、清楚,适合技术专业读者。专业术语可保留英文;缩写或重要术语首次出现时,需要给出英文全称或中英解释。例如 RAG 应写作「检索增强生成(Retrieval-Augmented Generation, RAG)」。
+
+## 推荐方案
+
+采用「中文静态汉化 + 术语英文保留」方案。
+
+不实现完整语言切换系统。当前 fork 的目标是中文版本,完整 i18n 会增加额外运行时状态、切换 UI 和维护成本。也不完全原地硬改所有文案;短文案应尽量集中在中文文案文件或术语文件中,长文章和富文本教程可以在原组件/数据结构中翻译,以减少 Svelte 富文本重构风险。
+
+## 翻译规则
+
+1. UI 操作文案使用中文,例如「生成」「示例」「试试示例」「最多可输入 12 个英文单词」。
+2. 专业术语保留英文或中英并列,例如「词元(Token)」「自注意力(Self-Attention)」「多层感知机(MLP, Multi-Layer Perceptron)」。
+3. 图表中的极短标签优先保持可读和不换行。`Q`、`K`、`V`、`MLP`、`Softmax` 等短标签可保留英文;标题和教程正文给出中文解释。
+4. 缩写首次出现时补充英文全称。之后可直接使用缩写或英文术语。
+5. 链接、论文标题、模型名、作者名、库名保持原文。
+6. 示例 prompt 暂时保留英文。GPT-2 tokenizer、缓存示例数据和模型输出都围绕英文 prompt 工作,直接改成中文会让演示行为和缓存数据不匹配。
+
+## 实现范围
+
+需要汉化:
+
+- `src/app.html` 的页面标题和 meta 文案。
+- `src/components/InputForm.svelte` 的按钮、占位符、helper 文案。
+- `src/components/Topbar.svelte` 和 `src/components/Header.svelte` 的可见标题或链接文本。
+- `src/components/Sampling.svelte`、`src/components/Temperature.svelte` 的控件标题和说明。
+- 主要可视化组件中的阶段名、矩阵标签、popover 标题和公式辅助文字。
+- `src/utils/textbookPages.ts` 中的交互式教程卡片。
+- `src/components/article/Article.svelte` 中的长文章正文、标题、图注和功能说明。
+- `src/store/index.ts` 中与示例相关的中文说明仅在不影响模型输入的前提下调整。
+
+不需要汉化:
+
+- 源代码变量名、CSS class、analytics event name、DOM selector、数据结构字段。
+- 模型输出 token、用户输入 prompt、缓存数据文件 `src/constants/examples/*.js`。
+- 外部链接标题、作者姓名、论文名和库名。
+
+## 文件结构
+
+新增 `src/lib/i18n/zh-CN.ts` 或类似位置,用于收纳短 UI 文案和术语常量。长文章 `Article.svelte` 与教程数据 `textbookPages.ts` 可以直接翻译现有 HTML 内容;若某些术语多次出现且容易不一致,再提取到小型 glossary 常量。
+
+预期结构:
+
+```text
+src/lib/i18n/zh-CN.ts
+src/lib/i18n/glossary.ts
+```
+
+如果项目现有别名不方便从 `src/lib` 引入,可改用 `src/utils/i18n.ts`,保持与现有 `~/utils/*` 引入风格一致。
+
+## 测试与验证
+
+1. 运行 `npm run check`,确保 Svelte 和 TypeScript 通过。
+2. 运行 `npm run build`,确保静态构建通过。
+3. 启动本地开发服务器,检查首页主要区域、教程卡片、长文章、popover 和移动端提示没有明显未翻译英文。
+4. 用文本扫描辅助检查剩余英文文案。允许保留术语、代码名、链接、模型名、作者名、库名和 prompt。
+5. 因当前 sparse checkout 未包含 `static/model-v2` 大模型分片,本地运行可能会在真实模型下载处不可用;验证时主要依赖缓存示例数据和构建检查。
+
+## 风险
+
+- 中文文案比英文更长,可能造成按钮、图表短标签或 popover 布局拥挤。短标签应保守处理,必要时保留英文。
+- 长文章包含大量 HTML 和 KaTeX,翻译时必须保留标签结构和公式内容。
+- 教程页的 `on/out/complete` 行为依赖 selector 和 page id,翻译不得修改这些 id 或 selector。
+- 示例 prompt 与缓存数据耦合,若未来要中文 prompt,需要重新生成缓存示例或改模型演示策略。
diff --git a/package-lock.json b/package-lock.json
index e9a5887..f32c955 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -48,7 +48,7 @@
"tailwindcss": "^3.4.1",
"tslib": "^2.4.1",
"typescript": "^5.0.0",
- "vite": "^5.4.21"
+ "vite": "^6.4.2"
},
"engines": {
"node": ">=20.0.0",
@@ -69,9 +69,9 @@
}
},
"node_modules/@esbuild/aix-ppc64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
- "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
+ "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
"cpu": [
"ppc64"
],
@@ -82,13 +82,13 @@
"aix"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/android-arm": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
- "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
+ "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
"cpu": [
"arm"
],
@@ -99,13 +99,13 @@
"android"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/android-arm64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
- "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
+ "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
"cpu": [
"arm64"
],
@@ -116,13 +116,13 @@
"android"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/android-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
- "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
+ "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
"cpu": [
"x64"
],
@@ -133,13 +133,13 @@
"android"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/darwin-arm64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
- "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
+ "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
"cpu": [
"arm64"
],
@@ -150,13 +150,13 @@
"darwin"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/darwin-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
- "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
+ "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
"cpu": [
"x64"
],
@@ -167,13 +167,13 @@
"darwin"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/freebsd-arm64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
- "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
"cpu": [
"arm64"
],
@@ -184,13 +184,13 @@
"freebsd"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/freebsd-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
- "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
+ "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
"cpu": [
"x64"
],
@@ -201,13 +201,13 @@
"freebsd"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-arm": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
- "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
+ "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
"cpu": [
"arm"
],
@@ -218,13 +218,13 @@
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-arm64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
- "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
+ "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
"cpu": [
"arm64"
],
@@ -235,13 +235,13 @@
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-ia32": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
- "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
+ "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
"cpu": [
"ia32"
],
@@ -252,13 +252,13 @@
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-loong64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
- "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
+ "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
"cpu": [
"loong64"
],
@@ -269,13 +269,13 @@
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-mips64el": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
- "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
+ "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
"cpu": [
"mips64el"
],
@@ -286,13 +286,13 @@
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-ppc64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
- "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
+ "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
"cpu": [
"ppc64"
],
@@ -303,13 +303,13 @@
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-riscv64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
- "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
+ "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
"cpu": [
"riscv64"
],
@@ -320,13 +320,13 @@
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-s390x": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
- "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
+ "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
"cpu": [
"s390x"
],
@@ -337,13 +337,13 @@
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
- "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
+ "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
"cpu": [
"x64"
],
@@ -354,13 +354,30 @@
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@esbuild/netbsd-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
- "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
+ "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
"cpu": [
"x64"
],
@@ -371,13 +388,30 @@
"netbsd"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@esbuild/openbsd-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
- "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
+ "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
"cpu": [
"x64"
],
@@ -388,13 +422,30 @@
"openbsd"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
+ "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@esbuild/sunos-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
- "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
+ "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
"cpu": [
"x64"
],
@@ -405,13 +456,13 @@
"sunos"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/win32-arm64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
- "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
+ "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
"cpu": [
"arm64"
],
@@ -422,13 +473,13 @@
"win32"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/win32-ia32": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
- "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
+ "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
"cpu": [
"ia32"
],
@@ -439,13 +490,13 @@
"win32"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/win32-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
- "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
+ "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
"cpu": [
"x64"
],
@@ -456,7 +507,7 @@
"win32"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@eslint-community/eslint-utils": {
@@ -3679,9 +3730,9 @@
"license": "MIT"
},
"node_modules/esbuild": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
- "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
+ "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@@ -3689,32 +3740,35 @@
"esbuild": "bin/esbuild"
},
"engines": {
- "node": ">=12"
+ "node": ">=18"
},
"optionalDependencies": {
- "@esbuild/aix-ppc64": "0.21.5",
- "@esbuild/android-arm": "0.21.5",
- "@esbuild/android-arm64": "0.21.5",
- "@esbuild/android-x64": "0.21.5",
- "@esbuild/darwin-arm64": "0.21.5",
- "@esbuild/darwin-x64": "0.21.5",
- "@esbuild/freebsd-arm64": "0.21.5",
- "@esbuild/freebsd-x64": "0.21.5",
- "@esbuild/linux-arm": "0.21.5",
- "@esbuild/linux-arm64": "0.21.5",
- "@esbuild/linux-ia32": "0.21.5",
- "@esbuild/linux-loong64": "0.21.5",
- "@esbuild/linux-mips64el": "0.21.5",
- "@esbuild/linux-ppc64": "0.21.5",
- "@esbuild/linux-riscv64": "0.21.5",
- "@esbuild/linux-s390x": "0.21.5",
- "@esbuild/linux-x64": "0.21.5",
- "@esbuild/netbsd-x64": "0.21.5",
- "@esbuild/openbsd-x64": "0.21.5",
- "@esbuild/sunos-x64": "0.21.5",
- "@esbuild/win32-arm64": "0.21.5",
- "@esbuild/win32-ia32": "0.21.5",
- "@esbuild/win32-x64": "0.21.5"
+ "@esbuild/aix-ppc64": "0.25.12",
+ "@esbuild/android-arm": "0.25.12",
+ "@esbuild/android-arm64": "0.25.12",
+ "@esbuild/android-x64": "0.25.12",
+ "@esbuild/darwin-arm64": "0.25.12",
+ "@esbuild/darwin-x64": "0.25.12",
+ "@esbuild/freebsd-arm64": "0.25.12",
+ "@esbuild/freebsd-x64": "0.25.12",
+ "@esbuild/linux-arm": "0.25.12",
+ "@esbuild/linux-arm64": "0.25.12",
+ "@esbuild/linux-ia32": "0.25.12",
+ "@esbuild/linux-loong64": "0.25.12",
+ "@esbuild/linux-mips64el": "0.25.12",
+ "@esbuild/linux-ppc64": "0.25.12",
+ "@esbuild/linux-riscv64": "0.25.12",
+ "@esbuild/linux-s390x": "0.25.12",
+ "@esbuild/linux-x64": "0.25.12",
+ "@esbuild/netbsd-arm64": "0.25.12",
+ "@esbuild/netbsd-x64": "0.25.12",
+ "@esbuild/openbsd-arm64": "0.25.12",
+ "@esbuild/openbsd-x64": "0.25.12",
+ "@esbuild/openharmony-arm64": "0.25.12",
+ "@esbuild/sunos-x64": "0.25.12",
+ "@esbuild/win32-arm64": "0.25.12",
+ "@esbuild/win32-ia32": "0.25.12",
+ "@esbuild/win32-x64": "0.25.12"
}
},
"node_modules/escalade": {
@@ -4088,6 +4142,24 @@
"reusify": "^1.0.4"
}
},
+ "node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
"node_modules/file-entry-cache": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@@ -5512,9 +5584,9 @@
"license": "ISC"
},
"node_modules/picomatch": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
- "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"license": "MIT",
"engines": {
@@ -7331,6 +7403,23 @@
"node": ">=0.8"
}
},
+ "node_modules/tinyglobby": {
+ "version": "0.2.16",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
+ "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -7520,21 +7609,24 @@
"license": "MIT"
},
"node_modules/vite": {
- "version": "5.4.21",
- "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz",
- "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
+ "version": "6.4.2",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.2.tgz",
+ "integrity": "sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "esbuild": "^0.21.3",
- "postcss": "^8.4.43",
- "rollup": "^4.20.0"
+ "esbuild": "^0.25.0",
+ "fdir": "^6.4.4",
+ "picomatch": "^4.0.2",
+ "postcss": "^8.5.3",
+ "rollup": "^4.34.9",
+ "tinyglobby": "^0.2.13"
},
"bin": {
"vite": "bin/vite.js"
},
"engines": {
- "node": "^18.0.0 || >=20.0.0"
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
},
"funding": {
"url": "https://github.com/vitejs/vite?sponsor=1"
@@ -7543,19 +7635,25 @@
"fsevents": "~2.3.3"
},
"peerDependencies": {
- "@types/node": "^18.0.0 || >=20.0.0",
+ "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
+ "jiti": ">=1.21.0",
"less": "*",
"lightningcss": "^1.21.0",
"sass": "*",
"sass-embedded": "*",
"stylus": "*",
"sugarss": "*",
- "terser": "^5.4.0"
+ "terser": "^5.16.0",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
},
"peerDependenciesMeta": {
"@types/node": {
"optional": true
},
+ "jiti": {
+ "optional": true
+ },
"less": {
"optional": true
},
@@ -7576,6 +7674,12 @@
},
"terser": {
"optional": true
+ },
+ "tsx": {
+ "optional": true
+ },
+ "yaml": {
+ "optional": true
}
}
},
diff --git a/package.json b/package.json
index d680935..ecc94e2 100644
--- a/package.json
+++ b/package.json
@@ -7,6 +7,7 @@
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
+ "localization:check": "node scripts/check-localization.mjs",
"lint": "prettier --check . && eslint .",
"format": "prettier --write .",
"deploy": "gh-pages -d build --nojekyll",
@@ -47,7 +48,7 @@
"tailwindcss": "^3.4.1",
"tslib": "^2.4.1",
"typescript": "^5.0.0",
- "vite": "^5.4.21"
+ "vite": "^6.4.2"
},
"type": "module",
"dependencies": {
diff --git a/scripts/check-localization.mjs b/scripts/check-localization.mjs
new file mode 100644
index 0000000..38a7536
--- /dev/null
+++ b/scripts/check-localization.mjs
@@ -0,0 +1,104 @@
+import { readFileSync } from 'node:fs';
+import { join } from 'node:path';
+
+const root = process.cwd();
+
+function read(path) {
+ return readFileSync(join(root, path), 'utf8');
+}
+
+function assertIncludes(path, expected) {
+ const content = read(path);
+ if (!content.includes(expected)) {
+ throw new Error(`${path} should include: ${expected}`);
+ }
+}
+
+function assertExcludes(path, banned) {
+ const content = read(path);
+ if (content.includes(banned)) {
+ throw new Error(`${path} should not include original English copy: ${banned}`);
+ }
+}
+
+assertIncludes('src/app.html', '');
+assertIncludes('src/app.html', 'Transformer Explainer:可视化理解 LLM Transformer 模型');
+assertExcludes('src/app.html', 'LLM Transformer Model Visually Explained');
+
+assertIncludes('src/utils/i18n.ts', '多层感知机(MLP, Multi-Layer Perceptron)');
+assertIncludes('src/utils/i18n.ts', '词元(Token)');
+assertIncludes('src/utils/i18n.ts', '自注意力(Self-Attention)');
+
+assertIncludes('src/components/InputForm.svelte', '生成');
+assertIncludes('src/components/InputForm.svelte', '示例');
+assertIncludes('src/components/InputForm.svelte', '输入你自己的英文提示词');
+assertExcludes('src/components/InputForm.svelte', 'Test your own input text');
+assertExcludes('src/components/InputForm.svelte', 'Generate');
+
+assertIncludes('src/components/Embedding.svelte', 'Embedding');
+assertIncludes('src/components/Embedding.svelte', 'Tokenization');
+assertIncludes('src/components/Embedding.svelte', 'Token Embedding');
+assertIncludes('src/components/Attention.svelte', '多头自注意力');
+assertIncludes('src/components/LinearSoftmax.svelte', '输出概率');
+assertIncludes('src/components/SubsequentBlocks.svelte', '个相同的');
+assertIncludes('src/components/Operation.svelte', 'Layer Normalization');
+
+const textbook = read('src/utils/textbookPages.ts');
+for (const expected of [
+ "title: '什么是 Transformer?'",
+ "title: 'Transformer 如何工作?'",
+ "title: 'Transformer 架构'",
+ "title: 'Embedding'",
+ "title: 'Token Embedding'",
+ "title: 'Positional Encoding'",
+ "title: '重复堆叠的 Transformer Blocks'",
+ "title: '多头自注意力(Multi-Head Self-Attention)'",
+ "title: 'Query、Key、Value'",
+ "title: 'Multi-head'",
+ "title: 'Masked Self-Attention'",
+ "title: 'Attention 输出与拼接'",
+ "title: 'MLP(Multi-Layer Perceptron)'",
+ "title: '输出 Logit'",
+ "title: '输出概率'",
+ "title: 'Temperature'",
+ "title: 'Sampling 策略'",
+ "title: '残差连接(Residual Connection)'",
+ "title: 'Layer Normalization'",
+ "title: 'Dropout'"
+]) {
+ if (!textbook.includes(expected)) {
+ throw new Error(`src/utils/textbookPages.ts should include: ${expected}`);
+ }
+}
+
+assertExcludes('src/utils/textbookPages.ts', 'What is Transformer?');
+assertExcludes('src/utils/textbookPages.ts', 'How Transformers Work?');
+assertExcludes('src/utils/textbookPages.ts', 'Transformer Architecture');
+assertExcludes('src/utils/textbookPages.ts', "Transformers aren't magic");
+assertExcludes('src/utils/textbookPages.ts', 'What is the most probable next word');
+
+for (const expected of [
+ '什么是 Transformer? ',
+ 'Transformer 架构 ',
+ 'Embedding ',
+ 'Transformer Block ',
+ 'Multi-Head Self-Attention ',
+ 'MLP:Multi-Layer Perceptron ',
+ '输出概率 ',
+ '辅助架构特性 ',
+ '交互功能 ',
+ '视频教程 ',
+ 'Transformer Explainer 是如何实现的? ',
+ '谁开发了 Transformer Explainer? '
+]) {
+ assertIncludes('src/components/article/Article.svelte', expected);
+}
+
+assertExcludes('src/components/article/Article.svelte', 'What is a Transformer? ');
+assertExcludes('src/components/article/Article.svelte', 'Interactive Features ');
+assertExcludes('src/components/article/Article.svelte', 'Output Probabilities ');
+assertExcludes('src/components/article/Article.svelte', 'and even');
+assertExcludes('src/components/article/Article.svelte', 'This expansion step allows');
+assertExcludes('src/components/article/Article.svelte', 'Transformer Explainer was created by');
+
+console.log('Localization checks passed.');
diff --git a/src/app.html b/src/app.html
index 53fee17..996119e 100644
--- a/src/app.html
+++ b/src/app.html
@@ -1,5 +1,5 @@
-
+
@@ -7,13 +7,13 @@
- Transformer Explainer: LLM Transformer Model Visually Explained
+ Transformer Explainer:可视化理解 LLM Transformer 模型
-
+
@@ -21,11 +21,11 @@
- Multi-head Self Attention
+ 多头自注意力
diff --git a/src/components/AttentionMatrix.svelte b/src/components/AttentionMatrix.svelte
index 66bf244..4b8f3ba 100644
--- a/src/components/AttentionMatrix.svelte
+++ b/src/components/AttentionMatrix.svelte
@@ -353,7 +353,7 @@
{showTooltip}
/>
- Dot product
+ 点积(Dot Product)
@@ -419,7 +419,7 @@
/>
- Scaling · Mask
+ 缩放 · Mask
diff --git a/src/components/Embedding.svelte b/src/components/Embedding.svelte
index 25d3258..a30de08 100644
--- a/src/components/Embedding.svelte
+++ b/src/components/Embedding.svelte
@@ -196,7 +196,8 @@
-
Token Embedding Token Embedding
-
Expanded Embeddings
+
扩展后的 Embeddings
-
Position
+
位置
{#each $tokens as token, token_idx}
-
Encoding Matrix
+
编码矩阵
diff --git a/src/components/Popovers/QKVWeightPopover.svelte b/src/components/Popovers/QKVWeightPopover.svelte
index 1e0609c..3fbbd3e 100644
--- a/src/components/Popovers/QKVWeightPopover.svelte
+++ b/src/components/Popovers/QKVWeightPopover.svelte
@@ -308,7 +308,7 @@
// };
-
+
@@ -319,8 +319,8 @@
- Embeddings{`Embeddings originate from tokens \nbut evolve through blocks, becoming \nabstract representations.`} {`Embedding 起源于词元(Token),\n并在经过多个 Block 后逐步演化为\n更抽象的表示。`}
@@ -339,8 +339,8 @@
- Q·K·V Weights{`Transforms embedding vectors into Query, Key, and Value vectors. \nParameters were learned in training, fixed in prediction.`} {`把 embedding 向量变换为 Query、Key、Value 向量。\n参数在训练中学习得到,在预测时保持固定。`}
@@ -362,8 +362,8 @@
- Q·K·V Bias{`Offsets added after transformation. \nParameters that learned in training, fixed in prediction.`} {`变换后额外加上的偏移量。\n这些参数在训练中学习得到,在预测时保持固定。`}
-
- Adds layer input to output to help preserve information.
-
把层输入加回输出,帮助保留信息。