Community코딩 & 개발github.com

Salt-555/SaltySkills

This is where I will publish fun skills for Hermes-Agent. Take what you want, just shower me with praise if I come up in conversation.

SaltySkills란 무엇인가요?

SaltySkills is a Codex agent skill that this is where I will publish fun skills for Hermes-Agent. Take what you want, just shower me with praise if I come up in conversation.

지원 대상~Claude CodeCodex CLI~Cursor
npx skills add Salt-555/SaltySkills

Installed? Explore more 코딩 & 개발 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

Cinematic Beats Video Style

Core Philosophy

Visuals lead timing. Audio follows. Animations and ASCII scenes play out at their natural runtime — they are NOT truncated, sped up, or held on final frames to match audio length. Silence between beats is intentional design, not a gap to fill.

  • TTS: One sentence per clip. Maximum signal-to-noise. No filler narration.
  • Visuals: Full natural runtime. Let animations breathe.
  • Cuts: Hard cuts only. No crossfades.
  • Music: User-provided tracks with automatic ducking during speech sections.
  • Check-ins: After each production phase, deliver assets to user for review before proceeding.

Project Structure

~/videos/[project-name]/
  project.md          # Living document — storyboard, decisions, revision notes
  beats/              # Individual beat assets
    beat-01/
      visual.mp4      # Generated visual (image with motion or animation)
      audio.mp3       # TTS clip for this beat (MP3 only — see Critical Rules)
      note.txt        # One-line description of what this beat shows
    beat-02/
      ...
  music/              # User-provided background music tracks
  output/             # Intermediate and final renders

Phase 1: Beat Script

Create project.md with the beat breakdown. Each beat = one visual + one TTS sentence.

Writing Beats

TTS rules:

  • ONE sentence per beat. Period.
  • Maximum signal-to-noise — every word earns its place.
  • If a thought needs two sentences, it's two beats.
  • Target: 5-15 words per clip. Shorter is better.
  • No introductory filler ("So...", "Now let's look at..."). Start on the point.

Visual rules:

  • Describe what the visual shows — not how long it lasts.
  • The visual runtime is determined by its natural completion, NOT by TTS length.
  • Image cuts: static image with Ken Burns motion (slow zoom/pan). Runtime: 4-6s minimum.
  • Animated cuts (p5js/manim/ascii): full animation plays out. Whatever it takes — 8s, 12s, 15s.
  • The beat duration = max(visual_duration, audio_duration) + pause.

Beat template in project.md:

# [Project Name]

