Skip to content

Render Hooks

Lightweight customization through hooks that extend the default rendering pipeline

Render hooks provide a lightweight way to customize waveform rendering by injecting custom logic at specific points during the default rendering pipeline. Unlike custom renderers, hooks extend the built-in rendering behavior rather than replacing it entirely.

Render hooks allow you to “hook into” the rendering process at predefined points:

  1. beforeRender – Called before any rendering begins
  2. Default background rendering – Library renders the background waveform
  3. afterBackground – Called after background is rendered
  4. Default progress rendering – Library renders progress overlay (if progress > 0)
  5. afterProgress – Called after progress is rendered
  6. Default progress line rendering – Library renders progress line
  7. afterComplete – Called when all rendering is complete
interface RenderHook {
beforeRender?: (
ctx: CanvasRenderingContext2D,
cache: RenderCache,
options: Required<WaveformOptions>
) => void;
afterBackground?: (
ctx: CanvasRenderingContext2D,
cache: RenderCache,
options: Required<WaveformOptions>
) => void;
afterProgress?: (
ctx: CanvasRenderingContext2D,
cache: RenderCache,
options: Required<WaveformOptions>,
progress: number
) => void;
afterComplete?: (
ctx: CanvasRenderingContext2D,
cache: RenderCache,
options: Required<WaveformOptions>
) => void;
}
import { WaveformRenderer } from "waveform-renderer";
const waveform = new WaveformRenderer(canvas, peaks);
waveform.setRenderHooks({
afterComplete: (ctx, cache, options) => {
ctx.fillStyle = "rgba(0, 0, 0, 0.3)";
ctx.font = "12px Arial";
ctx.fillText("Audio Player", 10, 20);
},
});
waveform.setRenderHooks({
afterProgress: (ctx, cache, options, progress) => {
const x = cache.canvasWidth * progress;
ctx.fillStyle = "#ff0000";
ctx.beginPath();
ctx.arc(x, cache.canvasHeight / 2, 4, 0, Math.PI * 2);
ctx.fill();
},
});
waveform.setRenderHooks({
afterComplete: (ctx, cache, options) => {
// Custom rendering logic
},
});
waveform.clearRenderHooks();
waveform.setRenderHooks({
afterProgress: (ctx, cache, options, progress) => {
if (progress > 0.1) {
this.drawProgressIndicator(ctx, cache, progress);
}
},
afterComplete: (ctx, cache, options) => {
if (options.position === "center") {
this.drawCenterAlignedOverlay(ctx, cache);
} else {
this.drawStandardOverlay(ctx, cache);
}
},
});
AspectRender HooksCustom Renderers
PurposeExtend default renderingReplace default rendering
ComplexityLightweight, targeted changesComplete rendering control
Default BehaviorPreserves library’s renderingOverrides library’s rendering
Use CasesOverlays, effects, annotationsComplete visual redesign
PerformanceMinimal impactCan optimize or impact performance
MaintenanceLibrary handles core updatesMust maintain all rendering logic

Recommended for:

  • Overlays or annotations
  • Custom progress indicators
  • Visual effects on top of the waveform
  • Debug visualizations
  • Watermarks or branding
  • Beat markers or time indicators
  • Real-time frequency overlays

Avoid when:

  • Completely changing visualization style
  • Implementing new rendering algorithms
  • Creating entirely different visual representations

Always save and restore canvas state:

afterBackground: (ctx, cache, options) => {
ctx.save();
try {
ctx.fillStyle = "red";
ctx.fillRect(0, 0, 100, 100);
} finally {
ctx.restore();
}
};

Keep hooks lightweight:

// ✅ Efficient
afterProgress: (ctx, cache, options, progress) => {
const x = cache.canvasWidth * progress;
ctx.fillRect(x - 1, 0, 2, cache.canvasHeight);
};
// ❌ Avoid heavy work
afterProgress: (ctx, cache, options, progress) => {
for (let i = 0; i < 10000; i++) {
// Expensive operations
}
};

Wrap hook logic in try-catch:

afterComplete: (ctx, cache, options) => {
try {
this.complexRenderingOperation(ctx, cache);
} catch (error) {
console.warn("Hook rendering failed:", error);
}
};

All hook functions receive:

  • ctx – Canvas rendering context
  • cache – Pre-computed rendering data (bar positions, dimensions)
  • options – Full waveform configuration
  • progress – Current progress value (only in afterProgress)