feat(phys9): единая палитра цветов PHYS9_COLORS (Phase 2)
Новый модуль frontend/js/phys9_palette.js — экспортирует
window.PHYS9_COLORS с цветами для всех кинематических, динамических,
энергетических и геометрических величин Физики 9.
Структура палитры:
- velocity / acceleration / displacement / position / time
- force / forceGravity / forceFriction / forceNormal / forceSpring /
forceTension
- energyK / energyP / work / power
- body / bodyAccent / liquid / gas / surface
- angle / axis / grid / dashed
- plotPrimary / plotSecondary / plotTertiary
- text / textMuted / textLabel
- bg / bgSubtle / bgCard
- ok / warn / fail
Палитра автоматически переключается между светлой и тёмной темой
через get-проперти, проверяющий html.dark / body.dark.
Утилиты:
- PHYS9_COLORS.vector('F'|'v'|'mg'|...) — цвет вектора по типу
- PHYS9_COLORS.byClass('kinematic'|'dynamic'|...) — цвет по классу
Подключён во все 5 ch-страниц до phys9_legacy.js.
Подготовка к Phase 3 — перенос hardcoded #цветов в legacy на ссылки
PHYS9_COLORS.*.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
// phys9_palette.js — единая палитра цветов для всех визуализаций Физики 9.
|
||||
// Экспорт в window.PHYS9_COLORS. Используется в phys9_legacy.js для canvas/SVG.
|
||||
// Цвета синхронизированы с phys.js и optics.js (Физика 8).
|
||||
(function(){
|
||||
'use strict';
|
||||
|
||||
// === Базовые цвета (для светлой темы) ===
|
||||
const LIGHT = {
|
||||
/* Кинематические величины */
|
||||
velocity: '#0891b2', /* cyan-600 — скорость v */
|
||||
acceleration: '#ea580c', /* orange-600 — ускорение a */
|
||||
displacement: '#2563eb', /* blue-600 — перемещение Δr */
|
||||
position: '#475569', /* slate-600 — положение */
|
||||
time: '#6b7280', /* gray-500 — ось времени */
|
||||
|
||||
/* Динамические величины */
|
||||
force: '#10b981', /* emerald-500 — сила F */
|
||||
forceGravity: '#2563eb', /* blue-600 — сила тяжести mg */
|
||||
forceFriction:'#7c3aed', /* violet-600 — трение */
|
||||
forceNormal: '#94a3b8', /* slate-400 — реакция опоры N */
|
||||
forceSpring: '#d97706', /* amber-600 — упругая сила */
|
||||
forceTension: '#16a34a', /* green-600 — натяжение нити */
|
||||
|
||||
/* Энергетика */
|
||||
energyK: '#dc2626', /* red-600 — кинетическая Ek */
|
||||
energyP: '#2563eb', /* blue-600 — потенциальная Ep */
|
||||
work: '#9333ea', /* purple-600 — работа A */
|
||||
power: '#db2777', /* pink-600 — мощность N */
|
||||
|
||||
/* Тела */
|
||||
body: '#475569', /* slate-600 — основной цвет тела */
|
||||
bodyAccent: '#1e293b', /* slate-800 — обводка/штрих */
|
||||
bodyLight: '#cbd5e1', /* slate-300 — заливка для светлых тел */
|
||||
surface: '#a16207', /* yellow-700 — поверхность/опора */
|
||||
liquid: '#3b82f6', /* blue-500 — жидкость */
|
||||
liquidLight: '#bfdbfe', /* blue-200 — поверхность жидкости */
|
||||
gas: '#dbeafe', /* blue-100 — газ/воздух */
|
||||
|
||||
/* Углы и геометрия */
|
||||
angle: '#dc2626', /* red-600 — углы α, β, φ */
|
||||
axis: '#1e293b', /* slate-800 — координатные оси */
|
||||
grid: '#e5e7eb', /* gray-200 — сетка */
|
||||
dashed: '#94a3b8', /* slate-400 — пунктир/перпендикуляр */
|
||||
|
||||
/* Графики */
|
||||
plotPrimary: '#dc2626', /* основной график */
|
||||
plotSecondary:'#2563eb', /* второй график для сравнения */
|
||||
plotTertiary: '#10b981', /* третий график */
|
||||
|
||||
/* Текст и подписи на канвасе */
|
||||
text: '#0f172a', /* slate-900 — главный текст */
|
||||
textMuted: '#64748b', /* slate-500 — приглушённый текст */
|
||||
textLabel: '#1e293b', /* slate-800 — подписи переменных */
|
||||
|
||||
/* Фоны */
|
||||
bg: '#fafafa', /* фон сцены */
|
||||
bgSubtle: '#f8fafc', /* мягкий фон */
|
||||
bgCard: '#ffffff', /* карточка */
|
||||
|
||||
/* Состояния */
|
||||
ok: '#16a34a', /* зелёный — успех */
|
||||
warn: '#f59e0b', /* янтарный — внимание */
|
||||
fail: '#dc2626' /* красный — ошибка */
|
||||
};
|
||||
|
||||
// === Цвета для тёмной темы ===
|
||||
const DARK = {
|
||||
velocity: '#22d3ee',
|
||||
acceleration: '#fb923c',
|
||||
displacement: '#60a5fa',
|
||||
position: '#94a3b8',
|
||||
time: '#9ca3af',
|
||||
force: '#34d399',
|
||||
forceGravity: '#60a5fa',
|
||||
forceFriction:'#a78bfa',
|
||||
forceNormal: '#cbd5e1',
|
||||
forceSpring: '#fbbf24',
|
||||
forceTension: '#4ade80',
|
||||
energyK: '#f87171',
|
||||
energyP: '#60a5fa',
|
||||
work: '#c084fc',
|
||||
power: '#f472b6',
|
||||
body: '#94a3b8',
|
||||
bodyAccent: '#e2e8f0',
|
||||
bodyLight: '#64748b',
|
||||
surface: '#ca8a04',
|
||||
liquid: '#60a5fa',
|
||||
liquidLight: '#3b82f6',
|
||||
gas: '#1e3a8a',
|
||||
angle: '#f87171',
|
||||
axis: '#e2e8f0',
|
||||
grid: '#374151',
|
||||
dashed: '#94a3b8',
|
||||
plotPrimary: '#f87171',
|
||||
plotSecondary:'#60a5fa',
|
||||
plotTertiary: '#34d399',
|
||||
text: '#f1f5f9',
|
||||
textMuted: '#94a3b8',
|
||||
textLabel: '#e2e8f0',
|
||||
bg: '#0f172a',
|
||||
bgSubtle: '#1e293b',
|
||||
bgCard: '#1f2937',
|
||||
ok: '#4ade80',
|
||||
warn: '#fbbf24',
|
||||
fail: '#f87171'
|
||||
};
|
||||
|
||||
// === Активная палитра — возвращает значения текущей темы ===
|
||||
function isDark(){
|
||||
try {
|
||||
return document.documentElement.classList.contains('dark') ||
|
||||
document.body.classList.contains('dark');
|
||||
} catch(e){ return false; }
|
||||
}
|
||||
|
||||
// Объект, который пересчитывает значения через геттеры
|
||||
const PHYS9_COLORS = {};
|
||||
for (const key of Object.keys(LIGHT)) {
|
||||
Object.defineProperty(PHYS9_COLORS, key, {
|
||||
enumerable: true,
|
||||
configurable: false,
|
||||
get(){ return isDark() ? (DARK[key] || LIGHT[key]) : LIGHT[key]; }
|
||||
});
|
||||
}
|
||||
|
||||
// === Утилиты ===
|
||||
|
||||
// Получить цвет вектора по типу величины (для drawArrow и т.п.)
|
||||
PHYS9_COLORS.vector = function(kind){
|
||||
switch(kind){
|
||||
case 'v': case 'velocity': return PHYS9_COLORS.velocity;
|
||||
case 'a': case 'acceleration': return PHYS9_COLORS.acceleration;
|
||||
case 'F': case 'force': return PHYS9_COLORS.force;
|
||||
case 'mg': case 'gravity': return PHYS9_COLORS.forceGravity;
|
||||
case 'N': case 'normal': return PHYS9_COLORS.forceNormal;
|
||||
case 'Ftr': case 'friction': return PHYS9_COLORS.forceFriction;
|
||||
case 'Fspr': case 'spring': return PHYS9_COLORS.forceSpring;
|
||||
case 'T': case 'tension': return PHYS9_COLORS.forceTension;
|
||||
default: return PHYS9_COLORS.text;
|
||||
}
|
||||
};
|
||||
|
||||
// Получить цвет по классу величины (kinematic / dynamic / energy / geometry)
|
||||
PHYS9_COLORS.byClass = function(cls){
|
||||
switch(cls){
|
||||
case 'kinematic': return PHYS9_COLORS.velocity;
|
||||
case 'dynamic': return PHYS9_COLORS.force;
|
||||
case 'energy': return PHYS9_COLORS.energyK;
|
||||
case 'geometry': return PHYS9_COLORS.angle;
|
||||
default: return PHYS9_COLORS.text;
|
||||
}
|
||||
};
|
||||
|
||||
// Полная схема для тёмной/светлой — для отладки
|
||||
PHYS9_COLORS._LIGHT = LIGHT;
|
||||
PHYS9_COLORS._DARK = DARK;
|
||||
|
||||
window.PHYS9_COLORS = PHYS9_COLORS;
|
||||
|
||||
})();
|
||||
@@ -15,6 +15,7 @@
|
||||
<script src="/js/api.js" defer></script>
|
||||
<script src="/js/xp.js" defer></script>
|
||||
<script src="/js/phys.js" defer></script>
|
||||
<script src="/js/phys9_palette.js" defer></script>
|
||||
<script src="/js/phys9_legacy.js" defer></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Manrope:wght@600;700;800;900&family=Unbounded:wght@700;800;900&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
<script src="/js/api.js" defer></script>
|
||||
<script src="/js/xp.js" defer></script>
|
||||
<script src="/js/phys.js" defer></script>
|
||||
<script src="/js/phys9_palette.js" defer></script>
|
||||
<script src="/js/phys9_legacy.js" defer></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Manrope:wght@600;700;800;900&family=Unbounded:wght@700;800;900&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
<script src="/js/api.js" defer></script>
|
||||
<script src="/js/xp.js" defer></script>
|
||||
<script src="/js/phys.js" defer></script>
|
||||
<script src="/js/phys9_palette.js" defer></script>
|
||||
<script src="/js/phys9_legacy.js" defer></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Manrope:wght@600;700;800;900&family=Unbounded:wght@700;800;900&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
<script src="/js/api.js" defer></script>
|
||||
<script src="/js/xp.js" defer></script>
|
||||
<script src="/js/phys.js" defer></script>
|
||||
<script src="/js/phys9_palette.js" defer></script>
|
||||
<script src="/js/phys9_legacy.js" defer></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Manrope:wght@600;700;800;900&family=Unbounded:wght@700;800;900&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
<script src="/js/api.js" defer></script>
|
||||
<script src="/js/xp.js" defer></script>
|
||||
<script src="/js/phys.js" defer></script>
|
||||
<script src="/js/phys9_palette.js" defer></script>
|
||||
<script src="/js/phys9_legacy.js" defer></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Manrope:wght@600;700;800;900&family=Unbounded:wght@700;800;900&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
Reference in New Issue
Block a user