yapcad.viewer package

Submodules

yapcad.viewer.api_server module

REST API and WebSocket Server

Flask-based REST API and SocketIO WebSocket server for remote viewer control.

This module provides a complete HTTP API for controlling the VTK viewer programmatically, along with WebSocket support for real-time event streaming.

Example Usage

Basic server startup:

from yapcad.viewer import VTKViewer, ViewerAPIServer, ViewerConfig

config = ViewerConfig(stl_dir="/path/to/stls")
viewer = VTKViewer(config)
server = ViewerAPIServer(viewer)
server.run(port=5000)

With custom configuration:

server = ViewerAPIServer(viewer, cors_origins=["http://localhost:3000"])
server.run(host="0.0.0.0", port=8080, debug=True)

REST API Endpoints

Status and Information:

  • GET /status - Get viewer status

  • GET /parts - List loaded parts

  • GET /config - Get viewer configuration

Part Management:

  • POST /load - Load parts from JSON or part list

  • POST /reload - Reload positions from JSON file

  • POST /clear - Clear all parts

Rendering Controls:

  • POST /xray - Toggle or set x-ray mode

  • POST /highlight - Highlight specific parts

Camera Controls:

  • POST /camera/reset - Reset camera to default

  • POST /camera/set - Set camera position

  • POST /camera/orbit - Orbit camera around focal point

  • POST /camera/focus - Focus on a specific part

Screenshot:

  • GET /screenshot - Capture and return screenshot

  • POST /screenshot - Capture and save screenshot

WebSocket Events

Server-to-Client:

  • status - Viewer status updates

  • part_loaded - Part was loaded

  • part_removed - Part was removed

  • parts_cleared - All parts cleared

  • xray_changed - X-ray mode changed

  • camera_changed - Camera position changed

  • screenshot_saved - Screenshot captured

  • selection_changed - Selection/highlight changed

  • error - Error occurred

Client-to-Server:

  • command - Execute a viewer command

  • subscribe - Subscribe to event types

  • unsubscribe - Unsubscribe from event types

Dependencies

Requires Flask and related packages:

pip install flask flask-socketio flask-cors
class yapcad.viewer.api_server.ViewerAPIServer(viewer: VTKViewer, cors_origins: List[str] | None = None, async_mode: str = 'threading')[source]

Bases: object

REST API and WebSocket server for the VTK viewer.

This class wraps a VTKViewer instance and provides HTTP endpoints and WebSocket events for remote control and monitoring.

Parameters:
  • viewer (VTKViewer) – The viewer instance to control.

  • cors_origins (list of str, optional) – Allowed CORS origins. Default: [“*”] (all origins).

  • async_mode (str, optional) – SocketIO async mode. Default: “threading”.

Variables:
  • viewer (VTKViewer) – The controlled viewer instance.

  • app (Flask) – The Flask application.

  • socketio (SocketIO) – The SocketIO instance.

Examples

Basic usage:

viewer = VTKViewer(config)
server = ViewerAPIServer(viewer)
server.run(port=5000)

With pre-configured Flask app:

app = Flask(__name__)
viewer = VTKViewer(config)
server = ViewerAPIServer(viewer)
# Add custom routes to server.app
server.run()
run(host: str = '127.0.0.1', port: int = 5000, debug: bool = False, use_reloader: bool = False, viewer_in_background: bool = True)[source]

Start the API server.

Parameters:
  • host (str, optional) – Host to bind to. Default: “127.0.0.1”.

  • port (int, optional) – Port to listen on. Default: 5000.

  • debug (bool, optional) – Enable Flask debug mode. Default: False.

  • use_reloader (bool, optional) – Enable auto-reload on code changes. Default: False.

  • viewer_in_background (bool, optional) – Run viewer rendering in background thread. Default: True.

Notes

This method blocks. The viewer render loop runs in a background thread if viewer_in_background is True.

Examples

Start server on default port:

server.run()

Start on custom host/port:

server.run(host="0.0.0.0", port=8080)

Start with debug mode:

server.run(debug=True)
stop()[source]

