Canvas Renderer System – Dynamic Visual Content for KOS Applications

Modern device interfaces increasingly demand sophisticated visual displays that go beyond static content. The KOS Canvas Renderer System addresses this need by providing a comprehensive framework for streaming dynamic visual content to pixel-based displays. From simple LED matrices to complex digital signage, this system handles everything from basic color displays to complex video sequences with real-time control and event coordination.

Architecture of Visual Streaming

The Canvas Renderer System operates through a two-tier architecture that separates pattern management from actual rendering operations. The CanvasDispatcher serves as the orchestration layer, managing rendering patterns and coordinating multiple display endpoints, while individual CanvasRenderer instances handle the streaming and lifecycle of visual content to specific displays.

This separation enables sophisticated scenarios where multiple displays can be coordinated, patterns can be reused across different endpoints, and complex sequences can be managed through centralized control:

@kosModel({ modelTypeId: "digital-signage-controller", singleton: false })
export class DigitalSignageController implements IKosDataModel {
  @kosDependency({ modelType: CanvasDispatcher.type })
  private dispatcher!: CanvasDispatcherModel;
  async load() {
    // Configure multiple display endpoints
    this.dispatcher.addNamedEndpoint("main-screen", {
      id: "main-screen",
      apiPath: "/api/system/canvas/main",
      width: 128,
      height: 64,
      fps: 30
    });
    this.dispatcher.addNamedEndpoint("status-panel", {
      id: "status-panel",
      apiPath: "/api/system/canvas/status",
      width: 32,
      height: 16,
      fps: 15
    });
  }
}

The dispatcher creates and manages renderer instances automatically when endpoints are added, handling the complexity of coordinating multiple displays while providing a unified control interface.

Pattern-Based Content Management

Rather than requiring custom rendering code for every visual effect, the Canvas Renderer System uses a pattern-based approach that defines reusable rendering configurations. These patterns encapsulate both the rendering type and its associated data, enabling content to be applied consistently across different displays:

// Video patterns with flexible looping
this.dispatcher.addPattern("product-demo", {
  id: "product-demo",
  type: "video",
  data: {
    src: "/assets/product-demo.mp4",
    loop: 3, // Play three times
    startTime: 2.5, // Start at 2.5 seconds
    endTime: 30.0 // End at 30 seconds
  }
});
// Matrix effect with customizable parameters
this.dispatcher.addPattern("system-status", {
  id: "system-status",
  type: "matrix",
  data: {
    speed: 2,
    fallChance: 0.8,
    baseColor: { r: 0, g: 255, b: 0 } // Green Matrix rain
  }
});
// Scrolling text optimized for LED displays
this.dispatcher.addPattern("status-message", {
  id: "status-message",
  type: "text",
  data: {
    text: "System Online - All Services Running",
    fontSize: 8, // Optimized for LED panels
    scroll: {
      enabled: true,
      direction: "left",
      speed: 50
    },
    color: "#00ff00",
    loop: true
  }
});

This pattern system enables rapid content creation and modification without requiring code changes. Patterns can be combined, sequenced, and modified at runtime through HTTP API calls, providing the flexibility needed for dynamic display management.

Complex Visual Compositions

The system supports sophisticated visual compositions through sequence patterns and overlay renderers. Sequence patterns enable multiple visual elements to play in order with configurable transitions, while overlay renderers provide persistent status indicators that remain visible during dynamic content changes:

// Sequence combining multiple visual elements
this.dispatcher.addPattern("welcome-sequence", {
  id: "welcome-sequence",
  type: "sequence",
  data: {
    patterns: ["company-logo", "product-demo", "call-to-action"],
    loop: false,
    transitionDuration: 1000,
    patternOverrides: {
      "product-demo": { loop: 1 } // Override to play once in sequence
    }
  }
});
// Overlay renderer for persistent status indicators
this.dispatcher.addPattern("status-with-overlay", {
  id: "status-with-overlay", 
  type: "overlay",
  data: {
    baseRenderer: {
      type: "text",
      data: {
        text: "Processing transaction...",
        scroll: { enabled: true, direction: "left", speed: 40 }
      }
    },
    overlays: [
      {
        src: "/assets/icons/wifi-connected.svg",
        size: 8,
        position: "top-left"
      },
      {
        src: "/assets/icons/power-status.svg",
        size: 8,
        position: "top-right"
      }
    ],
    persistOverlaysOnComplete: true
  }
});

