svg-portrait-mode
Portrait Mode" for SVGs — foveated vectorization with 4-zone selective detail. Combines Claude vision annotations, MediaPipe segmentation/landmarks, and optional saliency. Like phone portrait mode, but vectorized.
git clone --depth 1 https://github.com/oaustegard/claude-skills /tmp/svg-portrait-mode && cp -r /tmp/svg-portrait-mode/svg-portrait-mode ~/.claude/skills/svg-portrait-modeSKILL.md
# 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:
```python
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
```python
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:
```python
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:
```python
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
```python
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/`)
- `flowing` DAG runner (`/mnt/skills/user/flowing/`)
- `seeing-images` (`/mnt/skills/user/seeing-images/`) — for agent's visual inspection
Optional MediaPipe models (auto-downloaded on first use):
- `blaze_face_short_range.tflite` — face detection fallback
- `face_landmarker.task` — precise face oval (478 mesh points)
Note: MediaPipe selfie segmenter is NOT used in v0.6.GitHub repository access in containerized environments using REST API and credential detection. Use when git clone fails, or when accessing private repos/writing files via API.
Securely manages API credentials for multiple providers (Anthropic Claude, Google Gemini, GitHub). Use when skills need to access stored API keys for external service invocations.
Guidance for asking clarifying questions when user requests are ambiguous, have multiple valid approaches, or require critical decisions. Use when implementation choices exist that could significantly affect outcomes.
>-
>-
Browse Bluesky content via API and firehose - search posts, fetch user activity, sample trending topics, read feeds and lists, analyze and categorize accounts. Supports authenticated access for personalized feeds. Use for Bluesky research, user monitoring, trend analysis, feed reading, firehose sampling, account categorization.
Generate progressive disclosure indexes for GitHub repositories to use as Claude project knowledge. Use when setting up projects referencing external documentation, creating searchable indexes of technical blogs or knowledge bases, combining multiple repos into one index, or when user mentions "index", "github repo", "project knowledge", or "documentation reference".
Analyze and categorize Bluesky accounts by topic using keyword extraction. Use when users mention Bluesky account analysis, following/follower lists, topic discovery, account curation, or network analysis.