Stop the API server.

yapcad.viewer.config module

Viewer Configuration

Configuration dataclass for the VTK viewer and API server.

Example Usage

Basic configuration:

from yapcad.viewer import ViewerConfig

config = ViewerConfig(
    stl_dir="/path/to/stl/files",
    positions_file="/path/to/positions.json",
    window_size=(1600, 1000),
    background_color=(0.12, 0.12, 0.15)
)

Configuration with file-based commands (backward compatibility):

config = ViewerConfig(
    stl_dir="/path/to/stl/files",
    command_file="/path/to/viewer_cmd.txt",
    screenshot_dir="/path/to/screenshots"
)
class yapcad.viewer.config.ViewerConfig(stl_dir: str, positions_file: str | None = None, command_file: str | None = None, screenshot_dir: str | None = None, window_size: Tuple[int, int]=(1600, 1000), window_title: str = 'yapCAD Assembly Viewer', background_color: Tuple[float, float, float]=(0.12, 0.12, 0.15), default_opacity: float = 1.0, xray_opacity: float = 0.4, default_color: Tuple[float, float, float]=(0.4, 0.4, 0.4), color_palette: Dict[str, ~typing.Tuple[float, float, float]]=<factory>, enable_multi_viewport: bool = True, command_poll_interval_ms: int = 100)[source]

Bases: object

Configuration for the VTK assembly viewer.

This dataclass holds all configuration options for the viewer including file paths, window settings, rendering options, and color schemes.

Parameters:
  • stl_dir (str or Path) – Directory containing STL files to load.

  • positions_file (str or Path, optional) –

    JSON file containing part positions and transforms. Expected format:

    {
        "PART_NAME": {
            "transform_matrix": [[...], [...], [...], [...]],
            "stl_file": "optional/path/to/file.stl",
            "color": [r, g, b]  # optional, 0-1 range
        },
        ...
    }
    

  • command_file (str or Path, optional) – Path to file-based command interface for backward compatibility. Commands are read from this file and executed.

  • screenshot_dir (str or Path, optional) – Directory for saving screenshots. Defaults to stl_dir/renders.

  • window_size (tuple of int, optional) – Window dimensions (width, height). Default: (1600, 1000).

  • window_title (str, optional) – Window title. Default: “yapCAD Assembly Viewer”.

  • background_color (tuple of float, optional) – Background color as RGB (0-1 range). Default: (0.12, 0.12, 0.15).

  • default_opacity (float, optional) – Default opacity for parts. Default: 1.0.

  • xray_opacity (float, optional) – Opacity when x-ray mode is enabled. Default: 0.4.

  • default_color (tuple of float, optional) – Default part color as RGB (0-1 range). Default: (0.4, 0.4, 0.4).

  • color_palette (dict, optional) – Named color palette for automatic color assignment. Keys are color names, values are RGB tuples (0-1 range).

  • enable_multi_viewport (bool, optional) – Enable 4-viewport mode (ISO, TOP, FRONT, SIDE). Default: True.

  • command_poll_interval_ms (int, optional) – Interval in milliseconds for polling command file. Default: 100.

Variables:
  • stl_dir (Path) – Resolved STL directory path.

  • positions_file (Path or None) – Resolved positions file path.

  • command_file (Path or None) – Resolved command file path.

  • screenshot_dir (Path) – Resolved screenshot directory path.

Examples

Minimal configuration:

config = ViewerConfig(stl_dir="/my/stls")

Full configuration:

config = ViewerConfig(
    stl_dir="/my/stls",
    positions_file="/my/positions.json",
    window_size=(1920, 1080),
    background_color=(0.1, 0.1, 0.12),
    color_palette={
        "primary": (0.2, 0.4, 0.8),
        "secondary": (0.8, 0.4, 0.2),
        "highlight": (1.0, 0.9, 0.2)
    }
)
background_color: Tuple[float, float, float] = (0.12, 0.12, 0.15)
color_palette: Dict[str, Tuple[float, float, float]]
command_file: str | None = None
property command_path: Path | None

