
Visual Diagrams
- 1 installs
- 18 repo stars
- Updated May 3, 2026
- coleam00/archon-video-generation-workflow
Builds professional architecture and flow diagrams for Remotion video scenes with gradient fills, shadows, glow effects, and Lucide brand icons.
About
Provides Remotion diagram components (HubAndSpoke, FlowDiagram, LayeredArchitecture, ComparisonDiagram, InfographicFlow) with YouTube-grade visual styling. A developer uses it when a Remotion video scene needs connected boxes, pipelines, or architecture visuals.
- Component picker for hub-spoke, pipeline, layered, comparison diagrams
- Uses lucide-react icons and gradient/shadow depth over wireframes
Visual Diagrams by the numbers
- 1 all-time installs (skills.sh)
- Ranked #1,202 of 1,337 Generative Media skills by installs in the Skillselion catalog
- Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/coleam00/archon-video-generation-workflow --skill visual-diagramsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 18 |
| Last updated | May 3, 2026 |
| Repository | coleam00/archon-video-generation-workflow ↗ |
What it does
Builds professional architecture and flow diagrams for Remotion video scenes with gradient fills, shadows, glow effects, and Lucide brand icons.
Files
Visual Diagrams Design System
Professional-grade diagram components for Remotion explainer videos. Replaces wireframe-quality boxes-and-lines with YouTube-grade visuals: gradient fills, depth shadows, animated glowing connections, brand logo images, and layered visual hierarchy.
When to Use This Skill
- Phase 4 scene building when the plan calls for architecture/system diagrams
- Any scene showing relationships between components (hub-spoke, flow, layers)
- Infrastructure/tech stack visualizations
- Before/after or comparison layouts
- Data flow or pipeline diagrams
The Problem This Solves
Without this skill, sub-agents produce wireframe-quality diagrams:
- Thin 1-2px borders on transparent boxes
- Unicode characters as "icons" (invisible in headless Chromium)
- No shadows, no depth, no visual hierarchy
- Tiny nodes that look like developer sketches
- Thin dashed connection lines with no glow or energy
Quick Reference: Which Component to Use
| Visual Need | Component | When to Use |
|---|---|---|
| Multi-stage process (PREFERRED) | InfographicFlow | Pipelines, workflows, how-it-works, stage-by-stage explanations — enterprise-grade pastel bands with Lucide icons |
| Central element + surrounding services | HubAndSpoke | Tech stacks, service architectures, API ecosystems |
| Sequential process/pipeline | FlowDiagram | Simple 3-5 node pipelines, build chains |
| Stacked layers (UI > API > DB) | LayeredArchitecture | Software architecture, network stacks, abstraction layers |
| Side-by-side comparison | ComparisonDiagram | Before/after, old vs new, competitor analysis |
| Git workflow visualization | GitBranching | Branching strategies, CI/CD flows, merge patterns |
Icon Library: lucide-react
All diagram components support Lucide icons (1000+ professional SVG icons). Import directly:
import { Search, Brain, Cpu, Database, Shield, Send, Package, Puzzle } from 'lucide-react';
// Use in InfographicFlow stages
{ label: 'Discovery', icon: Search, nodes: [...] }
// Use in DiagramIcon wrapper
<DiagramIcon icon={Search} color="#2E7D32" bg="#C8E6C9" size={48} />Browse all icons: https://lucide.dev/icons
DiagramIcon Wrapper
DiagramIcon wraps any Lucide icon in a colored circle/rounded background with shadow:
import { DiagramIcon } from '../shared/components/diagrams';
<DiagramIcon icon={Brain} color="#1565C0" bg="#BBDEFB" size={52} variant="circle" />
<DiagramIcon icon={Database} color="#E65100" bg="#FFE0B2" size={48} variant="rounded" />
<DiagramIcon imageSrc={staticFile('images/comp/logo.png')} color="#333" size={48} />
<DiagramIcon letter="A" color="#7B1FA2" bg="#E1BEE7" size={44} />Priority: Lucide icon > brand logo image > styled letter badge.
InfographicFlow — Enterprise-Grade Stage Diagrams
The flagship component. Produces pastel-banded row layouts like enterprise infographics (Anthropic, Google, DailyDoseofDS style).
import { InfographicFlow } from '../shared/components/diagrams';
import { Search, Brain, Zap } from 'lucide-react';
<InfographicFlow
title="How It Works"
subtitle="A 5-stage pipeline"
mode="light" // or "dark"
stages={[
{
label: 'Discovery',
icon: Search,
nodes: [
{ label: 'Scan', icon: Search },
{ label: 'Match', icon: Brain },
],
connector: 'arrow', // or '+' or custom string
description: 'Finds relevant items',
},
// ... more stages
]}
/>Light vs Dark Mode
- Light mode (
mode="light"): White background, pastel-colored bands (green, blue, orange,
purple, yellow, cyan, red, indigo). Enterprise infographic style.
- Dark mode (
mode="dark"):#0B1120background, subtle tinted bands. Matches existing
video dark theme.
Both modes use the same component — just flip the mode prop.
Palette System
Custom palettes available via getDiagramPalette() and getStagePalette():
import { getDiagramPalette, getStagePalette } from '../shared/components/diagrams';
const palette = getDiagramPalette('light');
const stage0Colors = getStagePalette(palette, 0); // green band
// stage0Colors.band, .accent, .iconBg, .text, .textMutedDesign Principles
1. Gradient Fills Over Flat Colors
Every node/box MUST use a subtle gradient fill, not a flat color. Gradients create depth and make elements feel three-dimensional.
// WRONG - flat transparent fill (wireframe look)
backgroundColor: `${color}22`
// CORRECT - gradient fill with depth
background: `linear-gradient(135deg, ${color}25, ${color}08)`2. Multi-Layer Shadows for Depth
Every node MUST have at least a 2-layer box shadow: a tight inner shadow for definition and a wider outer glow for atmosphere.
// WRONG - no shadow (flat, floats in void)
// (no boxShadow property)
// CORRECT - depth + glow
boxShadow: `0 4px 20px ${color}30, 0 0 40px ${color}15, inset 0 1px 0 rgba(255,255,255,0.05)`3. Thick Borders with Gradient Feel
Use 2-3px borders minimum. 1px borders disappear on YouTube at 720p. Use the node's accent color at 40-60% opacity for borders (not 20%).
// WRONG - too thin, too transparent
border: `1px solid ${color}22`
// CORRECT - visible at YouTube resolution
border: `2px solid ${color}66`
borderTop: `3px solid ${color}` // accent top edge4. Brand Logo Images Instead of Unicode Icons
When referencing known tools/services (GitHub, Docker, AWS, Cloudflare, etc.), use actual brand logo images downloaded to public/images/<composition>/. Unicode symbols and emoji render as black glyphs in headless Chromium.
// WRONG - invisible in rendered video
<div style={{ fontSize: 36 }}>{'🐳'}</div>
// CORRECT - actual brand logo
<Img src={staticFile('images/mycomp/docker-logo.png')}
style={{ width: 40, height: 40, objectFit: 'contain' }} />Image acquisition: During Phase 4 scene building, if a brand logo is needed: 1. Check if it already exists in public/images/<composition>/ 2. If not, download from GitHub avatars: https://github.com/<org>.png?size=128 3. Or use the scene's screenshots.json manifest for batch capture 4. Fall back to a styled letter badge (colored circle + first letter) — never Unicode emoji
5. Generous Node Sizing
Nodes must be large enough to be instantly readable at 720p. Minimum sizes:
| Element | Minimum Size | Recommended |
|---|---|---|
| Hub/center node | 180x120px | 200x140px |
| Spoke/satellite node | 160x100px | 180x110px |
| Flow diagram node | 200x100px | 220x120px |
| Layer bar height | 90px | 100-120px |
| Icon/logo inside node | 36x36px | 40-48px |
| Node label font | 24px | 26-28px |
| Sub-label font | 20px | 22px |
6. Animated Glowing Connections
Connection lines between nodes must have:
- Minimum 2.5px stroke width (not 1-2px)
- A subtle glow via SVG filter or duplicate line with blur
- Animated draw-on via strokeDasharray/strokeDashoffset
- Color matching the source or target node's accent
// WRONG - thin invisible line
<line stroke={color} strokeWidth={1} strokeDasharray="4 4" />
// CORRECT - visible glowing connection
<>
{/* Glow layer */}
<line stroke={color} strokeWidth={6} opacity={0.15}
filter="url(#connectionGlow)" />
{/* Main line */}
<line stroke={color} strokeWidth={2.5} opacity={0.7}
strokeDasharray={len} strokeDashoffset={dashOff} />
</>7. SVG Glow Filter (Add to Every Diagram SVG)
<svg>
<defs>
<filter id="connectionGlow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur stdDeviation="4" result="blur" />
<feMerge>
<feMergeNode in="blur" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<marker id="arrowhead" markerWidth="12" markerHeight="8"
refX="11" refY="4" orient="auto">
<polygon points="0 0, 12 4, 0 8" fill={COLORS.primary} />
</marker>
</defs>
</svg>8. Background Atmosphere
Diagram scenes should include subtle background elements for depth:
ProceduralNoisewith low opacity (0.08-0.12) for organic movement- Subtle radial gradient centered on the diagram's focal point
- Optional grid pattern at very low opacity (0.03-0.05)
{/* Atmospheric background */}
<div style={{
position: 'absolute', inset: 0,
background: `radial-gradient(ellipse at ${CENTER_X}px ${CENTER_Y}px,
${COLORS.primary}08 0%, transparent 60%)`,
}} />
<ProceduralNoise seed="diagram" color={COLORS.primary}
count={12} opacity={0.08} speed={0.004} />Component Upgrade Patterns
See references/component-patterns.md for detailed before/after code patterns for each shared component (HubAndSpoke, FlowDiagram, LayeredArchitecture, ComparisonDiagram).
See references/icon-strategy.md for the complete icon/logo acquisition and fallback strategy.
See references/animation-choreography.md for connection line animation, node entrance sequencing, and SpotlightFocus patterns for multi-phase diagrams.
Integration with Phase 4
When Phase 4 encounters a scene plan that calls for an architecture diagram or connected component visualization:
1. Load this skill for design guidance 2. Check shared components — use HubAndSpoke, FlowDiagram, LayeredArchitecture, ComparisonDiagram, or GitBranching as the foundation 3. Download brand logos if the diagram references known tools/services 4. Use the component's props — all components accept nodeStyle, connectionStyle, and iconSrc overrides for professional visual treatment 5. Add background atmosphere — ProceduralNoise + radial gradient behind the diagram 6. Run `/validate-scene` after building to catch visual quality issues
Rulecheck Integration
The visual scanner (rulecheck-scanner-visual) checks for these diagram-specific violations:
| Rule | Pattern | Fix |
|---|---|---|
| Wireframe node (no gradient/shadow) | backgroundColor: '${color} + hex ≤ 2 chars opacity, no boxShadow | Add gradient fill + multi-layer shadow |
| Thin border on diagram node | border: '1px on diagram container | Minimum 2px border |
| Missing connection glow | SVG <line> without glow filter or duplicate blur line | Add glow layer or SVG filter |
| Unicode emoji as diagram icon | Emoji char in node content div | Replace with brand logo image or styled letter badge |
| Undersized diagram node | Node width < 160px or height < 100px | Increase to minimum sizes |
| Flat connection lines | strokeWidth < 2.5 on connection lines | Increase to 2.5px minimum |
Animation Choreography for Diagrams
Entrance Sequence
Diagram elements should appear in this order, synced to narration:
1. Background atmosphere — fade in during AUDIO_OFFSET (frames 0-10) 2. Hub/center node — spring entrance at first mention (wordToFrame) 3. Connection lines — draw-on starting 8 frames after hub 4. Spoke/satellite nodes — each at its spoken word timestamp 5. Labels and sublabels — appear with their parent node (staggered 5 frames)
// Choreography example
const hubFrame = wordToFrame(hubTimestamp, OFFSET);
// Hub enters first
const hubScale = spring({
frame: Math.max(0, frame - hubFrame),
fps, config: SPRINGS.entrance,
durationRestThreshold: 0.001,
});
// Lines start drawing 8 frames after hub
const lineProgress = spring({
frame: Math.max(0, frame - hubFrame - 8),
fps, config: SPRINGS.smooth,
durationRestThreshold: 0.001,
});
// Each spoke at its own spoken word
const spokeScale = spring({
frame: Math.max(0, frame - spokeTimestamp),
fps, config: SPRINGS.bouncy,
durationRestThreshold: 0.001,
});Connection Line Animation
Draw-On Effect (Preferred)
Lines "draw" from source to target using strokeDasharray:
const dx = targetX - sourceX;
const dy = targetY - sourceY;
const lineLength = Math.sqrt(dx * dx + dy * dy);
// Shorten lines to stop at node edges
const dist = lineLength;
const ux = dx / dist;
const uy = dy / dist;
const SOURCE_MARGIN = 90; // hub half-size + gap
const TARGET_MARGIN = 80; // spoke half-size + gap
const sx = sourceX + ux * SOURCE_MARGIN;
const sy = sourceY + uy * SOURCE_MARGIN;
const ex = targetX - ux * TARGET_MARGIN;
const ey = targetY - uy * TARGET_MARGIN;
const visibleLength = Math.sqrt((ex-sx)**2 + (ey-sy)**2);
const dashOffset = interpolate(lineProgress, [0, 1], [visibleLength, 0], {
extrapolateLeft: 'clamp', extrapolateRight: 'clamp',
});
// Glow layer (renders behind)
<line x1={sx} y1={sy} x2={ex} y2={ey}
stroke={color} strokeWidth={8} opacity={0.12}
filter="url(#connectionGlow)" />
// Main line with draw-on
<line x1={sx} y1={sy} x2={ex} y2={ey}
stroke={color} strokeWidth={2.5} opacity={0.6}
strokeDasharray={visibleLength}
strokeDashoffset={dashOffset}
strokeLinecap="round" />Pulse Effect (For Active Connections)
After draw-on completes, add a subtle pulse to show "data flow":
const pulse = 0.5 + 0.2 * Math.sin((frame / 20) * Math.PI);
<line stroke={color} strokeWidth={2.5} opacity={pulse}
strokeDasharray="8 16"
strokeDashoffset={-frame * 0.8} // flowing dots
strokeLinecap="round" />SpotlightFocus for Multi-Phase Diagrams
When narration moves through different parts of a diagram, use SpotlightFocus to highlight the active section:
// Phase A: Hub + first 2 spokes active
const isPhaseA = frame < PHASE_B_START;
const isPhaseB = frame >= PHASE_B_START && frame < PHASE_C_START;
const isPhaseC = frame >= PHASE_C_START;
{nodes.map(node => {
const isActive =
(isPhaseA && PHASE_A_NODES.includes(node.id)) ||
(isPhaseB && PHASE_B_NODES.includes(node.id)) ||
isPhaseC; // all active in final phase
return (
<SpotlightFocus key={node.id} active={isActive} dimOpacity={0.25}>
<DiagramNode {...node} />
</SpotlightFocus>
);
})}Arrowhead Definitions
Always include this SVG <defs> block in diagram SVGs:
<svg style={{ position: 'absolute', inset: 0, width: '100%', height: '100%' }}>
<defs>
{/* Glow filter for connection lines */}
<filter id="connectionGlow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur stdDeviation="4" result="blur" />
<feMerge>
<feMergeNode in="blur" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
{/* Arrowhead marker */}
<marker id="arrowhead" markerWidth="12" markerHeight="8"
refX="11" refY="4" orient="auto">
<polygon points="0 0, 12 4, 0 8" fill={COLORS.primary} />
</marker>
{/* Color-specific arrowheads (generate per node color) */}
{nodeColors.map(color => (
<marker key={color} id={`arrow-${color.replace('#','')}`}
markerWidth="12" markerHeight="8" refX="11" refY="4" orient="auto">
<polygon points="0 0, 12 4, 0 8" fill={color} />
</marker>
))}
</defs>
{/* ... lines ... */}
</svg>Orthogonal (Right-Angle) Paths
For flowcharts and layered diagrams, use L-shaped or Z-shaped paths:
const createOrthogonalPath = (
from: { x: number; y: number },
to: { x: number; y: number }
) => {
const midX = (from.x + to.x) / 2;
return `M ${from.x} ${from.y} H ${midX} V ${to.y} H ${to.x}`;
};
<path
d={createOrthogonalPath(source, target)}
stroke={color}
strokeWidth={2.5}
fill="none"
markerEnd="url(#arrowhead)"
strokeLinecap="round"
strokeLinejoin="round"
/>SFX Pairing for Diagram Animations
Every major diagram entrance should have matching SFX in Composition.tsx:
| Animation Event | SFX | Volume | Offset |
|---|---|---|---|
| Hub/center node entrance | cinematic-whoosh.mp3 | 0.35 | At hub triggerFrame |
| Each spoke/node pop-in | pop.mp3 | 0.3 | At each node triggerFrame |
| Connection line draw-on | ui-switch (@remotion/sfx) | 0.2 | At line start |
| Full diagram reveal | spring-pop.mp3 | 0.4 | When last element appears |
| SpotlightFocus shift | page-turn (@remotion/sfx) | 0.2 | At phase boundary |
Component Patterns — Before/After Upgrade Guide
Detailed patterns for upgrading each shared diagram component from wireframe-quality to professional YouTube-grade visuals.
Universal Style Constants
Every diagram component uses these shared visual constants. These are built into the upgraded components via the DIAGRAM_STYLES export from src/shared/components/constants/index.ts.
// Node visual treatment — applied to ALL diagram nodes
export const DIAGRAM_STYLES = {
/** Multi-layer shadow for depth + glow */
nodeShadow: (color: string) =>
`0 4px 20px ${color}30, 0 0 40px ${color}15, inset 0 1px 0 rgba(255,255,255,0.05)`,
/** Gradient fill for nodes (replaces flat transparent fills) */
nodeGradient: (color: string) =>
`linear-gradient(145deg, ${color}28, ${color}0A)`,
/** Thick accent border (replaces 1px transparent borders) */
nodeBorder: (color: string, width = 2) =>
`${width}px solid ${color}55`,
/** Top accent stripe */
nodeAccentTop: (color: string) =>
`3px solid ${color}`,
/** Connection line glow (duplicate blurred line behind main line) */
connectionGlowWidth: 8,
connectionGlowOpacity: 0.12,
/** Main connection line */
connectionWidth: 2.5,
connectionOpacity: 0.6,
/** Minimum node dimensions */
minNodeWidth: 160,
minNodeHeight: 100,
minHubSize: 180,
/** Node border radius */
borderRadius: 14,
hubBorderRadius: 20,
} as const;---
HubAndSpoke — Before/After
BEFORE (wireframe)
// Tiny 120px spoke circles, 1px transparent border, no shadow
<div style={{
width: 120, height: 120,
border: `1px solid ${color}44`,
borderRadius: '50%',
background: 'rgba(255,255,255,0.03)',
}}>
<div style={{ fontSize: 32 }}>{'⚡'}</div> {/* emoji icon */}
<div style={{ fontSize: 20 }}>Label</div>
</div>
// Thin 2px lines with no glow
<line stroke="rgba(255,255,255,0.15)" strokeWidth={2} />AFTER (professional)
// 180px spoke with gradient fill, multi-shadow, brand logo
<div style={{
width: 180, height: 180,
border: `2px solid ${color}55`,
borderRadius: 20,
background: `linear-gradient(145deg, ${color}28, ${color}0A)`,
boxShadow: `0 4px 20px ${color}30, 0 0 40px ${color}15,
inset 0 1px 0 rgba(255,255,255,0.05)`,
}}>
<Img src={staticFile('images/comp/logo.png')}
style={{ width: 44, height: 44, objectFit: 'contain' }} />
<div style={{ fontSize: 24, fontWeight: 700 }}>Label</div>
<div style={{ fontSize: 20, color: textSecondary }}>Subtitle</div>
</div>
// Glowing connection with blur layer
<line stroke={color} strokeWidth={8} opacity={0.12}
filter="url(#connectionGlow)" />
<line stroke={color} strokeWidth={2.5} opacity={0.6}
strokeDasharray={len} strokeDashoffset={dashOff} />Key Changes
1. Spoke shape: borderRadius: '50%' (circle) changed to borderRadius: 20 (rounded rect) — circles waste space for text labels 2. Spoke size: 120px -> 180px minimum 3. Hub size: 160px -> 200px minimum 4. Icon: Unicode emoji -> brand logo <Img> or styled letter badge 5. Background: Flat rgba -> gradient fill 6. Shadow: None -> multi-layer (tight shadow + wide glow + inner highlight) 7. Border: 1px 26% opacity -> 2px 33% opacity 8. Connections: Single thin line -> glow layer + main line with dash animation
---
FlowDiagram — Before/After
BEFORE (wireframe)
// 180x100 flat glass card, thin top border
<div style={{
width: 180, height: 100,
backgroundColor: 'rgba(255,255,255,0.03)',
border: `2px solid ${color}44`,
borderTop: `3px solid ${color}`,
borderRadius: 12,
}}>
<div style={{ fontSize: 32 }}>{'◆'}</div>
<div style={{ fontSize: 24 }}>Process</div>
</div>
// Plain SVG arrow
<line stroke="rgba(255,255,255,0.25)" strokeWidth={2.5} />
<polygon fill="rgba(255,255,255,0.25)" />AFTER (professional)
// 220x120 gradient card with depth
<div style={{
width: 220, height: 120,
background: `linear-gradient(145deg, ${color}28, ${color}0A)`,
border: `2px solid ${color}55`,
borderTop: `3px solid ${color}`,
borderRadius: 14,
boxShadow: `0 4px 20px ${color}30, 0 0 40px ${color}15,
inset 0 1px 0 rgba(255,255,255,0.05)`,
}}>
<Img src={logo} style={{ width: 40, height: 40, objectFit: 'contain' }} />
<div style={{ fontSize: 26, fontWeight: 700 }}>Process</div>
<div style={{ fontSize: 20 }}>Subtitle</div>
</div>
// Glowing arrow with proper arrowhead
<line stroke={color} strokeWidth={6} opacity={0.12}
filter="url(#connectionGlow)" />
<line stroke={color} strokeWidth={2.5} opacity={0.6}
markerEnd="url(#arrowhead)" />Key Changes
1. Node size: 180x100 -> 220x120 2. Background: Flat glass -> gradient fill with depth shadow 3. Arrow styling: Flat white -> colored glow + matching arrowhead 4. Icon support: Character -> image with fallback
---
LayeredArchitecture — Before/After
BEFORE (wireframe)
// 100px tall bar with 1px border, 4px left accent
<div style={{
height: 100,
backgroundColor: 'rgba(255,255,255,0.03)',
border: `1px solid ${color}33`,
borderLeft: `4px solid ${color}`,
borderRadius: 12,
}}>AFTER (professional)
// 110px tall bar with gradient fill, shadow, accent stripe
<div style={{
height: 110,
background: `linear-gradient(90deg, ${color}18, ${color}06)`,
border: `2px solid ${color}33`,
borderLeft: `4px solid ${color}`,
borderRadius: 14,
boxShadow: `0 2px 12px ${color}20, inset 0 1px 0 rgba(255,255,255,0.03)`,
}}>Key Changes
1. Height: 100 -> 110px for more breathing room 2. Background: Flat glass -> horizontal gradient (stronger near left accent) 3. Shadow: None -> subtle depth + inner highlight 4. Border: 1px -> 2px for visibility 5. Item badges: Plain text -> gradient-filled mini badges
---
ComparisonDiagram — Before/After
BEFORE (wireframe)
// Glass panel with thin top accent
<div style={{
backgroundColor: 'rgba(255,255,255,0.03)',
border: `1px solid ${color}33`,
borderTop: `3px solid ${color}`,
borderRadius: 16,
}}>AFTER (professional)
// Rich panel with gradient header zone
<div style={{
background: `linear-gradient(180deg, ${color}15 0%, ${color}04 30%, transparent 100%)`,
border: `2px solid ${color}33`,
borderTop: `3px solid ${color}`,
borderRadius: 16,
boxShadow: `0 4px 24px ${color}20, inset 0 1px 0 rgba(255,255,255,0.04)`,
}}>Key Changes
1. Background: Flat glass -> vertical gradient (stronger at top near accent) 2. Shadow: None -> depth shadow matching accent color 3. Item rows: Flat background -> subtle gradient with hover-like treatment 4. VS divider: Plain circle -> glowing circle with pulsing animation
---
Styled Letter Badge (Icon Fallback)
When no brand logo image is available, use a styled letter badge instead of Unicode:
// Styled letter badge — used when logo image unavailable
<div style={{
width: 44, height: 44,
borderRadius: 10,
background: `linear-gradient(135deg, ${color}, ${color}88)`,
display: 'flex', alignItems: 'center', justifyContent: 'center',
boxShadow: `0 2px 8px ${color}40`,
}}>
<div style={{
fontSize: 22, fontWeight: 900,
color: '#ffffff',
display: 'block',
}}>
{label.charAt(0).toUpperCase()}
</div>
</div>This produces a colored rounded square with the first letter — much more professional than a raw Unicode symbol.
Icon & Logo Strategy for Diagram Nodes
Priority Order
When a diagram node represents a known tool, service, or technology:
1. Brand Logo Image (Best)
Download to public/images/<composition>/ and use <Img> from remotion:
import { Img, staticFile } from 'remotion';
<Img
src={staticFile('images/mycomp/docker-logo.png')}
style={{ width: 44, height: 44, objectFit: 'contain' }}
/>Where to get logos:
- GitHub organization avatars:
https://github.com/<org>.png?size=128 https://github.com/docker.png?size=128-> Docker whalehttps://github.com/cloudflare.png?size=128-> Cloudflare logohttps://github.com/vercel.png?size=128-> Vercel trianglehttps://github.com/openai.png?size=128-> OpenAI logohttps://github.com/anthropics.png?size=128-> Anthropic logo- Simple Icons CDN:
https://cdn.simpleicons.org/<name>/<color> - Works for 3000+ brands
- Returns SVG that can be saved as
.svg - Product websites:
/favicon.icoor/logo.png
Naming convention: <tool-lowercase>-logo.png (e.g., docker-logo.png, cloudflare-logo.png)
Size: Download at 128x128px minimum. Display at 40-48px in nodes.
2. Styled Letter Badge (Good Fallback)
When logo isn't available or would take too long to acquire:
const LetterBadge: React.FC<{ label: string; color: string; size?: number }> = ({
label, color, size = 44
}) => (
<div style={{
width: size, height: size,
borderRadius: size * 0.22,
background: `linear-gradient(135deg, ${color}, ${color}88)`,
display: 'flex', alignItems: 'center', justifyContent: 'center',
boxShadow: `0 2px 8px ${color}40`,
}}>
<div style={{
fontSize: size * 0.5, fontWeight: 900,
color: '#ffffff', display: 'block',
}}>
{label.charAt(0).toUpperCase()}
</div>
</div>
);3. Unicode Text Symbols (Minimal Fallback)
ONLY these symbols are safe (they respect CSS color in headless Chromium):
Safe: ▸ ▹ ● ○ ◆ ◇ ■ □ ▣ ▲ △ ▷ ◁ ★ ☆ ✓ ✕ → ← ↑ ↓ ⟲ ⟳ ⚐ ⊕ ⊖ ⊗
NEVER use emoji: 🐳 🔧 ⚡ 🗄 📦 🌐 ☁️ 🔒 🚀 — these render as black glyphs in headless Chromium and are invisible on dark backgrounds.
Per-Component Icon Props
All diagram components accept an iconSrc prop on their nodes. When provided, it renders an <Img> element. When absent, falls back to the icon string prop (rendered as a styled letter badge if it's a single character, or as a Unicode symbol).
// With brand logo
<HubAndSpoke
hub={{ label: 'Docker', iconSrc: staticFile('images/comp/docker-logo.png'), color: '#2496ED' }}
spokes={[
{ label: 'Redis', iconSrc: staticFile('images/comp/redis-logo.png'), color: '#DC382D', triggerFrame: 30 },
{ label: 'Postgres', icon: 'P', color: '#4169E1', triggerFrame: 60 }, // letter badge fallback
]}
/>Batch Logo Acquisition
During Phase 4, if a diagram needs multiple brand logos:
1. Create a list of needed logos with GitHub org names 2. Download all at once:
for org in docker cloudflare vercel redis; do
curl -sL "https://github.com/${org}.png?size=128" \
-o "public/images/<composition>/${org}-logo.png"
done3. Verify each downloaded file is a valid image (not a 404 HTML page) 4. Reference in scene code via staticFile('images/<composition>/<org>-logo.png')