BandsEffectLib — Horizontal Bands Effect
Adds GPU-accelerated horizontal bands (scanlines) over any visual control, producing the look of a CRT monitor, VHS playback, or retro television. The effect wraps FireMonkey’s TBandsEffect with two simple properties: density (how many lines) and intensity (how visible they are). Perfect for vintage aesthetics, retro game overlays, and nostalgic photo filters. 14 functions.
| Category | Count | Description |
|---|---|---|
| Error Handling | 4 | bands_error, errormsg$, strerror$, clearerror |
| Creation & Destruction | 2 | bands# (create), bands_free (destroy) |
| Band Properties | 4 | density, intensity (get/set) |
| Effect Control | 4 | enabled, trigger (get/set) |
BandsEffectLib applies the same concept as a GPU filter on any Plan9Basic visual control.Cross-Platform Support
| Platform | Status | Notes |
|---|---|---|
| Windows | ✅ Full Support | GPU-accelerated via Direct2D |
| Linux | ✅ Full Support | Software rendering fallback |
| Android | ✅ Full Support | GPU-accelerated |
Error Handling
All functions set an error code on failure. Check with bands_error() after operations. Error code 0 means success.
| Function | Signature | Description |
|---|---|---|
bands_error() | bands_error@ | Returns last error code (0 = no error) |
bands_errormsg$() | bands_errormsg$@ | Returns last error message as string |
bands_strerror$(code) | bands_strerror$@n | Converts an error code to descriptive text |
bands_clearerror() | bands_clearerror@ | Clears the error state |
Error Codes
| Code | Constant | Meaning |
|---|---|---|
| 0 | ERR_NONE | No error |
| 1 | ERR_NIL_EFFECT | Effect pointer is nil |
| 2 | ERR_INVALID_EFFECT | Pointer is not a valid TBandsEffect |
| 3 | ERR_INVALID_VALUE | Property value out of range |
| 4 | ERR_NIL_PARENT | Parent control pointer is nil |
| 5 | ERR_INVALID_PARENT | Pointer is not a valid TFmxObject |
Creation & Destruction
| Function | Signature | Description |
|---|---|---|
bands#(parent#) | bands#@# | Creates a bands effect attached to the given control. Returns the effect pointer. |
bands_free(effect#) | bands_free@# | Destroys the effect and removes it from the parent control. |
The parent# can be any visual control. The effect is applied immediately with default values (density 50, intensity 0.5).
' Create bands effect on an image let bnd# = bands#(img#) ' Later, remove the effect bands_free(bnd#)
Band Properties
Density
Controls the number of horizontal bands drawn across the control. Higher values create finer, closer-together scanlines. Default is 50.
| Function | Signature | Description |
|---|---|---|
bands_density#(effect#, value) | bands_density#@#n | Sets number of bands |
bands_density(effect#) | bands_density@# | Gets current density |
| Density | Visual Effect | Use Case |
|---|---|---|
| 10–25 | Wide, clearly visible stripes | Dramatic retro overlay, VHS glitch art |
| 30–60 | Medium scanlines (default range) | Classic CRT monitor look |
| 75–120 | Fine, subtle lines | High-resolution CRT, subtle vintage |
| 150+ | Very fine, almost like a texture | Subtle film grain alternative |
Intensity
Controls the visibility/opacity of the bands. A value of 0.0 makes them invisible; 1.0 makes them fully opaque (solid black stripes). Default is 0.5.
| Function | Signature | Description |
|---|---|---|
bands_intensity#(effect#, value) | bands_intensity#@#n | Sets intensity (0.0–1.0) |
bands_intensity(effect#) | bands_intensity@# | Gets current intensity |
| Intensity | Visual Effect |
|---|---|
| 0.0 | Invisible — no bands visible |
| 0.1–0.3 | Subtle — barely visible overlay, good for photos |
| 0.3–0.5 | Moderate — clearly visible CRT look (default range) |
| 0.5–0.8 | Strong — prominent dark bands |
| 1.0 | Maximum — solid black stripes alternating with image |
' CRT monitor look bands_density#(bnd#, 75) bands_intensity#(bnd#, 0.3) ' Heavy VHS distortion look bands_density#(bnd#, 15) bands_intensity#(bnd#, 0.7) ' Subtle film grain alternative bands_density#(bnd#, 150) bands_intensity#(bnd#, 0.15)
Effect Control
Enabled
Toggles the effect on or off without destroying it. When disabled, the control renders as if the effect does not exist.
| Function | Signature | Description |
|---|---|---|
bands_enabled#(effect#, value) | bands_enabled#@#n | Enables (1) or disables (0) the effect |
bands_enabled(effect#) | bands_enabled@# | Gets enabled state (1 = on, 0 = off) |
Trigger
The trigger property is a string used by FireMonkey’s animation system. Primarily used for integration with animation components.
| Function | Signature | Description |
|---|---|---|
bands_trigger#(effect#, trigger$) | bands_trigger#@#$ | Sets trigger string |
bands_trigger$(effect#) | bands_trigger$@# | Gets current trigger string |
Complete Examples
CRT Scanline Effect
Applies a classic CRT monitor scanline overlay to an image.
let frm# = Pointer#(0) let img# = Pointer#(0) let bnd# = Pointer#(0) frm# = form#("Scanline Effect", 400, 350) img# = image#(frm#) image_bounds#(img#, 100, 30, 200, 150) image_load#(img#, "https://picsum.photos/200/150") ' Create bands effect - CRT style bnd# = bands#(img#) bands_density#(bnd#, 75) bands_intensity#(bnd#, 0.3) form_show(frm#)
Interactive Density & Intensity Controls
Two trackbars for real-time adjustment of density and intensity.
let frm# = Pointer#(0) let img# = Pointer#(0) let bnd# = Pointer#(0) let trkDens# = Pointer#(0) let trkInt# = Pointer#(0) let lblDens# = Pointer#(0) let lblInt# = Pointer#(0) frm# = form#("Bands Control", 450, 420) img# = image#(frm#) image_bounds#(img#, 125, 20, 200, 150) image_load#(img#, "https://picsum.photos/200/150") bnd# = bands#(img#) bands_density#(bnd#, 50) bands_intensity#(bnd#, 0.5) ' Density slider lblDens# = label#(frm#, "Density: 50", 50, 190) trkDens# = trackbar#(frm#) trackbar_bounds#(trkDens#, 50, 220, 350, 30) trackbar_max#(trkDens#, 200) trackbar_value#(trkDens#, 50) trackbar_onchange#(trkDens#, "OnDensChange") ' Intensity slider lblInt# = label#(frm#, "Intensity: 0.50", 50, 270) trkInt# = trackbar#(frm#) trackbar_bounds#(trkInt#, 50, 300, 350, 30) trackbar_max#(trkInt#, 100) trackbar_value#(trkInt#, 50) trackbar_onchange#(trkInt#, "OnIntChange") form_show(frm#) function OnDensChange(sender#) local d let d = trackbar_value(trkDens#) bands_density#(bnd#, d) label_text#(lblDens#, "Density: " + str$(d)) endfunction function OnIntChange(sender#) local i let i = trackbar_value(trkInt#) / 100 bands_intensity#(bnd#, i) label_text#(lblInt#, "Intensity: " + stri$(i, 2)) endfunction
Toggle Effect On/Off
A button toggles the bands effect without destroying it.
let frm# = Pointer#(0) let img# = Pointer#(0) let bnd# = Pointer#(0) let btn# = Pointer#(0) let isOn = 1 frm# = form#("Toggle Bands", 400, 300) img# = image#(frm#) image_bounds#(img#, 100, 30, 200, 150) image_load#(img#, "https://picsum.photos/200/150") bnd# = bands#(img#) bands_density#(bnd#, 100) bands_intensity#(bnd#, 0.4) btn# = button#(frm#, "Disable Effect") button_bounds#(btn#, 140, 210, 120, 30) button_onclick#(btn#, "Toggle") form_show(frm#) function Toggle(sender#) if isOn = 1 then bands_enabled#(bnd#, 0) isOn = 0 button_text#(btn#, "Enable Effect") else bands_enabled#(bnd#, 1) isOn = 1 button_text#(btn#, "Disable Effect") endif endfunction
Best Practices
| Practice | Why |
|---|---|
| Use density 50–100 with intensity 0.2–0.4 for CRT look | The classic scanline sweet spot — visible but not overwhelming |
| Use low density (10–20) with high intensity for VHS glitch | Creates bold, dramatic horizontal stripes for distressed effects |
| Use high density (150+) with low intensity for subtle texture | Works as a film-grain alternative without masking the image |
Combine with SepiaEffectLib for vintage photos | Sepia + scanlines = convincing old TV or vintage camera look |
Combine with MonochromeEffectLib for B&W CRT | Monochrome + bands = classic black-and-white television |
Use bands_enabled# to toggle instead of bands_free | Faster than destroying and recreating for on/off scenarios |
Animate intensity with FloatAnimationLib | Pulsating intensity creates a “signal interference” effect |
| Scale density relative to control height | A 300px image needs more bands than a 100px image for the same visual density |
Quick Reference
| Function | Signature | Description |
|---|---|---|
| ERROR HANDLING | ||
bands_error() | bands_error@ | Last error code |
bands_errormsg$() | bands_errormsg$@ | Last error message |
bands_strerror$(code) | bands_strerror$@n | Error code to text |
bands_clearerror() | bands_clearerror@ | Clear error state |
| CREATION & DESTRUCTION | ||
bands#(parent#) | bands#@# | Create effect on control |
bands_free(effect#) | bands_free@# | Destroy effect |
| BAND PROPERTIES | ||
bands_density#(effect#, val) | bands_density#@#n | Set band count |
bands_density(effect#) | bands_density@# | Get band count |
bands_intensity#(effect#, val) | bands_intensity#@#n | Set intensity (0.0–1.0) |
bands_intensity(effect#) | bands_intensity@# | Get intensity |
| EFFECT CONTROL | ||
bands_enabled#(effect#, val) | bands_enabled#@#n | Enable (1) / disable (0) |
bands_enabled(effect#) | bands_enabled@# | Get enabled state |
bands_trigger#(effect#, str$) | bands_trigger#@#$ | Set trigger string |
bands_trigger$(effect#) | bands_trigger$@# | Get trigger string |
14 functions. Part of the Plan9Basic visual effects library system.
See Also
- PixelateEffectLib — Pixelation effect for retro 8-bit look
- SepiaEffectLib — Sepia tone for vintage photo style
- MonochromeEffectLib — Monochrome/grayscale conversion
- ToonEffectLib — Cartoon/posterize effect
- FloatAnimationLib — Animate intensity for pulsating scanline effects