ForgeCut: Advanced User Guide

Everything you need to expand the engine with custom shaders, HTML motion graphics, VST3 plugins, and AI tools.

1. Asset Folders (Where to drop your files)

ForgeCut dynamically loads custom effects, visualizers, HTML templates, and transitions on startup.

🖥️ For Windows Users

Simply open the folder where ForgeCut.exe is located. You will see several folders (effects, visualizers, transitions, templates, presets). Drop your custom files directly into these folders and restart the app.

🐧 For Linux (AppImage) Users

Because Linux .AppImage files act like read-only compressed zip files, the application cannot read new folders placed "next to" the AppImage. To add custom assets on Linux, you must extract the AppImage into a portable folder:

  1. Open your terminal and extract the AppImage: ./Forge_Cut-x86_64.AppImage --appimage-extract
  2. This creates a folder named squashfs-root. Rename this to ForgeCut.
  3. Open ForgeCut/usr/bin/. This is your true application directory.
  4. Place your folders (like effects and templates) inside this bin directory.
  5. To launch the app, double-click the AppRun file inside the ForgeCut folder.

2. Custom GLSL Shaders & Visualizers

ForgeCut allows you to write your own GPU shaders (or download them from Shadertoy) and drop them into the app. They will automatically appear in the UI.

Supported Folders:
  • /effects - Shows up in the "Effects Library" panel.
  • /visualizers - Shows up in the "Audio Tools -> Audio Visualizer" dropdown.
  • /transitions - Shows up in the "Effects Library" under Transitions.
Basic Shader Syntax (.frag or .glsl)

ForgeCut automatically provides the following uniforms to your shaders:

uniform sampler2D texRGB;   // (The video frame)
uniform float iTime;        // (Playback time in seconds)
uniform vec2 iResolution;   // (Canvas width and height)
uniform vec3 iAudio;        // (Live audio reactivity! x = Bass, y = Mids, z = Treble)
varying vec2 vTexCoord;     // (UV coordinates, 0.0 to 1.0)

// --- ADVANCED UNIFORMS ---
uniform float opacity;      // IMPORTANT: Multiply your final gl_FragColor by this to support timeline fading!
varying vec2 vFragCoord;    // (Absolute pixel coordinates, identical to Shadertoy's gl_FragCoord.xy)
uniform vec2 texRes;        // (Alias for iResolution)

* Note: For Transitions, use sampler2D texA, sampler2D texB, and float progress instead of texRGB and iTime.

The Truth About Audio Reactivity (Built-in Magic)

You do not need to write complex dampening or smoothing math for your audio visualizers. ForgeCut's C++ Audio Engine pre-processes the FFT data for you before it reaches the shader:

  • Global Normalization: 1.0 represents the absolute loudest peak in the entire song. It will never clip.
  • EMA Smoothing: An Exponential Moving Average (Alpha 0.3) is pre-applied for buttery smooth reactivity.
  • Algorithmic Sync: The engine shifts the audio data back by exactly 83ms to perfectly counteract FFT latency, meaning your visualizer hits exactly on the drum kick.
Option A: The Legacy 3-Band System (Simple)

In older versions, or for quick & dirty visualizers, you can use a simple vec3 where x = Bass, y = Mids, and z = Highs.

uniform vec3 iAudio;

void main() {
    vec4 video = texture2D(texRGB, vTexCoord);
    // Flash the screen red to the bass!
    gl_FragColor = mix(video, vec4(1.0, 0.0, 0.0, 1.0), iAudio.x) * opacity;
}
Option B: The Advanced 64-Band Spectrum (Pro)

You now have access to an array of 64 distinct frequency bins, from deep sub-bass [0] to high treble [63]. Due to GLSL limits, dynamic array indexing requires a helper function. Paste this boilerplate into your shaders for buttery-smooth frequency interpolation:

uniform float iAudioSpectrum[64];

