takomi 2.1.40 → 2.1.41
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/plugins/marketplace.json +22 -22
- package/README.md +3 -3
- package/assets/.agent/skills/remotion/rules/assets/charts-bar-chart.tsx +173 -173
- package/assets/.agent/skills/remotion/rules/assets/text-animations-typewriter.tsx +100 -100
- package/assets/.agent/skills/remotion/rules/text-animations.md +20 -20
- package/assets/.agent/skills/remotion/rules/videos.md +171 -171
- package/assets/.agent/skills/remotion-real-ui-video/SKILL.md +264 -0
- package/assets/.agent/skills/remotion-real-ui-video/references/anti-patterns.md +114 -0
- package/assets/.agent/skills/remotion-real-ui-video/references/completion-checklist.md +75 -0
- package/assets/.agent/skills/remotion-real-ui-video/references/real-ui-bridge-example.md +93 -0
- package/assets/.agent/skills/takomi-flow/SKILL.md +244 -244
- package/docs/features/TakomiFlow_Portable_Plugin.md +82 -82
- package/docs/takomi-flow-onboarding.md +86 -86
- package/docs/takomi-flow-public-distribution.md +94 -94
- package/package.json +1 -1
- package/plugins/takomi-flow/.mcp.json +11 -11
- package/plugins/takomi-flow/assets/capabilities.json +203 -203
- package/plugins/takomi-flow/assets/collection.schema.json +29 -29
- package/plugins/takomi-flow/assets/examples.json +94 -94
- package/plugins/takomi-flow/assets/request.schema.json +91 -91
- package/plugins/takomi-flow/assets/result.schema.json +46 -46
- package/plugins/takomi-flow/assets/templates/image-request.json +17 -17
- package/plugins/takomi-flow/assets/templates/video-request.json +19 -19
- package/plugins/takomi-flow/package.json +38 -38
- package/plugins/takomi-flow/pnpm-lock.yaml +813 -813
- package/plugins/takomi-flow/references/flow-provider-contract.md +349 -349
- package/plugins/takomi-flow/scripts/lib/agent-plan.mjs +140 -140
- package/plugins/takomi-flow/scripts/lib/api.mjs +113 -113
- package/plugins/takomi-flow/scripts/lib/args.mjs +66 -66
- package/plugins/takomi-flow/scripts/lib/audit.mjs +65 -65
- package/plugins/takomi-flow/scripts/lib/browser.mjs +78 -78
- package/plugins/takomi-flow/scripts/lib/capabilities.mjs +11 -11
- package/plugins/takomi-flow/scripts/lib/collect.mjs +53 -53
- package/plugins/takomi-flow/scripts/lib/commands.mjs +192 -192
- package/plugins/takomi-flow/scripts/lib/doctor.mjs +77 -77
- package/plugins/takomi-flow/scripts/lib/examples.mjs +17 -17
- package/plugins/takomi-flow/scripts/lib/flow-media.mjs +39 -39
- package/plugins/takomi-flow/scripts/lib/flow-outcome.mjs +115 -115
- package/plugins/takomi-flow/scripts/lib/flow-project-session.mjs +153 -153
- package/plugins/takomi-flow/scripts/lib/flow-ui.mjs +204 -204
- package/plugins/takomi-flow/scripts/lib/generation.mjs +190 -190
- package/plugins/takomi-flow/scripts/lib/inspect.mjs +81 -81
- package/plugins/takomi-flow/scripts/lib/mcp-prompts.mjs +39 -39
- package/plugins/takomi-flow/scripts/lib/mcp-resources.mjs +16 -16
- package/plugins/takomi-flow/scripts/lib/mcp-tools.mjs +165 -165
- package/plugins/takomi-flow/scripts/lib/media.mjs +78 -78
- package/plugins/takomi-flow/scripts/lib/observe.mjs +54 -54
- package/plugins/takomi-flow/scripts/lib/paths.mjs +37 -37
- package/plugins/takomi-flow/scripts/lib/playwright-loader.mjs +23 -23
- package/plugins/takomi-flow/scripts/lib/prompts.mjs +72 -72
- package/plugins/takomi-flow/scripts/lib/report.mjs +141 -141
- package/plugins/takomi-flow/scripts/lib/request-validator.mjs +73 -73
- package/plugins/takomi-flow/scripts/lib/request.mjs +66 -66
- package/plugins/takomi-flow/scripts/lib/resource-files.mjs +69 -69
- package/plugins/takomi-flow/scripts/lib/result.mjs +31 -31
- package/plugins/takomi-flow/scripts/lib/review.mjs +44 -44
- package/plugins/takomi-flow/scripts/lib/selftest.mjs +153 -153
- package/plugins/takomi-flow/scripts/lib/settings-plan.mjs +44 -44
- package/plugins/takomi-flow/scripts/lib/templates.mjs +37 -37
- package/plugins/takomi-flow/scripts/lib/trusted-chrome.mjs +67 -67
- package/plugins/takomi-flow/scripts/lib/workflow.mjs +56 -56
- package/plugins/takomi-flow/scripts/mcp-server.mjs +18 -18
- package/plugins/takomi-flow/scripts/mcp-smoke.mjs +144 -144
- package/plugins/takomi-flow/scripts/takomi-flow.mjs +17 -17
- package/plugins/takomi-flow/skills/takomi-flow/SKILL.md +244 -244
- package/plugins/takomi-flow/skills/takomi-flow/agents/openai.yaml +7 -7
- package/scripts/install-takomi-flow.ps1 +85 -85
- package/src/skills-catalog.js +10 -9
|
@@ -4,29 +4,29 @@
|
|
|
4
4
|
"displayName": "J StaR Films Studios"
|
|
5
5
|
},
|
|
6
6
|
"plugins": [
|
|
7
|
-
{
|
|
8
|
-
"name": "takomi-codex",
|
|
9
|
-
"source": {
|
|
10
|
-
"source": "local",
|
|
11
|
-
"path": "./plugins/takomi-codex"
|
|
7
|
+
{
|
|
8
|
+
"name": "takomi-codex",
|
|
9
|
+
"source": {
|
|
10
|
+
"source": "local",
|
|
11
|
+
"path": "./plugins/takomi-codex"
|
|
12
12
|
},
|
|
13
13
|
"policy": {
|
|
14
14
|
"installation": "AVAILABLE",
|
|
15
15
|
"authentication": "ON_INSTALL"
|
|
16
|
-
},
|
|
17
|
-
"category": "Productivity"
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
"name": "takomi-flow",
|
|
21
|
-
"source": {
|
|
22
|
-
"source": "local",
|
|
23
|
-
"path": "./plugins/takomi-flow"
|
|
24
|
-
},
|
|
25
|
-
"policy": {
|
|
26
|
-
"installation": "AVAILABLE",
|
|
27
|
-
"authentication": "ON_INSTALL"
|
|
28
|
-
},
|
|
29
|
-
"category": "Productivity"
|
|
30
|
-
}
|
|
31
|
-
]
|
|
32
|
-
}
|
|
16
|
+
},
|
|
17
|
+
"category": "Productivity"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"name": "takomi-flow",
|
|
21
|
+
"source": {
|
|
22
|
+
"source": "local",
|
|
23
|
+
"path": "./plugins/takomi-flow"
|
|
24
|
+
},
|
|
25
|
+
"policy": {
|
|
26
|
+
"installation": "AVAILABLE",
|
|
27
|
+
"authentication": "ON_INSTALL"
|
|
28
|
+
},
|
|
29
|
+
"category": "Productivity"
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ This isn't prompt engineering. This is **orchestrated development** — a battle
|
|
|
24
24
|
|
|
25
25
|
## Features
|
|
26
26
|
|
|
27
|
-
- **🧠
|
|
27
|
+
- **🧠 75+ Skills** — Specialized capabilities from security audits to AI video generation, installed on demand
|
|
28
28
|
- **🔄 Universal IDE Sync** — Install once, sync to Antigravity, Claude Code, Codex, Cursor, Kilo Code, Pi, and Windsurf
|
|
29
29
|
- **🏗️ Full Project Lifecycle** — From genesis (planning) through design, build, and finalize — with verification gates at every step
|
|
30
30
|
- **🎭 Specialized Agent Modes** — Orchestrator, Architect, Coder, Debugger, Reviewer — each with purpose-built workflows
|
|
@@ -147,7 +147,7 @@ See [TakomiFlow Onboarding](docs/takomi-flow-onboarding.md) and [TakomiFlow Publ
|
|
|
147
147
|
|
|
148
148
|
## Skill Ecosystem
|
|
149
149
|
|
|
150
|
-
Think of skills as specialized team members you can summon on demand. Takomi ships **
|
|
150
|
+
Think of skills as specialized team members you can summon on demand. Takomi ships **75+ skills** organized by category.
|
|
151
151
|
|
|
152
152
|
### Core Skills (Default Install)
|
|
153
153
|
|
|
@@ -184,7 +184,7 @@ npx -y skills add https://github.com/JStaRFilms/VibeCode-Protocol-Suite
|
|
|
184
184
|
|
|
185
185
|
**AI Media / Content Creation** — `ai-avatar-video`, `ai-marketing-videos`, `ai-podcast-creation`, `ai-product-photography`, `ai-social-media-content`, `ai-voice-cloning`, `takomi-flow`
|
|
186
186
|
|
|
187
|
-
**Creative / Video / Art** — `algorithmic-art`, `blender-mcp-scene-director`, `takomi-flow`, `remotion`, `youtube-pipeline`, `ai-avatar-video`, `ai-marketing-videos`, `photo-book-builder`
|
|
187
|
+
**Creative / Video / Art** — `algorithmic-art`, `blender-mcp-scene-director`, `takomi-flow`, `remotion`, `remotion-real-ui-video`, `youtube-pipeline`, `ai-avatar-video`, `ai-marketing-videos`, `photo-book-builder`
|
|
188
188
|
|
|
189
189
|
**Skill Building / Prompting / Orchestration** — `skill-creator`, `prompt-engineering`, `subagent-driven-development`, `spawn-task`
|
|
190
190
|
|
|
@@ -1,173 +1,173 @@
|
|
|
1
|
-
import {loadFont} from '@remotion/google-fonts/Inter';
|
|
2
|
-
import {AbsoluteFill, spring, useCurrentFrame, useVideoConfig} from 'remotion';
|
|
3
|
-
|
|
4
|
-
const {fontFamily} = loadFont();
|
|
5
|
-
|
|
6
|
-
const COLOR_BAR = '#D4AF37';
|
|
7
|
-
const COLOR_TEXT = '#ffffff';
|
|
8
|
-
const COLOR_MUTED = '#888888';
|
|
9
|
-
const COLOR_BG = '#0a0a0a';
|
|
10
|
-
const COLOR_AXIS = '#333333';
|
|
11
|
-
|
|
12
|
-
// Ideal composition size: 1280x720
|
|
13
|
-
|
|
14
|
-
const Title: React.FC<{children: React.ReactNode}> = ({children}) => (
|
|
15
|
-
<div style={{textAlign: 'center', marginBottom: 40}}>
|
|
16
|
-
<div style={{color: COLOR_TEXT, fontSize: 48, fontWeight: 600}}>
|
|
17
|
-
{children}
|
|
18
|
-
</div>
|
|
19
|
-
</div>
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
const YAxis: React.FC<{steps: number[]; height: number}> = ({
|
|
23
|
-
steps,
|
|
24
|
-
height,
|
|
25
|
-
}) => (
|
|
26
|
-
<div
|
|
27
|
-
style={{
|
|
28
|
-
display: 'flex',
|
|
29
|
-
flexDirection: 'column',
|
|
30
|
-
justifyContent: 'space-between',
|
|
31
|
-
height,
|
|
32
|
-
paddingRight: 16,
|
|
33
|
-
}}
|
|
34
|
-
>
|
|
35
|
-
{steps
|
|
36
|
-
.slice()
|
|
37
|
-
.reverse()
|
|
38
|
-
.map((step) => (
|
|
39
|
-
<div
|
|
40
|
-
key={step}
|
|
41
|
-
style={{
|
|
42
|
-
color: COLOR_MUTED,
|
|
43
|
-
fontSize: 20,
|
|
44
|
-
textAlign: 'right',
|
|
45
|
-
}}
|
|
46
|
-
>
|
|
47
|
-
{step.toLocaleString()}
|
|
48
|
-
</div>
|
|
49
|
-
))}
|
|
50
|
-
</div>
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
const Bar: React.FC<{
|
|
54
|
-
height: number;
|
|
55
|
-
progress: number;
|
|
56
|
-
}> = ({height, progress}) => (
|
|
57
|
-
<div
|
|
58
|
-
style={{
|
|
59
|
-
flex: 1,
|
|
60
|
-
display: 'flex',
|
|
61
|
-
flexDirection: 'column',
|
|
62
|
-
justifyContent: 'flex-end',
|
|
63
|
-
}}
|
|
64
|
-
>
|
|
65
|
-
<div
|
|
66
|
-
style={{
|
|
67
|
-
width: '100%',
|
|
68
|
-
height,
|
|
69
|
-
backgroundColor: COLOR_BAR,
|
|
70
|
-
borderRadius: '8px 8px 0 0',
|
|
71
|
-
opacity: progress,
|
|
72
|
-
}}
|
|
73
|
-
/>
|
|
74
|
-
</div>
|
|
75
|
-
);
|
|
76
|
-
|
|
77
|
-
const XAxis: React.FC<{
|
|
78
|
-
children: React.ReactNode;
|
|
79
|
-
labels: string[];
|
|
80
|
-
height: number;
|
|
81
|
-
}> = ({children, labels, height}) => (
|
|
82
|
-
<div style={{flex: 1, display: 'flex', flexDirection: 'column'}}>
|
|
83
|
-
<div
|
|
84
|
-
style={{
|
|
85
|
-
display: 'flex',
|
|
86
|
-
alignItems: 'flex-end',
|
|
87
|
-
gap: 16,
|
|
88
|
-
height,
|
|
89
|
-
borderLeft: `2px solid ${COLOR_AXIS}`,
|
|
90
|
-
borderBottom: `2px solid ${COLOR_AXIS}`,
|
|
91
|
-
paddingLeft: 16,
|
|
92
|
-
}}
|
|
93
|
-
>
|
|
94
|
-
{children}
|
|
95
|
-
</div>
|
|
96
|
-
<div
|
|
97
|
-
style={{
|
|
98
|
-
display: 'flex',
|
|
99
|
-
gap: 16,
|
|
100
|
-
paddingLeft: 16,
|
|
101
|
-
marginTop: 12,
|
|
102
|
-
}}
|
|
103
|
-
>
|
|
104
|
-
{labels.map((label) => (
|
|
105
|
-
<div
|
|
106
|
-
key={label}
|
|
107
|
-
style={{
|
|
108
|
-
flex: 1,
|
|
109
|
-
textAlign: 'center',
|
|
110
|
-
color: COLOR_MUTED,
|
|
111
|
-
fontSize: 20,
|
|
112
|
-
}}
|
|
113
|
-
>
|
|
114
|
-
{label}
|
|
115
|
-
</div>
|
|
116
|
-
))}
|
|
117
|
-
</div>
|
|
118
|
-
</div>
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
export const MyAnimation = () => {
|
|
122
|
-
const frame = useCurrentFrame();
|
|
123
|
-
const {fps, height} = useVideoConfig();
|
|
124
|
-
|
|
125
|
-
const data = [
|
|
126
|
-
{month: 'Jan', price: 2039},
|
|
127
|
-
{month: 'Mar', price: 2160},
|
|
128
|
-
{month: 'May', price: 2327},
|
|
129
|
-
{month: 'Jul', price: 2426},
|
|
130
|
-
{month: 'Sep', price: 2634},
|
|
131
|
-
{month: 'Nov', price: 2672},
|
|
132
|
-
];
|
|
133
|
-
|
|
134
|
-
const minPrice = 2000;
|
|
135
|
-
const maxPrice = 2800;
|
|
136
|
-
const priceRange = maxPrice - minPrice;
|
|
137
|
-
const chartHeight = height - 280;
|
|
138
|
-
const yAxisSteps = [2000, 2400, 2800];
|
|
139
|
-
|
|
140
|
-
return (
|
|
141
|
-
<AbsoluteFill
|
|
142
|
-
style={{
|
|
143
|
-
backgroundColor: COLOR_BG,
|
|
144
|
-
padding: 60,
|
|
145
|
-
display: 'flex',
|
|
146
|
-
flexDirection: 'column',
|
|
147
|
-
fontFamily,
|
|
148
|
-
}}
|
|
149
|
-
>
|
|
150
|
-
<Title>Gold Price 2024</Title>
|
|
151
|
-
|
|
152
|
-
<div style={{display: 'flex', flex: 1}}>
|
|
153
|
-
<YAxis steps={yAxisSteps} height={chartHeight} />
|
|
154
|
-
<XAxis height={chartHeight} labels={data.map((d) => d.month)}>
|
|
155
|
-
{data.map((item, i) => {
|
|
156
|
-
const progress = spring({
|
|
157
|
-
frame: frame - i * 5 - 10,
|
|
158
|
-
fps,
|
|
159
|
-
config: {damping: 18, stiffness: 80},
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
const barHeight =
|
|
163
|
-
((item.price - minPrice) / priceRange) * chartHeight * progress;
|
|
164
|
-
|
|
165
|
-
return (
|
|
166
|
-
<Bar key={item.month} height={barHeight} progress={progress} />
|
|
167
|
-
);
|
|
168
|
-
})}
|
|
169
|
-
</XAxis>
|
|
170
|
-
</div>
|
|
171
|
-
</AbsoluteFill>
|
|
172
|
-
);
|
|
173
|
-
};
|
|
1
|
+
import {loadFont} from '@remotion/google-fonts/Inter';
|
|
2
|
+
import {AbsoluteFill, spring, useCurrentFrame, useVideoConfig} from 'remotion';
|
|
3
|
+
|
|
4
|
+
const {fontFamily} = loadFont();
|
|
5
|
+
|
|
6
|
+
const COLOR_BAR = '#D4AF37';
|
|
7
|
+
const COLOR_TEXT = '#ffffff';
|
|
8
|
+
const COLOR_MUTED = '#888888';
|
|
9
|
+
const COLOR_BG = '#0a0a0a';
|
|
10
|
+
const COLOR_AXIS = '#333333';
|
|
11
|
+
|
|
12
|
+
// Ideal composition size: 1280x720
|
|
13
|
+
|
|
14
|
+
const Title: React.FC<{children: React.ReactNode}> = ({children}) => (
|
|
15
|
+
<div style={{textAlign: 'center', marginBottom: 40}}>
|
|
16
|
+
<div style={{color: COLOR_TEXT, fontSize: 48, fontWeight: 600}}>
|
|
17
|
+
{children}
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
const YAxis: React.FC<{steps: number[]; height: number}> = ({
|
|
23
|
+
steps,
|
|
24
|
+
height,
|
|
25
|
+
}) => (
|
|
26
|
+
<div
|
|
27
|
+
style={{
|
|
28
|
+
display: 'flex',
|
|
29
|
+
flexDirection: 'column',
|
|
30
|
+
justifyContent: 'space-between',
|
|
31
|
+
height,
|
|
32
|
+
paddingRight: 16,
|
|
33
|
+
}}
|
|
34
|
+
>
|
|
35
|
+
{steps
|
|
36
|
+
.slice()
|
|
37
|
+
.reverse()
|
|
38
|
+
.map((step) => (
|
|
39
|
+
<div
|
|
40
|
+
key={step}
|
|
41
|
+
style={{
|
|
42
|
+
color: COLOR_MUTED,
|
|
43
|
+
fontSize: 20,
|
|
44
|
+
textAlign: 'right',
|
|
45
|
+
}}
|
|
46
|
+
>
|
|
47
|
+
{step.toLocaleString()}
|
|
48
|
+
</div>
|
|
49
|
+
))}
|
|
50
|
+
</div>
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const Bar: React.FC<{
|
|
54
|
+
height: number;
|
|
55
|
+
progress: number;
|
|
56
|
+
}> = ({height, progress}) => (
|
|
57
|
+
<div
|
|
58
|
+
style={{
|
|
59
|
+
flex: 1,
|
|
60
|
+
display: 'flex',
|
|
61
|
+
flexDirection: 'column',
|
|
62
|
+
justifyContent: 'flex-end',
|
|
63
|
+
}}
|
|
64
|
+
>
|
|
65
|
+
<div
|
|
66
|
+
style={{
|
|
67
|
+
width: '100%',
|
|
68
|
+
height,
|
|
69
|
+
backgroundColor: COLOR_BAR,
|
|
70
|
+
borderRadius: '8px 8px 0 0',
|
|
71
|
+
opacity: progress,
|
|
72
|
+
}}
|
|
73
|
+
/>
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const XAxis: React.FC<{
|
|
78
|
+
children: React.ReactNode;
|
|
79
|
+
labels: string[];
|
|
80
|
+
height: number;
|
|
81
|
+
}> = ({children, labels, height}) => (
|
|
82
|
+
<div style={{flex: 1, display: 'flex', flexDirection: 'column'}}>
|
|
83
|
+
<div
|
|
84
|
+
style={{
|
|
85
|
+
display: 'flex',
|
|
86
|
+
alignItems: 'flex-end',
|
|
87
|
+
gap: 16,
|
|
88
|
+
height,
|
|
89
|
+
borderLeft: `2px solid ${COLOR_AXIS}`,
|
|
90
|
+
borderBottom: `2px solid ${COLOR_AXIS}`,
|
|
91
|
+
paddingLeft: 16,
|
|
92
|
+
}}
|
|
93
|
+
>
|
|
94
|
+
{children}
|
|
95
|
+
</div>
|
|
96
|
+
<div
|
|
97
|
+
style={{
|
|
98
|
+
display: 'flex',
|
|
99
|
+
gap: 16,
|
|
100
|
+
paddingLeft: 16,
|
|
101
|
+
marginTop: 12,
|
|
102
|
+
}}
|
|
103
|
+
>
|
|
104
|
+
{labels.map((label) => (
|
|
105
|
+
<div
|
|
106
|
+
key={label}
|
|
107
|
+
style={{
|
|
108
|
+
flex: 1,
|
|
109
|
+
textAlign: 'center',
|
|
110
|
+
color: COLOR_MUTED,
|
|
111
|
+
fontSize: 20,
|
|
112
|
+
}}
|
|
113
|
+
>
|
|
114
|
+
{label}
|
|
115
|
+
</div>
|
|
116
|
+
))}
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
export const MyAnimation = () => {
|
|
122
|
+
const frame = useCurrentFrame();
|
|
123
|
+
const {fps, height} = useVideoConfig();
|
|
124
|
+
|
|
125
|
+
const data = [
|
|
126
|
+
{month: 'Jan', price: 2039},
|
|
127
|
+
{month: 'Mar', price: 2160},
|
|
128
|
+
{month: 'May', price: 2327},
|
|
129
|
+
{month: 'Jul', price: 2426},
|
|
130
|
+
{month: 'Sep', price: 2634},
|
|
131
|
+
{month: 'Nov', price: 2672},
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
const minPrice = 2000;
|
|
135
|
+
const maxPrice = 2800;
|
|
136
|
+
const priceRange = maxPrice - minPrice;
|
|
137
|
+
const chartHeight = height - 280;
|
|
138
|
+
const yAxisSteps = [2000, 2400, 2800];
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<AbsoluteFill
|
|
142
|
+
style={{
|
|
143
|
+
backgroundColor: COLOR_BG,
|
|
144
|
+
padding: 60,
|
|
145
|
+
display: 'flex',
|
|
146
|
+
flexDirection: 'column',
|
|
147
|
+
fontFamily,
|
|
148
|
+
}}
|
|
149
|
+
>
|
|
150
|
+
<Title>Gold Price 2024</Title>
|
|
151
|
+
|
|
152
|
+
<div style={{display: 'flex', flex: 1}}>
|
|
153
|
+
<YAxis steps={yAxisSteps} height={chartHeight} />
|
|
154
|
+
<XAxis height={chartHeight} labels={data.map((d) => d.month)}>
|
|
155
|
+
{data.map((item, i) => {
|
|
156
|
+
const progress = spring({
|
|
157
|
+
frame: frame - i * 5 - 10,
|
|
158
|
+
fps,
|
|
159
|
+
config: {damping: 18, stiffness: 80},
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const barHeight =
|
|
163
|
+
((item.price - minPrice) / priceRange) * chartHeight * progress;
|
|
164
|
+
|
|
165
|
+
return (
|
|
166
|
+
<Bar key={item.month} height={barHeight} progress={progress} />
|
|
167
|
+
);
|
|
168
|
+
})}
|
|
169
|
+
</XAxis>
|
|
170
|
+
</div>
|
|
171
|
+
</AbsoluteFill>
|
|
172
|
+
);
|
|
173
|
+
};
|
|
@@ -1,100 +1,100 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AbsoluteFill,
|
|
3
|
-
interpolate,
|
|
4
|
-
useCurrentFrame,
|
|
5
|
-
useVideoConfig,
|
|
6
|
-
} from 'remotion';
|
|
7
|
-
|
|
8
|
-
const COLOR_BG = '#ffffff';
|
|
9
|
-
const COLOR_TEXT = '#000000';
|
|
10
|
-
const FULL_TEXT = 'From prompt to motion graphics. This is Remotion.';
|
|
11
|
-
const PAUSE_AFTER = 'From prompt to motion graphics.';
|
|
12
|
-
const FONT_SIZE = 72;
|
|
13
|
-
const FONT_WEIGHT = 700;
|
|
14
|
-
const CHAR_FRAMES = 2;
|
|
15
|
-
const CURSOR_BLINK_FRAMES = 16;
|
|
16
|
-
const PAUSE_SECONDS = 1;
|
|
17
|
-
|
|
18
|
-
// Ideal composition size: 1280x720
|
|
19
|
-
|
|
20
|
-
const getTypedText = ({
|
|
21
|
-
frame,
|
|
22
|
-
fullText,
|
|
23
|
-
pauseAfter,
|
|
24
|
-
charFrames,
|
|
25
|
-
pauseFrames,
|
|
26
|
-
}: {
|
|
27
|
-
frame: number;
|
|
28
|
-
fullText: string;
|
|
29
|
-
pauseAfter: string;
|
|
30
|
-
charFrames: number;
|
|
31
|
-
pauseFrames: number;
|
|
32
|
-
}): string => {
|
|
33
|
-
const pauseIndex = fullText.indexOf(pauseAfter);
|
|
34
|
-
const preLen =
|
|
35
|
-
pauseIndex >= 0 ? pauseIndex + pauseAfter.length : fullText.length;
|
|
36
|
-
|
|
37
|
-
let typedChars = 0;
|
|
38
|
-
if (frame < preLen * charFrames) {
|
|
39
|
-
typedChars = Math.floor(frame / charFrames);
|
|
40
|
-
} else if (frame < preLen * charFrames + pauseFrames) {
|
|
41
|
-
typedChars = preLen;
|
|
42
|
-
} else {
|
|
43
|
-
const postPhase = frame - preLen * charFrames - pauseFrames;
|
|
44
|
-
typedChars = Math.min(
|
|
45
|
-
fullText.length,
|
|
46
|
-
preLen + Math.floor(postPhase / charFrames),
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
return fullText.slice(0, typedChars);
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
const Cursor: React.FC<{
|
|
53
|
-
frame: number;
|
|
54
|
-
blinkFrames: number;
|
|
55
|
-
symbol?: string;
|
|
56
|
-
}> = ({frame, blinkFrames, symbol = '\u258C'}) => {
|
|
57
|
-
const opacity = interpolate(
|
|
58
|
-
frame % blinkFrames,
|
|
59
|
-
[0, blinkFrames / 2, blinkFrames],
|
|
60
|
-
[1, 0, 1],
|
|
61
|
-
{extrapolateLeft: 'clamp', extrapolateRight: 'clamp'},
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
return <span style={{opacity}}>{symbol}</span>;
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
export const MyAnimation = () => {
|
|
68
|
-
const frame = useCurrentFrame();
|
|
69
|
-
const {fps} = useVideoConfig();
|
|
70
|
-
|
|
71
|
-
const pauseFrames = Math.round(fps * PAUSE_SECONDS);
|
|
72
|
-
|
|
73
|
-
const typedText = getTypedText({
|
|
74
|
-
frame,
|
|
75
|
-
fullText: FULL_TEXT,
|
|
76
|
-
pauseAfter: PAUSE_AFTER,
|
|
77
|
-
charFrames: CHAR_FRAMES,
|
|
78
|
-
pauseFrames,
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
return (
|
|
82
|
-
<AbsoluteFill
|
|
83
|
-
style={{
|
|
84
|
-
backgroundColor: COLOR_BG,
|
|
85
|
-
}}
|
|
86
|
-
>
|
|
87
|
-
<div
|
|
88
|
-
style={{
|
|
89
|
-
color: COLOR_TEXT,
|
|
90
|
-
fontSize: FONT_SIZE,
|
|
91
|
-
fontWeight: FONT_WEIGHT,
|
|
92
|
-
fontFamily: 'sans-serif',
|
|
93
|
-
}}
|
|
94
|
-
>
|
|
95
|
-
<span>{typedText}</span>
|
|
96
|
-
<Cursor frame={frame} blinkFrames={CURSOR_BLINK_FRAMES} />
|
|
97
|
-
</div>
|
|
98
|
-
</AbsoluteFill>
|
|
99
|
-
);
|
|
100
|
-
};
|
|
1
|
+
import {
|
|
2
|
+
AbsoluteFill,
|
|
3
|
+
interpolate,
|
|
4
|
+
useCurrentFrame,
|
|
5
|
+
useVideoConfig,
|
|
6
|
+
} from 'remotion';
|
|
7
|
+
|
|
8
|
+
const COLOR_BG = '#ffffff';
|
|
9
|
+
const COLOR_TEXT = '#000000';
|
|
10
|
+
const FULL_TEXT = 'From prompt to motion graphics. This is Remotion.';
|
|
11
|
+
const PAUSE_AFTER = 'From prompt to motion graphics.';
|
|
12
|
+
const FONT_SIZE = 72;
|
|
13
|
+
const FONT_WEIGHT = 700;
|
|
14
|
+
const CHAR_FRAMES = 2;
|
|
15
|
+
const CURSOR_BLINK_FRAMES = 16;
|
|
16
|
+
const PAUSE_SECONDS = 1;
|
|
17
|
+
|
|
18
|
+
// Ideal composition size: 1280x720
|
|
19
|
+
|
|
20
|
+
const getTypedText = ({
|
|
21
|
+
frame,
|
|
22
|
+
fullText,
|
|
23
|
+
pauseAfter,
|
|
24
|
+
charFrames,
|
|
25
|
+
pauseFrames,
|
|
26
|
+
}: {
|
|
27
|
+
frame: number;
|
|
28
|
+
fullText: string;
|
|
29
|
+
pauseAfter: string;
|
|
30
|
+
charFrames: number;
|
|
31
|
+
pauseFrames: number;
|
|
32
|
+
}): string => {
|
|
33
|
+
const pauseIndex = fullText.indexOf(pauseAfter);
|
|
34
|
+
const preLen =
|
|
35
|
+
pauseIndex >= 0 ? pauseIndex + pauseAfter.length : fullText.length;
|
|
36
|
+
|
|
37
|
+
let typedChars = 0;
|
|
38
|
+
if (frame < preLen * charFrames) {
|
|
39
|
+
typedChars = Math.floor(frame / charFrames);
|
|
40
|
+
} else if (frame < preLen * charFrames + pauseFrames) {
|
|
41
|
+
typedChars = preLen;
|
|
42
|
+
} else {
|
|
43
|
+
const postPhase = frame - preLen * charFrames - pauseFrames;
|
|
44
|
+
typedChars = Math.min(
|
|
45
|
+
fullText.length,
|
|
46
|
+
preLen + Math.floor(postPhase / charFrames),
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
return fullText.slice(0, typedChars);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const Cursor: React.FC<{
|
|
53
|
+
frame: number;
|
|
54
|
+
blinkFrames: number;
|
|
55
|
+
symbol?: string;
|
|
56
|
+
}> = ({frame, blinkFrames, symbol = '\u258C'}) => {
|
|
57
|
+
const opacity = interpolate(
|
|
58
|
+
frame % blinkFrames,
|
|
59
|
+
[0, blinkFrames / 2, blinkFrames],
|
|
60
|
+
[1, 0, 1],
|
|
61
|
+
{extrapolateLeft: 'clamp', extrapolateRight: 'clamp'},
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
return <span style={{opacity}}>{symbol}</span>;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const MyAnimation = () => {
|
|
68
|
+
const frame = useCurrentFrame();
|
|
69
|
+
const {fps} = useVideoConfig();
|
|
70
|
+
|
|
71
|
+
const pauseFrames = Math.round(fps * PAUSE_SECONDS);
|
|
72
|
+
|
|
73
|
+
const typedText = getTypedText({
|
|
74
|
+
frame,
|
|
75
|
+
fullText: FULL_TEXT,
|
|
76
|
+
pauseAfter: PAUSE_AFTER,
|
|
77
|
+
charFrames: CHAR_FRAMES,
|
|
78
|
+
pauseFrames,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<AbsoluteFill
|
|
83
|
+
style={{
|
|
84
|
+
backgroundColor: COLOR_BG,
|
|
85
|
+
}}
|
|
86
|
+
>
|
|
87
|
+
<div
|
|
88
|
+
style={{
|
|
89
|
+
color: COLOR_TEXT,
|
|
90
|
+
fontSize: FONT_SIZE,
|
|
91
|
+
fontWeight: FONT_WEIGHT,
|
|
92
|
+
fontFamily: 'sans-serif',
|
|
93
|
+
}}
|
|
94
|
+
>
|
|
95
|
+
<span>{typedText}</span>
|
|
96
|
+
<Cursor frame={frame} blinkFrames={CURSOR_BLINK_FRAMES} />
|
|
97
|
+
</div>
|
|
98
|
+
</AbsoluteFill>
|
|
99
|
+
);
|
|
100
|
+
};
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: text-animations
|
|
3
|
-
description: Typography and text animation patterns for Remotion.
|
|
4
|
-
metadata:
|
|
5
|
-
tags: typography, text, typewriter, highlighter ken
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## Text animations
|
|
9
|
-
|
|
10
|
-
Based on `useCurrentFrame()`, reduce the string character by character to create a typewriter effect.
|
|
11
|
-
|
|
12
|
-
## Typewriter Effect
|
|
13
|
-
|
|
14
|
-
See [Typewriter](assets/text-animations-typewriter.tsx) for an advanced example with a blinking cursor and a pause after the first sentence.
|
|
15
|
-
|
|
16
|
-
Always use string slicing for typewriter effects. Never use per-character opacity.
|
|
17
|
-
|
|
18
|
-
## Word Highlighting
|
|
19
|
-
|
|
20
|
-
See [Word Highlight](assets/text-animations-word-highlight.tsx) for an example for how a word highlight is animated, like with a highlighter pen.
|
|
1
|
+
---
|
|
2
|
+
name: text-animations
|
|
3
|
+
description: Typography and text animation patterns for Remotion.
|
|
4
|
+
metadata:
|
|
5
|
+
tags: typography, text, typewriter, highlighter ken
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Text animations
|
|
9
|
+
|
|
10
|
+
Based on `useCurrentFrame()`, reduce the string character by character to create a typewriter effect.
|
|
11
|
+
|
|
12
|
+
## Typewriter Effect
|
|
13
|
+
|
|
14
|
+
See [Typewriter](assets/text-animations-typewriter.tsx) for an advanced example with a blinking cursor and a pause after the first sentence.
|
|
15
|
+
|
|
16
|
+
Always use string slicing for typewriter effects. Never use per-character opacity.
|
|
17
|
+
|
|
18
|
+
## Word Highlighting
|
|
19
|
+
|
|
20
|
+
See [Word Highlight](assets/text-animations-word-highlight.tsx) for an example for how a word highlight is animated, like with a highlighter pen.
|