Get the resolved command file path.

command_poll_interval_ms: int = 100
default_color: Tuple[float, float, float] = (0.4, 0.4, 0.4)
default_opacity: float = 1.0
enable_multi_viewport: bool = True
classmethod from_dict(data: Dict[str, Any]) ViewerConfig[source]

Create configuration from dictionary.

Parameters:

data (dict) – Configuration dictionary.

Returns:

New configuration instance.

Return type:

ViewerConfig

get_color(name: str) Tuple[float, float, float][source]

Get a color from the palette by name.

Parameters:

name (str) – Color name (case-insensitive).

Returns:

RGB color tuple (0-1 range).

Return type:

tuple of float

Examples

>>> config = ViewerConfig(stl_dir="/tmp")
>>> config.get_color("blue")
(0.2, 0.4, 0.8)
>>> config.get_color("unknown")  # Returns default
(0.4, 0.4, 0.4)
positions_file: str | None = None
property positions_path: Path | None

Get the resolved positions file path.

screenshot_dir: str | None = None
property screenshot_path: Path

Get the resolved screenshot directory path.

stl_dir: str
property stl_path: Path

Get the resolved STL directory path.

to_dict() Dict[str, Any][source]

Convert configuration to dictionary.

Returns:

Configuration as a dictionary suitable for JSON serialization.

Return type:

dict

window_size: Tuple[int, int] = (1600, 1000)
window_title: str = 'yapCAD Assembly Viewer'
xray_opacity: float = 0.4

yapcad.viewer.events module

WebSocket Event Types

Defines event types for WebSocket communication between the viewer server and connected clients.

Event Categories

Client-to-Server Events:

Commands sent from clients to control the viewer.

Server-to-Client Events:

Notifications sent from the viewer to connected clients.

Example Usage

Sending events from server:

from yapcad.viewer.events import ServerEvent, PartLoadedEvent

event = PartLoadedEvent(
    part_name="AXIS1_SUN_GEAR",
    stl_file="gearbox/axis1_sun_gear.stl",
    bounds=[-10, 10, -10, 10, 0, 20]
)
socketio.emit(event.event_type, event.to_dict())

Handling events on client:

socket.on('part_loaded', (data) => {
    console.log(`Loaded: ${data.part_name}`);
});
class yapcad.viewer.events.BaseEvent[source]

Bases: object

Base class for all WebSocket events.

Variables:

event_type (str) – The event type identifier.

event_type: str
to_dict() Dict[str, Any][source]

Convert event to dictionary for JSON serialization.

Returns:

Event data as dictionary.

Return type:

dict

class yapcad.viewer.events.CameraChangedEvent(viewport: str, position: Tuple[float, float, float], focal_point: Tuple[float, float, float], view_up: Tuple[float, float, float] = (0.0, 0.0, 1.0))[source]

Bases: BaseEvent

Event emitted when camera position changes.

Variables:
  • viewport (str) – Viewport name that changed.

  • position (tuple of float) – New camera position (x, y, z).

  • focal_point (tuple of float) – New focal point (x, y, z).

  • view_up (tuple of float) – View up vector.

  • Event (WebSocket)

  • ---------------

  • name (Event)

  • Payload::

    {

    “viewport”: “ISO”, “position”: [100.0, 100.0, 100.0], “focal_point”: [0.0, 0.0, 50.0], “view_up”: [0.0, 0.0, 1.0]

    }

focal_point: Tuple[float, float, float]
position: Tuple[float, float, float]
view_up: Tuple[float, float, float] = (0.0, 0.0, 1.0)
viewport: str
class yapcad.viewer.events.CommandMessage(command: str, params: Dict[str, ~typing.Any]=<factory>)[source]

Bases: object

Command message sent from client to server.

Variables:
  • command (str) – Command type (from CommandType enum).

  • params (dict, optional) – Command parameters.

Example

Load command:

{
    "command": "load",
    "params": {
        "parts": ["AXIS1_SUN_GEAR", "AXIS1_RING_HOUSING"],
        "clear": true
    }
}

Screenshot command:

