aboutsummaryrefslogtreecommitdiff
path: root/docs/design
diff options
context:
space:
mode:
Diffstat (limited to 'docs/design')
-rw-r--r--docs/design/theme-studio-face-rules.org47
1 files changed, 47 insertions, 0 deletions
diff --git a/docs/design/theme-studio-face-rules.org b/docs/design/theme-studio-face-rules.org
new file mode 100644
index 00000000..4eb3e1b3
--- /dev/null
+++ b/docs/design/theme-studio-face-rules.org
@@ -0,0 +1,47 @@
+#+TITLE: theme-studio face rules
+#+DATE: 2026-06-09
+
+Two kinds of rules govern a theme's face structure. They are different in kind and must be kept separate: Design Rules are the designer's taste and may change per theme; Fidelity Rules come from the principles and never change. A face's final structure is its defface baseline (Fidelity), with Design Rules applied deliberately on top.
+
+* Design Rules (personal, optional, per-theme)
+
+Aesthetic choices the designer makes. They override package/Emacs defaults on purpose and are applied consistently across a whole face family. They can change from theme to theme. The tool should let the designer declare them and flag where the theme breaks one (these are not bugs — they are the rule being enforced).
+
+Structural only (weight/slant/underline/box/overline/height). Color is the palette, decided separately.
+
+** D1 — Headings and titles are bold
+
+Every heading/title face carries =:weight bold=, overriding per-package size-only or plain conventions: =org-level-*=, =shr-h1=..=shr-h6=, =magit-*-heading=, =*-title=, =org-document-title=, =dashboard-heading=, =telega-*-title= / =telega-*-heading=, etc.
+
+Open question for dupre: does the rule mean *all* headings bold, or *headings get emphasis via bold OR descending size*? org-level-2..8 use size, not weight.
+
+dupre faces that break D1 (heading/title but not bold):
+- size-based (intentional? — org distinguishes levels by height): org-level-2, org-level-3, org-level-4, org-level-5, org-level-6, org-level-7, org-level-8
+- genuinely plain (no bold, no height): magit-blame-heading, magit-diff-hunk-heading, telega-msg-heading, telega-describe-subsection-title, telega-secret-title
+
+** D2 — Hyperlinks are underlined
+
+Every hyperlink face carries =:underline=, applied across packages: =link=, =org-link=, =shr-link=, =shr-selected-link=, =mu4e-link-face=, =telega-link*=, etc. (Symlinks and link-count faces are not hyperlinks and are exempt.)
+
+dupre faces that break D2 (hyperlink but not underlined):
+- telega-link, telega-link-preview-sitename, telega-link-preview-title, telega-webpage-chat-link
+
+* Fidelity Rules (principle-derived, mandatory, theme-independent)
+
+Correctness and honesty invariants. They do not change between themes. A violation is a bug, not a preference.
+
+** F1 — Preview only what the theme controls
+
+Every element a preview draws must correspond to a real face the generated theme exports. No hardcoded decoration that implies theme control (this is why the mode-line box became a real =:box= attribute instead of a painted-on bevel, and why the fg/bg contrast cell must rate the face's own pair). Representational stand-ins are allowed only for theme-controlled *colors* whose shape/presence Emacs controls elsewhere — e.g. the cursor drawn as a box (the color is the =cursor= face; the shape is =cursor-type=), the fringe indicator (the color is the =fringe= face; the arrow's presence is truncation state).
+
+** F2 — Render the way Emacs renders
+
+A face is drawn the way Emacs would draw it. Overlay-style faces (region, highlight, isearch, lazy-highlight) merge like Emacs: the background applies and the foreground falls through to the underlying syntax colors unless the face sets its own. The block cursor sits on a glyph in the frame background over the cursor color. Every modeled attribute (weight/slant/underline/strike/box/height) actually renders, in both the table preview and the live buffer.
+
+** F3 — Preserve each face's defface structural baseline
+
+A face's own defface structural attributes (weight/slant/underline/box/overline/height/inherit) carry through into the theme's default for that face, except where a Design Rule deliberately overrides. An accidental drop — e.g. replacing =:inherit link= with a bare foreground and losing the underline — is a bug. For Emacs's built-in faces the baseline is verified against =emacs -Q= (error/warning/success bold; link, lazy-highlight, show-paren-match underline); for package faces, against the package's defface source.
+
+** F4 — Reference only real faces
+
+Every face the theme sets or previews must exist in Emacs. A face the theme defines that no package defines (a typo, a renamed/obsolete face) controls nothing and shows a phantom sample in the preview; it is removed. (This took out 11 dead mu4e faces.)