TRIOS Theme Central Control
AEL v2.0 | GO. Target: /Users/playra/BrowserOS
ЧТО ДЕЛАТЬ
Создать единый файл theme.ts — всё читает из него.
packages/shared/src/constants/theme.ts ← ТОЛЬКО ЗДЕСЬ меняй цвет
│
├── global.css (авто-генерация через generate:css)
├── theme-storage.ts (импорт напрямую)
└── browseros_prefs.cc (через generate:cpp)
Step 1: Создать packages/shared/src/constants/theme.ts
// TRIOS Theme — Single Source of Truth
// Изменяй ТОЛЬКО ЗДЕСЬ
export const TRIOS_THEME = {
// Дефолт режим: 'dark' | 'light' | 'system'
defaultMode: 'dark' as const,
// Основные цвета (oklch)
dark: {
background: 'oklch(0 0 0)',
foreground: 'oklch(0.93 0 0)',
card: 'oklch(0.04 0 0)',
cardForeground: 'oklch(0.93 0 0)',
popover: 'oklch(0.04 0 0)',
popoverForeground: 'oklch(0.93 0 0)',
primary: 'oklch(0.705 0.213 47.604)',
primaryForeground: 'oklch(0.98 0.016 73.684)',
secondary: 'oklch(0.08 0 0)',
secondaryForeground:'oklch(0.93 0 0)',
muted: 'oklch(0.08 0 0)',
mutedForeground: 'oklch(0.60 0 0)',
accent: 'oklch(0.12 0 0)',
accentForeground: 'oklch(0.93 0 0)',
destructive: 'oklch(0.704 0.191 22.216)',
destructiveForeground: 'oklch(0.93 0 0)',
border: 'oklch(0.16 0 0)',
input: 'oklch(0.12 0 0)',
ring: 'oklch(0.408 0.123 38.172)',
sidebar: 'oklch(0 0 0)',
sidebarForeground: 'oklch(0.93 0 0)',
sidebarBorder: 'oklch(0.16 0 0)',
// BrowserOS brand
accentOrange: 'oklch(0.6781 0.1663 43.21)',
accentOrangeBright: 'oklch(0.7531 0.1963 43.21)',
},
light: {
background: 'oklch(0 0 0)', // тоже чёрный — TRIOS всегда тёмный
foreground: 'oklch(0.93 0 0)',
card: 'oklch(0.04 0 0)',
cardForeground: 'oklch(0.93 0 0)',
popover: 'oklch(0.04 0 0)',
popoverForeground: 'oklch(0.93 0 0)',
primary: 'oklch(0.705 0.213 47.604)',
primaryForeground: 'oklch(0.98 0.016 73.684)',
secondary: 'oklch(0.06 0 0)',
secondaryForeground:'oklch(0.93 0 0)',
muted: 'oklch(0.06 0 0)',
mutedForeground: 'oklch(0.58 0 0)',
accent: 'oklch(0.10 0 0)',
accentForeground: 'oklch(0.93 0 0)',
destructive: 'oklch(0.577 0.245 27.325)',
destructiveForeground: 'oklch(0.99 0 0)',
border: 'oklch(0.14 0 0)',
input: 'oklch(0.10 0 0)',
ring: 'oklch(0.75 0.183 55.934)',
sidebar: 'oklch(0 0 0)',
sidebarForeground: 'oklch(0.93 0 0)',
sidebarBorder: 'oklch(0.14 0 0)',
accentOrange: 'oklch(0.6781 0.1663 43.21)',
accentOrangeBright: 'oklch(0.7531 0.1963 43.21)',
},
// Chromium C++ значения
chromium: {
// RGB(0,0,0) = 0x000000 = pure black frame
frameColorR: 0x00,
frameColorG: 0x00,
frameColorB: 0x00,
// BrowserColorScheme: 0=system, 1=light, 2=dark
colorScheme: 2,
},
} as const
export type ThemeMode = typeof TRIOS_THEME.defaultMode
export type ThemeColors = typeof TRIOS_THEME.dark
Step 2: Обновить packages/shared/src/index.ts
export * from './constants/theme'
// ... остальные экспорты
Step 3: Обновить theme-storage.ts — импорт из shared
File: packages/browseros-agent/apps/agent/lib/theme/theme-storage.ts
import { storage } from '@wxt-dev/storage'
import { TRIOS_THEME } from '@browseros/shared/constants/theme'
export type Theme = 'light' | 'dark' | 'system'
const DEV_FALLBACK: Theme = TRIOS_THEME.defaultMode
const isWxtContext = typeof chrome !== 'undefined' && chrome?.storage != null
export const themeStorage = isWxtContext
? storage.defineItem<Theme>('local:theme', { fallback: DEV_FALLBACK })
: {
getValue: async (): Promise<Theme> => {
try { return (localStorage.getItem('theme') as Theme) ?? DEV_FALLBACK }
catch { return DEV_FALLBACK }
},
setValue: async (value: Theme): Promise<void> => {
try { localStorage.setItem('theme', value) } catch {}
},
watch: (_cb: (value: Theme) => void) => () => {},
}
Step 4: Генерация global.css из theme.ts
Создать packages/browseros/tools/generate_css_from_theme.mjs:
#!/usr/bin/env node
// Reads TRIOS_THEME from shared/src/constants/theme.ts
// Writes :root and .dark blocks in global.css
import { readFileSync, writeFileSync } from 'fs'
import { resolve, dirname } from 'path'
import { fileURLToPath } from 'url'
const __dir = dirname(fileURLToPath(import.meta.url))
const ROOT = resolve(__dir, '../..')
// Dynamic import of theme constants
const { TRIOS_THEME } = await import(
resolve(ROOT, 'shared/src/constants/theme.ts')
).catch(() => {
// Fallback: read raw TS and eval with regex
const src = readFileSync(
resolve(ROOT, 'shared/src/constants/theme.ts'), 'utf8'
)
// Simple extraction via regex
const match = src.match(/dark:\s*\{([\s\S]+?)\},\s*light:/)
if (!match) throw new Error('Cannot parse theme.ts')
return { TRIOS_THEME: { dark: parseCssObj(match[1]), light: {} } }
})
function camelToKebab(str) {
return str.replace(/([A-Z])/g, '-$1').toLowerCase()
}
function themeToCSS(colors, selector) {
const vars = Object.entries(colors)
.map(([k, v]) => ` --${camelToKebab(k)}: ${v};`)
.join('\n')
return `${selector} {\n${vars}\n}`
}
const CSS_FILE = resolve(
ROOT,
'browseros-agent/apps/agent/styles/global.css'
)
let css = readFileSync(CSS_FILE, 'utf8')
const rootBlock = themeToCSS(TRIOS_THEME.light, ':root')
const darkBlock = themeToCSS(TRIOS_THEME.dark, '.dark')
// Preserve non-color :root vars (--radius, --chart-*, fonts, --accent-orange)
// Only replace color vars section
css = css
.replace(/:root\s*\{[\s\S]*?\}\s*(?=\.dark)/, rootBlock + '\n\n')
.replace(/\.dark\s*\{[\s\S]*?\}\s*(?=@theme)/, darkBlock + '\n\n')
writeFileSync(CSS_FILE, css)
console.log('✓ global.css updated from theme.ts')
Добавить в корневой package.json:
"theme:sync": "node packages/browseros/tools/generate_css_from_theme.mjs",
"theme:apply": "python3 packages/browseros/tools/set_dark_theme.py",
"theme:all": "bun run theme:sync && bun run theme:apply"
Step 5: Обновить Chromium патч browseros_prefs.cc
File: packages/browseros/chromium_patches/chrome/browser/browseros/core/browseros_prefs.cc
Изменить SyncDefaultTheme:
void SyncDefaultTheme(PrefService* pref_service) {
const PrefService::Preference* user_color_pref =
pref_service->FindPreference(::prefs::kUserColor);
if (user_color_pref && user_color_pref->IsDefaultValue()) {
pref_service->SetInteger(::prefs::kUserColor,
- static_cast<int>(SkColorSetRGB(136, 136, 136)));
+ static_cast<int>(SkColorSetRGB(0x00, 0x00, 0x00)));
pref_service->SetString(::prefs::kCurrentThemeID,
"user_color_theme_id");
pref_service->SetInteger(
::prefs::kBrowserColorVariant,
static_cast<int>(ui::mojom::BrowserColorVariant::kNeutral));
+ pref_service->SetInteger(
+ ::prefs::kBrowserColorScheme,
+ 2); // kDark = 2
}
}
File: packages/browseros/chromium_patches/chrome/browser/themes/theme_service.cc
- static_cast<int>(ThemeService::BrowserColorScheme::kLight),
+ static_cast<int>(ThemeService::BrowserColorScheme::kDark),
- static_cast<int>(ThemeService::BrowserColorScheme::kLight));
+ static_cast<int>(ThemeService::BrowserColorScheme::kDark));
Step 6: Runtime fix — set_dark_theme.py
Создать packages/browseros/tools/set_dark_theme.py:
#!/usr/bin/env python3
"""Apply TRIOS ultra-black theme to BrowserOS profile. No rebuild needed."""
import json, pathlib, sys
PREFS = pathlib.Path.home() / \
'Library/Application Support/BrowserOS/Default/Preferences'
if not PREFS.exists():
sys.exit(f'Profile not found: {PREFS}')
data = json.loads(PREFS.read_text())
browser = data.setdefault('browser', {})
# kDark = 2
browser['color_scheme2'] = 2
# Pure black: SkColor ARGB = 0xFF000000 = 4278190080
browser['user_color2'] = 4278190080
# Clear cached theme to force recompute
if 'extensions' in data and 'theme' in data['extensions']:
data['extensions']['theme'] = {'id': '', 'pack_hash': ''}
PREFS.write_text(json.dumps(data, indent=2))
print('✓ TRIOS ultra-black applied. Restart BrowserOS.')
Step 7: Проверить что @browseros/shared есть в workspace
# Проверить package.json shared
cat packages/shared/package.json | grep '"name"'
# Должно быть: "@browseros/shared"
# Проверить workspace
cat package.json | grep -A5 'workspaces'
Если packages/shared не есть — создать:
mkdir -p packages/shared/src/constants
cat > packages/shared/package.json << 'EOF'
{
"name": "@browseros/shared",
"version": "0.0.1",
"exports": {
"./constants/theme": "./src/constants/theme.ts"
}
}
EOF
Verification
# 1. Создать theme.ts
ls packages/shared/src/constants/theme.ts
# 2. Синх CSS
bun run theme:sync
# Должно вывести: ✓ global.css updated from theme.ts
# 3. Runtime применение
bun run theme:apply
# 4. Проверить CSS
grep 'background' packages/browseros-agent/apps/agent/styles/global.css | head -3
# Должно: --background: oklch(0 0 0);
# 5. bun dev — чёрный фон
bun dev
Commit
feat(theme): TRIOS_THEME central control — shared/constants/theme.ts | Closes #[this]
φ² + 1/φ² = 3 | TRINITY DARK #000000
TRIOS Theme Central Control
ЧТО ДЕЛАТЬ
Создать единый файл
theme.ts— всё читает из него.Step 1: Создать
packages/shared/src/constants/theme.tsStep 2: Обновить
packages/shared/src/index.tsStep 3: Обновить
theme-storage.ts— импорт из sharedFile:
packages/browseros-agent/apps/agent/lib/theme/theme-storage.tsStep 4: Генерация global.css из theme.ts
Создать
packages/browseros/tools/generate_css_from_theme.mjs:Добавить в корневой
package.json:Step 5: Обновить Chromium патч
browseros_prefs.ccFile:
packages/browseros/chromium_patches/chrome/browser/browseros/core/browseros_prefs.ccИзменить
SyncDefaultTheme:void SyncDefaultTheme(PrefService* pref_service) { const PrefService::Preference* user_color_pref = pref_service->FindPreference(::prefs::kUserColor); if (user_color_pref && user_color_pref->IsDefaultValue()) { pref_service->SetInteger(::prefs::kUserColor, - static_cast<int>(SkColorSetRGB(136, 136, 136))); + static_cast<int>(SkColorSetRGB(0x00, 0x00, 0x00))); pref_service->SetString(::prefs::kCurrentThemeID, "user_color_theme_id"); pref_service->SetInteger( ::prefs::kBrowserColorVariant, static_cast<int>(ui::mojom::BrowserColorVariant::kNeutral)); + pref_service->SetInteger( + ::prefs::kBrowserColorScheme, + 2); // kDark = 2 } }File:
packages/browseros/chromium_patches/chrome/browser/themes/theme_service.ccStep 6: Runtime fix —
set_dark_theme.pyСоздать
packages/browseros/tools/set_dark_theme.py:Step 7: Проверить что
@browseros/sharedесть в workspaceЕсли
packages/sharedне есть — создать:Verification
packages/shared/src/constants/theme.tsсозданtheme-storage.tsимпортируетTRIOS_THEME.defaultModegenerate_css_from_theme.mjsобновляетglobal.cssset_dark_theme.pyприменяет рунтаймbrowseros_prefs.ccиспользуетRGB(0,0,0)иkDark=2theme_service.ccиспользуетkDarkbun dev→ чистый чёрный фонCommit
φ² + 1/φ² = 3 | TRINITY DARK #000000