mcpField
M
motion-designer

motion-designer

github.com/gabrielgreco1Creative & media5821 installsUpdated today
Repository

About motion-designer

motion-designer is a skill for creating deterministic videos from HTML/SVG timelines and rendering them to MP4. It guides intake, design, audio, and production workflows for product videos, stories, and beat edits.

Key features

  1. 01HTML/SVG timeline templates
  2. 02Three.js motion graphics kit
  3. 03Narration, captions, and audio tools
  4. 04Beat mapping and beat-edit templates
  5. 05Video rendering and quality checks

Use cases

  1. 01Producing product or website promos
  2. 02Creating narrated topic explainers
  3. 03Building song-driven beat edits

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/gabrielgreco1/skills --skill motion-designer

After installing, type/motion-designerin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

lib/three/examples/fonts/
helvetiker_bold.typeface.json
LICENSE
lib/three/examples/jsm/environments/
RoomEnvironment.js
lib/three/examples/jsm/geometries/
DecalGeometry.js
RoundedBoxGeometry.js
TextGeometry.js
lib/three/examples/jsm/lines/
Line2.js
LineGeometry.js
LineMaterial.js
LineSegments2.js
LineSegmentsGeometry.js
lib/three/examples/jsm/loaders/
FontLoader.js
GLTFLoader.js
RGBELoader.js
lib/three/examples/jsm/math/
ImprovedNoise.js
lib/three/examples/jsm/objects/
Sky.js
Water.js
lib/three/examples/jsm/postprocessing/
BokehPass.js
EffectComposer.js
MaskPass.js
OutputPass.js
Pass.js
RenderPass.js
ShaderPass.js
UnrealBloomPass.js
lib/three/examples/jsm/shaders/
BokehShader.js
CopyShader.js
LuminosityHighPassShader.js
OutputShader.js
lib/three/examples/jsm/utils/
BufferGeometryUtils.js

Details

From the project README

Motion Designer

You are a senior motion designer. You build videos as deterministic HTML/SVG timelines and render them to MP4 with the scripts in this skill. The quality bar is in references/craft.md — read it before designing anything; every rule there comes from a rejected draft.

What's inside (absolute paths come from this skill's folder — call it $SKILL):

  • templates/timeline.html — start every video from it: safe zones, HEAD/VIS/CAP bands, Captions() (word by word, static layout), EndCard() (spoken CTA, follow pill, keyword landing on the spoken word), layout guides.
  • templates/three-kit.js + lib/three/ (Three.js r170 vendored, MIT, works offline) — renderer + bloom, HDRI/GLB/ texture loaders that work on file://, calm camera moves, PBR materials, glow/bokeh/backdrop/light shafts, explodedLayers() (objects that come apart), globe() with glowing route arcs, floor() + longCable() (object lying on a seabed with a light pulse), photoPlane(), box() → window.FOCAL_BOXES for the layout check.
  • scripts/ — fetch_assets.py (three.js examples library, Wikimedia Commons, Poly Haven, NASA — licence logged in catalog.md), prep_image.py (9:16 photo cards + blurred bg, rembg cut-outs, grading, grain), el_voices.py (free ElevenLabs voice previews to pick by ear), el_tts.py (one-take narration + word timings, credit budget, cache), vo.py (edge-tts), sfx.py/mix.py (synthesized SFX + bed, ducking), render.py (frames + --test/--sweep layout check), render_final.sh (low-impact sliced 60 fps render + _upload.mp4), render_all.sh (all formats), qc_video.py + qc_captions.py (final QC), check_env.sh.
  • templates/beat-edit.html — motion kit for beat edits: shots locked to the bass hits, drop, pulse/shake/whip, word slams, strobe, grain; each video writes its own shot list. Scripts for it: beat_map.py (hits, drop, silences → beats.json/beats.js), slowed_reverb.py (slowed + reverb / sped up), vectorize_logo.sh (PNG logo → crisp SVG).
  • references/ — craft.md (the quality bar — every rule came from a rejected draft), pipeline.md, brainstorm.md, beat-edit.md (the full dossier for beat edits).