{
    "command": "screenshot",
    "params": {
        "filename": "my_screenshot.png"
    }
}
command: str
classmethod from_dict(data: Dict[str, Any]) CommandMessage[source]

Create command from dictionary.

Parameters:

data (dict) – Command data with ‘command’ and optional ‘params’.

Returns:

Parsed command message.

Return type:

CommandMessage

params: Dict[str, Any]
class yapcad.viewer.events.CommandType(*values)[source]

Bases: str, Enum

Types of commands that can be sent to the viewer.

Commands

LOAD

Load parts into the viewer.

CLEAR

Clear all loaded parts.

RELOAD

Reload positions from JSON file.

XRAY

Toggle or set x-ray mode.

SCREENSHOT

Capture a screenshot.

FOCUS

Focus camera on a specific part.

HIGHLIGHT

Highlight specific parts.

CAMERA_RESET

Reset camera to default position.

CAMERA_SET

Set camera position directly.

CAMERA_ORBIT

Orbit camera around focal point.

MOVE

Move a part by relative offset.

MOVE_TO

Move a part to absolute position.

CAMERA_ORBIT = 'camera_orbit'
CAMERA_RESET = 'camera_reset'
CAMERA_SET = 'camera_set'
CLEAR = 'clear'
FOCUS = 'focus'
HIGHLIGHT = 'highlight'
LOAD = 'load'
MOVE = 'move'
MOVE_TO = 'move_to'
RELOAD = 'reload'
SCREENSHOT = 'screenshot'
XRAY = 'xray'
class yapcad.viewer.events.ErrorEvent(message: str, code: str | None = None, details: Dict[str, Any] | None = None)[source]

Bases: BaseEvent

Event emitted when an error occurs.

Variables:
  • message (str) – Error message.

  • code (str, optional) – Error code for programmatic handling.

  • details (dict, optional) – Additional error details.

  • Event (WebSocket)

  • ---------------

  • name (Event)

  • Payload::

    {

    “message”: “Failed to load STL file”, “code”: “LOAD_ERROR”, “details”: {“file”: “missing.stl”}

    }

code: str | None = None
details: Dict[str, Any] | None = None
message: str
class yapcad.viewer.events.EventType(*values)[source]

Bases: str, Enum

Enumeration of all WebSocket event types.

Client-to-Server

COMMAND

Execute a viewer command.

SUBSCRIBE

Subscribe to specific event types.

UNSUBSCRIBE

Unsubscribe from event types.

Server-to-Client

STATUS

Viewer status update.

PART_LOADED

Part was loaded into the scene.

PART_REMOVED

Part was removed from the scene.

PARTS_CLEARED

All parts were cleared.

XRAY_CHANGED

X-ray mode was toggled.

CAMERA_CHANGED

Camera position/orientation changed.

SCREENSHOT_SAVED

Screenshot was captured and saved.

SELECTION_CHANGED

Part selection changed.

ERROR

An error occurred.

CAMERA_CHANGED = 'camera_changed'
COMMAND = 'command'
ERROR = 'error'
PARTS_CLEARED = 'parts_cleared'
PART_LOADED = 'part_loaded'
PART_REMOVED = 'part_removed'
SCREENSHOT_SAVED = 'screenshot_saved'
SELECTION_CHANGED = 'selection_changed'
STATUS = 'status'
SUBSCRIBE = 'subscribe'
UNSUBSCRIBE = 'unsubscribe'
XRAY_CHANGED = 'xray_changed'
class yapcad.viewer.events.PartLoadedEvent(part_name: str, stl_file: str, bounds: List[float] = <factory>, color: Tuple[float, float, float] | None=None)[source]

Bases: BaseEvent

Event emitted when a part is loaded.

