Skip to content

Commit d2e17e1

Browse files
committed
darkmode and better canvas height for mobile
1 parent 94a8262 commit d2e17e1

4 files changed

Lines changed: 84 additions & 14 deletions

File tree

docs/_static/showcase.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
version https://git-lfs.github.com/spec/v1
2-
oid sha256:ca38daad75bded7da127d610643015dd0a6284f3bb6ae7119d64ea03df4b3152
3-
size 310648
2+
oid sha256:f10b9b152c3ad2ef2b459675f70b9a383f2116773c05ed02fa92d3a590f06655
3+
size 311035

docs/create_showcase.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,14 @@
5555

5656
canvas_id = "showcase_canvas"
5757
html = f"""\
58-
<div style="width:100%; max-width:800px; height:400px; margin:0 auto 1em auto; position:relative;">
59-
<canvas id="{canvas_id}" width="800" height="400" style="width:100%; height:100%; border-radius:8px; display:block;"></canvas>
58+
<style>
59+
#showcase_root {{ --webgpu-canvas-bg: #ffffff; }}
60+
@media (prefers-color-scheme: dark) {{
61+
#showcase_root {{ --webgpu-canvas-bg: #adadad; }}
62+
}}
63+
</style>
64+
<div id="showcase_root" style="width:min(800px,100%); max-width:100%; margin:0 auto 1em auto; position:relative;">
65+
<canvas id="{canvas_id}" width="800" height="400" style="background-color:var(--webgpu-canvas-bg,#ffffff); width:100%; max-width:100%; height:auto; aspect-ratio:800 / 400; border-radius:8px; display:block;"></canvas>
6066
<script>
6167
{engine_js}
6268
RenderEngine.create("{canvas_id}", "{blob_b64}");

webgpu/engine/engine.js

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
// All are concatenated into the same scope by the Python loader — no imports.
55

66
const SAMPLE_COUNT = 4;
7-
const CLEAR_COLOR = { r: 1.0, g: 1.0, b: 1.0, a: 1.0 };
7+
const LIGHT_CLEAR_COLOR = Object.freeze({ r: 1.0, g: 1.0, b: 1.0, a: 1.0 });
8+
const DARK_CLEAR_COLOR = Object.freeze({ r: 0.68, g: 0.68, b: 0.68, a: 1.0 });
9+
const LIGHT_CANVAS_BG = '#ffffff';
10+
const DARK_CANVAS_BG = '#adadad';
811
const DEPTH_FORMAT = 'depth24plus';
912

1013
const TRANSPARENT_BLEND = {
@@ -297,6 +300,10 @@ class RenderEngine {
297300
this._resizeObserver.observe(canvas);
298301
}
299302

303+
// --- Theme handling ---
304+
this._applyTheme();
305+
this._setupThemeObserver();
306+
300307
// --- First frame ---
301308
// In live mode, the host decides when to render. Don't auto-render.
302309
if (this.mode !== 'live') this.render();
@@ -741,7 +748,7 @@ class RenderEngine {
741748
resolveTarget: canvasTexture.createView(),
742749
loadOp: 'clear',
743750
storeOp: 'store',
744-
clearValue: CLEAR_COLOR,
751+
clearValue: this.clearColor || LIGHT_CLEAR_COLOR,
745752
}],
746753
depthStencilAttachment: {
747754
view: this.depthTexture.createView(),
@@ -864,8 +871,50 @@ class RenderEngine {
864871
return out;
865872
}
866873

874+
_isDarkMode() {
875+
try {
876+
return !!(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches);
877+
} catch {
878+
return false;
879+
}
880+
}
881+
882+
_applyTheme() {
883+
const dark = this._isDarkMode();
884+
this.clearColor = dark ? DARK_CLEAR_COLOR : LIGHT_CLEAR_COLOR;
885+
if (this.canvas && this.canvas.style) {
886+
this.canvas.style.backgroundColor = dark ? DARK_CANVAS_BG : LIGHT_CANVAS_BG;
887+
}
888+
}
889+
890+
_setupThemeObserver() {
891+
if (typeof window === 'undefined' || !window.matchMedia) return;
892+
this._themeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
893+
this._onThemeChange = () => {
894+
this._applyTheme();
895+
this.render();
896+
};
897+
if (this._themeMediaQuery.addEventListener) {
898+
this._themeMediaQuery.addEventListener('change', this._onThemeChange);
899+
} else if (this._themeMediaQuery.addListener) {
900+
this._themeMediaQuery.addListener(this._onThemeChange);
901+
}
902+
}
903+
904+
_teardownThemeObserver() {
905+
if (!this._themeMediaQuery || !this._onThemeChange) return;
906+
if (this._themeMediaQuery.removeEventListener) {
907+
this._themeMediaQuery.removeEventListener('change', this._onThemeChange);
908+
} else if (this._themeMediaQuery.removeListener) {
909+
this._themeMediaQuery.removeListener(this._onThemeChange);
910+
}
911+
this._themeMediaQuery = null;
912+
this._onThemeChange = null;
913+
}
914+
867915
dispose() {
868916
if (this._resizeObserver) this._resizeObserver.disconnect();
917+
this._teardownThemeObserver();
869918
if (this.input) this.input.dispose();
870919
if (this.interactions) this.interactions.dispose();
871920
if (this.depthTexture) this.depthTexture.destroy();

webgpu/jupyter.py

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,28 @@ def _init_html(scene, width, height, flex=None):
2626

2727
id_ = f"__webgpu_{next(_id_counter)}_"
2828

29-
style = f"background-color: white; width: {width}px; height: {height}px; touch-action: none;"
29+
style = (
30+
f"background-color: var(--webgpu-canvas-bg, #ffffff); width: min({width}px, 100%); max-width: 100%; "
31+
f"height: auto; aspect-ratio: {width} / {height}; touch-action: none;"
32+
)
3033
if flex is not None:
3134
style += f" flex: {flex};"
3235

3336
display(
3437
HTML(
3538
f"""
39+
<style>
40+
#{id_}root {{ --webgpu-canvas-bg: #ffffff; }}
41+
@media (prefers-color-scheme: dark) {{
42+
#{id_}root {{ --webgpu-canvas-bg: #adadad; }}
43+
}}
44+
</style>
3645
<div id='{id_}root'
37-
style="position: relative; width: {width}px; max-width: 100%; overflow: hidden;"
46+
style="position: relative; width: min({width}px, 100%); max-width: 100%; overflow: hidden;"
3847
>
39-
<canvas
48+
<canvas
4049
id='{id_}canvas'
41-
style='{style} max-width: 100%; display: block;'
50+
style='{style} display: block;'
4251
>
4352
</canvas>
4453
<div id='{id_}lilgui'
@@ -204,12 +213,18 @@ def _DrawHTMLLazy(scene, width=640, height=600):
204213