These composition capabilities enable sophisticated information displays where status indicators remain consistent while dynamic content changes, or where complex narrative sequences guide users through different interface states.

Event-Driven Content Control

The Canvas Renderer System integrates deeply with KOS’s event architecture, enabling reactive content management that responds to system state changes and user interactions. Completion events from finite renderers enable sophisticated content sequencing:

@kosModel({ modelTypeId: "interactive-display-controller", singleton: false })
export class InteractiveDisplayController implements IKosDataModel {
  @kosDependency({ modelType: CanvasDispatcher.type })
  private dispatcher!: CanvasDispatcherModel;
  private currentPhase: "attract" | "interaction" | "completion" = "attract";
  @kosTopicHandler("/canvas/renderer/completed")
  onRendererComplete(event: any) {
    if (event.endpoint === "main-display") {
      this.handleSequenceCompletion(event);
    }
  }
  private async handleSequenceCompletion(event: any) {
    switch (this.currentPhase) {
      case "attract":
        if (event.rendererId === "attract-sequence") {
          await this.startInteractionMode();
        }
        break;
      case "interaction":
        if (event.rendererId === "selection-timeout") {
          await this.returnToAttract();
        }
        break;
      case "completion":
        if (event.rendererId === "thank-you") {
          await this.resetToAttract();
        }
        break;
    }
  }
  private async startInteractionMode() {
    this.currentPhase = "interaction";
    await this.applyPattern("main-display", "interactive-menu");
  }
}

This event-driven approach enables complex state machines where visual content responds automatically to interaction patterns, system events, and operational requirements.

Runtime Content Modification

One of the system’s most powerful features is its ability to modify content parameters at runtime without requiring pattern redefinition. This enables dynamic personalization, real-time status updates, and context-sensitive content adaptation:

// Dynamically change matrix effect color based on system status
async updateSystemStatus(status: "normal" | "warning" | "error") {
  const colorMap = {
    normal: { r: 0, g: 255, b: 0 },   // Green
    warning: { r: 255, g: 165, b: 0 }, // Orange  
    error: { r: 255, g: 0, b: 0 }      // Red
  };
  await kosFetch({
    method: "POST",
    url: "/api/ui/canvas/pattern/status-display/system-matrix",
    body: {
      baseColor: colorMap[status],
      speed: status === "error" ? 4 : 2, // Faster animation for errors
      fallChance: status === "error" ? 0.95 : 0.7
    }
  });
}
// Update scrolling text content dynamically
async updateStatusMessage(message: string, urgent: boolean = false) {
  await kosFetch({
    method: "POST", 
    url: "/api/ui/canvas/pattern/info-panel/status-text",
    body: {
      text: message,
      color: urgent ? "#ff0000" : "#00ff00",
      scroll: {
        speed: urgent ? 100 : 50 // Faster scroll for urgent messages
      }
    }
  });
}

This runtime modification capability enables responsive interfaces that adapt to changing conditions without requiring application restarts or pattern redeployment.

Hardware Integration Patterns

The Canvas Renderer System is designed specifically for integration with physical display hardware, providing optimized rendering for LED matrices, digital signage displays, and other pixel-based output devices. The system handles pixel data streaming, frame rate management, and hardware-specific optimizations:

