Agent Skillskinncj/Heimdall › design-tokens

design-tokens

GitHub

用于读取和写入 W3C DTCG 格式的设计令牌(tokens.json),并自动生成 CSS 自定义属性、Tailwind 配置及 Mantine 主题对象。该技能确保设计令牌作为唯一事实来源,所有框架输出均由此派生再生。

.cursor/skills/design-tokens/SKILL.md kinncj/Heimdall

触发场景

修改或生成设计令牌 更新品牌颜色、排版、间距等设计系统值 需要同步前端样式与后端/设计令牌

安装

npx skills add kinncj/Heimdall --skill design-tokens -g -y
更多选项

不安装直接使用

npx skills use kinncj/Heimdall@design-tokens

指定 Agent (Claude Code)

npx skills add kinncj/Heimdall --skill design-tokens -a claude-code -g -y

安装 repo 全部 skill

npx skills add kinncj/Heimdall --all -g -y

预览 repo 内 skill

npx skills add kinncj/Heimdall --list

SKILL.md

Frontmatter
{
    "name": "design-tokens",
    "description": "Read and write design tokens in W3C DTCG format (tokens.json) and emit CSS, Tailwind, and Mantine outputs. Use when modifying or generating design tokens."
}

SKILL: design-tokens

Purpose

Read and write design tokens in W3C Design Token Community Group (DTCG) format (tokens.json). Emit framework-specific outputs: CSS custom properties, Tailwind config, and Mantine theme object. The tokens.json in docs/design/identity/ is the canonical source of truth; all framework outputs are derived and regenerated — never manually edited.

Token File: docs/design/identity/tokens.json

W3C DTCG format. Each token is an object with $value and $type:

{
  "$schema": "https://design-tokens.org/schema/v1.0.0",
  "_meta": { "status": "draft", "version": "1.0.0" },

  "color": {
    "brand": {
      "primary":   { "$value": "#2563eb", "$type": "color" },
      "secondary": { "$value": "#7c3aed", "$type": "color" },
      "accent":    { "$value": "#0ea5e9", "$type": "color" }
    },
    "semantic": {
      "success": { "$value": "#16a34a", "$type": "color" },
      "warning": { "$value": "#d97706", "$type": "color" },
      "error":   { "$value": "#dc2626", "$type": "color" },
      "info":    { "$value": "#0284c7", "$type": "color" }
    },
    "neutral": {
      "50":  { "$value": "#f8fafc", "$type": "color" },
      "500": { "$value": "#64748b", "$type": "color" },
      "900": { "$value": "#0f172a", "$type": "color" }
    },
    "surface": {
      "background": { "$value": "#ffffff", "$type": "color" },
      "foreground": { "$value": "#0f172a", "$type": "color" },
      "muted":      { "$value": "#f1f5f9", "$type": "color" },
      "border":     { "$value": "#e2e8f0", "$type": "color" }
    }
  },

  "typography": {
    "fontFamily": {
      "sans": { "$value": "Inter, system-ui, sans-serif", "$type": "fontFamily" },
      "mono": { "$value": "JetBrains Mono, monospace",   "$type": "fontFamily" }
    },
    "fontSize": {
      "sm":   { "$value": "0.875rem", "$type": "dimension" },
      "base": { "$value": "1rem",     "$type": "dimension" },
      "lg":   { "$value": "1.125rem", "$type": "dimension" },
      "xl":   { "$value": "1.25rem",  "$type": "dimension" },
      "2xl":  { "$value": "1.5rem",   "$type": "dimension" },
      "4xl":  { "$value": "2.25rem",  "$type": "dimension" }
    }
  },

  "spacing": {
    "1": { "$value": "0.25rem", "$type": "dimension" },
    "2": { "$value": "0.5rem",  "$type": "dimension" },
    "4": { "$value": "1rem",    "$type": "dimension" },
    "8": { "$value": "2rem",    "$type": "dimension" }
  },

  "radius": {
    "sm":   { "$value": "0.125rem", "$type": "dimension" },
    "md":   { "$value": "0.375rem", "$type": "dimension" },
    "lg":   { "$value": "0.5rem",   "$type": "dimension" },
    "full": { "$value": "9999px",   "$type": "dimension" }
  },

  "shadow": {
    "sm": { "$value": "0 1px 2px 0 rgb(0 0 0 / 0.05)", "$type": "shadow" },
    "md": { "$value": "0 4px 6px -1px rgb(0 0 0 / 0.1)", "$type": "shadow" },
    "lg": { "$value": "0 10px 15px -3px rgb(0 0 0 / 0.1)", "$type": "shadow" }
  }
}

