---
name: add-icons
description: >
  Add new SVG icons to @loke/icons. Covers SVG file placement (PascalCase
  filename in src/meta/), running bun run gen to generate components, JSON
  metadata (tags, categories, aliases with deprecation support), schema
  validation (icon.schema.json with 39 category enum, dependentRequired
  deprecation fields, aliasDeprecationReasons enum). SVGs should follow
  lucide-react constraints (24x24 viewBox, stroke-based). Activate when
  contributing a new icon or managing icon metadata and aliases.
type: core
library: '@loke/icons'
library_version: '1.0.0-alpha.1'
sources:
  - 'LOKE/merchant-frontends:packages/icons/gen.ts'
  - 'LOKE/merchant-frontends:packages/icons/src/schemas/icon.schema.json'
  - 'LOKE/merchant-frontends:packages/icons/src/schemas/category.schema.json'
  - 'LOKE/merchant-frontends:packages/icons/CLAUDE.md'
---

# @loke/icons — Adding Icons

## Setup

To add a new icon:

```bash
# 1. Place SVG file with PascalCase name in src/meta/
#    Example: src/meta/BellRing.svg

# 2. Run the generator
bun run gen

# 3. The generator creates:
#    - src/icons/bell-ring.ts        (component)
#    - src/meta/bell-ring.json       (metadata template, if not existing)
#    - Updates src/loke-icons.ts     (exports)
#    - Updates src/aliases.ts        (alias exports)
#    - Updates src/index.ts          (main entry)

# 4. Edit the metadata file to add tags, categories, and aliases
#    src/meta/bell-ring.json

# 5. Format
bun run format
```

## Core Patterns

### SVG file requirements

SVGs should follow the same constraints as existing icons (sourced from lucide-react):

- 24x24 viewBox (`viewBox="0 0 24 24"`)
- Stroke-based (not filled)
- Use supported SVG elements only: `circle`, `ellipse`, `g`, `line`, `path`, `polygon`, `polyline`, `rect`
- PascalCase filename (e.g., `BellRing.svg`, not `bell-ring.svg`)

### Metadata JSON structure

After running `bun run gen`, edit the generated JSON metadata file:

```json
{
  "$schema": "../schemas/icon.schema.json",
  "categories": ["notifications", "communication"],
  "tags": ["bell", "ring", "alert", "notification", "sound"],
  "aliases": [
    {
      "name": "NotificationBell"
    }
  ]
}
```

Required fields: `$schema`, `categories`, `tags` (minimum 1 tag).

### Adding aliases with deprecation

```json
{
  "$schema": "../schemas/icon.schema.json",
  "categories": ["navigation"],
  "tags": ["search", "find", "lookup"],
  "aliases": [
    {
      "name": "SearchIcon"
    },
    {
      "name": "Find",
      "deprecated": true,
      "deprecationReason": "alias.name",
      "toBeRemovedInVersion": "v2.0.0"
    }
  ]
}
```

Deprecation requires all three fields together: `deprecated`, `deprecationReason`, `toBeRemovedInVersion`.

Valid `deprecationReason` values for aliases: `"alias.typo"`, `"alias.name"`, `"alias.duplicate"`.

### Deprecating an entire icon

```json
{
  "$schema": "../schemas/icon.schema.json",
  "categories": ["brands"],
  "tags": ["logo"],
  "deprecated": true,
  "deprecationReason": "icon.brand",
  "toBeRemovedInVersion": "v2.0.0"
}
```

Valid `deprecationReason` for icons: `"icon.brand"`.

## Common Mistakes

### CRITICAL Using kebab-case for SVG filename

Wrong:

```
src/meta/alert-circle.svg
```

Correct:

```
src/meta/AlertCircle.svg
```

The generator reads PascalCase filenames and converts to kebab-case internally. A kebab-case filename like `alert-circle.svg` produces an incorrect component name.

Source: gen.ts:239

### HIGH Forgetting to run bun run gen after adding SVG

Wrong:

```bash
# Add SVG, then manually create src/icons/bell-ring.ts
```

Correct:

```bash
# Add SVG, then run the generator
bun run gen
```

Icon components are generated, not hand-written. The generator creates the component, updates index files, and generates alias exports.

Source: CLAUDE.md

### HIGH Using an invalid category

Wrong:

```json
{
  "$schema": "../schemas/icon.schema.json",
  "categories": ["ui", "general"],
  "tags": ["example"]
}
```

Correct:

```json
{
  "$schema": "../schemas/icon.schema.json",
  "categories": ["navigation", "arrows"],
  "tags": ["example"]
}
```

Categories are validated against a fixed enum of 39 values. See [references/categories.md](references/categories.md) for the complete list.

Source: src/schemas/icon.schema.json

### HIGH Incomplete deprecation fields

Wrong:

```json
{
  "aliases": [{ "name": "OldName", "deprecated": true }]
}
```

Correct:

```json
{
  "aliases": [{
    "name": "OldName",
    "deprecated": true,
    "deprecationReason": "alias.name",
    "toBeRemovedInVersion": "v2.0.0"
  }]
}
```

Schema uses `dependentRequired` — setting `deprecated` requires both `deprecationReason` and `toBeRemovedInVersion`.

Source: src/schemas/icon.schema.json

### MEDIUM Missing $schema field in metadata JSON

Wrong:

```json
{
  "categories": ["navigation"],
  "tags": ["arrow"]
}
```

Correct:

```json
{
  "$schema": "../schemas/icon.schema.json",
  "categories": ["navigation"],
  "tags": ["arrow"]
}
```

The `$schema` field is required by the JSON schema. The generator creates it automatically for new icons, but hand-created metadata files may omit it.

Source: src/schemas/icon.schema.json

### MEDIUM Using freeform text for deprecationReason

Wrong:

```json
{ "deprecationReason": "Use Search instead" }
```

Correct:

```json
{ "deprecationReason": "alias.name" }
```

Alias deprecation reasons are limited to `"alias.typo"`, `"alias.name"`, `"alias.duplicate"`. Icon deprecation reasons are limited to `"icon.brand"`.

Source: src/schemas/icon.schema.json

## References

- [Valid categories](references/categories.md)

See also: find-icons/SKILL.md — check existing icons before adding duplicates
