Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ntsc-rs/ntsc-rs/llms.txt

Use this file to discover all available pages before exploring further.

The NTSC composite signal encodes luma (brightness) and chroma (color) together on the same waveform, then separates them again on the receiving end. ntsc-rs simulates this entire pipeline — from how the input image is split into fields, through luma and chroma filtering and modulation, all the way to the output lowpass that softens the decoded color signal. The parameters on this page control every stage of that luma/chroma path, and small changes to them produce dramatically different looks ranging from sharp broadcast quality to severely degraded off-air reception.

Field and filter selection

use_field
UseField enum
default:"4 (InterleavedUpper)"
Determines which rows (“fields” in NTSC terminology) of the source image are processed each frame. NTSC video is interlaced — each frame contains two interleaved fields captured at slightly different times.
ValueVariantBehavior
0AlternatingAlternate between skipping even and odd rows each frame.
1UpperKeep only the upper (even-numbered) rows; skip the lower ones.
2LowerKeep only the lower (odd-numbered) rows; skip the upper ones.
3BothUse all rows — no rows are skipped.
4InterleavedUpperTreat the source as interlaced; upper field is the earlier frame. (default)
5InterleavedLowerTreat the source as interlaced; lower field is the earlier frame.
JSON key: "use_field"
filter_type
FilterType enum
default:"1 (Butterworth)"
Selects the low-pass filter design used throughout the entire effect pipeline.
ValueVariantBehavior
0ConstantKSimple constant-k ladder filter. Produces a softer, blurrier result with a gradual rolloff.
1ButterworthMaximally flat Butterworth filter. Sharper cutoff with less blur, more characteristic of real broadcast equipment. (default)
JSON key: "filter_type"

Input luma processing

input_luma_filter
LumaLowpass enum
default:"2 (Notch)"
Pre-filters the luminance signal before it is modulated onto the composite carrier. This step reduces “rainbow” color fringing artifacts that arise when fine luma detail bleeds into the chroma band.
ValueVariantBehavior
0NoneNo filtering. Preserves all luma detail but introduces rainbow artifacts.
1BoxSimple box (averaging) filter on the luma signal. Soft and artifact-free.
2NotchNotch filter centered on the color subcarrier frequency. Sharper than box, but may introduce mild ringing. (default)
JSON key: "input_luma_filter"
luma_smear
f32
default:"0.5"
Smears (low-pass filters) the luminance channel horizontally, simulating bandwidth limiting of the luma signal in lower-quality tape or transmission equipment. Higher values create a more pronounced horizontal blur on bright-to-dark transitions.
  • Range: 0.01.0
  • JSON key: "luma_smear"

Input chroma processing

chroma_lowpass_in
ChromaLowpass enum
default:"2 (Full)"
Applies a low-pass filter to the chrominance signal before it is encoded into the composite waveform. This limits the color bandwidth going into the simulated transmission, softening color edges.
ValueVariantBehavior
0NoneNo chroma filtering on input.
1LightMild low-pass — reduces color bandwidth slightly.
2FullFull-strength low-pass — strongly limits chroma bandwidth. (default)
JSON key: "chroma_lowpass_in"
chroma_demodulation
ChromaDemodulationFilter enum
default:"1 (Notch)"
The filter used to separate the chrominance signal from the composite waveform during demodulation. Different filter types produce very different color fringing and cross-color patterns.
ValueVariantBehavior
0BoxSimple horizontal box blur. Smooth color edges with some luma/chroma crosstalk.
1NotchNotch filter. Sharper separation, but may introduce ringing near color transitions. (default)
2OneLineCombAverages the current row with the previous row, phase-cancelling chroma. Requires video_scanline_phase_shift = 180°.
3TwoLineCombAverages the current row with the previous and next rows. Requires video_scanline_phase_shift = 180°. Best luma/chroma separation.
JSON key: "chroma_demodulation"

Composite signal sharpening

composite_sharpening
f32
default:"1.0"
Boosts high frequencies in the NTSC composite signal before demodulation, sharpening the image and making colors more vivid. Negative values soften the image; values above 1.0 produce an over-sharpened, “enhanced” broadcast look.
  • Range: -1.02.0
  • JSON key: "composite_preemphasis"
The JSON serialization key for this field is "composite_preemphasis", not "composite_sharpening". Using the wrong key will silently fall back to the default value when loading a preset.

Scanline phase shift