// LED matrix optimization with appropriate frame rates
this.dispatcher.addNamedEndpoint("led-matrix", {
  id: "led-matrix",
  apiPath: "/api/hardware/matrix/stream",
  width: 32,  // Match physical LED matrix dimensions
  height: 16,
  fps: 10,    // Appropriate for LED refresh rates
  durationMs: null // Infinite streaming
});
// High-resolution signage display
this.dispatcher.addNamedEndpoint("4k-display", {
  id: "4k-display", 
  apiPath: "/api/hardware/signage/stream",
  width: 3840,
  height: 2160,
  fps: 30,    // Smooth video playback
  durationMs: null
});
// Text rendering optimized for small LED panels
this.dispatcher.addPattern("led-text", {
  id: "led-text",
  type: "text", 
  data: {
    text: "WELCOME",
    fontSize: 8,        // Sweet spot for 32x16 panels
    fontFamily: "monospace", // Pixel-perfect rendering
    color: "#ffffff"    // High contrast
  }
});

The system automatically handles pixel data extraction and streaming to configured API endpoints, enabling seamless integration with hardware drivers and display controllers.

Custom Renderer Development

For specialized visual effects beyond the built-in renderer types, the system supports custom renderer development through well-defined interfaces. Custom renderers can implement complex animations, data visualizations, or hardware-specific effects:

import type { Renderer, DoneAware } from "@kosdev-code/kos-ui-sdk";
export class DataVisualizationRenderer implements Renderer, DoneAware {
  private canvas: HTMLCanvasElement;
  private ctx: CanvasRenderingContext2D;
  private animationFrame = 0;
  private completionCallback: (() => void) | null = null;
  constructor(private data: { dataSource: string; duration: number }) {
    this.canvas = document.createElement("canvas");
    const ctx = this.canvas.getContext("2d");
    if (!ctx) throw new Error("2D canvas not supported");
    this.ctx = ctx;
  }
  reset(): void {
    this.animationFrame = 0;
  }
  renderFrame(width: number, height: number): void {
    this.canvas.width = width;
    this.canvas.height = height;
    // Clear canvas
    this.ctx.fillStyle = "black";
    this.ctx.fillRect(0, 0, width, height);
    // Render data visualization based on current frame
    this.renderDataVisualization(width, height);
    this.animationFrame++;
    // Check completion
    if (this.animationFrame * (1000/30) >= this.data.duration) {
      if (this.completionCallback) {
        this.completionCallback();
      }
    }
  }
  onDone(callback: () => void): void {
    this.completionCallback = callback;
  }
  isOneShot(): boolean {
    return true;
  }
  readPixels(width: number, height: number): Uint8ClampedArray {
    return this.ctx.getImageData(0, 0, width, height).data;
  }
  dispose(): void {
    this.completionCallback = null;
    this.canvas.remove();
  }
  private renderDataVisualization(width: number, height: number): void {
    // Custom visualization logic here
    const progress = this.animationFrame / (this.data.duration / (1000/30));
    // Example: animated bar chart
    this.ctx.fillStyle = "#00ff00";
    const barHeight = (Math.sin(progress * Math.PI) * height * 0.8);
    this.ctx.fillRect(width * 0.4, height - barHeight, width * 0.2, barHeight);
  }
}

Custom renderers integrate seamlessly with the pattern system and can be registered for use across all display endpoints, enabling specialized visual effects while maintaining the system’s unified control interface.

Performance and Resource Management

The Canvas Renderer System incorporates sophisticated performance optimization strategies essential for real-time visual streaming. Frame rate adaptation, resource pooling, and automatic cleanup ensure smooth operation across varying hardware capabilities:

The system automatically adjusts rendering complexity based on configured frame rates and display dimensions, while completion events enable efficient resource cleanup when finite content sequences end. This approach ensures that visual quality scales appropriately with available processing power while maintaining responsive user interfaces.

The Canvas Renderer System represents a comprehensive solution for dynamic visual content management in KOS applications. By combining pattern-based content management with event-driven control and hardware integration capabilities, it enables sophisticated visual interfaces that respond dynamically to system state and user interaction while maintaining the performance and reliability required for production device deployments.