Agent skill

duotone-identity

Stars 7
Forks 0

Install this agent skill to your Project

npx add-skill https://github.com/ingpoc/SKILLS/tree/main/duotone-identity

SKILL.md

Duotone Identity Design System

Anthropic-inspired duotone design language for Identity Platform. Strict cream/charcoal palette with intentional typography and animated SVG illustrations.

Quick Reference

Element Value
Primary Light #FAF9F5 (cream)
Primary Dark #141413 (charcoal)
Display Font Instrument Serif
Body Font Inter
SVG viewBox 500 x 500
Chapter Number clamp(6rem, 15vw, 12rem) italic

Color Palette

Core Duotone Colors

css
:root {
  --cream: #FAF9F5;    /* Light backgrounds, dark text */
  --charcoal: #141413; /* Dark backgrounds, light text */
}

Usage Pattern

Section Background Text
Light (Hero, Ch1, Ch3) var(--cream) var(--charcoal)
Dark (Ch2, Ch4, Finale) var(--charcoal) var(--cream)

Rule: Never use other colors for primary UI. Accent colors only for interactive elements (wallet button, links).

Section Alternating

tsx
// Chapter 1, 3: Light
<section className="bg-[var(--cream)] text-[var(--charcoal)]">

// Chapter 2, 4: Dark
<section className="bg-[var(--charcoal)] text-[var(--cream)]">

Typography

Font Families

css
/* Display / Headings */
font-family: 'Instrument Serif', Georgia, serif;

/* Body / UI */
font-family: 'Inter', -apple-system, sans-serif;

Display Headings (H1, H2)

css
.landing-h1 {
  font-size: clamp(3rem, 12vw, 8rem);
  line-height: 1;
  letter-spacing: -0.02em;
}

.landing-h2 {
  font-size: clamp(2rem, 6vw, 4.5rem);
  line-height: 1.15;
  letter-spacing: -0.02em;
}

Chapter Labels

tsx
<p className="text-xs md:text-sm font-semibold uppercase tracking-[0.2em] opacity-50 flex items-center gap-4">
  <span className="w-10 h-px bg-current opacity-50"></span>
  {label}
</p>

Pattern: 40px horizontal dash + uppercase text + 0.2em letter-spacing

Chapter Numbers

tsx
<span className="font-serif italic opacity-[0.08]"
      style={{ fontSize: 'clamp(6rem, 15vw, 12rem)', lineHeight: 1 }}>
  {String(number).padStart(2, '0')}
</span>

Positioning: absolute top-4 left-4 md:top-8 md:left-8


Layout Patterns

Chapter Section Structure

tsx
<section className={`chapter ${isLight ? 'light' : 'dark'} min-h-screen flex items-center justify-center relative p-6 md:p-12 ${isLight ? 'bg-[var(--cream)] text-[var(--charcoal)]' : 'bg-[var(--charcoal)] text-[var(--cream)]'}`}>
  {/* Chapter Number - large, positioned */}
  <span className="chapter-number absolute top-4 left-4 md:top-8 md:left-8 font-serif italic opacity-[0.08]"
        style={{ fontSize: 'clamp(6rem, 15vw, 12rem)', lineHeight: 1 }}>
    {String(number).padStart(2, '0')}
  </span>

  <div className="chapter-inner grid grid-cols-1 md:grid-cols-2 gap-8 md:gap-12 max-w-6xl w-full relative z-10">
    {/* Content */}
    <div className="chapter-content">
      <p className="chapter-label text-xs md:text-sm font-semibold uppercase tracking-[0.2em] opacity-50 mb-4 flex items-center gap-4">
        <span className="w-10 h-px bg-current opacity-50"></span>
        {label}
      </p>
      <h2 className={`landing-h2 ${isLight ? 'text-[var(--charcoal)]' : 'text-[var(--cream)]'}`}>
        {title}
      </h2>
    </div>
    {/* Illustration */}
  </div>
</section>

Key Rules:

  • Even chapters (2, 4): reverse layout (illustration left, content right)
  • Odd chapters (1, 3): standard layout (content left, illustration right)
  • Always explicitly set h2 color based on isLight (global CSS overrides)

SVG Illustrations

Standard viewBox

Always use viewBox="0 0 500 500" for consistency.

All coordinates must stay within 0-500 range to prevent clipping.

Path Classes

Class Purpose Animation
.fill-path Shapes, filled elements Opacity 0→0.9, scale 0.8→1
.draw-path Lines, strokes strokeDashoffset animation
.label-path Text labels Opacity 0→0.7

CSS Initial States

css
.fill-path {
  opacity: 0;
  transform-origin: center;
  vector-effect: non-scaling-stroke;
}

