@lalalic/markcut 1.0.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -0
- package/SKILL.md +28 -172
- package/docs/markdown-descriptive.md +12 -0
- package/package.json +3 -3
- package/src/entry.tsx +8 -2
- package/src/render/cli.mjs +88 -38
- package/src/render/cli.test.ts +13 -0
- package/src/utils/component-import-map.ts +93 -0
- package/templates/courseware/TEMPLATE.md +311 -0
- package/templates/courseware/agents/reviewer.md +84 -0
- package/templates/courseware/prompts/fix.md +30 -0
- package/templates/courseware/prompts/outline.md +53 -0
- package/templates/courseware/prompts/scene.md +64 -0
- package/docs/dynamic-components.md +0 -191
- package/docs/templates.md +0 -52
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
# Dynamic Components
|
|
2
|
-
|
|
3
|
-
Three ways to add custom visual content without rebuilding the engine.
|
|
4
|
-
|
|
5
|
-
## 1. Effects on Any Node (CSS Keyframes)
|
|
6
|
-
|
|
7
|
-
Add the `effects` key to any node to apply CSS keyframe animations. No wrapper node needed.
|
|
8
|
-
|
|
9
|
-
```json
|
|
10
|
-
{
|
|
11
|
-
"id": "animated-scene",
|
|
12
|
-
"type": "image",
|
|
13
|
-
"src": "photo.jpg",
|
|
14
|
-
"duration": 3,
|
|
15
|
-
"effects": ["bounceIn(1, ease-out, 2)"]
|
|
16
|
-
}
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
### 25+ Built-in Animation Names
|
|
20
|
-
|
|
21
|
-
| Fades | Slides | Zooms | Attention | Bounce | Rotations |
|
|
22
|
-
|-------|--------|-------|-----------|--------|-----------|
|
|
23
|
-
| `fadeIn` | `slideInDown` | `zoomIn` | `pulse` | `bounceIn` | `rotateIn` |
|
|
24
|
-
| `fadeOut` | `slideInUp` | `zoomOut` | `flash` | | `rotateOut` |
|
|
25
|
-
| `fadeInDown` | `slideInLeft` | | `bounce` | | |
|
|
26
|
-
| `fadeInUp` | `slideInRight` | | `heartBeat` | | |
|
|
27
|
-
| `fadeInLeft` | | | `rubberBand` | | |
|
|
28
|
-
| `fadeInRight` | | | `shakeX` | | |
|
|
29
|
-
| (8 total) | | | | | |
|
|
30
|
-
|
|
31
|
-
### Custom Keyframes
|
|
32
|
-
|
|
33
|
-
```json
|
|
34
|
-
{
|
|
35
|
-
"type": "effect",
|
|
36
|
-
"animation": "custom",
|
|
37
|
-
"customKeyframes": {
|
|
38
|
-
"0": { "opacity": "0", "transform": "scale3d(0,0,0) rotate(0deg)" },
|
|
39
|
-
"50": { "opacity": "0.5", "transform": "scale3d(1.2,1.2,1.2) rotate(180deg)" },
|
|
40
|
-
"100": { "opacity": "1", "transform": "scale3d(1,1,1) rotate(360deg)" }
|
|
41
|
-
},
|
|
42
|
-
"children": [...],
|
|
43
|
-
"actions": [{ "start": 0, "end": 2 }]
|
|
44
|
-
}
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
Percentages `"0"`–`"100"` map to action duration. Any numeric CSS property works.
|
|
48
|
-
|
|
49
|
-
## 2. Remote Components (bundler-based)
|
|
50
|
-
|
|
51
|
-
Register remote React components via the `~~~js imports` code fence (markdown) or `root.imports` array (JSON descriptive). The player server bundles all registered components into a single ESM module at startup.
|
|
52
|
-
|
|
53
|
-
```markdown
|
|
54
|
-
~~~js imports
|
|
55
|
-
export { BarChart } from "recharts"
|
|
56
|
-
export { Hello } from "git:user/repo/path/to/Hello.tsx"
|
|
57
|
-
export { Badge } from "https://cdn.example.com/components/badge.js"
|
|
58
|
-
|
|
59
|
-
export function Slide(props) {
|
|
60
|
-
return <div style={{color: '#fff'}}>{props.children}</div>;
|
|
61
|
-
}
|
|
62
|
-
~~~
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
Then use them in component JSX:
|
|
66
|
-
|
|
67
|
-
```json
|
|
68
|
-
{
|
|
69
|
-
"type": "component",
|
|
70
|
-
"jsx": "<Badge text='LIVE' color='#ff0000' />",
|
|
71
|
-
"actions": [{ "start": 0, "end": 3 }]
|
|
72
|
-
}
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
### How it works
|
|
76
|
-
|
|
77
|
-
1. The server extracts the imports block from the source file
|
|
78
|
-
2. `parseImportsBlock` resolves `export { X } from "spec"` and `export function X() {}` patterns
|
|
79
|
-
3. Inline functions' source code is scanned for `import X from "pkg"` statements — those packages are added to dependencies
|
|
80
|
-
4. `bundleFromEntries` creates a temp npm project, installs all packages, and runs `esbuild` to produce a single ESM file
|
|
81
|
-
5. The bundled file URL is set on `root.imports` and served from `/.component-cache/<hash>.js`
|
|
82
|
-
6. At runtime, `MarkCut.useComponentRegistry` does a dynamic `import(url)` to load all named exports
|
|
83
|
-
7. react-jsx-parser resolves component tags from the loaded registry
|
|
84
|
-
|
|
85
|
-
### Import spec forms
|
|
86
|
-
|
|
87
|
-
| Pattern | Resolves to | Example |
|
|
88
|
-
|---|---|---|
|
|
89
|
-
| `pkg` or `npm:pkg` | npm package (installed + bundled) | `export { BarChart } from "recharts"` |
|
|
90
|
-
| `git:user/repo` | GitHub repo source | `export { Comp } from "git:user/repo/src/Comp.tsx"` |
|
|
91
|
-
| `https://...` | Raw URL (used as-is) | `export { X } from "https://cdn.example.com/x.js"` |
|
|
92
|
-
| local path | Filesystem path | `export { X } from "./local/Component.tsx"` |
|
|
93
|
-
|
|
94
|
-
### Inline functions
|
|
95
|
-
|
|
96
|
-
Define components directly in the imports block. Dependencies used inside the function body are automatically detected and installed:
|
|
97
|
-
|
|
98
|
-
```markdown
|
|
99
|
-
~~~js imports
|
|
100
|
-
import ReactMarkdown from "react-markdown"
|
|
101
|
-
|
|
102
|
-
export function Slide({ children }) {
|
|
103
|
-
return <div className="slide"><ReactMarkdown>{children}</ReactMarkdown></div>;
|
|
104
|
-
}
|
|
105
|
-
~~~
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
The `import` statements at the top serve dual purpose: they bring packages into scope inside inline functions AND tell the bundler what to install. The packages are added to `package.json` during bundling.
|
|
109
|
-
|
|
110
|
-
### Component Contract
|
|
111
|
-
|
|
112
|
-
Props injected automatically:
|
|
113
|
-
- Nothing special required — just standard React props. The engine passes any `data` bindings from the component node as JSX variables.
|
|
114
|
-
|
|
115
|
-
For frame-accurate animation, use standard Remotion hooks inside inline functions:
|
|
116
|
-
|
|
117
|
-
```markdown
|
|
118
|
-
~~~js imports
|
|
119
|
-
import { useCurrentFrame } from "remotion"
|
|
120
|
-
|
|
121
|
-
export function FadeIn({ children }) {
|
|
122
|
-
const frame = useCurrentFrame();
|
|
123
|
-
const opacity = Math.min(1, frame / 15);
|
|
124
|
-
return <div style={{ opacity }}>{children}</div>;
|
|
125
|
-
}
|
|
126
|
-
~~~
|
|
127
|
-
|
|
128
|
-
Note: `remotion` and `react` are automatically available in the bundle's external scope — they do NOT need to be imported. However, adding `import { useCurrentFrame } from "remotion"` in the imports block is harmless and makes the dependency explicit.
|
|
129
|
-
|
|
130
|
-
## 3. Custom Components
|
|
131
|
-
|
|
132
|
-
Create a React component file in `src/components/`, register in `builtinComponents`.
|
|
133
|
-
|
|
134
|
-
### Component Contract
|
|
135
|
-
|
|
136
|
-
Props the engine injects automatically:
|
|
137
|
-
- `action: { start: number; end: number }` — action timing from the stream node
|
|
138
|
-
|
|
139
|
-
Use `useCurrentFrame()` for frame-accurate animation, `useVideoConfig()` for canvas size.
|
|
140
|
-
|
|
141
|
-
### Example
|
|
142
|
-
|
|
143
|
-
```tsx
|
|
144
|
-
// src/components/my/Badge.tsx
|
|
145
|
-
import React from "react";
|
|
146
|
-
import { useCurrentFrame, interpolate } from "remotion";
|
|
147
|
-
|
|
148
|
-
export const Badge: React.FC<{text: string; color?: string; action: any}> =
|
|
149
|
-
({ text, color, action }) => {
|
|
150
|
-
const frame = useCurrentFrame();
|
|
151
|
-
const local = frame - action.start * 30;
|
|
152
|
-
const opacity = interpolate(local, [0, 15], [0, 1]);
|
|
153
|
-
return (
|
|
154
|
-
<div style={{ opacity, padding: 12, background: color || theme.colors.primary,
|
|
155
|
-
color: "white", borderRadius: 8, fontSize: 48 }}>
|
|
156
|
-
{text}
|
|
157
|
-
</div>
|
|
158
|
-
);
|
|
159
|
-
};
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
### Register
|
|
163
|
-
|
|
164
|
-
```tsx
|
|
165
|
-
// src/components/index.ts
|
|
166
|
-
import { Badge } from "./my/Badge";
|
|
167
|
-
export const builtinComponents = { ..., Badge };
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
### Reference in stream tree
|
|
171
|
-
|
|
172
|
-
```json
|
|
173
|
-
{
|
|
174
|
-
"type": "component",
|
|
175
|
-
"jsx": "<Badge text='NEW' color='#ff6b35' />",
|
|
176
|
-
"actions": [{ "start": 1, "end": 4 }]
|
|
177
|
-
}
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
# common used components
|
|
182
|
-
- `react-markdown` — render markdown content, use plugins to extend functionality
|
|
183
|
-
- `remark-gfm` — support GitHub Flavored Markdown (tables, strikethrough, task lists)
|
|
184
|
-
- `remark-toc` — generate table of contents
|
|
185
|
-
- `remark-math` — support math formulas
|
|
186
|
-
- `rehype-katex` — render math formulas with KaTeX
|
|
187
|
-
- `remark-mermaidjs` — render mermaid diagrams in
|
|
188
|
-
- `react-markdown-mermaid` — render mermaid diagrams in standalone mode (no need to install mermaid separately)
|
|
189
|
-
|
|
190
|
-
- `@remotion/shapes` — render shapes like arrows, circles, rectangles, etc
|
|
191
|
-
- `@remotion/starburst` — render starburst animations
|
package/docs/templates.md
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# Video Templates
|
|
2
|
-
|
|
3
|
-
Ready-to-use markdown templates for common video scenarios. Each template:
|
|
4
|
-
|
|
5
|
-
- Contains **YAML frontmatter** with usage guidance (when, how, key decisions)
|
|
6
|
-
- Lists **required external packages** (npm imports)
|
|
7
|
-
- Uses **src:auto prompt:"..."** placeholders for AI-generated images/videos
|
|
8
|
-
- Includes **TTS narration** with configured voice and pacing
|
|
9
|
-
- Provides **scene structure** with named scenes, layouts, and durations
|
|
10
|
-
|
|
11
|
-
## Quick Start
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
# 1. Pick a template
|
|
15
|
-
cp docs/templates/courseware.md my-video.md
|
|
16
|
-
|
|
17
|
-
# 2. Fill in [bracketed] placeholders with actual content
|
|
18
|
-
# 3. Render
|
|
19
|
-
npx markcut render my-video.md --aspect 16x9
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
## Template Catalog
|
|
23
|
-
|
|
24
|
-
| Template | Scenario | Duration | Key Components |
|
|
25
|
-
|---|---|---|---|
|
|
26
|
-
| [courseware.md](templates/courseware.md) | 课件 / Lessons | 1-5 min | MarpSlide (markdown→slides), SlideText, MathDisplay |
|
|
27
|
-
| [product-ad.md](templates/product-ad.md) | 产品广告 / Ads | 15-45s | TextReveal, DeviceMockup, QRCode, FeatureCard |
|
|
28
|
-
| [movie-review.md](templates/movie-review.md) | 影视讲解 / Reviews | 1-3 min | CinematicText, StarRating, TextAnnotation, SplitScreen |
|
|
29
|
-
| [audiobook.md](templates/audiobook.md) | 有声图书 / Audiobooks | 3-30 min | BookCover, AmbientBackground, ProgressBar |
|
|
30
|
-
| [story-video.md](templates/story-video.md) | 故事视频 / Stories | 1-5 min | StoryTitle, SpeechBubble, ParticleEffect |
|
|
31
|
-
| [travel-log.md](templates/travel-log.md) | 旅行日志 / Travel | 1-3 min | LocationCard, WeatherIcon, TravelStats, Map node |}
|
|
32
|
-
|
|
33
|
-
## Frontmatter Fields Used by Templates
|
|
34
|
-
|
|
35
|
-
| Field | Purpose | Example |
|
|
36
|
-
|---|---|---|
|
|
37
|
-
| `tts` | TTS CLI command with `{input}` `{output}` | `edge-tts --voice "zh-CN-XiaoxiaoNeural" --text "{input}" --write-media "{output}"` |
|
|
38
|
-
| `stt` | STT CLI command with `{input}` `{output}` | `whisper "{input}" --model tiny --language zh --output_format vtt --output_dir "{output}"` |
|
|
39
|
-
| `tti` | TTI CLI command with `{input}` `{output}` | `pi --model agnes-2.0-flash --print "generate image: {input}" --output "{output}"` |
|
|
40
|
-
| `ttv` | TTV CLI command with `{input}` `{output}` | `pi --model agnes-2.0-flash --print "generate video: {input}" --output "{output}"` |
|
|
41
|
-
|
|
42
|
-
## src:auto — AI-Generated Media
|
|
43
|
-
|
|
44
|
-
Templates use a special `src:auto` value on `image` and `video` nodes to indicate AI generation:
|
|
45
|
-
|
|
46
|
-
```md
|
|
47
|
-
- image src:auto prompt:"sunset over Tokyo skyline, cinematic" duration:5
|
|
48
|
-
- video src:auto prompt:"person walking through cherry blossom park" duration:3
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
The `prompt:` key provides the generation prompt to the configured TTI/TTV CLI.
|
|
52
|
-
The pipeline resolves `src:auto` before compilation: runs the CLI command, gets the output path, and replaces `src:auto` with the actual generated file path.
|