@lalalic/markcut 2.0.0 → 2.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.
Files changed (48) hide show
  1. package/AGENTS.md +1 -0
  2. package/package.json +1 -1
  3. package/{SKILL.md → skills/markcut/SKILL.md} +8 -2
  4. package/{docs → skills/markcut/docs}/system-prompt-edit.md +5 -2
  5. package/skills/markcut/docs/template.md +213 -0
  6. package/{templates → skills/markcut/docs/templates}/courseware/TEMPLATE.md +220 -10
  7. package/{templates → skills/markcut/docs/templates}/courseware/prompts/outline.md +5 -0
  8. package/{templates → skills/markcut/docs/templates}/courseware/prompts/scene.md +6 -0
  9. package/skills/markcut/docs/templates/deep-dive/TEMPLATE.md +355 -0
  10. package/skills/markcut/docs/templates/deep-dive/agents/researcher.md +69 -0
  11. package/skills/markcut/docs/templates/deep-dive/agents/reviewer.md +108 -0
  12. package/skills/markcut/docs/templates/deep-dive/prompts/fix.md +28 -0
  13. package/skills/markcut/docs/templates/deep-dive/prompts/outline.md +102 -0
  14. package/skills/markcut/docs/templates/deep-dive/prompts/script.md +64 -0
  15. package/skills/markcut/docs/templates/illustrated-book/TEMPLATE.md +360 -0
  16. package/skills/markcut/docs/templates/illustrated-book/agents/reviewer.md +115 -0
  17. package/skills/markcut/docs/templates/illustrated-book/prompts/fix.md +29 -0
  18. package/skills/markcut/docs/templates/illustrated-book/prompts/illustration.md +35 -0
  19. package/skills/markcut/docs/templates/illustrated-book/prompts/story.md +69 -0
  20. package/skills/markcut/docs/templates/short-film/TEMPLATE.md +387 -0
  21. package/skills/markcut/docs/templates/short-film/agents/reviewer.md +115 -0
  22. package/skills/markcut/docs/templates/short-film/prompts/fix.md +29 -0
  23. package/skills/markcut/docs/templates/short-film/prompts/screenplay.md +101 -0
  24. package/skills/markcut/docs/templates/short-film/prompts/storyboard.md +54 -0
  25. package/skills/markcut/docs/templates/short-video/TEMPLATE.md +302 -0
  26. package/skills/markcut/docs/templates/short-video/agents/reviewer.md +94 -0
  27. package/skills/markcut/docs/templates/short-video/prompts/fix.md +27 -0
  28. package/skills/markcut/docs/templates/short-video/prompts/script.md +65 -0
  29. package/skills/markcut/docs/templates/vlog/TEMPLATE.md +405 -0
  30. package/skills/markcut/docs/templates/vlog/agents/reviewer.md +89 -0
  31. package/skills/markcut/docs/templates/vlog/agents/story-writer.md +100 -0
  32. package/skills/markcut/docs/templates/vlog/prompts/bgm-select.md +38 -0
  33. package/skills/markcut/docs/templates/vlog/prompts/group-clips.md +93 -0
  34. package/skills/markcut/docs/templates/vlog/prompts/local-context.md +59 -0
  35. package/skills/markcut/docs/templates/vlog/prompts/outline.md +56 -0
  36. package/skills/markcut/docs/templates/vlog/prompts/review-fix.md +27 -0
  37. package/skills/markcut/docs/templates/vlog/prompts/storyboard.md +41 -0
  38. package/src/config.mjs +11 -3
  39. package/src/player/bundle/player.js +5 -24
  40. package/src/player/components/EditControls.tsx +1 -1
  41. package/src/player/components/SceneThumbnails.tsx +6 -33
  42. package/src/player/server.mjs +217 -129
  43. /package/{docs → skills/markcut/docs}/edit-mode.md +0 -0
  44. /package/{docs → skills/markcut/docs}/json-descriptive.md +0 -0
  45. /package/{docs → skills/markcut/docs}/label-mode.md +0 -0
  46. /package/{docs → skills/markcut/docs}/markdown-descriptive.md +0 -0
  47. /package/{templates → skills/markcut/docs/templates}/courseware/agents/reviewer.md +0 -0
  48. /package/{templates → skills/markcut/docs/templates}/courseware/prompts/fix.md +0 -0