Variables:
  • part_name (str) – Name/identifier of the loaded part.

  • stl_file (str) – Path to the STL file.

  • bounds (list of float) – Bounding box [xmin, xmax, ymin, ymax, zmin, zmax].

  • color (tuple of float, optional) – RGB color (0-1 range).

  • Event (WebSocket)

  • ---------------

  • name (Event)

  • Payload::

    {

    “part_name”: “AXIS1_SUN_GEAR”, “stl_file”: “gearbox/axis1_sun_gear.stl”, “bounds”: [-10.0, 10.0, -10.0, 10.0, 0.0, 20.0], “color”: [0.8, 0.5, 0.2]

    }

bounds: List[float]
color: Tuple[float, float, float] | None = None
part_name: str
stl_file: str
class yapcad.viewer.events.PartRemovedEvent(part_name: str)[source]

Bases: BaseEvent

Event emitted when a part is removed.

Variables:
  • part_name (str) – Name of the removed part.

  • Event (WebSocket)

  • ---------------

  • name (Event)

  • Payload::

    {

    “part_name”: “AXIS1_SUN_GEAR”

    }

part_name: str
class yapcad.viewer.events.PartsClearedEvent(previous_count: int)[source]

Bases: BaseEvent

Event emitted when all parts are cleared.

Variables:
  • previous_count (int) – Number of parts that were cleared.

  • Event (WebSocket)

  • ---------------

  • name (Event)

  • Payload::

    {

    “previous_count”: 42

    }

previous_count: int
class yapcad.viewer.events.ScreenshotSavedEvent(filename: str, filepath: str, size: Tuple[int, int] = (0, 0))[source]

Bases: BaseEvent

Event emitted when a screenshot is saved.

Variables:
  • filename (str) – Name of the saved file.

  • filepath (str) – Full path to the saved file.

  • size (tuple of int) – Image dimensions (width, height).

  • Event (WebSocket)

  • ---------------

  • name (Event)

  • Payload::

    {

    “filename”: “screenshot_001.png”, “filepath”: “/path/to/renders/screenshot_001.png”, “size”: [1600, 1000]

    }

filename: str
filepath: str
size: Tuple[int, int] = (0, 0)
class yapcad.viewer.events.SelectionChangedEvent(selected_parts: List[str] = <factory>, highlighted_parts: List[str] = <factory>)[source]

Bases: BaseEvent

Event emitted when part selection changes.

Variables:
  • selected_parts (list of str) – Names of currently selected parts.

  • highlighted_parts (list of str) – Names of currently highlighted parts.

  • Event (WebSocket)

  • ---------------

  • name (Event)

  • Payload::

    {

    “selected_parts”: [“AXIS1_SUN_GEAR”], “highlighted_parts”: [“AXIS1_SUN_GEAR”, “AXIS1_RING_HOUSING”]

    }

highlighted_parts: List[str]
selected_parts: List[str]
class yapcad.viewer.events.StatusEvent(part_count: int, xray_enabled: bool, viewport: str = 'ISO', camera_position: Tuple[float, float, float] = (0.0, 0.0, 0.0), camera_focal_point: Tuple[float, float, float] = (0.0, 0.0, 0.0))[source]

Bases: BaseEvent

Viewer status update event.

Sent periodically or on request to provide current viewer state.

Variables:
  • part_count (int) – Number of parts currently loaded.

  • xray_enabled (bool) – Whether x-ray mode is active.

  • viewport (str) – Current active viewport name.

  • camera_position (tuple of float) – Camera position (x, y, z).

  • camera_focal_point (tuple of float) – Camera focal point (x, y, z).

  • Event (WebSocket)

  • ---------------

  • name (Event)

  • Payload::

    {

    “part_count”: 42, “xray_enabled”: false, “viewport”: “ISO”, “camera_position”: [100.0, 100.0, 100.0], “camera_focal_point”: [0.0, 0.0, 50.0]

    }

camera_focal_point: Tuple[float, float, float] = (0.0, 0.0, 0.0)
camera_position: Tuple[float, float, float] = (0.0, 0.0, 0.0)
part_count: int
viewport: str = 'ISO'
xray_enabled: bool
class yapcad.viewer.events.XrayChangedEvent(enabled: bool, opacity: float)[source]

Bases: BaseEvent

Event emitted when x-ray mode changes.