// 1. Safe Array Access
float getAudioRaw(int idx) {
    if(idx==0) return iAudioSpectrum[0]; else if(idx==1) return iAudioSpectrum[1];
    else if(idx==2) return iAudioSpectrum[2]; else if(idx==3) return iAudioSpectrum[3];
    else if(idx==4) return iAudioSpectrum[4]; else if(idx==5) return iAudioSpectrum[5];
    else if(idx==6) return iAudioSpectrum[6]; else if(idx==7) return iAudioSpectrum[7];
    else if(idx==8) return iAudioSpectrum[8]; else if(idx==9) return iAudioSpectrum[9];
    else if(idx==10) return iAudioSpectrum[10]; else if(idx==11) return iAudioSpectrum[11];
    else if(idx==12) return iAudioSpectrum[12]; else if(idx==13) return iAudioSpectrum[13];
    else if(idx==14) return iAudioSpectrum[14]; else if(idx==15) return iAudioSpectrum[15];
    else if(idx==16) return iAudioSpectrum[16]; else if(idx==17) return iAudioSpectrum[17];
    else if(idx==18) return iAudioSpectrum[18]; else if(idx==19) return iAudioSpectrum[19];
    else if(idx==20) return iAudioSpectrum[20]; else if(idx==21) return iAudioSpectrum[21];
    else if(idx==22) return iAudioSpectrum[22]; else if(idx==23) return iAudioSpectrum[23];
    else if(idx==24) return iAudioSpectrum[24]; else if(idx==25) return iAudioSpectrum[25];
    else if(idx==26) return iAudioSpectrum[26]; else if(idx==27) return iAudioSpectrum[27];
    else if(idx==28) return iAudioSpectrum[28]; else if(idx==29) return iAudioSpectrum[29];
    else if(idx==30) return iAudioSpectrum[30]; else if(idx==31) return iAudioSpectrum[31];
    else if(idx==32) return iAudioSpectrum[32]; else if(idx==33) return iAudioSpectrum[33];
    else if(idx==34) return iAudioSpectrum[34]; else if(idx==35) return iAudioSpectrum[35];
    else if(idx==36) return iAudioSpectrum[36]; else if(idx==37) return iAudioSpectrum[37];
    else if(idx==38) return iAudioSpectrum[38]; else if(idx==39) return iAudioSpectrum[39];
    else if(idx==40) return iAudioSpectrum[40]; else if(idx==41) return iAudioSpectrum[41];
    else if(idx==42) return iAudioSpectrum[42]; else if(idx==43) return iAudioSpectrum[43];
    else if(idx==44) return iAudioSpectrum[44]; else if(idx==45) return iAudioSpectrum[45];
    else if(idx==46) return iAudioSpectrum[46]; else if(idx==47) return iAudioSpectrum[47];
    else if(idx==48) return iAudioSpectrum[48]; else if(idx==49) return iAudioSpectrum[49];
    else if(idx==50) return iAudioSpectrum[50]; else if(idx==51) return iAudioSpectrum[51];
    else if(idx==52) return iAudioSpectrum[52]; else if(idx==53) return iAudioSpectrum[53];
    else if(idx==54) return iAudioSpectrum[54]; else if(idx==55) return iAudioSpectrum[55];
    else if(idx==56) return iAudioSpectrum[56]; else if(idx==57) return iAudioSpectrum[57];
    else if(idx==58) return iAudioSpectrum[58]; else if(idx==59) return iAudioSpectrum[59];
    else if(idx==60) return iAudioSpectrum[60]; else if(idx==61) return iAudioSpectrum[61];
    else if(idx==62) return iAudioSpectrum[62]; else if(idx==63) return iAudioSpectrum[63];
    return 0.0;
}

// 2. Ping-Pong utility
float pingPong(float x) { return abs(mod(x + 1.0, 2.0) - 1.0); }

// 3. Smooth Cubic Interpolation
float getAudio(float t) {
    t = pingPong(t); 
    float fIdx = t * 40.0; // Map 't' to lower 40 bins for visual punch
    
    int i = int(fIdx); float f = fract(fIdx);
    
    int i0 = int(max(0.0, float(i - 1))); int i1 = i;
    int i2 = int(min(63.0, float(i + 1))); int i3 = int(min(63.0, float(i + 2)));
    
    float v0 = getAudioRaw(i0); float v1 = getAudioRaw(i1);
    float v2 = getAudioRaw(i2); float v3 = getAudioRaw(i3);
    
    float p0 = (v2 - v0) * 0.5; float p1 = (v3 - v1) * 0.5;
    float t2 = f * f; float t3 = f * t2;
    
    float val = (2.0 * t3 - 3.0 * t2 + 1.0) * v1 + (t3 - 2.0 * t2 + f) * p0 + (-2.0 * t3 + 3.0 * t2) * v2 + (t3 - t2) * p1;
    return max(0.0, val);
}

