aboutsummaryrefslogtreecommitdiff
path: root/docs
Commit message (Collapse)AuthorAgeFilesLines
* feat(music): queue radio picks and save on requestCraig Jennings21 hours1-0/+1
| | | | | | | | The radio-browser lookup and the manual station creator no longer write .m3u files at pick time. Picks become url tracks in the queue, carrying the station name, uuid, and favicon as track properties, and play immediately. The display and cover-art layers read the properties first and fall back to the on-disk metadata, so existing station files keep working. Saving is the normal playlist save, now on w. The radio feature's S=stop rebind had silently shadowed the old S=save binding. An all-stream queue saves into the MPD playlist dir, and the station name pre-fills the prompt with no -Radio suffix. A custom emitter writes the station metadata back out as .m3u comment lines, since the stock EMMS writer emits bare URLs and would lose names and cover art on reload. I removed the write-at-pick machinery (station-m3u, write-stations, disambiguate-name, the -Radio filename suffix) and the orphaned safe-filename helper. An empty name at the save prompt now signals an error instead of writing a hidden .m3u.
* docs(specs): flip fancy music-player UI spec READY -> DOINGCraig Jennings3 days1-2/+3
|
* docs(specs): review and respond fancy music-player UI spec (READY)Craig Jennings3 days1-17/+55
| | | | | | | | | | I reviewed the fancy music-player UI spec, then dispositioned all seven findings: five accept, two modify, none rejected. Two were blockers. The progress bar had a chosen rendering and cadence but no data source: a stream has no duration, and for a local file the elapsed position isn't wired. The playing-time display is off and the mpv IPC helper is send-only. I narrowed it to mpv's percent-pos over the socket the seek commands already use, with streams rendering "on air" and no fill. That avoids reviving the EMMS timer I turned off on purpose. The named row renderer, cj/music--track-description, is also the header's now-playing source and EMMS's description function, so glyph and meta would have leaked into both. I split it into a pure name-only helper the header and the row share, with the glyph, aligned meta, and image added on the row alone. The rest tightened scope: favicon-at-creation applies to search-created stations only, fetched art is validated before caching, meta right-aligns with :align-to so it survives a resize, the placeholder is a shipped vinyl SVG with per-station tinting left to vNext, and the nerd-icons dependency gets a require and a TTY fallback. I flipped DRAFT to READY.
* docs(specs): resolve fancy music-player UI decisions (5/5)Craig Jennings3 days1-6/+7
|
* docs(specs): add fancy music-player UI spec + prototype (DRAFT)Craig Jennings3 days2-0/+369
| | | | | | | | A spec for the hi-fi look Craig picked from the prototype: the EMMS playlist buffer gains names instead of stream URLs, cover art, a serif now-playing hero with a progress bar, and a warm amber palette, degrading to plain text in a terminal frame. I verified the cover-art path is reachable (radio-browser stations carry a favicon URL, retrievable at search time or by UUID) and framed the work as three layers: a name and text base that ships value on its own and doubles as the terminal fallback, cover-art fetch and cache, then the fancy GUI render. Five design decisions are open, each with a recommended call. The three-direction prototype (minimal, fancy, modern) lands beside the spec as its companion.
* feat(music): radio row for name, tag, and manual station searchCraig Jennings3 days1-2/+3
| | | | | | | | I turned the radio-browser lookup into a Radio row in the playlist buffer: n searches by station name, t searches by tag/genre, m enters a station by hand. Tag search is new (it was a vNext item), and both name and tag hit radio-browser's search endpoint with a name= or tag= field. Freeing n and t moved two keys: single mode goes from t to s, and stop goes from s to S. The header gains a Radio row and the Mode row now reads [s] single. Created station files carry a -Radio suffix (Adroit_Jazz_Underground-Radio.m3u). The pure pieces and the search-URL field are unit-tested (20). Name and tag searches are live-verified. The picker and playback stay a manual check.
* feat(music): radio-browser search client + emitter (phase 1)Craig Jennings3 days1-2/+3
| | | | | | | | I built the first phase of the radio-browser lookup: the pure pieces and the network client behind the search command, with no UI yet. It lives in modules/music-config.el, alongside the existing radio-station creator. The client is url.el plus json-parse-string, trying a pinned host and falling back to one from /json/servers. The pure layer parses a response into station plists, and a non-JSON body signals a clear user-error rather than a stack trace. It picks a station's stream URL (url_resolved, then url), emits the .m3u in the existing radio format with the radio-browser UUID, formats the completion annotation (codec, bitrate, country, votes, tags), and disambiguates a colliding filename by UUID. Names are newline-stripped so an odd one can't inject extra m3u lines. The pure pieces are unit-tested (14). The network client is smoke-tested against the live API.
* docs(specs): review + respond the radio-browser lookup spec (READY)Craig Jennings3 days1-12/+44
| | | | | | I reviewed the spec and folded the review back in. The review found seven gaps, one blocking: completing-read-multiple splits its selection on commas, and radio-browser station names contain commas. A comma'd name would be mis-selected silently. Resolving all seven: selection is now a loop-based single-select that never round-trips through a delimiter, the emitter skips a station with no usable stream URL, same-name picks in one search disambiguate by UUID, the server client has a defined fallback, and create-and-play interrupts current playback. The annotation format is codec, bitrate, country, votes, and tags, with no play count. Decisions read 5 of 5 and findings 7 of 7, so the spec flips to READY.
* docs(specs): add radio-browser lookup UI prototypeCraig Jennings3 days2-0/+194
| | | | | | The prototype is a standalone HTML mockup of the four minibuffer screens for the radio-browser lookup: query, station list, multi-select, and created-and-playing. I drew it with real jazz-search data in the vertico and marginalia style. It shows the two candidate-annotation formats the design picks between. The spec's References section links to it. This sets the convention for a spec's visual companion: docs/specs/<slug>.prototype.html, tracked alongside the spec.
* docs(specs): add radio-browser station lookup spec (DRAFT)Craig Jennings3 days1-0/+162
| | | | | | A spec for searching radio-browser.info from Emacs and turning a selection into a playable radio .m3u, reusing the existing writer, multi-directory sourcing, and mpv path. The player can already read and play radio playlists but has no native way to discover stations, so every station is hand-entered from a browser. I verified the API live (server discovery and station search) and matched the output to the existing radio .m3u format. All four design decisions are resolved: built-in url.el, multi-select writing one file per station, saving into the MPD playlist directory, and create-and-play. The spec has two build phases and is ready for spec-review.
* docs(specs): record seeding Phase 2 blocker in the spec historyCraig Jennings5 days1-0/+7
| | | | | | The spec's package-scope premise is false against the generator. It assumes the non-org bespoke packages keep their curated dupre seeds, but apply_default_face_seeds overwrites every bespoke face with the Emacs-default snapshot whenever emacs-default-faces.json is present, so org opens empty and the rest open on light-theme hexes. "Keep the curated defaults" and "the seeded page reads as a coherent dupre" then contradict, and the dupre-revised.json emitter can't be pure-Node because the non-org colors live in Python. Phase 1 stands. I paused Phase 2 pending a spec revision that picks the direction: reseed the non-org packages from the curated dupre dicts, or keep the snapshot hexes.
* docs: reclassify subr-mock-migration as a design noteCraig Jennings5 days1-1/+1
|
* docs(specs): adopt status-heading lifecycle convention across specsCraig Jennings5 days31-132/+248
| | | | | | | | Migrate 29 legacy specs off the old shape (a status suffix in the filename plus a :STATUS: property drawer) onto the docs-lifecycle status heading: a top-level heading carrying the org lifecycle keyword and a dated history line, with the two #+TODO sequences in the header. Dropping the -doing/-implemented/-superseded suffixes means a status change no longer forces a rename and link surgery. Each keyword comes from the spec's own recorded status. The four specs already on the heading form are untouched, and every inbound reference now points at the new names. The status board is one grep: rg '^\* (DRAFT|READY|DOING|IMPLEMENTED|SUPERSEDED|CANCELLED) ' docs/specs/
* docs: editable-height spec READY -> DOINGCraig Jennings6 days1-2/+8
| | | | | Phases decomposed into build tasks; Phase 1 gains a load-time kind-inference migration for saved themes that predate the explicit height-kind field.
* docs: editable-height spec reviewed, DRAFT -> READYCraig Jennings6 days1-23/+39
| | | | | | | | | | Code read surfaced two findings: JSON collapses integral relative floats to absolute ints (WIP.json's mode-line-inactive height 2 is the live casualty), so the face model carries the kind explicitly; and the minimal seed fix the metadata referenced never shipped. All five open decisions settled: one field plus abs/rel toggle, exposed on chrome plus already-seeded faces, raw 1/10pt entry with a pt hint, row-sample plus mock-editor previews, seed fix owns the artifact cleanup.
* docs: theme-studio editable-height spec draftCraig Jennings6 days1-0/+83
| | | | | | Stubbed from the 2026-07-02 nov-reading modeline-height diagnosis: the studio exports per-face :height but offers no editable control, and the absolute-vs- relative distinction is what separates a scaling heading from a fixed modeline.
* docs: sort three theme-studio specs into docs/specs with status headingsCraig Jennings7 days4-7/+31
| | | | First spec-sort pass under the docs-lifecycle convention: color-families -> READY (its status field carried the 2026-06-10 confirmation), palette-columns and palette-ramps -> DRAFT. Each got the authoritative status heading with an :ID: UUID; six inbound links rewritten. subr-mock-migration-spec is -spec-named but lacks the spec spine, so it stays put until it's renamed or retrofitted.
* docs(calendar-sync): keep placeholder feed-url examplesCraig Jennings8 days1-1/+1
|
* docs: spec for migrating tests off mocking primitivesCraig Jennings9 days1-0/+158
| | | | Pull the long-term subr-mock migration out of the task list into a discussion spec: the native-comp origin, the stopgap already shipped (variadic sweep plus the arity meta-test), the real scope (the UI-prompt mocks, not the boundary mocks the test rules say to keep), and the open decisions to settle before any code moves.
* refactor: prefix two collision-prone helpers, document naming auditCraig Jennings10 days1-0/+91
| | | | | | Two owned helpers carried unprefixed generic names that risk colliding in the single Emacs namespace: car-member (local-repository.el) and unpropertize-kill-ring (system-defaults.el). I renamed them to localrepo--car-member and cj/--unpropertize-kill-ring and updated their callers and tests. Both are non-interactive and contained, so no alias was needed. docs/design/naming-audit.org records the rest of the scan: the allowlist of deliberate module prefixes, the foreign forward-declarations that aren't owned definitions, and a deferred list (keybound commands, the with-timer macro, the ui-theme defcustoms, the user-constants paths) that each want a focused pass rather than an unattended rename.
* docs(term): design for the F12 -> EAT terminal swapCraig Jennings14 days1-0/+83
|
* chore(google-keep): mark v1 implemented, file live-setup VERIFY, record in specCraig Jennings2026-06-251-1/+5
|
* docs(spec): round 2 review clean, google-keep spec ReadyCraig Jennings2026-06-251-1/+5
|
* docs(spec): fold round-1 review into google-keep spec (rubric Ready)Craig Jennings2026-06-251-30/+90
|
* docs(spec): resolve google-keep decisions (read-only v1 to write v2, ↵Craig Jennings2026-06-251-52/+51
| | | | gkeepapi, authinfo)
* docs(spec): google-keep in-editor integration spec (draft, 5 open decisions)Craig Jennings2026-06-241-0/+153
|
* feat(theme-studio): visible size-nav buttons + 48 pt gallery scaleCraig Jennings2026-06-241-1/+1
| | | | | | | | | | The preview dropdown gets flanking nav buttons, matching the view selector, so the size steps with a click. Left/Right arrows do the same when the dropdown is focused. Both clamp at the ends and disable on a single-pane app. I extended the size scale to 32 and 48 pt for inspecting a glyph's detail. The cell width scales with the size, so beyond about 48 pt the grid is mostly scrolling. I removed the separate hover info line beside the dropdown. Each glyph's own title tooltip already shows its face and color, so the line was redundant. A new computed-style gate confirms the point size renders to the right pixels (24 pt is 32 px), so the pt label isn't lying.
* feat(theme-studio): nerd-icons gallery as a hue-ordered icon gridCraig Jennings2026-06-241-1/+106
| | | | | | | | | | The nerd-icons pane is now a grid: one row per color face, the rows ordered by hue so families cluster, distinct icons (deduped within a color) drawn in their color with the icon's nerd-font name beneath. A "preview:" dropdown above the grid picks the glyph size in points, with Left/Right arrows to step it. Single-pane apps show it disabled, naming the preview. This replaces the v1 legend in the pane, whose data is still captured for round-trip. build-nerd-icons-legend.el is now a library. A cj/nerd-icons-write-legend entry point requires nerd-icons only at write time, so the capture logic loads and unit-tests without it. It dedupes icons by name within a face, computes each face's native hue, and orders the groups by hue. Writing the test surfaced a latent bug: face-hsl used (cadr (assoc t spec)), which grabs the first keyword instead of the plist. It only worked because the real faces fall through to the face-foreground branch. I fixed it to a correct t-clause parse. Coverage: 7 ERT capture tests (dedupe, hue order, lightness tiebreak, name sort, skip rules), 4 Python validator edges, and browser gates for the grid and the size dropdown. Locate stays color-level: clicking a color flashes its icons, and clicking an icon flashes its color row. Icons aren't individually editable, so there's nothing per-icon to select.
* docs(theme-studio): reconcile stale spec prose with resolved decisionsCraig Jennings2026-06-231-9/+23
| | | | Round-3 Codex review flagged one blocker: summary/readiness/risk text still described the superseded contracts (native color capture, build-inventory.el, dual dir-row sources). Reconciled the Scope tiers, For-the-implementer summary, legend source paragraph, three readiness dimensions, and the Risks section to match the resolved decisions. No decision changed, only the lagging prose. Findings 10/10, decisions 6/6, Ready pending go.
* docs(theme-studio): incorporate round-2 spec-review into nerd-icons specCraig Jennings2026-06-231-12/+75
| | | | Folded the six round-2 Codex blockers into the spec. Added the explicit 13-row v1 legend table and the missing-key rule. Settled dir-color precedence (the dir advice prepends nerd-icons-yellow, so it wins) and cross-package ownership (the bespoke pane owns only nerd-icons faces; nerd-icons-completion-dir-face stays in its own app). Named the concrete legend artifact and its failure behavior, reordered into an atomic assign-then-drop-tint phase, and added a contract-by-contract test plan. Findings 9/9, decisions 6/6. Ready pending go.
* docs(theme-studio): render real nerd-icons glyphs in the legend (v1)Craig Jennings2026-06-231-9/+14
| | | | Flipped the legend-rendering decision: v1 draws the actual nerd-font glyph in its assigned color rather than a swatch + label. The deferral rested on an unverified font dependency; Nerd Fonts are installed system-wide, so Chrome renders the glyphs from a font-family rule with no @font-face or font file. Monospace fallback for absent fonts; the gate asserts the glyph char and inline color.
* docs(theme-studio): incorporate spec-review into nerd-icons colors specCraig Jennings2026-06-231-22/+58
| | | | Folded the three blocking Codex findings into the spec. Added the legend data contract (row schema, per-category sources, v1 scope). Corrected the native-color seed to ride the existing default-face pipeline rather than a new build-inventory.el capture that would double-seed. Resolved all six decisions. Spec is Ready pending Craig's go.
* docs(theme-studio): spec theme-driven nerd-icons colors + filetype legendCraig Jennings2026-06-231-0/+157
| | | | Drafts the spec to drop the runtime nerd-icons tint (so icon color is theme-driven) and add a theme-studio filetype-legend representation over the 34 nerd-icons-* color faces. Five decisions left open for review: color model, legend scope, seed source, config sequencing, and the dir advice. Filed the cross-linked task in todo.org.
* chore(ai): archive gptel and remove it from the live configCraig Jennings2026-06-234-3110/+0
| | | | | | | | | | I archived gptel to archive/gptel/ since I rarely use it. Moved there: the six gptel modules (ai-config, ai-conversations, ai-conversations-browser, ai-mcp, ai-quick-ask, ai-rewrite), the gptel-tools/ directory, custom/gptel-prompts.el, their test files and utilities, and the four gptel-only specs. Scrubbed from the live config: the ai-config require in init.el, which also drops the whole C-; a keymap; the gptel-mode emojify hook in font-config.el; the gptel-tools entries in the Makefile clean target and the coverage runner; and the gptel feature notes in README. Cancelled the open gptel tasks in todo.org (the AI Open Work issues, the feature-extension brainstorm, the velox gptel-magit bug). ai-term stays. It is the ghostel Claude launcher, independent of gptel. Verified: every module loads, a batch init launch reaches completion clean, and the full test suite shows only pre-existing coverage failures unrelated to this change.
* docs(theme-studio): draft completion-preview specCraig Jennings2026-06-231-0/+211
| | | | A single inventory-composed "minibuffer completion" preview entry: a vanilla baseline always shown, a container radio plus modifier checkboxes selecting the completion stack, a two-family model (default/Vertico vs Ivy). Discoverability rides the preview-locate feature it depends on. Draft only, not yet ready to build: open implementation-readiness blockers remain.
* feat(theme-studio): locate preview elements by hover and clickCraig Jennings2026-06-231-34/+237
| | | | | | | | Hovering a data-face preview element shows its section, face, and effective value in the preview-label info line, and the element's title carries the full record: effective fg/bg plus a per-attribute source note (direct, inherited-from-X, default, or cleared-rendering-as-default). Clicking an on-pane element scrolls to and flashes its assignment row. Off-pane and cross-surface elements stay hover-only. A single owner-qualified registry keyed by {owner, face} backs both data-face surfaces, package and UI, so the same face name under two owners never collides. The pure helpers in app-core.js take all state as arguments and return data. The one stateful adapter, previewSpan, lives in previews.js and emits the escaped markup. os() stays a package-owner wrapper over previewSpan, and a unified locateClick dispatcher replaces the per-surface click branches. Covered by test-locate.mjs and four new browser gates. Full harness green.
* docs: add VAMP standalone music-player designCraig Jennings2026-06-221-0/+340
|
* docs: explain native-comp vs primitive-mocking, refine the insightCraig Jennings2026-06-211-0/+159
| | | | A reference for the native-comp + subr-mocking trap: the mechanism, the three failure modes, the research with URLs, and the decision (variadic mocks + a meta-test now, migrate off primitive-mocking long-term). Refines the CLAUDE.md codified insight, whose old 'don't mock subrs' framing was too broad, and points it at the new doc.
* fix: load games-config via the malyon hook, not an autoload chainCraig Jennings2026-06-211-1/+1
| | | | | | | | The previous deferral (8b2bc518) autoloaded malyon to games-config, but games-config doesn't define malyon. It leaves the command to the malyon package, so M-x malyon loaded games-config, found malyon still undefined, and errored "Autoloading games-config.el failed to define function malyon". Emacs won't chain through a second autoload. malyon and 2048-game autoload their own commands via package.el, so games-config should never own them. init.el now loads games-config via (with-eval-after-load 'malyon ...), and games-config just sets malyon-stories-directory when malyon loads. M-x malyon loads the package as a real command, then games-config applies its config. The earlier batch check loaded the files by hand and missed the autoload failure. The new test resolves the autoload the way M-x does (autoload-do-load), so the real path is covered now.
* refactor: defer games-config behind autoloads (load-graph Phase 4)Craig Jennings2026-06-211-1/+1
| | | | | | init.el eagerly required games-config at startup just to configure two on-demand game packages. package.el already autoloads malyon and 2048-game, so the eager require bought nothing but the one setting the module adds (malyon-stories-directory). init.el now autoloads malyon and 2048-game to games-config instead of requiring it. The first game command loads the module, which configures then loads the package. Startup no longer touches games-config, and both the commands and the stories-directory setting still work. This is the first module of the Phase 4 low-risk batch.
* docs(messenger): add the per-app keybinding alphabet to the unification specCraig Jennings2026-06-161-0/+138
| | | | | | I added a "Global Prefix Keybinding Alphabet" section to the messenger-unification spec. The per-app C-; prefix is a third keybinding surface, separate from the in-buffer chords (C-c C-c / C-c C-k / C-c C-a) and decision 6's cross-app verbs. Today the action leaf under each app is ad hoc: the same key means different things in Slack, Signal, Telega, and ERC. The section spells out the canonical actions, shows the inconsistency as a matrix, and proposes one leaf alphabet across all four, with the core seven verbs as the unifiable floor and the richer verbs as optional per-backend extensions. I also added a smoke-first parity note to Phase 1 (build the controllable signel replacement to the capability floor, not its ceiling) and promoted the todo task to [#A] "Unify Signel and All Messengers into one UX" with a direct link to the spec.
* docs: spec the theme-studio preview-locate feature; file org-agenda app taskCraig Jennings2026-06-151-0/+148
| | | | Spec the general preview interaction: hover any element for its section/face/value, click a current-pane element to flash and jump to its assignment row, off-pane elements hover-only via a derived face->owning-app registry that previews also read for cross-pane live rendering. Decisions 5/5 settled. File the locate feature and the dependent org-agenda app (break the agenda faces out of the org-mode pane into their own, with a representative week-agenda preview) as tasks; org-agenda depends on the locate feature.
* feat(face-diagnostic): Phase 4 render, command, and init wiringCraig Jennings2026-06-151-2/+2
| | | | Phase 4 completes the face/font diagnostic. cj/describe-face-at-point renders cj/--face-diagnosis-at into a read-only *Face Diagnosis* buffer (cj/face-diagnostic-mode), with a region-scan mode over distinct face-runs (capped at 20) and an out-of-scope banner. It is required in init.el. The render is split into small section formatters tested on captured plists, and the command is smoke-tested and live-verified in the daemon, where it already surfaces the active auto-dim remaps. The command name is settled as cj/describe-face-at-point. The keybinding stays Craig's pick, and face-name buttons plus the module-header allowlist entry are filed as a follow-up. The spec is marked implemented and renamed to its lifecycle filename. 35 ERT tests, byte-compile clean.
* feat(face-diagnostic): Phase 2 merged attributes and real fontCraig Jennings2026-06-151-4/+4
| | | | Extend the diagnostic core with the effective merged attributes and the real-font layer. cj/--face-diag-merged-attributes folds the ordered, remap-expanded spec stack (overlays over text-props over default), taking the first non-unspecified value per attribute, labeled "computed". cj/--face-diag-real-font reports font-at's font, or "unavailable" under batch and on terminals. cj/--face-diagnosis-at now returns groups 0-4. Settles spec decision #7 (the hand-fold approach), pinned by fixtures: overlay-over-text-prop, a default remap, a face-symbol attribute. 23 ERT tests, byte-compile clean.
* refactor(themes): retire dupre, fall back to modus-vivendiCraig Jennings2026-06-151-1/+1
| | | | WIP, the theme-studio export, is the active theme. dupre was only the fallback and a structural reference. Move the fallback to the built-in modus-vivendi, guaranteed present everywhere this config loads. Delete the three dupre files plus its test and palette assets, and fix the stale comments that pointed at dupre-faces.el for the auto-dim and org-keyword faces (those moved to org-faces-config.el). Repoint the dupre-clear-theme spec's palette reference to git history.
* docs: move the two docs-root specs into docs/specs/Craig Jennings2026-06-152-8/+16
| | | | Finish the reorg: theme-studio-palette-generator (doing — core planner, UI, and generatortest gate shipped, one refinement open) and theme-studio-semantic-theme-architecture (not-started) lived in docs/ root. Moved both into docs/specs/ with status filenames, ID and STATUS drawers, and id-linked references. Fixed their Related links from ../todo.org to ../../todo.org for the deeper path.
* docs: move specs to docs/specs/ with lifecycle-status filenamesCraig Jennings2026-06-1534-28/+289
| | | | | | Separate the 27 formal specs from working notes. Specs move to docs/specs/, notes stay in docs/design/. Each spec carries its lifecycle in the filename (-spec, -spec-doing, -spec-implemented, -spec-superseded) plus an authoritative ID and STATUS property drawer. The status came from checking each spec against the code, not the doc's own field: 6 implemented, 8 in progress, 12 not started, 1 superseded. Inbound links become org-id links so future status renames don't break them; code-comment paths repoint to docs/specs/. Working notes, inventories, reviews, and brainstorms stay in docs/design/.
* docs: file roam-inbox tasks, face/font diagnostic spec, close org-facesCraig Jennings2026-06-151-0/+193
| | | | File the roam-inbox backlog (face/font diagnostic popup, gold-text-in-dimmed-buffers, and the theme-studio bugs: elfeed all-white, dashboard preview icons, converter :inherit gap, cursor row controls, sample renames). Add the face/font diagnostic spec the lead task references. Close the org-faces feature as DONE and file its residual visual round-trip as a VERIFY under Manual testing and validation.
* feat(org): themeable agenda header-row faces via org-faces-configCraig Jennings2026-06-151-0/+150
| | | | | | Each TODO keyword and priority cookie gets its own named face instead of sharing org's built-in org-todo / org-done / org-priority. org-faces-config.el defines org-faces-<keyword> and org-faces-priority-a..d (plus -dim variants for auto-dim), each with a real default color, and wires them through org-todo-keyword-faces and org-priority-faces once org loads. The file is org-faces-config, not org-faces, because org ships its own org-faces feature that the bare name would shadow. This re-introduces the per-keyword/priority coloring that was stripped earlier, now as a named, theme-agnostic layer a theme can override. The design and the four resolved decisions are in docs/design/org-faces-spec.org; a theme-studio "org-faces" app and the auto-dim repoint follow in later phases.
* feat(theme-studio): palette generator and preview fidelityCraig Jennings2026-06-142-146/+461
| | | | | | | | | | Two strands land together because the generated theme-studio.html bundles every source file into one page and can't be split cleanly. The palette generator is a preview-first panel: palette-generator-core.js plans the palette and palette-generator-ui.js draws it. Generated colors stay inspectable and tunable through the existing selector, and committing one creates a normal base column. It adds source-mode and scheme controls, a configurable accent count, and color names from color-names.json. For preview fidelity, syntax and UI colors now resolve through the real Emacs inherit chains, so the preview matches how Emacs renders the theme. resolveSyntaxFg pins dec to ty (Emacs has no decorator face) and otherwise follows comment-delimiter to comment, doc to string, property to variable, function-call to function-name. resolveUiAttr walks mode-line-inactive to mode-line and line-number-current-line to line-number. The decorator label now reads "decorator to type" to match the type face Emacs uses for it. Design recorded in the two theme-studio specs under docs/.