Skip to content

Commit f9f32f1

Browse files
committed
Add vibrant themes with p3 color space
1 parent e364188 commit f9f32f1

File tree

9 files changed

+711
-13
lines changed

9 files changed

+711
-13
lines changed

DISPLAY-P3.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# Display P3 Color Space Implementation
2+
3+
This document covers the Display P3 color space implementation for the Pierre theme, including technical details for future reference.
4+
5+
## Overview
6+
7+
The vibrant theme variants (`pierre-light-vibrant.json` and `pierre-dark-vibrant.json`) use CSS `color(display-p3 r g b)` format with saturation enhancement to fully utilize Display P3's wider color gamut. These themes are designed for web projects using [Shiki](https://shiki.style/) syntax highlighting. They won't work in VS Code itself, as VS Code only supports hex/RGB color formats.
8+
9+
## Color Conversion Process
10+
11+
### 1. Linear Transformation
12+
13+
```typescript
14+
// 1. Parse hex → RGB (0-1 range)
15+
const [r, g, b] = hexToRgb01(hex)
16+
17+
// 2. Linearize sRGB (remove gamma)
18+
const linear = srgbToLinear(rgb)
19+
20+
// 3. Transform to P3 color space (matrix transformation)
21+
const [rP3, gP3, bP3] = linearSrgbToLinearP3(linearR, linearG, linearB)
22+
23+
// 4. Apply P3 gamma
24+
const displayP3 = linearToP3(linearP3)
25+
```
26+
27+
**Transformation Matrix** (linear sRGB → linear P3):
28+
```
29+
R_p3 = 0.82246197 * R_srgb + 0.17753803 * G_srgb
30+
G_p3 = 0.03319420 * R_srgb + 0.96680580 * G_srgb
31+
B_p3 = 0.01708263 * R_srgb + 0.07239744 * G_srgb + 0.91051993 * B_srgb
32+
```
33+
34+
### 2. Gamut Enhancement
35+
36+
After P3 conversion, colors are enhanced to push into the wider gamut:
37+
38+
```typescript
39+
// 1. Convert to HSL for easier manipulation
40+
const [h, s, l] = rgbToHsl(r, g, b)
41+
42+
// 2. Skip neutrals (grays, near-blacks/whites)
43+
if (s < 0.1 || l < 0.1 || l > 0.9) return [r, g, b]
44+
45+
// 3. Boost saturation (15-30% based on original)
46+
const saturationBoost = 0.15 + (s * 0.15)
47+
const newS = Math.min(1.0, s + (s * saturationBoost))
48+
49+
// 4. Boost luminance for vibrant colors (5%)
50+
let newL = l
51+
if (s > 0.5 && l < 0.7) {
52+
newL = Math.min(0.9, l + (l * 0.05))
53+
}
54+
55+
// 5. Convert back to RGB → format as CSS
56+
return `color(display-p3 ${r} ${g} ${b})`
57+
```
58+
59+
This enhancement pushes colors into P3 gamut regions not accessible in sRGB, making them noticeably more vibrant on compatible displays.
60+
61+
## Color Examples
62+
63+
| Color | sRGB (Standard) | Display P3 (Vibrant) | Notes |
64+
|--------|-----------------|----------------------|-------|
65+
| Blue | `#008cff` | `color(display-p3 0.267653 0.570512 1.000000)` | Maxed blue channel |
66+
| Red | `#ff2e3f` | `color(display-p3 1.000000 0.250216 0.262337)` | Maxed red channel |
67+
| Purple | `#c635e4` | `color(display-p3 0.770871 0.230698 0.945253)` | Highly saturated |
68+
| Green | `#0dbe4e` | `color(display-p3 0.298067 0.776115 0.322484)` | Enhanced saturation |
69+
| Cyan | `#08c0ef` | `color(display-p3 0.327292 0.790977 0.995660)` | Nearly maxed blue |
70+
71+
## Usage with Shiki
72+
73+
```bash
74+
npm i @pierre/vscode-theme
75+
```
76+
77+
```typescript
78+
import { createHighlighter } from 'shiki'
79+
import pierreDarkVibrant from 'pierre-vscode-theme/themes/pierre-dark-vibrant.json'
80+
81+
const highlighter = await createHighlighter({
82+
themes: [pierreDarkVibrant],
83+
langs: ['typescript', 'javascript']
84+
})
85+
86+
const html = highlighter.codeToHtml(code, {
87+
lang: 'typescript',
88+
theme: 'Pierre Dark Vibrant'
89+
})
90+
```
91+
92+
## Relevant files
93+
94+
- **`src/color-p3.ts`** - Color conversion and enhancement
95+
- **`src/demo-p3.ts`** - Demo showing conversions (`npx ts-node src/demo-p3.ts`)
96+
- **`color-comparison.html`** - Visual comparison tool (open in Safari on P3 display)
97+
98+
## Testing
99+
100+
```bash
101+
# View color conversions
102+
npx ts-node src/demo-p3.ts
103+
104+
# Rebuild themes
105+
npm run build
106+
107+
# Run tests
108+
npm test
109+
```
110+
111+
## Why this matters
112+
113+
Unlike typical P3 conversions that just transform color space mathematically, this implementation:
114+
115+
1. **Actually uses the wider gamut** - Pushes colors beyond sRGB constraints
116+
2. **Intelligently enhances** - Only boosts saturated colors, preserves neutrals
117+
3. **Maintains accuracy** - Grays, blacks, whites stay true
118+
4. **Degrades gracefully** - Automatic fallback for non-P3 browsers
119+
120+
This makes the themes truly take advantage of modern display technology on compatible hardware.

