kingkont 0.7.39 → 0.7.40
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/assets/PROJECT_CLAUDE.md +31 -132
- package/bin/kingkont.js +59 -49
- package/index.html +9 -10137
- package/lib/cli.js +504 -0
- package/lib/projectFs.js +391 -0
- package/lib/providers.js +689 -0
- package/lib/settings.js +70 -0
- package/main.js +22 -0
- package/package.json +5 -1
- package/preload.js +7 -0
- package/renderer/board.js +1522 -0
- package/renderer/generate.js +1727 -0
- package/renderer/media.js +1413 -0
- package/renderer/settings.js +1128 -0
- package/renderer/state.js +566 -0
- package/renderer/styles.css +1018 -0
- package/renderer/timeline.js +2836 -0
- package/server.js +103 -787
- package/settings.html +46 -0
- package/skill/SKILL.md +160 -78
package/assets/PROJECT_CLAUDE.md
CHANGED
|
@@ -1,149 +1,48 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Это проект KingKont
|
|
2
2
|
|
|
3
|
-
Эта папка —
|
|
4
|
-
|
|
5
|
-
любой инструмент (включая Claude Code) может читать/изменять напрямую.
|
|
3
|
+
Эта папка — проект редактора **KingKont · Chatium** (нод-редактор сцен фильма
|
|
4
|
+
с AI-генерацией картинок/видео/голоса/SFX/музыки/текста).
|
|
6
5
|
|
|
7
|
-
##
|
|
6
|
+
## Для Claude
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
│ └── <имя>/ ← одна доска на персонажа
|
|
14
|
-
├── _locations/ ← локации
|
|
15
|
-
│ └── <имя>/ ← одна доска на локацию
|
|
16
|
-
├── <имя сцены>/ ← сцены лежат прямо в корне как папки
|
|
17
|
-
│ └── … ← (любое имя кроме начинающихся с `_` и `.`)
|
|
18
|
-
├── _deleted/ ← корзина: удалённые файлы попадают сюда
|
|
19
|
-
│ (восстанавливаются через Cmd+Z в редакторе)
|
|
20
|
-
└── (любые другие файлы) ← редактор их не трогает
|
|
21
|
-
```
|
|
8
|
+
**Используй скилл `kingkont`.** Он знает формат `scene.json`, расположение
|
|
9
|
+
досок (`_characters/`, `_locations/`, `<сцена>/`) и умеет управлять нодами +
|
|
10
|
+
запускать генерации через CLI без открытия UI приложения. API-ключи скилл
|
|
11
|
+
берёт автоматически из настроек установленного приложения KingKont.
|
|
22
12
|
|
|
23
|
-
|
|
13
|
+
### Установка скилла
|
|
24
14
|
|
|
25
|
-
|
|
26
|
-
имеет одинаковую структуру:
|
|
15
|
+
Если приложение `kingkont` ещё не установлено:
|
|
27
16
|
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
├── scene.json ← вся метаинформация (см. ниже)
|
|
31
|
-
├── clips/ ← видео-файлы (mp4, mov, webm…)
|
|
32
|
-
├── images/ ← картинки (jpg, png, webp…)
|
|
33
|
-
├── audio/ ← аудио (mp3, wav, m4a…)
|
|
34
|
-
└── texts/ ← .md-файлы текстовых нод
|
|
17
|
+
```bash
|
|
18
|
+
npm i -g kingkont
|
|
35
19
|
```
|
|
36
20
|
|
|
37
|
-
|
|
21
|
+
Установить скилл (положит `~/.claude/skills/kingkont/SKILL.md`):
|
|
38
22
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
```json
|
|
43
|
-
{
|
|
44
|
-
"nodes": [
|
|
45
|
-
{
|
|
46
|
-
"id": "uuid-here",
|
|
47
|
-
"type": "image" | "video" | "audio" | "text",
|
|
48
|
-
"name": "опциональное имя для @-ссылок",
|
|
49
|
-
"file": "images/foo.jpg", // относительный путь в папке доски
|
|
50
|
-
"x": 100, "y": 200, // позиция на холсте (логические px)
|
|
51
|
-
"width": 280, "height": 320, // опц., если юзер ресайзил ноду
|
|
52
|
-
"generated": { // опц., если нода создана генерацией
|
|
53
|
-
"kind": "image" | "video" | "audio" | "text",
|
|
54
|
-
"prompt": "финальный промпт после resolve mentions",
|
|
55
|
-
"rawPrompt": "исходный промпт с [@ref]",
|
|
56
|
-
"model": "nano-banana-2" | "bytedance/seedance-2" | "eleven_v3" | "anthropic/claude-sonnet-4" | …,
|
|
57
|
-
"modelKey": "ключ модели для KIE",
|
|
58
|
-
"voiceId": "...", // для audio
|
|
59
|
-
"tones": ["шепот", …], // для audio
|
|
60
|
-
"refs": [{name, type, file}],
|
|
61
|
-
"state": "submitting" | "queued" | "generating" | "success" | "error",
|
|
62
|
-
"taskId": "..."
|
|
63
|
-
},
|
|
64
|
-
"status": "generating" | "draft" | "error" | undefined,
|
|
65
|
-
"error": "текст ошибки если status=error",
|
|
66
|
-
"history": [...], // history правок (через ⇄ Заменить)
|
|
67
|
-
"historyIndex": 0
|
|
68
|
-
}
|
|
69
|
-
// ... text-нода: поле "text" в JSON НЕ хранится; контент лежит в texts/<file>.md
|
|
70
|
-
],
|
|
71
|
-
"connections": [
|
|
72
|
-
{ "from": "node-id", "to": "node-id" }
|
|
73
|
-
],
|
|
74
|
-
"view": { "scrollLeft": 0, "scrollTop": 0, "zoom": 1.0 },
|
|
75
|
-
"character": { // только для досок-персонажей
|
|
76
|
-
"characterSheet": "images/sheet.jpg",
|
|
77
|
-
"voice": "elevenlabs-voice-id",
|
|
78
|
-
"tone": "по умолчанию",
|
|
79
|
-
"commonTones": ["шепот", "крик", …],
|
|
80
|
-
"lastTones": [],
|
|
81
|
-
"replicas": [...]
|
|
82
|
-
},
|
|
83
|
-
"location": { // только для досок-локаций
|
|
84
|
-
"sheet": "images/sheet.jpg"
|
|
85
|
-
},
|
|
86
|
-
"timeline": { // монтажный лист сцены
|
|
87
|
-
"tracks": [
|
|
88
|
-
{
|
|
89
|
-
"id": "tv", "name": "Видео", "kind": "video" | "audio",
|
|
90
|
-
"clips": [
|
|
91
|
-
{
|
|
92
|
-
"id": "uuid",
|
|
93
|
-
"nodeId": "node-id или null", // привязка к ноде на холсте
|
|
94
|
-
"type": "video" | "image" | "audio",
|
|
95
|
-
"file": "clips/foo.mp4",
|
|
96
|
-
"name": "Foo",
|
|
97
|
-
"duration": 5.0, // в секундах
|
|
98
|
-
"start": 0, // позиция начала на дорожке
|
|
99
|
-
"trimStart": 0, // обрезка спереди
|
|
100
|
-
"sourceDuration": 5.0, // полная длительность файла
|
|
101
|
-
"_durationLoaded": true,
|
|
102
|
-
"groupId": "...", // опц., группа клипов
|
|
103
|
-
"disabled": false // skip при playback
|
|
104
|
-
}
|
|
105
|
-
]
|
|
106
|
-
}
|
|
107
|
-
],
|
|
108
|
-
"playhead": 0.27
|
|
109
|
-
},
|
|
110
|
-
"history": { // undo/redo (Cmd+Z / Cmd+Shift+Z)
|
|
111
|
-
"past": [{ "ts": 1234567890, "label": "…", "snap": "JSON-string", "movedFiles": [...] }],
|
|
112
|
-
"future": [...]
|
|
113
|
-
}
|
|
114
|
-
}
|
|
23
|
+
```bash
|
|
24
|
+
kingkont install-skill
|
|
115
25
|
```
|
|
116
26
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
Текст ноды хранится не в `scene.json`, а в `texts/<имя>.md`. Поле `node.file`
|
|
120
|
-
указывает путь, поле `node.text` в JSON отсутствует (грузится при загрузке
|
|
121
|
-
доски). Это удобно для редактирования: можно править .md руками, и редактор
|
|
122
|
-
подхватит изменения при следующем открытии.
|
|
27
|
+
После `/reload` в Claude Code скилл `kingkont` станет доступен.
|
|
123
28
|
|
|
124
|
-
|
|
29
|
+
### Если скилл недоступен
|
|
125
30
|
|
|
126
|
-
|
|
127
|
-
Cmd+Z восстанавливает обратно (movedFiles в history).
|
|
128
|
-
- **Замена/перегенерация**: новый файл записывается в соответствующую
|
|
129
|
-
подпапку, старый сохраняется в `node.history[]` для отката.
|
|
130
|
-
- **Импорт через drag-drop**: файлы копируются в правильную подпапку
|
|
131
|
-
(clips/images/audio) с уникальным именем.
|
|
31
|
+
Краткая шпаргалка (полный API — в `kingkont --help` и в самом скилле):
|
|
132
32
|
|
|
133
|
-
|
|
33
|
+
```bash
|
|
34
|
+
kingkont open <project> # JSON со структурой проекта
|
|
35
|
+
kingkont board <project> <board> # одна доска (--json)
|
|
36
|
+
kingkont add-node <project> <board> --kind=image|video|audio|text [--name=...]
|
|
37
|
+
kingkont gen <project> <board> --kind=... --prompt="..." [--model=...] [--refs=@a,@b]
|
|
38
|
+
kingkont connect <project> <board> <fromId> <toId>
|
|
39
|
+
kingkont rm-node <project> <board> <nodeId>
|
|
40
|
+
```
|
|
134
41
|
|
|
135
|
-
|
|
136
|
-
history. Меняй name, prompt, x/y свободно.
|
|
137
|
-
- `history.past`/`future` — снимки всей сцены. Лучше не редактировать, иначе
|
|
138
|
-
Cmd+Z восстановит мусор.
|
|
42
|
+
Где `<board>` — это `Scene1`, `_characters/Anna` или `_locations/Office`.
|
|
139
43
|
|
|
140
|
-
|
|
44
|
+
---
|
|
141
45
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
3. Если меняешь `scene.json` — сохраняй валидный JSON и не трогай поля
|
|
146
|
-
которые не понимаешь (особенно `history`).
|
|
147
|
-
4. Бинарные ресурсы (клипы/картинки/аудио) лежат в подпапках по типу.
|
|
148
|
-
Импорт через drag-drop в редакторе автоматически кладёт в правильное
|
|
149
|
-
место и регистрирует ноду на холсте.
|
|
46
|
+
*Этот файл создан KingKont автоматически и обновляется при каждом открытии
|
|
47
|
+
проекта. Безопасно удалить — приложение положит его обратно. Если хочешь
|
|
48
|
+
свою документацию — переименуй файл (например в `NOTES.md`).*
|
package/bin/kingkont.js
CHANGED
|
@@ -1,26 +1,59 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// CLI launcher для KingKont.
|
|
3
|
-
//
|
|
2
|
+
// CLI launcher для KingKont.
|
|
3
|
+
// `kingkont` — запустить Electron-приложение
|
|
4
|
+
// `kingkont serve` — поднять только HTTP-сервер для Chrome
|
|
5
|
+
// `kingkont install-skill`— положить SKILL.md для Claude Code
|
|
6
|
+
// `kingkont <node-cmd>` — управление нодами проекта без UI
|
|
7
|
+
// (open / list / board / add-node / gen / generate /
|
|
8
|
+
// status / connect / rm-node / voices / balance / upload)
|
|
9
|
+
//
|
|
10
|
+
// Полный help: `kingkont --help`.
|
|
11
|
+
// Подробная документация по нод-командам — в SKILL.md.
|
|
12
|
+
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
4
15
|
const path = require('node:path');
|
|
5
16
|
const { spawn } = require('node:child_process');
|
|
6
17
|
|
|
7
18
|
const root = path.resolve(__dirname, '..');
|
|
8
19
|
const args = process.argv.slice(2);
|
|
9
20
|
|
|
21
|
+
const settingsLib = require(path.join(root, 'lib', 'settings.js'));
|
|
22
|
+
|
|
10
23
|
function showHelp() {
|
|
11
24
|
console.log(`
|
|
12
25
|
KingKont · Chatium — видео-редактор сериала
|
|
13
26
|
|
|
14
|
-
|
|
15
|
-
npx kingkont
|
|
16
|
-
npx kingkont serve
|
|
17
|
-
npx kingkont serve <path>
|
|
18
|
-
npx kingkont install-skill
|
|
27
|
+
Запуск редактора:
|
|
28
|
+
npx kingkont запустить Electron-приложение (рекомендуется)
|
|
29
|
+
npx kingkont serve запустить HTTP-сервер; URL для Chrome
|
|
30
|
+
npx kingkont serve <path> то же, путь к проекту/cwd по умолчанию
|
|
31
|
+
npx kingkont install-skill установить Skill для Claude Code
|
|
32
|
+
|
|
33
|
+
Управление нодами без UI (правит scene.json напрямую):
|
|
34
|
+
kingkont open <project> структура проекта (JSON с --json)
|
|
35
|
+
kingkont list <project> список досок
|
|
36
|
+
kingkont board <project> <board> одна доска (--json для машины)
|
|
37
|
+
kingkont add-node <project> <board> --kind=image|video|audio|text [--name=...]
|
|
38
|
+
kingkont gen <project> <board> --kind=... --prompt="..." [--model=...] [--refs=@a,@b]
|
|
39
|
+
kingkont generate <project> <board> <nodeId> перезапустить draft-ноду
|
|
40
|
+
kingkont status <project> <board> <nodeId> прогресс in-flight задачи
|
|
41
|
+
kingkont connect <project> <board> <fromId> <toId>
|
|
42
|
+
kingkont rm-node <project> <board> <nodeId>
|
|
43
|
+
|
|
44
|
+
Утилиты:
|
|
45
|
+
kingkont voices список голосов ElevenLabs (нужен ключ)
|
|
46
|
+
kingkont balance балансы всех включённых провайдеров
|
|
47
|
+
kingkont upload <file> загрузить файл в storage, печатает URL
|
|
19
48
|
|
|
20
49
|
Опции:
|
|
21
|
-
--port <N>
|
|
22
|
-
--
|
|
23
|
-
--
|
|
50
|
+
--port <N> порт HTTP-сервера (по умолчанию 17893)
|
|
51
|
+
--json машино-читаемый вывод (для cli/Claude)
|
|
52
|
+
--project install-skill: положить в .claude/skills/ текущей папки
|
|
53
|
+
--help, -h эта справка
|
|
54
|
+
|
|
55
|
+
Где CLI берёт API-ключи: ~/Library/Application Support/KingKont/settings.json
|
|
56
|
+
(те же ключи, что подключены через UI приложения).
|
|
24
57
|
`);
|
|
25
58
|
}
|
|
26
59
|
|
|
@@ -51,21 +84,27 @@ if (args.includes('--help') || args.includes('-h')) {
|
|
|
51
84
|
const portIdx = args.indexOf('--port');
|
|
52
85
|
const port = portIdx >= 0 ? parseInt(args[portIdx + 1], 10) : 17893;
|
|
53
86
|
|
|
54
|
-
|
|
87
|
+
// Подгружаем ключи из settings.json в env (для всех режимов).
|
|
88
|
+
settingsLib.applySettingsToEnv(settingsLib.loadSettings());
|
|
89
|
+
|
|
90
|
+
const cmd = args[0];
|
|
91
|
+
|
|
92
|
+
if (cmd === 'install-skill') {
|
|
55
93
|
installSkill();
|
|
56
94
|
process.exit(0);
|
|
57
95
|
}
|
|
58
96
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
97
|
+
// Нод-команды — делегируем в lib/cli.
|
|
98
|
+
const NODE_COMMANDS = require(path.join(root, 'lib', 'cli.js')).COMMANDS;
|
|
99
|
+
if (cmd && NODE_COMMANDS[cmd]) {
|
|
100
|
+
const cliLib = require(path.join(root, 'lib', 'cli.js'));
|
|
101
|
+
cliLib.run(args).then(
|
|
102
|
+
() => process.exit(0),
|
|
103
|
+
err => { console.error('Ошибка:', err.message); process.exit(1); }
|
|
104
|
+
);
|
|
105
|
+
} else if (cmd === 'serve') {
|
|
62
106
|
process.env.PORT = String(port);
|
|
63
|
-
// Если задан путь — на старте просто печатаем подсказку, открыть его
|
|
64
|
-
// через FSAH юзер должен руками (нельзя без gesture).
|
|
65
107
|
const targetPath = args[1] && !args[1].startsWith('--') ? path.resolve(args[1]) : null;
|
|
66
|
-
// Подгружаем сервер. Если ключи не в env — попробуем взять из userData
|
|
67
|
-
// (так же как делает main.js).
|
|
68
|
-
applySettingsToEnv();
|
|
69
108
|
const { start } = require(path.join(root, 'server.js'));
|
|
70
109
|
start(port).then(actualPort => {
|
|
71
110
|
const url = `http://localhost:${actualPort}/`;
|
|
@@ -77,13 +116,7 @@ if (args[0] === 'serve') {
|
|
|
77
116
|
process.exit(1);
|
|
78
117
|
});
|
|
79
118
|
} else {
|
|
80
|
-
// Electron
|
|
81
|
-
applySettingsToEnv();
|
|
82
|
-
// Self-heal: если postinstall не отработал (npm 9+ иногда тихо пропускает
|
|
83
|
-
// scripts при глобал-install под некоторыми node-prefix'ами), Electron.app
|
|
84
|
-
// в node_modules останется не переименованным → в menubar macOS «Electron»
|
|
85
|
-
// вместо «KingKont». Запустим патч-скрипт прямо сейчас, idempotent — если
|
|
86
|
-
// уже переименовано, выйдет no-op. Ошибку проглатываем — это cosmetic.
|
|
119
|
+
// Electron-приложение (default).
|
|
87
120
|
if (process.platform === 'darwin') {
|
|
88
121
|
try {
|
|
89
122
|
const patch = require(path.join(root, 'scripts', 'patch-electron-name.js'));
|
|
@@ -92,7 +125,6 @@ if (args[0] === 'serve') {
|
|
|
92
125
|
}
|
|
93
126
|
const electronPath = (() => {
|
|
94
127
|
try {
|
|
95
|
-
// Сбрасываем кэш — postinstall мог только что переписать path.txt.
|
|
96
128
|
delete require.cache[require.resolve('electron')];
|
|
97
129
|
return require('electron');
|
|
98
130
|
}
|
|
@@ -105,25 +137,3 @@ if (args[0] === 'serve') {
|
|
|
105
137
|
const proc = spawn(electronPath, [root], { stdio: 'inherit', env: process.env });
|
|
106
138
|
proc.on('exit', code => process.exit(code || 0));
|
|
107
139
|
}
|
|
108
|
-
|
|
109
|
-
// Прокидываем сохранённые ключи из userData/settings.json в process.env,
|
|
110
|
-
// чтобы server.js (handleGenerate/Tts/Sfx/Music/Text) их подхватил.
|
|
111
|
-
function applySettingsToEnv() {
|
|
112
|
-
try {
|
|
113
|
-
const fs = require('node:fs');
|
|
114
|
-
const os = require('node:os');
|
|
115
|
-
// На macOS userData = ~/Library/Application Support/KingKont
|
|
116
|
-
const candidates = [
|
|
117
|
-
path.join(os.homedir(), 'Library', 'Application Support', 'KingKont', 'settings.json'),
|
|
118
|
-
path.join(os.homedir(), '.config', 'KingKont', 'settings.json'),
|
|
119
|
-
];
|
|
120
|
-
for (const p of candidates) {
|
|
121
|
-
if (!fs.existsSync(p)) continue;
|
|
122
|
-
const s = JSON.parse(fs.readFileSync(p, 'utf-8'));
|
|
123
|
-
if (s.kieKey) process.env.KIE_API_KEY = s.kieKey;
|
|
124
|
-
if (s.elevenKey) process.env.ELEVENLABS_API_KEY = s.elevenKey;
|
|
125
|
-
if (s.openrouterKey) process.env.OPENROUTER_API_KEY = s.openrouterKey;
|
|
126
|
-
break;
|
|
127
|
-
}
|
|
128
|
-
} catch {}
|
|
129
|
-
}
|