// 4. Kernel Smoothing
float getSmoothedAudio(float t) {
    float sum = 0.0; float spread = 0.025;
    sum += getAudio(t - spread * 3.0) * 0.05; sum += getAudio(t - spread * 2.0) * 0.10;
    sum += getAudio(t - spread * 1.0) * 0.20; sum += getAudio(t)                * 0.30;
    sum += getAudio(t + spread * 1.0) * 0.20; sum += getAudio(t + spread * 2.0) * 0.10;
    sum += getAudio(t + spread * 3.0) * 0.05;
    return sum;
}

Usage: Pass a normalized angle (0.0 to 1.0) into the smoothed function to generate a circular spectrum!

void main() {
    vec2 uv = vTexCoord;
    vec2 delta = uv - vec2(0.5);
    delta.x *= iResolution.x / iResolution.y; // Aspect correction
    
    float r = length(delta);
    float theta = atan(delta.y, delta.x); 
    float normalizedAngle = abs(theta) / 3.14159265;
    
    // Fetch smooth audio reactivity for this angle
    float audioReactivity = getSmoothedAudio(normalizedAngle);
    float circleRadius = 0.2 + (audioReactivity * 0.3);
    
    vec3 color = vec3(0.0);
    if (r < circleRadius) color = vec3(0.0, 1.0, 0.5); // Neon Green
    
    gl_FragColor = vec4(color, 1.0) * opacity;
}
How to Auto-Generate UI Sliders & Inputs

ForgeCut parses special comments in your shader file and builds the UI automatically!

// @param float mySliderName 0.0 100.0 50.0
uniform float mySliderName;

// @param image dirtOverlay
uniform sampler2D dirtOverlay;

The @param image syntax creates a dropdown allowing the user to select any image from their Media Bin to feed directly into your shader.

Advanced: Multi-Pass & 3D LUTs (manifest.json)

For cinematic effects, you can create a Folder instead of a single file, and include a manifest.json. This allows you to run multiple shaders in sequence and load .cube 3D LUTs or local PNGs automatically!

// manifest.json
{
    "name": "Cinematic Look",
    "parameters": [
        { "name": "lutIntensity", "min": 0.0, "max": 1.0, "default": 1.0 }
    ],
    "assets": {
        "myLUT": "teal_orange.cube",
        "filmGrain": "grain.png"
    },
    "passes": ["colorgrade.frag"]
}

ForgeCut will automatically inject your assets as local_ prefixed uniforms. 3D LUTs are automatically mapped to sampler3D.

// colorgrade.frag
uniform sampler3D local_myLUT;     
uniform sampler2D local_filmGrain; 
uniform float lutIntensity;        

void main() {
    vec4 video = texture2D(texRGB, vTexCoord);
    vec4 graded = texture3D(local_myLUT, video.rgb); // 3D LUT Color Grading!
    gl_FragColor = mix(video, graded, lutIntensity) * opacity;
}

3. Titles & Text Presets

ForgeCut features a dynamic text generator capable of typewriter effects, rolling credits, and Karaoke-style word highlighting.

Creating a Preset
  1. In the Transport Bar (below the Preview Monitor), click the "Add Text Generator" (T) button.
  2. Edit the text to your liking (e.g., set up your font, shadow, outline, and animation speed).
  3. Right-click the new Text Clip on the timeline.
  4. Select "Save as Text Preset".
  5. Name it. It will now permanently appear in the "Titles and Presets" dock on the left side of the screen!

* Advanced: Presets are saved as .fctext JSON files in the /presets folder. You can easily share these files with other users.

4. AI Subtitles & Audio Tools

AI Auto-Subtitles (Whisper)

ForgeCut can automatically transcribe audio and generate animated, karaoke-style subtitles.

  1. Select an audio or video clip containing speech on the timeline.
  2. Open the Audio Tools panel on the right.
  3. Click Auto-Subtitle with AI. (The Whisper AI model is pre-packaged with the editor, so no extra downloads are required!)

