Skip to content
Skill Authoring
Skill

/svg-portrait-mode

Portrait Mode for SVGs — foveated vectorization with 4-zone selective detail. Combines vision annotations, MediaPipe segmentation/landmarks, and optional saliency. Like phone portrait mode, but vectorized. Use when vectorizing a portrait or photo where subject detail should

BOOST
From plugin
claude-skills
15498 skills1 agent
Install
$ npx -y skills add oaustegard/claude-skills --skill svg-portrait-mode --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/svg-portrait-mode

Context preview

The summary Claude sees to decide when to auto-load this skill.

Portrait Mode for SVGs — foveated vectorization with 4-zone selective detail. Combines vision annotations, MediaPipe segmentation/landmarks, and optional saliency. Like phone portrait mode, but vectorized. Use when vectorizing a portrait or photo where subject detail should

SKILL.md

svg-portrait-mode.SKILL.md
name: svg-portrait-mode
description: 'Portrait Mode for SVGs — foveated vectorization with 4-zone selective detail. Combines vision annotations, MediaPipe segmentation/landmarks, and optional saliency. Like phone portrait mode, but vectorized. Use when vectorizing a portrait or photo where subject detail should outrank background detail.'
metadata:
  version: 0.7.0

SVG Portrait Mode

Selective simplification: one pipeline pass at high K → zone-aware contour simplification → optional per-zone style transforms. Like phone portrait mode, but vectorized — not blur, but stylistic separation of foreground and background.

Quick Start

Agent-annotated (recommended)

The agent looks at the image first, identifies important regions with rough bounding boxes, then calls:

from portrait_mode import portrait_mode

svg, stats = portrait_mode("photo.jpg",
    focus_targets=[
        {'bbox': (215, 125, 295, 195), 'label': 'face'},
    ],
    focus_edges=[
        {'bbox': (214, 170, 310, 290), 'label': 'beard'},
        {'bbox': (210, 415, 300, 505), 'label': 'hands'},
        {'bbox': (195, 95, 330, 140), 'label': 'hat'},
    ])

With style transforms

svg, stats = portrait_mode("photo.jpg",
    focus_targets=[{'bbox': (215, 125, 295, 195), 'label': 'face'}],
    focus_edges=[{'bbox': (214, 170, 310, 290), 'label': 'beard'}],
    style_transforms={
        'background': 'desaturate:0.7',
        'periphery': 'desaturate:0.3',
    })

Backward-compatible (MP-only)

Without annotations, falls back to MediaPipe face detection:

svg, stats = portrait_mode("photo.jpg")

How It Works

image-to-svg pipeline (K=96, unified palette)
    → zone detection (agent bboxes + optional MediaPipe landmarks)
    → assign contours to zones (by centroid)
    → per-zone simplification (epsilon, min_area)
    → optional per-zone style transforms
    → single SVG output (zone-labeled <g> groups, no clipPaths)

**Subtractive, not additive.** One pipeline pass produces full detail everywhere. Zones that don't need detail get simplified by coarsening contour approximation and raising minimum area thresholds. Subject stays sharp; background gets abstract.

Why This Works

v0.5.0 ran four independent pipelines (one per zone) with different K-means palettes, then composited via clipPaths. This produced tonal discontinuities at zone boundaries and was 4-7x slower. v0.6.0 uses a single palette so colors harmonize naturally, and simplification is a cheap post-process on contours the pipeline already extracted.

Agent Workflow

1. **Look at the image** — identify what's compositionally important 2. **Provide rough bounding boxes** as `(x1, y1, x2, y2)` pixel coordinates

  • Precision is NOT required (±30px is fine)
  • Use `focus_targets` for where the eye goes first (face, eyes)
  • Use `focus_edges` for compositionally important areas (beard, hands, hat, props)

3. **Call `portrait_mode()`** — skill handles zone detection, extraction, and assembly 4. **Review output** — check stats for path distribution across zones

Four Zones

| Zone | Purpose | Epsilon | Min Area | Examples | |------|---------|---------|----------|----------| | **Target** | Where the eye goes first | 0.5× (tight) | 15 px² | Face, eyes, key subject | | **Edge** | Compositionally important | 1.0× (default) | 40 px² | Beard, hands, hat, props | | **Periphery** | Context, not focal | 2.5× (loose) | 100 px² | Torso, clothing, limbs | | **Background** | Atmosphere | 5.0× (very loose) | 200 px² | Sky, walls, landscape |

Epsilon multiplies the base simplification factor (0.002 × perimeter). Higher = fewer vertices = more abstract. Min area filters out small shapes entirely.

Zone Assignment

Each contour is assigned to the highest-priority zone covering >30% of its area. This prevents focal shapes that straddle a zone boundary from getting simplified. Small contours (<500 px²) use centroid lookup for speed.

Periphery Generation

When focus targets or edges are specified, periphery is automatically generated as a buffer zone around the foreground (dilated union of target + edge zones). This creates a smooth detail gradient from subject to background.

Per-Zone Style Transforms

With zone-tagged shapes sharing a unified palette, backgrounds can be independently styled without affecting subject colors:

style_transforms={
    'background': 'desaturate:0.7',   # 70% desaturated
    'periphery': 'mute:0.3',          # 30% toward mid-gray
}

Available transforms:

| Transform | Effect | |-----------|--------| | `desaturate:N` | Shift toward gray (0=none, 1=grayscale) | | `grayscale` | Full grayscale | | `mute:N` | Shift toward mid-gray (0=none, 1=flat gray) | | `warm:N` | Warmer color temperature | | `cool:N` | Cooler color temperature | | `opacity:N` | Group opacity (0=invisible, 1=full) |

Parameters

portrait_mode(image_path,
    # Zone annotations
    focus_targets=None,   # [{'bbox': (x1,y1,x2,y2), 'label': str}, ...]
    focus_edges=None,     # [{'bbox': (x1,y1,x2,y2), 'label': str}, ...]

    # Pipeline settings
    K=96,                 # Color clusters (higher = more tonal detail)
    smooth=None,          # ImageMagick preprocessing ("oilpaint", "kuwahara:N")
    svg_width=800,

    # MediaPipe options
    use_landmarks=True,   # Try MP face landmarks for precise face geometry

    # Per-zone simplification overrides
    zone_simplification=None,  # {ZONE_TARGET: {'epsilon_mult': 0.3, 'min_area': 10}}

    # Per-zone style transforms
    style_transforms=None,  # {'background': 'desaturate:0.7'}
)

Performance

Single pipeline pass (~8-12s for a typical photo at K=96) vs v0.5.0's four independent passes (~40-60s). Zone detection and contour assignment add <1s. Style transforms are string operations with zero computational cost.

Requirements

Cross-skill dependencies:

  • `image-to-svg` pipeline (`/mnt/skills/user/image-to-svg/`)
Read more
Ships withclaude-skills

A collection of Claude skills distributed as a Claude Code plugin marketplace. Skills are primarily designed for the Claude.ai PaaS skill compute environment; mileage will vary if used as Claude Code Agent Skills.

Get the whole plugin

Other skills on claude-skills.