Variables:
  • enabled (bool) – Whether x-ray mode is now enabled.

  • opacity (float) – Current opacity value.

  • Event (WebSocket)

  • ---------------

  • name (Event)

  • Payload::

    {

    “enabled”: true, “opacity”: 0.4

    }

enabled: bool
opacity: float

yapcad.viewer.vtk_viewer module

VTK-Based Assembly Viewer

Core VTK rendering engine for the yapCAD assembly viewer.

This module provides a general-purpose STL viewer with multi-viewport support, transform application, and real-time rendering capabilities. It is designed to work with any assembly defined by JSON position files and STL directories.

Example Usage

Basic usage:

from yapcad.viewer import VTKViewer, ViewerConfig

config = ViewerConfig(
    stl_dir="/path/to/stls",
    positions_file="/path/to/positions.json"
)
viewer = VTKViewer(config)
viewer.load_from_json()
viewer.start()

Manual part loading:

viewer = VTKViewer(config)
viewer.add_part(
    name="my_part",
    stl_path="/path/to/part.stl",
    transform=[[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]],
    color=(0.8, 0.4, 0.2)
)
viewer.start()

With file-based commands (backward compatibility):

config = ViewerConfig(
    stl_dir="/path/to/stls",
    command_file="/path/to/viewer_cmd.txt"
)
viewer = VTKViewer(config)
viewer.start()  # Will poll command file for instructions

Dependencies

Requires VTK >= 9.0:

pip install vtk
class yapcad.viewer.vtk_viewer.VTKViewer(config: ViewerConfig)[source]

Bases: object

VTK-based multi-viewport assembly viewer.

This class provides a complete 3D viewer for STL assemblies with support for multiple viewports, transform application, x-ray mode, and various camera controls.

Parameters:

config (ViewerConfig) – Viewer configuration object.

Variables:
  • config (ViewerConfig) – Current configuration.

  • actors (dict) – Mapping of part names to VTK actors.

  • positions (dict) – Current part positions loaded from JSON.

  • xray_mode (bool) – Whether x-ray mode is currently enabled.

Examples

Create viewer and load from JSON:

config = ViewerConfig(
    stl_dir="/my/stls",
    positions_file="/my/positions.json"
)
viewer = VTKViewer(config)
viewer.load_from_json()
viewer.start()

Create viewer and add parts manually:

viewer = VTKViewer(ViewerConfig(stl_dir="/my/stls"))
viewer.add_part("gear", "/my/stls/gear.stl", transform, (0.8, 0.5, 0.2))
viewer.add_part("housing", "/my/stls/housing.stl", transform, (0.4, 0.4, 0.4))
viewer.start()
add_part(name: str, stl_path: str | Path, transform: List[List[float]] | None = None, color: Tuple[float, float, float] | None = None) bool[source]

Add a single part to the viewer.

Parameters:
  • name (str) – Unique identifier for the part.

  • stl_path (str or Path) – Path to the STL file.

  • transform (list of list of float, optional) – 4x4 transformation matrix. Identity matrix if not provided.

  • color (tuple of float, optional) – RGB color (0-1 range). Auto-assigned if not provided.

Returns:

True if part was loaded successfully.

Return type:

bool

Examples

Add a part with transform:

transform = [
    [1, 0, 0, 10],
    [0, 1, 0, 20],
    [0, 0, 1, 30],
    [0, 0, 0, 1]
]
viewer.add_part("my_gear", "/path/to/gear.stl", transform, (0.8, 0.5, 0.2))

Add a part at origin with auto color:

viewer.add_part("housing", "/path/to/housing.stl")
clear_parts()[source]

Remove all parts from the viewer.

focus_part(name: str)[source]

Focus all cameras on a specific part.

Parameters:

name (str) – Name of the part to focus on.

Raises:

KeyError – If part name is not found.

get_camera_state(viewport: str = 'ISO') Dict[str, Any][source]

Get current camera state.

Parameters:

viewport (str, optional) – Viewport to query. Default: “ISO”.

Returns:

Camera state with position, focal_point, view_up.

Return type:

dict

