hermoso 0.1.34 → 0.1.35

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 (2) hide show
  1. package/mcp/tools.mjs +5 -5
  2. package/package.json +1 -1
package/mcp/tools.mjs CHANGED
@@ -4445,7 +4445,7 @@ export function registerTools(server) {
4445
4445
 
4446
4446
  server.registerTool('make_explainer', {
4447
4447
  title: 'Make an explainer video',
4448
- description: "Turn a TOPIC into a finished narrated, captioned explainer video. Writes a sectioned script, paints a BURST of pictures per section (about one every 1.5s — most of them one-detail edits of the frame before, so it reads as movement rather than a slideshow), narrates each section with TTS, adds gentle Ken-Burns motion, then composites the on-screen text + end card with the Chrome+ffmpeg engine the ads use (text is never model-painted, so it never garbles). It is an image film WITH motion, not N video-model renders — that's what keeps it affordable. `style` picks the visual family: the default 'cinematic' is photoreal editorial; every other id is a STYLED, strictly non-photoreal look (illustrated / collage / clay / pixel …) that first renders ONE style-key image and then locks every scene to it, so the whole film holds one look. Cost at the default frame density: a ~130-credit hold for a 60s explainer on the default style, ~100 styled; `frameDensity:'lean'` roughly halves it and `'minimal'` (one picture per section) is ~30. All settle to the exact per-frame image + narration spend (a longer target = more sections = more). Takes SEVERAL minutes — one image render per frame; independent frames are painted concurrently, so it is far faster than the frame count suggests. Needs the writing model and a narration voice engine connected. NOT the tool for a short product ad — use render_ad or generate_video for those, and make_template_ad for the deterministic native formats.",
4448
+ description: "Turn a TOPIC into a finished narrated explainer video. Writes a sectioned script, paints a BURST of pictures per section (about one every 1.5s — most of them one-detail edits of the frame before, so it reads as movement rather than a slideshow), narrates each section with TTS, adds gentle Ken-Burns motion, then composites the end card (and any on-screen text you asked for) with the Chrome+ffmpeg engine the ads use (text is never model-painted, so it never garbles). BURNED ON-SCREEN TEXT IS OFF BY DEFAULT — the narration carries the point and the pictures carry the story, so the film ships clean unless the user asks otherwise; `captions:true` adds held key points and `subtitles:true` adds narration-timed CAPS (see both). It is an image film WITH motion, not N video-model renders — that's what keeps it affordable. `style` picks the visual family: the default 'cinematic' is photoreal editorial; every other id is a STYLED, strictly non-photoreal look (illustrated / collage / clay / pixel …) that first renders ONE style-key image and then locks every scene to it, so the whole film holds one look. Cost at the default frame density: a ~130-credit hold for a 60s explainer on the default style, ~100 styled; `frameDensity:'lean'` roughly halves it and `'minimal'` (one picture per section) is ~30. All settle to the exact per-frame image + narration spend (a longer target = more sections = more). Takes SEVERAL minutes — one image render per frame; independent frames are painted concurrently, so it is far faster than the frame count suggests. Needs the writing model and a narration voice engine connected. NOT the tool for a short product ad — use render_ad or generate_video for those, and make_template_ad for the deterministic native formats.",
4449
4449
  inputSchema: {
4450
4450
  topic: z.string().describe('what the explainer should teach or explain — a topic or a short brief'),
4451
4451
  durationSeconds: z.number().optional().describe('target length 20-120s (default 60); drives the section count — ~10s of narration each, 3-8 sections'),
@@ -4454,9 +4454,9 @@ export function registerTools(server) {
4454
4454
  style: z.enum(['cinematic', 'editorial_collage', 'flat_vector', 'stickman', 'whiteboard', 'ink_marker', 'silhouette', 'storybook', 'paper_diorama', 'isometric', 'claymation', 'pixel_art', 'watercolor', 'fluffy_toy', 'low_poly', 'stylized_3d', 'studio_3d', 'mannequin']).optional().describe("visual style. 'cinematic' (default) is photoreal; the rest are non-photoreal styled looks — editorial_collage (halftone cutouts + marker accents), flat_vector, stickman, whiteboard, ink_marker, silhouette, storybook (gouache), paper_diorama, isometric, claymation, pixel_art, watercolor, fluffy_toy (felted plush), low_poly, stylized_3d (matte clay render), studio_3d (preschool toy 3D on a white sweep — the Kids default), mannequin (clay-render reenactment figures — a History alternate). Ask the user which they want rather than picking silently; a styled pick costs more (see the cost note)."),
4455
4455
  channel: z.enum(['explainer', 'history', 'kids', 'fairytale']).optional().describe("the CHANNEL TYPE — it sets the pacing, the narration register and the default look, and is orthogonal to `style` (a named style always wins): explainer (casual second-person, fast cuts), history (witty chronological retelling / documentary), kids (fastest, question-first, warm teacher), fairytale (slow, atmospheric myth or folklore). Default 'explainer'."),
4456
4456
  voice: z.string().optional().describe('narration voice name — omit for the default warm read'),
4457
- captions: z.boolean().optional().describe('burn on-screen text (default true)'),
4458
- subtitles: z.boolean().optional().describe('burn CAPS SUBTITLES timed to the narration instead of one held key point per section (default false). Free — no extra render, no extra credits.'),
4459
- music: z.string().optional().describe("music bed under the narration, ducked under the voice. Omit and the KIDS and FAIRYTALE channels get their recommended bed from the curated library FREE (and simply ship dry when no track is on file); the other channels are dry. 'off' forces silence. NAME A MOOD — upbeat / calm / warm / epic / tense / playful / elegant / hype / chill / dramatic — and a bespoke instrumental is COMPOSED for this film, which costs a small flat fee on top. hermoso_capabilities reports the exact figure as explainerMusicCredits; quote it before you pick a mood."),
4457
+ captions: z.boolean().optional().describe('burn ON-SCREEN KEY POINTS — one short line per section (at most 5 words / 32 characters, enforced), held over the picture for that whole section (~7-15s). Drawn by the same burner the subtitles use: slim white CAPS, thin black outline, bottom safe band, NO plate and no box. DEFAULT FALSE: the narration already says the point and the pictures carry it, so the clean film is the better default. Set true only when the user asks for on-screen text.'),
4458
+ subtitles: z.boolean().optional().describe('burn CAPS SUBTITLES timed to the narration instead of the held key points (default false; implies captions). Free — no extra render, no extra credits, and there is NO cue limit: the whole film is subtitled however long it runs. Slim white CAPS, thin black outline, bottom safe band, no plate, at most 5 words / 32 characters per line. TIMING: each cue is anchored to that section’s REAL measured narration length and distributed inside the section by character count — exact at every section boundary, approximate to a few tenths of a second within one. It is not a word-level speech clock, so never promise frame-accurate sync.'),
4459
+ music: z.string().optional().describe("music bed under the narration, measured to sit about 14 dB under the voice and sidechain-ducked beneath it. Omit and the KIDS and FAIRYTALE channels get their recommended bed COMPOSED for this film those two are the only channels a bed is due on unasked, and it costs a small flat fee; every other channel ships dry. 'off' forces silence. 'library' takes a free curated track only, and ships dry when none is on file. NAME A MOOD — upbeat / calm / warm / epic / tense / playful / elegant / hype / chill / dramatic — to compose one on ANY channel, at the same fee. hermoso_capabilities reports the exact figure as explainerMusicCredits; quote it before you turn a bed on or pick a mood."),
4460
4460
  upscale: z.number().optional().describe("optional FINAL upscale — 2 doubles each side, 4 quadruples. Captions and the end card are burned BEFORE it so they upscale with the frame. It is priced BY LENGTH and it is the expensive part — several times the cost of rendering the film itself. hermoso_capabilities reports the exact figures per length as explainerUpscaleCredits. Never turn it on unasked: quote the number and let the user choose."),
4461
4461
  endCard: z.boolean().optional().describe('append the branded end card (default true)'),
4462
4462
  brandName: z.string().optional().describe('brand name for the end card — omit to leave it unbranded'),
@@ -4472,7 +4472,7 @@ export function registerTools(server) {
4472
4472
  const fin = `${d.music ? ` · ${d.music.source === 'composed' ? 'composed' : 'library'} ${d.music.mood} music bed` : ''}${d.upscaled ? ` · upscaled ${d.upscaled}×` : ''}`;
4473
4473
  // The length is whatever ffprobe measured on the DELIVERED file, and `null` means it could not be measured — print
4474
4474
  // the `—` placeholder rather than inventing a number from the ask (the read-back law: only a measurement ships).
4475
- return okVideo(`Explainer ready${d.sections ? ` — ${d.sections} sections, ${d.frames || d.sections} frames, ${d.durationSeconds == null ? '—' : d.durationSeconds + 's'}` : ''}${d.lengthNote ? ` (${d.lengthNote})` : ''}${d.style && d.style !== 'cinematic' ? ` in the ${String(d.style).replace(/_/g, ' ')} style${d.styleLocked ? '' : ' (style key unavailable — the look rides on the prompt only)'}` : ''}${fin}: ${r.url} [job ${r.jobId}]${d.musicNote ? `\n${d.musicNote}` : ''}${d.upscaleNote ? `\n⚠ ${d.upscaleNote}` : ''}`, r);
4475
+ return okVideo(`Explainer ready${d.sections ? ` — ${d.sections} sections, ${d.frames || d.sections} frames, ${d.durationSeconds == null ? '—' : d.durationSeconds + 's'}` : ''}${d.lengthNote ? ` (${d.lengthNote})` : ''}${d.style ? ` in the ${String(d.style).replace(/_/g, ' ')} style${d.styleLocked ? '' : ' (style key unavailable — the look rides on the prompt only)'}` : ''}${fin}: ${r.url} [job ${r.jobId}]${d.musicNote ? `\n${d.musicNote}` : ''}${d.captionNote ? `\n⚠ ${d.captionNote}` : ''}${d.upscaleNote ? `\n⚠ ${d.upscaleNote}` : ''}`, r);
4476
4476
  }));
4477
4477
 
4478
4478
  server.registerTool('product_sizzle', {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hermoso",
3
- "version": "0.1.34",
3
+ "version": "0.1.35",
4
4
  "mcpName": "io.github.hermoso-ai/hermoso",
5
5
  "description": "Generate finished VIDEO ADS, image ads and UGC avatar ads for any brand with AI — spy on competitor ads across the Meta, Google and LinkedIn ad libraries plus TikTok/Instagram/YouTube organic — then publish to Facebook, Instagram, Threads, TikTok, YouTube, X, LinkedIn and Pinterest and build & manage the ad campaigns behind them on Meta, Google Ads, LinkedIn, Pinterest, Microsoft Advertising and ChatGPT Ads. MCP server (262 tools), CLI and Claude skills for Hermoso, the AI ad studio: brand onboarding, 30+ image/video models, finished-ad pipeline (script, voiceover, music, brand end card), ad scoring and competitor teardowns.",
6
6
  "type": "module",