AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Blender Impl Animation

skill-impertio-studio-blender-bonsai-ifcopenshell-sverchok-claude-skill-package-blender-impl-animation · by Impertio-Studio

>

No reviews yet
0 installs
30 views
0.0% view→install

Install

$ agentstack add skill-impertio-studio-blender-bonsai-ifcopenshell-sverchok-claude-skill-package-blender-impl-animation

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No 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.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-impertio-studio-blender-bonsai-ifcopenshell-sverchok-claude-skill-package-blender-impl-animation)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
5mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

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 →
Are you the author of Blender Impl Animation? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

blender-impl-animation

Quick Reference

Critical Warnings

ALWAYS set the property value BEFORE calling keyframe_insert() — keyframes record the current value at call time.

ALWAYS call fcurve.update() after manually adding or modifying keyframe points via keyframe_points.add() or direct .co assignment.

ALWAYS create animation_data before accessing .action or .nla_tracks — call obj.animation_data_create() if obj.animation_data is None.

NEVER use bone.layers or pose.bone_groups in Blender 4.0+ — removed. Use BoneCollection API.

NEVER insert keyframes on objects not linked to any collection — they will exist in bpy.data but have no scene presence.

ALWAYS call scene.frame_set(frame) when you need depsgraph evaluation at that frame (e.g., for visibility keyframes, constraint evaluation). Direct scene.frame_current = frame does NOT trigger depsgraph update.

ALWAYS use bpy.data.objects.get("Name") with None-check instead of direct key access bpy.data.objects["Name"] — prevents KeyError crashes.

Decision Tree: AEC Animation Workflow

What type of AEC animation do you need?
├─ Construction sequence (4D BIM)?
│  ├─ Objects appear/disappear over time?
│  │  └─ WORKFLOW A: Visibility Phasing
│  └─ Objects move into position (crane sim)?
│     └─ WORKFLOW B: Transform Sequencing
├─ Camera walkthrough / flythrough?
│  ├─ Fixed path (predefined route)?
│  │  └─ WORKFLOW C: Path-Based Camera
│  └─ Point-to-point with smooth transitions?
│     └─ WORKFLOW D: Keyframed Camera
├─ Solar / daylight study?
│  └─ WORKFLOW E: Sun Path Animation
├─ Phasing visualization (design options)?
│  └─ WORKFLOW F: Collection Phasing
└─ Multiple animation clips combined?
   └─ WORKFLOW G: NLA Orchestration

Version Matrix: Implementation Features

| Feature | Blender 3.x | Blender 4.0+ | Blender 5.x | |---------|-------------|--------------|-------------| | Visibility/NLA/Path/Constraints | Available | Available | Available | | BoneCollection | Not available | NEW | Available | | bgl for overlays | Available | Deprecated | REMOVED |

Workflow A: Visibility Phasing (Construction Sequence)

Use when objects must appear/disappear at specific frames to simulate construction phases.

Step 1: Organize objects into phase collections

import bpy

# Create phase collections under the scene collection
phase_names = ["Phase_Foundation", "Phase_Structure", "Phase_Envelope", "Phase_Interior"]
phases = {}
for name in phase_names:
    col = bpy.data.collections.new(name)
    bpy.context.scene.collection.children.link(col)
    phases[name] = col

Step 2: Assign objects to phases

# Move objects to phase collections
# ALWAYS unlink from current collection first to avoid duplicates
def assign_to_phase(obj, phase_collection):
    for col in obj.users_collection:
        col.objects.unlink(obj)
    phase_collection.objects.link(obj)

Step 3: Keyframe visibility per phase

