lopaka

repository·main·Indexed 23 days ago

https://github.com/sbrin/lopaka

An open-source, web-based graphics editor for embedded systems (version 0.6). It allows users to design pixel-perfect graphics and automatically generate C/C++ source code for libraries such as TFT_eSPI, u8g2, and AdafruitGFX, targeting platforms like Arduino, ESP32, STM32, FlipperZero, Inkplate, and Watchy.

Tokens
7.6K
Snippets
11
Records
46
Agent score
81%

What's inside lopaka

  1. Overview of Lopaka features and supported platforms

    main

    Lopaka is an open-source graphics editor designed to create graphics for embedded screens. It allows you to draw graphics and automatically generate C/C++ source code for use in Arduino, ESP32, or STM32 projects.

    Key Features

    • Pixel perfect editor with various screen sizes.
    • Tools for drawing shapes and using custom images.
    • Support for popular fonts.
    • Auto-generation of XBMP graphics.
    • C/C++ source code generation.
    • FlipperZero live preview.
    • Zoom scale selection.

    Supported Platforms

    Lopaka provides compatibility for several embedded graphics libraries and hardware, including:

    • Libraries: TFT_eSPI, u8g2, AdafruitGFX (and ESPHome coming soon).
    • Hardware/Frameworks: FlipperZero, Inkplate, Watchy, and compatibility with M5GFX, LovyanGFX, and others.
  2. Run Lopaka development server or build production

    main

    After installing dependencies with pnpm, you can use the following commands to manage the application:

    • Development server: Starts the local development environment.
    • Production build: Generates the production-ready assets.
    pnpm dev
    
    pnpm build
  3. Define layer interaction via EditMode and TLayerEditPoint

    main

    Lopaka uses EditMode to track the current interaction state of a layer and TLayerEditPoint to provide handles (like resize corners) for user interaction.

    Edit Modes

    Use the EditMode enum to manage how a layer responds to input:

    • MOVING: The layer is being repositioned.
    • RESIZING: The layer's dimensions are being changed.
    • CREATING: A new layer is being initialized.
    • DRAWING: Active drawing is occurring.
    • ERASING: Content is being removed.
    • NONE / EMPTY: No active interaction.

    Edit Points

    Layers can expose TLayerEditPoint objects via the editPoints array. Each point defines:

    • cursor: The CSS cursor to display (e.g., 'nwse-resize', 'move', 'ns-resize').
    • getRect(): Returns the Rect area of the handle.
    • move(point: Point, event?: MouseEvent | TouchEvent): The logic to execute when the user interacts with this specific handle.
  4. Supported font formats in Lopaka

    main

    Lopaka supports several font formats for rendering graphics on embedded screens. When providing or selecting fonts, you can work with the following formats:

    • BDF: Bitmap Distribution Format (FontFormat.FORMAT_BDF).
    • GFX: C header files containing bitmap data (FontFormat.FORMAT_GFX).
    • TTF: TrueType Fonts (FontFormat.FORMAT_TTF).
    • 5x7: Specialized 5x7 bitmap fonts (e.g., Adafruit 5x7) (FontFormat.FORMAT_5x7).
  5. Use SmoothDrawingRenderer for anti-aliased vector graphics

    main

    The SmoothDrawingRenderer is a specialized implementation of AbstractDrawingRenderer designed for platforms requiring vector-based, anti-aliased rendering (such as LVGL via a canvas). It provides high-level methods for drawing primitive shapes, complex UI components (buttons, switches, sliders, checkboxes), and text.

    Note that most drawing methods in this renderer call this.clear() internally, which clears the current drawing context before performing the new draw operation.

  6. Deploy Lopaka using docker-compose

    main

    You can deploy Lopaka using the provided docker-compose.yml file. This configuration builds the service from the local directory and maps the web service to port 80 on the host machine. The service uses the woomoo/lopaka image.

    services:
      web:
        build: .
        ports:
          - "80:80"
        image: woomoo/lopaka
  7. Draw primitive shapes with PixelatedDrawingRenderer

    main

    Use the following methods to draw basic geometric shapes. Most methods require a Point for position/size and a color string.

    • drawRect(position: Point, size: Point, fill: boolean, color: string): Draws a rectangle.
    • drawRoundedRect(position: Point, size: Point, radius: number, fill: boolean, color: string): Draws a rectangle with rounded corners.
    • drawCircle(center: Point, radius: number, fill: boolean, color: string): Draws a circle.
    • drawEllipse(center: Point, radiusX: number, radiusY: number, fill: boolean, color: string): Draws an ellipse.
    • drawLine(from: Point, to: Point, color: string): Draws a line between two points.
    • drawTriangle(p1: Point, p2: Point, p3: Point, fill: boolean, color: string): Draws a triangle.
    • drawPolygon(points: Point[], fill: boolean, color: string): Draws a polygon defined by an array of points.
  8. Implement the Platform class

    main

    To support a new target hardware, you must extend the Platform abstract class. You are required to implement the generateSourceCode method, which converts Lopaka layers into the target platform's specific source code (e.g., C++ for embedded screens).

    Other available methods for managing platform state include:

    • setTemplate(templateName: string): Switches the current code generation template.
    • getTemplate(): Returns the current template name.
    • getTemplateSettings(): Returns settings for the active template.
    • setTemplateSetting(name: string, value: boolean): Updates a specific setting in the current template.
    • createRenderer(): Returns a platform-specific AbstractDrawingRenderer. The default implementation returns a PixelatedDrawingRenderer.
    abstract generateSourceCode(layers: AbstractLayer[], ctx?: OffscreenCanvasRenderingContext2D, screenTitle?: string): string;
  9. Retrieve a loaded font with getFont()

    main

    Use getFont(name: string) to retrieve a previously loaded font from the internal cache by its name.

    Behavior Note: If the requested name is not found in the cache, the function returns the first available font in the cache instead of throwing an error. If the cache is empty, it returns undefined (via the iterator's next value).

  10. Implement a custom drawing layer by extending AbstractLayer

    main

    To create a new type of drawing element in Lopaka, you must extend the AbstractLayer class and implement its core lifecycle methods. A layer manages its own OffscreenCanvas buffer and uses a DrawContext for rendering.

    Required Methods to Implement:

    • draw(): The main rendering logic. Use the internal this.renderer to perform drawing operations.
    • updateBounds(): Updates the layer's bounds (a Rect) based on its current content or size.
    • startEdit(mode: EditMode, point?: Point, editPoint?: TLayerEditPoint, originalEvent?: MouseEvent | TouchEvent): Logic for when a user begins interacting with the layer (e.g., starting a resize or move).
    • edit(point: Point, originalEvent?: MouseEvent | TouchEvent): Logic for continuous interaction (e.g., dragging a corner during a resize).
    • stopEdit(): Cleanup or finalization logic when interaction ends.

    Core Properties:

    • this.state: Access and update the layer's serialized state.
    • this.bounds: The Rect defining the layer's position and size.
    • this.renderer: The AbstractDrawingRenderer used for platform-specific drawing.
    • this.uid: A unique identifier for the layer instance.