summaryrefslogtreecommitdiff
path: root/shaders/ui.frag.glsl
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-29 06:04:28 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:16 -0300
commit09ec515c5e94de741104038cd61f18b2b997e78c (patch)
tree4a7910c76c650df1695c4e3327538bfd8f68f493 /shaders/ui.frag.glsl
parent4452a8f467765cbfa0dd0444a9bf416ac8bd0bf5 (diff)
downloadpardes-09ec515c5e94de741104038cd61f18b2b997e78c.tar.gz
pardes-09ec515c5e94de741104038cd61f18b2b997e78c.zip
G5: lapis, 0x4200.cafe's manuscript, as a theme with its ornament
A native theme `lapis` (src/themes/lapis.zig) from web/theme/lapis.css: a lapis-deep page, lapis tags with gold names, vellum text, vermilion rubrics, gold rules and a vermilion tag rule, gold selection in lapis ink. Its ornament is the theme's new `decor` (colors.Decor), drawn by a pixel shell inside the chrome it already has (decision 1), all of it off every focus indicator: - page_dots: the site's gold dot grid (#e8c46a22, 22 px), drawn by the cell shader on page-coloured cells alone (flag 0x10000000), so it lies under the text and never under a selection, a tag or the cursor; fixed to the window, a page the panes lie on. - rail_checker: the dither frame's gold and lapis checker in the scroll track (a decor kind, flag 0x08000000), anchored to its rail; the thumb stays solid gold. - tag plaques (tag_border, tag_shadow, tag_stripe): every tag a raised plaque inside its own band, the site's trail: a 2px gold frame and a hard 5px vermilion shadow down and right, both within the band's rows and columns (down, what the slack under the text leaves), so no shadow reaches a body, a grip or the next pane. The focused pane's plaque is the code window's title bar, gold and lapis stripes of 2px, its words on plates of the focused ground; unfocused ones are plain; column and workspace tags take the object-label language (1px frame, 2px shadow toward the page). Drawn as decor under the cells (a group's under range), with blank tag cells see-through and the cells blended premultiplied (pipeline_over) on such frames; opaque windows only. - title_shadow: the titles' vermilion offset shadow under a file name's letters, sampled in the cell shader inside the letters' own cells (flag 0x08000000), none on a cursor. Chrome carries the decor (decor_*, name_ink, active_name_ink); a theme file folds a nested decor literal field by field. Left out, with why, in docs/effects.md: the fonts, the ornaments, a decor crossfade, and in the tty anything but the colours (a tag row has no spare cell for a shadow). An empty column is the page. The effect id is masked to 27 bits (ui.vert/ui.frag) for the fifth flag. Tests: the cell flags land only on page ground and file-name cells, never a cursor, nothing without decor; lapis's plaques stay inside their tag's band, clear of every grip, only the focused one striped; its checker is in the track; no other theme draws any; the separator and focus tests cover lapis. Goldens: theme and themesel (the ring gains lapis after acme). Gates as G4. Feel review: .scratch/render/lapis/ (lapis.png, lapis-2x.png, tags-focused-vs-unfocused-2x.png, a PanelSlide at 60 fps and a quarter).
Diffstat (limited to 'shaders/ui.frag.glsl')
-rw-r--r--shaders/ui.frag.glsl32
1 files changed, 30 insertions, 2 deletions
diff --git a/shaders/ui.frag.glsl b/shaders/ui.frag.glsl
index dca224ba..62dbbfa2 100644
--- a/shaders/ui.frag.glsl
+++ b/shaders/ui.frag.glsl
@@ -10,6 +10,12 @@
layout(set = 2, binding = 0) uniform sampler2D u_atlas;
layout(std140, set = 3, binding = 0) uniform UiUniforms {
float background_opacity;
+ // A theme's ornament (colors.Decor): the page's dots (rgb, strength),
+ // their geometry (period, solid radius, faded radius, in pixels), and a
+ // file name's shadow (rgb, offset in pixels).
+ vec4 decor_dots;
+ vec4 decor_dot_geom;
+ vec4 decor_shadow;
} u_ui;
layout(location = 0) in vec2 v_uv;
@@ -43,7 +49,7 @@ void main() {
float bgA = (v_effect.x & 0x20000000u) != 0u ? 1.0
: (v_effect.x & 0x40000000u) != 0u ? 0.0
: clamp(u_ui.background_opacity, 0.0, 1.0);
- uint effect = v_effect.x & 0x0fffffffu;
+ uint effect = v_effect.x & 0x07ffffffu;
float progress = clamp(uintBitsToFloat(v_effect.y), 0.0, 1.0);
uint cellCol = v_effect.w & 0xffffu;
uint cellRow = v_effect.w >> 16;
@@ -52,7 +58,29 @@ void main() {
// Ink over ground, both premultiplied: v_fg*a + (v_bg*bgA)*(1-a), which is
// mix() with the ground already premultiplied. At bgA = 1 that is exactly
// the mix(v_bg, v_fg, a) at alpha 1 this shader always wrote.
- vec4 cell = vec4(mix(v_bg * bgA, v_fg, a), mix(bgA, 1.0, a));
+ vec3 ground = v_bg;
+ // 0x10000000: the page's ground under a pane body, dotted (lapis): a
+ // dot every period pixels, fixed to the window, under the text.
+ if ((v_effect.x & 0x10000000u) != 0u) {
+ float period = u_ui.decor_dot_geom.x;
+ vec2 d = mod(gl_FragCoord.xy, period) - 0.5 * period;
+ float dot_a = 1.0 - smoothstep(u_ui.decor_dot_geom.y, u_ui.decor_dot_geom.z, length(d));
+ ground = mix(ground, u_ui.decor_dots.rgb, u_ui.decor_dots.a * dot_a);
+ }
+ vec4 under = vec4(ground * bgA, bgA);
+ // Derivatives outside any branch: a pixel's step in the atlas and in
+ // the cell, for the shadow's offset.
+ vec2 step_uv = vec2(dFdx(v_uv.x), dFdy(v_uv.y)) * u_ui.decor_shadow.a;
+ vec2 step_cell = vec2(dFdx(v_cell_uv.x), dFdy(v_cell_uv.y)) * u_ui.decor_shadow.a;
+ // 0x08000000: a file name's letters cast a shadow down and right onto
+ // their own cell's ground (lapis), under the ink; what would fall past
+ // the cell's edge is not drawn.
+ if ((v_effect.x & 0x08000000u) != 0u) {
+ vec2 from = v_cell_uv - step_cell;
+ float s = all(greaterThanEqual(from, vec2(0.0))) ? texture(u_atlas, v_uv - step_uv).r : 0.0;
+ under = mix(under, vec4(u_ui.decor_shadow.rgb, 1.0), s);
+ }
+ vec4 cell = vec4(mix(under.rgb, v_fg, a), mix(under.a, 1.0, a));
// 3 = data dissolve. Changed cells retain the frozen old cell until their
// stable threshold, then atomically become the new cell. Exact endpoints