def animate_phase_visibility(obj, appear_frame, disappear_frame=None):
    """Keyframe object visibility for construction phasing."""
    # Hidden before appear_frame
    obj.hide_viewport = True
    obj.hide_render = True
    obj.keyframe_insert(data_path="hide_viewport", frame=appear_frame - 1)
    obj.keyframe_insert(data_path="hide_render", frame=appear_frame - 1)

    # Visible at appear_frame
    obj.hide_viewport = False
    obj.hide_render = False
    obj.keyframe_insert(data_path="hide_viewport", frame=appear_frame)
    obj.keyframe_insert(data_path="hide_render", frame=appear_frame)

    if disappear_frame is not None:
        obj.hide_viewport = False
        obj.hide_render = False
        obj.keyframe_insert(data_path="hide_viewport", frame=disappear_frame - 1)
        obj.keyframe_insert(data_path="hide_render", frame=disappear_frame - 1)

        obj.hide_viewport = True
        obj.hide_render = True
        obj.keyframe_insert(data_path="hide_viewport", frame=disappear_frame)
        obj.keyframe_insert(data_path="hide_render", frame=disappear_frame)

    # ALWAYS set CONSTANT interpolation for boolean visibility
    if obj.animation_data and obj.animation_data.action:
        for fc in obj.animation_data.action.fcurves:
            if fc.data_path in ("hide_viewport", "hide_render"):
                for kp in fc.keyframe_points:
                    kp.interpolation = 'CONSTANT'

Step 4: Apply to phase schedule

# Define schedule: {phase_name: (start_frame, end_frame or None)}
schedule = {
    "Phase_Foundation": (1, None),
    "Phase_Structure": (60, None),
    "Phase_Envelope": (120, None),
    "Phase_Interior": (180, None),
}

for phase_name, (start, end) in schedule.items():
    col = bpy.data.collections.get(phase_name)
    if col is None:
        continue
    for obj in col.objects:
        animate_phase_visibility(obj, start, end)

# Set timeline
bpy.context.scene.frame_start = 1
bpy.context.scene.frame_end = 250

Workflow B: Transform Sequencing (Crane/Assembly)

Use when objects must animate from off-screen or staging positions to final positions.

import bpy

def animate_assembly(obj, staging_location, final_location,
                     start_frame, end_frame, interpolation='BEZIER'):
    """Animate object from staging to final position."""
    obj.location = staging_location
    obj.keyframe_insert(data_path="location", frame=start_frame)

    obj.location = final_location
    obj.keyframe_insert(data_path="location", frame=end_frame)

    # Set interpolation
    if obj.animation_data and obj.animation_data.action:
        for fc in obj.animation_data.action.fcurves:
            if fc.data_path == "location":
                for kp in fc.keyframe_points:
                    kp.interpolation = interpolation

# Example: Lower beam from above
beam = bpy.data.objects.get("SteelBeam_01")
if beam:
    animate_assembly(
        beam,
        staging_location=(beam.location.x, beam.location.y, beam.location.z + 20),
        final_location=(beam.location.x, beam.location.y, beam.location.z),
        start_frame=60,
        end_frame=90
    )

Workflow C: Path-Based Camera Walkthrough

Use for architectural walkthroughs following a predefined curve path.

Step 1: Create camera and path

import bpy
from mathutils import Vector

# Create camera
cam_data = bpy.data.cameras.new("WalkthroughCam")
cam_data.lens = 24  # Wide angle for architecture
cam_obj = bpy.data.objects.new("WalkthroughCam", cam_data)
bpy.context.scene.collection.objects.link(cam_obj)

# Create path curve (or use existing)
curve_data = bpy.data.curves.new("CameraPath", type='CURVE')
curve_data.dimensions = '3D'
spline = curve_data.splines.new('NURBS')
# Define waypoints
points = [(0, 0, 1.7), (5, 0, 1.7), (5, 10, 1.7), (10, 10, 1.7)]
spline.points.add(count=len(points) - 1)
for i, (x, y, z) in enumerate(points):
    spline.points[i].co = (x, y, z, 1.0)  # NURBS uses 4D (w=1.0)
spline.use_endpoint_u = True
spline.order_u = 3

path_obj = bpy.data.objects.new("CameraPath", curve_data)
bpy.context.scene.collection.objects.link(path_obj)

Step 2: Add Follow Path constraint

# Add Follow Path constraint to camera
follow = cam_obj.constraints.new('FOLLOW_PATH')
follow.target = path_obj
follow.use_curve_follow = True
follow.forward_axis = 'FORWARD_Y'  # Camera looks along Y by default
follow.up_axis = 'UP_Z'

# Animate the path offset
follow.offset = 0.0
follow.keyframe_insert(data_path="offset", frame=1)
follow.offset = -100.0  # Full path traversal
follow.keyframe_insert(data_path="offset", frame=250)

# Set LINEAR interpolation for constant speed
cam_obj_action = cam_obj.animation_data.action
for fc in cam_obj_action.fcurves:
    if "offset" in fc.data_path:
        for kp in fc.keyframe_points:
            kp.interpolation = 'LINEAR'

