Skip to content

contribute

How to help build this

SP Night is a palette, a layer of names on top of it, and one repository per themed app. There are 6 of those today. Everything you need to build the next one is on this page or the spec.

Adding a port, step by step

  1. 1

    Start from the spec, not from a colour picker

    The colour decisions are already made. Open the spec and find what your app is asking for: a terminal wants the sixteen ansi roles, an editor wants the syntax group, a status bar mostly wants ui. Building a port is deciding which of your app's keys means which role — nothing more.

  2. 2

    Map keys to roles, never to colours

    This is the one rule that matters. Your app's "cursor colour" is ui.cursor, not sodio. A mapping that names a palette colour directly breaks the moment a flavour is added or a colour is retuned, and it silently disagrees with every other port.

  3. 3

    Write out one file per flavour

    Resolve each role against each flavour and write the app's config in its own format. Three flavours means three finished files. How you produce them is your business — by hand, by script, by whatever you like reading six months from now.

  4. 4

    Check anything the app composes itself

    The palette's own pairings are already measured. What is not measured is a combination your app invents — text placed on an accent, a badge, a tooltip over glass. If your port creates a pair like that, check it holds 4.5:1 before shipping it.

  5. 5

    Ship it as a repository

    A port is its own repo under the org: the finished theme files, a README with real install instructions, and a preview of the actual app. The bar is that someone can install it in one command without reading anything else — a screenshot is what convinces them to try.

What a mapping looks like

Here is the whole idea in four lines, taken from the Ghostty port. On the left, the decision you make once: which role each config key means. On the right, what that resolves to for the flavour selected in the header.

the mapping · decided once
background    ui.bg
foreground    ui.fg
cursor-color  ui.cursor
palette = 4   ansi.blue
resolved · one file per flavour
background    #151723
              
foreground    #d3d7eb
              
cursor-color  #f2984a
              
palette = 4   #6e92de
              
background    #1c1e20
              
foreground    #c7cdd6
              
cursor-color  #e3a068
              
palette = 4   #7993cb
              
background    #0c100d
              
foreground    #d3dad5
              
cursor-color  #f2984a
              
palette = 4   #6e92de
              

Those are the real values for the flavour selected in the header — switch it and the resolved side changes while the mapping does not. That is the whole point.

Reporting a colour problem

A contrast bug is the most valuable issue you can file, and the easiest to act on. Include the two colours, where they meet, and the ratio if you measured it — for example: “fg_muted on vidro in the eza header row, 3.02:1, unreadable on my monitor.”

Judgement calls are welcome too. The jaragua flavour was rebuilt because its surfaces read as dark green rather than black, and that started as somebody simply not enjoying looking at it.

Who has built it

2 people have committed to SP Night across 7 repositories — the palette, the engine, the ports and this site. Every name here is a person; nothing generated is credited.

Where the pieces live