get_part_bounds(name: str) Tuple[float, ...] | None[source]

Get bounding box of a specific part.

Parameters:

name (str) – Part name.

Returns:

Bounding box (xmin, xmax, ymin, ymax, zmin, zmax) or None.

Return type:

tuple of float or None

get_part_names() List[str][source]

Get list of loaded part names.

Returns:

Names of all loaded parts.

Return type:

list of str

get_status() StatusEvent[source]

Get current viewer status.

Returns:

Current viewer status.

Return type:

StatusEvent

highlight_parts(names: List[str], dim_opacity: float = 0.15)[source]

Highlight specific parts by dimming others.

Parameters:
  • names (list of str) – Part names to highlight.

  • dim_opacity (float, optional) – Opacity for non-highlighted parts. Default: 0.15.

Examples

Highlight gears:

viewer.highlight_parts(["SUN_GEAR", "RING_HOUSING"])

Clear highlighting (show all):

viewer.highlight_parts([])  # Or pass all part names
load_from_json(positions_file: str | Path | None = None) int[source]

Load all parts defined in a positions JSON file.

The JSON file should have the format:

{
    "PART_NAME": {
        "transform_matrix": [[...], [...], [...], [...]],
        "stl_file": "path/to/file.stl",  // optional
        "color": [r, g, b]  // optional, 0-1 range
    },
    ...
}
Parameters:

positions_file (str or Path, optional) – Path to positions JSON file. Uses config.positions_file if not provided.

Returns:

Number of parts successfully loaded.

Return type:

int

Raises:

FileNotFoundError – If positions file doesn’t exist.

load_parts(part_specs: List[Tuple[str, str, str | None]], clear: bool = True) int[source]

Load multiple parts from specifications.

Parameters:
  • part_specs (list of tuple) – List of (stl_file, part_name, color_name) tuples. stl_file is relative to stl_dir. color_name is optional; if None, auto-assigned.

  • clear (bool, optional) – Clear existing parts first. Default: True.

Returns:

Number of parts successfully loaded.

Return type:

int

Examples

Load multiple parts:

parts = [
    ("gearbox/sun_gear.stl", "SUN_GEAR", "orange"),
    ("gearbox/ring_housing.stl", "RING_HOUSING", "brown"),
    ("motors/servo.stl", "SERVO", "dark"),
]
viewer.load_parts(parts)
move_part(name: str, dx: float, dy: float, dz: float)[source]

Move a part by relative offset.

Parameters:
  • name (str) – Part name.

  • dx (float) – X offset.

  • dy (float) – Y offset.

  • dz (float) – Z offset.

Raises:

KeyError – If part name is not found.

move_part_to(name: str, x: float, y: float, z: float)[source]

Move a part to absolute position (centers part at position).

Parameters:
  • name (str) – Part name.

  • x (float) – Target X coordinate.

  • y (float) – Target Y coordinate.

  • z (float) – Target Z coordinate.

Raises:

KeyError – If part name is not found.

on_event(event_type: str, callback: Callable[[Any], None])[source]

Register a callback for viewer events.

Parameters:
  • event_type (str) – Event type to listen for (e.g., “part_loaded”, “xray_changed”).

  • callback (callable) – Function to call when event occurs. Receives event object.

Examples

Track loaded parts:

def on_load(event):
    print(f"Loaded: {event.part_name}")

viewer.on_event("part_loaded", on_load)
orbit_camera(azimuth: float, elevation: float, distance: float, viewport: str = 'ISO')[source]

Position camera using spherical coordinates around focal point.

Parameters:
  • azimuth (float) – Azimuth angle in degrees (rotation around Z axis).

  • elevation (float) – Elevation angle in degrees (angle from XY plane).

  • distance (float) – Distance from focal point.

  • viewport (str, optional) – Viewport to modify. Default: “ISO”.

Examples

Orbit to 45 degrees azimuth, 30 degrees elevation:

viewer.orbit_camera(azimuth=45, elevation=30, distance=500)
reload_positions()[source]

Reload positions from the JSON file and update transforms.

