vangard-daz-mcp
Version 0.4.0 | MCP Server for DAZ Studio
A Model Context Protocol (MCP) server that exposes DAZ Studio operations to Claude and other MCP clients. Built on FastMCP and wraps the DazScriptServer HTTP plugin.
What Is This?
This MCP server allows Claude (via Claude Desktop or other MCP clients) to control DAZ Studio directly (at least these are the aspirational goals, not all of them are working just yet!):
- Query scene information (figures, cameras, lights, spatial positions)
- Read and modify node properties (transforms, morphs)
- Discover and apply morphs, including searching by name pattern
- Traverse and manipulate scene hierarchies (parent/child, skeleton)
- Apply emotional expressions to characters
- Coordinate multi-character interactions (look-at, reach-toward, hug, handshake)
- Execute batch operations (set multiple properties in one call, 5-10x faster)
- Control cameras and viewport (orbit, frame, presets)
- Create keyframe animations and export as image sequences
- Trigger synchronous or asynchronous renders with cancellation support
- Apply professional lighting presets and cinematography composition rules
- Browse and query the DAZ content library
- Save and restore named scene checkpoints
- Generate complete scenes from natural language descriptions
- Create multi-camera shot sequences (orbit, push-in, shot-reverse-shot)
- Choreograph animated conversations with dialogue beats
- Record and replay operation macros for workflow automation
- Execute arbitrary DazScript code
- Access comprehensive DazScript documentation and examples
The server acts as a bridge: MCP Client ↔ vangard-daz-mcp ↔ DazScriptServer plugin ↔ DAZ Studio 4.5+ or 6.25+
Prerequisites
Before using this server, you need:
- DAZ Studio installed and running — compatible with:
- DAZ Studio 4.5+ (legacy/classic versions)
- DAZ Studio 6.25+ (current versions)
- DazScriptServer plugin — must match your DAZ Studio version:
- Download from: https://github.com/bluemoonfoundry/daz-script-server
- Install the DS4 build for DAZ Studio 4.x, or the DS6 build for DAZ Studio 6.x
- Plugin must be running on port 18811 (default)
- Authentication must be configured (API token auto-generated on first run)
- Python 3.11+ for running the MCP server
- uv package manager (recommended) or pip
Installation
1. Install uv (if you don't have it)
macOS / Linux:
curl -LsSf https://astral.sh/uv/install.sh | sh
Windows (PowerShell):
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
See uv installation docs for other options.
2. Clone and install
# Clone the repository
git clone https://github.com/bluemoonfoundry/daz-mcp-server.git
cd daz-mcp-server
# Install dependencies (creates .venv automatically)
uv sync
# Verify it works
uv run vangard-daz-mcp --help
Using pip (alternative)
git clone https://github.com/bluemoonfoundry/daz-mcp-server.git
cd daz-mcp-server
pip install .
# Run the server
vangard-daz-mcp
Configuration
Environment Variables
Configure the server via environment variables:
| Variable | Default | Description |
|---|---|---|
DAZ_HOST |
localhost |
DazScriptServer hostname |
DAZ_PORT |
18811 |
DazScriptServer port |
DAZ_TIMEOUT |
30.0 |
Request timeout in seconds (increase for long renders) |
DAZ_API_TOKEN |
(from file) | API token for authentication |
DAZ_CONTENT_BROWSER_URL |
http://localhost:8080 |
Content browser API URL (if using a separate content service) |
Authentication
The server automatically reads the API token from ~/.daz3d/dazscriptserver_token.txt (the file created by DazScriptServer).
Override with environment variable:
export DAZ_API_TOKEN="your-token-here"
Important: DazScriptServer must have authentication enabled (default). The MCP server cannot connect without a valid token.
MCP Client Configuration
Claude Desktop
Config file location:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
macOS / Linux:
{
"mcpServers": {
"vangard-daz-mcp": {
"command": "uv",
"args": [
"run",
"--project",
"/absolute/path/to/daz-mcp-server",
"vangard-daz-mcp"
],
"env": {
"DAZ_HOST": "localhost",
"DAZ_PORT": "18811"
}
}
}
}
Windows:
{
"mcpServers": {
"vangard-daz-mcp": {
"command": "uv",
"args": [
"run",
"--project",
"C:\\Users\\YourName\\daz-mcp-server",
"vangard-daz-mcp"
],
"env": {
"DAZ_HOST": "localhost",
"DAZ_PORT": "18811"
}
}
}
}
Replace the path with the actual location where you cloned the repo. Use --project (not --directory) so uv run picks up the project's .venv.
After saving the config, restart Claude Desktop. The DAZ Studio tools will appear in Claude's tool palette.
Cursor
Add to .cursor/mcp.json in your project, or ~/.cursor/mcp.json for global access:
{
"mcpServers": {
"vangard-daz-mcp": {
"command": "uv",
"args": [
"run",
"--project",
"/absolute/path/to/daz-mcp-server",
"vangard-daz-mcp"
],
"env": {
"DAZ_HOST": "localhost",
"DAZ_PORT": "18811"
}
}
}
}
VS Code (GitHub Copilot / MCP extension)
Add to .vscode/mcp.json in your workspace:
{
"servers": {
"vangard-daz-mcp": {
"type": "stdio",
"command": "uv",
"args": [
"run",
"--project",
"/absolute/path/to/daz-mcp-server",
"vangard-daz-mcp"
],
"env": {
"DAZ_HOST": "localhost",
"DAZ_PORT": "18811"
}
}
}
}
Verifying the connection
After configuration, ask your MCP client:
Check if DAZ Studio is running
Claude will call daz_status. A successful response looks like:
{ "running": true, "version": "1.3.0" }
If it fails, see the Troubleshooting section below.
Domain Reference Files (SKILL files)
The repository ships six SKILL files — curated knowledge documents that you can ask Claude (or any MCP client) to read before working in a particular area of DAZ Studio. They exist because LLMs have reasonable general knowledge about 3D software but will make confident, wrong assumptions about DAZ Studio specifics — inverted rotation signs, broken API methods, generation-specific bone names, and so on. Loading the right SKILL file before a task corrects those assumptions and produces dramatically better results.
How to use them
Ask Claude to read the relevant file at the start of a session or task:
Read the file SKILL_DAZ_STUDIO.md before we begin.
Before writing any DazScript code, read SKILL_DAZSCRIPT.md.
You can load more than one if your task spans domains:
Read SKILL_DAZ_STUDIO.md and SKILL_CINEMA.md — we're going to set up a portrait shot.
SKILL file reference
| File | Domain | Load when… |
|---|---|---|
SKILL_DAZ_STUDIO.md |
DAZ Studio conventions | Starting any session — covers coordinate system inversions, camera Y-rotation being backwards, bone rotation limits, and known tool limitations |
SKILL_DAZSCRIPT.md |
DazScript API | Writing or debugging custom scripts via daz_execute — documents verified-working API patterns and a list of broken/wrong methods to avoid |
SKILL_SCENE.md |
Scene management | Working with scene hierarchy, content library, spatial layout, materials, or batch operations |
SKILL_ACTORS.md |
Characters & posing | Working with morphs, emotions, body language, gaze direction, wardrobe, or multi-character interactions |
SKILL_CINEMA.md |
Cameras, lighting & rendering | Composing shots, setting up lighting rigs, animating cameras, or running renders |
SKILL_DEVELOPMENT.md |
MCP server internals | Modifying or extending the MCP server itself — module layout, how to add tools, the script registry |
When to load SKILL_DAZ_STUDIO.md
This is the most important file and the one most likely to save you from a frustrating session. Key things it corrects:
- Camera Y rotation is inverted — positive values turn the camera left, not right. Every other 3D application does this the other way.
daz_look_at_pointapplies rotations in the wrong direction — always verify in the viewport and correct manually.daz_orbit_camera_aroundaims at the figure's root (feet), not the face — use explicit world-space coordinates for portrait work instead.- Genesis 9 faces +Z by default — "in front of" a character is at a positive Z coordinate.
- Focal distance requires true 3D distance — using Z distance alone throws portrait shots out of focus.
Available Tools
📚 Documentation Tools
daz_script_help
Get DazScript documentation, examples, and best practices.
Arguments:
topic(string, default"overview"): Documentation topic to retrieve
Available Topics:
overview- DazScript environment basicsgotchas- Critical mistakes that cause timeouts or errorscamera- Camera creation, positioning, and aiminglight- Light creation, types, and three-point lightingenvironment- Iray environment settings and lighting modesscene- Scene management (new, save, load, selection)properties- Node properties, transforms, and morphscontent- Browsing and loading content from librarycoordinates- Coordinate system and positioning referenceposing- Figure posing, bone hierarchy, morphs vs poses, rotation gotchasmorphs- Morph discovery, searching, value ranges, and managementhierarchy- Scene hierarchy, parent-child relationships, parenting operationsinteraction- Multi-character interaction, look-at mechanics, world-space posingbatch- Batch operations patterns and performance optimizationviewport- Viewport and camera control, spherical positioning, presetsanimation- Keyframe animation, timeline control, image sequence exportrendering- Rendering workflows, multi-camera, batch render, animation export
Returns: Formatted documentation with examples
Use when: Before writing custom DazScript code to learn correct patterns and avoid common mistakes.
Example:
daz_script_help("camera") # Get camera documentation
daz_script_help("gotchas") # Learn critical gotchas
🔍 Inspection Tools
daz_status
Check DAZ Studio connectivity and version.
Returns:
{
"running": true,
"version": "1.3.0"
}
Use when: Verifying DAZ Studio is running and the connection works.
daz_scene_info
Get a snapshot of the current scene.
Returns:
{
"sceneFile": "/path/to/scene.duf",
"selectedNode": "Genesis 9",
"figures": [
{"name": "Genesis9", "label": "Genesis 9", "type": "DzFigure"}
],
"cameras": [
{"name": "Camera", "label": "Camera 1"}
],
"lights": [
{"name": "DistantLight", "label": "Distant Light", "type": "DzDistantLight"}
],
"totalNodes": 3247
}
Use when: You need an overview of what's in the scene (characters, cameras, lights).
Note: Does not enumerate all nodes (scenes can have 1000+ nodes). Use daz_execute for fine-grained queries.
daz_get_node
Read all numeric properties of a node by its label or internal name.
Arguments:
node_label(string): Display label or internal name (e.g., "Genesis 9")
Returns:
{
"name": "Genesis9",
"label": "Genesis 9",
"type": "DzFigure",
"properties": {
"X Translate": 0.0,
"Y Translate": 0.0,
"Z Translate": 0.0,
"X Rotate": 0.0,
"Y Rotate": 0.0,
"Z Rotate": 0.0,
"Scale": 100.0,
"Head Size": 0.5
}
}
Use when: You need to read transforms, morphs, or other numeric properties on a node.
daz_get_selected_nodes
Return the nodes currently selected in the DAZ Studio viewport.
Returns:
{
"count": 2,
"nodes": [
{"label": "Genesis 9", "name": "Genesis9"},
{"label": "Camera 1", "name": "Camera"}
]
}
Use when: The user has manually selected items in DAZ Studio and wants the AI to act on that selection.
🔬 Morph Discovery Tools
daz_list_morphs
List all morphs (numeric properties) on a node with their current values.
Arguments:
node_label(string): Node display label or internal nameinclude_zero(bool, defaultFalse): Include morphs with zero values
Returns:
{
"morphs": [
{"label": "Height", "name": "Height", "value": 1.05, "path": "Morphs/Body"},
{"label": "Head Size", "name": "HeadSize", "value": 0.9, "path": "Morphs/Head"}
],
"count": 2,
"nodeLabel": "Genesis 9"
}
Use when:
- Discovering what morphs are available on a figure
- Checking which morphs are currently active
- Building morph selection UIs
- Exploring character customization options
Example:
# List only active morphs (non-zero values)
daz_list_morphs("Genesis 9", include_zero=False)
# List ALL available morphs (warning: may return 500-1000+ morphs)
daz_list_morphs("Genesis 9", include_zero=True)
Note: Genesis figures can have 1000+ morphs. Use include_zero=False to see only active morphs, or use daz_search_morphs to filter by pattern.
daz_search_morphs
Search for morphs matching a name pattern.
Arguments:
node_label(string): Node display label or internal namepattern(string): Substring to search for (case-insensitive)include_zero(bool, defaultFalse): Include morphs with zero values
Returns:
{
"morphs": [
{"label": "Smile", "name": "Smile", "value": 0.0, "path": "Morphs/Expressions"},
{"label": "Smile Open", "name": "SmileOpen", "value": 0.0, "path": "Morphs/Expressions"}
],
"count": 2,
"pattern": "smile",
"nodeLabel": "Genesis 9"
}
Use when:
- Finding specific morphs (e.g., all smile morphs, head morphs)
- Discovering morphs by category or body part
- Building filtered morph lists
Example:
# Find all smile-related morphs
daz_search_morphs("Genesis 9", "smile", include_zero=True)
# Find active head morphs only
daz_search_morphs("Genesis 9", "head", include_zero=False)
# Find all facial expression morphs
daz_search_morphs("Genesis 9", "express", include_zero=True)
Common search patterns:
"smile","frown","express"- Facial expressions"head","face","nose"- Facial features"arm","leg","body"- Body parts"muscle","tone","fit"- Body definition"height","scale"- Size adjustments
🌳 Scene Hierarchy Tools
daz_get_node_hierarchy
Get complete hierarchy tree for a node with all descendants.
Arguments:
node_label(string): Root node display label or internal namemax_depth(int, default10): Maximum recursion depth (0 = unlimited)
Returns:
{
"node": "Genesis 9",
"hierarchy": {
"label": "Genesis 9",
"name": "Genesis9",
"type": "DzFigure",
"children": [
{
"label": "hip",
"name": "hip",
"type": "DzBone",
"children": [...]
}
]
},
"totalDescendants": 127
}
Use when:
- Understanding skeleton structure
- Exploring bone relationships
- Mapping complex scene hierarchies
- Finding all descendants of a node
Example:
# Get skeleton hierarchy with depth limit
daz_get_node_hierarchy("Genesis 9", max_depth=3)
# Get full hierarchy (warning: Genesis 9 has 100+ bones)
daz_get_node_hierarchy("Genesis 9", max_depth=0)
daz_list_children
List direct children of a node.
Arguments:
node_label(string): Parent node display label or internal name
Returns:
{
"node": "hip",
"children": [
{"label": "pelvis", "name": "pelvis", "type": "DzBone"},
{"label": "lThighBend", "name": "lThighBend", "type": "DzBone"},
{"label": "rThighBend", "name": "rThighBend", "type": "DzBone"}
],
"count": 3
}
Use when:
- Exploring hierarchy one level at a time
- Checking if a node has children
- Building custom tree structures
Example:
# List children of Genesis 9 root
daz_list_children("Genesis 9")
# Check if node has children
result = daz_list_children("Camera 1")
if result["count"] == 0:
print("No children")
daz_get_parent
Get parent node of a node.
Arguments:
node_label(string): Child node display label or internal name
Returns:
{
"node": "lHand",
"parent": {
"label": "lForearmBend",
"name": "lForearmBend",
"type": "DzBone"
}
}
Returns null for parent if node is a root (no parent).
Use when:
- Traversing hierarchy upward
- Finding what contains a node
- Checking if node is a root
Example:
# Get parent of a bone
result = daz_get_parent("lHand")
print(f"Parent: {result['parent']['label']}")
# Check if node is root
result = daz_get_parent("Genesis 9")
if result["parent"] is None:
print("This is a root node")
daz_set_parent
Set parent of a node (parenting operation).
Arguments:
node_label(string): Node to parentparent_label(string): New parent nodemaintain_world_transform(bool, defaultTrue): If true, adjust local transform to keep same world position
Returns:
{
"success": true,
"node": "Sword",
"newParent": "rHand",
"previousParent": null
}
Use when:
- Attaching props to figures (e.g., weapon to hand)
- Parenting cameras to nodes
- Reorganizing scene hierarchy
- Attaching clothing to bones
Example:
# Attach sword to right hand (maintains position)
daz_set_parent("Sword", "rHand", maintain_world_transform=True)
# Parent camera to figure (follows figure)
daz_set_parent("Camera 1", "Genesis 9", maintain_world_transform=True)
# Attach bracelet to forearm
daz_set_parent("Bracelet", "lForearmBend", maintain_world_transform=True)
Note: When maintain_world_transform=True, the node's world position stays the same, but local transform values (X/Y/Z Translate, Rotate) change to account for the new parent's transform.
⚡ Batch Operations
Batch operations allow you to modify multiple nodes or properties in a single call, significantly improving performance. Each operation has individual error handling, so failures don't abort the entire batch.
Performance benefits:
- Single script call (all operations execute in one round-trip)
- No HTTP/network overhead between operations
- 5-10x faster than individual calls for typical batches
- Individual error handling without aborting the batch
Common use cases:
- Applying facial expressions (multiple morphs at once)
- Configuring lighting setups (multiple light properties)
- Moving/rotating groups of props together
- Showing/hiding groups of nodes for scene management
- Resetting multiple cameras or lights to default values
daz_batch_set_properties
Set multiple properties on one or more nodes in a single call.
Arguments:
operations(array): List of operation objects, each containing:nodeLabel(string): Display label of the nodepropertyName(string): Property label or internal namevalue(float): New value for the property
Returns:
{
"results": [
{"success": true, "node": "Genesis 9", "property": "X Translate", "value": 100},
{"success": false, "node": "Missing", "error": "Node not found: Missing"}
],
"successCount": 1,
"failureCount": 1,
"total": 2
}
Use when: Setting 3+ properties, applying facial expressions, configuring scene presets.
Example:
# Apply "surprised" facial expression
daz_batch_set_properties([
{"nodeLabel": "Genesis 9", "propertyName": "PHMEyesWide", "value": 0.8},
{"nodeLabel": "Genesis 9", "propertyName": "PHMBrowsUp", "value": 0.7},
{"nodeLabel": "Genesis 9", "propertyName": "PHMMouthOpen", "value": 0.4}
])
# Configure lighting setup
daz_batch_set_properties([
{"nodeLabel": "Key Light", "propertyName": "Flux", "value": 2000},
{"nodeLabel": "Fill Light", "propertyName": "Flux", "value": 800},
{"nodeLabel": "Rim Light", "propertyName": "Flux", "value": 2500}
])
Performance: Setting 10 morphs via batch is ~5-10x faster than 10 individual daz_set_property calls.
daz_batch_transform
Apply the same transform properties to multiple nodes.
Arguments:
node_labels(array): List of node display labels to transformtransforms(object): Dictionary of property names to values (e.g.,{"XTranslate": 50, "YRotate": 45})
Returns:
{
"results": [
{"success": true, "node": "Prop1", "applied": ["X Translate", "Y Rotate"]},
{"success": false, "node": "Missing", "error": "Node not found: Missing"}
],
"successCount": 1,
"failureCount": 1,
"total": 2
}
Use when: Moving, rotating, or scaling multiple objects by the same amount.
Example:
# Move multiple props to the right
daz_batch_transform(
["Chair", "Table", "Lamp"],
{"XTranslate": 100}
)
# Rotate and scale multiple objects
daz_batch_transform(
["Prop1", "Prop2", "Prop3"],
{"YRotate": 45, "Scale": 1.2}
)
# Reset rotation for all cameras
daz_batch_transform(
["Camera 1", "Camera 2", "Camera 3"],
{"XRotate": 0, "YRotate": 0, "ZRotate": 0}
)
Note: Only properties that exist on each node are applied. Missing properties are silently skipped.
daz_batch_visibility
Show or hide multiple nodes in the viewport and renders.
Arguments:
node_labels(array): List of node display labels to modifyvisible(bool, defaultTrue): True to show nodes, False to hide them
Returns:
{
"results": [
{"success": true, "node": "Ground", "visible": false},
{"success": true, "node": "Sky Dome", "visible": false}
],
"successCount": 2,
"failureCount": 0,
"total": 2
}
Use when: Scene management, testing configurations, optimizing render times.
Example:
# Hide all cameras
daz_batch_visibility(["Camera 1", "Camera 2", "Camera 3"], visible=False)
# Hide environment elements for character close-up
daz_batch_visibility(["Ground", "Sky Dome", "Background"], visible=False)
# Show all weapons
daz_batch_visibility(["Sword", "Shield", "Helmet"], visible=True)
Note: Hidden nodes remain in the scene but are not visible in viewport or renders.
daz_batch_select
Select multiple nodes in the DAZ Studio scene.
Arguments:
node_labels(array): List of node display labels to selectadd_to_selection(bool, defaultFalse): If True, add to current selection; if False, replace current selection
Returns:
{
"selected": ["Genesis 9", "Genesis 8 Female"],
"count": 2,
"total": 2
}
Use when: Selecting groups of nodes for inspection or operations.
Example:
# Select multiple characters
daz_batch_select(["Genesis 9", "Genesis 8 Female"])
# Add props to current selection
daz_batch_select(["Sword", "Shield"], add_to_selection=True)
# Select all lights
daz_batch_select(["Spot Light 1", "Distant Light 1", "Point Light 1"])
Note: Nodes that don't exist are silently skipped. Returns count of successful selections.
📷 Viewport and Camera Control
Viewport control tools enable programmatic camera positioning, framing, and preset management for automated scene photography and consistent camera angles.
Key capabilities:
- Switch active viewport camera
- Position camera using spherical coordinates (orbit around target)
- Auto-frame camera to show objects (calculates bounding box)
- Save/load camera positions as presets (JSON-serializable)
- Reusable camera angles across scenes
daz_set_active_camera
Set which camera is active in the DAZ Studio viewport.
Arguments:
camera_label(string): Display label of the camera to activate
Returns:
{
"success": true,
"camera": "Camera 1",
"previousCamera": "Perspective View"
}
Use when: Switching between predefined camera angles, previewing from multiple viewpoints.
Example:
# Switch to specific camera
daz_set_active_camera("Camera 1")
# Switch back to default
daz_set_active_camera("Perspective View")
daz_orbit_camera_around
Position camera orbiting around a target node at specified angle and distance.
Arguments:
camera_label(string): Camera to positiontarget_label(string): Target node to orbit arounddistance(float, default200.0): Distance from target in cmangle_horizontal(float, default45.0): Horizontal angle in degrees (0=front/+Z, 90=right/+X)angle_vertical(float, default15.0): Vertical angle in degrees (positive=above)
Returns:
{
"success": true,
"camera": "Camera 1",
"target": "Genesis 9",
"position": {"x": 141.4, "y": 151.8, "z": 141.4},
"targetPosition": {"x": 0, "y": 100, "z": 0}
}
Use when: Character photography, product shots, turntable animations, establishing camera angles.
Example:
# Front 3/4 view (classic portrait angle)
daz_orbit_camera_around("Camera 1", "Genesis 9",
distance=200, angle_horizontal=45, angle_vertical=15)
# Side view from left
daz_orbit_camera_around("Camera 1", "Genesis 9",
distance=150, angle_horizontal=-90, angle_vertical=0)
# Bird's eye view
daz_orbit_camera_around("Camera 1", "Genesis 9",
distance=300, angle_horizontal=0, angle_vertical=60)
# Dramatic low angle
daz_orbit_camera_around("Camera 1", "Genesis 9",
distance=180, angle_horizontal=25, angle_vertical=-20)
Angle reference:
- Horizontal: 0°=front(+Z), 90°=right(+X), 180°=back(-Z), -90°=left(-X)
- Vertical: positive=above horizon, negative=below
Distance guidelines (170cm tall figure):
- Full body: 350-450cm
- Portrait: 80-120cm
- Face close-up: 30-50cm
daz_frame_camera_to_node
Frame camera to show a node by positioning at calculated distance.
Arguments:
camera_label(string): Camera to positionnode_label(string): Node to framedistance(float, optional): Distance from node center in cm. If not specified, auto-calculated as 2.5x largest bounding box dimension.
Returns:
{
"success": true,
"camera": "Camera 1",
"node": "Genesis 9",
"position": {"x": 0, "y": 100, "z": 450},
"nodeCenter": {"x": 0, "y": 100, "z": 0},
"nodeSize": {"x": 50, "y": 170, "z": 40}
}
Use when: Auto-framing objects of varying sizes, consistent framing across scenes.
Example:
# Frame character (auto distance)
daz_frame_camera_to_node("Camera 1", "Genesis 9")
# Frame prop with specific distance
daz_frame_camera_to_node("Camera 1", "Sword", distance=50)
# Close-up on head
daz_frame_camera_to_node("Camera 1", "head", distance=30)
Note: Camera is positioned in front (+Z) and aimed at node's bounding box center. Auto-calculated distance is 2.5x the largest dimension.
daz_save_camera_preset
Save camera position and rotation as preset data.
Arguments:
camera_label(string): Camera to save
Returns:
{
"preset": {
"label": "Camera 1",
"transforms": {
"XTranslate": 0, "YTranslate": 100, "ZTranslate": 300,
"XRotate": -10, "YRotate": 0, "ZRotate": 0,
"XScale": 1.0, "YScale": 1.0, "ZScale": 1.0
}
}
}
Use when: Saving reusable camera angles, sharing camera positions across projects.
Example:
# Save camera position
preset = daz_save_camera_preset("Camera 1")
# Store to file
import json
with open("portrait_camera.json", "w") as f:
json.dump(preset, f)
Note: Preset data is JSON-serializable and can be applied to any camera.
daz_load_camera_preset
Restore camera position and rotation from preset data.
Arguments:
camera_label(string): Camera to modifypreset(dict): Preset dictionary fromdaz_save_camera_preset()(must containtransformskey)
Returns:
{
"success": true,
"camera": "Camera 1",
"applied": ["XTranslate", "YTranslate", "ZTranslate", "XRotate", "YRotate", "ZRotate"]
}
Use when: Restoring saved camera positions, applying same angle to multiple cameras.
Example:
# Load preset from file
import json
with open("portrait_camera.json") as f:
preset = json.load(f)
# Apply to camera
daz_load_camera_preset("Camera 1", preset["preset"])
# Apply same preset to multiple cameras
for cam in ["Camera 1", "Camera 2", "Camera 3"]:
daz_load_camera_preset(cam, preset["preset"])
Note: Preset can be applied to any camera, not just the original. Useful for synchronizing multiple cameras.
daz_list_cameras
List all cameras currently in the scene.
Returns:
{
"camera_count": 2,
"cameras": [
{"name": "Camera", "label": "Camera 1", "focal_length": 65.0},
{"name": "Camera2", "label": "Wide Shot", "focal_length": 35.0}
]
}
Use when: Discovering what cameras exist before calling daz_set_active_camera or daz_render_with_camera.
daz_create_camera
Create a new camera and add it to the scene.
Arguments:
label(string): Display name for the new camerax,y,z(float): World-space position in cm (defaults: 0, 150, 300)aim_at_label(string, optional): Aim the camera at this node's centrefocal_length(float, optional): Lens focal length in mm
Returns:
{
"label": "Close-up Cam",
"position": {"x": 0, "y": 160, "z": 120},
"focal_length": 85.0
}
Example:
daz_create_camera("Close-up Cam", x=0, y=160, z=120,
aim_at_label="Genesis 9", focal_length=85)
Note: Use daz_list_cameras to confirm the camera was added, and daz_set_active_camera to switch the active viewport.
🎬 Animation System
Animation tools enable keyframe-based property animation. Set keyframes at specific frames, and DAZ Studio interpolates smoothly between them. Supports animating any numeric property (transforms, morphs, lights, cameras).
Key capabilities:
- Set/get/remove keyframes on properties
- Timeline control (current frame, frame range)
- Export animations as image sequences
- Copy and offset animations between properties
- Inspect keyframe data programmatically
Common use cases:
- Character animation (walk cycles, gestures, facial expressions)
- Camera animation (dolly, pan, zoom)
- Product turntables (360° rotation)
- Morph animations (smile fade, eye blink)
- Multi-character choreography
daz_set_keyframe
Set a keyframe on a property at specified frame.
Arguments:
node_label(string): Node display labelproperty_name(string): Property label or internal nameframe(int): Frame number (0-based)value(float): Value at this frame
Returns:
{
"success": true,
"node": "Genesis 9",
"property": "X Translate",
"frame": 0,
"value": 0.0
}
Use when: Creating animations, defining key poses.
Example:
# Animate movement (0 to 100cm over 30 frames)
daz_set_keyframe("Genesis 9", "XTranslate", frame=0, value=0)
daz_set_keyframe("Genesis 9", "XTranslate", frame=30, value=100)
# Animate rotation (0 to 90 degrees)
daz_set_keyframe("Genesis 9", "YRotate", frame=0, value=0)
daz_set_keyframe("Genesis 9", "YRotate", frame=60, value=90)
# Animate morph (fade in smile)
daz_set_keyframe("Genesis 9", "PHMSmile", frame=0, value=0)
daz_set_keyframe("Genesis 9", "PHMSmile", frame=15, value=0.8)
Note: DAZ Studio interpolates between keyframes automatically. Setting keyframe at existing frame updates the value.
daz_get_keyframes
Get all keyframes for a property.
Arguments:
node_label(string): Node display labelproperty_name(string): Property label or internal name
Returns:
{
"keyframes": [
{"frame": 0, "value": 0.0},
{"frame": 30, "value": 100.0}
],
"count": 2
}
Use when: Inspecting animations, copying keyframes, checking if property is animated.
Example:
# Get keyframes
result = daz_get_keyframes("Genesis 9", "XTranslate")
for kf in result['keyframes']:
print(f"Frame {kf['frame']}: {kf['value']}")
# Copy keyframes to another node
for kf in result['keyframes']:
daz_set_keyframe("Genesis 8", "XTranslate", kf['frame'], kf['value'])
daz_remove_keyframe
Remove a keyframe at specified frame.
Arguments:
node_label(string): Node display labelproperty_name(string): Property label or internal nameframe(int): Frame number
Returns:
{
"success": true,
"node": "Genesis 9",
"property": "X Translate",
"frame": 15,
"removed": true
}
Use when: Removing specific keyframes, editing animation timing.
Example:
# Remove keyframe
daz_remove_keyframe("Genesis 9", "XTranslate", frame=15)
Note: Returns removed: false if no keyframe exists at that frame (not an error).
daz_clear_animation
Remove all keyframes from a property.
Arguments:
node_label(string): Node display labelproperty_name(string): Property label or internal name
Returns:
{
"success": true,
"node": "Genesis 9",
"property": "X Translate",
"removed": 5
}
Use when: Clearing animations, resetting properties to static state.
Example:
# Clear animation
result = daz_clear_animation("Genesis 9", "XTranslate")
print(f"Removed {result['removed']} keyframes")
# Clear all transform animations
for prop in ["XTranslate", "YTranslate", "ZTranslate", "XRotate", "YRotate", "ZRotate"]:
daz_clear_animation("Genesis 9", prop)
Note: More efficient than removing keyframes individually.
daz_set_frame
Set current animation frame.
Arguments:
frame(int): Frame number to move to
Returns:
{
"success": true,
"frame": 30,
"previousFrame": 0
}
Use when: Previewing animation, rendering specific frames.
Example:
# Jump to frame 30
daz_set_frame(30)
# Render all frames
info = daz_get_animation_info()
for frame in range(info['startFrame'], info['endFrame'] + 1):
daz_set_frame(frame)
daz_render(output_path=f"frame_{frame:04d}.png")
Note: Scene updates to show animated state at the frame.
daz_set_frame_range
Set animation frame range (start and end).
Arguments:
start_frame(int): First frame (typically 0)end_frame(int): Last frame
Returns:
{
"success": true,
"startFrame": 0,
"endFrame": 119,
"previousStart": 0,
"previousEnd": 30
}
Use when: Defining animation length before creating keyframes.
Example:
# 4-second animation (120 frames at 30fps)
daz_set_frame_range(0, 119)
# 10-second animation
daz_set_frame_range(0, 299)
Note: Frame range is inclusive (frames 0-119 = 120 frames). Duration = (end - start + 1) / fps.
daz_get_animation_info
Get animation timeline info (current frame, range, fps).
Returns:
{
"currentFrame": 0,
"startFrame": 0,
"endFrame": 119,
"fps": 30.0,
"totalFrames": 120,
"durationSeconds": 4.0
}
Use when: Checking timeline state before rendering, calculating duration.
Example:
# Get timeline info
info = daz_get_animation_info()
print(f"Animation: {info['durationSeconds']} seconds ({info['totalFrames']} frames)")
# Render entire animation
for frame in range(info['startFrame'], info['endFrame'] + 1):
daz_set_frame(frame)
daz_render(output_path=f"frame_{frame:04d}.png")
Note: FPS is typically 30 in DAZ Studio.
🎥 Advanced Rendering Control
Advanced rendering tools provide programmatic control for multi-camera rendering, animation export, and batch rendering operations.
Key capabilities:
- Render from specific camera without changing viewport
- Batch render from multiple cameras
- Export animations as image sequences
- Query render settings
- Automated rendering workflows
Common use cases:
- Multi-angle product shots (front, side, top, perspective)
- Character turntables (8-16 camera angles)
- Animation export (frame-by-frame image sequences)
- Test renders from multiple angles
- Multi-camera animation rendering
daz_render_with_camera
Render from specific camera without changing active viewport camera.
Arguments:
camera_label(string): Camera to render fromoutput_path(string, optional): Output file path (if not specified, renders to viewport)
Returns:
{
"success": true,
"camera": "Camera 1",
"outputPath": "/path/to/render.png"
}
Use when: Multi-camera batch renders, testing camera angles without disrupting viewport.
Example:
# Render from specific camera
daz_render_with_camera("Camera 1", output_path="/renders/cam1.png")
# Render from multiple cameras
for cam in ["Front", "Side", "Top"]:
daz_render_with_camera(cam, output_path=f"/renders/{cam}.png")
Note: Viewport camera remains unchanged. Previous render camera is restored automatically.
daz_get_render_settings
Get current render settings and configuration.
Returns:
{
"renderToFile": true,
"outputPath": "/path/to/output.png",
"currentCamera": "Camera 1",
"aspectRatio": 1.777,
"aspectWidth": 16,
"aspectHeight": 9
}
Use when: Verifying render configuration before batch operations, debugging render issues.
Example:
# Check render settings
settings = daz_get_render_settings()
print(f"Render camera: {settings['currentCamera']}")
print(f"Aspect: {settings['aspectWidth']}x{settings['aspectHeight']}")
# Verify configuration
if not settings['renderToFile']:
print("Warning: Render configured for viewport, not file")
daz_batch_render_cameras
Render from multiple cameras in sequence.
Arguments:
cameras(list[string]): List of camera labelsoutput_dir(string): Output directorybase_filename(string, default"render"): Base filename (camera name is appended)
Returns:
{
"success": true,
"rendered": [
{"camera": "Front", "outputPath": "/renders/product_Front.png"},
{"camera": "Side", "outputPath": "/renders/product_Side.png"}
],
"total": 2
}
Use when: Product photography, turntable renders, multi-angle test renders.
Example:
# Render from multiple cameras
daz_batch_render_cameras(
cameras=["Front", "Side", "Top", "Perspective"],
output_dir="/renders",
base_filename="product"
)
# Generates: product_Front.png, product_Side.png, product_Top.png, product_Perspective.png
# Turntable (8 cameras around character)
cameras = [f"Cam_{angle}" for angle in [0, 45, 90, 135, 180, 225, 270, 315]]
daz_batch_render_cameras(cameras, "/renders/turntable", "angle")
``
No comments yet
Be the first to share your take.