Step 3: Optional: Track To constraint for look-at target

# Make camera look at a specific point during walkthrough
target = bpy.data.objects.new("CamTarget", None)  # Empty
bpy.context.scene.collection.objects.link(target)
target.location = (5, 5, 3)

track = cam_obj.constraints.new('TRACK_TO')
track.target = target
track.track_axis = 'TRACK_NEGATIVE_Z'
track.up_axis = 'UP_Y'
track.influence = 0.5  # Blend between path direction and target

Workflow D: Keyframed Camera (Point-to-Point)

Use for controlled camera transitions between specific viewpoints.

import bpy
from math import radians

def keyframe_camera_viewpoint(cam_obj, location, rotation_euler,
                              frame, interpolation='BEZIER'):
    """Set camera to a viewpoint and keyframe it."""
    cam_obj.location = location
    cam_obj.rotation_euler = rotation_euler
    cam_obj.keyframe_insert(data_path="location", frame=frame)
    cam_obj.keyframe_insert(data_path="rotation_euler", frame=frame)

    if cam_obj.animation_data and cam_obj.animation_data.action:
        for fc in cam_obj.animation_data.action.fcurves:
            for kp in fc.keyframe_points:
                if kp.co[0] == frame:
                    kp.interpolation = interpolation

# Define viewpoints: (location, rotation_euler, frame)
viewpoints = [
    ((20, -20, 10), (radians(60), 0, radians(135)), 1),
    ((5, -15, 5),   (radians(70), 0, radians(160)), 60),
    ((-5, 0, 2),    (radians(85), 0, radians(200)), 120),
    ((0, 10, 15),   (radians(30), 0, radians(250)), 180),
]

cam = bpy.data.objects.get("Camera")
if cam:
    for loc, rot, frame in viewpoints:
        keyframe_camera_viewpoint(cam, loc, rot, frame)

Workflow E: Sun Path Animation (Solar Study)

Use for daylight/shadow analysis across time-of-day or seasons.

import bpy
from math import radians, sin, cos

def animate_sun_arc(sun_obj, latitude, start_hour, end_hour,
                    frame_start, frame_end):
    """Animate sun lamp along simplified arc. See references/examples.md for full version."""
    total_frames = frame_end - frame_start
    total_hours = end_hour - start_hour

    for i in range(total_frames + 1):
        frame = frame_start + i
        t = i / total_frames
        hour = start_hour + t * total_hours
        hour_angle = (hour - 12) * 15
        altitude = max(0, min(90, 90 - abs(latitude) + 23.5 * sin(radians(hour_angle))))
        azimuth = hour_angle
        distance = 100
        x = distance * cos(radians(altitude)) * sin(radians(azimuth))
        y = distance * cos(radians(altitude)) * cos(radians(azimuth))
        z = distance * sin(radians(altitude))
        sun_obj.location = (x, y, z)
        sun_obj.keyframe_insert(data_path="location", frame=frame)

    # LINEAR interpolation for smooth arc
    if sun_obj.animation_data and sun_obj.animation_data.action:
        for fc in sun_obj.animation_data.action.fcurves:
            for kp in fc.keyframe_points:
                kp.interpolation = 'LINEAR'

# Setup: create Sun light + Track To constraint pointing at origin
sun_data = bpy.data.lights.new("SunStudy", type='SUN')
sun_data.energy = 5.0
sun_obj = bpy.data.objects.new("SunStudy", sun_data)
bpy.context.scene.collection.objects.link(sun_obj)

track = sun_obj.constraints.new('TRACK_TO')
target = bpy.data.objects.new("SunTarget", None)
bpy.context.scene.collection.objects.link(target)
target.location = (0, 0, 0)
track.target = target
track.track_axis = 'TRACK_NEGATIVE_Z'
track.up_axis = 'UP_Y'

animate_sun_arc(sun_obj, latitude=52.0, start_hour=6, end_hour=18,
                frame_start=1, frame_end=120)

Workflow F: Collection Phasing (Design Options)

Use when toggling entire collections to show design alternatives or construction phases.

import bpy