This updates transforms without reloading STL files, which is faster for iterating on kinematic positions.

remove_part(name: str) bool[source]

Remove a part from the viewer.

Parameters:

name (str) – Name of the part to remove.

Returns:

True if part was found and removed.

Return type:

bool

render()[source]

Trigger a render update.

reset_camera()[source]

Reset all cameras to view the entire scene.

screenshot(filename: str | None = None, directory: str | Path | None = None) str[source]

Capture a screenshot.

Parameters:
  • filename (str, optional) – Output filename. Default: “screenshot.png”.

  • directory (str or Path, optional) – Output directory. Uses config.screenshot_dir if not provided.

Returns:

Full path to saved screenshot.

Return type:

str

Examples

Save with default name:

path = viewer.screenshot()

Save with custom name:

path = viewer.screenshot("my_view.png")

Save to custom directory:

path = viewer.screenshot("view.png", "/my/images")
set_camera(position: Tuple[float, float, float], focal_point: Tuple[float, float, float], viewport: str = 'ISO', view_up: Tuple[float, float, float] = (0, 0, 1))[source]

Set camera position and orientation.

Parameters:
  • position (tuple of float) – Camera position (x, y, z).

  • focal_point (tuple of float) – Point camera is looking at (x, y, z).

  • viewport (str, optional) – Viewport to modify. Default: “ISO”.

  • view_up (tuple of float, optional) – Up direction vector. Default: (0, 0, 1).

Examples

Set camera for isometric view:

viewer.set_camera(
    position=(200, 200, 150),
    focal_point=(0, 0, 50)
)
set_xray(enabled: bool, opacity: float | None = None)[source]

Enable or disable x-ray mode.

Parameters:
  • enabled (bool) – Whether to enable x-ray mode.

  • opacity (float, optional) – Opacity value when x-ray is enabled. Uses config default if not provided.

Examples

Enable x-ray:

viewer.set_xray(True)

Enable with custom opacity:

viewer.set_xray(True, opacity=0.3)

Disable:

viewer.set_xray(False)
start()[source]

Start the viewer main loop (blocking).

This starts the VTK interactor and blocks until the window is closed. Use this for standalone viewer applications.

Examples

Basic standalone usage:

viewer = VTKViewer(config)
viewer.load_from_json()
viewer.start()  # Blocks until window closed
start_offscreen()[source]

Initialize for offscreen rendering.

Use this when running headless or with the API server. Does not block.

toggle_xray()[source]

Toggle x-ray mode on/off.

Module contents

yapCAD Viewer Package

A VTK-based 3D assembly viewer with REST API and WebSocket support.

This package provides a general-purpose STL viewer for visualizing assemblies with support for:

  • Multi-viewport rendering (ISO, TOP, FRONT, SIDE)

  • Real-time part positioning via 4x4 transform matrices

  • X-ray mode for internal inspection

  • REST API for programmatic control

  • WebSocket events for real-time updates

  • Optional file-based command interface for backward compatibility

Example Usage

Basic viewer with positions file:

from yapcad.viewer import VTKViewer, ViewerConfig

config = ViewerConfig(
    stl_dir="/path/to/stl/files",
    positions_file="/path/to/positions.json"
)
viewer = VTKViewer(config)
viewer.load_from_json()
viewer.start()

With REST API server:

from yapcad.viewer import VTKViewer, ViewerAPIServer, ViewerConfig

config = ViewerConfig(stl_dir="/path/to/stls")
viewer = VTKViewer(config)
server = ViewerAPIServer(viewer)
server.run(port=5000)  # Viewer runs in background thread

Dependencies

Required:
  • vtk >= 9.0

Optional (for API server):
  • flask >= 2.0

  • flask-socketio >= 5.0

  • flask-cors >= 3.0

Module Contents

  • VTKViewer - Core VTK-based viewer with multi-viewport support

  • ViewerAPIServer - Flask REST API and SocketIO WebSocket server

  • ViewerConfig - Configuration dataclass

  • events - WebSocket event type definitions

Viewer system contributed by Jeremy Mika.