# ScientiaLux Brand Asset API

Three equivalent ways to ask "what's the best logo for this context":

1. **Static SVG URLs** — fastest, zero logic. Hardcode the URL when context never changes.
2. **`/select.js` ES module** — WCAG-correct, runs in browser or Node. Use when context is dynamic and the consumer can run JS.
3. **`/api/select.php` HTTP endpoint** — same algorithm, but as a single GET. Use when the consumer can't run JS (curl, scripts, language-agnostic).

All three are public. The interactive gallery at `/gallery/` is password-protected.

## 1. Direct asset URLs

```
/logos/{family}/{color}.svg
/logos/{family}/png/{color}-{size}.png

  family  ∈ { horizontal, stacked }
  color   ∈ { navy, black, bright, white }
  size (horizontal) ∈ { 256, 512, 1024, 2048 }
  size (stacked)    ∈ { 128, 256, 512, 1024 }
```

Examples:
- `https://assets.scientialux.com/logos/horizontal/navy.svg` — the primary mark
- `https://assets.scientialux.com/logos/stacked/bright.svg` — accent on dark, square
- `https://assets.scientialux.com/logos/horizontal/png/navy-1024.png` — email-safe raster

Long-cache friendly. Hot-link freely.

## 2. `/select.js` — JavaScript module

Browser:
```html
<script type="module">
  import { loadManifest, selectLogo } from 'https://assets.scientialux.com/select.js';
  const m = await loadManifest();
  const r = selectLogo(m, { background: '#1a2f5a', width: 400 });
  document.querySelector('#logo').src = r.url;
</script>
```

Node 20+:
```js
import { loadManifest, selectLogo } from 'https://assets.scientialux.com/select.js';
// ...
```

### `selectLogo(manifest, opts)`

| Option | Type | Default | Notes |
|---|---|---|---|
| `background` | hex string | **required** | Dominant bg color the logo will sit on. |
| `accents` | hex[] | `[]` | Other prominent doc colors. Used for harmony scoring. |
| `width` | px | — | Used to derive family when `preferredFamily="auto"`. |
| `height` | px | — | (with `width`) for aspect-based family selection. |
| `preferredFamily` | `"horizontal"\|"stacked"\|"auto"` | `"auto"` | Force a family or let the algorithm decide. |
| `minContrast` | number | `4.5` | WCAG AA threshold. Below this → penalized 5 points. |
| `preferPng` | `true \| number \| null` | `null` | Return nearest PNG instead of SVG. `true` = use `width`. |

Returns:
```js
{
  id: "horizontal-bright",
  url: "https://assets.scientialux.com/logos/horizontal/bright.svg",
  family: "horizontal",
  color: "bright",
  fg: "#D8FF71",
  contrast: 9.84,             // WCAG contrast vs bg
  minContrast: 4.5,
  passesAA: true,
  reasoning: "contrast 9.8:1; brand-pop on navy bg",
  alternatives: [
    { id: "horizontal-white", url: "...", contrast: 12.4, score: 9.4 },
    ...
  ]
}
```

### Other exports

- `hexToRgb(hex)`, `relativeLuminance(hex)`, `contrastRatio(hexA, hexB)` — WCAG-correct math
- `colorDistance(hexA, hexB)` — CIEDE76 (good enough for "close color" checks)
- `loadManifest(url?)` — fetches and parses manifest.json

## 3. `/api/select.php` — HTTP endpoint

```
GET /api/select.php?bg=#1a2f5a&w=400[&family=auto][&accents=#d8ff71,#fff][&min=4.5][&png=1024]
```

| Param | Required | Notes |
|---|---|---|
| `bg` | yes | hex color, with or without `#` |
| `w`, `width` | — | px target width |
| `h`, `height` | — | px target height (pairs with `width`) |
| `family` | — | `horizontal\|stacked\|auto`. Default `auto`. |
| `accents` | — | comma-separated hex list, e.g. `accents=%23d8ff71,%23fff` |
| `min` | — | min contrast ratio (default 4.5) |
| `png` | — | `1` (use width to pick size) or a specific size (`512`) |

Returns identical JSON shape to `selectLogo()`. CORS-enabled, cache-friendly (`max-age=300`).

```bash
curl 'https://assets.scientialux.com/api/select.php?bg=%231a2f5a&w=400'
```

## 4. `logoctl` CLI

```bash
curl -O https://assets.scientialux.com/cli/logoctl.js
node logoctl.js select --bg "#1a2f5a" --width 400
```

See [`/cli/README.md`](../cli/README.md) for full reference.

## Brand palette

| Token | Hex | Use |
|---|---|---|
| `oxford` | `#102142` | Primary dark — "use in place of black" |
| `navy` | `#1A2F5A` | Surface |
| `navy-2` | `#223972` | Elevated surface |
| `dark-blue` | `#244A96` | Primary action |
| `sky` | `#509BE8` | Accent / link |
| `mindaro` | `#D8FF71` | Signature accent |
| `silvery` | `#F0F5F7` | Body text on dark |
| `logo-navy` | `#142952` | Navy logo foreground (sRGB-tuned, distinct from `navy` surface) |

Live JSON: `/manifest.json` includes the full palette + per-logo metadata.

## Selection algorithm at a glance

For each candidate logo `L`:

```
score = WCAG_contrast(L.fg, bg)
     + 1.0 if L.color == "navy" and bg is light
     + 1.5 if L.color == "bright" and bg ≈ brand-navy (CIEDE76 < 25)
     + 0.5 per accent that harmonizes with L.fg (CIEDE76 < 15)
     − 5.0 if contrast < minContrast
     − 2.0 if L.fg clashes with bg (CIEDE76 < 15)
```

Tie-breaker: contrast value. The algorithm is deterministic — same inputs always yield the same winner across all three callsites.
