Skip to content

Commit 8cd5f9f

Browse files
committed
Add focus, dark mode, high contrast, and prefers-contrast support
1 parent bf206f0 commit 8cd5f9f

2 files changed

Lines changed: 94 additions & 4 deletions

File tree

Examples/webgpu-jelly-slider/index.html

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,55 @@
77
</head>
88
<body>
99
<style>
10+
:root {
11+
color-scheme: light dark;
12+
}
1013
#slider {
1114
cursor: grab;
1215
width: 75%;
1316
height: 12.5%;
1417
opacity: 0;
18+
19+
--jelly-color: rgb(255, 115, 19);
20+
--ground-color: rgb(255, 255, 255);
21+
--text-color: rgb(40, 40, 40);
22+
23+
color: var(--jelly-color);
24+
background-color: var(--ground-color);
25+
caret-color: var(--text-color);
26+
}
27+
#slider:focus {
28+
--jelly-color: rgb(51, 153, 255);
29+
}
30+
@media (prefers-color-scheme: dark) {
31+
#slider {
32+
--ground-color: rgb(26, 26, 26);
33+
--text-color: rgb(204, 204, 204);
34+
}
35+
}
36+
@media (prefers-contrast: more) {
37+
#slider {
38+
--jelly-color: rgb(255, 51, 0);
39+
--text-color: rgb(0, 0, 0);
40+
}
41+
#slider:focus {
42+
--jelly-color: rgb(0, 0, 255);
43+
}
44+
@media (prefers-color-scheme: dark) {
45+
#slider {
46+
--text-color: rgb(255, 255, 255);
47+
}
48+
}
49+
}
50+
@media (forced-colors: active) {
51+
#slider {
52+
--jelly-color: transparent;
53+
--ground-color: Canvas;
54+
--text-color: CanvasText;
55+
}
56+
#slider:focus {
57+
--jelly-color: Highlight;
58+
}
1559
}
1660
#value {
1761
text-align: right;

Examples/webgpu-jelly-slider/src/index.ts

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import {
2929
AO_INTENSITY,
3030
AO_RADIUS,
3131
AO_STEPS,
32-
GROUND_ALBEDO,
3332
JELLY_IOR,
3433
JELLY_SCATTER_STRENGTH,
3534
LINE_HALF_THICK,
@@ -131,6 +130,8 @@ const lightUniform = root.createUniform(DirectionalLight, {
131130
});
132131

133132
const jellyColorUniform = root.createUniform(d.vec4f, d.vec4f(1.0, 0.45, 0.075, 1.0));
133+
const groundColorUniform = root.createUniform(d.vec3f, d.vec3f(1.0));
134+
const groundTextColorUniform = root.createUniform(d.vec3f, d.vec3f(0.5));
134135

135136
const randomUniform = root.createUniform(d.vec2f);
136137
const blurEnabledUniform = root.createUniform(d.u32);
@@ -612,11 +613,11 @@ const renderBackground = (
612613
.mul(std.abs(newNormal.z));
613614

614615
const litColor = calculateLighting(posOffset, newNormal, rayOrigin);
615-
const backgroundColor = applyAO(GROUND_ALBEDO.mul(litColor), posOffset, newNormal)
616+
const backgroundColor = applyAO(groundColorUniform.$.mul(litColor), posOffset, newNormal)
616617
.add(d.vec4f(bounceLight, 0))
617618
.add(d.vec4f(sideBounceLight, 0));
618619

619-
const textColor = std.saturate(backgroundColor.rgb.mul(d.vec3f(0.5)));
620+
const textColor = groundTextColorUniform.$;
620621

621622
return d.vec4f(
622623
std.mix(backgroundColor.rgb, textColor, percentageSample.x).mul(1.0 + highlights),
@@ -705,7 +706,9 @@ const rayMarch = (rayOrigin: d.v3f, rayDirection: d.v3f, _uv: d.v2f) => {
705706

706707
const jelly = std.add(reflection.mul(F), refractedColor.mul(1 - F));
707708

708-
return d.vec4f(jelly, 1.0);
709+
const finalJelly = std.mix(background.rgb, jelly, jellyColorUniform.$.w);
710+
711+
return d.vec4f(finalJelly, 1.0);
709712
}
710713

711714
if (distanceFromOrigin > backgroundDist) {
@@ -838,7 +841,50 @@ resizeObserver.observe(canvas);
838841
animationFrameHandle = requestAnimationFrame(render);
839842

840843

844+
const hcMedia = window.matchMedia('(forced-colors: active)');
845+
const darkMedia = window.matchMedia('(prefers-color-scheme: dark)');
846+
const contrastMedia = window.matchMedia('(prefers-contrast: more)');
847+
848+
const parseColor3 = (colorStr: string): d.Infer<typeof d.vec3f> => {
849+
const match = colorStr.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
850+
if (match) {
851+
return d.vec3f(parseInt(match[1]) / 255, parseInt(match[2]) / 255, parseInt(match[3]) / 255);
852+
}
853+
return d.vec3f(1.0);
854+
};
855+
856+
const parseColor4 = (colorStr: string): d.Infer<typeof d.vec4f> => {
857+
const match = colorStr.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([0-9.]+))?\)/);
858+
if (match) {
859+
const a = match[4] !== undefined ? parseFloat(match[4]) : 1.0;
860+
return d.vec4f(parseInt(match[1]) / 255, parseInt(match[2]) / 255, parseInt(match[3]) / 255, a);
861+
}
862+
return d.vec4f(1.0, 1.0, 1.0, 1.0);
863+
};
864+
865+
const updateColors = () => {
866+
const style = getComputedStyle(sliderElement);
867+
868+
jellyColorUniform.write(parseColor4(style.color));
869+
groundColorUniform.write(parseColor3(style.backgroundColor));
870+
groundTextColorUniform.write(parseColor3(style.caretColor));
871+
(canvas as any).requestPaint?.();
872+
};
873+
874+
sliderElement.addEventListener('focus', updateColors);
875+
sliderElement.addEventListener('blur', updateColors);
876+
hcMedia.addEventListener('change', updateColors);
877+
darkMedia.addEventListener('change', updateColors);
878+
contrastMedia.addEventListener('change', updateColors);
879+
updateColors();
880+
881+
841882
export function onCleanup() {
883+
sliderElement.removeEventListener('focus', updateColors);
884+
sliderElement.removeEventListener('blur', updateColors);
885+
hcMedia.removeEventListener('change', updateColors);
886+
darkMedia.removeEventListener('change', updateColors);
887+
contrastMedia.removeEventListener('change', updateColors);
842888
cancelAnimationFrame(animationFrameHandle);
843889
resizeObserver.disconnect();
844890
root.destroy();

0 commit comments

Comments
 (0)