From 4dd92f83a0c018afa31d29dfa0f1fd3922c7784a Mon Sep 17 00:00:00 2001 From: Maxim Dolgolyov Date: Sat, 13 Jun 2026 11:14:13 +0300 Subject: [PATCH] =?UTF-8?q?feat(sim-builder):=20=D1=84=D0=B0=D0=B7=D0=B0?= =?UTF-8?q?=200=20=E2=80=94=20=D1=80=D0=B0=D0=BD=D1=82=D0=B0=D0=B9=D0=BC?= =?UTF-8?q?=20SimEngine=20+=20=D0=B1=D0=B5=D0=B7=D0=BE=D0=BF=D0=B0=D1=81?= =?UTF-8?q?=D0=BD=D1=8B=D0=B9=20=D0=B4=D0=B2=D0=B8=D0=B6=D0=BE=D0=BA=20?= =?UTF-8?q?=D0=B2=D1=8B=D1=80=D0=B0=D0=B6=D0=B5=D0=BD=D0=B8=D0=B9=20+=20?= =?UTF-8?q?=D0=B0=D0=B4=D0=B0=D0=BF=D1=82=D0=B5=D1=80=20LabRegistry?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CLAUDE.md | 13 + frontend/js/labs/_sim_adapter.js | 149 ++++++ frontend/js/labs/_sim_demo.js | 112 ++++ frontend/js/labs/_sim_engine.js | 616 ++++++++++++++++++++++ frontend/js/labs/_sim_expr.js | 423 +++++++++++++++ plans/sim-builder/CONTEXT.md | 13 +- plans/sim-builder/PLAN.md | 4 +- plans/sim-builder/phase-0-runtime-core.md | 63 ++- 8 files changed, 1371 insertions(+), 22 deletions(-) create mode 100644 frontend/js/labs/_sim_adapter.js create mode 100644 frontend/js/labs/_sim_demo.js create mode 100644 frontend/js/labs/_sim_engine.js create mode 100644 frontend/js/labs/_sim_expr.js diff --git a/CLAUDE.md b/CLAUDE.md index 86b94f7..6d34365 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -51,3 +51,16 @@ git push origin master - Node.js/Express backend, SQLite (better-sqlite3, sync) - Frontend: vanilla JS, без бандлера - ast-index проиндексирован: `ast-index rebuild` при добавлении новых файлов + +## Feature: Конструктор симуляций (SimForge) + +Движок авторинга интерактивных 2D-симуляций из JSON-спеки (данные, НЕ код). План: `plans/sim-builder/`. + +### Phase 0 — Learnings + +- **Спека = данные.** Любое числовое свойство объекта = число ИЛИ строка-выражение. Выражения шарятся между людьми → движок безопасный, ⛔ без `eval`/`new Function`. +- **`window.SimExpr`** (`frontend/js/labs/_sim_expr.js`): токенайзер → AST → evaluate. `compile(src)->{ast,fn,error}`; `fn(env)` НИКОГДА не бросает (NaN/∞/деление на 0 → 0). Whitelist: `+ - * / ^ %`, унарный `- + !`, сравнения `< <= > >= == !=`, логика `&& ||`, тернарник `?:`, функции `sin cos tan tg ctg cot asin..arctg sqrt abs exp ln log log2 log10 floor ceil round sign min max mod atan2 pow hypot`, константы `pi e tau`. Идентификаторы (вкл. точечные `obj.x`) — только из `env`. Парсер — расширение `y=f(x)` из `graph.js`; `-2^2 == 4` (парити). Также `evalSafe`, `compileValue`, `parse`, `tokenize`, `FUNCTIONS`, `CONSTANTS`. +- **`window.SimEngine.mount(host, spec)`** (`_sim_engine.js`) → `{ play, pause, reset, setParam, getParam, isRunning, destroy, el }`. Canvas (мир→экран, равные оси, Y вверх) + KaTeX-оверлей подписей (`katex.renderToString`, как graph.js) + слайдеры из `params[]`. Выражения компилируются 1 раз в mount; в rAF — только evaluate. `env = { t, , w, h, xmin..ymax, .x, .y }`. Объекты: `point segment vector circle rect polyline path label`. **Формат спеки v1 — в шапке `_sim_engine.js`.** +- **`window.registerSpecSim(spec)`** (`_sim_adapter.js`): спека → манифест LabRegistry (ленивый хост `#sim-spec-host-` в `#lab-sim`; `stop` прячет, `destroy` уничтожает). Так спек-сим открывается тем же путём, что рукописные ~40 (через `openSim` → реестр). +- Демо `customdemo` — `_sim_demo.js`, за флагом `?simdemo=1` / `?sim=customdemo` / `LAB_SHOW_SPEC_DEMO` / localStorage `lab-spec-demo=1` (ученикам не светится). +- Подключение: 3 каркасных `