## Concept
[One paragraph — what this video is about and the feeling we're going for]

## Music
- Track: [filename or description of music user will provide]
- Mood: [description]

## Beats

### Beat 01
**Visual:** [type: image | p5js | manim | ascii] — [prompt/description]
**TTS:** "One punchy sentence."
**Status:** [ ] visual [ ] audio [ ] approved

### Beat 02
...

## Notes
[Running log of decisions, revisions, user feedback]

Cut Types

TypeToolRuntimeBest For
imageimage_generate + Ken Burns4-6sPhotos, scenes, portraits, establishing shots
p5jsp5js skillNatural (8-15s)Generative art, particles, data viz, flow fields
manimmanim-video skillNatural (8-20s)Math animations, diagrams, technical explainers
asciiascii-video skillNatural (6-12s)Terminal aesthetic, retro computing, hacking topics
captionffmpeg drawtext4-8sCentered TTS text on dark background — pulls focus to words

CRITICAL: Before producing any p5js/manim/ascii beat, load the skill with skill_view(name) first. These skills contain brand palettes, font rules, and implementation patterns that must be followed exactly.

Phase 2: Script Approval Gate

STOP. Present project.md to user. Do not generate assets until explicitly approved.

Update project.md Notes section with approval timestamp.

Phase 3: Generate Visuals

Generate all visual assets per their type. Save as beats/beat-XX/visual.mp4.

Image beats (VHS-filtered Ken Burns)

  1. Generate image via image_generate
  2. Apply VHS filter to the image (grain, scanlines, vignette, chromatic aberration):
python3 scripts/vhs-filter.py \
  --input beat-XX-image.png \
  --output beat-XX-vhs.png \
  --seed 42 \
  --intensity 1.0

Requirements: pip install numpy Pillow (numpy for the array effects, Pillow for image I/O).

Intensity levels: 0.7 (subtle — grain + vignette only), 1.0 (standard — all effects), 1.5 (heavy — strong chromatic aberration, visible scanlines). Default is 1.0.

  1. Apply Ken Burns motion to the VHS-filtered image to create MP4:
ffmpeg -loop 1 -i beat-XX-vhs.png -t 5 \
  -vf "zoompan=z='min(zoom+0.001,1.3)':x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':d=125:s=1920x1080:fps=25" \
  -c:v libx264 -pix_fmt yuv420p -r 25 beats/beat-XX/visual.mp4

Why VHS first, then Ken Burns? The zoompan filter would blur out the grain and scanlines. Apply VHS to the static image first, then add motion on top. The Ken Burns movement on top of the VHS-filtered image creates a lived-in analog feel — like watching old footage through a slightly degraded CRT.

Animated beats (p5js/manim/ascii)

Load the relevant skill first, then generate. Save output as beats/beat-XX/visual.mp4.

Resolution: All visuals must be 1920x1080 at 25fps. Scale manim outputs:

ffmpeg -y -i raw-manim.mp4 \
  -vf "scale=1920:1080:flags=lanczos,setsar=1:1,fps=25" \
  -c:v libx264 -pix_fmt yuv420p -r 25 beats/beat-XX/visual.mp4

Batch image_generate calls in groups of 6. If flagged, rephrase neutrally and retry once.

VHS Filter Reference

The VHS filter (scripts/vhs-filter.py) applies these effects to a single image:

EffectWhat it doesVisual result
Chromatic aberrationR/B channel offset (0-2px)Color fringing on edges, like a misaligned CRT
Analog noise±8 grain per channel (intensity-scaled)Film-like texture in shadows and midtones
ScanlinesEvery 4th row darkened to 96%CRT phosphor grid overlay
CRT vignetteEdge darkening (15-35% based on intensity)Rounded screen corners, like old TV

For images: All effects apply once with a single random seed. Chromatic aberration and noise are visible; jitter/tracking lines are subtle since there's only one frame.

Note: This filter is image-only — it does not process video input. To get motion, apply the filter to a static frame first, then add Ken Burns/zoompan on top.

Phase 3.5: Visual Check-In Gate

STOP. Send each visual clip to the user for review.

Include the screenshot or MP4 with MEDIA: paths. Present them numbered:

Beat 01: [MEDIA path] — [brief description]
Beat 02: [MEDIA path] — [brief description]
...

Ask: "Any edits needed before we proceed to audio?"

Do not generate TTS until user approves visuals. Record feedback in project.md Notes.

If changes requested, regenerate only the affected beats and re-check-in.

Phase 4: Generate TTS Audio

Generate ALL TTS clips — one per beat. Use text_to_speech tool with output_path as .mp3. Save as beats/beat-XX/audio.mp3.

CRITICAL: Always use MP3 format for audio. OGG has codec compatibility issues with Telegram delivery and ffmpeg concat operations. Set TTS provider to OpenAI with MP3 output.

Rules:

  • One sentence per call. No concatenation.
  • Measure each clip duration with ffprobe after generation.
  • Record durations in project.md next to each beat.
ffprobe -v error -show_entries format=duration -of csv=p=0 beats/beat-XX/audio.mp3

Phase 4.5: Audio Check-In Gate

STOP. Present audio clips to user.

Apply voice filter (required)

Apply the dry/wet bitcrush chain to every TTS clip — this is our signature voice. See references/dry-wet-bitcrush.md for full technique and pitfalls.

Two approaches available:

A) Static mix (simple, consistent):

# Step 1: Create crushed version via wav intermediate (preserves duration)
ffmpeg -y -i beats/beat-XX/audio.mp3 \
  -af "aresample=resampler=soxr:osr=2000,aformat=sample_fmts=u8,aresample=resampler=soxr,lowpass=f=2500" \
  temp-crushed.wav