.draw-path {
  opacity: 0;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.label-path {
  opacity: 0;
  font-size: 14px;
  font-weight: 500;
  text-anchor: middle;
  pointer-events: none;
}

Common SVG Patterns

Person/Figure (Chapter 1):

tsx
<circle className="fill-path" cx="250" cy="140" r="35" fill="#141413" opacity="0"/>
<path className="fill-path" d="M 215 180 Q 200 220 210 280..." fill="#141413" opacity="0"/>

Process Flow (Chapter 2):

tsx
{/* Horizontal left-to-right flow */}
<rect className="fill-path" x="60" y="200" width="80" height="60" fill="#FAF9F5" opacity="0"/>
<path className="draw-path" d="M 140 230 L 180 230" stroke="#FAF9F5" strokeWidth="2" opacity="0"/>

Growth Trajectory (Chapter 3):

tsx
<path className="draw-path" d="M 50 420 Q 120 400 160 350..." stroke="#141413" strokeWidth="3" opacity="0"/>
<circle className="fill-path" cx="160" cy="350" r="10" fill="#141413" opacity="0"/>

Central Hub (Chapter 4):

tsx
<circle className="fill-path" cx="250" cy="250" r="45" fill="#FAF9F5" opacity="0"/>
<circle className="draw-path" cx="250" cy="250" r="65" fill="none" stroke="#FAF9F5" strokeWidth="2" opacity="0"/>

GSAP Animations

Animation Pattern for Chapters

typescript
import { gsap } from 'gsap';
import ScrollTrigger from 'gsap/ScrollTrigger';

gsap.registerPlugin(ScrollTrigger);

export const useChapterAnimations = () => {
  useEffect(() => {
    const chapters = document.querySelectorAll('.chapter');
    if (chapters.length === 0) return;

    const ctx = gsap.context(() => {
      chapters.forEach((chapter) => {
        const fillPaths = chapter.querySelectorAll('.fill-path');
        const drawPaths = chapter.querySelectorAll('.draw-path');

        // Fill paths: opacity + scale
        if (fillPaths.length > 0) {
          gsap.to(fillPaths, {
            opacity: 0.9,
            scale: 1,
            duration: 0.8,
            stagger: 0.1,
            ease: 'back.out(1.5)',
            scrollTrigger: {
              trigger: chapter,
              start: 'top 80%',
              toggleActions: 'play none none reverse',
            },
          });
        }

        // Draw paths: stroke animation
        if (drawPaths.length > 0) {
          drawPaths.forEach(path => {
            const length = (path as SVGPathElement).getTotalLength() || 1000;
            (path as SVGPathElement).style.strokeDasharray = String(length);
            (path as SVGPathElement).style.strokeDashoffset = String(length);
          });

          gsap.to(drawPaths, {
            strokeDashoffset: 0,
            opacity: 0.6,
            duration: 1.5,
            stagger: 0.1,
            ease: 'power2.inOut',
            scrollTrigger: {
              trigger: chapter,
              start: 'top 75%',
              toggleActions: 'play none none reverse',
            },
          });
        }
      });
    });

    return () => ctx.revert();
  }, []);
};

Key GSAP Rules

  1. Always use gsap.context() for cleanup
  2. toggleActions: 'play none none reverse' for reversible scroll animations
  3. Never use inline style={{ transform: 'scale' }} - let GSAP handle all transforms
  4. Initialize strokeDasharray in the effect, not inline styles
  5. stagger: 0.1 for sequential element animations

Resources

references/

  • palette.md - Full color definitions with usage examples
  • typography.md - Font loading, sizing, and heading styles
  • svg-patterns.md - Common SVG illustration templates
  • gsap-recipes.md - Copy-paste animation patterns

scripts/

  • validate_colors.sh - Check if colors match duotone palette
  • generate_chapter.sh - Scaffold new chapter section

Usage Examples

Creating a new chapter:

1. Use scripts/generate_chapter.sh 5
2. Add SVG to illustration container (500x500 viewBox)
3. Use fill-path/draw-path/label-path classes
4. Set isLight based on position (odd=light, even=dark)

Validating colors:

Use scripts/validate_colors.sh before committing to ensure only cream/charcoal are used

Anti-Patterns

❌ Don't ✅ Do
Use other colors for UI Only cream/charcoal
Inline style={{ scale }} Let GSAP animate
Different viewBox sizes Always 500x500
Coordinates outside 0-500 Keep within bounds
Generic class names Use fill-path/draw-path/label-path

Expand your agent's capabilities with these related and highly-rated skills.

ingpoc/SKILLS

scroll-storyteller

Use when creating interactive scroll-based storytelling experiences with mouse-following spotlight effects, animated SVG art, and the Anthropic design language. Load for explainer pages, product showcases, visual narratives, or any content needing immersive scroll storytelling with organic shapes and smooth animations. Supports GSAP-powered or lightweight CSS-only animations.

7 0
Explore
ingpoc/SKILLS

enforcement

Use when implementing hooks that BLOCK invalid actions, creating quality gates for state transitions, or enforcing tested:true verification. Load when designing enforcement mechanisms. Uses exit code 2 to block, JSON permissionDecision:deny, or updatedInput modification. Rules are instructions; hooks are enforcement.

7 0
Explore
ingpoc/SKILLS

async-programming-skill

This skill provides async/await patterns and best practices for concurrent programming

7 0
Explore
ingpoc/SKILLS

postgresql-skill

This skill provides PostgreSQL-specific patterns for database design, optimization, and transaction management

7 0
Explore
ingpoc/SKILLS

token-efficient

Use when processing 50+ items, analyzing CSV/log files, executing code in sandbox, or searching for tools. Load for data processing tasks. Achieves 98%+ token savings via in-sandbox execution, progressive disclosure, and pagination. Supports heredocs for multi-line bash.

7 0
Explore
ingpoc/SKILLS

mcp-builder

Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).

7 0
Explore

Didn't find tool you were looking for?

Be as detailed as possible for better results