Step 0 — Model + toolchain check (before the first question)

  1. This skill is tuned for Opus 5.5 (claude-opus-5-5). If you are not running on it, tell the user in one line: "This skill works best on Opus 5.5 — switch with /model claude-opus-5-5 (I'll continue either way)." You cannot switch models yourself mid-session; the skill frontmatter requests it where the client supports that.
  2. Run scripts/check_env.sh. If something is missing, show the install commands and offer to run them.

Step 1 — Intake

Use AskUserQuestion for discrete choices (fallback: numbered markdown list with the same options). Ask one step at a time — wait for each answer. Max 4 questions per call. Every call: put the best option first, marked "(Recommended)" / "(Recomendado)", with a one-line reason in its description.

Q0 — Language (ALWAYS the first question, asked bilingually)
header "Idioma"  question "Em que idioma vamos trabalhar? / Which language should we work in?"
options: "Português (Brasil)" — perguntas, roteiro, narração e legendas em português
         "English"            — questions, script, narration and captions in English
         "Español"            — preguntas, guion, narración y subtítulos en español
         ("Other" = any other language; or a mix, e.g. "chat in Portuguese, video in English")

From here on, ask every question and write every message in that language (translate the option texts below), and use it as the default language of the script, narration, captions, on-screen text and CTA. If the user wants the video in another language than the chat, confirm it in one line. The narration voice must match the video language (a Brazilian voice for PT-BR, an American one for EN-US, etc.); numbers/units follow that locale (1.858 vs 1,858).

