From 09ec515c5e94de741104038cd61f18b2b997e78c Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Tue, 29 Sep 2026 06:04:28 -0300 Subject: 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). --- src/draw.zig | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'src/draw.zig') diff --git a/src/draw.zig b/src/draw.zig index b8cf4e7d..5f14ae21 100644 --- a/src/draw.zig +++ b/src/draw.zig @@ -470,7 +470,24 @@ pub fn render(p: *Pardes, arena: std.mem.Allocator) !*Surface { .grip_dirty = boxDirty(p), .tag_rule = p.theme().tag_rule, .rail_px = @intCast(@min(255, @as(u32, p.theme().rail_px orelse 12) * p.settings.grip_width / 100)), + .name_ink = chrome.tag_name_fg, + .active_name_ink = if (p.settings.focus_tint) chrome.tag_active_name_fg else chrome.tag_name_fg, }; + if (p.theme().decor) |decor| { + s.chrome.decor_dots = decor.page_dots; + s.chrome.decor_dot_alpha = decor.page_dot_alpha; + s.chrome.decor_dot_px = decor.page_dot_px; + s.chrome.decor_checker = decor.rail_checker; + s.chrome.decor_checker_px = decor.rail_checker_px; + s.chrome.decor_box_border = decor.tag_border; + s.chrome.decor_box_border_px = decor.tag_border_px; + s.chrome.decor_box_shadow = decor.tag_shadow; + s.chrome.decor_box_shadow_px = decor.tag_shadow_px; + s.chrome.decor_box_stripe = decor.tag_stripe; + s.chrome.decor_box_stripe_px = decor.tag_stripe_px; + s.chrome.decor_title = decor.title_shadow; + s.chrome.decor_title_px = decor.title_shadow_px; + } place(p, s); // Separators have their own role; a scrollbar need not frame the page. const whole = s.regions[0].rect; -- cgit v1.3