remotion-trading
npx skills add https://github.com/josebarnetche/remotion-trading --skill remotion-trading
Agent 安装分布
Skill 文档
Remotion Trading â Bloomberg-Style Crypto Reels
You create polished crypto price journey videos as Instagram Reels (1080×1920 vertical). The aesthetic is Bloomberg terminal â clean, data-dense, professional, minimal animation. Every video loops seamlessly and works without sound.
Core Principles
- Real data only â Every number comes from Binance or CoinGecko. Never fabricate prices.
- Bloomberg terminal aesthetic â Data-dense, monospace numbers, thin grid lines, structured panels. No flashy glows or glass morphism. Precision is the style.
- Silent-first â Text overlays carry the entire story. No audio dependency. A viewer scrolling on mute must understand everything.
- Always loop â Every composition seamlessly loops. The last frame blends into the first.
- Price journey â The chart draws from past to present. The viewer watches history unfold, then the current price locks in with a counter/scramble effect.
- Weekly premium â 2-3 polished videos per week. Quality over speed. Every frame matters.
Before Building
Ask only what’s needed (many defaults are set):
1. Asset & Timeframe
- Which coin? (BTC, ETH, SOL, etc.)
- What timeframe? (1D, 7D, 30D, 90D, YTD)
- Default: 30D daily candles from Binance
2. Story Focus
- Any key moment to annotate? (ATH, crash, breakout, support bounce)
- Any specific stat to highlight beyond price? (volume spike, dominance shift)
- Default: clean price journey with current price reveal
3. Variation
- Candle chart or line chart?
- Include a light indicator? (one MA, S/R line, or none)
- Default: line chart, no indicators
Output Format â Vertical Reel
All compositions are 1080×1920 at 30fps. Duration is 15-30 seconds (450-900 frames).
export const reelConfig = {
width: 1080,
height: 1920,
fps: 30,
} as const;
Vertical Layout Zones
ââââââââââââââââââââ
â â â Zone 1: Header (asset + timeframe)
â BTC / USDT â y: 80-200
â 30D · Binance â
â â
â â
â ââââââââââââââ â â Zone 2: Chart area
â â â â y: 280-1100 (820px tall)
â â ââââ
ââââ
â â padded 60px sides
â â â â
â ââââââââââââââ â
â â
â $97,432.18 â â Zone 3: Hero price (counter reveal)
â â² +3.60% â y: 1200-1500
â â
â Vol $28.4B â â Zone 4: Stats row
â MCap $1.91T â y: 1550-1750
â 24h H $98,100 â
â â
â â â Zone 5: Bottom margin (safe area)
ââââââââââââââââââââ y: 1750-1920
Safe areas: 60px padding on all sides. Bottom 170px is safe zone for Instagram UI overlay.
Design System
Color Palette â Bloomberg Terminal
export const colors = {
// Backgrounds
bg: '#000000', // Pure black
bgPanel: '#0d1117', // Slightly lifted panels
bgRow: '#161b22', // Alternating row highlight
// Price action
up: '#3fb950', // Green (Bloomberg green)
down: '#f85149', // Red
neutral: '#8b949e', // Unchanged/muted
// Text
primary: '#e6edf3', // Primary text (near-white)
secondary: '#8b949e', // Labels, timestamps
muted: '#484f58', // Subtle grid, borders
// Chart
priceLine: '#58a6ff', // Blue price line
grid: 'rgba(139,148,158,0.1)', // Very subtle grid
axis: 'rgba(139,148,158,0.25)',
// Accent (used sparingly)
accent: '#58a6ff', // Blue for emphasis
} as const;
Typography
export const fonts = {
mono: '"JetBrains Mono", "SF Mono", "Fira Code", "Consolas", monospace',
label: '"Inter", "SF Pro", system-ui, sans-serif',
} as const;
Rules:
- ALL numbers use
fonts.monoâ prices, percentages, volumes, dates, everything - Labels use
fonts.labelat weight 500, uppercase, letter-spacing 1-2px - Hero price:
fonts.mono, weight 300, size 88-110px - Decimals: same font, 70% of the whole-number size, opacity 0.7
- No bold on prices â thin weight (300) reads more terminal-like
Spring Configs
// Data elements (chart lines, bars) â smooth and precise
const dataSpring = { damping: 18, stiffness: 80, mass: 0.7 };
// UI elements (labels, badges) â snappy
const uiSpring = { damping: 14, stiffness: 120, mass: 0.4 };
// Counter settle â quick lock
const counterSpring = { damping: 10, stiffness: 180, mass: 0.3 };
Minimal animation. No bouncy overshoots. Things appear with purpose and settle fast.
The Price Journey â Core Composition
Every video follows this arc:
Timeline (15s / 450 frames)
Phase 1: Header (0-45, 1.5s)
âââ Asset pair fades in: "BTC / USDT" (mono, 36px, primary color)
âââ Timeframe + source below: "30D · Binance" (label, 18px, secondary)
âââ Thin horizontal divider line draws leftâright
Phase 2: Chart Draw (45-270, 7.5s)
âââ Y-axis price labels appear (right side, mono, secondary)
âââ X-axis date labels appear (bottom, mono, muted)
âââ Grid lines: horizontal only, very subtle
âââ Price line draws leftâright (strokeDasharray animation)
âââ Small tracking dot at the drawing tip (4px, accent color)
âââ Optional: one MA line draws behind price (dashed, muted)
Phase 3: Price Lock (270-360, 3s)
âââ Chart holds (animation complete)
âââ Digits scramble: each character cycles rapidly then locks leftâright
âââ Final price locked: "$ 97,432.18" (mono, 96px, primary)
âââ Percent badge appears below: "â² +3.60%" (up=green, down=red)
âââ Subtle crosshair or horizontal line connects chart endpoint to price
Phase 4: Stats (360-420, 2s)
âââ Stats rows cascade in (stagger 4 frames each):
â âââ "24h Vol $28.4B"
â âââ "MCap $1.91T"
â âââ "24h Range $94,200 â $98,100"
âââ All mono, aligned with tabular spacing
Phase 5: Loop Crossfade (420-450, 1s)
âââ Everything fades out (opacity â 0)
âââ Overlaps with Phase 1 of next loop (crossfade blend)
For 30s version: expand Phase 2 to 15s, add a “Key Moment” pause mid-chart where an annotation callout appears at a notable point (ATH, dip, breakout), hold 2s, then continue drawing.
Data Integration â Crypto Only
Binance (Primary â No API Key)
// Klines (OHLCV)
const fetchKlines = async (symbol: string, interval: string, limit: number): Promise<OHLCV[]> => {
const res = await fetch(
`https://api.binance.com/api/v3/klines?symbol=${symbol}&interval=${interval}&limit=${limit}`
);
const raw = await res.json();
return raw.map((k: any[]) => ({
time: k[0],
open: parseFloat(k[1]),
high: parseFloat(k[2]),
low: parseFloat(k[3]),
close: parseFloat(k[4]),
volume: parseFloat(k[5]),
}));
};
// 24h Ticker
const fetchTicker = async (symbol: string) => {
const res = await fetch(`https://api.binance.com/api/v3/ticker/24hr?symbol=${symbol}`);
return res.json();
};
CoinGecko (Supplementary â Market Cap, Coin Details)
const fetchCoinDetails = async (coinId: string) => {
const res = await fetch(`https://api.coingecko.com/api/v3/coins/${coinId}`);
return res.json();
// market_data.market_cap.usd, total_volume, ath, circulating_supply
};
Common Symbols
| Coin | Binance Symbol | CoinGecko ID |
|---|---|---|
| BTC | BTCUSDT | bitcoin |
| ETH | ETHUSDT | ethereum |
| SOL | SOLUSDT | solana |
| BNB | BNBUSDT | binancecoin |
| XRP | XRPUSDT | ripple |
| DOGE | DOGEUSDT | dogecoin |
| ADA | ADAUSDT | cardano |
| AVAX | AVAXUSDT | avalanche-2 |
Data Loading Pattern
Always use calculateMetadata â fetch before render, never during:
export const calculatePriceJourneyMetadata: CalculateMetadataFunction<Props> = async ({ props }) => {
const { symbol = 'BTCUSDT', interval = '1d', limit = 30 } = props;
const [klines, ticker] = await Promise.all([
fetchKlines(symbol, interval, limit),
fetchTicker(symbol),
]);
validateOHLCV(klines);
return {
props: {
...props,
data: klines,
currentPrice: parseFloat(ticker.lastPrice),
change24h: parseFloat(ticker.priceChangePercent),
volume24h: parseFloat(ticker.quoteVolume),
high24h: parseFloat(ticker.highPrice),
low24h: parseFloat(ticker.lowPrice),
},
durationInFrames: 450,
fps: 30,
width: 1080,
height: 1920,
};
};
Counter / Scramble Effect â The Price Reveal
This is the hero moment. Digits cycle rapidly then lock one by one, left to right.
function scramblePrice(
targetFormatted: string, // "$97,432.18"
frame: number,
lockStartFrame: number,
framesPerLock: number, // 3 frames between each character locking
): string {
const chars = '0123456789';
return targetFormatted.split('').map((char, i) => {
// Non-digit characters ($, comma, dot) appear immediately
if (!'0123456789'.includes(char)) return char;
const charLockFrame = lockStartFrame + i * framesPerLock;
if (frame >= charLockFrame) return char; // Locked
// Cycling: change digit every 2 frames
const cycleIndex = Math.floor(frame / 2 + i * 3) % 10;
return chars[cycleIndex];
}).join('');
}
Timing: Start scramble at Phase 3 frame 0. Lock first digit after 15 frames. Each subsequent digit locks 3 frames later. Full price locked in ~40 frames (~1.3s). Then settle with counterSpring scale 1.02â1.0.
Seamless Looping
Every composition MUST loop. Use the crossfade overlap technique:
const OVERLAP = 30; // 1 second crossfade
const totalFrames = composition.durationInFrames;
// In the main component:
const outOpacity = frame >= totalFrames - OVERLAP
? interpolate(frame, [totalFrames - OVERLAP, totalFrames], [1, 0], { extrapolateRight: 'clamp' })
: 1;
// Render a <Sequence from={totalFrames - OVERLAP}> with the intro content
// at opacity: 1 - outOpacity
Design for loops:
- Phase 1 (header) must be simple enough to crossfade cleanly
- No elements that would look broken mid-transition
- Background grid is continuous (modular frame:
frame % gridCycleLength)
Chart Drawing
Line Chart (Default)
SVG <path> with strokeDasharray draw animation. See references/chart-components.md for full implementation.
Key specs for vertical Reel:
- Chart area: 960px wide (60px padding each side), 820px tall
- Price line:
strokeWidth: 2.5, color:colors.priceLine - Grid: horizontal lines only, spaced every ~160px, color:
colors.grid - Y-axis: right-aligned price labels in
fonts.mono, 14px,colors.secondary - X-axis: bottom date labels, 12px,
colors.muted - Tracking dot: 4px radius,
colors.accent, subtle 8px glow ring
Candlestick Chart (Variation)
For when user requests candles. Same chart area, staggered build animation. See references/chart-components.md.
- Body width:
(chartWidth / dataLength) * 0.6 - Wick: 1.5px centered on body
- Colors:
colors.up/colors.down - Last candle: slightly brighter (opacity 1.0 vs 0.85)
Optional Light Indicator
One of:
- SMA line: 20-period, dashed (
strokeDasharray: "4 6"),colors.muted, drawn behind price line - S/R line: horizontal, user-specified price level, dashed,
colors.secondary
Never more than one indicator. Clean chart = better content.
Text Overlay System (Silent-First)
Since there’s no audio, text overlays tell the story:
Annotation Callout
For key moments mid-chart:
âââââââââââââââ
â ATH $73,750 â â mono, 16px, panel background
ââââââââ¬ââââââââ
â (thin leader line)
â (4px dot on chart)
- Panel:
colors.bgPanelbackground, 1pxcolors.mutedborder, 8px radius - Leader line: 1px,
colors.muted - Appears with fade (10 frames), holds 60 frames, fades out (10 frames)
Stat Labels
Tabular layout â label left-aligned, value right-aligned:
24h Vol $28.4B
MCap $1.91T
24h Range $94.2K â $98.1K
- Label:
fonts.label, 16px,colors.secondary, uppercase - Value:
fonts.mono, 16px,colors.primary - Row height: 44px
- Cascade in: stagger 4 frames per row
Formatting
function formatPrice(price: number): string {
if (price >= 1000) return price.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
if (price >= 1) return price.toFixed(2);
if (price >= 0.01) return price.toFixed(4);
return price.toFixed(8); // sub-cent altcoins
}
function formatCompact(n: number): string {
if (n >= 1e12) return `$${(n / 1e12).toFixed(2)}T`;
if (n >= 1e9) return `$${(n / 1e9).toFixed(2)}B`;
if (n >= 1e6) return `$${(n / 1e6).toFixed(1)}M`;
if (n >= 1e3) return `$${(n / 1e3).toFixed(1)}K`;
return `$${n.toFixed(2)}`;
}
function formatPercent(v: number): string {
return `${v >= 0 ? 'â²' : 'â¼'} ${v >= 0 ? '+' : ''}${v.toFixed(2)}%`;
}
Critical Rules
- NEVER fabricate data â If API fails, abort. No placeholder prices.
- Correct decimals â BTC/ETH: 2 for USD price. Sub-$1 alts: 4-8 decimals.
- Monospace everything numeric â Prices, percents, volumes, dates. No exceptions.
- Always 1080×1920 â Vertical Reel format. No landscape variants unless explicitly asked.
- Always loop â Crossfade overlap on every composition.
- No branding â No logos, watermarks, handles, or CTAs. Pure data.
- No audio components â No
<Audio>tags. Silent by design. - Pre-fetch only â All data in
calculateMetadata. Zero network calls during render. - Minimal animation â Things appear, settle, hold. No bouncy overshoots. Terminal precision.
- Hold still for reading â After every reveal, minimum 2s of static frame.
For component blueprints: See references/chart-components.md For animation recipes: See references/animation-patterns.md For API details: See references/data-integration.md For scene templates: See references/scene-templates.md