@gthanks/moviespec 0.1.0 → 0.1.2
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/README.md +2 -0
- package/bin/moviespec.js +93 -2
- package/package.json +1 -1
- package/schema/moviespec.schema.yaml +1 -0
- package/templates/aesthetics/directors//346/200/252/350/257/236/345/257/271/347/247/260/351/243/216.md +26 -0
- package/templates/aesthetics/directors//350/203/241/351/207/221/351/223/250/351/243/216.md +26 -0
- package/templates/aesthetics/genres//351/273/221/347/231/275/344/276/246/346/216/242/351/243/216.md +26 -0
- package/templates/aesthetics/movies//351/273/221/345/256/242/345/270/235/345/233/275/351/243/216.md +26 -0
package/README.md
CHANGED
|
@@ -38,6 +38,8 @@ CLI 将按 `schema/moviespec.schema.yaml` 的默认路径读取与写入上述
|
|
|
38
38
|
|
|
39
39
|
- `moviespec init`
|
|
40
40
|
- `moviespec list types`
|
|
41
|
+
- `moviespec list-aesthetics` (查看有哪些内置的经典电影美学)
|
|
42
|
+
- `moviespec apply <name>` (将内置美学套用到当前项目的视觉风格中)
|
|
41
43
|
- `moviespec new <type> <name>`
|
|
42
44
|
- `moviespec compile-prompts --shots <file>`
|
|
43
45
|
- `moviespec validate` / `moviespec check`
|
package/bin/moviespec.js
CHANGED
|
@@ -138,7 +138,7 @@ async function cmdInit(projectRoot) {
|
|
|
138
138
|
if (selectedAgents.length > 0) {
|
|
139
139
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
140
140
|
const templatesDir = path.resolve(here, '..', 'templates', 'agents');
|
|
141
|
-
|
|
141
|
+
|
|
142
142
|
const agentFiles = {
|
|
143
143
|
cursor: '.cursorrules',
|
|
144
144
|
windsurf: '.windsurfrules',
|
|
@@ -148,7 +148,7 @@ async function cmdInit(projectRoot) {
|
|
|
148
148
|
for (const agent of selectedAgents) {
|
|
149
149
|
const sourceFile = path.join(templatesDir, `${agent}.md`);
|
|
150
150
|
const targetFile = path.join(root, agentFiles[agent]);
|
|
151
|
-
|
|
151
|
+
|
|
152
152
|
if (await pathExists(sourceFile)) {
|
|
153
153
|
const content = await fs.readFile(sourceFile, 'utf8');
|
|
154
154
|
await fs.writeFile(targetFile, content, 'utf8');
|
|
@@ -175,6 +175,81 @@ async function cmdListTypes() {
|
|
|
175
175
|
}
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
+
async function cmdListAesthetics() {
|
|
179
|
+
const schema = await loadMovieSpecSchema();
|
|
180
|
+
const aestheticsDirRel = schema.project?.aestheticsDir ?? 'templates/aesthetics';
|
|
181
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
182
|
+
const aestheticsDirAbs = path.resolve(here, '..', aestheticsDirRel);
|
|
183
|
+
|
|
184
|
+
if (!(await pathExists(aestheticsDirAbs))) {
|
|
185
|
+
console.log(chalk.yellow('No aesthetics library found.'));
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const files = await fg(['**/*.md', '**/*.yaml'], { cwd: aestheticsDirAbs, onlyFiles: true });
|
|
190
|
+
if (files.length === 0) {
|
|
191
|
+
console.log(chalk.yellow('Aesthetics library is empty.'));
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
console.log(chalk.cyan('Available Cinematic Aesthetics:'));
|
|
196
|
+
|
|
197
|
+
const categories = {};
|
|
198
|
+
for (const f of files) {
|
|
199
|
+
const parts = f.split('/');
|
|
200
|
+
const category = parts.length > 1 ? parts[0] : 'uncategorized';
|
|
201
|
+
const name = path.parse(f).name;
|
|
202
|
+
|
|
203
|
+
if (!categories[category]) categories[category] = [];
|
|
204
|
+
categories[category].push(name);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
for (const [category, names] of Object.entries(categories)) {
|
|
208
|
+
console.log(`\n [${chalk.yellow(category)}]`);
|
|
209
|
+
for (const name of names) {
|
|
210
|
+
console.log(` - ${chalk.green(name)}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
async function cmdApplyAesthetic(aestheticName, { projectRoot }) {
|
|
216
|
+
const schema = await loadMovieSpecSchema();
|
|
217
|
+
const root = resolveProjectRoot(projectRoot);
|
|
218
|
+
|
|
219
|
+
const aestheticsDirRel = schema.project?.aestheticsDir ?? 'templates/aesthetics';
|
|
220
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
221
|
+
const aestheticsDirAbs = path.resolve(here, '..', aestheticsDirRel);
|
|
222
|
+
|
|
223
|
+
// Search recursively for the aesthetic name
|
|
224
|
+
const files = await fg([`**/${aestheticName}.md`, `**/${aestheticName}.yaml`], { cwd: aestheticsDirAbs, onlyFiles: true });
|
|
225
|
+
|
|
226
|
+
if (files.length === 0) {
|
|
227
|
+
throw new Error(`Aesthetic template '${aestheticName}' not found in library.`);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (files.length > 1) {
|
|
231
|
+
console.log(chalk.yellow(`Warning: Multiple aesthetic templates found named '${aestheticName}'. Using the first one: ${files[0]}`));
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const sourceTemplate = path.join(aestheticsDirAbs, files[0]);
|
|
235
|
+
|
|
236
|
+
const targetRel = defaultTypePath(schema, 'visual_style');
|
|
237
|
+
const targetDir = path.join(root, targetRel);
|
|
238
|
+
await ensureDir(targetDir);
|
|
239
|
+
|
|
240
|
+
const ext = path.extname(sourceTemplate);
|
|
241
|
+
const targetPath = path.join(targetDir, `${aestheticName}${ext}`);
|
|
242
|
+
|
|
243
|
+
if (await pathExists(targetPath)) {
|
|
244
|
+
throw new Error(`File already exists: ${targetPath}`);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const content = await fs.readFile(sourceTemplate, 'utf8');
|
|
248
|
+
await fs.writeFile(targetPath, content, 'utf8');
|
|
249
|
+
|
|
250
|
+
console.log(chalk.green(`Applied cinematic aesthetic '${aestheticName}' to: ${toPosix(path.relative(root, targetPath))}`));
|
|
251
|
+
}
|
|
252
|
+
|
|
178
253
|
async function cmdNew(typeId, name, { projectRoot }) {
|
|
179
254
|
const schema = await loadMovieSpecSchema();
|
|
180
255
|
const root = resolveProjectRoot(projectRoot);
|
|
@@ -468,6 +543,22 @@ program
|
|
|
468
543
|
await cmdListTypes();
|
|
469
544
|
});
|
|
470
545
|
|
|
546
|
+
program
|
|
547
|
+
.command('list-aesthetics')
|
|
548
|
+
.description('List available cinematic aesthetics templates')
|
|
549
|
+
.action(async () => {
|
|
550
|
+
await cmdListAesthetics();
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
program
|
|
554
|
+
.command('apply')
|
|
555
|
+
.description('Apply a cinematic aesthetic template to your project')
|
|
556
|
+
.argument('<aesthetic_name>', 'Name of the aesthetic template')
|
|
557
|
+
.option('-C, --project-root <path>', 'Project root (default: cwd)')
|
|
558
|
+
.action(async (name, opts) => {
|
|
559
|
+
await cmdApplyAesthetic(name, { projectRoot: opts.projectRoot });
|
|
560
|
+
});
|
|
561
|
+
|
|
471
562
|
program
|
|
472
563
|
.command('new')
|
|
473
564
|
.argument('<type>', 'Type id')
|
package/package.json
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: visual_style
|
|
3
|
+
name: "怪诞对称风"
|
|
4
|
+
style: "怪诞对称风 (Quirky Symmetrical)"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 视觉风格:韦斯·安德森美学 (Wes Anderson Aesthetic)
|
|
8
|
+
|
|
9
|
+
## 色彩方案 (Color Grading)
|
|
10
|
+
- **Tint (色调)**: 马卡龙粉色,芥末黄,婴儿蓝。
|
|
11
|
+
- **Shadows (阴影)**: 提亮阴影,极低的对比度。
|
|
12
|
+
- **Saturation (饱和度)**: 均匀饱和的马卡龙粉彩质感。
|
|
13
|
+
|
|
14
|
+
## 灯光设计 (Lighting)
|
|
15
|
+
- **Style (风格)**: 平光源打光 (Flat lighting),几乎没有方向性的阴影。
|
|
16
|
+
- **Atmosphere (氛围)**: 怪诞,戏剧舞台感,极其静止。
|
|
17
|
+
- **Modifiers (修饰)**: 柔和、漫反射的顶光源。
|
|
18
|
+
|
|
19
|
+
## 镜头语言与材质 (Cinematography & Texture)
|
|
20
|
+
- **Lens (镜头)**: 超广角镜头(如18mm或24mm),极小的景深模糊(要求背景和前景全部清晰在焦内)。
|
|
21
|
+
- **Composition (构图)**: 严格的屏幕中心对称构图,扁平化的舞台场面调度 (Planimetric staging)。
|
|
22
|
+
- **Texture (材质)**: 复古胶片摄影质感,所有道具必须看起来是精心摆放过的。
|
|
23
|
+
|
|
24
|
+
## AI 专属 Prompt 增强
|
|
25
|
+
- **Positive Suffix (正面词缀)**: `Wes Anderson style, perfect symmetry, pastel colors, flat lighting, whimsical, meticulously arranged, wide angle, center focus, cinematic still, highly detailed`
|
|
26
|
+
- **Negative Prefix (负面词缀)**: `asymmetrical, high contrast, dark shadows, moody, messy, chaotic, shallow depth of field, dutch angle`
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: visual_style
|
|
3
|
+
name: "胡金铨风"
|
|
4
|
+
style: "King Hu Zen Wuxia"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 视觉风格:胡金铨导演美学 (King Hu Aesthetic)
|
|
8
|
+
|
|
9
|
+
## 色彩方案 (Color Grading)
|
|
10
|
+
- **Tint (色调)**: 褪色的自然复古色调,冷峻的石青与暗红。
|
|
11
|
+
- **Shadows (阴影)**: 强烈的明暗对比,人物常常从极暗的背景中显现。
|
|
12
|
+
- **Saturation (饱和度)**: 整体偏低,局部色彩(如鲜血或特定服饰)克制性点缀。
|
|
13
|
+
|
|
14
|
+
## 灯光设计 (Lighting)
|
|
15
|
+
- **Style (风格)**: 戏剧化的自然高光,轮廓边缘光。
|
|
16
|
+
- **Atmosphere (氛围)**: 肃杀,禅宗意境,充满神秘与张力。
|
|
17
|
+
- **Modifiers (修饰)**: 浓重的迷雾 (Thick mist),斜射的日光,大量利用自然环境(如芦苇荡、竹林)带来的斑驳光影。
|
|
18
|
+
|
|
19
|
+
## 镜头语言与材质 (Cinematography & Texture)
|
|
20
|
+
- **Lens (镜头)**: 中长焦镜头压缩空间,制造群雄压境的局促感。
|
|
21
|
+
- **Composition (构图)**: 极具京剧舞台感的调度,人物在画面边缘突然跃入。强调“气”与“动势”。
|
|
22
|
+
- **Editing Hint (剪辑提示)**: (此风格特有)如果生成序列,多使用极短的碎剪 (Rapid montage) 表现战斗。
|
|
23
|
+
|
|
24
|
+
## AI 专属 Prompt 增强
|
|
25
|
+
- **Positive Suffix (正面词缀)**: `King Hu film style, A Touch of Zen, vintage 1970s Hong Kong cinema aesthetics, thick mist, bamboo forest combat, dramatic natural lighting, somber mood, Beijing opera staging, cinematic still, masterpiece`
|
|
26
|
+
- **Negative Prefix (负面词缀)**: `wuxia fantasy magic, glowing auras, saturated colors, modern digital look, 3D render, cartoon, bright sunlight`
|
package/templates/aesthetics/genres//351/273/221/347/231/275/344/276/246/346/216/242/351/243/216.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: visual_style
|
|
3
|
+
name: "黑白侦探风"
|
|
4
|
+
style: "黑白侦探风 (Black & White Detective)"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 视觉风格:黑色电影美学 (Film Noir Aesthetic)
|
|
8
|
+
|
|
9
|
+
## 色彩方案 (Color Grading)
|
|
10
|
+
- **Tint (色调)**: 纯正的黑白单色 (Monochrome)。
|
|
11
|
+
- **Shadows (阴影)**: 极致压暗的死黑,极高的画面对比度。
|
|
12
|
+
- **Saturation (饱和度)**: 0% (完全剥离色彩)。
|
|
13
|
+
|
|
14
|
+
## 灯光设计 (Lighting)
|
|
15
|
+
- **Style (风格)**: 低调打光 (Low-key lighting),强烈的明暗对照法 (Chiaroscuro)。
|
|
16
|
+
- **Atmosphere (氛围)**: 情绪化,充满悬疑,充满危险感。
|
|
17
|
+
- **Modifiers (修饰)**: 极其生硬刺眼的阴影,百叶窗的条纹阴影切过人物面部,剪影打光法。
|
|
18
|
+
|
|
19
|
+
## 镜头语言与材质 (Cinematography & Texture)
|
|
20
|
+
- **Lens (镜头)**: 35mm 镜头。采用大景深 (Deep focus)。经常使用荷兰角 (倾斜构图) 来表现人物内心的不安感。
|
|
21
|
+
- **Atmosphere (环境)**: 雨水打湿反光的街道,缭绕的香烟烟雾,浓雾。
|
|
22
|
+
- **Texture (材质)**: 极重的1940年代赛璐珞胶卷颗粒感,高边缘对比度。
|
|
23
|
+
|
|
24
|
+
## AI 专属 Prompt 增强
|
|
25
|
+
- **Positive Suffix (正面词缀)**: `film noir style, 1940s black and white cinema, extreme high contrast, harsh shadows, chiaroscuro lighting, moody, mystery, rain-slicked streets, cigarette smoke, heavy film grain, cinematic masterpiece`
|
|
26
|
+
- **Negative Prefix (负面词缀)**: `color, vibrant, cheerful, flat lighting, sunny, modern, daytime, low contrast, washed out`
|
package/templates/aesthetics/movies//351/273/221/345/256/242/345/270/235/345/233/275/351/243/216.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: visual_style
|
|
3
|
+
name: "黑客帝国风"
|
|
4
|
+
style: "赛博朋克动作风 (Cyberpunk Action)"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 视觉风格:黑客帝国美学 (The Matrix Aesthetic)
|
|
8
|
+
|
|
9
|
+
## 色彩方案 (Color Grading)
|
|
10
|
+
- **Tint (色调)**: `#00FF41` (经典的矩阵绿)。
|
|
11
|
+
- **Shadows (阴影)**: 极深的黑色,极高对比度。
|
|
12
|
+
- **Saturation (饱和度)**: 肤色饱和度极低,绿色/青色的中间调饱和度极高。
|
|
13
|
+
|
|
14
|
+
## 灯光设计 (Lighting)
|
|
15
|
+
- **Style (风格)**: 类似办公室荧光灯的顶光 (Top-down fluorescent),明暗对照 (Chiaroscuro)。
|
|
16
|
+
- **Atmosphere (氛围)**: 冰冷,不自然,机械感。
|
|
17
|
+
- **Modifiers (修饰)**: 画面带有雾霾感 (Haze),使用边缘光 (Rim lighting) 将人物从黑暗背景中分离出来。
|
|
18
|
+
|
|
19
|
+
## 镜头语言与材质 (Cinematography & Texture)
|
|
20
|
+
- **Lens (镜头)**: 35mm 到 50mm,带有些微的广角畸变以体现不真实感。
|
|
21
|
+
- **Shutter Speed (快门)**: 极快的快门速度,确保动作戏极其锐利清晰。
|
|
22
|
+
- **Texture (材质)**: 90年代胶片颗粒感,锐利的边缘,光滑反光的乳胶和皮革材质。
|
|
23
|
+
|
|
24
|
+
## AI 专属 Prompt 增强
|
|
25
|
+
- **Positive Suffix (正面词缀)**: `cinematic style, Matrix green color grading, cyberpunk atmosphere, high contrast, 90s action movie texture, masterpiece, 8k resolution, photorealistic`
|
|
26
|
+
- **Negative Prefix (负面词缀)**: `warm colors, sunny, vibrant, cheerful, soft lighting, pastel, cartoon, low quality`
|