Translation Tip: You can export generated subtitles via File -> Export Texts as SRT, translate them using external tools, and bring them back using File -> Import Translated SRT.

Auto-Silence Remover (Jump Cuts)

Instantly remove dead air, long breaths, and pauses from your talking-head videos.

  1. Select a clip with audio and open the Audio Tools panel.
  2. Adjust the Volume Threshold (e.g., 2%) and Min Duration (e.g., 0.5s).
  3. Click Analyze Selected Clip to detect all silent regions.
  4. Ensure Ripple (Collapse Gaps) is checked.
  5. Click Remove Selected Silences. ForgeCut will automatically slice the clip and ripple-delete the gaps!

5. Advanced Plugins (VST3 & Native Video)

VST3 Audio Plugins

ForgeCut supports commercial DAWs plugins (EQs, Compressors, Reverbs).

  • Select an Audio clip, go to Audio Tools, and click Load VST3 Plugin.
  • Check the "⏱ Automate" box in the Effect Controls panel to record live knob twists from the VST UI into timeline keyframes!
Native Video Plugins (.dll or .so)

If GLSL isn't powerful enough, developers can write raw C++ plugins (OpenCV, AI upscaling, etc.).

  • Select a Video clip, go to Effect Controls, and click Load Native Video Plugin.
  • UI sliders will be automatically generated based on the C++ SDK exports.

6. Object Tracking & Action Sync

Auto Object Tracking (AI Framing)
  1. Select a video clip and open the Effect Controls panel.
  2. Click Start Object Tracking.
  3. In the Preview Monitor, click and drag a line across the object you want to track (drawing a line provides scale and rotation data to the tracker).
  4. The tracker will analyze forward and backward.
  5. Change the Action dropdown to Center Object to automatically stabilize shaky footage around the tracked point.
Manual Tracking (The Pivot Tool)

If auto-tracking fails, or you just want precise manual control, you can track objects by hand:

  1. Select a clip and click Manual Tracking (Pivot Tool) in the Effect Controls (or press Shift+T).
  2. An orange target ring will appear on the Preview Monitor. Drag it over your subject.
  3. Move the playhead forward on the timeline and continuously reposition the orange ring over your moving subject. ForgeCut automatically generates keyframes for every adjustment!
  4. Change the Action dropdown to Center Object to instantly stabilize the footage around your manually tracked points. You can then use standard Scale and Position controls to reframe the stabilized shot.
Action Beat Sync (Velocity Ramping)

Want to sync a punch, jump, or gunshot perfectly to a music beat?

  1. Open the Audio Tools panel -> Action Beat Sync.
  2. Move the playhead to where the action starts in your video, click Set IN.
  3. Move to where the action ends, click Set OUT.
  4. Click Slice & Sync. ForgeCut will analyze the bass transients in your audio track, slice your video, and alter the playback speed (1.5x, 0.4x, etc.) so the action happens exactly on the beat.

7. Performance, Pro-Tips & Hidden Shortcuts

  • Proxy Generation (Smooth 4K Editing): ForgeCut automatically generates lightweight H.264 proxies for your heavy 4K videos in the background as soon as they are imported. Look at the colored bar at the bottom of your video clips on the timeline: Orange means it's generating, Green means the proxy is ready for buttery smooth playback!
  • Optical Flow Slow-Mo: Right-click a clip -> Time Interpolation -> Optical Flow. This uses FFmpeg to artificially hallucinate frames, turning choppy 30fps footage into buttery-smooth slow motion. (It will display a Purple bar when ready).
  • Auto-Fill Black Bars: If you import vertical phone footage into a widescreen project, go to Effect Controls and click Auto-Fill Black Bars. ForgeCut will automatically calculate the exact scale needed to remove the black borders without distorting the image.
  • Middle-Mouse Drag: Click and drag the middle mouse button on the Preview Monitor to pan around the canvas. Middle-Mouse Double-Click to instantly "Fit" the video back to the screen.
  • Clip Masks: Need a picture-in-picture circle or split screen? Select a clip, go to Effect Controls, and add a Rectangle or Ellipse mask. You can invert it, feather the edges, and animate its position!
  • Shift + Scroll Wheel: Zooms the preview monitor by snapping perfectly to 25%, 50%, 100% scales.
  • Smart Snapping: By default, clips snap to each other. Hold SHIFT while dragging a clip or the playhead to temporarily disable snapping for frame-perfect placement.
  • Virtual Color Generators: Right-click inside the Media Bin to instantly generate "Solid Colors" or "Transparent Objects". These are processed mathematically without using any disk space!

