superimg
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSuperImg Skill
SuperImg 使用指南
How It Works
工作原理
SuperImg generates videos from HTML/CSS templates. A template is a function that receives a and returns an HTML string. The renderer calls this function once per frame, advancing timing values each time.
RenderContext- (0 to 1) drives animation within a scene
sceneProgress - gives elapsed time for phase-based timing
sceneTimeSeconds - provides tween, math, and color utilities
ctx.std - carries template data (merged with defaults)
ctx.data
Templates render to MP4 via the CLI () or the server API (, ).
superimg renderrenderVideoloadTemplateSuperImg 基于HTML/CSS模板生成视频。模板是一个接收并返回HTML字符串的函数。渲染器会逐帧调用该函数,同时更新时间参数。
RenderContext- (0到1):控制场景内的动画进度
sceneProgress - :提供基于阶段计时的已流逝时间
sceneTimeSeconds - :提供补间、数学计算和颜色处理工具
ctx.std - :承载模板数据(与默认值合并)
ctx.data
模板可通过CLI命令()或服务端API(、)渲染为MP4格式。
superimg renderrenderVideoloadTemplateTemplate Authoring
模板编写
defineTemplate
defineTemplate
typescript
import { defineTemplate } from "superimg";
export default defineTemplate({
defaults: {
title: "Hello, SuperImg!",
subtitle: "Create stunning videos from code",
accentColor: "#667eea",
},
config: {
width: 1920,
height: 1080,
fps: 30,
durationSeconds: 4,
fonts: ["Space+Grotesk:wght@400;700"],
},
render(ctx) {
const { std, sceneTimeSeconds: time, width, height, isPortrait, data } = ctx;
const { title, subtitle, accentColor } = data;
// Responsive sizing
const titleSize = isPortrait ? 64 : 88;
const subtitleSize = isPortrait ? 22 : 28;
// Phase timing: Enter 0-1.5s | Hold 1.5-3s | Exit 3-4s
const enterProgress = std.math.clamp(time / 1.5, 0, 1);
const exitProgress = std.math.clamp((time - 3.0) / 1.0, 0, 1);
// Animate title
const titleOpacity = std.tween(0, 1, enterProgress, "easeOutCubic") * (1 - exitProgress);
const titleY = std.tween(40, 0, enterProgress, "easeOutCubic");
// Staggered subtitle (+0.3s delay)
const subtitleEnter = std.math.clamp((time - 0.3) / 1.5, 0, 1);
const subtitleOpacity = std.tween(0, 0.8, subtitleEnter, "easeOutCubic") * (1 - exitProgress);
const subtitleY = std.tween(30, 0, subtitleEnter, "easeOutCubic");
// Accent line
const lineEnter = std.math.clamp((time - 0.5) / 1.0, 0, 1);
const lineWidth = std.tween(0, 100, lineEnter, "easeOutCubic") * (1 - exitProgress);
const lineColor = std.color.alpha(accentColor, 0.8 * (1 - exitProgress));
return `
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
width: ${width}px;
height: ${height}px;
display: flex;
align-items: center;
justify-content: center;
background: #0f0f23;
font-family: system-ui, sans-serif;
overflow: hidden;
}
.title {
font-size: ${titleSize}px;
font-weight: 700;
color: ${accentColor};
opacity: ${titleOpacity};
transform: translateY(${titleY}px);
margin: 24px 0 12px;
}
.subtitle {
font-size: ${subtitleSize}px;
color: white;
opacity: ${subtitleOpacity};
transform: translateY(${subtitleY}px);
margin-bottom: 24px;
}
.accent-line {
width: ${lineWidth}%;
max-width: 500px;
height: 2px;
background: ${lineColor};
margin: 0 auto;
}
</style>
<div style="text-align: center">
<div class="accent-line"></div>
<h1 class="title">${title}</h1>
<p class="subtitle">${subtitle}</p>
<div class="accent-line"></div>
</div>
`;
},
});typescript
import { defineTemplate } from "superimg";
export default defineTemplate({
defaults: {
title: "Hello, SuperImg!",
subtitle: "Create stunning videos from code",
accentColor: "#667eea",
},
config: {
width: 1920,
height: 1080,
fps: 30,
durationSeconds: 4,
fonts: ["Space+Grotesk:wght@400;700"],
},
render(ctx) {
const { std, sceneTimeSeconds: time, width, height, isPortrait, data } = ctx;
const { title, subtitle, accentColor } = data;
// Responsive sizing
const titleSize = isPortrait ? 64 : 88;
const subtitleSize = isPortrait ? 22 : 28;
// Phase timing: Enter 0-1.5s | Hold 1.5-3s | Exit 3-4s
const enterProgress = std.math.clamp(time / 1.5, 0, 1);
const exitProgress = std.math.clamp((time - 3.0) / 1.0, 0, 1);
// Animate title
const titleOpacity = std.tween(0, 1, enterProgress, "easeOutCubic") * (1 - exitProgress);
const titleY = std.tween(40, 0, enterProgress, "easeOutCubic");
// Staggered subtitle (+0.3s delay)
const subtitleEnter = std.math.clamp((time - 0.3) / 1.5, 0, 1);
const subtitleOpacity = std.tween(0, 0.8, subtitleEnter, "easeOutCubic") * (1 - exitProgress);
const subtitleY = std.tween(30, 0, subtitleEnter, "easeOutCubic");
// Accent line
const lineEnter = std.math.clamp((time - 0.5) / 1.0, 0, 1);
const lineWidth = std.tween(0, 100, lineEnter, "easeOutCubic") * (1 - exitProgress);
const lineColor = std.color.alpha(accentColor, 0.8 * (1 - exitProgress));
return `
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
width: ${width}px;
height: ${height}px;
display: flex;
align-items: center;
justify-content: center;
background: #0f0f23;
font-family: system-ui, sans-serif;
overflow: hidden;
}
.title {
font-size: ${titleSize}px;
font-weight: 700;
color: ${accentColor};
opacity: ${titleOpacity};
transform: translateY(${titleY}px);
margin: 24px 0 12px;
}
.subtitle {
font-size: ${subtitleSize}px;
color: white;
opacity: ${subtitleOpacity};
transform: translateY(${subtitleY}px);
margin-bottom: 24px;
}
.accent-line {
width: ${lineWidth}%;
max-width: 500px;
height: 2px;
background: ${lineColor};
margin: 0 auto;
}
</style>
<div style="text-align: center">
<div class="accent-line"></div>
<h1 class="title">${title}</h1>
<p class="subtitle">${subtitle}</p>
<div class="accent-line"></div>
</div>
`;
},
});RenderContext Key Fields
RenderContext 核心字段
typescript
interface RenderContext<TData> {
std: Stdlib; // Tween, math, color utilities
// Scene timing (use these for animation)
sceneProgress: number; // 0-1 progress through current scene
sceneTimeSeconds: number; // Elapsed seconds in current scene
sceneDurationSeconds: number; // Total scene duration
// Canvas
width: number; // Canvas width in pixels
height: number; // Canvas height in pixels
isPortrait: boolean; // height > width
isLandscape: boolean; // width > height
// Data
data: TData; // Scene-specific data (merged with defaults)
// Global timing (rarely needed in templates)
globalProgress: number; // 0-1 progress through entire video
globalTimeSeconds: number;
fps: number;
}typescript
interface RenderContext<TData> {
std: Stdlib; // Tween, math, color utilities
// Scene timing (use these for animation)
sceneProgress: number; // 0-1 progress through current scene
sceneTimeSeconds: number; // Elapsed seconds in current scene
sceneDurationSeconds: number; // Total scene duration
// Canvas
width: number; // Canvas width in pixels
height: number; // Canvas height in pixels
isPortrait: boolean; // height > width
isLandscape: boolean; // width > height
// Data
data: TData; // Scene-specific data (merged with defaults)
// Global timing (rarely needed in templates)
globalProgress: number; // 0-1 progress through entire video
globalTimeSeconds: number;
fps: number;
}Core Stdlib
核心标准库
Tween (canonical animation primitive):
std.tween(from, to, progress) // Linear interpolation
std.tween(from, to, progress, "easeOutCubic") // Eased interpolation
std.tween(from, to, progress, { start, end, easing }) // Windowed animationMath:
std.math.clamp(value, min, max) // Restrict to range
std.math.map(val, inMin, inMax, outMin, outMax) // Remap rangeColor:
std.color.alpha(color, opacity) // Add transparency: alpha('#F00', 0.5)
std.color.mix(color1, color2, t) // Blend two colors
std.color.lighten(color, amount) // Lighten by percentage
std.color.darken(color, amount) // Darken by percentage
std.color.hsl(h, s, l) // Create HSL string补间动画(标准动画原语):
std.tween(from, to, progress) // Linear interpolation
std.tween(from, to, progress, "easeOutCubic") // Eased interpolation
std.tween(from, to, progress, { start, end, easing }) // Windowed animation数学工具:
std.math.clamp(value, min, max) // Restrict to range
std.math.map(val, inMin, inMax, outMin, outMax) // Remap range颜色工具:
std.color.alpha(color, opacity) // Add transparency: alpha('#F00', 0.5)
std.color.mix(color1, color2, t) // Blend two colors
std.color.lighten(color, amount) // Lighten by percentage
std.color.darken(color, amount) // Darken by percentage
std.color.hsl(h, s, l) // Create HSL stringPhase Timing Pattern
阶段计时模式
For multi-phase animations, use with :
sceneTimeSecondsclamptypescript
render(ctx) {
const { std, sceneTimeSeconds: time } = ctx;
// Enter: 0-1s | Hold: 1-3s | Exit: 3-4s
const enterProgress = std.math.clamp(time / 1.0, 0, 1);
const exitProgress = std.math.clamp((time - 3.0) / 1.0, 0, 1);
const eased = std.tween(0, 1, enterProgress, "easeOutCubic");
const opacity = eased * (1 - exitProgress);
const y = std.tween(50, 0, enterProgress, "easeOutCubic");
// ...
}对于多阶段动画,可结合与函数使用:
sceneTimeSecondsclamptypescript
render(ctx) {
const { std, sceneTimeSeconds: time } = ctx;
// Enter: 0-1s | Hold: 1-3s | Exit: 3-4s
const enterProgress = std.math.clamp(time / 1.0, 0, 1);
const exitProgress = std.math.clamp((time - 3.0) / 1.0, 0, 1);
const eased = std.tween(0, 1, enterProgress, "easeOutCubic");
const opacity = eased * (1 - exitProgress);
const y = std.tween(50, 0, enterProgress, "easeOutCubic");
// ...
}Responsive Sizing
响应式尺寸适配
Use / to adapt layout:
isPortraitisLandscapetypescript
const fontSize = ctx.isPortrait ? 48 : 72;
const layout = ctx.isPortrait ? "column" : "row";使用 / 来适配布局:
isPortraitisLandscapetypescript
const fontSize = ctx.isPortrait ? 48 : 72;
const layout = ctx.isPortrait ? "column" : "row";Rendering
渲染
CLI Rendering
CLI渲染
bash
undefinedbash
undefinedScaffold a new project (detects package manager automatically)
Scaffold a new project (detects package manager automatically)
superimg init my-project
superimg init my-project --pm pnpm # override package manager
superimg init --add # Add videos/ to existing project
superimg init my-project
superimg init my-project --pm pnpm # override package manager
superimg init --add # Add videos/ to existing project
Dev server with live preview (bare name resolves to videos/intro.ts)
Dev server with live preview (bare name resolves to videos/intro.ts)
superimg dev intro
superimg dev intro
Render to video
Render to video
superimg render videos/intro.ts -o output.mp4
superimg render videos/intro.ts -o output.mp4
With options
With options
superimg render videos/intro.ts -o output.mp4 --width 1080 --height 1920 --fps 60
undefinedsuperimg render videos/intro.ts -o output.mp4 --width 1080 --height 1920 --fps 60
undefinedProgrammatic Rendering (Server)
程序化渲染(服务端)
typescript
import { renderVideo, loadTemplate } from "superimg/server";
// Load template from file
const template = await loadTemplate("videos/intro.ts");
// Render to MP4
await renderVideo("videos/intro.ts", {
outputPath: "output.mp4",
width: 1920,
height: 1080,
});For low-level control, use , , and from .
createRenderPlanexecuteRenderPlanPlaywrightEnginesuperimg/servertypescript
import { renderVideo, loadTemplate } from "superimg/server";
// Load template from file
const template = await loadTemplate("videos/intro.ts");
// Render to MP4
await renderVideo("videos/intro.ts", {
outputPath: "output.mp4",
width: 1920,
height: 1080,
});如需底层控制,可使用中的、和。
superimg/servercreateRenderPlanexecuteRenderPlanPlaywrightEngineGotchas
注意事项
-
HTML strings, not JSX. Templates return template literal strings, not React/JSX. Useinterpolation for dynamic values.
${} -
Pure render function. Thefunction must be pure — no side effects, no DOM manipulation, no global state. It receives context and returns an HTML string.
render -
Use, not
sceneProgress. For animation within a scene, always useglobalProgress(0-1 within the current scene).sceneProgressspans the entire video and is rarely useful in templates.globalProgress -
Set root dimensions to canvas size. Style the root element (typicallyor an outer
body) todivso content fills the frame.width: ${width}px; height: ${height}px -
Import from the right path. Templates import from(for
"superimg", types). Server/rendering imports fromdefineTemplate."superimg/server" -
Data merges with defaults. When a template has, scene
defaultsis merged:data. You only need to pass overrides.{ ...defaults, ...data } -
Usefor Google Fonts. Declare fonts in
config.fonts(e.g.,config.fonts) instead of adding["Space+Grotesk:wght@400;700"]in your render HTML. The library automatically injects the@import url(...)tags and waits for fonts to load before capturing each frame.<link>
-
使用HTML字符串,而非JSX:模板需返回模板字面量字符串,而非React/JSX。使用语法插入动态值。
${} -
纯渲染函数:函数必须是纯函数——无副作用、无DOM操作、无全局状态。它接收上下文参数并返回HTML字符串。
render -
使用而非
sceneProgress:场景内的动画应始终使用globalProgress(当前场景内0到1的进度)。sceneProgress代表整个视频的进度,在模板中很少用到。globalProgress -
设置根元素尺寸为画布大小:将根元素(通常是或外层
body)的样式设置为div,确保内容填满整个帧。width: ${width}px; height: ${height}px -
正确导入路径:模板需从导入(用于
"superimg"和类型定义)。服务端/渲染相关代码需从defineTemplate导入。"superimg/server" -
数据与默认值合并:当模板定义了时,场景
defaults会与默认值合并:data。只需传入需要覆盖的参数即可。{ ...defaults, ...data } -
通过使用谷歌字体:在
config.fonts中声明字体(例如config.fonts),而非在渲染的HTML中添加["Space+Grotesk:wght@400;700"]。该库会自动注入@import url(...)标签,并在捕获每帧前等待字体加载完成。<link>