video_scanline_phase_shift
PhaseShift enum
default:"2 (Degrees180)"
The phase offset applied to the chroma subcarrier on each successive scanline. In standard NTSC, this is 180° — each line’s color carrier is inverted relative to the line above it. This alternation is what allows comb filters to separate luma from chroma.
ValueVariant
0Degrees0
1Degrees90
2Degrees180 (default)
3Degrees270
JSON key: "video_scanline_phase_shift"
OneLineComb and TwoLineComb demodulation filters only work correctly when this value is Degrees180 (2).
video_scanline_phase_shift_offset
i32
default:"0"
Shifts the starting line for the scanline phase alternation pattern. Adjusting this can change which lines receive which phase, which affects the color pattern produced by comb filters.
  • Range: 03
  • JSON key: "video_scanline_phase_shift_offset"

Chroma delay

chroma_delay_horizontal
f32
default:"0.0"
Shifts the decoded chroma signal horizontally relative to luma, in pixels. Positive values move color to the right; negative values move it to the left. This simulates the color registration errors common in consumer VHS playback, where chroma and luma paths have slightly different delays.
  • Range: -40.040.0
  • JSON key: "chroma_delay_horizontal"
chroma_delay_vertical
i32
default:"0"
Shifts the decoded chroma signal vertically relative to luma, in scanlines. A vertical chroma offset becomes more pronounced with each generation of VHS dubbing.
  • Range: -2020
  • JSON key: "chroma_delay_vertical"
chroma_phase_error
f32
default:"0.0"
Applies a static, constant phase error to the entire chroma signal. This rotates all colors in the image by a fixed hue offset, simulating a misaligned color burst reference on a TV or VCR. The value is a percentage of a full rotation (0.0 = no shift, 1.0 = 360°).
  • Range: 0.01.0 (percentage)
  • JSON key: "chroma_phase_error"

Output chroma processing

chroma_vert_blend
bool
default:"true"
When enabled, blends each scanline’s chroma signal with the scanline above it vertically. This emulates the chroma bandwidth limiting that occurs in VHS playback and cheap composite decoders, softening color transitions between lines. Automatically disabled in Easy Mode when VHS emulation is active.JSON key: "vhs_chroma_vert_blend"
chroma_lowpass_out
ChromaLowpass enum
default:"2 (Full)"
Applies a low-pass filter to the chroma signal after all processing is complete, before the final YIQ-to-RGB conversion. This is the output-side counterpart to chroma_lowpass_in.
ValueVariantBehavior
0NoneNo filtering.
1LightLight low-pass filter.
2FullFull-strength low-pass filter. (default)
JSON key: "chroma_lowpass_out"

Scale settings

The scale field is a SettingsBlock<ScaleSettings>. When disabled (the default), the effect uses the native pixel dimensions of the input. Enabling it allows you to scale the effect independently of the video resolution.
scale.enabled
bool
default:"false"
Enable or disable the scale block. When disabled, scaling factors are ignored.JSON key: "scale_settings"
scale.settings.horizontal_scale
f32
default:"1.0"
Scales all horizontal frequency-domain operations by this factor. At 1.0 the effect is calibrated for 480p video. Increase this value when working with higher-resolution sources to maintain physically accurate-looking results.
  • Range: 0.1258.0
  • JSON key: "bandwidth_scale"
The JSON key for this field is "bandwidth_scale", not "horizontal_scale". This name reflects its original purpose of scaling the effective signal bandwidth.
scale.settings.vertical_scale
f32
default:"1.0"
Scales vertical frequency-domain operations by this factor. In most cases this should be left at 1.0.
  • Range: 0.1258.8
  • JSON key: "vertical_scale"
scale.settings.scale_with_video_size
bool
default:"false"
When enabled, multiplies both scaling factors by the video’s height in pixels. This provides a rough approximation of resolution-independent scaling, but scaling the input to 480p first gives more accurate-looking results.JSON key: "scale_with_video_size"

Example preset (luma/chroma section)

{
  "version": 1,
  "use_field": 4,
  "filter_type": 1,
  "input_luma_filter": 2,
  "chroma_lowpass_in": 2,
  "chroma_demodulation": 1,
  "luma_smear": 0.5,
  "composite_preemphasis": 1.0,
  "video_scanline_phase_shift": 2,
  "video_scanline_phase_shift_offset": 0,
  "vhs_chroma_vert_blend": true,
  "chroma_lowpass_out": 2,
  "chroma_delay_horizontal": 0.0,
  "chroma_delay_vertical": 0,
  "chroma_phase_error": 0.0,
  "scale_settings": false,
  "bandwidth_scale": 1.0,
  "vertical_scale": 1.0,
  "scale_with_video_size": false
}

Build docs developers (and LLMs) love