8. HTML Motion Graphics & Web Templates

ForgeCut features an embedded Chromium browser that renders standard HTML/CSS/JS directly over your video with full transparency. This is perfect for animated Lower Thirds, dynamic Twitch/TikTok overlays, and data-driven motion graphics.

The Required Files

Create a new folder inside your templates directory (e.g., /templates/my_overlay/) and add two files:

  • index.html: Your actual webpage, styling, and JavaScript logic.
  • manifest.json: Tells ForgeCut what sliders, text boxes, and color pickers to generate in the UI.
1. The Manifest (manifest.json)
{
    "name": "Modern Lower Third",
    "defaultDuration": 5.0,
    "parameters": [
        { "name": "MainText", "type": "string", "defaultString": "JOHN DOE" },
        { "name": "BoxColor", "type": "color", "defaultColor": "#2a82da" },
        { "name": "Scale", "type": "float", "min": 0.5, "max": 2.0, "default": 1.0 }
    ]
}
2. The HTML & JavaScript (index.html)

ForgeCut communicates with your HTML file by automatically calling specific JavaScript functions. You just need to define them:

  • setWebParameters(jsonStr): Called when a user types text, picks a color, or scrubs a slider. Also provides live audio data.
  • seekTime(time): Called every frame. Provides the current timeline time in seconds so you can trigger CSS animations.
<!DOCTYPE html>
<html>
<head>
    <style>
        /* IMPORTANT: Ensure background is transparent so video shows through! */
        body { margin: 0; overflow: hidden; background: transparent; color: white; font-family: sans-serif; }
        #my-box { padding: 20px; font-size: 50px; display: inline-block; transition: transform 0.1s; }
    </style>
</head>
<body>
    <div id="my-box">Loading...</div>

    <script>
        // ForgeCut calls this when UI parameters or audio levels change
        function setWebParameters(jsonStr) {
            const params = JSON.parse(jsonStr);
            
            let box = document.getElementById('my-box');
            
            // Apply UI Parameters
            if (params.MainText !== undefined) box.innerText = params.MainText;
            if (params.BoxColor !== undefined) box.style.background = params.BoxColor;
            if (params.Scale !== undefined) box.style.transform = `scale(${params.Scale})`;

            // LIVE AUDIO REACTIVITY (Optional)
            // params.AudioLevels contains [Bass, Mids, Treble] (0.0 to 1.0)
            if (params.AudioLevels !== undefined) {
                let bass = params.AudioLevels[0];
                box.style.transform = `scale(${params.Scale + bass})`; // Pump to the beat!
            }
        }

        // ForgeCut calls this every frame
        function seekTime(time) {
            // e.g., Fade in after 1 second
            document.getElementById('my-box').style.opacity = time > 1.0 ? 1 : 0;
        }
    </script>
</body>
</html>
Audio Reactivity & WebGL (Advanced)

If your HTML template overlaps with an audio clip on the timeline, the jsonStr payload automatically includes an AudioSpectrum array containing 64 frequency bins. This allows you to easily build highly complex Canvas or WebGL audio visualizers in Javascript (using Three.js, p5.js, etc.) without writing a single line of C++ or GLSL backend code!

9. Native C++ Plugin SDK Developer Guide

If GLSL shaders aren't powerful enough for your needs, ForgeCut features a bare-metal C++ Plugin API. This allows you to write custom .dll (Windows) or .so (Linux) files that directly manipulate the ForgeCut video buffer in RAM using C++ libraries like OpenCV, Eigen, or LibTorch.

The SDK Header

To create a plugin, create a new C++ Shared Library project and include this exact header file (which defines the ForgeCut ABI bridge):

// FastNLE_VideoPlugin.h
#pragma once
#include <stdint.h>

#ifdef _WIN32
    #define FASTNLE_PLUGIN_API __declspec(dllexport)