README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,20 @@
66

77
1. Go to the [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=pierre-computer-co.pierre-vscode-theme).
88
2. Click on the "Install" button.
9-
3. Then [select a theme](https://code.visualstudio.com/docs/getstarted/themes#_selecting-the-color-theme). Two themes are included:
9+
3. Then [select a theme](https://code.visualstudio.com/docs/getstarted/themes#_selecting-the-color-theme). Four themes are included:
1010
- `Pierre Light`
1111
- `Pierre Dark`
12+
- `Pierre Light Vibrant` (Display P3 color space)
13+
- `Pierre Dark Vibrant` (Display P3 color space)
14+
15+
## Vibrant themes (Display P3)
16+
17+
> [!NOTE]
18+
> Vibrant themes do not work in VS Code at this time as it does not support color formats other than Hex or RGB. You can, however, use these with [Precision Diffs](https://pierrejs-docs.vercel.app) or any [Shiki](https://shiki.style) project to render code.
19+
20+
The **Vibrant** theme variants use CSS's `color(display-p3 r g b)` format with enhanced saturation to fully utilize Display P3's wider color gamut. Display P3 can represent ~25% more colors than standard sRGB, and these themes are optimized to take full advantage of that on compatible displays.
21+
22+
The conversion algorithm transforms sRGB colors to Display P3 through proper linear color space transformations, then enhances saturation (15-30%) and luminance (5% for vibrant colors) to push colors into the wider P3 gamut that isn't accessible in sRGB.
1223

1324
## Override
1425

color-comparison.html

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>Pierre Theme - Display P3 Color Comparison</title>
7+
<style>
8+
body {
9+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
10+
max-width: 1200px;
11+
margin: 40px auto;
12+
padding: 20px;
13+
background: #141415;
14+
color: #fbfbfb;
15+
}
16+
h1 { text-align: center; margin-bottom: 40px; }
17+
.comparison-grid {
18+
display: grid;
19+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
20+
gap: 30px;
21+
margin: 40px 0;
22+
}
23+
.color-card {
24+
background: #1f1f21;
25+
border-radius: 12px;
26+
padding: 20px;
27+
border: 1px solid #39393c;
28+
}
29+
.color-card h3 {
30+
margin-top: 0;
31+
color: #fbfbfb;
32+
}
33+
.color-swatch {
34+
height: 100px;
35+
border-radius: 8px;
36+
margin: 10px 0;
37+
display: flex;
38+
align-items: center;
39+
justify-content: center;
40+
font-weight: 600;
41+
font-family: 'Monaco', 'Courier New', monospace;
42+
font-size: 12px;
43+
color: white;
44+
text-shadow: 0 0 2px rgba(0,0,0,0.5);
45+
}
46+
47+
.label {
48+
font-size: 12px;
49+
color: #adadb1;
50+
margin-bottom: 5px;
51+
margin-top: 15px;
52+
}
53+
.hex-value {
54+
font-family: 'Monaco', 'Courier New', monospace;
55+
font-size: 11px;
56+
color: #c6c6c8;
57+
margin-top: 5px;
58+
word-break: break-all;
59+
}
60+
.info {
61+
background: #2e2e30;
62+
padding: 20px;
63+
border-radius: 8px;
64+
margin: 20px 0;
65+
border-left: 4px solid color(display-p3 0.340 0.734 0.360);
66+
}
67+
.info h3 {
68+
margin-top: 0;
69+
}
70+
.p3-notice {
71+
text-align: center;
72+
padding: 15px;
73+
background: #39393c;
74+
border-radius: 8px;
75+
margin: 20px 0;
76+
}
77+
.supports { color: color(display-p3 0.340 0.734 0.360); }
78+
.no-support { color: #ff6762; }
79+
80+
code {
81+
background: #2e2e30;
82+
padding: 2px 6px;
83+
border-radius: 4px;
84+
font-size: 13px;
85+
}
86+
</style>
87+
</head>
88+
<body>
89+
<h1>Pierre Theme: Display P3 Color Comparison</h1>
90+
91+
<div class="p3-notice" id="p3-status">
92+
Checking Display P3 support...
93+
</div>
94+
95+
<div class="info">
96+
<h3>About Display P3 Enhanced Colors</h3>
97+
<p>Display P3 is a wider color gamut that can display ~25% more colors than standard sRGB. The Pierre Vibrant themes use CSS <code>color(display-p3 r g b)</code> format with <strong>enhanced saturation</strong> to fully utilize the P3 color space.</p>
98+
<p><strong>Enhancement:</strong> Colors are boosted by 15-30% saturation (depending on original saturation) and 5% luminance for highly saturated colors. This pushes colors into the wider P3 gamut that isn't available in sRGB.</p>
99+
<p><strong>Important:</strong> To see the difference, you need a P3-capable display (most Macs from 2015+, iPhones, iPads).</p>
100+
</div>
101+
102+
<div class="comparison-grid">
103+
<div class="color-card">
104+
<h3>Blue</h3>
105+
<div class="label">Standard (sRGB)</div>
106+
<div class="color-swatch srgb" style="background-color: #008cff;">
107+
#008cff
108+
</div>
109+
<div class="label">Vibrant (Display P3 Enhanced)</div>
110+
<div class="color-swatch p3" style="background-color: color(display-p3 0.267653 0.570512 1.000000);">
111+
P3
112+
</div>
113+
<div class="hex-value">color(display-p3 0.267653 0.570512 1.000000)</div>
114+
</div>
115+
116+
<div class="color-card">
117+
<h3>Green</h3>
118+
<div class="label">Standard (sRGB)</div>
119+
<div class="color-swatch srgb" style="background-color: #0dbe4e;">
120+
#0dbe4e
121+
</div>
122+
<div class="label">Vibrant (Display P3 Enhanced)</div>
123+
<div class="color-swatch p3" style="background-color: color(display-p3 0.298067 0.776115 0.322484);">
124+
P3
125+
</div>
126+
<div class="hex-value">color(display-p3 0.298067 0.776115 0.322484)</div>
127+
</div>
128+
129+
<div class="color-card">
130+
<h3>Red</h3>
131+
<div class="label">Standard (sRGB)</div>
132+
<div class="color-swatch srgb" style="background-color: #ff2e3f;">
133+
#ff2e3f
134+
</div>
135+
<div class="label">Vibrant (Display P3 Enhanced)</div>
136+
<div class="color-swatch p3" style="background-color: color(display-p3 1.000000 0.250216 0.262337);">
137+
P3
138+
</div>
139+
<div class="hex-value">color(display-p3 1.000000 0.250216 0.262337)</div>
140+
</div>
141+
142+
<div class="color-card">
143+
<h3>Purple</h3>
144+
<div class="label">Standard (sRGB)</div>
145+
<div class="color-swatch srgb" style="background-color: #c635e4;">
146+
#c635e4
147+
</div>
148+
<div class="label">Vibrant (Display P3 Enhanced)</div>
149+
<div class="color-swatch p3" style="background-color: color(display-p3 0.770871 0.230698 0.945253);">
150+
P3
151+
</div>
152+
<div class="hex-value">color(display-p3 0.770871 0.230698 0.945253)</div>
153+
</div>
154+
155+
<div class="color-card">
156+
<h3>Pink</h3>
157+
<div class="label">Standard (sRGB)</div>
158+
<div class="color-swatch srgb" style="background-color: #fc2b73;">
159+
#fc2b73
160+
</div>
161+
<div class="label">Vibrant (Display P3 Enhanced)</div>
162+
<div class="color-swatch p3" style="background-color: color(display-p3 0.995522 0.233444 0.460772);">
163+
P3
164+
</div>
165+
<div class="hex-value">color(display-p3 0.995522 0.233444 0.460772)</div>
166+
</div>
167+
168+
<div class="color-card">
169+
<h3>Orange</h3>
170+
<div class="label">Standard (sRGB)</div>
171+
<div class="color-swatch srgb" style="background-color: #fe8c2c;">
172+
#fe8c2c
173+
</div>
174+
<div class="label">Vibrant (Display P3 Enhanced)</div>
175+
<div class="color-swatch p3" style="background-color: color(display-p3 1.000000 0.598672 0.265916);">
176+
P3
177+
</div>
178+
<div class="hex-value">color(display-p3 1.000000 0.598672 0.265916)</div>
179+
</div>
180+
181+
<div class="color-card">
182+
<h3>Cyan</h3>
183+
<div class="label">Standard (sRGB)</div>
184+
<div class="color-swatch srgb" style="background-color: #08c0ef;">
185+
#08c0ef
186+
</div>
187+
<div class="label">Vibrant (Display P3 Enhanced)</div>
188+
<div class="color-swatch p3" style="background-color: color(display-p3 0.327292 0.790977 0.995660);">
189+
P3
190+
</div>
191+
<div class="hex-value">color(display-p3 0.327292 0.790977 0.995660)</div>
192+
</div>
193+
194+
<div class="color-card">
195+
<h3>Teal</h3>
196+
<div class="label">Standard (sRGB)</div>
197+
<div class="color-swatch srgb" style="background-color: #00c5d2;">
198+
#00c5d2
199+
</div>
200+
<div class="label">Vibrant (Display P3 Enhanced)</div>
201+
<div class="color-swatch p3" style="background-color: color(display-p3 0.342284 0.816699 0.877157);">
202+
P3
203+
</div>
204+
<div class="hex-value">color(display-p3 0.342284 0.816699 0.877157)</div>
205+
</div>
206+
</div>
207+
208+
<div class="info">
209+
<h3>Browser Support</h3>
210+
<p>CSS <code>color(display-p3 ...)</code> is supported in:</p>
211+
<ul>
212+
<li>Safari 10+ (macOS and iOS)</li>
213+
<li>Chrome 111+</li>
214+
<li>Firefox 113+</li>
215+
<li>Edge 111+</li>
216+
</ul>
217+
<p>Browsers without P3 support will automatically fall back to the closest sRGB color.</p>
218+
</div>
219+
220+
<script>
221+
// Check for P3 support
222+
const supportsP3 = window.matchMedia('(color-gamut: p3)').matches;
223+
const statusEl = document.getElementById('p3-status');
224+
225+
if (supportsP3) {
226+
statusEl.innerHTML = '<span class="supports">✓</span> Your display supports Display P3! You should see more vibrant colors in the P3 swatches above. Compare the top and bottom colors in each card.';
227+
statusEl.style.borderLeft = '4px solid color(display-p3 0.340 0.734 0.360)';
228+
} else {
229+
statusEl.innerHTML = '<span class="no-support">✗</span> Your display does not support Display P3, or your browser doesn\'t support the color(display-p3) syntax. The P3 colors will appear similar to the standard sRGB colors.';
230+
statusEl.style.borderLeft = '4px solid #ff6762';
231+
}
232+
</script>
233+
</body>
234+
</html>

package.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@
4040
"label": "Pierre Dark",
4141
"uiTheme": "vs-dark",
4242
"path": "./themes/pierre-dark.json"
43+
},
44+
{
45+
"label": "Pierre Light Vibrant",
46+
"uiTheme": "vs",
47+
"path": "./themes/pierre-light-vibrant.json"
48+
},
49+
{
50+
"label": "Pierre Dark Vibrant",
51+
"uiTheme": "vs-dark",
52+
"path": "./themes/pierre-dark-vibrant.json"
4353
}
4454
]
4555
},

0 commit comments

Comments
 (0)