# Step 2: Mix dry + wet with compression glue
ffmpeg -y -i beats/beat-XX/audio.mp3 -i temp-crushed.wav \
  -filter_complex "[0:a]volume=0.7[dry];[1:a]volume=0.3[wet];[dry][wet]amix=inputs=2:duration=first:normalize=0,acompressor=threshold=0.05:ratio=4:attack=10:release=100[out]" \
  -map "[out]" beats/beat-XX/audio-filtered.mp3

rm temp-crushed.wav

B) Dynamic mix (signal degradation effect — preferred): Uses Python script (scripts/vibey-mix.py) with zero-order hold upsampling for authentic bitcrush at correct pitch.

Requirements: pip install numpy pydub (numpy for array processing, pydub for MP3 read/write).

Locked parameters (dec5-bit8 variant):

  • Decimation: 5× (drops every 5th sample, then repeats via zero-order hold)
  • Quantization: 8-bit (constant)
  • Dry/wet baseline: 80% dry / 20% wet
  • Dip pattern: Every ~1.2s, dry drops to ~35%, wet rises to ~65% (duration ~0.25s)
  • Tremolo on wet only: 4Hz triangle wave, depth 70% (wet pulses between 30-100%)
  • Slapback delay: 80ms at -18dB (~0.12 volume), applied to final mix
python3 scripts/vibey-mix.py beats/beat-XX/audio.mp3
cp beats/beat-XX/audio-dynamic.mp3 beats/beat-XX/audio-filtered.mp3

Chain breakdown: Clean dry signal layered with extreme digital artifacts (5× decimation, 8-bit quantization via zero-order hold upsampling), periodic dips raising the wet level for a "degrading transmission" effect, tremolo on wet signal for rhythmic pulsing, and slapback delay for space. Keep the chain structure intact — only adjust individual parameters if needed.

Use audio-filtered.mp3 in all subsequent phases. Keep original audio.mp3 for reference.

Record decisions in project.md Notes.

Phase 5: Compose Beats

For each beat, merge visual + audio with hard cut (no transition). The beat duration is determined by whichever is longer — visual or audio.

If visual >= audio:

Audio plays under the full visual. No padding needed.

ffmpeg -i beats/beat-XX/visual.mp4 -i beats/beat-XX/audio-filtered.mp3 \
  -c:v libx264 -pix_fmt yuv420p -c:a aac \
  -shortest -r 25 output/beat-XX-composed.mp4

If audio > visual:

Visual holds its final frame to fill the remaining time. Use tpad on video:

AUDIO_DUR=$(ffprobe -v error -show_entries format=duration -of csv=p=0 beats/beat-XX/audio-filtered.mp3)
ffmpeg -i beats/beat-XX/visual.mp4 -i beats/beat-XX/audio-filtered.mp3 \
  -vf "tpad=stop_mode=clone:stop_duration=$AUDIO_DUR" \
  -c:v libx264 -pix_fmt yuv420p -c:a aac \
  -t $AUDIO_DUR -r 25 output/beat-XX-composed.mp4

If no audio filter applied, use audio.mp3 instead of audio-filtered.mp3.

Between-beat pause

Add a short black frame between beats for breathing room:

ffmpeg -f lavfi -i color=c=black:s=1920x1080:d=0.15:r=25 \
  -c:v libx264 -pix_fmt yuv420p output/pause-XX.mp4

ASCII caption beats (word focus)

When the narration itself is the focal point — not the visual — use an ASCII-style beat with the TTS text centered on screen. Mark these in project.md as [caption] type:

Beat template:

### Beat 03 [caption]
**Visual:** ascii caption — center text, dark background, subtle terminal aesthetic
**TTS:** "The exact words that appear on screen."
**Status:** [ ] visual [ ] audio [ ] approved

Generate with ffmpeg drawtext on a black/dark background with monospace font and ALLMIND gold (#C5A55A) text:

TEXT="Your TTS sentence here"
ffmpeg -f lavfi -i color=c=black:s=1920x1080:d=6:r=25 \
  -vf "drawtext=text='${TEXT}':fontsize=42:fontcolor='#C5A55A':fontfile=/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf:x=(w-tex

관련 스킬