Colors

Reef includes a comprehensive color generation system that transforms source color definitions into consistent, themeable color palettes. The system uses the OKLCH color space to generate tints and shades while maintaining perceptual uniformity.

Overview

The color system consists of three parts:

colors/ - Source JSON files defining color families and their base values

scripts/generate-colors.ts - Effect-based script that generates color palettes

reef/src/colors.gen/ - Auto-generated TypeScript and StyleX files (do not edit)

Run bun run generate-colors to regenerate color files after modifying the source JSON.

Color Families

Colors are organized into families and groups. Each family represents a cohesive color collection, while groups contain individual named colors within that family.

FamilyGroupsDescription
Chinese ColorsBlue, Red, Green, Purple, Pink, Orange, Yellow, Cyan, Brown, Black, White

Traditional Chinese color palettes with poetic names like Moonlight, Jade City, and Dragon's Blood

MiscHagoromo

Miscellaneous color palettes including Hagoromo

Example Colors

Moonlight

(月白)

Sapphire

(宝石蓝)

Crane Crest

(鹤顶红)

Rouge

(胭脂)

Source File Format

Source color files are JSON with the following structure:

{
  "family": "Chinese Colors",
  "group": "Blue",
  "colors": {
    "Moonlight (月白)": "#D4E5EF",
    "Sapphire (宝石蓝)": "#2486B9",
    "Cloisonne (景泰蓝)": "#2775B6",
    "Ocean Depths (海青)": "#080F40"
  }
}

Color names can include Chinese characters or other annotations in parentheses. The generator strips these for the exported variable names while preserving them in the source for documentation.

Depth Levels

Each source color generates 13 depth levels using the OKLCH color space. Tints increase lightness toward white, while shades decrease lightness toward black. Chroma is automatically adjusted at extremes to maintain visual quality.

LevelDescription
0

Near-white with minimal chroma (l: 0.97, c: 15% of original)

50

Very light tint (95% tint)

100

Light tint (85% tint)

200

Medium-light tint (65% tint)

300

Subtle tint (45% tint)

400

Slight tint (25% tint)

500

Base color (original)

600

Slight shade (15% shade)

700

Medium shade (30% shade)

800

Dark shade (45% shade)

900

Very dark shade (60% shade)

950

Near-black shade (70% shade)

1000

Near-black with reduced chroma (l: 0.08, c: 40% of original)

Tint and Shade Algorithm

The generator uses OKLCH (Oklab Lightness Chroma Hue) for perceptually uniform color transformations:

// Tint: blend toward white
function tint(color: Oklch, intensity: number): Oklch {
  const newL = color.l + (1 - color.l) * intensity;
  return {
    ...color,
    l: newL,
    c: newL > 0.9 ? color.c * 0.5 : color.c, // Reduce chroma near white
  };
}

// Shade: blend toward black
function shade(color: Oklch, intensity: number): Oklch {
  const newL = color.l - color.l * intensity;
  return {
    ...color,
    l: newL,
    c: newL < 0.3 ? color.c * 0.8 : color.c, // Reduce chroma near black
  };
}

Generated Output

The generator creates two types of files for each color group:

Directory Structure

reef/src/colors.gen/
├── raw/
│   ├── chinese-colors/
│   │   ├── blue.ts
│   │   ├── red.ts
│   │   └── ...
│   └── misc/
│       └── hagoromo.ts
└── stylex/
    ├── chinese-colors/
    │   ├── blue.stylex.ts
    │   ├── red.stylex.ts
    │   └── ...
    └── misc/
        └── hagoromo.stylex.ts

Raw TypeScript Export

Raw files export OKLCH color objects for programmatic use:

// reef/src/colors.gen/raw/chinese-colors/blue.ts
export const Moonlight = {
  "0": { l: 0.97, c: 0.003, h: 220 },
  "50": { l: 0.96, c: 0.02, h: 220 },
  "100": { l: 0.92, c: 0.02, h: 220 },
  // ... levels 200-900 ...
  "950": { l: 0.28, c: 0.016, h: 220 },
  "1000": { l: 0.08, c: 0.008, h: 220 },
};

export const Sapphire = {
  "0": { l: 0.97, c: 0.008, h: 230 },
  // ...
};

StyleX Export

StyleX files export CSS-ready color constants using stylex.defineConsts:

// reef/src/colors.gen/stylex/chinese-colors/blue.stylex.ts
import * as stylex from "@stylexjs/stylex";

export const Moonlight = stylex.defineConsts({
  "0": "oklch(97% 0.003 220)",
  "50": "oklch(96% 0.02 220)",
  "100": "oklch(92% 0.02 220)",
  // ... levels 200-900 ...
  "950": "oklch(28% 0.016 220)",
  "1000": "oklch(8% 0.008 220)",
});

export const Sapphire = stylex.defineConsts({
  "0": "oklch(97% 0.008 230)",
  // ...
});

Usage

Using StyleX Colors

Import generated StyleX colors for use in component styles:

import * as stylex from "@stylexjs/stylex";
import { Moonlight, Sapphire } from "@228-co/reef/colors.gen/stylex/chinese-colors/blue.stylex";

const styles = stylex.create({
  card: {
    backgroundColor: Moonlight[100],
    borderColor: Moonlight[300],
  },
  highlight: {
    color: Sapphire[600],
    backgroundColor: Sapphire[50],
  },
});

Using Raw Colors

Import raw OKLCH values for programmatic color manipulation:

import { Moonlight } from "@228-co/reef/colors.gen/raw/chinese-colors/blue";
import { formatCss } from "culori";

// Access raw OKLCH values
const baseColor = Moonlight["500"];
console.log(baseColor); // { l: 0.85, c: 0.02, h: 220 }

// Convert to CSS string
const cssColor = formatCss(baseColor);
console.log(cssColor); // "oklch(85% 0.02 220)"

In Theme Definitions

Colors are used in the theme system to define semantic color tokens:

// reef/src/themes/theme.stylex.ts
import { Red, Blue, Green } from "../colors.gen/stylex/misc/hagoromo.stylex";
import { Lampblack, FishBelly } from "../colors.gen/stylex/chinese-colors/black.stylex";

export const themeColors = stylex.defineVars({
  danger100: Red[100],
  danger500: Red[500],
  danger900: Red[900],

  info100: Blue[100],
  info500: Blue[500],

  primary500: { default: Lampblack[500], [DARK]: White[500] },
  background100: { default: FishBelly[100], [DARK]: CeremonialBlack[100] },
});

Best Practices

Never edit colors.gen files - They are auto-generated and will be overwritten

Use StyleX exports for styling - They integrate seamlessly with the build system

Prefer theme tokens over direct colors - Use themeColors for consistent semantics

Match depth to visual hierarchy - Lower numbers (100-400) for backgrounds, higher (600-900) for text

Test colors in both light and dark modes - Ensure sufficient contrast in all contexts

Use meaningful color names - Source colors should have descriptive, memorable names

Technical Details

Dependencies

culori - Color conversion and OKLCH manipulation

effect - Functional programming patterns and error handling

@effect/platform - File system operations

Why OKLCH?

OKLCH provides perceptually uniform color manipulation, meaning equal changes in lightness values produce visually equal changes in perceived brightness. This is superior to HSL for generating consistent tints and shades across different hues.