一键导入
ars-new-card
Generate a new custom card for the active series using ARS primitives. Creates a self-contained CardSpec at src/episodes/<active-series>/cards/.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Generate a new custom card for the active series using ARS primitives. Creates a self-contained CardSpec at src/episodes/<active-series>/cards/.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Run a single-episode coherence checklist after Studio review edits and before prepare/publish; diagnose or patch thesis drift, step seams, stale arguments, visual rhythm, and publish readiness.
Apply Studio intents back into the episode source and validate the result.
Generate 3 YouTube metadata candidates (title/description/tags) grounded in episode context, let the user pick one, then mark the artifact ready.
Usage guide for generating MiniMax TTS audio and subtitles for an episode.
Validate repo bootstrap readiness, ARS config, providers, and environment readiness with npx ars doctor.
Create a new episode scaffold for a series with npx ars episode create.
| name | ars:new-card |
| description | Generate a new custom card for the active series using ARS primitives. Creates a self-contained CardSpec at src/episodes/<active-series>/cards/. |
| argument-hint | <card-name> [description] |
| model | claude-sonnet-4-6 |
| effort | medium |
Generate a new series-scoped card using ARS engine primitives.
Prefer using this only when the episode plan clearly calls for a new custom card or the user explicitly asks for one. Existing series-scoped cards are reusable assets for that series, not throwaway episode-specific files.
Cards in ARS are self-contained modules (CardSpec) consisting of:
spec.ts — exports cardSpec: CardSpec<TData> with type, schema, defaults, component, agentHintsBaseSlide, WindowSlide, ScrollSlideimport.meta.glob — no manual registry edits neededOutput path: src/episodes/<active-series>/cards/<card-name>/
References:
references/card-primitives.md for BaseSlide, WindowSlide, and ScrollSlide props API.Parse arguments: Extract <card-name> and optional <description> from args.
Resolve the active series from .ars/config.json. /ars:new-card works inside one repo = one series, so do not ask for a series argument unless the repo is not initialized.
Read series theme: Check src/episodes/<active-series>/series-config.ts for theme seed / channel name to inform visual style.
Understand the card purpose: If no description, first look at the relevant episode plan.md, especially the ## New card section. Only ask one focused question if the concept is still unclear.
Check for reuse before scaffolding:
ars card list to see all built-in and series-scoped cards with agentHints and live examples.Choose the right primitive:
BaseSlide — fullscreen content, no chrome (default choice for most cards)WindowSlide — content inside a window frame (mac/terminal/browser/simple)ScrollSlide — WindowSlide with auto-scrolling (for long content like logs, code)Generate the card:
Create src/episodes/<active-series>/cards/<card-name>/spec.ts:
import { z } from "zod";
import type { CardSpec } from "../../../../engine/cards/types";
import { <CardName>Component } from "./component";
export type <CardName>Data = {
// fields derived from description
};
export const cardSpec = {
type: "<card-name>",
title: "<Human Label>",
description: "<one-line description of what this card renders>",
schema: z.object({ /* matching fields */ }),
defaults: { /* sensible defaults */ } satisfies Partial<<CardName>Data>,
component: <CardName>Component,
agentHints: {
whenToUse: "<when an agent should pick this card>",
notForUseCases: "<what this card is NOT for>",
exampleData: { /* minimal working data object */ },
},
} satisfies CardSpec<<CardName>Data>;
Create src/episodes/<active-series>/cards/<card-name>/component.tsx:
import React from "react";
import { BaseSlide, useCardContext } from "../../../../engine/primitives/BaseSlide";
import type { CardRenderProps } from "../../../../engine/cards/types";
import type { <CardName>Data } from "./spec";
// Body runs INSIDE <BaseSlide>, so it can safely call useCardContext() /
// Remotion hooks like useCurrentFrame(). The outer component must not call
// these — the BaseSlide context does not exist before <BaseSlide> mounts.
const Body: React.FC<{ data: <CardName>Data }> = ({ data }) => {
const { theme } = useCardContext();
// implement using theme.colors tokens only — never hardcoded hex
return <div>{/* card content */}</div>;
};
export const <CardName>Component: React.FC<CardRenderProps<<CardName>Data>> = ({ data }) => (
<BaseSlide>
<Body data={data} />
</BaseSlide>
);
useCardContext, useTheme, or Remotion hooks (useCurrentFrame, useVideoConfig) in the outer <CardName>Component that returns <BaseSlide>. They only work inside BaseSlide's subtree — put them in the Body child. See references/card-primitives.md for the Gotcha.<text>, avoid fractional text coordinates. Snap label x / y to integer pixels, especially when using textAnchor="middle", and prefer textRendering="geometricPrecision" to reduce shimmer in Remotion renders.Verify: Run ./node_modules/.bin/tsc --noEmit to confirm no type errors. Never use npx tsc — it may install a fake tsc package instead of TypeScript.
Report: Tell the user:
type string to reference in episode scripts (e.g., "<card-name>")theme.colors.* — never hardcoded hex valuessrc/episodes/<active-series>/cards/, not in the engine<text>, do not leave x / y on fractional pixels. Snap them to integers to avoid encoded-video shimmer, especially for centered labels and tick legends.type as a built-in engine card will silently replace it in the registry for that series. Use this to fully swap an engine card's implementation — all episode steps using that contentType will automatically use the series version. See references/card-primitives.md for the primitive API.