factoriax.playground.ui#

Shared UI primitives for all pygame-based Factoriax applications.

This package provides the common building blocks used by the editor, play mode, and inspector. Importing from here (rather than from play.ui or play.main) keeps the dependency graph clean and ensures consistent styling across all interactive tools.

Modules

compositing

Image compositing utilities for numpy-array-based UI rendering.

fonts

Cached pixel-font loader and text rendering for pygame applications.

forms

Shared visual constants and drawing primitives for menu/launch forms.

icons

Procedural icon and texture generation for play, editor, and menu UI.

labels

Human-readable display names for Factoriax UI applications.

panels

Reusable drawing primitives for Factoriax menus.

primitives

Core UI primitives: click regions, hit testing, and panel drawing.

scaling

Fixed-resolution canvas with integer scaling to a pygame window.

theme

Shared color and size constants for all Factoriax UI applications.

window

Window sizing utilities for pygame applications.

class factoriax.playground.ui.ScaledCanvas(base_size: int, ui_scale: int, window: Surface)#

A fixed-size pygame surface that integer-scales to the window.

handle_resize(window_w: int, window_h: int) → None#

Recompute scale and offsets after a window resize event.

Parameters:
  • window_w – New window width in pixels.

  • window_h – New window height in pixels.

property height: int#

Canvas height in pixels.

present(screen: Surface) → None#

Scale the canvas and blit it centered onto the display surface.

Fills the screen with black for letterboxing, integer-scales the canvas, and blits it centered.

Parameters:

screen – The pygame display surface.

property surface: Surface#

The fixed-size drawing target.

to_canvas(window_x: int, window_y: int) → tuple[int, int]#

Transform window pixel coordinates to canvas coordinates.

Parameters:
  • window_x – X position in window pixels.

  • window_y – Y position in window pixels.

property width: int#

Canvas width in pixels.

factoriax.playground.ui.auto_ui_scale(base_size: int = 1024) → int#

Pick the highest UI scale where the canvas fits the monitor.

Returns the largest integer s in {3, 2, 1} such that base_size * s fits within 80% of the monitor on both axes.

Parameters:

base_size – Logical base resolution (default 1024).

Return type:

Integer scale factor (1, 2, or 3).

factoriax.playground.ui.blit_rgba(overlay: ndarray, src: ndarray, y: int, x: int) → None#

Alpha-composite src onto overlay at (y, x), clipping to bounds.

Parameters:
  • overlay – Destination RGBA array of shape (H, W, 4). Modified in place.

  • src – Source RGBA array of shape (h, w, 4).

  • y – Top row in overlay.

  • x – Left column in overlay.

factoriax.playground.ui.blit_scroll_view(overlay: ndarray, content: ndarray, vp_x: int, vp_y: int, vp_w: int, vp_h: int, scroll_offset: int) → None#

Composite a scrollable content canvas into a viewport on overlay.

When the content is taller than the viewport a scrollbar is drawn along the right edge.

Parameters:
  • overlay – Destination RGBA array. Modified in place.

  • content – Full content RGBA canvas of shape (content_h, vp_w, 4).

  • vp_x – Left edge of the viewport in overlay coordinates.

  • vp_y – Top edge of the viewport in overlay coordinates.

  • vp_w – Viewport width in pixels (includes scrollbar when shown).

  • vp_h – Viewport height in pixels.

  • scroll_offset – Number of content pixels scrolled off the top.

factoriax.playground.ui.calculate_window_size(base_width: int, base_height: int, scale_factor: float = 0.8) → tuple[int, int]#

Calculate window size using integer scaling for crisp pixel art.

Uses the largest integer scale factor that fits within scale_factor (default 80%) of the screen.

Parameters:
  • base_width – Base render width in pixels.

  • base_height – Base render height in pixels.

  • scale_factor – Fraction of screen to use (0.0 to 1.0).

Return type:

(window_width, window_height) in pixels.

factoriax.playground.ui.clip_scroll_offset(offset: int, content_h: int, viewport_h: int) → int#

Clamp a scroll offset to the valid range.

Parameters:
  • offset – Proposed scroll offset in pixels.

  • content_h – Total height of the scrollable content in pixels.

  • viewport_h – Height of the visible viewport in pixels.

Return type:

Clamped offset in [0, max(0, content_h - viewport_h)].

factoriax.playground.ui.composite_rgba_over_rgb(background: ndarray, overlay: ndarray) → None#

Composite an RGBA overlay onto an RGB background in-place.

The function mixes the pixels inside the box that holds the visible part of the overlay. It does no float arithmetic for the clear area around a menu panel, which is most of the surface.

Parameters:
  • background – RGB image array of shape (H, W, 3), modified in place.

  • overlay – RGBA image array of shape (H, W, 4).

factoriax.playground.ui.draw_panel(overlay: ndarray, x: int, y: int, w: int, h: int, *, bg: tuple[int, int, int, int] | None = None, border: tuple[int, int, int, int] | None = None, border_px: int | None = None) → None#

Draw a rectangular panel: solid background with a uniform border.

Modifies overlay in place.

Parameters:
  • overlay – Destination RGBA array of shape (H, W, 4).

  • x – Left column of the panel.

  • y – Top row of the panel.

  • w – Panel width in pixels.

  • h – Panel height in pixels.

  • bg – Background RGBA colour.

  • border – Border RGBA colour.

  • border_px – Border thickness in pixels.

  • *

  • int

  • None (int] |)

factoriax.playground.ui.get_pixel_font(size: int) → Font#

Return a pixel-style monospace font at the requested size.

The cache holds one font for each size, so the number of frames does not change the number of fonts.

If a play session called pygame.quit(), pygame.font is closed. The function then starts it again, and empties the font cache and the text cache. A caller therefore always gets a font that it can draw with.

Parameters:

size – Desired font height in pixels.

Return type:

pygame.font.Font

factoriax.playground.ui.hit_test_regions(regions: list[ClickRegion], x: int, y: int) → ClickRegion | None#

Find the first click region containing the given point.

Parameters:
  • regions – List of click regions to test.

  • x – X coordinate in base resolution.

  • y – Y coordinate in base resolution.

Return type:

The first matching ClickRegion, or None if no hit.

factoriax.playground.ui.render_text_rgba(text: str, font: Font, color: tuple[int, int, int]) → ndarray#

Render text to an RGBA array with a fully transparent background.

Results are cached by (id(font), text, color) so that identical text drawn on consecutive frames is rasterised at most once.

Parameters:
  • text – String to render.

  • font – pygame Font to use.

  • color – RGB glyph colour.

  • int

  • int]

Return type:

RGBA uint8 array of shape (h, w, 4).