Emit: CSS Custom Properties

Output to docs/design/identity/tokens.css:

import json, re

def flatten(obj, prefix=""):
    result = {}
    for k, v in obj.items():
        if k.startswith("$") or k.startswith("_"):
            continue
        key = f"{prefix}-{k}" if prefix else k
        if isinstance(v, dict) and "$value" in v:
            result[key] = v["$value"]
        elif isinstance(v, dict):
            result.update(flatten(v, key))
    return result

tokens = json.load(open("docs/design/identity/tokens.json"))
flat = flatten(tokens)

lines = [":root {"]
for name, value in sorted(flat.items()):
    css_var = "--" + name.replace(".", "-")
    lines.append(f"  {css_var}: {value};")
lines.append("}")

with open("docs/design/identity/tokens.css", "w") as f:
    f.write("\n".join(lines) + "\n")

print(f"[design-tokens] CSS  docs/design/identity/tokens.css  vars={len(flat)}")

Emit: Tailwind Config

Output to docs/design/identity/tailwind.tokens.js:

import json

tokens = json.load(open("docs/design/identity/tokens.json"))

def extract_colors():
    result = {}
    for group, values in tokens.get("color", {}).items():
        result[group] = {}
        for name, token in values.items():
            if "$value" in token:
                result[group][name] = token["$value"]
    return result

colors = extract_colors()
font_family = {
    k: v["$value"]
    for k, v in tokens.get("typography", {}).get("fontFamily", {}).items()
}

config = f"""/** @type {{import('tailwindcss').Config}} */
// AUTO-GENERATED — edit docs/design/identity/tokens.json, not this file
module.exports = {{
  theme: {{
    extend: {{
      colors: {json.dumps(colors, indent(6))},
      fontFamily: {json.dumps(font_family, indent(6))},
    }},
  }},
}};
"""

with open("docs/design/identity/tailwind.tokens.js", "w") as f:
    f.write(config)

print("[design-tokens] TAILWIND  docs/design/identity/tailwind.tokens.js")

Emit: Mantine Theme

Output to docs/design/identity/mantine.theme.ts:

import json

tokens = json.load(open("docs/design/identity/tokens.json"))

primary = tokens["color"]["brand"]["primary"]["$value"]
secondary = tokens["color"]["brand"]["secondary"]["$value"]

theme = f"""// AUTO-GENERATED — edit docs/design/identity/tokens.json, not this file
import {{ createTheme }} from '@mantine/core';

export const theme = createTheme({{
  primaryColor: 'brand',
  colors: {{
    brand: [
      '{tokens["color"]["neutral"]["50"]["$value"]}',
      '{tokens["color"]["neutral"]["100"]["$value"] if "100" in tokens["color"]["neutral"] else "#f1f5f9"}',
      '{tokens["color"]["neutral"]["200"]["$value"] if "200" in tokens["color"]["neutral"] else "#e2e8f0"}',
      '{tokens["color"]["neutral"]["300"]["$value"] if "300" in tokens["color"]["neutral"] else "#cbd5e1"}',
      '{tokens["color"]["neutral"]["400"]["$value"] if "400" in tokens["color"]["neutral"] else "#94a3b8"}',
      '{tokens["color"]["neutral"]["500"]["$value"]}',
      '{primary}',
      '{tokens["color"]["neutral"]["700"]["$value"] if "700" in tokens["color"]["neutral"] else "#334155"}',
      '{tokens["color"]["neutral"]["800"]["$value"] if "800" in tokens["color"]["neutral"] else "#1e293b"}',
      '{tokens["color"]["neutral"]["900"]["$value"]}',
    ],
  }},
  fontFamily: '{tokens["typography"]["fontFamily"]["sans"]["$value"]}',
  fontFamilyMonospace: '{tokens["typography"]["fontFamily"]["mono"]["$value"]}',
}});
"""

with open("docs/design/identity/mantine.theme.ts", "w") as f:
    f.write(theme)

print("[design-tokens] MANTINE  docs/design/identity/mantine.theme.ts")

