From 5b103ab606cfcd9818c02275425d631d9efb98d9 Mon Sep 17 00:00:00 2001 From: Maxim Dolgolyov Date: Mon, 1 Jun 2026 09:34:29 +0300 Subject: [PATCH] =?UTF-8?q?refactor(lab):=20=D0=BF=D1=80=D0=B5=D0=B2=D1=8C?= =?UTF-8?q?=D1=8E=20=D1=81=D0=B8=D0=BC=D1=83=D0=BB=D1=8F=D1=86=D0=B8=D0=B9?= =?UTF-8?q?=20=D0=B2=D1=8B=D0=BD=D0=B5=D1=81=D0=B5=D0=BD=D1=8B=20=D0=B2=20?= =?UTF-8?q?=D0=BE=D0=B1=D1=89=D0=B8=D0=B9=20lab-previews.js=20(=D0=B5?= =?UTF-8?q?=D0=B4=D0=B8=D0=BD=D1=8B=D0=B9=20=D0=B8=D1=81=D1=82=D0=BE=D1=87?= =?UTF-8?q?=D0=BD=D0=B8=D0=BA)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ~45 SVG-превью (P_*) и хелперы _grid/_axes/_svg вынесены из lab-glue.js в общий /js/lab-previews.js: window.LabPreviews (карта id→SVG, 40 симуляций) + window.__LabP (по имени, lab-glue берёт алиасы оттуда). SIMS не тронут. lab.html подключает lab-previews.js перед lab-glue.js. Теперь дашборд берёт настоящие превью симуляций из того же источника → «Лаборатория дня» крутит весь каталог, а не 6 захардкоженных. Дублирование 6 превью устранено. Co-Authored-By: Claude Opus 4.8 (1M context) --- frontend/js/lab-previews.js | 765 +++++++++++++++++++++++++++++++++-- frontend/js/labs/lab-glue.js | 723 +-------------------------------- frontend/lab.html | 1 + 3 files changed, 730 insertions(+), 759 deletions(-) diff --git a/frontend/js/lab-previews.js b/frontend/js/lab-previews.js index 6c5ae56..8cfc58d 100644 --- a/frontend/js/lab-previews.js +++ b/frontend/js/lab-previews.js @@ -1,12 +1,16 @@ 'use strict'; /* - * LabPreviews — реальные SVG-превью симуляций (зеркало P_* из labs/lab-glue.js) - * для карточки «Лаборатория дня» на дашборде. Тёмные тайлы 270×140. - * Источник истины — lab-glue.js; здесь лёгкая копия, чтобы не грузить весь - * движок лаборатории на дашборде. + * lab-previews.js — ЕДИНЫЙ источник SVG-превью симуляций лаборатории. + * Вынесено из lab-glue.js, чтобы превью были доступны и на /lab (карточки), + * и на дашборде («Лаборатория дня»), без загрузки тяжёлого lab-glue.js. + * + * window.LabPreviews — карта id симуляции -> SVG-строка (для дашборда/реестра). + * window.__LabP — те же превью по имени P_* (lab-glue.js берёт их отсюда). + * + * Грузить ПЕРЕД lab-glue.js (на /lab) и на дашборде. */ (function () { - function _grid(fg='rgba(255,255,255,0.06)') { +function _grid(fg='rgba(255,255,255,0.06)') { return ` @@ -15,23 +19,139 @@ `; } - + function _axes() { + return ` + + + `; + } function _svg(body) { - return ` + return ` ${body}`; } - const P_LENS = _svg(`${_grid('rgba(255,255,255,0.04)')} - - - - - - - - - `); + /* 1 — Graph */ + const P_GRAPH = _svg(`${_grid()}${_axes()} + + `); + /* 2 — Transform: three shifted/scaled sines */ + const P_TRANSFORM = _svg(`${_grid()}${_axes()} + + + `); + + /* 3 — Triangle geometry */ + const P_TRIANGLE = _svg(`${_grid('rgba(255,255,255,0.04)')} + + + + + + `); + + /* 4 — Inscribed/circumscribed circles */ + const P_CIRCLES = _svg(`${_grid('rgba(255,255,255,0.04)')} + + + + + `); + + /* 5 — Quadratic roots: parabola crossing x-axis */ + const P_QUADRATIC = _svg(`${_grid()}${_axes()} + + + + + + D = b²− 4ac`); + + /* 6 — 3D geometry: isometric cube */ + const P_3D = _svg(`${_grid('rgba(255,255,255,0.04)')} + + + + + V = a³`); + + /* 7 — Probability: histogram bars */ + const P_PROB = _svg(`${_grid()} + + + + + + + + + `); + + /* 8 — Normal distribution: bell curve */ + const P_NORMAL = _svg(`${_grid()} + + + + + μ = 0, σ = 1`); + + /* 8b — Trig circle */ + const P_TRIGCIRCLE = _svg(`${_grid('rgba(255,255,255,0.04)')} + + + + + + + + + sin · cos · tg · ctg`); + + /* 9 — Projectile motion */ + const P_PROJECTILE = _svg(`${_grid('rgba(255,255,255,0.04)')} + + + + + + + + + x = v₀cos(α)·t`); + + /* 10 — Pendulum */ + const P_PENDULUM = _svg(`${_grid('rgba(255,255,255,0.04)')} + + + + + + + T = 2π√(l/g)`); + + /* 11 — Collision */ + const P_COLLISION = _svg(`${_grid('rgba(255,255,255,0.04)')} + + + m₁ + + + m₂ + + + + + `); + + + /* 13 — Electric circuit */ const P_CIRCUIT = _svg(`${_grid('rgba(255,255,255,0.04)')} @@ -45,25 +165,95 @@ I = U/R`); - const P_PENDULUM = _svg(`${_grid('rgba(255,255,255,0.04)')} - - - - - - - T = 2π√(l/g)`); + /* 14 — Magnetic field */ + const P_MAGNETIC = _svg(` + + ${_grid('rgba(155,93,229,0.06)')} + + + + + + + + + + + + + + + + + + B = μ₀I / 2πr`); - const P_WAVES = _svg(`${_grid()} - - - - - v = \u03bbf \u00b7 y = A sin(\u03c9t \u2212 kx) \u00b7 \u0441\u0442\u043e\u044f\u0447\u0438\u0435 \u0432\u043e\u043b\u043d\u044b`); + /* 14 — Electric field lines */ + const P_FIELD = _svg(`${_grid('rgba(255,255,255,0.04)')} + + + + + + + + + + + + + + + `); + /* 15 — Thin lens */ + const P_LENS = _svg(`${_grid('rgba(255,255,255,0.04)')} + + + + + + + + + `); + + /* 16 — Refraction */ + const P_REFRACTION = _svg(` + + + + + + + + + + + α + β + n₁sinα = n₂sinβ`); + + /* 17 — Mirrors */ + const P_MIRROR = _svg(`${_grid('rgba(255,255,255,0.04)')} + + + + + + + + + F + + + + + + + + `); + + /* 18 — Isoprocesses */ const P_ISOPROCESS = _svg(`${_grid('rgba(255,255,255,0.04)')} @@ -79,15 +269,506 @@ V P`); - const P_3D = _svg(`${_grid('rgba(255,255,255,0.04)')} - - - - - V = a³`); + /* ── Chemistry / Molecular Physics previews ── */ + const P_GAS = _svg(` + + + ${[ + [40,30,'#4CC9F0'],[70,80,'#7BF5A4'],[110,25,'#EF476F'],[150,60,'#FFD166'],[190,30,'#4CC9F0'], + [220,90,'#EF476F'],[55,110,'#7BF5A4'],[95,65,'#4CC9F0'],[130,110,'#EF476F'],[170,40,'#FFD166'], + [210,115,'#4CC9F0'],[240,55,'#7BF5A4'],[30,70,'#FFD166'],[80,120,'#EF476F'],[165,95,'#4CC9F0'] + ].map(([x,y,c])=>``).join('')} + + + + + + + + PV=nRT`); + + /* ── Законы Ньютона ── */ + const P_NEWTON = _svg(` + + + + + + F + + + + m₂ + + + a = F/m · III законы Ньютона`); + + /* ── Песочница сил ── */ + const P_SANDBOX = _svg(` + + ${_grid('rgba(255,255,255,0.03)')} + + + 5кг + + 8кг + + + + + + + F₁ + F₂ + Песочница сил · F = ma`); + + const P_HYDRO = _svg(` + + ${_grid('rgba(255,255,255,0.03)')} + + + + + P = ρgh + + + + F_A + + + + + + + + + Δh + + + + + + + + + + Архимед · Паскаль · капиллярность`); + + /* ── coming soon chem previews (simple) ── */ + const P_KINETICS = _svg(` + + ${_grid()} + + + + + [C] продукт + [A] реагент`); + + const P_EQUILIBRIUM = _svg(` + + A + B ⇌ C + D + + + + A,B + K + C,D`); + + const P_ELECTROLYSIS = _svg(` + + + + + ${[55,58,61,64,67,70].map(x=>``).join('')} + ${[210,214,218,222,226].map(x=>``).join('')} + + +`); + + const P_BOHR = _svg(` + + + + + + + + + + `); + + const P_ORBITALS = _svg(` + + + + + + `); + + const P_PH = _svg(` + + ${_grid()} + + + pH + V`); + + const P_CHEMSANDBOX = _svg(` + + ${_grid()} + + + + + + A + B C + D + + + + + + + + `); + + const P_STOICHIOMETRY = _svg(` + + ${_grid()} + + + + + + Zn + + + + + + + 2HCl + + + + + + + ZnCl₂ + + + + H₂ + ● лимит`); + + /* Periodic Table — 6×4 coloured cell grid */ + const P_PERIODIC = _svg(` + + ${(function(){ + const cols=18,rows=4,pad=6,w=(270-pad*2)/cols,h=(140-pad*2)/rows; + const colors=['#EF476F','#FF6B35','#FFD166','#7BF5A4','#C77DFF','#A8DADC', + '#7B8EF7','#06D6E0','#9B5DE5','#F15BB5','#EF476F','#FF6B35', + '#06D6E0','#7B8EF7','#FFD166','#C77DFF','#A8DADC','#7BF5A4']; + let s=''; + for(let r=0;r=2&&c<=15)||(r===1&&c>=2&&c<=11); + if(!skip) s+=``; + } + return s; + })()} + 118 элементов`); + + const P_CRYSTAL = _svg(` + + ${[ + [80,40],[135,40],[190,40], + [55,75],[110,75],[165,75],[220,75], + [80,110],[135,110],[190,110] + ].map(([x,y],i)=>``).join('')} + + + + + + + + + + + `); + + const P_CELLDIVISION = _svg(` + + + + + + + + + + + + + + + + + + + + + Метафаза · митоз`); + + const P_PHOTOSYNTHESIS = _svg(` + + + + + + + + + + + + H₂O + CO₂ + ATP + G3P + Световые реакции · цикл Кальвина`); + + const P_ANGRYBIRDS = _svg(` + + + + + + + + + + + + + + + + + + + Физика полёта · импульс · разрушение`); + + const P_WAVES = _svg(`${_grid()} + + + + + v = \u03bbf \u00b7 y = A sin(\u03c9t \u2212 kx) \u00b7 \u0441\u0442\u043e\u044f\u0447\u0438\u0435 \u0432\u043e\u043b\u043d\u044b`); + + /* Radioactive decay preview */ + const P_RADIOACTIVE = _svg(`${_grid()} + + + + + + + + + + + + + + N(t) = N₀·e⁻λt · T½ · цепочки распада`); + + /* Heat Engines preview */ + const P_HEATENGINE = _svg(`${_grid('rgba(255,255,255,0.04)')} + + + + + + + + + + A + B + C + V + P + η = 1 − Tc/Th`); + + /* Geometry (planimetry) preview */ + const P_GEOMETRY = _svg(`${_grid('rgba(255,255,255,0.04)')} + + + + + + + + + + A + B + C`); + + + /* Race sim preview — two objects on a track, x(t) lines */ + const P_RACE = _svg(`${_grid('rgba(255,255,255,0.05)')} + + + + + + + + встреча + x = x₀ + v₀t + at²/2`); + + /* Logic Circuits preview */ + const P_LOGIC = _svg(`${_grid('rgba(255,255,255,0.04)')} + + AND + + XOR + + AND + + + + + + + + + + + S + C + S = A⊕B · C = A∧B · Таблица истинности`); + + + /* Qualitative Analysis preview */ + const P_QUALANALYSIS = _svg(` + + + + + + + + + + + Cl + Fe(III) + SO4 + AgNO3 + + + + AgCl / Fe(SCN) / BaSO4`); + + /* Organic Chemistry preview — benzene ring + OH group */ + const P_ORGANIC = _svg(` + + ${_grid('rgba(255,255,255,0.03)')} + + + + + + C + C + C + C + C + C + + + + O + + + H + + + + C + Конструктор · Ряды · Качественные реакции`); + + /* Solutions preview */ + const P_SOLUTIONS = _svg(` + + + + + + + 20% + + + ω% + C-M + ν моль + ω = m₀/m​ · 100% + Калькулятор · Разбавление · Смешивание · S(T)`); + + // Экспорт по имени P_* (для lab-glue.js) + window.__LabP = { P_GRAPH, P_TRANSFORM, P_TRIANGLE, P_CIRCLES, P_QUADRATIC, P_3D, P_PROB, P_NORMAL, P_TRIGCIRCLE, P_PROJECTILE, P_PENDULUM, P_COLLISION, P_CIRCUIT, P_MAGNETIC, P_FIELD, P_LENS, P_REFRACTION, P_MIRROR, P_ISOPROCESS, P_GAS, P_NEWTON, P_SANDBOX, P_HYDRO, P_KINETICS, P_EQUILIBRIUM, P_ELECTROLYSIS, P_BOHR, P_ORBITALS, P_PH, P_CHEMSANDBOX, P_STOICHIOMETRY, P_PERIODIC, P_CRYSTAL, P_CELLDIVISION, P_PHOTOSYNTHESIS, P_ANGRYBIRDS, P_WAVES, P_RADIOACTIVE, P_HEATENGINE, P_GEOMETRY, P_RACE, P_LOGIC, P_QUALANALYSIS, P_ORGANIC, P_SOLUTIONS }; + + // Экспорт по id симуляции (для дашборда и реестра) window.LabPreviews = { - opticsbench: P_LENS, circuit: P_CIRCUIT, pendulum: P_PENDULUM, - waves: P_WAVES, isoprocess: P_ISOPROCESS, stereo: P_3D, + "graph": P_GRAPH, + "graphtransform": P_TRANSFORM, + "geometry": P_GEOMETRY, + "triangle": P_TRIANGLE, + "quadratic": P_QUADRATIC, + "stereo": P_3D, + "probability": P_PROB, + "trigcircle": P_TRIGCIRCLE, + "normaldist": P_NORMAL, + "projectile": P_PROJECTILE, + "pendulum": P_PENDULUM, + "collision": P_COLLISION, + "emfield": P_MAGNETIC, + "circuit": P_CIRCUIT, + "hydrostatics": P_HYDRO, + "dynamics": P_SANDBOX, + "opticsbench": P_LENS, + "isoprocess": P_ISOPROCESS, + "waves": P_WAVES, + "radioactive": P_RADIOACTIVE, + "race": P_RACE, + "heatengine": P_HEATENGINE, + "logic": P_LOGIC, + "molphys": P_GAS, + "chemistry": P_KINETICS, + "equilibrium": P_EQUILIBRIUM, + "electrolysis": P_ELECTROLYSIS, + "bohratom": P_BOHR, + "orbitals": P_ORBITALS, + "titration": P_PH, + "chemsandbox": P_CHEMSANDBOX, + "stoichiometry": P_STOICHIOMETRY, + "crystal": P_CRYSTAL, + "qualanalysis": P_QUALANALYSIS, + "periodic": P_PERIODIC, + "organic": P_ORGANIC, + "solutions": P_SOLUTIONS, + "celldivision": P_CELLDIVISION, + "photosynthesis": P_PHOTOSYNTHESIS, + "angrybirds": P_ANGRYBIRDS }; })(); diff --git a/frontend/js/labs/lab-glue.js b/frontend/js/labs/lab-glue.js index 3317a05..b32c547 100644 --- a/frontend/js/labs/lab-glue.js +++ b/frontend/js/labs/lab-glue.js @@ -49,725 +49,14 @@ if (window.lucide) lucide.createIcons(); } - /* ════════════════════════════════ - CARD PREVIEW SVGs + /* ════════════════════════════════ + CARD PREVIEW SVGs — вынесены в /js/lab-previews.js (единый источник). + Берём их по имени из window.__LabP; SIMS ниже ссылается на эти алиасы. ════════════════════════════════ */ - function _grid(fg='rgba(255,255,255,0.06)') { - return ` - - - - - - `; - } - function _axes() { - return ` - - - `; - } - function _svg(body) { - return ` - ${body}`; - } + var __LP = window.__LabP || {}; + var P_GRAPH = __LP.P_GRAPH, P_TRANSFORM = __LP.P_TRANSFORM, P_TRIANGLE = __LP.P_TRIANGLE, P_CIRCLES = __LP.P_CIRCLES, P_QUADRATIC = __LP.P_QUADRATIC, P_3D = __LP.P_3D, P_PROB = __LP.P_PROB, P_NORMAL = __LP.P_NORMAL, P_TRIGCIRCLE = __LP.P_TRIGCIRCLE, P_PROJECTILE = __LP.P_PROJECTILE, P_PENDULUM = __LP.P_PENDULUM, P_COLLISION = __LP.P_COLLISION, P_CIRCUIT = __LP.P_CIRCUIT, P_MAGNETIC = __LP.P_MAGNETIC, P_FIELD = __LP.P_FIELD, P_LENS = __LP.P_LENS, P_REFRACTION = __LP.P_REFRACTION, P_MIRROR = __LP.P_MIRROR, P_ISOPROCESS = __LP.P_ISOPROCESS, P_GAS = __LP.P_GAS, P_NEWTON = __LP.P_NEWTON, P_SANDBOX = __LP.P_SANDBOX, P_HYDRO = __LP.P_HYDRO, P_KINETICS = __LP.P_KINETICS, P_EQUILIBRIUM = __LP.P_EQUILIBRIUM, P_ELECTROLYSIS = __LP.P_ELECTROLYSIS, P_BOHR = __LP.P_BOHR, P_ORBITALS = __LP.P_ORBITALS, P_PH = __LP.P_PH, P_CHEMSANDBOX = __LP.P_CHEMSANDBOX, P_STOICHIOMETRY = __LP.P_STOICHIOMETRY, P_PERIODIC = __LP.P_PERIODIC, P_CRYSTAL = __LP.P_CRYSTAL, P_CELLDIVISION = __LP.P_CELLDIVISION, P_PHOTOSYNTHESIS = __LP.P_PHOTOSYNTHESIS, P_ANGRYBIRDS = __LP.P_ANGRYBIRDS, P_WAVES = __LP.P_WAVES, P_RADIOACTIVE = __LP.P_RADIOACTIVE, P_HEATENGINE = __LP.P_HEATENGINE, P_GEOMETRY = __LP.P_GEOMETRY, P_RACE = __LP.P_RACE, P_LOGIC = __LP.P_LOGIC, P_QUALANALYSIS = __LP.P_QUALANALYSIS, P_ORGANIC = __LP.P_ORGANIC, P_SOLUTIONS = __LP.P_SOLUTIONS; - /* 1 — Graph */ - const P_GRAPH = _svg(`${_grid()}${_axes()} - - `); - - /* 2 — Transform: three shifted/scaled sines */ - const P_TRANSFORM = _svg(`${_grid()}${_axes()} - - - `); - - /* 3 — Triangle geometry */ - const P_TRIANGLE = _svg(`${_grid('rgba(255,255,255,0.04)')} - - - - - - `); - - /* 4 — Inscribed/circumscribed circles */ - const P_CIRCLES = _svg(`${_grid('rgba(255,255,255,0.04)')} - - - - - `); - - /* 5 — Quadratic roots: parabola crossing x-axis */ - const P_QUADRATIC = _svg(`${_grid()}${_axes()} - - - - - - D = b²− 4ac`); - - /* 6 — 3D geometry: isometric cube */ - const P_3D = _svg(`${_grid('rgba(255,255,255,0.04)')} - - - - - V = a³`); - - /* 7 — Probability: histogram bars */ - const P_PROB = _svg(`${_grid()} - - - - - - - - - `); - - /* 8 — Normal distribution: bell curve */ - const P_NORMAL = _svg(`${_grid()} - - - - - μ = 0, σ = 1`); - - /* 8b — Trig circle */ - const P_TRIGCIRCLE = _svg(`${_grid('rgba(255,255,255,0.04)')} - - - - - - - - - sin · cos · tg · ctg`); - - /* 9 — Projectile motion */ - const P_PROJECTILE = _svg(`${_grid('rgba(255,255,255,0.04)')} - - - - - - - - - x = v₀cos(α)·t`); - - /* 10 — Pendulum */ - const P_PENDULUM = _svg(`${_grid('rgba(255,255,255,0.04)')} - - - - - - - T = 2π√(l/g)`); - - /* 11 — Collision */ - const P_COLLISION = _svg(`${_grid('rgba(255,255,255,0.04)')} - - - m₁ - - - m₂ - - - - - `); - - - /* 13 — Electric circuit */ - const P_CIRCUIT = _svg(`${_grid('rgba(255,255,255,0.04)')} - - - - R₁ - - - R₂ - - - - I = U/R`); - - /* 14 — Magnetic field */ - const P_MAGNETIC = _svg(` - - ${_grid('rgba(155,93,229,0.06)')} - - - - - - - - - - - - - - - - - - B = μ₀I / 2πr`); - - /* 14 — Electric field lines */ - const P_FIELD = _svg(`${_grid('rgba(255,255,255,0.04)')} - - + - - - - - - - - - - - - `); - - /* 15 — Thin lens */ - const P_LENS = _svg(`${_grid('rgba(255,255,255,0.04)')} - - - - - - - - - `); - - /* 16 — Refraction */ - const P_REFRACTION = _svg(` - - - - - - - - - - - α - β - n₁sinα = n₂sinβ`); - - /* 17 — Mirrors */ - const P_MIRROR = _svg(`${_grid('rgba(255,255,255,0.04)')} - - - - - - - - - F - - - - - - - - `); - - /* 18 — Isoprocesses */ - const P_ISOPROCESS = _svg(`${_grid('rgba(255,255,255,0.04)')} - - - - - - - - - - 2 - 1 - V - P`); - - /* ── Chemistry / Molecular Physics previews ── */ - const P_GAS = _svg(` - - - ${[ - [40,30,'#4CC9F0'],[70,80,'#7BF5A4'],[110,25,'#EF476F'],[150,60,'#FFD166'],[190,30,'#4CC9F0'], - [220,90,'#EF476F'],[55,110,'#7BF5A4'],[95,65,'#4CC9F0'],[130,110,'#EF476F'],[170,40,'#FFD166'], - [210,115,'#4CC9F0'],[240,55,'#7BF5A4'],[30,70,'#FFD166'],[80,120,'#EF476F'],[165,95,'#4CC9F0'] - ].map(([x,y,c])=>``).join('')} - - - - - - - - PV=nRT`); - - - /* ── Законы Ньютона ── */ - const P_NEWTON = _svg(` - - - - - - F - - - - m₂ - - - a = F/m · III законы Ньютона`); - - /* ── Песочница сил ── */ - const P_SANDBOX = _svg(` - - ${_grid('rgba(255,255,255,0.03)')} - - - 5кг - - 8кг - - - - - - - F₁ - F₂ - Песочница сил · F = ma`); - - const P_HYDRO = _svg(` - - ${_grid('rgba(255,255,255,0.03)')} - - - - - P = ρgh - - - - F_A - - - - - - - - - Δh - - - - - - - - - - Архимед · Паскаль · капиллярность`); - - /* ── coming soon chem previews (simple) ── */ - const P_KINETICS = _svg(` - - ${_grid()} - - - - - [C] продукт - [A] реагент`); - - const P_EQUILIBRIUM = _svg(` - - A + B ⇌ C + D - - - - A,B - K - C,D`); - - const P_ELECTROLYSIS = _svg(` - - - - - ${[55,58,61,64,67,70].map(x=>``).join('')} - ${[210,214,218,222,226].map(x=>``).join('')} - - +`); - - const P_BOHR = _svg(` - - - - - - - - - - `); - - const P_ORBITALS = _svg(` - - - - - - `); - - const P_PH = _svg(` - - ${_grid()} - - - pH - V`); - - const P_CHEMSANDBOX = _svg(` - - ${_grid()} - - - - - - A + B C + D - - - - - - - - `); - - const P_STOICHIOMETRY = _svg(` - - ${_grid()} - - - - - - Zn - - - - - - - 2HCl - - - - - - - ZnCl₂ - - - - H₂ - ● лимит`); - - /* Periodic Table — 6×4 coloured cell grid */ - const P_PERIODIC = _svg(` - - ${(function(){ - const cols=18,rows=4,pad=6,w=(270-pad*2)/cols,h=(140-pad*2)/rows; - const colors=['#EF476F','#FF6B35','#FFD166','#7BF5A4','#C77DFF','#A8DADC', - '#7B8EF7','#06D6E0','#9B5DE5','#F15BB5','#EF476F','#FF6B35', - '#06D6E0','#7B8EF7','#FFD166','#C77DFF','#A8DADC','#7BF5A4']; - let s=''; - for(let r=0;r=2&&c<=15)||(r===1&&c>=2&&c<=11); - if(!skip) s+=``; - } - return s; - })()} - 118 элементов`); - - const P_CRYSTAL = _svg(` - - ${[ - [80,40],[135,40],[190,40], - [55,75],[110,75],[165,75],[220,75], - [80,110],[135,110],[190,110] - ].map(([x,y],i)=>``).join('')} - - - - - - - - - - - `); - - const P_CELLDIVISION = _svg(` - - - - - - - - - - - - - - - - - - - - - Метафаза · митоз`); - - const P_PHOTOSYNTHESIS = _svg(` - - - - - - - - - - - - H₂O - CO₂ - ATP - G3P - Световые реакции · цикл Кальвина`); - - const P_ANGRYBIRDS = _svg(` - - - - - - - - - - - - - - - - - - - Физика полёта · импульс · разрушение`); - - const P_WAVES = _svg(`${_grid()} - - - - - v = \u03bbf \u00b7 y = A sin(\u03c9t \u2212 kx) \u00b7 \u0441\u0442\u043e\u044f\u0447\u0438\u0435 \u0432\u043e\u043b\u043d\u044b`); - - /* Radioactive decay preview */ - const P_RADIOACTIVE = _svg(`${_grid()} - - - - - - - - - - - - - - N(t) = N₀·e⁻λt · T½ · цепочки распада`); - - /* Heat Engines preview */ - const P_HEATENGINE = _svg(`${_grid('rgba(255,255,255,0.04)')} - - - - - - - - - - A - B - C - V - P - η = 1 − Tc/Th`); - - /* Geometry (planimetry) preview */ - const P_GEOMETRY = _svg(`${_grid('rgba(255,255,255,0.04)')} - - - - - - - - - - A - B - C`); - - - /* Race sim preview — two objects on a track, x(t) lines */ - const P_RACE = _svg(`${_grid('rgba(255,255,255,0.05)')} - - - - - - - - встреча - x = x₀ + v₀t + at²/2`); - - /* Logic Circuits preview */ - const P_LOGIC = _svg(`${_grid('rgba(255,255,255,0.04)')} - - AND - - XOR - - AND - - - - - - - - - - - S - C - S = A⊕B · C = A∧B · Таблица истинности`); - - - /* Qualitative Analysis preview */ - const P_QUALANALYSIS = _svg(` - - - - - - - - - - - Cl - Fe(III) - SO4 - AgNO3 - - - - AgCl / Fe(SCN) / BaSO4`); - - /* Organic Chemistry preview — benzene ring + OH group */ - const P_ORGANIC = _svg(` - - ${_grid('rgba(255,255,255,0.03)')} - - - - - - C - C - C - C - C - C - - - - O - - - H - - - - C - Конструктор · Ряды · Качественные реакции`); - - /* Solutions preview */ - const P_SOLUTIONS = _svg(` - - - - - - - 20% - - - ω% - C-M - ν моль - ω = m₀/m​ · 100% - Калькулятор · Разбавление · Смешивание · S(T)`); - - const SIMS = [ +const SIMS = [ /* ── Математика ── */ { id: 'graph', cat: 'math', title: 'График функции', diff --git a/frontend/lab.html b/frontend/lab.html index abc74da..2c6ea77 100644 --- a/frontend/lab.html +++ b/frontend/lab.html @@ -425,6 +425,7 @@ +