def animate_collection_visibility(collection, visible_start, visible_end=None):
    """Animate collection visibility using exclude flag via view layer.

    NOTE: Collection.hide_viewport can be keyframed directly.
    """
    # Keyframe collection visibility
    collection.hide_viewport = True
    collection.keyframe_insert(data_path="hide_viewport", frame=1)

    collection.hide_viewport = False
    collection.keyframe_insert(data_path="hide_viewport", frame=visible_start)

    if visible_end is not None:
        collection.hide_viewport = False
        collection.keyframe_insert(data_path="hide_viewport", frame=visible_end - 1)
        collection.hide_viewport = True
        collection.keyframe_insert(data_path="hide_viewport", frame=visible_end)

    # CONSTANT interpolation for boolean toggle
    if collection.animation_data and collection.animation_data.action:
        for fc in collection.animation_data.action.fcurves:
            for kp in fc.keyframe_points:
                kp.interpolation = 'CONSTANT'

# Example: Phase schedule
phases = {
    "Demolition": (1, 30),
    "Foundation": (30, 90),
    "Structure": (90, 150),
    "Envelope": (150, 210),
    "Finishes": (210, None),
}

for name, (start, end) in phases.items():
    col = bpy.data.collections.get(name)
    if col is not None:
        animate_collection_visibility(col, start, end)

Workflow G: NLA Orchestration

Use when combining multiple animation actions into a sequenced timeline. See [references/examples.md](references/examples.md) for full NLA example.

import bpy

def create_visibility_action(action_name):
    """Create a self-contained visibility action."""
    action = bpy.data.actions.new(name=action_name)
    fc = action.fcurves.new(data_path="hide_viewport")
    fc.keyframe_points.add(count=2)
    fc.keyframe_points[0].co = (0.0, 1.0)   # Hidden
    fc.keyframe_points[1].co = (1.0, 0.0)   # Visible
    for kp in fc.keyframe_points:
        kp.interpolation = 'CONSTANT'
    fc.update()
    return action

def sequence_on_nla(obj, actions_schedule):
    """Place actions on NLA tracks. actions_schedule: list of (action, start_frame, track_name)."""
    anim_data = obj.animation_data if obj.animation_data else obj.animation_data_create()
    for action, start_frame, track_name in actions_schedule:
        track = anim_data.nla_tracks.new()
        track.name = track_name
        strip = track.strips.new(name=action.name, start=start_frame, action=action)
        strip.blend_type = 'REPLACE'
        strip.use_auto_blend = False

# Batch apply: staggered appearance via NLA
collection = bpy.data.collections.get("Structure")
if collection:
    for i, obj in enumerate(collection.objects):
        action = create_visibility_action(f"Appear_{obj.name}")
        sequence_on_nla(obj, [(action, i * 10, f"Phase_{obj.name}")])

Batch Keyframe Operations

import bpy

def batch_keyframe_property(objects, data_path, frame, index=-1):
    """Insert keyframes for the current value on multiple objects."""
    for obj in objects:
        try:
            obj.keyframe_insert(data_path=data_path, frame=frame, index=index)
        except TypeError:
            pass  # Property not animatable on this object type

def batch_set_interpolation(objects, interpolation='LINEAR'):
    """Set interpolation type on all keyframes of given objects."""
    for obj in objects:
        if obj.animation_data and obj.animation_data.action:
            for fc in obj.animation_data.action.fcurves:
                for kp in fc.keyframe_points:
                    kp.interpolation = interpolation

def batch_clear_animation(objects):
    """Remove all animation data from objects."""
    for obj in objects:
        if obj.animation_data:
            obj.animation_data_clear()

Render Settings for Animation Output

import bpy
scene = bpy.context.scene
scene.frame_start = 1
scene.frame_end = 250
scene.render.filepath = "//render/construction_"  # // = blend-relative
scene.render.image_settings.file_format = 'PNG'   # PNG sequence (resumable)
scene.render.resolution_x = 1920
scene.render.resolution_y = 1080
scene.render.resolution_percentage = 100
scene.render.fps =

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [Impertio-Studio](https://github.com/Impertio-Studio)
- **Source:** [Impertio-Studio/Blender-Bonsai-ifcOpenshell-Sverchok-Claude-Skill-Package](https://github.com/Impertio-Studio/Blender-Bonsai-ifcOpenshell-Sverchok-Claude-Skill-Package)
- **License:** MIT
- **Homepage:** https://github.com/OpenAEC-Foundation

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.