Emit: Terminal Theme (tui target)

When design.target is tui, emit docs/design/identity/terminal-theme.json from tokens.json instead of the CSS/Tailwind/Mantine outputs. Map each color role to an ANSI-256 index (and the hex) plus a lipgloss style name, and record the foreground/background pairs with their contrast ratios so the a11y auditor can flag any pair under WCAG 2.2 AA. Shape:

{
  "roles": {
    "primary":    { "fg": "#7aa2f7", "ansi256": 111, "lipgloss": "primary" },
    "muted":      { "fg": "#565f89", "ansi256": 60,  "lipgloss": "muted" },
    "accent":     { "fg": "#bb9af7", "ansi256": 141, "lipgloss": "accent" },
    "error":      { "fg": "#f7768e", "ansi256": 204, "lipgloss": "error" },
    "success":    { "fg": "#9ece6a", "ansi256": 149, "lipgloss": "success" },
    "background": { "bg": "#1a1b26", "ansi256": 234 },
    "foreground": { "fg": "#c0caf5", "ansi256": 189 }
  },
  "pairs": [
    { "role": "foreground", "on": "background", "contrast": 12.6 },
    { "role": "muted",      "on": "background", "contrast": 3.4 }
  ]
}

Run All Emitters

python3 - <<'EOF'
# Run all three emitters in sequence
# (inline the three scripts above, or import from scripts/emit-tokens.py)
EOF

Update Tokens (read-write)

To update a single token value:

import json, sys

tokens = json.load(open("docs/design/identity/tokens.json"))
# Set tokens["color"]["brand"]["primary"]["$value"] = "#1d4ed8"
# Write back, then re-run all emitters
json.dump(tokens, open("docs/design/identity/tokens.json", "w"), indent=2)

Always re-emit all framework outputs after any token change.

Failure Modes

Condition Action
tokens.json malformed Log parse error with line number. Do not emit partial output.
Missing required token key Log MISSING_TOKEN: {path}. Emit with placeholder TODO value.
Emitted file differs from committed Acceptable — these are always regenerated.
_meta.status != approved Log warning. Emit anyway (dev workflow). Gate is in visual-identity approval, not here.

Logging

[design-tokens] READ    docs/design/identity/tokens.json  tokens=47
[design-tokens] CSS     docs/design/identity/tokens.css   vars=47
[design-tokens] TAILWIND docs/design/identity/tailwind.tokens.js
[design-tokens] MANTINE  docs/design/identity/mantine.theme.ts
[design-tokens] MISSING_TOKEN  color.neutral.100  — using placeholder

版本历史

  • f4ea31f 当前 2026-07-05 10:41

同 Skill 集合