@@ -0,0 +1,93 @@
1
+ # Prompt: Group & Filter Clips
2
+
3
+ > Fill every `{placeholder}`, then execute in your own context.
4
+ > Reads: `metadata.json` from `markcut vision --label`. Outputs structured scene groups.
5
+
6
+ ---
7
+
8
+ You are transforming raw clip metadata into structured scene groups for a {style} vlog: "{theme}".
9
+
10
+ ## Input — raw clip understanding
11
+
12
+ Below is the per-clip understanding from `markcut vision --label`, sorted by capture time. Each clip has:
13
+
14
+ - `filename` — original file name
15
+ - `type` — "image" or "video"
16
+ - `duration` — full clip duration in seconds (for videos)
17
+ - `caption` — VLM description of what the clip shows
18
+ - `aes_score` — aesthetic/interestingness score (0–1, higher = better)
19
+ - `user_label` — (optional) user's annotation from interactive labeling
20
+ - `gps` — (optional) {lat, lng} coordinates
21
+ - `stt` — (optional) STT transcript if video has speech
22
+
23
+ {clips_detail}
24
+
25
+ GPS waypoints (deduplicated, sorted): {gps_waypoints}
26
+
27
+ ## Rules — filter
28
+
29
+ 1. **Auto-keep** if `user_label` is present and positive (user specifically marked this clip as important).
30
+ 2. **Drop** clips where `aes_score < 0.4`, unless it has a positive user label or is the only clip in its visual scene.
31
+ 3. **Drop** near-duplicates: if two clips have visually identical captions (same subject, same angle), keep the one with higher aes_score.
32
+ 4. **Drop** off-topic clips: screen recordings, blurry shots, transitions (pointing at ground, pocket shots).
33
+ 5. **Max drops**: ≤20% of total clips. Never below 5 kept.
34
+ 6. **List every dropped clip** with filename and reason.
35
+
36
+ ## Rules — group into scenes
37
+
38
+ Each scene is a **single story beat** — one moment or idea. Group clips by **visual continuity**:
39
+
40
+ - **Same background + same clothing/lighting/subject-state → same scene**. Exhaust one scene before starting the next.
41
+ - A scene can be: a location/setting stop (lake, trail, campfire), a specific activity (setting up tent, cooking), or a thematic moment (arrival, farewell).
42
+ - **1–4 clips per scene**. A single long video take >10s may be its own scene.
43
+ - Each scene **3–20 seconds** estimated duration. Split if >20s.
44
+ - Clips within a scene play in capture order.
45
+ - **Transition between scenes**: root `layout:series` plays scenes sequentially, so group clips that belong together visually.
46
+
47
+ ### For video clips, suggest trim boundaries
48
+
49
+ If a video clip is longer than needed:
50
+ - `startFrom` — where to start (seconds from beginning of clip)
51
+ - `endAt` — where to end (seconds from beginning of clip)
52
+ - Example: a 30s walking video may be trimmed to `startFrom:5 endAt:15` for the narrative-relevant 10 seconds.
53
+
54
+ ### Route scene
55
+
56
+ If the user provided ≥2 GPS waypoints OR the clips reveal ≥2 distinct locations with GPS data, include a Route scene as the first scene with:
57
+ - Waypoints list
58
+ - Brief route narration
59
+ - Estimated duration: 4–8 seconds
60
+
61
+ ## Output format
62
+
63
+ ```json
64
+ {
65
+ "route_scene": null | {
66
+ "waypoints": [
67
+ { "lat": 0, "lng": 0, "label": "place name" }
68
+ ],
69
+ "narration": "Route overview line..."
70
+ },
71
+ "scenes": [
72
+ {
73
+ "name": "Short descriptive name for the scene",
74
+ "clips": [
75
+ {
76
+ "source": "filename",
77
+ "type": "image | video",
78
+ "startFrom": 0,
79
+ "endAt": 10,
80
+ "duration": 0
81
+ }
82
+ ],
83
+ "estimated_duration": 0
84
+ }
85
+ ],
86
+ "dropped_clips": [
87
+ { "source": "filename", "reason": "Low aes_score (0.35)" }
88
+ ],
89
+ "arc": "Hook → Core → Vibe → Close",
90
+ "total_kept": 0,
91
+ "total_dropped": 0
92
+ }
93
+ ```
@@ -0,0 +1,59 @@
1
+ # Prompt: Search Local Context (News, Weather, Events)
2
+
3
+ > Fill every `{placeholder}`, then execute in your own context.
4
+ > Runs after Phase 1 (media understanding) before storyboard writing.
5
+ > Uses web search to find real facts about the vlog's location and date.
6
+
7
+ ---
8
+
9
+ You are researching local context for a vlog about "{theme}" at {location}.
10
+
11
+ Date range: {date_range} (or approximate dates from media timestamps)
12
+ Location description: {location} (from GPS reverse-geocode or user input)
13
+ Vlog style: {style}
14
+
15
+ ## Task
16
+
17
+ Search for the following and report real facts that could naturally weave into the narration:
18
+
19
+ 1. **Weather** — What was the weather like on those dates? High/low temps, conditions (sunny, rainy, cloudy), notable patterns (heatwave, storm, full moon).
20
+ 2. **Local events** — Any festivals, markets, sports events, holidays, or community gatherings happening at that location during the date range.
21
+ 3. **Seasonal context** — Seasonal highlights: fall colours, cherry blossoms, ski season opening, migration patterns, park hours.
22
+ 4. **Recent news** — Any notable local news near that location within the week before the vlog dates (park closures, trail openings, wildlife alerts, cultural events).
23
+
24
+ Use multiple search queries for coverage. Prefer official sources (weather service, park website, local news).
25
+
26
+ ## Output format
27
+
28
+ ```
29
+ ## Local Context
30
+
31
+ Weather:
32
+ - <fact 1> (source: <url>)
33
+ - <fact 2> (source: <url>)
34
+
35
+ Events:
36
+ - <fact> (source: <url>)
37
+
38
+ Seasonal:
39
+ - <fact> (source: <url>)
40
+
41
+ News:
42
+ - <fact> (source: <url>)
43
+
44
+ ## Amplification ideas (optional, for narrator)
45
+
46
+ - <How a fact amplifies the story: "The fall colours festival meant the park was busier than usual, which explains the crowded trail clip">
47
+ - <Another idea>
48
+ ```
49
+
50
+ ## Rules
51
+
52
+ - Only include facts confirmed by at least one web source. If a search yields nothing useful for a category, write "None found."
53
+ - Do not invent weather, events, or news.
54
+ - The amplification ideas are suggestions only — the story-writer decides whether to use them.
55
+ - Focus on facts that **connect** to what the media shows (weather matching the sky in photos, events explaining crowds, seasonal features matching the scenery).
56
+
57
+ ## After this step
58
+
59
+ Pass the result to the storyboard phase (Phase 3). The story-writer agent or outline prompt should receive the local context as an additional input. Use at most **2 local-context references** in the final narration — enough to add color, not enough to overwhelm the personal story.
@@ -0,0 +1,56 @@
1
+ # Prompt: Vlog Outline — Narrative Arc
2
+
3
+ > Fill every `{placeholder}`, then execute in your own context.
4
+ > Reads: `metadata.json` (per-clip captions, aes_score, GPS), project inputs.
5
+
6
+ ---
7
+
8
+ You are planning a {duration_min}-second {style} vlog: "{theme}".
9
+
10
+ Creator: {creator_profile}
11
+ Language: {language}
12
+
13
+ Given the clip understanding below, plan the narrative arc.
14
+
15
+ Clip understanding (from `markcut vision --label`):
16
+ - Total clips: {total_clips}
17
+ - Dominant mood: {dominant_mood}
18
+ - Narrative summary: {narrative_summary}
19
+ - Key subjects: {key_subjects}
20
+ {clips_detail}
21
+
22
+ Requirements:
23
+
24
+ 1. **Hook → Core → Vibe → Close arc**: First scene hooks the viewer with the best visual + intriguing line. Middle scenes are chronological story beats. Final scene provides closure.
25
+
26
+ 2. **Visual continuity**: Clips sharing same background/outfit/subject-state form one scene. No jumping A→B→A.
27
+
28
+ 3. **Drop rules**: Keep all clips unless aes_score < 0.4, near-duplicate, or off-topic. Max ~20% drops. Never below 5 clips.
29
+
30
+ 4. **GPS**: {gps_info} — if ≥2 GPS waypoints, include a route scene with map.
31
+
32
+ Output format:
33
+
34
+ ```
35
+ ## Scene Plan
36
+
37
+ ### Route Scene (if applicable)
38
+ - waypoints: <list>
39
+ - route narration: <one line describing the route>
40
+
41
+ ### Scene 1: <title>
42
+ - clips: <filenames with time ranges>
43
+ - narration: <first-person line, 10-40 words>
44
+ - mood: <mood word>
45
+ - duration: <estimated seconds>
46
+
47
+ ### Scene 2: <title>
48
+ ...
49
+
50
+ ### Scene N: <title>
51
+
52
+ Dropped clips:
53
+ - <filename>: <reason>
54
+
55
+ Title suggestion: <3-15 words>
56
+ ```
@@ -0,0 +1,27 @@
1
+ # Prompt: Apply Reviewer Findings
2
+
3
+ > Fill every `{placeholder}`, then execute in your own context.
4
+ > Used after a FAIL verdict. You edit; the reviewer never does.
5
+
6
+ ---
7
+
8
+ Apply the reviewer findings below to `{vlog_md_path}` with minimal, targeted edits.
9
+
10
+ Reviewer findings (JSON):
11
+
12
+ {findings_json}
13
+
14
+ Rules:
15
+ - Address every `blocker` and `major` finding. Minor findings only when trivially fixable.
16
+ - Each fix must respect TEMPLATE.md §2 scene grammar and §3 authoring rules.
17
+ - Narration fabrication → rewrite the line to use conservative paraphrase of clip captions.
18
+ - Broken src → fix the path or add a placeholder image.
19
+ - Duration mismatch → shorten/lengthen narration and adjust subtitle `duration:`.
20
+ - Blank frames → check startFrom/endAt values, clip ordering, and file existence.
21
+
22
+ After editing, list what changed:
23
+ ```
24
+ - <finding id>: <scene> — <one-line description of the edit>
25
+ ```
26
+
27
+ Then re-render and re-review.
@@ -0,0 +1,41 @@
1
+ # Prompt: Vlog Scene → Markcut Markdown
2
+
3
+ > Fill every `{placeholder}`, then execute in your own context.
4
+ > Run once per scene in the outline. Constraints mirror TEMPLATE.md §2/§3.
5
+
6
+ ---
7
+
8
+ You are writing one scene of a {style} vlog. The scene will be rendered with markcut markdown syntax.
9
+
10
+ Theme: {theme}
11
+ Creator: {creator_profile}
12
+ Language: {language}
13
+
14
+ Scene from outline:
15
+
16
+ {outline_scene}
17
+
18
+ All clips are in the media directory `{media_dir}`. Use filenames as `src:` values relative to this directory.
19
+
20
+ **A. Media selection:**
21
+ - 1-4 clips for this scene. Use imaging for photos, videos for clips. See `startFrom`/`endAt` for trimming.
22
+ - Image: `- image src:{filename} duration:{s} start:{s}`
23
+ - Video: `- video src:{filename} startFrom:{trim_start} endAt:{trim_end} start:{s}`
24
+ - First clip starts at `start:0`. Subsequent clips start at the cumulative previous duration.
25
+
26
+ **B. Narration:**
27
+ - One `subtitle script:"..."` node per scene. Duration matches total scene length.
28
+ - First-person, conversational, matching creator profile.
29
+ - Every word grounded in clip captions, user labels, or GPS. No fabrication.
30
+ - Length: 10-40 words (~3-15 seconds at 2.5 w/s).
31
+ - No parentheses, no ellipses. At most one emoji.
32
+
33
+ Output format for ONE scene:
34
+
35
+ ```
36
+ ## <SceneTitle (PascalCase)>
37
+ layout:parallel
38
+ - image src:<filename> duration:<s> start:<s>
39
+ - video src:<filename> startFrom:<s> endAt:<s> start:<s>
40
+ - subtitle script:"<narration line>" duration:<total_s>
41
+ ```
package/src/config.mjs CHANGED
@@ -75,14 +75,22 @@ export const DEFAULT_TTS_CLI =
75
75
 