205214
# Emit the lazy-load HTML: only screenshot + overlay, everything else loaded on click
206215
lazy_html = f"""
216+
<style>
217+
#{id_}root {{ --webgpu-canvas-bg: #ffffff; }}
218+
@media (prefers-color-scheme: dark) {{
219+
#{id_}root {{ --webgpu-canvas-bg: #adadad; }}
220+
}}
221+
</style>
207222
<div id='{id_}root'
208-
style="position: relative; width: {width}px; max-width: 100%; overflow: hidden;"
223+
style="position: relative; width: min({width}px, 100%); max-width: 100%; overflow: hidden;"
209224
>
210225
<img id='{id_}img'
211226
src='{screenshot_url}'
212-
style='width: {width}px; height: {height}px; max-width: 100%; display: block;'
227+
style='width: 100%; max-width: 100%; height: auto; aspect-ratio: {width} / {height}; display: block;'
213228
/>
214229
<div id='{id_}overlay'
215230
style='position: absolute; top: 0; left: 0; width: 100%; height: 100%;
@@ -226,8 +241,8 @@ def _DrawHTMLLazy(scene, width=640, height=600):
226241
</div>
227242
<canvas
228243
id='{canvas_id}'
229-
style='background-color: white; width: {width}px; height: {height}px;
230-
touch-action: none; max-width: 100%; display: none;'
244+
style='background-color: var(--webgpu-canvas-bg, #ffffff); width: 100%; max-width: 100%; height: auto;
245+
aspect-ratio: {width} / {height}; touch-action: none; display: none;'
231246
></canvas>
232247
<div id='{id_}lilgui'
233248
style='position: absolute; top: 0; right: 0; z-index: 10;'

0 commit comments

Comments
 (0)