.claude/skills/a11y-audit/SKILL.md
.claude/skills/component-scaffold/SKILL.md
.claude/skills/cucumber-automation/SKILL.md
.claude/skills/design-tokens/SKILL.md
.claude/skills/docker-patterns/SKILL.md
.claude/skills/finops-review/SKILL.md
.claude/skills/gh-issues/SKILL.md
.claude/skills/gh-labels-milestones/SKILL.md
.claude/skills/gh-projects/SKILL.md
.claude/skills/gherkin-authoring/SKILL.md
.claude/skills/github-cli/SKILL.md
.claude/skills/humanizer/SKILL.md
.claude/skills/jupyter-patterns/SKILL.md
.claude/skills/karpathy-audit/SKILL.md
.claude/skills/kubernetes-patterns/SKILL.md
.claude/skills/mermaid-diagrams/SKILL.md
.claude/skills/mockup/SKILL.md
.claude/skills/pipeline-runner/SKILL.md
.claude/skills/playwright-cli/SKILL.md
.claude/skills/postgresql-patterns/SKILL.md
.claude/skills/redis-patterns/SKILL.md
.claude/skills/rfc-adr/SKILL.md
.claude/skills/rubber-duck/SKILL.md
.claude/skills/ship-safe/SKILL.md
.claude/skills/spec-kit/SKILL.md
.claude/skills/sre-review/SKILL.md
.claude/skills/story-issue-sync/SKILL.md
.claude/skills/stripe-patterns/SKILL.md
.claude/skills/supabase-patterns/SKILL.md
.claude/skills/tdd-workflow/SKILL.md
.claude/skills/terraform-patterns/SKILL.md
.claude/skills/threat-modeling/SKILL.md
.claude/skills/vercel-patterns/SKILL.md
.claude/skills/visual-identity/SKILL.md
.claude/skills/wireframe/SKILL.md
.cursor/skills/a11y-audit/SKILL.md
.cursor/skills/component-scaffold/SKILL.md
.cursor/skills/cucumber-automation/SKILL.md
.cursor/skills/docker-patterns/SKILL.md
.cursor/skills/finops-review/SKILL.md
.cursor/skills/gh-issues/SKILL.md
.cursor/skills/gh-labels-milestones/SKILL.md
.cursor/skills/gh-projects/SKILL.md
.cursor/skills/gherkin-authoring/SKILL.md
.cursor/skills/github-cli/SKILL.md
.cursor/skills/humanizer/SKILL.md
.cursor/skills/jupyter-patterns/SKILL.md
.cursor/skills/karpathy-audit/SKILL.md
.cursor/skills/kubernetes-patterns/SKILL.md
.cursor/skills/mermaid-diagrams/SKILL.md
.cursor/skills/mockup/SKILL.md
.cursor/skills/pipeline-runner/SKILL.md
.cursor/skills/playwright-cli/SKILL.md
.cursor/skills/postgresql-patterns/SKILL.md
.cursor/skills/redis-patterns/SKILL.md
.cursor/skills/rfc-adr/SKILL.md
.cursor/skills/rubber-duck/SKILL.md
.cursor/skills/ship-safe/SKILL.md
.cursor/skills/spec-kit/SKILL.md
.cursor/skills/sre-review/SKILL.md
.cursor/skills/story-issue-sync/SKILL.md
.cursor/skills/stripe-patterns/SKILL.md
.cursor/skills/supabase-patterns/SKILL.md
.cursor/skills/tdd-workflow/SKILL.md
.cursor/skills/terraform-patterns/SKILL.md
.cursor/skills/threat-modeling/SKILL.md
.cursor/skills/vercel-patterns/SKILL.md
.cursor/skills/visual-identity/SKILL.md
.cursor/skills/wireframe/SKILL.md
.opencode/skills/a11y-audit/SKILL.md
.opencode/skills/component-scaffold/SKILL.md
.opencode/skills/cucumber-automation/SKILL.md
.opencode/skills/design-tokens/SKILL.md
.opencode/skills/docker-patterns/SKILL.md
.opencode/skills/finops-review/SKILL.md
.opencode/skills/gh-issues/SKILL.md
.opencode/skills/gh-labels-milestones/SKILL.md
.opencode/skills/gh-projects/SKILL.md
.opencode/skills/gherkin-authoring/SKILL.md
.opencode/skills/github-cli/SKILL.md
.opencode/skills/humanizer/SKILL.md
.opencode/skills/jupyter-patterns/SKILL.md
.opencode/skills/karpathy-audit/SKILL.md
.opencode/skills/kubernetes-patterns/SKILL.md
.opencode/skills/mermaid-diagrams/SKILL.md
.opencode/skills/mockup/SKILL.md
.opencode/skills/pipeline-runner/SKILL.md
.opencode/skills/playwright-cli/SKILL.md
.opencode/skills/postgresql-patterns/SKILL.md
.opencode/skills/redis-patterns/SKILL.md
.opencode/skills/rfc-adr/SKILL.md
.opencode/skills/rubber-duck/SKILL.md
.opencode/skills/ship-safe/SKILL.md
.opencode/skills/spec-kit/SKILL.md
.opencode/skills/sre-review/SKILL.md
.opencode/skills/story-issue-sync/SKILL.md
.opencode/skills/stripe-patterns/SKILL.md
.opencode/skills/supabase-patterns/SKILL.md
.opencode/skills/tdd-workflow/SKILL.md
.opencode/skills/terraform-patterns/SKILL.md
.opencode/skills/threat-modeling/SKILL.md
.opencode/skills/vercel-patterns/SKILL.md
.opencode/skills/visual-identity/SKILL.md
.opencode/skills/wireframe/SKILL.md

元信息

文件数
0
版本
0e34c62
Hash
f4eebaf4
收录时间
2026-07-05 10:41

首页 - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-07-14 14:59
浙ICP备14020137号-1 $访客地图$