76
76
  /**
77
77
  * Default agent CLI — general-purpose text LLM.
78
- * Used for text-only tasks like detect-scenes and editing.
78
+ * Used for text-only tasks like detect-scenes.
79
+ * Placeholder:
80
+ * {prompt} = user prompt (current context + edit request)
81
+ * Override with MARKCUT_AGENT_CLI env var.
82
+ */
83
+ export const DEFAULT_AGENT_CLI = process.env.MARKCUT_AGENT_CLI || 'npx pi -p {prompt}';
84
+
85
+ /**
86
+ * Default edit agent CLI — used by the edit-mode persistent rpc session.
79
87
  * Placeholders:
80
88
  * {systemprompt} = system prompt (role, instructions, knowledge)
81
89
  * {prompt} = user prompt (current context + edit request)
82
90
  * {sessionid} = unique session ID for conversation continuity
83
- * Override with MARKCUT_AGENT_CLI env var.
91
+ * Override with MARKCUT_EDIT_CLI env var.
84
92
  */
85
- export const DEFAULT_AGENT_CLI = process.env.MARKCUT_AGENT_CLI || 'npx pi --session-id {sessionid} --system-prompt {systemprompt} -p {prompt}';
93
+ export const DEFAULT_EDIT_CLI = process.env.MARKCUT_EDIT_CLI || 'npx pi --session-id {sessionid} --system-prompt {systemprompt} -p {prompt}';
86
94
 
