kingkont 0.2.0 → 0.4.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/README.md CHANGED
@@ -60,6 +60,19 @@ macOS) — переустановка приложения их не теряе
60
60
  | Cut / Copy / Paste | `Cmd+X` / `Cmd+C` / `Cmd+V` |
61
61
  | Esc | закрыть любую модалку |
62
62
 
63
+ ## Скилл для Claude Code
64
+
65
+ Чтобы Claude Code в любой сессии умел запускать редактор для текущей папки:
66
+
67
+ ```bash
68
+ npx kingkont install-skill # для всех проектов: ~/.claude/skills/kingkont/
69
+ npx kingkont install-skill --project # только для текущего проекта: ./.claude/skills/kingkont/
70
+ ```
71
+
72
+ После этого в новой сессии Claude Code достаточно сказать «открой kingkont»
73
+ или «запусти редактор» — Claude увидит скилл, выполнит `npx -y kingkont serve`
74
+ в текущей папке и подскажет URL для Chrome.
75
+
63
76
  ## Разработка
64
77
 
65
78
  ```bash
package/bin/kingkont.js CHANGED
@@ -12,16 +12,37 @@ function showHelp() {
12
12
  KingKont · Chatium — видео-редактор сериала
13
13
 
14
14
  Запуск:
15
- npx kingkont запустить Electron-приложение (рекомендуется)
16
- npx kingkont serve запустить только HTTP-сервер; URL для Chrome
17
- npx kingkont serve <path> то же, путь к проекту/cwd по умолчанию
15
+ npx kingkont запустить Electron-приложение (рекомендуется)
16
+ npx kingkont serve запустить только HTTP-сервер; URL для Chrome
17
+ npx kingkont serve <path> то же, путь к проекту/cwd по умолчанию
18
+ npx kingkont install-skill установить Skill для Claude Code (~/.claude/skills/kingkont)
18
19
 
19
20
  Опции:
20
21
  --port <N> порт сервера (по умолчанию 17893)
22
+ --project install-skill: положить в .claude/skills/ текущей папки
21
23
  --help, -h эта справка
22
24
  `);
23
25
  }
24
26
 
