yapcad.viewer package

Submodules

yapcad.viewer.api_server module

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.

stl_dir

Resolved STL directory path.

Type:

Path

positions_file

Resolved positions file path.

Type:

Path or None

command_file

Resolved command file path.

Type:

Path or None

screenshot_dir

Resolved screenshot directory path.

Type:

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.

event_type

The event type identifier.

Type:

str

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.

viewport

Viewport name that changed.

Type:

str

position

New camera position (x, y, z).

Type:

tuple of float

focal_point

New focal point (x, y, z).

Type:

tuple of float

view_up

View up vector.

Type:

tuple of float

WebSocket Event
---------------
Event name
Type:

camera_changed

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.

command

Command type (from CommandType enum).

Type:

str

params

Command parameters.

Type:

dict, optional

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.

message

Error message.

Type:

str

code

Error code for programmatic handling.

Type:

str, optional

details

Additional error details.

Type:

dict, optional

WebSocket Event
---------------
Event name
Type:

error

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.

part_name

Name/identifier of the loaded part.

Type:

str

stl_file

Path to the STL file.

Type:

str

bounds

Bounding box [xmin, xmax, ymin, ymax, zmin, zmax].

Type:

list of float

color

RGB color (0-1 range).

Type:

tuple of float, optional

WebSocket Event
---------------
Event name
Type:

part_loaded

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.

part_name

Name of the removed part.

Type:

str

WebSocket Event
---------------
Event name
Type:

part_removed

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.

previous_count

Number of parts that were cleared.

Type:

int

WebSocket Event
---------------
Event name
Type:

parts_cleared

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.

filename

Name of the saved file.

Type:

str

filepath

Full path to the saved file.

Type:

str

size

Image dimensions (width, height).

Type:

tuple of int

WebSocket Event
---------------
Event name
Type:

screenshot_saved

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.

selected_parts

Names of currently selected parts.

Type:

list of str

highlighted_parts

Names of currently highlighted parts.

Type:

list of str

WebSocket Event
---------------
Event name
Type:

selection_changed

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.

part_count

Number of parts currently loaded.

Type:

int

xray_enabled

Whether x-ray mode is active.

Type:

bool

viewport

Current active viewport name.

Type:

str

camera_position

Camera position (x, y, z).

Type:

tuple of float

camera_focal_point

Camera focal point (x, y, z).

Type:

tuple of float

WebSocket Event
---------------
Event name
Type:

status

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.

enabled

Whether x-ray mode is now enabled.

Type:

bool

opacity

Current opacity value.

Type:

float

WebSocket Event
---------------
Event name
Type:

xray_changed

Payload::
{

“enabled”: true, “opacity”: 0.4

}

enabled: bool
opacity: float

yapcad.viewer.vtk_viewer module

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.