Color

Choose the colors your product starts from. Looma derives the related roles that buttons, fields, text, surfaces, and statuses need in light and dark.

From a brand seed to usable colors

Action seed + canvas + surface + text
                ↓
Palette relationships and readability checks
                ↓
Light and dark semantic roles
                ↓
Action fills, labels, links, focus, selection, and statuses

action is a starting pigment. The generator chooses readable on-fill text separately and resolves contextual text and interaction states against their surfaces. A seed may be adjusted when needed for readability.

Foreground contrast while customizing

Customize uses apca-w3 to choose black or white labels on solid fills. The same generator supplies the live preview, saved themes, and exported CSS. It compares APCA contrast with text supplied before its background. Positive Lc means dark text on a lighter background; negative Lc means light text on a darker background. Label selection compares their magnitudes.

Your chosen fill stays intact. For example, gold #ffb84d keeps its black label, while warning orange #b27522 uses white. APCA foreground selection runs after the palette and its material states are resolved, so text-contrast decisions do not recolor backgrounds.

Icon Button uses separate --ui-non-text-on-<tone> foreground roles so non-text icons retain a 3:1 minimum across filled interaction states. Their initial defaults keep each component's on-fill fallback live in authored themes; --ui-icon-button-solid-text remains the explicit component override.

Reading-text derivation and non-text boundaries retain their existing contrast rules. APCA and WCAG 2 can prefer different labels; choosing a foreground does not establish accessibility conformance. Review the chosen typeface and size in the finished interface against the font-size and weight guidance.

Existing saved recipes remain editable. Regenerate their CSS to apply the label choices. Read Why APCA, ask questions in the APCA discussion forum, or review the contrast calculation license.

Start with four seeds

Recipe keyPublic CSS roleWhat you see
action--ui-accentThe primary action family, with readable labels and states derived separately.
canvas--ui-surfaceThe page's ground behind its content surfaces.
surface--ui-surface-raisedCards, fields, and floating content surfaces.
text--ui-textThe starting text color; usable primary and supporting text roles are derived against surfaces.
{
  "schemaVersion": 1,
  "values": {
    "action": "#315c48",
    "canvas": "#faf8f1",
    "surface": "#ffffff",
    "text": "#29382e"
  }
}

These are the seed choices used in Fellowship UI. The generated colors can differ from the seeds to keep the finished roles readable.

Refine relationships

These keys guide palette generation. They live in the recipe; there is no CSS property with the same purpose to turn later.

Recipe keysDecision
warmth, color-intensity, palette-relationshipCool or warm paper and ink, quiet or vivid color, and how quiet surfaces relate to the brand.
secondary-action, tertiary-actionOptional supporting brand families. Components expose them as tone="accent-secondary" and tone="accent-tertiary"; omitted accents follow primary.
neutral-source, neutral-strength, neutral-border-contrastWhere neutral pigment comes from, how strongly it fills controls, and the minimum boundary contrast shared by neutral actions and fields.
status-chroma, success-source, danger-source, warning-source, info-sourceStatus saturation and whether each status keeps a semantic hue, harmonizes toward primary, or uses a brand family.
selection-accent, focus-accent, link-accentWhich brand family speaks through selected rows, keyboard focus, and inline links.

Warmth and color intensity use 0.5 as their original-seed midpoint. Palette relationship preserves seed hues, relates quiet surfaces to neighboring hues, or uses complementary hues. Neutral fill strength and boundary contrast remain separate decisions. Status relationships change the palette, while words and icons continue to carry status meaning.

Use semantic roles in components

Choose the role for the job: --ui-text-primary for readable content, --ui-text-secondary for supporting text, and --ui-control-border for the shared neutral control boundary. A semantic role carries the theme's light/dark result and the intended relationship to nearby surfaces.

Every exported theme contains both modes. Set data-theme="dark" on a region to give that subtree a dark palette, including inside a light page. A floating surface needs to retain the mode of the region it came from.

Back to Theme decisions · Next: typography