27
+ function installSkill() {
28
+ const fs = require('node:fs');
29
+ const os = require('node:os');
30
+ const isProject = args.includes('--project');
31
+ const dest = isProject
32
+ ? path.resolve(process.cwd(), '.claude', 'skills', 'kingkont')
33
+ : path.join(os.homedir(), '.claude', 'skills', 'kingkont');
34
+ const src = path.join(root, 'skill', 'SKILL.md');
35
+ if (!fs.existsSync(src)) {
36
+ console.error('Шаблон SKILL.md не найден в пакете:', src);
37
+ process.exit(1);
38
+ }
39
+ fs.mkdirSync(dest, { recursive: true });
40
+ fs.copyFileSync(src, path.join(dest, 'SKILL.md'));
41
+ console.log(`✓ KingKont skill установлен: ${path.join(dest, 'SKILL.md')}`);
42
+ console.log(' В новой сессии Claude Code (или после /reload) скилл будет доступен:');
43
+ console.log(' попроси «открой kingkont» в папке проекта.');
44
+ }
45
+
25
46
  if (args.includes('--help') || args.includes('-h')) {
26
47
  showHelp();
27
48
  process.exit(0);
@@ -30,6 +51,11 @@ if (args.includes('--help') || args.includes('-h')) {
30
51
  const portIdx = args.indexOf('--port');
31
52
  const port = portIdx >= 0 ? parseInt(args[portIdx + 1], 10) : 17893;
32
53
 
54
+ if (args[0] === 'install-skill') {
55
+ installSkill();
56
+ process.exit(0);
57
+ }
58
+
33
59
  if (args[0] === 'serve') {
34
60
  // Только Node-сервер. FSAH-API в Chrome требует user-gesture для
35
61
  // showDirectoryPicker — юзер сам выбирает папку через UI.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kingkont",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "KingKont · Chatium — нод-редактор сцен с AI-генерацией (картинки/видео/голос/SFX/музыка/текст)",
5
5
  "main": "main.js",
6
6
  "bin": {
@@ -14,6 +14,7 @@
14
14
  "assets/**/*",
15
15
  "bin/**/*",
16
16
  "scripts/**/*",
17
+ "skill/**/*",
17
18
  "README.md"
18
19
  ],
19
20
  "engines": {
package/skill/SKILL.md ADDED
@@ -0,0 +1,315 @@
1
+ ---
2
+ name: kingkont
3
+ description: Use this skill when the user works with a KingKont project — a film/series scene editor where each scene is a folder with scene.json. Triggers — fraзы вроде «открой/запусти kingkont», «открой редактор сцен», «добавь сцену/персонажа/локацию», «добавь ноду на холст», «сгенерируй картинку/видео/голос/SFX/музыку/текст», или работа с папкой содержащей _characters/ _locations/ <scene>/scene.json. Skill знает формат данных и API-ключи из настроек kingkont, может править scene.json напрямую и запускать UI редактора через `npx -y kingkont serve` для визуальной работы.
4
+ ---
5
+
6
+ # KingKont · Chatium — Skill
7
+
8
+ KingKont — нод-редактор сцен фильма/сериала с AI-генерацией. Каждая сцена/
9
+ персонаж/локация — папка на диске с `scene.json` и подпапками для медиа.
10
+ Формат plain JSON + plain files: всё можно читать и менять руками или
11
+ через AI-агента, не запуская сам редактор.
12
+
13
+ ## Когда использовать этот skill
14
+
15
+ - Юзер работает в папке-проекте KingKont (есть `_characters/`,
16
+ `_locations/`, любая папка с `scene.json`, или файл `CLAUDE.md` в корне).
17
+ - Просит «открой редактор», «запусти kingkont», «открой проект» —
18
+ поднимаешь UI через `npx -y kingkont serve` (см. ниже).
19
+ - Просит править данные: «добавь персонажа Анна», «добавь сцену
20
+ «Прощание»», «вставь текстовую ноду на сцену 3 с этим текстом», «свяжи
21
+ ноды @Анна и @сценарий», «сгенерируй картинку», «озвучь реплику» — это
22
+ работа со scene.json и/или вызов API; делается без открытия UI.
23
+ - Любые правки тексту, перестановка нод, чистка истории, бэкап — все
24
+ через прямую правку `scene.json` и `texts/*.md`.
25
+
26
+ ## Как открыть UI редактора
27
+
28
+ ```bash
29
+ npx -y kingkont serve
30
+ ```
31
+
32
+ Печатает `▶ KingKont готов: http://localhost:17893/`. Скажи юзеру открыть
33
+ этот URL в **Chrome / Edge / Brave** (Safari/Firefox не поддерживают
34
+ File System Access API). На macOS можно открыть автоматом:
35
+
36
+ ```bash
37
+ open -a "Google Chrome" "http://localhost:17893/"
38
+ ```
39
+
40
+ Альтернатива — Electron-приложение (без браузера): `npx -y kingkont`.
41
+
42
+ ## Формат проектной папки
43
+
44
+ ```
45
+ <root>/
46
+ ├── CLAUDE.md ← подробный формат (создаётся редактором при первом
47
+ │ открытии в его UI; идентичен этому skill, но
48
+ │ живёт рядом с проектом)
49
+ ├── _characters/
50
+ │ └── <имя>/ ← одна доска на персонажа
51
+ ├── _locations/
52
+ │ └── <имя>/ ← одна доска на локацию
53
+ ├── <имя сцены>/ ← сцены лежат в корне как любые папки
54
+ │ │ (имена не начинающиеся с `_` и `.`,
55
+ │ │ не равные _characters / _locations)
56
+ │ ├── scene.json ← главный файл — описан ниже
57
+ │ ├── clips/ ← видео (mp4, mov, webm)
58
+ │ ├── images/ ← картинки (jpg, png, webp)
59
+ │ ├── audio/ ← аудио (mp3, wav, m4a)
60
+ │ └── texts/ ← .md-файлы текстовых нод
61
+ ├── _deleted/ ← корзина: при удалении ноды/доски файл/папка
62
+ │ переезжает сюда. Cmd+Z в редакторе
63
+ │ восстанавливает.
64
+ └── (любые другие файлы редактор не трогает)
65
+ ```
66
+
67
+ ## Формат `scene.json` (полный)
68
+
69
+ ```json5
70
+ {
71
+ "nodes": [
72
+ {
73
+ "id": "uuid", // UUID v4, уникальный в пределах доски
74
+ "type": "image" | "video" | "audio" | "text",
75
+ "name": "опц. имя для @-ссылок", // используется в [@name] и автокомплите
76
+ "file": "images/foo.jpg", // относительный путь в папке доски
77
+ "x": 100, "y": 200, // координаты на холсте (логические px)
78
+ "width": 280, "height": 320, // опц., если юзер ресайзил
79
+ "generated": { // опц., если создано генерацией
80
+ "kind": "image" | "video" | "audio" | "text",
81
+ "subKind": "sfx" | "music", // только для audio: тип эффекта
82
+ "prompt": "...", // финальный промпт после resolve
83
+ "rawPrompt": "...", // исходный с [@ref]
84
+ "translatedPrompt": "...", // для SFX/music: en-перевод (для ElevenLabs)
85
+ "model": "nano-banana-2" | "bytedance/seedance-2"
86
+ | "eleven_v3" | "eleven-sfx" | "eleven-music"
87
+ | "anthropic/claude-sonnet-4" | ...,
88
+ "modelKey": "ключ модели для KIE",
89
+ "voiceId": "...", // для голоса
90
+ "voiceName": "...",
91
+ "tones": ["шепот", ...], // ElevenLabs v3 audio-tags
92
+ "durationSeconds": 3, // для SFX
93
+ "durationMs": 30000, // для music
94
+ "refs": [{ "name": "...", "type": "image", "file": "..." }],
95
+ "state": "submitting" | "queued" | "generating" | "success" | "error",
96
+ "taskId": "..." // KIE job id
97
+ },
98
+ "status": "generating" | "draft" | "error", // отсутствует если нода готова
99
+ "error": "...",
100
+ "history": [...], // история правок (через ⇄ Заменить)
101
+ "historyIndex": 0
102
+ }
103
+ // Текст ноды (n.text для type=text) в JSON НЕ хранится; контент лежит в texts/<file>.md
104
+ ],
105
+ "connections": [
106
+ { "from": "node-id", "to": "node-id" } // направленная связь
107
+ ],
108
+ "view": {
109
+ "scrollLeft": 0, // pan/zoom холста для восстановления
110
+ "scrollTop": 0,
111
+ "zoom": 1.0
112
+ },
113
+ "character": { // только для _characters/<name>/scene.json
114
+ "characterSheet": "images/sheet.jpg", // референс-картинка персонажа
115
+ "voice": "elevenlabs-voice-id", // дефолтный голос для генерации
116
+ "voiceName": "...",
117
+ "tone": "по умолчанию",
118
+ "commonTones": ["шепот", "крик", ...],
119
+ "lastTones": [],
120
+ "replicas": [
121
+ { "id": "...", "text": "...", "audio": "audio/replica_1.mp3", ... }
122
+ ]
123
+ },
124
+ "location": { // только для _locations/<name>/scene.json
125
+ "sheet": "images/sheet.jpg"
126
+ },
127
+ "timeline": { // монтажный лист сцены
128
+ "tracks": [
129
+ {
130
+ "id": "tv",
131
+ "name": "Видео" | "Голос" | "Эффекты" | "Музыка" | ...,
132
+ "kind": "video" | "audio",
133
+ "clips": [
134
+ {
135
+ "id": "uuid",
136
+ "nodeId": "node-id" | null, // привязка к ноде (если из неё)
137
+ "type": "video" | "image" | "audio",
138
+ "file": "clips/foo.mp4",
139
+ "name": "...",
140
+ "duration": 5.0, // в секундах
141
+ "start": 0, // позиция начала на дорожке
142
+ "trimStart": 0, // обрезка спереди
143
+ "sourceDuration": 5.0, // полная длительность файла
144
+ "_durationLoaded": true,
145
+ "groupId": "...", // опц., группа клипов
146
+ "disabled": false // skip при playback
147
+ }
148
+ ]
149
+ }
150
+ ],
151
+ "playhead": 0.27 // секунды
152
+ },
153
+ "history": { // undo/redo стек редактора
154
+ "past": [{ "ts": ..., "label": "...", "snap": "JSON-string", "movedFiles": [...] }],
155
+ "future": [...]
156
+ }
157
+ }
158
+ ```
159
+
160
+ ## Текстовые ноды
161
+
162
+ `node.text` в JSON отсутствует. Контент текстовой ноды лежит в
163
+ `texts/<filename>.md` (путь в `node.file`). Редактируй .md руками; редактор
164
+ подхватит изменения при следующем открытии доски.
165
+
166
+ Чтобы создать новую текстовую ноду через правку файлов:
167
+
168
+ 1. Записать содержимое в `<board>/texts/some-name.md`.
169
+ 2. Добавить ноду в `<board>/scene.json`:
170
+ ```json5
171
+ {
172
+ "id": "<uuid v4>",
173
+ "type": "text",
174
+ "name": "опционально, для @-ссылок",
175
+ "file": "texts/some-name.md",
176
+ "x": 100, "y": 100
177
+ }
178
+ ```
179
+
180
+ ## Файловые операции
181
+
182
+ - **Удаление ноды**: файл переезжает в `<root>/_deleted/<уникальное-имя>`.
183
+ Cmd+Z в редакторе восстанавливает (через movedFiles в history).
184
+ - **Замена/перегенерация**: новый файл записывается в подпапку, старый
185
+ сохраняется в `node.history[]` для отката (⇄ Заменить).
186
+ - **Импорт через drag-drop**: файлы копируются в правильную подпапку с
187
+ уникальным именем, нода создаётся автоматически.
188
+
189
+ ## API-ключи (для генерации)
190
+
191
+ Хранятся в `~/Library/Application Support/KingKont/settings.json` (macOS)
192
+ или `~/.config/KingKont/settings.json` (Linux):
193
+
194
+ ```json
195
+ {
196
+ "kieKey": "...", // для картинок и видео (api.kie.ai)
197
+ "elevenKey": "...", // для голоса/SFX/музыки (elevenlabs.io)
198
+ "openrouterKey": "..." // для текста и vision (openrouter.ai)
199
+ }
200
+ ```
201
+
202
+ Если ключа не хватает — попроси юзера задать в редакторе через `Cmd+,`.
203
+
204
+ ## Программная генерация (без UI)
205
+
206
+ Запусти `npx kingkont serve` в фоне — сервер становится прокси к KIE/
207
+ ElevenLabs/OpenRouter с уже подставленными ключами из settings.json.
208
+ Дёргай endpoints прямым curl/fetch:
209
+
210
+ ### `POST http://localhost:17893/api/text` — текст (OpenRouter)
211
+ ```json
212
+ {
213
+ "prompt": "...",
214
+ "model": "anthropic/claude-sonnet-4", // или openai/gpt-4o, google/gemini-..., etc
215
+ "system": "опционально system prompt",
216
+ "images": [{ "url": "data:image/jpeg;base64,..." }] // vision-режим
217
+ }
218
+ ```
219
+ Возвращает `{ "text": "...", "model": "..." }`.
220
+
221
+ ### `POST http://localhost:17893/api/sfx` — звуковой эффект (ElevenLabs)
222
+ ```json
223
+ {
224
+ "text": "heavy door slamming with echo", // лучше английский
225
+ "durationSeconds": 3, // 0.5–22, опц.
226
+ "promptInfluence": 0.3 // 0–1, опц.
227
+ }
228
+ ```
229
+ Возвращает `audio/mpeg` (mp3 stream). Сохрани в `<board>/audio/sfx_<ts>.mp3`.
230
+
231
+ ### `POST http://localhost:17893/api/music` — музыка (ElevenLabs)
232
+ ```json
233
+ {
234
+ "prompt": "epic orchestral cinematic, slow buildup, hopeful",
235
+ "durationMs": 30000 // опц.
236
+ }
237
+ ```
238
+ Возвращает `audio/mpeg`.
239
+
240
+ ### `POST http://localhost:17893/api/tts` — речь (ElevenLabs)
241
+ ```json
242
+ {
243
+ "text": "...",
244
+ "voiceId": "JBFqnCBsd6RMkjVDRZzb", // ElevenLabs voice id
245
+ "modelId": "eleven_v3"
246
+ }
247
+ ```
248
+ Возвращает `audio/mpeg`.
249
+
250
+ ### `POST http://localhost:17893/api/generate` — image/video (KIE, async)
251
+ ```json
252
+ {
253
+ "kind": "image" | "video",
254
+ "prompt": "...",
255
+ "model": "nano-banana-2" | "flux-schnell" | "sdxl-lightning"
256
+ | "seedream" | "seedream-5-lite" | "grok"
257
+ | "seedance-2", // для video — bytedance/seedance-2
258
+ "imageInputs": ["http(s) URL"], // опц., референсы
259
+ "aspectRatio": "16:9",
260
+ "resolution": "1K"
261
+ }
262
+ ```
263
+ Возвращает `{ "taskId": "..." }`. Затем поллить:
264
+
265
+ ### `GET http://localhost:17893/api/poll?taskId=...`
266
+ Возвращает `{ "status": "pending" | "done" | "error", "url": "https://..." }`.
267
+ Когда `done` — скачай `url` (это публичный URL картинки/видео).
268
+
269
+ ### `POST http://localhost:17893/api/upload` — загрузить локальный файл в KIE
270
+ Передай binary в body, заголовок `X-File-Name: filename.jpg`.
271
+ Возвращает `{ "url": "https://..." }` — этот URL можно класть в
272
+ `imageInputs`.
273
+
274
+ ### `GET http://localhost:17893/api/proxy?url=...`
275
+ Прокси для скачивания произвольных http(s)-URL минуя CORS.
276
+
277
+ ## Распространённые сценарии для агента
278
+
279
+ **«Открой редактор»** → `npx -y kingkont serve` + сообщить URL.
280
+
281
+ **«Добавь персонажа Анна»** → `mkdir -p _characters/Анна`, создать
282
+ минимальный `_characters/Анна/scene.json`:
283
+ ```json
284
+ { "nodes": [], "connections": [], "character": { "voice": null }, "view": { "zoom": 1, "scrollLeft": 0, "scrollTop": 0 }, "timeline": { "tracks": [], "playhead": 0 } }
285
+ ```
286
+
287
+ **«Добавь текстовую ноду на сцену "Прощание" с таким текстом ...»**:
288
+ 1. Записать `Прощание/texts/<slug>.md` с текстом.
289
+ 2. Прочитать `Прощание/scene.json`, добавить новую node-запись (`type: 'text'`,
290
+ уникальный uuid v4, `file: "texts/<slug>.md"`, `x/y` подальше от
291
+ существующих), записать обратно.
292
+
293
+ **«Свяжи ноды @А и @Б»** → найти их id по `name` в `scene.json`, добавить
294
+ `{from: "<id-A>", to: "<id-Б>"}` в `connections[]`.
295
+
296
+ **«Сгенерируй SFX "камни сыпятся"»** → `POST /api/sfx` с translated en-промптом
297
+ (модель Sound Generation на не-en тексте делает TTS-fallback), сохранить mp3
298
+ в `<board>/audio/sfx_<ts>.mp3`, добавить audio-ноду в scene.json с
299
+ `generated.subKind = "sfx"`.
300
+
301
+ **Не трогай**: `node.history[]`, `metadata.history.past/future` — это
302
+ снимки сцены для Cmd+Z. Поломав, потеряешь возможность отката. Поля с
303
+ UUID `id` тоже не меняй — на них завязаны связи и timeline-clips.
304
+
305
+ ## Шорткаты редактора (для подсказок юзеру)
306
+
307
+ - `Cmd+O` — открыть проект
308
+ - `Cmd+N` — новая сцена
309
+ - `Cmd+W` — закрыть проект (при втором нажатии — свернуть)
310
+ - `Cmd+,` — настройки (API-ключи)
311
+ - `Cmd+Z` / `Cmd+Shift+Z` — undo/redo
312
+ - `Cmd+X / C / V` — cut/copy/paste нод и клипов
313
+ - ПКМ по ноде / клипу / папке — контекст-меню
314
+ - ПКМ на пустом холсте — добавить новую ноду (Текст / Сгенерить ...)
315
+ - Тяга от точки на правом краю ноды → меню «что генерить»