fix: apply theme overlay config to contour layers

addContours() was using hardcoded black/white colors instead of
theme-specific overlay config. Now uses getOverlayConfig(themeId,
"contours") like other overlay layers (hillshade, publicLands, etc).

Also updates cyberpunk contours from dark purple to cyan (#1a5566 →
#3a99aa) to contrast with purple roads.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Matt 2026-05-21 21:42:41 +00:00
commit fcc9101239
2 changed files with 447 additions and 430 deletions

View file

@ -560,9 +560,11 @@ function removePublicLands(map) {
}
/** Add topographic contours via maplibre-contour */
function addContours(map) {
console.log('[CONTOUR] addContours called, source exists:', !!map?.getSource(CONTOUR_SOURCE), 'demSource:', !!demSourceInstance)
function addContours(map, themeId) {
console.log("[CONTOUR] addContours called, source exists:", !!map?.getSource(CONTOUR_SOURCE), "demSource:", !!demSourceInstance)
if (!map || !demSourceInstance || map.getSource(CONTOUR_SOURCE)) return
const c = getOverlayConfig(themeId, "contours")
const contourThresholds = {
3: [5000, 25000],
4: [2500, 10000],
@ -579,54 +581,69 @@ function addContours(map) {
15: [20, 100],
}
map.addSource(CONTOUR_SOURCE, {
type: 'vector',
type: "vector",
tiles: [demSourceInstance.contourProtocolUrl({
multiplier: 3.28084,
thresholds: contourThresholds,
})],
maxzoom: 16,
})
console.log('[CONTOUR] protocol URL:', demSourceInstance.contourProtocolUrl({
console.log("[CONTOUR] protocol URL:", demSourceInstance.contourProtocolUrl({
multiplier: 3.28084,
thresholds: contourThresholds,
}))
console.log('[CONTOUR] source added:', !!map.getSource(CONTOUR_SOURCE))
console.log("[CONTOUR] source added:", !!map.getSource(CONTOUR_SOURCE))
let beforeId = undefined
for (const layer of map.getStyle().layers) {
if (layer.type === 'symbol') { beforeId = layer.id; break }
if (layer.type === "symbol") { beforeId = layer.id; break }
}
const isDark = document.documentElement.getAttribute('data-theme') === 'dark'
// Line layer with theme-aware colors
// maplibre-contour level: 0 = minor, 1 = index (major)
const opacityMod = c.opacityMod ?? 1
map.addLayer({
id: CONTOUR_LINE, type: 'line', source: CONTOUR_SOURCE,
'source-layer': 'contours',
id: CONTOUR_LINE, type: "line", source: CONTOUR_SOURCE,
"source-layer": "contours",
paint: {
'line-color': 'rgba(0,0,0,0.35)',
'line-width': [
'interpolate', ['linear'], ['zoom'],
7, ['match', ['get', 'level'], 1, 1, 0.3],
11, ['match', ['get', 'level'], 1, 1.5, 0.6],
14, ['match', ['get', 'level'], 1, 2, 0.8],
"line-color": [
"match", ["get", "level"],
1, c.indexColor,
c.minorColor
],
"line-opacity": [
"match", ["get", "level"],
1, c.indexOpacity * opacityMod,
c.minorOpacity * opacityMod
],
"line-width": [
"interpolate", ["linear"], ["zoom"],
7, ["match", ["get", "level"], 1, c.indexWidth?.z4 ?? 1.2, c.minorWidth?.z11 ?? 0.5],
11, ["match", ["get", "level"], 1, ((c.indexWidth?.z4 ?? 1.2) + (c.indexWidth?.z14 ?? 1.8)) / 2, ((c.minorWidth?.z11 ?? 0.5) + (c.minorWidth?.z14 ?? 1.0)) / 2],
14, ["match", ["get", "level"], 1, c.indexWidth?.z14 ?? 1.8, c.minorWidth?.z14 ?? 1.0],
],
},
}, beforeId)
// Label layer for index contours (level > 0)
map.addLayer({
id: CONTOUR_LABEL, type: 'symbol', source: CONTOUR_SOURCE,
'source-layer': 'contours',
filter: ['>', ['get', 'level'], 0],
id: CONTOUR_LABEL, type: "symbol", source: CONTOUR_SOURCE,
"source-layer": "contours",
filter: [">", ["get", "level"], 0],
layout: {
'symbol-placement': 'line',
'text-size': ['interpolate', ['linear'], ['zoom'], 7, 9, 11, 11, 14, 13],
'text-field': ['concat', ['number-format', ['get', 'ele'], {}], "'"],
'text-font': ['Noto Sans Medium'],
'text-max-angle': 25,
"symbol-placement": "line",
"text-size": c.labelSize ?? 10,
"text-field": ["concat", ["number-format", ["get", "ele"], {}], "'"],
"text-font": c.labelFont ?? ["Noto Sans Regular"],
"text-max-angle": 25,
},
paint: {
'text-color': 'rgba(0,0,0,0.7)',
'text-halo-color': 'rgba(255,255,255,0.9)',
'text-halo-width': 1.5,
"text-color": c.labelColor,
"text-halo-color": c.labelHaloColor,
"text-halo-width": c.labelHaloWidth ?? 1.5,
"text-opacity": (c.labelOpacity ?? 0.85) * opacityMod,
},
})
console.log('[CONTOUR] layers added:', !!map.getLayer(CONTOUR_LINE), !!map.getLayer(CONTOUR_LABEL))
console.log("[CONTOUR] layers added:", !!map.getLayer(CONTOUR_LINE), !!map.getLayer(CONTOUR_LABEL))
}
/** Remove contour layers + source */

View file

@ -1,403 +1,403 @@
/**
* Cyberpunk Theme for Navi
*
* Inspired by Mapbox's "Terminal" cyberpunk style, Blade Runner, and Ghost in
* the Shell. A tactical display in a neon-lit command center. Near-black base
* with deep blue-purple undertones. Roads glow in hot magenta and electric cyan.
* Water is inky dark. Vegetation is barely there dark teal hints. Labels are
* cool white with colored halos.
*
* The whole thing should feel like you're navigating Night City.
*
* CUSTOM FONTS:
* - Heading: "Orbitron" geometric, futuristic display font
* - Body: "Share Tech Mono" monospaced terminal feel for entire UI
*/
// ═══════════════════════════════════════════════════════════════════════════
// PALETTE
// ═══════════════════════════════════════════════════════════════════════════
//
// base: #0a0a14 ← near-black with blue-purple undertone
// surface: #10101e ← panels, cards
// surfaceAlt: #161628 ← secondary surfaces, hover states
// border: #1e1e3a ← subtle purple edges
// text: #d0d0e8 ← cool white text
// textSecondary: #8888aa ← lavender-gray
// textMuted: #5a5a7a ← dark purple-gray
// textInverse: #0a0a14 ← text on neon backgrounds
// accent: #ff2d6b ← hot pink/magenta — primary actions
// accentHover: #ff4d8b ← lighter magenta
// accentAlt: #00f0ff ← electric cyan — secondary accent
// success: #00ff88 ← neon green
// warning: #ffaa00 ← amber
// danger: #ff3333 ← neon red
// water: #06061a ← deep dark blue-black
// waterLabel: #3a6a8a ← muted blue for water labels
// vegetation: #0a1a12 ← barely-there dark teal-green
// forest: #0e1e14 ← slightly deeper
// road: #1a1a3a ← ghost purple minor roads
// roadSecondary: #2a2a5a
// roadPrimary: #8833aa ← purple for primary
// roadMotorway: #ff2d6b ← hot magenta for motorways
// roadCasing: #0a0a14 ← dark casing
// building: #141428 ← dark purple-gray buildings
// contour: #1e1e3e ← dark lines, just visible
// contourLabel: #5a5a7a
//
// ═══════════════════════════════════════════════════════════════════════════
/**
* Map flavor colors - protomaps-themes-base schema
* All 73 flat keys + pois + landcover nested objects
*/
const cyberpunkColors = {
// Background & earth
background: '#08080f',
earth: '#0a0a14',
// Land use areas - dark with slight purple undertones
park_a: '#0a1a14',
park_b: '#0e1e18',
hospital: '#1a1020',
industrial: '#0e0e1a',
school: '#14101e',
wood_a: '#0a1a12',
wood_b: '#0e1e14',
pedestrian: '#0c0c18',
scrub_a: '#0a1410',
scrub_b: '#0c1812',
glacier: '#101020',
sand: '#12101a',
beach: '#14121c',
aerodrome: '#0a0a16',
runway: '#1a1a30',
water: '#06061a',
zoo: '#0c1614',
military: '#100a14',
// Tunnels - dark purple casings
tunnel_other_casing: '#0a0a14',
tunnel_minor_casing: '#0a0a14',
tunnel_link_casing: '#0a0a14',
tunnel_major_casing: '#0a0a14',
tunnel_highway_casing: '#0a0a14',
tunnel_other: '#161628',
tunnel_minor: '#161628',
tunnel_link: '#2a2050',
tunnel_major: '#4a2870',
tunnel_highway: '#801848',
// Pier & buildings
pier: '#1a1a30',
buildings: '#141428',
// Roads & casings - glowing neon progression
minor_service_casing: '#0a0a14',
minor_casing: '#0a0a14',
link_casing: '#0a0a14',
major_casing_late: '#0a0a14',
highway_casing_late: '#0a0a14',
other: '#1a1a3a',
minor_service: '#1a1a3a',
minor_a: '#2a2a5a',
minor_b: '#1a1a3a',
link: '#5a3888',
major_casing_early: '#0a0a14',
major: '#8833aa',
highway_casing_early: '#0a0a14',
highway: '#ff2d6b',
railway: '#2a2050',
boundaries: '#4a4a6a',
// Waterway label
waterway_label: '#3a6a8a',
// Bridges - same neon colors
bridges_other_casing: '#0c0c18',
bridges_minor_casing: '#0a0a14',
bridges_link_casing: '#0a0a14',
bridges_major_casing: '#0a0a14',
bridges_highway_casing: '#0a0a14',
bridges_other: '#1a1a3a',
bridges_minor: '#2a2a5a',
bridges_link: '#5a3888',
bridges_major: '#8833aa',
bridges_highway: '#ff2d6b',
// Labels - cool white with DARK halos
roads_label_minor: '#8888aa',
roads_label_minor_halo: '#0a0a14',
roads_label_major: '#a0a0c0',
roads_label_major_halo: '#0a0a14',
ocean_label: '#3a6a8a',
peak_label: '#8888aa',
subplace_label: '#8888aa',
subplace_label_halo: '#0a0a14',
city_label: '#d0d0e8',
city_label_halo: '#0a0a14',
state_label: '#5a5a7a',
state_label_halo: '#0a0a14',
country_label: '#7a7a9a',
address_label: '#8888aa',
address_label_halo: '#0a0a14',
// POI icon colors - neon palette
pois: {
blue: '#00a0ff',
green: '#00ff88',
lapis: '#6060ff',
pink: '#ff2d6b',
red: '#ff3333',
slategray: '#8888aa',
tangerine: '#ffaa00',
turquoise: '#00f0ff',
},
// Landcover fill colors - very dark, barely visible
landcover: {
grassland: 'rgba(10, 26, 18, 1)',
barren: 'rgba(18, 16, 26, 1)',
urban_area: 'rgba(14, 14, 26, 1)',
farmland: 'rgba(12, 24, 16, 1)',
glacier: 'rgba(16, 16, 32, 1)',
scrub: 'rgba(12, 20, 16, 1)',
forest: 'rgba(14, 30, 20, 1)',
},
}
/**
* UI CSS custom properties - neon command center aesthetic
* Dark translucent panels with magenta/cyan accents
*/
const cyberpunkUI = {
// Fonts - monospace terminal feel
'--font-sans': "'Share Tech Mono', monospace",
'--font-mono': "'Share Tech Mono', monospace",
'--font-heading': "'Orbitron', sans-serif",
// Backgrounds - dark with blue-purple undertone
'--bg-base': '#0a0a14',
'--bg-raised': '#10101e',
'--bg-overlay': '#161628',
'--bg-input': '#0c0c18',
'--bg-inset': '#08080f',
'--bg-muted': '#12121e',
// Text - cool white spectrum
'--text-primary': '#d0d0e8',
'--text-secondary': '#8888aa',
'--text-tertiary': '#5a5a7a',
'--text-inverse': '#0a0a14',
// Borders - subtle purple edges
'--border': '#1e1e3a',
'--border-subtle': '#141428',
// Accent - hot magenta
'--accent': '#ff2d6b',
'--accent-hover': '#ff4d8b',
'--accent-muted': '#3a1828',
// Tan becomes cyan in this theme
'--tan': '#00f0ff',
'--tan-muted': '#0a2830',
// Pins - neon colors
'--pin-origin': '#ff2d6b',
'--pin-destination': '#00f0ff',
'--pin-intermediate': '#8833aa',
'--pin-stroke': '#0a0a14',
// Status - neon signals
'--status-success': '#00ff88',
'--status-warning': '#ffaa00',
'--status-danger': '#ff3333',
'--success': '#00ff88',
'--warning': '#ffaa00',
'--warning-muted': '#2a2010',
// Route - cyan for contrast with magenta UI
'--route-line': '#00f0ff',
// Shadows - subtle magenta glow
'--shadow': '0 2px 8px rgba(255, 45, 107, 0.25)',
'--shadow-lg': '0 4px 16px rgba(255, 45, 107, 0.35)',
}
/**
* Overlay configuration - subtle, muted for dark theme
*/
const cyberpunkOverlay = {
// Hillshade - dramatic shadows
hillshade: {
exaggeration: 0.6,
illuminationDirection: 315,
shadowColor: '#000000',
highlightColor: '#2a2a4a',
},
// Contours - very subtle dark purple-gray
contours: {
opacityMod: 0.5,
minorColor: '#1e1e3e',
minorOpacity: 0.3,
minorWidth: { z11: 0.4, z14: 0.8 },
intermediateColor: '#2a2a4a',
intermediateOpacity: 0.4,
intermediateWidth: { z8: 0.6, z14: 1.0 },
indexColor: '#3a3a5a',
indexOpacity: 0.5,
indexWidth: { z4: 0.8, z14: 1.2 },
labelColor: '#5a5a7a',
labelHaloColor: '#0a0a14',
labelHaloWidth: 1.5,
labelOpacity: 0.6,
labelSize: 10,
labelFont: ['Noto Sans Regular'],
},
// Contours Test - cyan variant
contoursTest: {
minorColor: '#1a3a4a',
intermediateColor: '#2a4a5a',
indexColor: '#3a5a6a',
labelColor: '#5a8a9a',
},
// Contours Test 10ft - purple variant
contoursTest10ft: {
minorColor: '#2a1a4a',
intermediateColor: '#3a2a5a',
indexColor: '#4a3a6a',
labelColor: '#7a6a9a',
},
// Public Lands - very muted fills
publicLands: {
opacityMod: 0.5,
// Fill colors - dark teal/purple tints
fillWA: '#1a2a20',
fillNPS: '#0a2a1a',
fillUSFS: '#102820',
fillBLM: '#1a2828',
fillFWS: '#0a2a2a',
fillSTAT: '#102028',
fillLOC: '#182028',
fillDefault: '#1a1a2a',
// Fill opacities - very low
fillOpacityWA: 0.25,
fillOpacityNPS: 0.25,
fillOpacityUSFS: 0.20,
fillOpacityBLM: 0.15,
fillOpacitySTAT: 0.20,
fillOpacityLOC: 0.15,
fillOpacityDefault: 0.10,
// Outline colors - subtle
outlineWA: '#2a3a30',
outlineNPS: '#1a3a2a',
outlineUSFS: '#203830',
outlineBLM: '#2a3838',
outlineFWS: '#1a3a3a',
outlineSTAT: '#203038',
outlineLOC: '#283038',
outlineDefault: '#2a2a3a',
// Outline opacities
outlineOpacityNPS: 0.5,
outlineOpacityUSFS: 0.4,
outlineOpacityDefault: 0.3,
// Outline width
outlineWidth: { z4: 0.3, z8: 0.6, z12: 1.0 },
// Labels - muted teal
labelColor: '#5a8a8a',
labelHaloColor: '#0a0a14',
labelHaloWidth: 1.5,
labelOpacity: 0.7,
labelSize: { z10: 10, z14: 12 },
labelFont: ['Noto Sans Regular'],
},
// USFS Trails - purple/magenta/cyan family instead of earthy browns
usfsTrails: {
// Roads - purple
roadsColor: '#8833aa',
roadsOpacity: 0.85,
roadsWidth: { z10: 1.5, z14: 2.5, z16: 3.5 },
// Trails - neon colors by use type
trailsMotorized: '#ff2d6b',
trailsBicycle: '#ffaa00',
trailsHiker: '#00ff88',
trailsDefault: '#8833aa',
trailsOpacity: 0.85,
trailsWidth: { z10: 2.0, z14: 3.0, z16: 4.0 },
trailsDash: [2, 1.5],
// Road labels
roadsLabelColor: '#a080c0',
roadsLabelHaloColor: '#0a0a14',
roadsLabelHaloWidth: 1.5,
roadsLabelOpacity: 0.85,
roadsLabelSize: 11,
// Trail labels
trailsLabelColor: '#a080c0',
trailsLabelHaloColor: '#0a0a14',
trailsLabelHaloWidth: 1.5,
trailsLabelOpacity: 0.85,
trailsLabelSize: 11,
labelFont: ['Noto Sans Regular'],
// Hit layer
hitWidth: 14,
},
// BLM Trails - purple/cyan/magenta family
blmTrails: {
// Route colors - neon family
color4wdHigh: '#ff2d6b',
color4wdLow: '#cc2288',
colorAtv: '#ff3333',
colorMotoSingle: '#aa44cc',
color2wdLow: '#8833aa',
colorNonMech: '#00ff88',
colorDefault: '#6644aa',
colorSnow: '#00f0ff',
lineOpacity: 0.85,
lineOpacityOther: 0.75,
lineWidth: { z10: 2.0, z14: 3.0, z16: 4.0 },
// Dash patterns
dashImproved: [4, 2],
dashAggregate: [1, 2],
dashSnow: [4, 2, 1, 2],
dashOther: [4, 2, 1, 2, 1, 2],
// Labels
labelColor: '#a080c0',
labelHaloColor: '#0a0a14',
labelHaloWidth: 1.5,
labelOpacity: 0.85,
labelSize: 11,
labelFont: ['Noto Sans Regular'],
// Hit layer
hitWidth: 14,
},
}
/**
* Satellite adjustments - dark, desaturated, purple-shifted
*/
const cyberpunkSatellite = {
opacity: 0.8,
brightnessMin: 0.0,
brightnessMax: 0.30,
contrast: 0.15,
saturation: -0.6,
hueRotate: 280,
}
/**
* Cyberpunk theme configuration
*/
const cyberpunkTheme = {
id: 'cyberpunk',
name: 'Cyberpunk',
dark: true,
swatch: ['#0a0a14', '#ff2d6b', '#00f0ff'],
fontImports: [
'https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;600;700&display=swap',
'https://fonts.googleapis.com/css2?family=Share+Tech+Mono&display=swap',
],
colors: cyberpunkColors,
satellite: cyberpunkSatellite,
overlay: cyberpunkOverlay,
ui: cyberpunkUI,
}
export default cyberpunkTheme
/**
* Cyberpunk Theme for Navi
*
* Inspired by Mapbox's "Terminal" cyberpunk style, Blade Runner, and Ghost in
* the Shell. A tactical display in a neon-lit command center. Near-black base
* with deep blue-purple undertones. Roads glow in hot magenta and electric cyan.
* Water is inky dark. Vegetation is barely there dark teal hints. Labels are
* cool white with colored halos.
*
* The whole thing should feel like you're navigating Night City.
*
* CUSTOM FONTS:
* - Heading: "Orbitron" geometric, futuristic display font
* - Body: "Share Tech Mono" monospaced terminal feel for entire UI
*/
// ═══════════════════════════════════════════════════════════════════════════
// PALETTE
// ═══════════════════════════════════════════════════════════════════════════
//
// base: #0a0a14 ← near-black with blue-purple undertone
// surface: #10101e ← panels, cards
// surfaceAlt: #161628 ← secondary surfaces, hover states
// border: #1e1e3a ← subtle purple edges
// text: #d0d0e8 ← cool white text
// textSecondary: #8888aa ← lavender-gray
// textMuted: #5a5a7a ← dark purple-gray
// textInverse: #0a0a14 ← text on neon backgrounds
// accent: #ff2d6b ← hot pink/magenta — primary actions
// accentHover: #ff4d8b ← lighter magenta
// accentAlt: #00f0ff ← electric cyan — secondary accent
// success: #00ff88 ← neon green
// warning: #ffaa00 ← amber
// danger: #ff3333 ← neon red
// water: #06061a ← deep dark blue-black
// waterLabel: #3a6a8a ← muted blue for water labels
// vegetation: #0a1a12 ← barely-there dark teal-green
// forest: #0e1e14 ← slightly deeper
// road: #1a1a3a ← ghost purple minor roads
// roadSecondary: #2a2a5a
// roadPrimary: #8833aa ← purple for primary
// roadMotorway: #ff2d6b ← hot magenta for motorways
// roadCasing: #0a0a14 ← dark casing
// building: #141428 ← dark purple-gray buildings
// contour: #1e1e3e ← dark lines, just visible
// contourLabel: #5a5a7a
//
// ═══════════════════════════════════════════════════════════════════════════
/**
* Map flavor colors - protomaps-themes-base schema
* All 73 flat keys + pois + landcover nested objects
*/
const cyberpunkColors = {
// Background & earth
background: '#08080f',
earth: '#0a0a14',
// Land use areas - dark with slight purple undertones
park_a: '#0a1a14',
park_b: '#0e1e18',
hospital: '#1a1020',
industrial: '#0e0e1a',
school: '#14101e',
wood_a: '#0a1a12',
wood_b: '#0e1e14',
pedestrian: '#0c0c18',
scrub_a: '#0a1410',
scrub_b: '#0c1812',
glacier: '#101020',
sand: '#12101a',
beach: '#14121c',
aerodrome: '#0a0a16',
runway: '#1a1a30',
water: '#06061a',
zoo: '#0c1614',
military: '#100a14',
// Tunnels - dark purple casings
tunnel_other_casing: '#0a0a14',
tunnel_minor_casing: '#0a0a14',
tunnel_link_casing: '#0a0a14',
tunnel_major_casing: '#0a0a14',
tunnel_highway_casing: '#0a0a14',
tunnel_other: '#161628',
tunnel_minor: '#161628',
tunnel_link: '#2a2050',
tunnel_major: '#4a2870',
tunnel_highway: '#801848',
// Pier & buildings
pier: '#1a1a30',
buildings: '#141428',
// Roads & casings - glowing neon progression
minor_service_casing: '#0a0a14',
minor_casing: '#0a0a14',
link_casing: '#0a0a14',
major_casing_late: '#0a0a14',
highway_casing_late: '#0a0a14',
other: '#1a1a3a',
minor_service: '#1a1a3a',
minor_a: '#2a2a5a',
minor_b: '#1a1a3a',
link: '#5a3888',
major_casing_early: '#0a0a14',
major: '#8833aa',
highway_casing_early: '#0a0a14',
highway: '#ff2d6b',
railway: '#2a2050',
boundaries: '#4a4a6a',
// Waterway label
waterway_label: '#3a6a8a',
// Bridges - same neon colors
bridges_other_casing: '#0c0c18',
bridges_minor_casing: '#0a0a14',
bridges_link_casing: '#0a0a14',
bridges_major_casing: '#0a0a14',
bridges_highway_casing: '#0a0a14',
bridges_other: '#1a1a3a',
bridges_minor: '#2a2a5a',
bridges_link: '#5a3888',
bridges_major: '#8833aa',
bridges_highway: '#ff2d6b',
// Labels - cool white with DARK halos
roads_label_minor: '#8888aa',
roads_label_minor_halo: '#0a0a14',
roads_label_major: '#a0a0c0',
roads_label_major_halo: '#0a0a14',
ocean_label: '#3a6a8a',
peak_label: '#8888aa',
subplace_label: '#8888aa',
subplace_label_halo: '#0a0a14',
city_label: '#d0d0e8',
city_label_halo: '#0a0a14',
state_label: '#5a5a7a',
state_label_halo: '#0a0a14',
country_label: '#7a7a9a',
address_label: '#8888aa',
address_label_halo: '#0a0a14',
// POI icon colors - neon palette
pois: {
blue: '#00a0ff',
green: '#00ff88',
lapis: '#6060ff',
pink: '#ff2d6b',
red: '#ff3333',
slategray: '#8888aa',
tangerine: '#ffaa00',
turquoise: '#00f0ff',
},
// Landcover fill colors - very dark, barely visible
landcover: {
grassland: 'rgba(10, 26, 18, 1)',
barren: 'rgba(18, 16, 26, 1)',
urban_area: 'rgba(14, 14, 26, 1)',
farmland: 'rgba(12, 24, 16, 1)',
glacier: 'rgba(16, 16, 32, 1)',
scrub: 'rgba(12, 20, 16, 1)',
forest: 'rgba(14, 30, 20, 1)',
},
}
/**
* UI CSS custom properties - neon command center aesthetic
* Dark translucent panels with magenta/cyan accents
*/
const cyberpunkUI = {
// Fonts - monospace terminal feel
'--font-sans': "'Share Tech Mono', monospace",
'--font-mono': "'Share Tech Mono', monospace",
'--font-heading': "'Orbitron', sans-serif",
// Backgrounds - dark with blue-purple undertone
'--bg-base': '#0a0a14',
'--bg-raised': '#10101e',
'--bg-overlay': '#161628',
'--bg-input': '#0c0c18',
'--bg-inset': '#08080f',
'--bg-muted': '#12121e',
// Text - cool white spectrum
'--text-primary': '#d0d0e8',
'--text-secondary': '#8888aa',
'--text-tertiary': '#5a5a7a',
'--text-inverse': '#0a0a14',
// Borders - subtle purple edges
'--border': '#1e1e3a',
'--border-subtle': '#141428',
// Accent - hot magenta
'--accent': '#ff2d6b',
'--accent-hover': '#ff4d8b',
'--accent-muted': '#3a1828',
// Tan becomes cyan in this theme
'--tan': '#00f0ff',
'--tan-muted': '#0a2830',
// Pins - neon colors
'--pin-origin': '#ff2d6b',
'--pin-destination': '#00f0ff',
'--pin-intermediate': '#8833aa',
'--pin-stroke': '#0a0a14',
// Status - neon signals
'--status-success': '#00ff88',
'--status-warning': '#ffaa00',
'--status-danger': '#ff3333',
'--success': '#00ff88',
'--warning': '#ffaa00',
'--warning-muted': '#2a2010',
// Route - cyan for contrast with magenta UI
'--route-line': '#00f0ff',
// Shadows - subtle magenta glow
'--shadow': '0 2px 8px rgba(255, 45, 107, 0.25)',
'--shadow-lg': '0 4px 16px rgba(255, 45, 107, 0.35)',
}
/**
* Overlay configuration - subtle, muted for dark theme
*/
const cyberpunkOverlay = {
// Hillshade - dramatic shadows
hillshade: {
exaggeration: 0.6,
illuminationDirection: 315,
shadowColor: '#000000',
highlightColor: '#2a2a4a',
},
// Contours - very subtle dark purple-gray
contours: {
opacityMod: 1.0,
minorColor: "#1a5566",
minorOpacity: 0.5,
minorWidth: { z11: 0.5, z14: 1.0 },
intermediateColor: "#2a7788",
intermediateOpacity: 0.65,
intermediateWidth: { z8: 0.8, z14: 1.2 },
indexColor: "#3a99aa",
indexOpacity: 0.8,
indexWidth: { z4: 1.2, z14: 1.8 },
labelColor: "#55ccdd",
labelHaloColor: "#0a0a14",
labelHaloWidth: 1.5,
labelOpacity: 0.85,
labelSize: 10,
labelFont: ["Noto Sans Regular"],
},
// Contours Test - cyan variant
contoursTest: {
minorColor: '#1a3a4a',
intermediateColor: '#2a4a5a',
indexColor: '#3a5a6a',
labelColor: '#5a8a9a',
},
// Contours Test 10ft - purple variant
contoursTest10ft: {
minorColor: '#2a1a4a',
intermediateColor: '#3a2a5a',
indexColor: '#4a3a6a',
labelColor: '#7a6a9a',
},
// Public Lands - very muted fills
publicLands: {
opacityMod: 0.5,
// Fill colors - dark teal/purple tints
fillWA: '#1a2a20',
fillNPS: '#0a2a1a',
fillUSFS: '#102820',
fillBLM: '#1a2828',
fillFWS: '#0a2a2a',
fillSTAT: '#102028',
fillLOC: '#182028',
fillDefault: '#1a1a2a',
// Fill opacities - very low
fillOpacityWA: 0.25,
fillOpacityNPS: 0.25,
fillOpacityUSFS: 0.20,
fillOpacityBLM: 0.15,
fillOpacitySTAT: 0.20,
fillOpacityLOC: 0.15,
fillOpacityDefault: 0.10,
// Outline colors - subtle
outlineWA: '#2a3a30',
outlineNPS: '#1a3a2a',
outlineUSFS: '#203830',
outlineBLM: '#2a3838',
outlineFWS: '#1a3a3a',
outlineSTAT: '#203038',
outlineLOC: '#283038',
outlineDefault: '#2a2a3a',
// Outline opacities
outlineOpacityNPS: 0.5,
outlineOpacityUSFS: 0.4,
outlineOpacityDefault: 0.3,
// Outline width
outlineWidth: { z4: 0.3, z8: 0.6, z12: 1.0 },
// Labels - muted teal
labelColor: '#5a8a8a',
labelHaloColor: '#0a0a14',
labelHaloWidth: 1.5,
labelOpacity: 0.7,
labelSize: { z10: 10, z14: 12 },
labelFont: ['Noto Sans Regular'],
},
// USFS Trails - purple/magenta/cyan family instead of earthy browns
usfsTrails: {
// Roads - purple
roadsColor: '#8833aa',
roadsOpacity: 0.85,
roadsWidth: { z10: 1.5, z14: 2.5, z16: 3.5 },
// Trails - neon colors by use type
trailsMotorized: '#ff2d6b',
trailsBicycle: '#ffaa00',
trailsHiker: '#00ff88',
trailsDefault: '#8833aa',
trailsOpacity: 0.85,
trailsWidth: { z10: 2.0, z14: 3.0, z16: 4.0 },
trailsDash: [2, 1.5],
// Road labels
roadsLabelColor: '#a080c0',
roadsLabelHaloColor: '#0a0a14',
roadsLabelHaloWidth: 1.5,
roadsLabelOpacity: 0.85,
roadsLabelSize: 11,
// Trail labels
trailsLabelColor: '#a080c0',
trailsLabelHaloColor: '#0a0a14',
trailsLabelHaloWidth: 1.5,
trailsLabelOpacity: 0.85,
trailsLabelSize: 11,
labelFont: ['Noto Sans Regular'],
// Hit layer
hitWidth: 14,
},
// BLM Trails - purple/cyan/magenta family
blmTrails: {
// Route colors - neon family
color4wdHigh: '#ff2d6b',
color4wdLow: '#cc2288',
colorAtv: '#ff3333',
colorMotoSingle: '#aa44cc',
color2wdLow: '#8833aa',
colorNonMech: '#00ff88',
colorDefault: '#6644aa',
colorSnow: '#00f0ff',
lineOpacity: 0.85,
lineOpacityOther: 0.75,
lineWidth: { z10: 2.0, z14: 3.0, z16: 4.0 },
// Dash patterns
dashImproved: [4, 2],
dashAggregate: [1, 2],
dashSnow: [4, 2, 1, 2],
dashOther: [4, 2, 1, 2, 1, 2],
// Labels
labelColor: '#a080c0',
labelHaloColor: '#0a0a14',
labelHaloWidth: 1.5,
labelOpacity: 0.85,
labelSize: 11,
labelFont: ['Noto Sans Regular'],
// Hit layer
hitWidth: 14,
},
}
/**
* Satellite adjustments - dark, desaturated, purple-shifted
*/
const cyberpunkSatellite = {
opacity: 0.8,
brightnessMin: 0.0,
brightnessMax: 0.30,
contrast: 0.15,
saturation: -0.6,
hueRotate: 280,
}
/**
* Cyberpunk theme configuration
*/
const cyberpunkTheme = {
id: 'cyberpunk',
name: 'Cyberpunk',
dark: true,
swatch: ['#0a0a14', '#ff2d6b', '#00f0ff'],
fontImports: [
'https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;600;700&display=swap',
'https://fonts.googleapis.com/css2?family=Share+Tech+Mono&display=swap',
],
colors: cyberpunkColors,
satellite: cyberpunkSatellite,
overlay: cyberpunkOverlay,
ui: cyberpunkUI,
}
export default cyberpunkTheme