satori-constraints
Satori library constraints for JSX-to-SVG rendering and OG image generation. Use when working with report package, image generation, satori, resvg, CSS styling for images, or font loading.
What this skill does
# Satori Constraints Reference
Comprehensive reference for Satori's limitations and best practices when generating images from JSX.
## Overview
Satori is Vercel's library that converts HTML/CSS (or JSX) to SVG. It's used for generating OG images, social cards, and report images. This project uses Satori in the `@scout-for-lol/report` package with `@resvg/resvg-js` for SVG-to-PNG conversion.
---
## Layout Engine
### Flexbox-Based (Yoga)
Satori uses **Yoga** (the same layout engine as React Native), not browser CSS:
- **Only flexbox layout is supported** - no CSS Grid, no `float`, no `position: absolute` outside flex containers
- Every element with children must use `display: flex` explicitly
- Default flex direction is `row` (like React Native, unlike CSS default of `block`)
### Key Differences from Browser CSS
| Feature | Satori | Browser CSS |
| ---------------------- | ----------------------- | ------------------------------- |
| Default display | `flex` | `block` |
| Default flex-direction | `row` | `row` |
| `position: absolute` | Relative to flex parent | Relative to positioned ancestor |
| `z-index` | Not supported | Supported |
| 3D transforms | Not supported | Supported |
---
## Supported CSS Properties
### Layout Properties
- `display` (only `flex` and `none`)
- `position` (`relative`, `absolute`)
- `top`, `right`, `bottom`, `left`
- `margin`, `padding` (all variants)
- `width`, `height`, `min-*`, `max-*`
- `flex`, `flex-grow`, `flex-shrink`, `flex-basis`
- `flex-direction`, `flex-wrap`
- `align-items`, `align-self`, `align-content`
- `justify-content`
- `gap`
- `overflow` (`hidden`, `visible`)
### Visual Properties
- `color`
- `background`, `background-color`, `background-image`
- `border`, `border-radius`
- `box-shadow`
- `opacity`
### Typography
- `font-family`, `font-size`, `font-weight`, `font-style`
- `line-height`
- `letter-spacing`
- `text-align`
- `text-decoration`
- `text-transform`
- `white-space`
- `word-break`
- `text-overflow`
### NOT Supported
- `z-index` - elements render in DOM order
- `transform` with 3D functions (`rotateX`, `translateZ`, etc.)
- `animation`, `transition`
- `cursor`
- `filter` (partial support)
- Advanced typography (kerning, ligatures, OpenType features)
- RTL text direction
- CSS Grid
- `float`
- `::before`, `::after` pseudo-elements
- Media queries
- CSS variables
---
## Font Requirements
### Supported Formats
| Format | Supported | Notes |
| ------ | --------- | -------------------------------------- |
| TTF | Yes | Recommended for server-side |
| OTF | Yes | Recommended for server-side |
| WOFF | Yes | Good balance of size/speed |
| WOFF2 | **No** | Not supported (opentype.js limitation) |
### Loading Fonts
Fonts must be passed as `ArrayBuffer` (browser) or `Buffer` (Node.js):
```typescript
import satori from 'satori';
const fontData = await Bun.file('./fonts/Inter-Regular.ttf').arrayBuffer();
const svg = await satori(
<div style={{ fontFamily: 'Inter' }}>Hello</div>,
{
width: 1200,
height: 630,
fonts: [
{
name: 'Inter',
data: fontData,
weight: 400,
style: 'normal',
},
],
}
);
```
### Best Practices
1. **Define fonts globally** - don't create new font objects per render
2. **Use TTF/OTF on server** - faster to parse than WOFF
3. **Multiple weights** - pass each weight as separate font entry
4. **Fallback fonts** - provide fallbacks for missing characters
---
## Image Handling
### Image Requirements
```tsx
// REQUIRED: width and height for external URLs
<img
src="https://example.com/image.png"
width={100}
height={100}
/>
// RECOMMENDED: base64 for best performance
<img
src="data:image/png;base64,iVBORw0KGgoAAAANS..."
width={100}
height={100}
/>
```
### Image Best Practices
1. **Use base64** - avoids extra network requests during rendering
2. **Always set dimensions** - `width` and `height` are required for external URLs
3. **Fetch and convert** - for dynamic images, fetch then convert to base64:
```typescript
async function imageToBase64(url: string): Promise<string> {
const response = await fetch(url);
const buffer = await response.arrayBuffer();
const base64 = Buffer.from(buffer).toString("base64");
const mimeType = response.headers.get("content-type") || "image/png";
return `data:${mimeType};base64,${base64}`;
}
```
### Background Images
```tsx
<div
style={{
backgroundImage: "url(data:image/png;base64,...)",
backgroundSize: "cover",
backgroundPosition: "center",
}}
/>
```
---
## Emoji Support
Satori supports emoji through dynamic loading:
### Using `graphemeImages`
```typescript
const svg = await satori(
<div>Hello World! </div>,
{
width: 600,
height: 400,
fonts: [...],
graphemeImages: {
'': 'https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/svg/1f44b.svg',
},
}
);
```
### Using `loadAdditionalAsset`
```typescript
const svg = await satori(element, {
width: 1200,
height: 630,
fonts: [...],
loadAdditionalAsset: async (code, segment) => {
if (code === 'emoji') {
// Fetch Twemoji SVG and return as data URL
const emojiCode = getEmojiCodePoint(segment);
const response = await fetch(
`https://cdn.jsdelivr.net/gh/twitter/[email protected]/assets/svg/${emojiCode}.svg`
);
const svg = await response.text();
return `data:image/svg+xml;base64,${btoa(svg)}`;
}
return null;
},
});
```
---
## Known Issues & Workarounds
### Transparent Gradients Render as Black
**Bug:** `linear-gradient(transparent, white)` renders as dark gray to white.
**Workaround:** Use `rgba(255, 255, 255, 0)` instead of `transparent`:
```tsx
backgroundImage: "linear-gradient(rgba(255, 255, 255, 0), white)";
```
### No z-index Support
**Issue:** Elements render in DOM order, no z-index control.
**Workaround:** Order elements correctly in JSX (later elements render on top).
### Text Overflow
**Issue:** Long text may overflow containers unexpectedly.
**Workaround:** Always set `overflow: hidden` and use `text-overflow: ellipsis`:
```tsx
<div
style={{
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
maxWidth: 400,
}}
>
Long text that might overflow...
</div>
```
### Inconsistent Font Metrics
**Issue:** Text positioning may differ slightly from browser rendering.
**Workaround:** Test with actual fonts, add padding for safety margins.
---
## SVG to PNG Conversion
### Using @resvg/resvg-js
```typescript
import satori from "satori";
import { Resvg } from "@resvg/resvg-js";
// Generate SVG with Satori
const svg = await satori(element, options);
// Convert to PNG
const resvg = new Resvg(svg, {
fitTo: {
mode: "width",
value: 1200,
},
});
const pngData = resvg.render();
const pngBuffer = pngData.asPng();
```
### Performance Tips
1. **Lazy load** - import satori and resvg only when needed
2. **Cache fonts** - load fonts once at startup
3. **Reuse Resvg instances** - when generating many images
4. **Set appropriate dimensions** - larger images = longer render time
---
## Common Patterns
### OG Image Template
```tsx
const OGImage = ({ title, description }: Props) => (
<div
style={{
display: "flex",
flexDirection: "column",
width: "100%",
height: "100%",
padding: 60,
backgroundColor: "#1a1a2e",
color: "white",
fontFamily: "Inter",
}}
>
<div
style={{
display: "flex",
fontSize: 64,
fontWeight: 700,
marginBottom: 20,
}}
>
{title}
</div>
<div
style={{
display: "flex",
Related in Image & Video
watch
IncludedWatch a video (URL or local path). Downloads with yt-dlp, extracts auto-scaled frames with ffmpeg, pulls the transcript from captions (or Whisper API fallback), and hands the result to Claude so it can answer questions about what's in the video.
physical-ai-defect-image-generation
IncludedUse when the user wants to orchestrate defect image generation, run associated setup, or handle outputs on OSMO. The Day 0 path handles cold-start with USD-to-ROI, image-edit augmentation, and AnomalyGen to create initial PCBA datasets. The Day 1 path performs inference and labeling on real images. This skill helps with first-time asset setup, creation of finetuning checkpoints, and configuring deployment. Trigger keywords: defect image generation, dig workflow, dig pipeline, defect image detection workflow, aoi pipeline, aoi anomalygen, usd2roi anomalygen, day 0 pcba, day 1 pcba, day 1 real-photo alignment, day 1 manual roi, metal surface anomaly, glass defect, anomalygen finetune, setup_pcb, setup_metal, setup_glass, setup_pretrained, dig setup, dig datasets, dig pretrained checkpoint, dig image-edit endpoint.
accelint-react-best-practices
IncludedReact performance optimization and best practices. ALWAYS use this skill when working with any React code - writing components, hooks, JSX; refactoring; optimizing re-renders, memoization, state management; reviewing for performance; fixing hydration mismatches; debugging infinite re-renders, stale closures, input focus loss, animations restarting; preventing remounting; implementing transitions, lazy initialization, effect dependencies. Even simple React tasks benefit from these patterns. Covers React 19+ (useEffectEvent, Activity, ref props). Triggers - useEffect, useState, useMemo, useCallback, memo, inline components, nested components, components inside components, re-render, performance, hydration, SSR, Next.js, useDeferredValue, combined hooks.
elevenlabs-agents
IncludedBuild conversational AI voice agents with ElevenLabs Platform using React, JavaScript, React Native, or Swift SDKs. Configure agents, tools (client/server/MCP), RAG knowledge bases, multi-voice, and Scribe real-time STT. Use when: building voice chat interfaces, implementing AI phone agents with Twilio, configuring agent workflows or tools, adding RAG knowledge bases, testing with CLI "agents as code", or troubleshooting deprecated @11labs packages, Android audio cutoff, CSP violations, dynamic variables, or WebRTC config. Keywords: ElevenLabs Agents, ElevenLabs voice agents, AI voice agents, conversational AI, @elevenlabs/react, @elevenlabs/client, @elevenlabs/react-native, @elevenlabs/elevenlabs-js, @elevenlabs/agents-cli, elevenlabs SDK, voice AI, TTS, text-to-speech, ASR, speech recognition, turn-taking model, WebRTC voice, WebSocket voice, ElevenLabs conversation, agent system prompt, agent tools, agent knowledge base, RAG voice agents, multi-voice agents, pronunciation dictionary, voice speed control, elevenlabs scribe, @11labs deprecated, Android audio cutoff, CSP violation elevenlabs, dynamic variables elevenlabs, case-sensitive tool names, webhook authentication
humanizer
IncludedHumanize AI-generated text by detecting and removing patterns typical of LLM output. Rewrites text to sound natural, specific, and human. Uses 28 pattern detectors, 560+ AI vocabulary terms across 3 tiers, and statistical analysis (burstiness, type-token ratio, readability) for comprehensive detection. Use when asked to humanize text, de-AI writing, make content sound more natural/human, review writing for AI patterns, score text for AI detection, or improve AI-generated drafts. Covers content, language, style, communication, and filler categories.
generating-mermaid-diagrams
IncludedSalesforce architecture diagrams using Mermaid with ASCII fallback. Use this skill when generating text-based diagrams for Salesforce architecture, OAuth flows, ERDs, integration sequences, or Agentforce structure. TRIGGER when: user says "diagram", "visualize", "ERD", or asks for sequence diagrams, flowcharts, class diagrams, or architecture visualizations in Mermaid. DO NOT TRIGGER when: user wants PNG/SVG image output (use generating-visual-diagrams), or asks about non-Salesforce systems.