#else
    #define FASTNLE_PLUGIN_API __attribute__((visibility("default")))
#endif

extern "C" {
    struct FastNLE_ParamInfo {
        const char* name;
        float minValue;
        float maxValue;
        float defaultValue;
    };

    // 1. Return the UI display name
    FASTNLE_PLUGIN_API const char* GetPluginName();
    
    // 2. Define how many sliders your UI needs
    FASTNLE_PLUGIN_API int GetParameterCount();
    
    // 3. Configure the name and bounds of each slider
    FASTNLE_PLUGIN_API void GetParameterInfo(int index, FastNLE_ParamInfo* outInfo);
    
    // 4. The Main Render Loop
    FASTNLE_PLUGIN_API void ProcessVideoFrame(uint8_t* rgbaBuffer, int width, int height, float time, const float* paramValues);
    
    // 5. Cleanup when the user deletes the effect
    FASTNLE_PLUGIN_API void ReleasePlugin();
}
How the Pipeline Works

When a user loads your plugin into ForgeCut, the engine automatically interrogates GetParameterCount and GetParameterInfo to build keyframe-able sliders in the Effect Controls panel.

During playback, ForgeCut calls ProcessVideoFrame up to 60 times a second.

  • rgbaBuffer: A raw 1D array of pixels. The format is strictly RGBA (8-bit per channel).
  • Top-Down Orientation: Even though ForgeCut uses OpenGL (Bottom-Up) internally, the engine automatically flips the buffer to standard Top-Down orientation before passing it to your C++ plugin, meaning (0,0) is exactly the Top-Left pixel.
  • paramValues: A float array containing the live, keyframed slider values for this exact frame, matching the index order you provided in GetParameterInfo.
Limitations & Best Practices
  1. In-Place Modification: The ProcessVideoFrame function does not give you a separate input and output buffer. You must modify the rgbaBuffer in-place. If your algorithm requires a separate source, you must allocate a temporary buffer inside your plugin, copy the data, process it, and write it back.
  2. CPU Bottlenecks: Because this plugin runs on the CPU, heavy single-threaded math will cause ForgeCut's playback to lag. You are highly encouraged to use std::thread or #pragma omp parallel for (OpenMP) inside your ProcessVideoFrame function to utilize all CPU cores.
  3. Thread Safety: ForgeCut guarantees that ProcessVideoFrame is called synchronously for a single clip. However, if the user applies your plugin to two different clips simultaneously, the engine may call your plugin from two different threads at once. Avoid using global or static variables for rendering state.
  4. Memory Management: Always use the ReleasePlugin() function to delete or free any heavy memory allocations or AI models your plugin loads.
Example: A Simple C++ Color Inverter

Here is a complete, compilable example of a plugin that inverts colors and blends it based on a UI slider:

#include "FastNLE_VideoPlugin.h"
#include <algorithm>

const char* GetPluginName() { return "C++ Color Inverter"; }

int GetParameterCount() { return 1; }

void GetParameterInfo(int index, FastNLE_ParamInfo* outInfo) {
    if (index == 0) {
        outInfo->name = "Blend Amount";
        outInfo->minValue = 0.0f;
        outInfo->maxValue = 1.0f;
        outInfo->defaultValue = 1.0f;
    }
}

void ProcessVideoFrame(uint8_t* rgbaBuffer, int width, int height, float time, const float* paramValues) {
    float blend = paramValues[0];
    int totalPixels = width * height;
    
    // Simple pixel manipulation (Recommended to multi-thread this loop!)
    for (int i = 0; i < totalPixels; ++i) {
        int idx = i * 4;
        
        uint8_t r = rgbaBuffer[idx];
        uint8_t g = rgbaBuffer[idx + 1];
        uint8_t b = rgbaBuffer[idx + 2];
        
        // Invert and blend
        rgbaBuffer[idx]     = r + ( (255 - r) - r ) * blend;
        rgbaBuffer[idx + 1] = g + ( (255 - g) - g ) * blend;
        rgbaBuffer[idx + 2] = b + ( (255 - b) - b ) * blend;
        // rgbaBuffer[idx + 3] is Alpha. We leave it alone.
    }
}

void ReleasePlugin() {
    // Free any allocated memory here
}