Convert all Figma theme backgrounds to dark/colored, dedupe again
The 34 kept themes were split 24 light-mode / 18 dark-mode - the light ones all shared the same washed-out near-white background (L=0.95), too bright per feedback. Added a force_mood override to build_theme() and regenerated all 24 as dark instead, same accent character, colored- dark background rather than near-white. That conversion collapsed a lot of previously-distinct light backgrounds into similar dark neutrals, so re-ran the same color-distance dedup pass across the full set: 8 more turned out to be near-twins once everything converged to dark (including a 3-way orange-on-dark cluster trimmed to one). Net: 53 candidates -> 34 kept, all dark/colored, zero white backgrounds - down from the 42 (24 light/18 dark) shipped last commit. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -120,12 +120,13 @@ silently stay blank instead of erroring.
|
|||||||
- Per-course study guide export (markdown, organized by section)
|
- Per-course study guide export (markdown, organized by section)
|
||||||
|
|
||||||
**Personalization** (Settings)
|
**Personalization** (Settings)
|
||||||
- 54 built-in themes (grouped in the dropdown: Base, Editor Themes, and 5
|
- 46 built-in themes (grouped in the dropdown: Base, Editor Themes, and 5
|
||||||
categories of website-inspired schemes sourced from Figma's "53 Unique
|
categories of website-inspired schemes sourced from Figma's "53 Unique
|
||||||
Website Color Schemes" - 42 of the 53 kept, after cutting a couple of
|
Website Color Schemes" - 34 of the 53 kept, all as dark/colored
|
||||||
neon-bright ones and several that ended up near-duplicates of another
|
backgrounds rather than the source page's mostly-white mockups, after
|
||||||
scheme once mapped into actual UI colors), or a fully custom accent
|
cutting a couple of neon-bright accents and pruning near-duplicates by
|
||||||
color, corner radius, and card style
|
actual color distance), or a fully custom accent color, corner radius,
|
||||||
|
and card style
|
||||||
- Font, text size, page width, and spacing density
|
- Font, text size, page width, and spacing density
|
||||||
- Default library path override + manual "Refresh Library" (bypasses the
|
- Default library path override + manual "Refresh Library" (bypasses the
|
||||||
5-minute filesystem-scan cache)
|
5-minute filesystem-scan cache)
|
||||||
@@ -199,10 +200,13 @@ folder and file names.
|
|||||||
## Tools
|
## Tools
|
||||||
|
|
||||||
`tools/generate_website_scheme_themes.py` is the one-off script that
|
`tools/generate_website_scheme_themes.py` is the one-off script that
|
||||||
produced the 42 "website scheme" theme entries in `THEME_PALETTES` (of
|
produced the 34 "website scheme" theme entries in `THEME_PALETTES` (of
|
||||||
53 candidates - 11 were cut after visual review, 2 for a neon-bright
|
53 candidates - all 24 light-mode ones were converted to dark/colored
|
||||||
accent and 9 for landing too close to another kept scheme once mapped
|
backgrounds per request, then 19 were cut across two review passes: 2
|
||||||
into actual UI colors) - not part of the running app, kept for reference
|
for a neon-bright accent, 17 for landing too close to another kept
|
||||||
if those palettes ever need regenerating or extending. See its module
|
scheme once mapped into actual UI colors, since forcing everything dark
|
||||||
docstring for how it turned Figma's color-scheme screenshots into actual
|
made several collide that hadn't before) - not part of the running app,
|
||||||
UI palettes.
|
kept for reference if those palettes ever need regenerating or
|
||||||
|
extending. `build_theme()` takes a `force_mood='dark'|'light'` override
|
||||||
|
for exactly this kind of bulk remapping. See its module docstring for
|
||||||
|
how it turned Figma's color-scheme screenshots into actual UI palettes.
|
||||||
|
|||||||
+82
-133
@@ -100,28 +100,25 @@ SETTINGS_CHOICES = {
|
|||||||
'theme': {
|
'theme': {
|
||||||
'dark', 'light', 'dracula', 'tokyo_night', 'catppuccin_mocha', 'ayu_dark',
|
'dark', 'light', 'dracula', 'tokyo_night', 'catppuccin_mocha', 'ayu_dark',
|
||||||
'github_dark', 'atom_one_dark', 'houston', 'night_owl', 'nord', 'matcha',
|
'github_dark', 'atom_one_dark', 'houston', 'night_owl', 'nord', 'matcha',
|
||||||
# 42 palettes derived from Figma's "53 Unique Website Color Schemes"
|
# 34 palettes derived from Figma's "53 Unique Website Color Schemes"
|
||||||
# resource page (11 of the 53 dropped: 2 for a neon-bright accent
|
# resource page, all converted to dark/colored backgrounds (the
|
||||||
# that read badly as a button color, the rest for being too close
|
# source page's own schemes were mostly light-mode marketing
|
||||||
# to another scheme already kept - same accent hue/lightness and
|
# mockups) - see WEBSITE_SCHEME_CATEGORIES below for the dropdown
|
||||||
# background, just a different name) - see WEBSITE_SCHEME_CATEGORIES
|
# grouping, and tools/generate_website_scheme_themes.py (a one-off
|
||||||
# below for the dropdown grouping, and
|
# content-generation script, not part of the running app) for how
|
||||||
# tools/generate_website_scheme_themes.py (a one-off content-
|
# the kept ones were built: dominant colors extracted per scheme,
|
||||||
# generation script, not part of the running app) for how the kept
|
# mapped into this app's bg/text/accent shape with automatic
|
||||||
# ones were built from that page's screenshots: dominant colors
|
# contrast adjustment against both the background and the white
|
||||||
# extracted per scheme, then mapped into this app's bg/text/accent
|
# button text, then deduplicated against each other by actual
|
||||||
# shape with automatic contrast adjustment against both the
|
# color distance (not eyeballed) once everything converged to dark.
|
||||||
# background and the white button text.
|
'ink_wash', 'jade_pebble_morning', 'woodland', 'graphite', 'pearl', 'yacht_club',
|
||||||
'ink_wash', 'jade_pebble_morning', 'woodland', 'graphite', 'urban_slate', 'pearl',
|
'amber_walnut_morning', 'copper_aquamarine_dream', 'sandstone_aquamarine_serenity',
|
||||||
'vichy', 'sorbet', 'yacht_club', 'amber_walnut_morning', 'copper_aquamarine_dream',
|
'honey_opal_sunset', 'seashell_garnet_afternoon', 'rose_quartz_evening', 'calcite',
|
||||||
'cocoa_topaz_noonday', 'sandstone_aquamarine_serenity', 'honey_opal_sunset',
|
'fireside', 'terrazzo', 'sapphire_nightfall_whisper', 'marina',
|
||||||
'seashell_garnet_afternoon', 'rose_quartz_evening', 'calcite', 'fireside', 'terrazzo',
|
'emerald_lavender_lake', 'sage_peridot_morning', 'amethyst_dawn_haze', 'royal_glimmer',
|
||||||
'sapphire_nightfall_whisper', 'marina', 'emerald_lavender_lake',
|
'neptune', 'tropical_heat', 'celestial', 'festive_eve', 'freshly_squeezed',
|
||||||
'sage_peridot_morning', 'amethyst_dawn_haze', 'turquoise_amber_autumn',
|
'jelly_shoes', 'lemon_granite_morning', 'arctic_reflection', 'slate', 'autumn_luxe',
|
||||||
'sapphire_ash_morning', 'royal_glimmer', 'neptune', 'tropical_heat', 'celestial',
|
'inked', 'wraith', 'urban_nocturne',
|
||||||
'festive_eve', 'freshly_squeezed', 'jelly_shoes', 'gossamer', 'clockwork',
|
|
||||||
'lemon_granite_morning', 'arctic_reflection', 'slate', 'autumn_luxe', 'inked',
|
|
||||||
'wraith', 'urban_nocturne',
|
|
||||||
},
|
},
|
||||||
'font_family': {'system', 'sans', 'serif', 'monospace', 'monaspace'},
|
'font_family': {'system', 'sans', 'serif', 'monospace', 'monaspace'},
|
||||||
'font_size': {'small', 'medium', 'large', 'xlarge'},
|
'font_size': {'small', 'medium', 'large', 'xlarge'},
|
||||||
@@ -144,14 +141,10 @@ THEME_DISPLAY_NAMES = {
|
|||||||
'jade_pebble_morning': 'Jade Pebble Morning',
|
'jade_pebble_morning': 'Jade Pebble Morning',
|
||||||
'woodland': 'Woodland',
|
'woodland': 'Woodland',
|
||||||
'graphite': 'Graphite',
|
'graphite': 'Graphite',
|
||||||
'urban_slate': 'Urban Slate',
|
|
||||||
'pearl': 'Pearl',
|
'pearl': 'Pearl',
|
||||||
'vichy': 'Vichy',
|
|
||||||
'sorbet': 'Sorbet',
|
|
||||||
'yacht_club': 'Yacht Club',
|
'yacht_club': 'Yacht Club',
|
||||||
'amber_walnut_morning': 'Amber Walnut Morning',
|
'amber_walnut_morning': 'Amber Walnut Morning',
|
||||||
'copper_aquamarine_dream': 'Copper Aquamarine Dream',
|
'copper_aquamarine_dream': 'Copper Aquamarine Dream',
|
||||||
'cocoa_topaz_noonday': 'Cocoa Topaz Noonday',
|
|
||||||
'sandstone_aquamarine_serenity': 'Sandstone Aquamarine Serenity',
|
'sandstone_aquamarine_serenity': 'Sandstone Aquamarine Serenity',
|
||||||
'honey_opal_sunset': 'Honey Opal Sunset',
|
'honey_opal_sunset': 'Honey Opal Sunset',
|
||||||
'seashell_garnet_afternoon': 'Seashell Garnet Afternoon',
|
'seashell_garnet_afternoon': 'Seashell Garnet Afternoon',
|
||||||
@@ -164,8 +157,6 @@ THEME_DISPLAY_NAMES = {
|
|||||||
'emerald_lavender_lake': 'Emerald Lavender Lake',
|
'emerald_lavender_lake': 'Emerald Lavender Lake',
|
||||||
'sage_peridot_morning': 'Sage Peridot Morning',
|
'sage_peridot_morning': 'Sage Peridot Morning',
|
||||||
'amethyst_dawn_haze': 'Amethyst Dawn Haze',
|
'amethyst_dawn_haze': 'Amethyst Dawn Haze',
|
||||||
'turquoise_amber_autumn': 'Turquoise Amber Autumn',
|
|
||||||
'sapphire_ash_morning': 'Sapphire Ash Morning',
|
|
||||||
'royal_glimmer': 'Royal Glimmer',
|
'royal_glimmer': 'Royal Glimmer',
|
||||||
'neptune': 'Neptune',
|
'neptune': 'Neptune',
|
||||||
'tropical_heat': 'Tropical Heat',
|
'tropical_heat': 'Tropical Heat',
|
||||||
@@ -173,8 +164,6 @@ THEME_DISPLAY_NAMES = {
|
|||||||
'festive_eve': 'Festive Eve',
|
'festive_eve': 'Festive Eve',
|
||||||
'freshly_squeezed': 'Freshly Squeezed',
|
'freshly_squeezed': 'Freshly Squeezed',
|
||||||
'jelly_shoes': 'Jelly Shoes',
|
'jelly_shoes': 'Jelly Shoes',
|
||||||
'gossamer': 'Gossamer',
|
|
||||||
'clockwork': 'Clockwork',
|
|
||||||
'lemon_granite_morning': 'Lemon Granite Morning',
|
'lemon_granite_morning': 'Lemon Granite Morning',
|
||||||
'arctic_reflection': 'Arctic Reflection',
|
'arctic_reflection': 'Arctic Reflection',
|
||||||
'slate': 'Slate',
|
'slate': 'Slate',
|
||||||
@@ -260,16 +249,16 @@ THEME_PALETTES = {
|
|||||||
'bg-tertiary-hover': '#3c4850', 'text-primary': '#d1ded3', 'text-muted': '#7c8885',
|
'bg-tertiary-hover': '#3c4850', 'text-primary': '#d1ded3', 'text-muted': '#7c8885',
|
||||||
'border-color': '#707c4f', 'accent': '#a4b07e', 'accent-hover': '#8b966b',
|
'border-color': '#707c4f', 'accent': '#a4b07e', 'accent-hover': '#8b966b',
|
||||||
},
|
},
|
||||||
# --- Minimal & Neutral (from Figma's "53 Unique Website Color Schemes") ---
|
# --- Minimal & Neutral (from Figma's "53 Unique Website Color Schemes", converted to dark backgrounds) ---
|
||||||
'ink_wash': {
|
'ink_wash': {
|
||||||
'bg-primary': '#202020', 'bg-secondary': '#323232', 'bg-tertiary': '#444444',
|
'bg-primary': '#202020', 'bg-secondary': '#323232', 'bg-tertiary': '#444444',
|
||||||
'bg-tertiary-hover': '#4b4b4b', 'text-primary': '#e6e6e6', 'text-muted': '#9e9e9e',
|
'bg-tertiary-hover': '#4b4b4b', 'text-primary': '#e6e6e6', 'text-muted': '#9e9e9e',
|
||||||
'border-color': '#494949', 'accent': '#2990d6', 'accent-hover': '#2173ab',
|
'border-color': '#494949', 'accent': '#2990d6', 'accent-hover': '#2173ab',
|
||||||
},
|
},
|
||||||
'jade_pebble_morning': {
|
'jade_pebble_morning': {
|
||||||
'bg-primary': '#f2f4f1', 'bg-secondary': '#ffffff', 'bg-tertiary': '#edefeb',
|
'bg-primary': '#242d24', 'bg-secondary': '#344134', 'bg-tertiary': '#445544',
|
||||||
'bg-tertiary-hover': '#e0e5dc', 'text-primary': '#242522', 'text-muted': '#6b7066',
|
'bg-tertiary-hover': '#4b5e4b', 'text-primary': '#e5e6e5', 'text-muted': '#9ba19b',
|
||||||
'border-color': '#d1d6cd', 'accent': '#659539', 'accent-hover': '#4c702b',
|
'border-color': '#495b49', 'accent': '#9dca73', 'accent-hover': '#83bc4e',
|
||||||
},
|
},
|
||||||
'woodland': {
|
'woodland': {
|
||||||
'bg-primary': '#323220', 'bg-secondary': '#48482e', 'bg-tertiary': '#5d5d3c',
|
'bg-primary': '#323220', 'bg-secondary': '#48482e', 'bg-tertiary': '#5d5d3c',
|
||||||
@@ -277,50 +266,30 @@ THEME_PALETTES = {
|
|||||||
'border-color': '#646440', 'accent': '#acc927', 'accent-hover': '#879e1f',
|
'border-color': '#646440', 'accent': '#acc927', 'accent-hover': '#879e1f',
|
||||||
},
|
},
|
||||||
'graphite': {
|
'graphite': {
|
||||||
'bg-primary': '#f4f1f1', 'bg-secondary': '#ffffff', 'bg-tertiary': '#efebeb',
|
'bg-primary': '#2c2c26', 'bg-secondary': '#3f3f37', 'bg-tertiary': '#525247',
|
||||||
'bg-tertiary-hover': '#e5dcdc', 'text-primary': '#252222', 'text-muted': '#706666',
|
'bg-tertiary-hover': '#5a5a4f', 'text-primary': '#e6e6e5', 'text-muted': '#a0a09c',
|
||||||
'border-color': '#d6cdcd', 'accent': '#d34646', 'accent-hover': '#ba2c2c',
|
'border-color': '#57574c', 'accent': '#e07b7b', 'accent-hover': '#d65252',
|
||||||
},
|
|
||||||
'urban_slate': {
|
|
||||||
'bg-primary': '#f4f1f1', 'bg-secondary': '#ffffff', 'bg-tertiary': '#efebeb',
|
|
||||||
'bg-tertiary-hover': '#e5dcdc', 'text-primary': '#252222', 'text-muted': '#706666',
|
|
||||||
'border-color': '#d6cdcd', 'accent': '#2174ab', 'accent-hover': '#195780',
|
|
||||||
},
|
},
|
||||||
'pearl': {
|
'pearl': {
|
||||||
'bg-primary': '#f2f1f4', 'bg-secondary': '#ffffff', 'bg-tertiary': '#ecebef',
|
'bg-primary': '#292929', 'bg-secondary': '#3b3b3b', 'bg-tertiary': '#4d4d4d',
|
||||||
'bg-tertiary-hover': '#dfdce5', 'text-primary': '#232225', 'text-muted': '#696670',
|
'bg-tertiary-hover': '#545454', 'text-primary': '#e6e6e6', 'text-muted': '#9e9e9e',
|
||||||
'border-color': '#d0cdd6', 'accent': '#bd7c3d', 'accent-hover': '#966331',
|
'border-color': '#525252', 'accent': '#d7ad84', 'accent-hover': '#ca935e',
|
||||||
},
|
|
||||||
'vichy': {
|
|
||||||
'bg-primary': '#f4f1f1', 'bg-secondary': '#ffffff', 'bg-tertiary': '#efebeb',
|
|
||||||
'bg-tertiary-hover': '#e5dcdc', 'text-primary': '#252222', 'text-muted': '#706666',
|
|
||||||
'border-color': '#d6cdcd', 'accent': '#1d968b', 'accent-hover': '#156b63',
|
|
||||||
},
|
|
||||||
'sorbet': {
|
|
||||||
'bg-primary': '#f4f1f1', 'bg-secondary': '#ffffff', 'bg-tertiary': '#efebeb',
|
|
||||||
'bg-tertiary-hover': '#e5dcdc', 'text-primary': '#252222', 'text-muted': '#706666',
|
|
||||||
'border-color': '#d6cdcd', 'accent': '#c07b59', 'accent-hover': '#a7613f',
|
|
||||||
},
|
},
|
||||||
'yacht_club': {
|
'yacht_club': {
|
||||||
'bg-primary': '#f4f1f1', 'bg-secondary': '#ffffff', 'bg-tertiary': '#efebeb',
|
'bg-primary': '#322720', 'bg-secondary': '#48382e', 'bg-tertiary': '#5d493c',
|
||||||
'bg-tertiary-hover': '#e5dcdc', 'text-primary': '#252222', 'text-muted': '#706666',
|
'bg-tertiary-hover': '#675042', 'text-primary': '#e7e5e4', 'text-muted': '#a49d98',
|
||||||
'border-color': '#d6cdcd', 'accent': '#97562b', 'accent-hover': '#6f3f20',
|
'border-color': '#644e40', 'accent': '#c67139', 'accent-hover': '#9e5a2e',
|
||||||
},
|
},
|
||||||
# --- Warm (from Figma's "53 Unique Website Color Schemes") ---
|
# --- Warm (from Figma's "53 Unique Website Color Schemes", converted to dark backgrounds) ---
|
||||||
'amber_walnut_morning': {
|
'amber_walnut_morning': {
|
||||||
'bg-primary': '#292929', 'bg-secondary': '#3b3b3b', 'bg-tertiary': '#4d4d4d',
|
'bg-primary': '#292929', 'bg-secondary': '#3b3b3b', 'bg-tertiary': '#4d4d4d',
|
||||||
'bg-tertiary-hover': '#545454', 'text-primary': '#e6e6e6', 'text-muted': '#9e9e9e',
|
'bg-tertiary-hover': '#545454', 'text-primary': '#e6e6e6', 'text-muted': '#9e9e9e',
|
||||||
'border-color': '#525252', 'accent': '#d09070', 'accent-hover': '#c3724a',
|
'border-color': '#525252', 'accent': '#d09070', 'accent-hover': '#c3724a',
|
||||||
},
|
},
|
||||||
'copper_aquamarine_dream': {
|
'copper_aquamarine_dream': {
|
||||||
'bg-primary': '#f4f4f1', 'bg-secondary': '#ffffff', 'bg-tertiary': '#efefeb',
|
'bg-primary': '#202c32', 'bg-secondary': '#2e3f48', 'bg-tertiary': '#3c525d',
|
||||||
'bg-tertiary-hover': '#e5e5dc', 'text-primary': '#252522', 'text-muted': '#707066',
|
'bg-tertiary-hover': '#425a67', 'text-primary': '#e4e6e7', 'text-muted': '#98a0a4',
|
||||||
'border-color': '#d6d6cd', 'accent': '#bc5224', 'accent-hover': '#913f1c',
|
'border-color': '#405864', 'accent': '#d65d29', 'accent-hover': '#ab4a21',
|
||||||
},
|
|
||||||
'cocoa_topaz_noonday': {
|
|
||||||
'bg-primary': '#322620', 'bg-secondary': '#48362e', 'bg-tertiary': '#5d473c',
|
|
||||||
'bg-tertiary-hover': '#674e42', 'text-primary': '#e7e5e4', 'text-muted': '#a49c98',
|
|
||||||
'border-color': '#644c40', 'accent': '#f1a04e', 'accent-hover': '#ed871f',
|
|
||||||
},
|
},
|
||||||
'sandstone_aquamarine_serenity': {
|
'sandstone_aquamarine_serenity': {
|
||||||
'bg-primary': '#322420', 'bg-secondary': '#48342e', 'bg-tertiary': '#5d443c',
|
'bg-primary': '#322420', 'bg-secondary': '#48342e', 'bg-tertiary': '#5d443c',
|
||||||
@@ -333,9 +302,9 @@ THEME_PALETTES = {
|
|||||||
'border-color': '#645240', 'accent': '#d6b12a', 'accent-hover': '#ac8e21',
|
'border-color': '#645240', 'accent': '#d6b12a', 'accent-hover': '#ac8e21',
|
||||||
},
|
},
|
||||||
'seashell_garnet_afternoon': {
|
'seashell_garnet_afternoon': {
|
||||||
'bg-primary': '#f1f2f4', 'bg-secondary': '#ffffff', 'bg-tertiary': '#ebedef',
|
'bg-primary': '#203232', 'bg-secondary': '#2e4848', 'bg-tertiary': '#3c5d5d',
|
||||||
'bg-tertiary-hover': '#dce0e5', 'text-primary': '#222425', 'text-muted': '#666b70',
|
'bg-tertiary-hover': '#426767', 'text-primary': '#e4e7e7', 'text-muted': '#98a4a4',
|
||||||
'border-color': '#cdd1d6', 'accent': '#da3e50', 'accent-hover': '#c02537',
|
'border-color': '#406464', 'accent': '#f36878', 'accent-hover': '#ef394e',
|
||||||
},
|
},
|
||||||
'rose_quartz_evening': {
|
'rose_quartz_evening': {
|
||||||
'bg-primary': '#322024', 'bg-secondary': '#482e34', 'bg-tertiary': '#5d3c44',
|
'bg-primary': '#322024', 'bg-secondary': '#482e34', 'bg-tertiary': '#5d3c44',
|
||||||
@@ -348,102 +317,82 @@ THEME_PALETTES = {
|
|||||||
'border-color': '#525252', 'accent': '#f1854e', 'accent-hover': '#ed641f',
|
'border-color': '#525252', 'accent': '#f1854e', 'accent-hover': '#ed641f',
|
||||||
},
|
},
|
||||||
'fireside': {
|
'fireside': {
|
||||||
'bg-primary': '#f4f2f1', 'bg-secondary': '#ffffff', 'bg-tertiary': '#efedeb',
|
'bg-primary': '#322420', 'bg-secondary': '#48342e', 'bg-tertiary': '#5d443c',
|
||||||
'bg-tertiary-hover': '#e5e0dc', 'text-primary': '#252422', 'text-muted': '#706b66',
|
'bg-tertiary-hover': '#674b42', 'text-primary': '#e7e5e4', 'text-muted': '#a49b98',
|
||||||
'border-color': '#d6d1cd', 'accent': '#ca7226', 'accent-hover': '#9f5a1e',
|
'border-color': '#644940', 'accent': '#d67929', 'accent-hover': '#ab6121',
|
||||||
},
|
},
|
||||||
'terrazzo': {
|
'terrazzo': {
|
||||||
'bg-primary': '#203232', 'bg-secondary': '#2e4848', 'bg-tertiary': '#3c5d5d',
|
'bg-primary': '#203232', 'bg-secondary': '#2e4848', 'bg-tertiary': '#3c5d5d',
|
||||||
'bg-tertiary-hover': '#426767', 'text-primary': '#e4e7e7', 'text-muted': '#98a4a4',
|
'bg-tertiary-hover': '#426767', 'text-primary': '#e4e7e7', 'text-muted': '#98a4a4',
|
||||||
'border-color': '#406464', 'accent': '#ecad6f', 'accent-hover': '#e69342',
|
'border-color': '#406464', 'accent': '#ecad6f', 'accent-hover': '#e69342',
|
||||||
},
|
},
|
||||||
# --- Cool (from Figma's "53 Unique Website Color Schemes") ---
|
# --- Cool (from Figma's "53 Unique Website Color Schemes", converted to dark backgrounds) ---
|
||||||
'sapphire_nightfall_whisper': {
|
'sapphire_nightfall_whisper': {
|
||||||
'bg-primary': '#202932', 'bg-secondary': '#2e3b48', 'bg-tertiary': '#3c4c5d',
|
'bg-primary': '#202932', 'bg-secondary': '#2e3b48', 'bg-tertiary': '#3c4c5d',
|
||||||
'bg-tertiary-hover': '#425467', 'text-primary': '#e4e6e7', 'text-muted': '#989ea4',
|
'bg-tertiary-hover': '#425467', 'text-primary': '#e4e6e7', 'text-muted': '#989ea4',
|
||||||
'border-color': '#405264', 'accent': '#297fd6', 'accent-hover': '#2166ab',
|
'border-color': '#405264', 'accent': '#297fd6', 'accent-hover': '#2166ab',
|
||||||
},
|
},
|
||||||
'marina': {
|
'marina': {
|
||||||
'bg-primary': '#f1f3f4', 'bg-secondary': '#ffffff', 'bg-tertiary': '#ebeeef',
|
'bg-primary': '#322720', 'bg-secondary': '#48382e', 'bg-tertiary': '#5d493c',
|
||||||
'bg-tertiary-hover': '#dce2e5', 'text-primary': '#222425', 'text-muted': '#666d70',
|
'bg-tertiary-hover': '#675042', 'text-primary': '#e7e5e4', 'text-muted': '#a49d98',
|
||||||
'border-color': '#cdd3d6', 'accent': '#3e8cda', 'accent-hover': '#2572c0',
|
'border-color': '#644e40', 'accent': '#76ade5', 'accent-hover': '#4b93dd',
|
||||||
},
|
},
|
||||||
'emerald_lavender_lake': {
|
'emerald_lavender_lake': {
|
||||||
'bg-primary': '#f1f4f4', 'bg-secondary': '#ffffff', 'bg-tertiary': '#ebefef',
|
'bg-primary': '#203228', 'bg-secondary': '#2e4839', 'bg-tertiary': '#3c5d4a',
|
||||||
'bg-tertiary-hover': '#dce5e5', 'text-primary': '#222525', 'text-muted': '#667070',
|
'bg-tertiary-hover': '#426752', 'text-primary': '#e4e7e5', 'text-muted': '#98a49d',
|
||||||
'border-color': '#cdd6d6', 'accent': '#239f58', 'accent-hover': '#1a7541',
|
'border-color': '#40644f', 'accent': '#2ed174', 'accent-hover': '#25a75d',
|
||||||
},
|
},
|
||||||
'sage_peridot_morning': {
|
'sage_peridot_morning': {
|
||||||
'bg-primary': '#f1f4f1', 'bg-secondary': '#ffffff', 'bg-tertiary': '#ebefeb',
|
'bg-primary': '#203220', 'bg-secondary': '#2e482e', 'bg-tertiary': '#3c5d3c',
|
||||||
'bg-tertiary-hover': '#dce5dc', 'text-primary': '#222522', 'text-muted': '#667066',
|
'bg-tertiary-hover': '#426742', 'text-primary': '#e4e7e4', 'text-muted': '#98a498',
|
||||||
'border-color': '#cdd6cd', 'accent': '#1f9e83', 'accent-hover': '#177360',
|
'border-color': '#406440', 'accent': '#20d1af', 'accent-hover': '#19a58a',
|
||||||
},
|
},
|
||||||
'amethyst_dawn_haze': {
|
'amethyst_dawn_haze': {
|
||||||
'bg-primary': '#242032', 'bg-secondary': '#342e48', 'bg-tertiary': '#443c5d',
|
'bg-primary': '#242032', 'bg-secondary': '#342e48', 'bg-tertiary': '#443c5d',
|
||||||
'bg-tertiary-hover': '#4b4267', 'text-primary': '#e5e4e7', 'text-muted': '#9b98a4',
|
'bg-tertiary-hover': '#4b4267', 'text-primary': '#e5e4e7', 'text-muted': '#9b98a4',
|
||||||
'border-color': '#494064', 'accent': '#ccba27', 'accent-hover': '#a1931f',
|
'border-color': '#494064', 'accent': '#ccba27', 'accent-hover': '#a1931f',
|
||||||
},
|
},
|
||||||
'turquoise_amber_autumn': {
|
|
||||||
'bg-primary': '#322620', 'bg-secondary': '#48362e', 'bg-tertiary': '#5d473c',
|
|
||||||
'bg-tertiary-hover': '#674e42', 'text-primary': '#e7e5e4', 'text-muted': '#a49c98',
|
|
||||||
'border-color': '#644c40', 'accent': '#d66329', 'accent-hover': '#ab4f21',
|
|
||||||
},
|
|
||||||
'sapphire_ash_morning': {
|
|
||||||
'bg-primary': '#f1f2f4', 'bg-secondary': '#ffffff', 'bg-tertiary': '#ebecef',
|
|
||||||
'bg-tertiary-hover': '#dcdfe5', 'text-primary': '#222325', 'text-muted': '#666970',
|
|
||||||
'border-color': '#cdd0d6', 'accent': '#356a8d', 'accent-hover': '#274e68',
|
|
||||||
},
|
|
||||||
'royal_glimmer': {
|
'royal_glimmer': {
|
||||||
'bg-primary': '#1f312d', 'bg-secondary': '#2d4741', 'bg-tertiary': '#3b5c56',
|
'bg-primary': '#1f312d', 'bg-secondary': '#2d4741', 'bg-tertiary': '#3b5c56',
|
||||||
'bg-tertiary-hover': '#41665e', 'text-primary': '#e4e7e7', 'text-muted': '#98a4a2',
|
'bg-tertiary-hover': '#41665e', 'text-primary': '#e4e7e7', 'text-muted': '#98a4a2',
|
||||||
'border-color': '#3f635b', 'accent': '#29d6b4', 'accent-hover': '#21ab90',
|
'border-color': '#3f635b', 'accent': '#29d6b4', 'accent-hover': '#21ab90',
|
||||||
},
|
},
|
||||||
'neptune': {
|
'neptune': {
|
||||||
'bg-primary': '#f1f3f4', 'bg-secondary': '#ffffff', 'bg-tertiary': '#ebeeef',
|
'bg-primary': '#203232', 'bg-secondary': '#2e4848', 'bg-tertiary': '#3c5d5d',
|
||||||
'bg-tertiary-hover': '#dce2e5', 'text-primary': '#222425', 'text-muted': '#666d70',
|
'bg-tertiary-hover': '#426767', 'text-primary': '#e4e7e7', 'text-muted': '#98a4a4',
|
||||||
'border-color': '#cdd3d6', 'accent': '#248fb8', 'accent-hover': '#1c6e8d',
|
'border-color': '#406464', 'accent': '#68ccf3', 'accent-hover': '#39bcef',
|
||||||
},
|
},
|
||||||
# --- Vibrant & Bold (from Figma's "53 Unique Website Color Schemes") ---
|
# --- Vibrant & Bold (from Figma's "53 Unique Website Color Schemes", converted to dark backgrounds) ---
|
||||||
'tropical_heat': {
|
'tropical_heat': {
|
||||||
'bg-primary': '#f4f3f1', 'bg-secondary': '#ffffff', 'bg-tertiary': '#efeeeb',
|
'bg-primary': '#203232', 'bg-secondary': '#2e4848', 'bg-tertiary': '#3c5d5d',
|
||||||
'bg-tertiary-hover': '#e5e3dc', 'text-primary': '#252522', 'text-muted': '#706e66',
|
'bg-tertiary-hover': '#426767', 'text-primary': '#e4e7e7', 'text-muted': '#98a4a4',
|
||||||
'border-color': '#d6d4cd', 'accent': '#ca5226', 'accent-hover': '#9f411e',
|
'border-color': '#406464', 'accent': '#d65729', 'accent-hover': '#ab4621',
|
||||||
},
|
},
|
||||||
'celestial': {
|
'celestial': {
|
||||||
'bg-primary': '#f4f4f1', 'bg-secondary': '#ffffff', 'bg-tertiary': '#efefeb',
|
'bg-primary': '#323220', 'bg-secondary': '#48482e', 'bg-tertiary': '#5d5d3c',
|
||||||
'bg-tertiary-hover': '#e5e4dc', 'text-primary': '#252522', 'text-muted': '#707066',
|
'bg-tertiary-hover': '#676742', 'text-primary': '#e7e7e4', 'text-muted': '#a4a498',
|
||||||
'border-color': '#d6d5cd', 'accent': '#918b1c', 'accent-hover': '#666214',
|
'border-color': '#646440', 'accent': '#cbc026', 'accent-hover': '#a0971e',
|
||||||
},
|
},
|
||||||
'festive_eve': {
|
'festive_eve': {
|
||||||
'bg-primary': '#f2f1f4', 'bg-secondary': '#ffffff', 'bg-tertiary': '#ecebef',
|
'bg-primary': '#202b32', 'bg-secondary': '#2e3e48', 'bg-tertiary': '#3c515d',
|
||||||
'bg-tertiary-hover': '#dfdce5', 'text-primary': '#232225', 'text-muted': '#696670',
|
'bg-tertiary-hover': '#425a67', 'text-primary': '#e4e6e7', 'text-muted': '#98a0a4',
|
||||||
'border-color': '#d0cdd6', 'accent': '#733eda', 'accent-hover': '#5a25c0',
|
'border-color': '#405764', 'accent': '#8f5cf2', 'accent-hover': '#6f2dee',
|
||||||
},
|
},
|
||||||
'freshly_squeezed': {
|
'freshly_squeezed': {
|
||||||
'bg-primary': '#f4f3f1', 'bg-secondary': '#ffffff', 'bg-tertiary': '#efeeeb',
|
'bg-primary': '#322d20', 'bg-secondary': '#48412e', 'bg-tertiary': '#5d553c',
|
||||||
'bg-tertiary-hover': '#e5e2dc', 'text-primary': '#252422', 'text-muted': '#706d66',
|
'bg-tertiary-hover': '#675e42', 'text-primary': '#e7e6e4', 'text-muted': '#a4a198',
|
||||||
'border-color': '#d6d3cd', 'accent': '#a28320', 'accent-hover': '#776118',
|
'border-color': '#645b40', 'accent': '#d6ab29', 'accent-hover': '#ab8921',
|
||||||
},
|
},
|
||||||
'jelly_shoes': {
|
'jelly_shoes': {
|
||||||
'bg-primary': '#f3f1f4', 'bg-secondary': '#ffffff', 'bg-tertiary': '#eeebef',
|
'bg-primary': '#242032', 'bg-secondary': '#342e48', 'bg-tertiary': '#443c5d',
|
||||||
'bg-tertiary-hover': '#e1dce5', 'text-primary': '#242225', 'text-muted': '#6c6670',
|
'bg-tertiary-hover': '#4b4267', 'text-primary': '#e5e4e7', 'text-muted': '#9b98a4',
|
||||||
'border-color': '#d2cdd6', 'accent': '#9d3eda', 'accent-hover': '#8325c0',
|
'border-color': '#494064', 'accent': '#bc68f3', 'accent-hover': '#a739ef',
|
||||||
},
|
|
||||||
# --- Modern (from Figma's "53 Unique Website Color Schemes") ---
|
|
||||||
'gossamer': {
|
|
||||||
'bg-primary': '#f4f1f1', 'bg-secondary': '#ffffff', 'bg-tertiary': '#efebeb',
|
|
||||||
'bg-tertiary-hover': '#e5dcdc', 'text-primary': '#252222', 'text-muted': '#706666',
|
|
||||||
'border-color': '#d6cdcd', 'accent': '#d95c37', 'accent-hover': '#ba4623',
|
|
||||||
},
|
|
||||||
'clockwork': {
|
|
||||||
'bg-primary': '#f4f1f1', 'bg-secondary': '#ffffff', 'bg-tertiary': '#efebeb',
|
|
||||||
'bg-tertiary-hover': '#e5dcdc', 'text-primary': '#252222', 'text-muted': '#706666',
|
|
||||||
'border-color': '#d6cdcd', 'accent': '#d26c28', 'accent-hover': '#a75620',
|
|
||||||
},
|
},
|
||||||
|
# --- Modern (from Figma's "53 Unique Website Color Schemes", converted to dark backgrounds) ---
|
||||||
'lemon_granite_morning': {
|
'lemon_granite_morning': {
|
||||||
'bg-primary': '#f4f1f1', 'bg-secondary': '#ffffff', 'bg-tertiary': '#efebeb',
|
'bg-primary': '#202c32', 'bg-secondary': '#2e3f48', 'bg-tertiary': '#3c525d',
|
||||||
'bg-tertiary-hover': '#e5dcdc', 'text-primary': '#252222', 'text-muted': '#706666',
|
'bg-tertiary-hover': '#425a67', 'text-primary': '#e4e6e7', 'text-muted': '#98a0a4',
|
||||||
'border-color': '#d6cdcd', 'accent': '#89831b', 'accent-hover': '#5e5a13',
|
'border-color': '#405864', 'accent': '#c9bf27', 'accent-hover': '#9e961f',
|
||||||
},
|
},
|
||||||
'arctic_reflection': {
|
'arctic_reflection': {
|
||||||
'bg-primary': '#202c32', 'bg-secondary': '#2e3f48', 'bg-tertiary': '#3c525d',
|
'bg-primary': '#202c32', 'bg-secondary': '#2e3f48', 'bg-tertiary': '#3c525d',
|
||||||
@@ -451,9 +400,9 @@ THEME_PALETTES = {
|
|||||||
'border-color': '#405864', 'accent': '#4693b9', 'accent-hover': '#387694',
|
'border-color': '#405864', 'accent': '#4693b9', 'accent-hover': '#387694',
|
||||||
},
|
},
|
||||||
'slate': {
|
'slate': {
|
||||||
'bg-primary': '#f4f1f1', 'bg-secondary': '#ffffff', 'bg-tertiary': '#efebeb',
|
'bg-primary': '#262c26', 'bg-secondary': '#373f37', 'bg-tertiary': '#475247',
|
||||||
'bg-tertiary-hover': '#e5dcdc', 'text-primary': '#252222', 'text-muted': '#706666',
|
'bg-tertiary-hover': '#4f5a4f', 'text-primary': '#e5e6e5', 'text-muted': '#9ca09c',
|
||||||
'border-color': '#d6cdcd', 'accent': '#1f9e31', 'accent-hover': '#177324',
|
'border-color': '#4c574c', 'accent': '#1ad236', 'accent-hover': '#14a52a',
|
||||||
},
|
},
|
||||||
'autumn_luxe': {
|
'autumn_luxe': {
|
||||||
'bg-primary': '#303020', 'bg-secondary': '#45452e', 'bg-tertiary': '#5b5b3d',
|
'bg-primary': '#303020', 'bg-secondary': '#45452e', 'bg-tertiary': '#5b5b3d',
|
||||||
@@ -482,11 +431,11 @@ THEME_PALETTES = {
|
|||||||
# neutral / Warm / Cool / Vibrant and bold / Modern" section headings, so
|
# neutral / Warm / Cool / Vibrant and bold / Modern" section headings, so
|
||||||
# browsing the dropdown still mirrors how the original schemes were curated.
|
# browsing the dropdown still mirrors how the original schemes were curated.
|
||||||
WEBSITE_SCHEME_CATEGORIES = {
|
WEBSITE_SCHEME_CATEGORIES = {
|
||||||
'Minimal & Neutral': ['ink_wash', 'jade_pebble_morning', 'woodland', 'graphite', 'urban_slate', 'pearl', 'vichy', 'sorbet', 'yacht_club'],
|
'Minimal & Neutral': ['ink_wash', 'jade_pebble_morning', 'woodland', 'graphite', 'pearl', 'yacht_club'],
|
||||||
'Warm': ['amber_walnut_morning', 'copper_aquamarine_dream', 'cocoa_topaz_noonday', 'sandstone_aquamarine_serenity', 'honey_opal_sunset', 'seashell_garnet_afternoon', 'rose_quartz_evening', 'calcite', 'fireside', 'terrazzo'],
|
'Warm': ['amber_walnut_morning', 'copper_aquamarine_dream', 'sandstone_aquamarine_serenity', 'honey_opal_sunset', 'seashell_garnet_afternoon', 'rose_quartz_evening', 'calcite', 'fireside', 'terrazzo'],
|
||||||
'Cool': ['sapphire_nightfall_whisper', 'marina', 'emerald_lavender_lake', 'sage_peridot_morning', 'amethyst_dawn_haze', 'turquoise_amber_autumn', 'sapphire_ash_morning', 'royal_glimmer', 'neptune'],
|
'Cool': ['sapphire_nightfall_whisper', 'marina', 'emerald_lavender_lake', 'sage_peridot_morning', 'amethyst_dawn_haze', 'royal_glimmer', 'neptune'],
|
||||||
'Vibrant & Bold': ['tropical_heat', 'celestial', 'festive_eve', 'freshly_squeezed', 'jelly_shoes'],
|
'Vibrant & Bold': ['tropical_heat', 'celestial', 'festive_eve', 'freshly_squeezed', 'jelly_shoes'],
|
||||||
'Modern': ['gossamer', 'clockwork', 'lemon_granite_morning', 'arctic_reflection', 'slate', 'autumn_luxe', 'inked', 'wraith', 'urban_nocturne'],
|
'Modern': ['lemon_granite_morning', 'arctic_reflection', 'slate', 'autumn_luxe', 'inked', 'wraith', 'urban_nocturne'],
|
||||||
}
|
}
|
||||||
|
|
||||||
# How each choice resolves to an actual CSS value. Keeping this server-side
|
# How each choice resolves to an actual CSS value. Keeping this server-side
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
One-off tool that generated the 53 "website scheme" theme entries in
|
One-off tool behind the 34 "website scheme" theme entries in
|
||||||
THEME_PALETTES/THEME_DISPLAY_NAMES (offlineu_core.py), sourced from Figma's
|
THEME_PALETTES/THEME_DISPLAY_NAMES (offlineu_core.py), sourced from Figma's
|
||||||
"53 Unique Website Color Schemes" resource page:
|
"53 Unique Website Color Schemes" resource page:
|
||||||
https://www.figma.com/resource-library/website-color-schemes/
|
https://www.figma.com/resource-library/website-color-schemes/
|
||||||
@@ -8,22 +8,36 @@ That page has no raw hex data - each scheme is a rendered mockup
|
|||||||
screenshot, not a swatch grid - so website_scheme_swatches.json (checked in
|
screenshot, not a swatch grid - so website_scheme_swatches.json (checked in
|
||||||
alongside this script) holds dominant colors already extracted from those
|
alongside this script) holds dominant colors already extracted from those
|
||||||
53 images via canvas pixel-histogram sampling in a browser, one entry per
|
53 images via canvas pixel-histogram sampling in a browser, one entry per
|
||||||
scheme: {n, name, colors: [{hex, pct}, ...]}. This script turns that raw
|
scheme: {n, name, colors: [{hex, pct}, ...]}. build_theme() turns that raw
|
||||||
material into an actual UI palette per scheme (bg/text/accent, matching
|
material into an actual UI palette per scheme (bg/text/accent, matching
|
||||||
THEME_PALETTES' shape), then nudges lightness as needed so every result
|
THEME_PALETTES' shape), then nudges lightness/saturation as needed so every
|
||||||
clears the same contrast bars this file's checks apply: text-vs-background,
|
result clears the same contrast bars this file's checks apply:
|
||||||
accent-vs-background, and accent-vs-white (buttons always use white text -
|
text-vs-background, accent-vs-background, and accent-vs-white (buttons
|
||||||
see .btn in course_dashboard.html - so a too-bright accent needs catching
|
always use white text - see .btn in course_dashboard.html - so a too-bright
|
||||||
even when it reads fine against the background alone).
|
accent needs catching even when it reads fine against the background
|
||||||
|
alone), and so accents don't land at the full saturation that reads as
|
||||||
|
neon in the mid-lightness band.
|
||||||
|
|
||||||
Not a live pipeline - re-running it regenerates the exact same 53 themes
|
Running this file directly (see __main__ below) auto-detects each scheme's
|
||||||
from the same frozen swatch data. To add more schemes, extract their
|
own mood from its swatches and writes all 53 as candidates - that's NOT
|
||||||
dominant colors the same way (see the canvas-sampling approach used
|
what's actually shipped. The source material is mostly light-mode
|
||||||
in-session; not scripted here) and append to the JSON, then rerun and
|
marketing mockups, so the first pass over-represented near-white
|
||||||
splice the output into offlineu_core.py by hand.
|
backgrounds; the shipped 34 all use build_theme(entry, force_mood='dark')
|
||||||
|
instead (every one of the 53 converted to a dark/colored background), then
|
||||||
|
had duplicates pruned by measuring real color distance (hue + lightness +
|
||||||
|
saturation, background and accent both) between every pair, tight enough
|
||||||
|
to only catch genuine near-twins - not something this script's __main__
|
||||||
|
does for you. That curation was one-off analysis, not captured as a single
|
||||||
|
rerunnable command; to redo it, call build_theme(entry, force_mood='dark')
|
||||||
|
per scheme, then de-duplicate the results the same way before splicing
|
||||||
|
into offlineu_core.py by hand.
|
||||||
|
|
||||||
|
To add more schemes: extract their dominant colors the same way (see the
|
||||||
|
canvas-sampling approach used originally; not scripted here) and append to
|
||||||
|
the JSON, then rerun.
|
||||||
|
|
||||||
Usage: python3 generate_website_scheme_themes.py
|
Usage: python3 generate_website_scheme_themes.py
|
||||||
Writes generated_themes.json with the full computed palette per scheme.
|
Writes generated_themes.json with all 53 candidates, auto-detected mood.
|
||||||
"""
|
"""
|
||||||
import colorsys
|
import colorsys
|
||||||
import json
|
import json
|
||||||
@@ -93,7 +107,7 @@ def tame_accent_saturation(s, l):
|
|||||||
return min(s, 0.85)
|
return min(s, 0.85)
|
||||||
|
|
||||||
|
|
||||||
def build_theme(entry):
|
def build_theme(entry, force_mood=None):
|
||||||
name = entry['name']
|
name = entry['name']
|
||||||
swatches = entry['colors']
|
swatches = entry['colors']
|
||||||
parsed = []
|
parsed = []
|
||||||
@@ -107,8 +121,13 @@ def build_theme(entry):
|
|||||||
if not content:
|
if not content:
|
||||||
content = parsed
|
content = parsed
|
||||||
|
|
||||||
darkest_l = min(p['l'] for p in content)
|
if force_mood == 'dark':
|
||||||
is_dark = darkest_l < 0.28
|
is_dark = True
|
||||||
|
elif force_mood == 'light':
|
||||||
|
is_dark = False
|
||||||
|
else:
|
||||||
|
darkest_l = min(p['l'] for p in content)
|
||||||
|
is_dark = darkest_l < 0.28
|
||||||
|
|
||||||
accent_candidates = [p for p in content if p['s'] > 0.25]
|
accent_candidates = [p for p in content if p['s'] > 0.25]
|
||||||
if accent_candidates:
|
if accent_candidates:
|
||||||
|
|||||||
Reference in New Issue
Block a user