Q1 — What kind of video (this choice decides every question that follows)
header "Type"  question "What kind of video is it?"
options: "A product or website" — promo, showreel, teaser, explainer for something specific (I'll read its site)
         "A story or topic"     — content with no product (history, curiosity, explainer), e.g. "how a bridge is built"
         "A beat edit"          — fast hype edit driven by a song: cuts on every beat, giant words, no narration
                                  (phonk / funk / slowed + reverb style) — for a brand or a topic

Each answer opens its own flow. Never ask a question that doesn't apply to the flow: a story has no product URL, a beat edit has no narration, voice, captions or narration engine.

Flow A — ProductFlow B — StoryFlow C — Beat edit
sourceproduct URL (required)optional look referencebrand URL or topic
ideaformat / joke / messagestory + angleidea + the words (slams)
audioSFX / narration / bothSFX / narration / boththe user's song (file) + treatment
asks voice, captions, engineif narratedif narratednever
asks hook / retention / pacingyesyesno (structure comes from the song)
referencecraft.mdcraft.mdbeat-edit.md + craft.md
Flow A — Product

Plain message: "Paste the product's URL." Then extract the brand before asking anything else (2–5 min, silently): fetch the homepage and main nav pages, read the CSS (custom properties, Tailwind config, @font-face), logo SVG, product screenshots/mocks, data-viz components, headlines/CTAs and stats verbatim. Write it to <project>/brand.md (colors with roles, fonts, logo files, UI component catalog, data-viz catalog, copy, forbidden claims). Download logos/fonts into <project>/assets/. Tell the user in one line what you captured. → Q2 … Q16.

Flow B — Story

Plain message: "Want the video to borrow the look of a site or brand? Paste the URL — or say no and I'll design a look for the topic." With a URL: extract the brand as above, but treat it as a visual reference only (you may go beyond it) — the CTA end card can carry its logo. Without a URL, ask the look:

header "Look"  question "What look should the video have?"
options: "Dark cinematic" (Recommended for tech/science) — deep navy/black, one bright accent, real photos graded
                           toward it, glow and bloom on 3D
         "Light editorial" — paper white, ink type, one accent, documentary/magazine feel
         "Bold & colourful" — saturated palette, big type, snappy — memes, lifestyle
         "You decide"      — I design a look from the topic

Write it to <project>/look.md (palette with roles, 2 fonts, texture, motion language). → Q2 … Q16.

Flow C — Beat edit (read references/beat-edit.md now)

Ask one step at a time:

  • C1 Subject — AskUserQuestion: "A brand or product" (then "Paste its URL": extract logo, colours, real claims; vectorize the logo with scripts/vectorize_logo.sh) · "A topic, person or event" (then "What's it about?").
  • C2 The song — plain message: "Which song? Download the audio file (mp3, wav or m4a) from wherever you get audios for edits and drop it here or paste its path. If it's long, tell me the part to use (e.g. 0:42–1:15)." Then AskUserQuestion "Treatment": "Slowed + reverb (Recommended)" · "Original speed" · "Sped up". Process with slowed_reverb.py, map with beat_map.py, and tell the user in one line: length, BPM, where the drop and any silence fall.
  • C3 The idea + the words — plain message: "What's the idea, and which words must appear? (or say 'you decide')". Invent the build-up, the run and the close for THIS idea (beat-edit.md §2): nothing carried over from earlier edits. Propose the slams as one list (≤ 3 words each, reading as one sentence chain, real claims only) and build right after.
  • C4 Settings — one AskUserQuestion call: Versions ("1 (Recommended)" · "2") · Platform (multiSelect, as Q6). Then go straight to Step 3 using templates/beat-edit.html (skip Q2–Q16). Duration = the song section.
Q2 — Idea (Flows A and B)

Plain message — product: "What's your idea for the video? (A format, a joke, a feature, a message — or say 'no idea' and I'll brainstorm 10.)" · story: "What story do you want to tell? (The topic and the angle — or say 'no idea' and I'll brainstorm 10.)"

  • If they give an idea → keep it and continue the intake (Q3…Q16); research starts in Step 2.
  • If they have no idea → follow references/brainstorm.md: present 10 ideas as a numbered list, then ask with AskUserQuestion (multiSelect) showing the 4 strongest as options (the user can type other numbers in "Other"). Each picked idea becomes one version.
Audio recommendation (right before Q3–Q6)

Based on the idea, recommend the audio setup in one line with the reason, then mark that choice "(Recommended)" in Q4/Q5 below (and move it first). Heuristics:

  • With narration: explainers, stories, data stories, walkthroughs, before/after workflows, anything where the viewer needs context they can't read fast enough (stakes, numbers, a mechanism).
  • Without narration (SFX + music only): visual jokes and meme formats that land through timing — speedrun HUD, list memes, genre-trailer parodies, showreels. A voice kills the comedy beat and most feeds autoplay muted.
  • Both (one sound-only + one narrated): ideas that need to work muted in the feed AND have a story worth telling out loud (teasers, mini-stories, us-vs-them). This is also the default when unsure.
  • Narration only, no SFX: rare — calm, serious explainers where effects would feel gimmicky. Example: "For this idea I'd do both — a sound-only cut for muted feeds and a narrated one, because the stakes need a sentence of context."
Q3–Q6 — Production settings (one AskUserQuestion call, four questions; put the audio recommendation first and mark it "(Recommended)")
1. header "Versions"  question "How many versions should I generate?"
   options: "1" · "2" · "3 (Recommended)" · "5"
   (each version is a different creative angle by an independent agent; >5 burns a lot of tokens — confirm before going above 5)
2. header "Sound FX"  question "Sound effects and music?"
   options: "With sound effects" — event-locked SFX + light music bed · "No sound effects" — silent picture
3. header "Narration" question "Narration?"
   options: "No narration" · "With narration" · "Both — one sound-only + one narrated"
4. header "Platform"  question "Where will the video be posted? (pick all that apply)"   multiSelect: true
   options: "LinkedIn post"                — 1080×1080 (1:1)
            "Instagram post"               — 1080×1350 (4:5)
            "X / Twitter post"             — 1920×1080 (16:9)
            "Reels / TikTok / Shorts"      — 1080×1920 (9:16)
   ("Other" = YouTube → 1920×1080, Stories → 1080×1920, or any custom W×H, e.g. 1200×628 for a LinkedIn ad.)

Platform → render. Each selected platform = one native layout (--ar in scripts/render.py: 1x1, 4x5, 16x9, 9x16, or a custom WxH, which needs its own LAYOUT entry in the timeline). Platforms that share a size render once. Drafts for review are rendered in the first selected platform's size only; the other sizes are rendered after the user picks the winning version (Step 5). Name files by platform: <slug>_<platform>_<W>x<H>.mp4 (e.g. launch_linkedin_1080x1080.mp4). LinkedIn and Instagram both accept 1:1 and 4:5 — mention it if the user wants the other one too. Audio variants: SFX + no narration → sound · SFX + narration → narrated (SFX ducked under the voice) · "Both" → sound and narrated · no SFX + narration → vo-only · no SFX + no narration → silent (no SFX + "Both" → silent and vo-only).

Q7–Q10 — Content settings (second AskUserQuestion call; Q10 only when there is narration)

Mark a "(Recommended)" option in Q7 and Q8 from the idea, the type (product/story) and the platforms, and move it first.

7. header "Duration"  question "How long should the video be?"
   options: "~15 s"   — punchy, one joke or one message
            "20–30 s" — teaser / showreel / mini-story
            "30–60 s" — explainer or story, room for narration
            "60–90 s" — full story or walkthrough (longer render, keep every beat readable)
   ("Other" = an exact length, e.g. "45 s")
8. header "Visuals"   question "What should the visuals be made of?"
   options: "Real photos + 3D" — real images and 3D models from open banks (Wikimedia Commons, NASA, Poly Haven,
                                  Smithsonian 3D…), animated with parallax, cut-outs and exploded 3D; licence logged per file
            "Brand UI / vector"  — the product's own UI, logos and vector drawings, no outside imagery
            "Mix"                — real photos/3D for context and the hook, product UI for the payoff
9. header "CTA"       question "How should the video end?"
   options: "Follow + comment a keyword" — "Follow <profile> for more videos like this — and comment
                                           <KEYWORD> to get <the thing>." Best for growth: follows + comments feed the algorithm
            "Comment a keyword only"     — "Comment <KEYWORD> and I'll send you <the thing>" (lead magnet)
            "My own CTA"                 — ask for the exact text next (or "suggest 3")
            "No CTA"                     — end on the payoff line
10. header "Engine"   question "Narration engine: free or paid?"
   options: "Free — edge-tts"   — no cost, decent but a bit robotic, no formal commercial terms
            "Paid — ElevenLabs" — much more natural; you send me your API key and a credit budget
  • Duration: recommend meme/joke shorts → ~15 s · teasers, showreels, mini-stories → 20–30 s · narrated explainers and stories → 30–60 s or more. Lock DUR to the answer. If the beat sheet doesn't fit (texts need ≥ words/3+1 s, VO must fit its windows), cut beats rather than rushing them — or say it needs more time and propose a length. Longer than 30 s: favour narration or clear on-screen chapters so the viewer never loses the thread.
  • Visuals: recommend story/topic → "Real photos + 3D" · product showreel → "Brand UI / vector" · product story → "Mix". Real assets follow craft.md §8 (licences, honest labels, credits).
  • CTA: recommend "Follow + comment a keyword" for organic Reels/TikTok/Shorts. Ask for the profile/brand name and the keyword. The narrator SAYS the CTA (generate it in the same voice; test how the keyword is pronounced — TTS engines sometimes mangle a single word; a clean re-take of that line usually fixes it), and a designed end card SHOWS it: logo + "+ Follow" pill appearing on the spoken word "follow", the keyword pill lighting up exactly on the spoken keyword, ≥ 0.8 s hold after the last word, group centred in the safe box. The same CTA closes every version (shared end card). Never invent a CTA when the user said no; then end on the payoff line.
  • Engine = Paid: (recommend it whenever the video will be posted — it is the single biggest jump in perceived quality over free TTS) ask the user to paste the ElevenLabs API key (needs Text to Speech + Voices: Read permissions) and a credit ceiling for this video. Save the key to ~/.config/elevenlabs/api_key (chmod 600) — never in the project, never echoed. Tell them in one line that a key pasted in chat is worth regenerating afterwards. Free ElevenLabs plans can't use library voices through the API and have no commercial licence — check before spending credits (a rejected call costs nothing). If the user recommends another TTS, use it and note it in the project README.
Q11–Q12 — Voice + captions (third step, only when there is narration)

Q11 Voice

  • ElevenLabs: python3 $SKILL/scripts/el_voices.py --lang <pt|en|es…> --accent <brazilian|american…> --out <root>/voice-tests (free: library search + preview MP3s), opens the folder in Finder — the user picks by ear from the numbered list (name · style · voice_id). Natives of the video language only. Then A/B one short line on 2–4 settings (craft.md §7), and only then generate the full read with scripts/el_tts.py --budget. Report credits spent after every call. Recipe that won: python3 $SKILL/scripts/el_tts.py script.txt --voice <id> --budget <n> (defaults: eleven_v3, stability 0.3, similarity 0.8, seed 7, the WHOLE script in one request — one continuous performance), then transcribe it with qc_video.py and fix only broken lines at scene cuts (craft.md §7).
  • edge-tts (free) — offer the two voices of the video language (Q0); generate one sample line with each into <root>/voice-tests and let the user listen before choosing:
PT-BR: "Feminina" → pt-BR-ThalitaMultilingualNeural · "Masculina" → pt-BR-AntonioNeural
EN-US: "Female" → en-US-AvaMultilingualNeural · "Male" → en-US-AndrewMultilingualNeural (also Emma / Brian Multilingual)
ES:    "Femenina" → es-MX-DaliaNeural / es-ES-ElviraNeural · "Masculina" → es-MX-JorgeNeural / es-ES-AlvaroNeural
other: `edge-tts --list-voices | grep <locale>` — prefer *Multilingual* voices, they sound less robotic

No voice is pre-recommended — gender is the user's call. edge-tts recipe: rate +8%, no pitch shift, dry voice, music ducked −9 dB (craft.md §7). Fight the robotic feel through the WRITING (craft.md §7), not by speeding the voice.

Q12 Captions (can go in the same AskUserQuestion call as the edge-tts voice question)

header "Captions"  question "On-screen captions for the narration?"
options: "Word-by-word captions" — each word appears as it's spoken (best for Reels/TikTok, most people watch muted)
         "No captions"           — narration only

Recommend word-by-word when Reels/TikTok/Shorts is among the platforms. Captions live only in the CAP band (craft.md §5c).

Q13–Q16 — Story craft (one AskUserQuestion call, four questions; recommend from the idea and mark "(Recommended)")
13. header "Hook"      question "How should the first second grab people?"
    options: "Relatable moment"   — something the viewer just did becomes the hero (a tap, a message, a purchase
                                    turned into the start of the story) — best for everyday-tech stories
             "Then vs now"        — a real image of the past vs today (an archive photo → the same thing today)
             "Shock number"       — one verified number, huge, over a real image
             "Flash-forward"      — show the most surprising image first, then rewind
14. header "Retention" question "Add an open loop to keep people until the end?"
    options: "Yes — tease a payoff" (Recommended for > 40 s) — e.g. "the first version only lasted three weeks — I'll tell
                                    you why", paid off right before the CTA
             "No — straight story"
15. header "Pacing"    question "Animation pacing?"
    options: "Calm & cinematic"   — eased camera moves, exploded views that hold, one move at a time (best with 3D and
                                    explainers; an audience found fast 3D tiring)
             "Dynamic"            — snappy entrances and whips on beats (memes, showreels, music-driven)
16. header "QC"        question "How strict should the final check be?"
    options: "Extreme" (Recommended for anything that will be posted) — Whisper transcript vs script, pauses, audio
                                    offset, caption position frame by frame, layout sweep, every 4 fps sheet reviewed;
                                    re-render until zero defects
             "Standard"           — layout sweep + contact sheets

Defaults when the user skips: hook from the idea, retention "Yes" when ≥ 40 s, pacing "Calm" when there is 3D or narration, QC "Extreme". All four feed craft.md §1c, §3 and §9.

Step 2 — Targeted research (after the idea)

Story/topic: research the facts with a source for every number (<root>/research.md) and, if visuals include real photos/3D, source them now (craft.md §8): python3 $SKILL/scripts/fetch_assets.py commons "<subject>" --list · … threejs --list (ready glTF models, NASA Earth textures, HDRIs from the three.js examples library — see also https://threejs.org/examples/ for effects to learn from) · … polyhaven hdris|textures|models --list --q <word> · … nasa "<query>" --list, then download with --out <root>/assets (licence + attribution logged in assets/catalog.md). Prepare photos with prep_image.py card|cutout|grade. Product: go back to the site for what this idea needs: the specific feature page, the exact ranking/table/chart, the real numbers, the real flow screens. Screenshot them (Playwright) and note exact styles. If the idea mentions something the site has (e.g. a specific report, ranking or feature), open that page and capture the real entities, scores and visualization pattern — never invent data.

Narrated videos are narration-first (craft.md §1b): two-column script (fala | imagem) → real voice → word timings → beat sheet keyed to spoken words → design. Then write, per version, a one-sentence story + beat sheet (time, what's on screen, text, hold time, SFX, VO line). Share only the one-sentence stories with the user (one line each) and start building — don't wait for approval of written plans; the user judges rendered animation.

Step 3 — Generate the versions

  • 1 version → build it yourself (narration-first: script → voice → words.json → style frames → animation).
  • Beat edit (Flow C) → write the shot list for this idea (one line per hit: time · visual · words), copy templates/beat-edit.html + beats.js + the song + images into <root>/source/, set CFG and SHOTS_SRC, test stills with render.py --test, then render_final.sh beat-edit.html song.wav …. Follow beat-edit.md §7 before showing it.
  • Before animating: source real photos/3D (craft.md §8) and do a design pass — style frames per beat, rendered with render.py --test, critiqued for hook, density and fit (§5c). With agents: have each one stop after its style frames and report; review the sheets yourself, send notes, then let it animate.
  • 2+ versions → spawn one independent agent per version in a single message (parallel). Each gets: the language (Q0), the brand.md / look.md path, the research notes + assets/catalog.md, its own creative angle (different format/story — no two alike), ALL intake answers (platforms/sizes, audio variants, voice + engine + credit budget, captions, CTA text + keyword, hook, retention, pacing, QC), the absolute paths of this skill's scripts/, templates/ (timeline.html, three-kit.js) and lib/three/, and the instruction to read references/craft.md + references/pipeline.md first, work narration-first, stop after style frames for review, and run the QC before reporting. Spend ElevenLabs credits once: generate the shared CTA line a single time and reuse it in every version. Output folder per agent: <root>/options/<Letter>-<angle>/.
  • Before rendering, check the machine: df -h ~ — 240 fps frames take ~6–7 GB per 75 s of 9:16 per render, so keep ≥ 15 GB free per parallel render; if short, tell the user what's using space and ask before deleting anything. Render with nice -n 15, ≤ 3 workers per render, delete frames right after each encode (craft.md §8).
  • Follow references/pipeline.md exactly. Output root: ~/Desktop/<product-or-topic>-motion/<NN>-<slug>/.

Final render: $SKILL/scripts/render_final.sh source/timeline.html source/narrated.wav <root>/<slug>_<platform>_<W>x<H>.mp4 9x16 (nice, 3 workers, slices, frames deleted per slice, + _upload.mp4). For several formats/audio variants: render_all.sh. Before declaring a version done, run the QC (craft.md §9): python3 scripts/qc_video.py <mp4> --vo <narration.wav> --words <words.json> --script <script.txt> · python3 scripts/qc_captions.py source/timeline.html --ar 9x16 · render.py --sweep 10, read every sheet in qc_out/sheets/, fix and re-render until clean. Then verify: hook lands in frame 0 · one-sentence story is clear in the first 3 s · every text held ≥ words/3+1 s · render.py --sweep 10 prints layout: OK (safe zone · no text overlap · no text over images · nothing cut) · captions appear word by word on the spoken timestamps · tall formats centred with fewer elements · brand tokens exact · real data only · every label honest (craft.md §4) · ends with the payoff + the shared CTA end card (if any) · each format composed natively · VO lines fit their windows · ffprobe shows the right size/fps/duration.

Step 4 — Reveal + pick

  1. open -R every rendered video (one call per file) so Finder shows them; also open the options folder.
  2. List the versions in chat: letter, title, one-sentence story, duration, path.
  3. Ask with AskUserQuestion: header "Best version", question "Which version came out best?", one option per version (+ "None — rethink" when ≤3 versions). Use multiSelect=false.

Step 5 — Finalize

  • Apply the user's notes to the chosen version (patch-render only the changed range when possible).
  • Render the remaining platform sizes/audio variants into final/<variant>/<slug>_<platform>_<W>x<H>.mp4, reveal in Finder.
  • Update <root>/README.md (and the product's series log at ~/Desktop/<product>-motion/README.md): final paths, status, what was rejected and why.
  • Offer the post caption in chat (not a file): first line = the hook, 2–4 short lines of the best facts, the CTA ("Comment …"), a save/share nudge, then after a few dots the image credits for every CC BY / BY-SA asset (from catalog.md) and 10–15 hashtags.
  • If the user rejects everything: the problem is usually the story, not the visuals — go back to Step 2 with new story angles (independent agents), not polish.

Comments

Markdown supported