87
95
  // ── Render-only pipeline CLI templates ─────────────────────────────────────
88
96
  // These are specific to the render pipeline (no vision pipeline equivalent).
@@ -60017,7 +60017,7 @@ function EditControls({ onStatusChange, suppressReloadRef, currentTime, activeSc
60017
60017
  });
60018
60018
  const data2 = await res.json();
60019
60019
  if (res.ok) {
60020
- const summary = (data2.output || "done").split("\n")[0].slice(0, 65);
60020
+ const summary = data2.summary || (data2.output || "done").split("\n")[0].slice(0, 65);
60021
60021
  onStatusChange?.(summary);
60022
60022
  setTimeout(() => {
60023
60023
  if (suppressReloadRef) suppressReloadRef.current = false;
@@ -60348,15 +60348,6 @@ function LabelControls({ playerRef, currentTime, onSceneChange }) {
60348
60348
  // src/player/components/SceneThumbnails.tsx
60349
60349
  var React51 = __toESM(require_react(), 1);
60350
60350
  var import_jsx_runtime93 = __toESM(require_jsx_runtime(), 1);
60351
- var VIDEO_EXT2 = {
60352
- ".mov": 1,
60353
- ".mp4": 1,
60354
- ".avi": 1,
60355
- ".mkv": 1,
60356
- ".webm": 1,
60357
- ".m4v": 1,
60358
- ".wmv": 1
60359
- };
60360
60351
  function SceneThumbnails({ currentTime, onSeek }) {
60361
60352
  const [scenes, setScenes] = React51.useState([]);
60362
60353
  React51.useEffect(() => {
@@ -60375,22 +60366,12 @@ function SceneThumbnails({ currentTime, onSeek }) {
60375
60366
  }
60376
60367
  return /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("div", { id: "scene-thumbnails", children: scenes.map((scene2, i3) => {
60377
60368
  const isActive = i3 === activeIdx;
60378
- const ext = scene2.src.substring(scene2.src.lastIndexOf(".")).toLowerCase();
60379
- const isVideo = !!VIDEO_EXT2[ext];
60380
- const hasMedia = !!scene2.src;
60381
- return /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)(
60382
- "div",
60369
+ return /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(
60370
+ "span",
60383
60371
  {
60384
- className: "sthumb-item" + (isActive ? " active" : ""),
60372
+ className: "scene-pill" + (isActive ? " active" : ""),
60385
60373
  onClick: () => onSeek?.(scene2.start),
60386
- children: [
60387
- /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)("div", { className: "sthumb-media", children: [
60388
- hasMedia && !isVideo && /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("img", { src: scene2.src, alt: "", loading: "lazy" }),
60389
- hasMedia && isVideo && /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("video", { src: scene2.src, muted: true, preload: "metadata" }),
60390
- !hasMedia && /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("span", { className: "sthumb-fallback", children: (scene2.name || "S" + (i3 + 1)).slice(0, 2).toUpperCase() })
60391
- ] }),
60392
- /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("span", { className: "sthumb-name", children: scene2.name || "Scene " + (i3 + 1) })
60393
- ]
60374
+ children: scene2.name || "Scene " + (i3 + 1)
60394
60375
  },
60395
60376
  i3
60396
60377
  );
@@ -40,7 +40,7 @@ export function EditControls({ onStatusChange, suppressReloadRef, currentTime, a
40
40
  });
41
41
  const data = await res.json();
42
42
  if (res.ok) {
43
- const summary = (data.output || "done").split("\n")[0].slice(0, 65);
43
+ const summary = data.summary || (data.output || "done").split("\n")[0].slice(0, 65);
44
44
  onStatusChange?.(summary);
45
45
  setTimeout(() => {
46
46
  if (suppressReloadRef) suppressReloadRef.current = false;
@@ -1,10 +1,8 @@
1
1
  /**
2
2
  * SceneThumbnails — horizontal scene selector for all modes.
3
3
  *
4
- * Fetches scene info from /api/video-info and renders clickable thumbnails
5
- * with scene names. Active scene is highlighted based on currentTime.
6
- *
7
- * Layout: supported in edit and preview modes (label mode has its own).
4
+ * Fetches scene info from /api/video-info and renders clickable scene name pills.
5
+ * Active scene is highlighted based on currentTime.
8
6
  */
9
7
  import * as React from "react";
10
8
 
@@ -12,15 +10,8 @@ interface Scene {
12
10
  name: string;
13
11
  start: number;
14
12
  end: number;
15
- duration: number;
16
- src: string;
17
- mediaType: string;
18
13
  }
19
14
 
20
- const VIDEO_EXT: Record<string, number> = {
21
- ".mov": 1, ".mp4": 1, ".avi": 1, ".mkv": 1, ".webm": 1, ".m4v": 1, ".wmv": 1,
22
- };
23
-
24
15
  interface SceneThumbnailsProps {
25
16
  /** Current player time in seconds — used to highlight active scene */
26
17
  currentTime: number;
@@ -42,7 +33,6 @@ export function SceneThumbnails({ currentTime, onSeek }: SceneThumbnailsProps) {
42
33
 
43
34
  if (scenes.length === 0) return null;
44
35
 
45
- // Determine active scene index from currentTime
46
36
  let activeIdx = -1;
47
37
  for (let i = 0; i < scenes.length; i++) {
48
38
  if (currentTime >= scenes[i].start && currentTime < scenes[i].end) {
@@ -55,31 +45,14 @@ export function SceneThumbnails({ currentTime, onSeek }: SceneThumbnailsProps) {
55
45
  <div id="scene-thumbnails">
56
46
  {scenes.map((scene, i) => {
57
47
  const isActive = i === activeIdx;
58
- const ext = scene.src.substring(scene.src.lastIndexOf(".")).toLowerCase();
59
- const isVideo = !!VIDEO_EXT[ext];
60
- const hasMedia = !!scene.src;
61
-
62
48
  return (
63
- <div
49
+ <span
64
50
  key={i}
65
- className={"sthumb-item" + (isActive ? " active" : "")}
51
+ className={"scene-pill" + (isActive ? " active" : "")}
66
52
  onClick={() => onSeek?.(scene.start)}
67
53
  >
68
- <div className="sthumb-media">
69
- {hasMedia && !isVideo && (
70
- <img src={scene.src} alt="" loading="lazy" />
71
- )}
72
- {hasMedia && isVideo && (
73
- <video src={scene.src} muted preload="metadata" />
74
- )}
75
- {!hasMedia && (
76
- <span className="sthumb-fallback">
77
- {(scene.name || "S" + (i + 1)).slice(0, 2).toUpperCase()}
78
- </span>
79
- )}
80
- </div>
81
- <span className="sthumb-name">{scene.name || "Scene " + (i + 1)}</span>
82
- </div>
54
+ {scene.name || "Scene " + (i + 1)}
55
+ </span>
83
56
  );
84
57
  })}
85
58
  </div>