Install
$ agentstack add skill-devanshutak25-agent-skills-houdini-viewport-states ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Houdini Python Viewport States
This skill helps you write, edit, and improve Python viewer state code for Houdini 21.0.
What are Python Viewer States?
A viewer state controls how Houdini interprets mouse movements, clicks, keys, and other input in the 3D viewport. Every interactive tool in Houdini (Rotate, Translate, the Handles tool) is a viewer state. Houdini lets you create custom viewer states in Python to build your own interactive viewport tools.
A custom state can:
- Display and respond to handles for parameter editing
- Respond to mouse, keyboard, and tablet events
- Display guide geometry (drawables, gadgets)
- Let users select geometry components
- Show context menus and info panels (HUD)
- Wrap actions in undo blocks
- Work with or without a specific node (nodeless states)
Available contexts: SOP, OBJ, DOP, COP (Copernicus), and LOP.
How to Use This Skill
Before writing any code, read the relevant reference file(s) from the references/ directory based on what the user needs. Use this decision tree:
What does the user need?
- Creating a new state from scratch
→ Read references/state-registration.md first (for boilerplate and structure) → Then read whichever feature references apply to their use case
- Adding/editing event handling (mouse, keyboard, tablet)
→ Read references/event-handlers.md
- Adding/editing guide geometry or drawables
→ Read references/drawables-and-guides.md
- Adding/editing handles (built-in or Python handles)
→ Read references/handles.md
- Adding/editing selection behavior
→ Read references/selectors.md
- Adding/editing context menus, hotkeys, or info panels
→ Read references/menus-and-info.md
- Migrating file-based state → HDA-embedded
→ Read references/state-registration.md (migration section)
- Undo support, debugging, or architectural patterns
→ Read references/patterns.md
- COP (Copernicus) or LOP state specifics
→ Read references/cop-lop-states.md
Multiple references will often be needed for a single task. For example, building a brush tool would require state-registration.md + event-handlers.md + drawables-and-guides.md + patterns.md (for undo).
Core Principles When Writing State Code
Structure
Every viewer state consists of two parts:
- A state class — implements behavior via event handler methods
- A
createViewerStateTemplate()function — registers the state with Houdini, binding
handles, selectors, menus, gadgets, and hotkeys to the state template
State Class Pattern
import hou
import viewerstate.utils as su
class State(object):
def __init__(self, state_name, scene_viewer):
self.state_name = state_name
self.scene_viewer = scene_viewer
# Event handlers go here (onEnter, onMouseEvent, etc.)
Key Rules
- The
__init__receivesstate_name(string) andscene_viewer(hou.SceneViewer) - You do NOT have access to the node in
__init__— useonEnter(kwargs)where
kwargs["node"] is available
- Event handlers receive a single
kwargsdict containing context-specific items - Return
Truefrom input event handlers to consume the event (stops propagation) - Return
False(default) to let the event continue to other consumers - Consuming events carelessly can break selectors and other Houdini UI
- Store references to Drawable objects on
selfto prevent garbage collection - Cache geometry references (e.g., from
node.inputs()[0].geometry()) rather than
re-fetching per event — Houdini builds acceleration structures for intersection
File-Based Development Workflow (Recommended)
The recommended workflow for developing states under version control:
- Develop as a file-based state in
$HOUDINI_USER_PREF_DIR/viewer_states/ - Test iteratively (Houdini auto-registers on startup; use reload for changes)
- Version control the
.pyfile with git (clean diffs, standard workflow) - Migrate to HDA when ready to ship — embed the code in the asset's State Script
See references/state-registration.md for the full registration boilerplate and migration guide.
kwargs Dictionary
Most event handlers receive a kwargs dict. Common keys include:
"node"— hou.OpNode for the current node (not available in nodeless states)"ui_event"— hou.ViewerEvent for input events (mouse, key)"state_parms"— dict of state parameter names/values"state_flags"— dict of flags you can set- Menu toggle/radio values are injected directly into kwargs by their item IDs
Reference Files
| File | Contents | |------|----------| | references/state-registration.md | File-based & HDA registration, naming, migration workflow | | references/event-handlers.md | All lifecycle & UI event handler signatures and behavior | | references/drawables-and-guides.md | SimpleDrawable, GeometryDrawable, TextDrawable, gadgets | | references/handles.md | Static & dynamic handle binding, onHandleToState/onStateToHandle | | references/selectors.md | Geometry, object, drawable selectors; volatile & existing selection | | references/menus-and-info.md | Context menus, hotkeys, info panels (HUD) | | references/patterns.md | Undo, debugging, state machine patterns, performance tips | | references/cop-lop-states.md | COP (Copernicus) and LOP viewer state specifics |
Quick Examples
Minimal SOP State (file-based)
import hou
import viewerstate.utils as su
class State(object):
def __init__(self, state_name, scene_viewer):
self.state_name = state_name
self.scene_viewer = scene_viewer
def onEnter(self, kwargs):
self.scene_viewer.setPromptMessage("My custom state is active")
def onMouseEvent(self, kwargs):
ui_event = kwargs["ui_event"]
dev = ui_event.device()
self.log("Mouse:", dev.mouseX(), dev.mouseY())
return False
def createViewerStateTemplate():
state_typename = "my_custom_state"
state_label = "My Custom State"
state_cat = hou.sopNodeTypeCategory()
template = hou.ViewerStateTemplate(state_typename, state_label, state_cat)
template.bindFactory(State)
template.bindIcon("MISC_python")
return template
Minimal OBJ Nodeless State (file-based)
import hou
import viewerstate.utils as su
class State(object):
def __init__(self, state_name, scene_viewer):
self.state_name = state_name
self.scene_viewer = scene_viewer
def onGenerate(self, kwargs):
self.scene_viewer.setPromptMessage("Inspector active — move mouse over geometry")
def onMouseEvent(self, kwargs):
ui_event = kwargs["ui_event"]
origin, direction = ui_event.ray()
self.log("Ray origin:", origin)
return False
def createViewerStateTemplate():
state_typename = "my_inspector"
state_label = "My Inspector"
state_cat = hou.objNodeTypeCategory()
template = hou.ViewerStateTemplate(state_typename, state_label, state_cat)
template.bindFactory(State)
template.bindIcon("MISC_python")
return template
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: devanshutak25
- Source: devanshutak25/agent-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.