[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6HQ3DH9F4SM4WDF5SC947CF":3,"skill-same:01M6HQ3DH9F4SM4WDF5SC947CF":96},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":39,"linkOnly":40,"markdownContent":41,"markdownBody":42,"frontMatter":43,"refName":76,"commitSha":77,"skillDirectory":78,"forksCount":79,"repositoryHtmlUrl":80,"repositoryHomepageUrl":6,"ownerHtmlUrl":81,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":82,"install":83,"resources":95},"01M6HQ3DH9F4SM4WDF5SC947CF","godot-setup-animationtree",null,"用于设置 AnimationTree 节点的状态机驱动动画， 创建 AnimationNodeStateMachine 图形，配置 BlendSpace2D\u002F3D 进行运动混合，实现状态过渡条件， 或创建动画混合树进行复杂的动画混合。 支持玩家角色动画、NPC 和复杂动画系统。","welflau\u002Fai-dev-system","welflau","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F7010385?v=4","01M6HPTDGF18RFY07M229P8CTM","01M6HPTDMRMZCJPYBFEA9XVVYT",3,"MIT","https:\u002F\u002Fgithub.com\u002Fwelflau\u002Fai-dev-system\u002Fblob\u002Fmain\u002Fbackend\u002Fconfig_packs\u002Fgodot-dev\u002Fclaude\u002Fskills\u002Fgodot-setup-animationtree\u002FSKILL.md",[],[18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],"godot setup animationtree","setup","animationtree","godot","README","true","advanced","machine","动画","scenes","state-machine","superpowers","linux","生成","tool","game","3D","Animation","state","development","windows","2026-11-10 10:12:30",false,"---\nname: godot-setup-animationtree\nversion: 1.0.0\ndisplayName: 设置 AnimationTree 状态机\ndescription: >\n  用于设置 AnimationTree 节点的状态机驱动动画，\n  创建 AnimationNodeStateMachine 图形，配置 BlendSpace2D\u002F3D\n  进行运动混合，实现状态过渡条件，\n  或创建动画混合树进行复杂的动画混合。\n  支持玩家角色动画、NPC 和复杂动画系统。\nauthor: Asreonn\nlicense: MIT\ncategory: game-development\ntype: tool\ndifficulty: advanced\naudience: [developers]\nkeywords:\n  - godot\n  - animation\n  - animationtree\n  - state-machine\n  - blendspace\n  - blendspace2d\n  - blendspace3d\n  - transitions\n  - animationtreeplayer\n  - locomotion\nplatforms: [macos, linux, windows]\nrepository: https:\u002F\u002Fgithub.com\u002Fasreonn\u002Fgodot-superpowers\nhomepage: https:\u002F\u002Fgithub.com\u002Fasreonn\u002Fgodot-superpowers#readme\n\npermissions:\n  filesystem:\n    read: [\".gd\", \".tscn\", \".tres\"]\n    write: [\".tscn\", \".tres\", \".gd\"]\n  git: true\n\nbehavior:\n  auto_rollback: true\n  validation: true\n  git_commits: true\n\noutputs: \"AnimationTree 节点配置、AnimationNodeStateMachine 图形、BlendSpace2D\u002F3D 设置、过渡条件、动画控制器脚本\"\nrequirements: \"Git 仓库，Godot 4.x，AnimatedSprite3D 或带 AnimationPlayer 的 Sprite2D\"\nexecution: \"全自动场景生成和脚本更新\"\nintegration: \"与 godot-add-signals 配合处理动画事件，与 godot-extract-to-scenes 配合组织角色场景\"\n---\n\n# 设置 AnimationTree 状态机\n\n## 核心原则\n\n**动画是状态驱动的，不是帧驱动的。** 使用 AnimationTree 管理动画状态，使用 BlendSpace 进行平滑的参数混合，使用过渡实现状态切换。避免在游戏逻辑代码中直接调用 AnimationPlayer 播放。\n\n## 本技能的功能\n\n设置完整的 AnimationTree 系统：\n\n1. **AnimationTree Node 结构** - 创建树节点并绑定动画播放器\n2. **AnimationNodeStateMachine** - 构建包含入口\u002F出口状态的状态机图形\n3. **BlendSpace2D\u002F3D** - 基于速度\u002F输入配置运动混合\n4. **状态过渡** - 定义条件（布尔、表达式、基于时间）的状态切换\n5. **混合树** - 使用 OneShot、Add2、Blend2 节点创建复杂的动画混合\n\n## AnimationTree 设置\n\n### 基本 AnimationTree 配置\n\n**修改前（直接使用 AnimationPlayer）：**\n```gdscript\n# player_animation.gd - Manual animation management\nextends CharacterBody2D\n\n@onready var anim_player: AnimationPlayer = $AnimationPlayer\n\nfunc _physics_process(delta):\n    var velocity = Input.get_vector(\"ui_left\", \"ui_right\", \"ui_up\", \"ui_down\")\n\n    if velocity.length() > 0:\n        if not anim_player.current_animation == \"run\":\n            anim_player.play(\"run\")\n    else:\n        if not anim_player.current_animation == \"idle\":\n            anim_player.play(\"idle\")\n```\n\n**修改后（使用 AnimationTree）：**\n```gdscript\n# player_animation.gd - State-driven animation\nextends CharacterBody2D\n\n@onready var animation_tree: AnimationTree = $AnimationTree\n@onready var playback: AnimationNodeStateMachinePlayback\n\nfunc _ready():\n    animation_tree.active = true\n    playback = animation_tree.get(\"parameters\u002Fplayback\")\n\nfunc _physics_process(delta):\n    var input_dir = Input.get_vector(\"ui_left\", \"ui_right\", \"ui_up\", \"ui_down\")\n\n    # Update blend position for BlendSpace2D\n    animation_tree.set(\"parameters\u002Fblend_position\", input_dir)\n\n    # Transition states\n    if input_dir.length() > 0.1:\n        playback.travel(\"Locomotion\")\n    else:\n        playback.travel(\"Idle\")\n```\n\n**生成的场景：**\n```ini\n# player.tscn\n[gd_scene load_steps=6 format=3]\n\n[ext_resource type=\"Script\" path=\"res:\u002F\u002Fplayer_animation.gd\" id=\"1_abc123\"]\n\n[sub_resource type=\"AnimationNodeAnimation\" id=\"AnimationNodeAnimation_idle\"]\nanimation = &\"idle\"\n\n[sub_resource type=\"AnimationNodeBlendSpace2D\" id=\"AnimationNodeBlendSpace2D_loco\"]\nblend_point_0\u002Fnode = SubResource(\"AnimationNodeAnimation_idle\")\nblend_point_0\u002Fpos = Vector2(0, 0)\nblend_point_1\u002Fnode = SubResource(\"AnimationNodeAnimation_walk\")\nblend_point_1\u002Fpos = Vector2(0, 1)\nblend_point_2\u002Fnode = SubResource(\"AnimationNodeAnimation_run\")\nblend_point_2\u002Fpos = Vector2(0, 1.5)\n\n[sub_resource type=\"AnimationNodeStateMachine\" id=\"AnimationNodeStateMachine_main\"]\nstates\u002FIdle\u002Fnode = SubResource(\"AnimationNodeAnimation_idle\")\nstates\u002FIdle\u002Fposition = Vector2(300, 100)\nstates\u002FLocomotion\u002Fnode = SubResource(\"AnimationNodeBlendSpace2D_loco\")\nstates\u002FLocomotion\u002Fposition = Vector2(500, 100)\n\n[sub_resource type=\"AnimationNodeStateMachinePlayback\" id=\"AnimationNodeStateMachinePlayback_main\"]\n\n[node name=\"Player\" type=\"CharacterBody2D\"]\nscript = ExtResource(\"1_abc123\")\n\n[node name=\"AnimationPlayer\" type=\"AnimationPlayer\" parent=\".\"]\n\n[node name=\"AnimationTree\" type=\"AnimationTree\" parent=\".\"]\nanim_player = NodePath(\"..\u002FAnimationPlayer\")\ntree_root = SubResource(\"AnimationNodeStateMachine_main\")\nparameters\u002Fplayback = SubResource(\"AnimationNodeStateMachinePlayback_main\")\nparameters\u002Fblend_position = Vector2(0, 0)\n```\n\n### AnimationTree 激活\n\n```gdscript\n# Essential setup for AnimationTree\nfunc _ready():\n    # Activate the tree (must be done after node is ready)\n    animation_tree.active = true\n\n    # Get reference to state machine playback\n    playback = animation_tree.get(\"parameters\u002Fplayback\")\n\n    # Optional: Set initial state\n    playback.start(\"Idle\")\n```\n\n## AnimationNodeStateMachine\n\n### 状态机结构\n\n**状态机图形：**\n```ini\n# State machine nodes in .tscn format\n[sub_resource type=\"AnimationNodeStateMachine\" id=\"AnimationNodeStateMachine_character\"]\nstates\u002FStart\u002Fposition = Vector2(150, 100)\nstates\u002FEnd\u002Fposition = Vector2(800, 100)\n\n# Idle state (single animation)\nstates\u002FIdle\u002Fnode = SubResource(\"AnimationNodeAnimation_idle\")\nstates\u002FIdle\u002Fposition = Vector2(300, 100)\n\n# Locomotion (blend space)\nstates\u002FLocomotion\u002Fnode = SubResource(\"AnimationNodeBlendSpace2D_loco\")\nstates\u002FLocomotion\u002Fposition = Vector2(500, 100)\n\n# Attack (one-shot animation)\nstates\u002FAttack\u002Fnode = SubResource(\"AnimationNodeOneShot_attack\")\nstates\u002FAttack\u002Fposition = Vector2(500, 300)\n\n# Death state\nstates\u002FDeath\u002Fnode = SubResource(\"AnimationNodeAnimation_death\")\nstates\u002FDeath\u002Fposition = Vector2(700, 100)\n```\n\n### 状态过渡\n\n**过渡配置：**\n```ini\n# Transitions between states\n[sub_resource type=\"AnimationNodeStateMachine\" id=\"AnimationNodeStateMachine_character\"]\n\n# Idle -> Locomotion (auto on bool parameter)\ntransitions = [\"Idle\", \"Locomotion\", SubResource(\"AnimationNodeStateMachineTransition_idle_to_loco\")]\n\n# Locomotion -> Idle\ntransitions = [\"Locomotion\", \"Idle\", SubResource(\"AnimationNodeStateMachineTransition_loco_to_idle\")]\n\n# Any State -> Attack (using Attack trigger)\ntransitions = [\"Start\", \"Attack\", SubResource(\"AnimationNodeStateMachineTransition_attack\")]\n\n# Any State -> Death\ntransitions = [\"Start\", \"Death\", SubResource(\"AnimationNodeStateMachineTransition_death\")]\n```\n\n**过渡 Resource 定义：**\n```gdscript\n# Transition with condition\nvar transition = AnimationNodeStateMachineTransition.new()\ntransition.switch_mode = AnimationNodeStateMachineTransition.SWITCH_MODE_IMMEDIATE\ntransition.advance_mode = AnimationNodeStateMachineTransition.ADVANCE_MODE_AUTO\ntransition.advance_condition = \"is_moving\"\n\n# Transition with expression (Godot 4.1+)\ntransition.advance_expression = \"velocity.length() > 0.1\"\n\n# Transition with time condition\ntransition.switch_mode = AnimationNodeStateMachineTransition.SWITCH_MODE_AT_END\n```\n\n### 播放控制\n\n```gdscript\n# State machine playback script\nextends CharacterBody2D\n\n@onready var animation_tree: AnimationTree = $AnimationTree\nvar playback: AnimationNodeStateMachinePlayback\n\nfunc _ready():\n    animation_tree.active = true\n    playback = animation_tree.get(\"parameters\u002Fplayback\")\n\nfunc _physics_process(delta):\n    # Transition to locomotion state\n    if velocity.length() > 0.1:\n        playback.travel(\"Locomotion\")\n    else:\n        playback.travel(\"Idle\")\n\n    # Trigger attack (OneShot)\n    if Input.is_action_just_pressed(\"attack\"):\n        playback.travel(\"Attack\")\n\n    # Trigger death (immediate)\n    if health \u003C= 0:\n        playback.travel(\"Death\")\n\nfunc stop_movement():\n    # Stop at current state\n    playback.stop()\n\nfunc reset_to_idle():\n    # Start over from Start node\n    playback.start(\"Idle\")\n```\n\n## BlendSpace2D 配置\n\n### 运动混合空间\n\n**修改前（无混合）：**\n```gdscript\n# Discrete animations - jarring transitions\nfunc update_animation():\n    if velocity.length() \u003C 0.1:\n        anim_player.play(\"idle\")\n    elif velocity.length() \u003C 100:\n        anim_player.play(\"walk\")\n    else:\n        anim_player.play(\"run\")\n```\n\n**修改后（使用 BlendSpace2D）：**\n```gdscript\n# Smooth blending between all animations\nfunc _physics_process(delta):\n    # Normalize velocity for blend position (-1 to 1)\n    var blend_pos = velocity \u002F max_speed\n    animation_tree.set(\"parameters\u002FLocomotion\u002Fblend_position\", blend_pos)\n```\n\n**生成的 BlendSpace2D：**\n```ini\n# BlendSpace2D resource\n[sub_resource type=\"AnimationNodeBlendSpace2D\" id=\"AnimationNodeBlendSpace2D_loco\"]\n\n# Center - Idle\nblend_point_0\u002Fnode = SubResource(\"AnimationNodeAnimation_idle\")\nblend_point_0\u002Fpos = Vector2(0, 0)\n\n# Up - Walk North\nblend_point_1\u002Fnode = SubResource(\"AnimationNodeAnimation_walk_north\")\nblend_point_1\u002Fpos = Vector2(0, -1)\n\n# Down - Walk South\nblend_point_2\u002Fnode = SubResource(\"AnimationNodeAnimation_walk_south\")\nblend_point_2\u002Fpos = Vector2(0, 1)\n\n# Left - Walk West\nblend_point_3\u002Fnode = SubResource(\"AnimationNodeAnimation_walk_west\")\nblend_point_3\u002Fpos = Vector2(-1, 0)\n\n# Right - Walk East\nblend_point_4\u002Fnode = SubResource(\"AnimationNodeAnimation_walk_east\")\nblend_point_4\u002Fpos = Vector2(1, 0)\n\n# Diagonal blends (automatically interpolated)\nblend_point_5\u002Fnode = SubResource(\"AnimationNodeAnimation_walk_northeast\")\nblend_point_5\u002Fpos = Vector2(0.707, -0.707)\n\n# Blend mode\nblend_mode = 1  # BLEND_MODE_INTERPOLATED\nmin_space = Vector2(-1.5, -1.5)\nmax_space = Vector2(1.5, 1.5)\n```\n\n### BlendSpace2D 设置脚本\n\n```gdscript\n# Programmatically create BlendSpace2D\nfunc create_locomotion_blend_space() -> AnimationNodeBlendSpace2D:\n    var blend_space = AnimationNodeBlendSpace2D.new()\n\n    # Add idle animation at center\n    var idle_node = AnimationNodeAnimation.new()\n    idle_node.animation = \"idle\"\n    blend_space.add_blend_point(idle_node, Vector2.ZERO)\n\n    # Add directional walks\n    var walk_north = AnimationNodeAnimation.new()\n    walk_north.animation = \"walk_north\"\n    blend_space.add_blend_point(walk_north, Vector2(0, -1))\n\n    var walk_south = AnimationNodeAnimation.new()\n    walk_south.animation = \"walk_south\"\n    blend_space.add_blend_point(walk_south, Vector2(0, 1))\n\n    var walk_east = AnimationNodeAnimation.new()\n    walk_east.animation = \"walk_east\"\n    blend_space.add_blend_point(walk_east, Vector2(1, 0))\n\n    var walk_west = AnimationNodeAnimation.new()\n    walk_west.animation = \"walk_west\"\n    blend_space.add_blend_point(walk_west, Vector2(-1, 0))\n\n    # Configure blend triangles for proper interpolation\n    blend_space.add_triangle(0, 1, 4)  # Idle, North, East\n    blend_space.add_triangle(0, 4, 2)  # Idle, East, South\n    blend_space.add_triangle(0, 2, 3)  # Idle, South, West\n    blend_space.add_triangle(0, 3, 1)  # Idle, West, North\n\n    return blend_space\n```\n\n### 参数驱动的混合空间\n\n```gdscript\n# Update blend space based on input\u002Fvelocity\nfunc update_locomotion_blend():\n    var input_dir = Input.get_vector(\"move_left\", \"move_right\", \"move_up\", \"move_down\")\n\n    # Calculate blend position based on input\n    var blend_position = input_dir\n\n    # Apply to AnimationTree\n    animation_tree.set(\"parameters\u002FLocomotion\u002Fblend_position\", blend_position)\n\n    # Also update speed scale for walk\u002Frun distinction\n    var speed = velocity.length()\n    var speed_scale = clamp(speed \u002F base_speed, 0.5, 2.0)\n    animation_tree.set(\"parameters\u002FLocomotion\u002Fspeed_scale\", speed_scale)\n```\n\n## BlendSpace3D 配置\n\n### 3D 运动混合空间\n\n```ini\n# BlendSpace3D for 3D characters\n[sub_resource type=\"AnimationNodeBlendSpace3D\" id=\"AnimationNodeBlendSpace3D_loco3d\"]\n\n# Idle at center\nblend_point_0\u002Fnode = SubResource(\"AnimationNodeAnimation_idle_3d\")\nblend_point_0\u002Fpos = Vector3(0, 0, 0)\n\n# Cardinal directions\nblend_point_1\u002Fnode = SubResource(\"AnimationNodeAnimation_walk_forward\")\nblend_point_1\u002Fpos = Vector3(0, 0, 1)\n\nblend_point_2\u002Fnode = SubResource(\"AnimationNodeAnimation_walk_backward\")\nblend_point_2\u002Fpos = Vector3(0, 0, -1)\n\nblend_point_3\u002Fnode = SubResource(\"AnimationNodeAnimation_strafe_left\")\nblend_point_3\u002Fpos = Vector3(-1, 0, 0)\n\nblend_point_4\u002Fnode = SubResource(\"AnimationNodeAnimation_strafe_right\")\nblend_point_4\u002Fpos = Vector3(1, 0, 0)\n\n# Run variants at higher magnitude\nblend_point_5\u002Fnode = SubResource(\"AnimationNodeAnimation_run_forward\")\nblend_point_5\u002Fpos = Vector3(0, 0, 1.5)\n```\n\n**3D 角色动画脚本：**\n```gdscript\n# character_3d.gd\nextends CharacterBody3D\n\n@onready var animation_tree: AnimationTree = $AnimationTree\n\nfunc _physics_process(delta):\n    # Get local velocity relative to character rotation\n    var local_velocity = transform.basis.inverse() * velocity\n\n    # Normalize for blend position\n    var blend_pos = Vector3(\n        clamp(local_velocity.x \u002F max_speed, -1, 1),\n        0,\n        clamp(local_velocity.z \u002F max_speed, -1, 1)\n    )\n\n    # Update blend space\n    animation_tree.set(\"parameters\u002FLocomotion3D\u002Fblend_position\", blend_pos)\n\n    # Update animation speed based on actual velocity\n    var speed_factor = velocity.length() \u002F max_speed\n    animation_tree.set(\"parameters\u002FLocomotion3D\u002Fspeed_scale\", clamp(speed_factor, 0.5, 1.5))\n```\n\n## 状态过渡\n\n### 布尔条件过渡\n\n```gdscript\n# Setup boolean condition in AnimationTree\nfunc setup_conditions():\n    # Set condition values\n    animation_tree.set(\"parameters\u002Fconditions\u002Fis_moving\", velocity.length() > 0.1)\n    animation_tree.set(\"parameters\u002Fconditions\u002Fis_attacking\", Input.is_action_pressed(\"attack\"))\n    animation_tree.set(\"parameters\u002Fconditions\u002Fis_grounded\", is_on_floor())\n    animation_tree.set(\"parameters\u002Fconditions\u002Fis_dead\", health \u003C= 0)\n```\n\n**对应的场景配置：**\n```ini\n[sub_resource type=\"AnimationNodeStateMachineTransition\" id=\"AnimationNodeStateMachineTransition_idle_to_move\"]\nadvance_mode = 1  # ADVANCE_MODE_AUTO\nadvance_condition = \"is_moving\"\n\n[sub_resource type=\"AnimationNodeStateMachineTransition\" id=\"AnimationNodeStateMachineTransition_move_to_idle\"]\nadvance_mode = 1\nadvance_condition = \"is_moving\"\nnegated = true\n\n[sub_resource type=\"AnimationNodeStateMachineTransition\" id=\"AnimationNodeStateMachineTransition_attack\"]\nadvance_mode = 1\nadvance_condition = \"is_attacking\"\n```\n\n### 基于表达式的过渡\n\n```gdscript\n# Godot 4.1+ expression transitions\n# No need for manual condition setting\n\n# Transition expression examples:\n# \"velocity.length() > 0.1\"\n# \"health \u003C= 0\"\n# \"is_on_floor() and Input.is_action_pressed(\\\"jump\\\")\"\n# \"anim_time >= 0.8\" (requires anim_time parameter tracking)\n```\n\n**设置表达式过渡：**\n```gdscript\nfunc create_expression_transition(expression: String) -> AnimationNodeStateMachineTransition:\n    var transition = AnimationNodeStateMachineTransition.new()\n    transition.advance_mode = AnimationNodeStateMachineTransition.ADVANCE_MODE_AUTO\n    transition.advance_expression = expression\n    return transition\n\n# Usage\nvar jump_transition = create_expression_transition(\"is_on_floor() and Input.is_action_pressed('jump')\")\nstate_machine.add_transition(\"Idle\", \"Jump\", jump_transition)\n```\n\n### 基于时间的过渡\n\n```gdscript\n# Transition at end of animation\nvar end_transition = AnimationNodeStateMachineTransition.new()\nend_transition.switch_mode = AnimationNodeStateMachineTransition.SWITCH_MODE_AT_END\nend_transition.advance_mode = AnimationNodeStateMachineTransition.ADVANCE_MODE_AUTO\n\n# Transition after specific time\nvar time_transition = AnimationNodeStateMachineTransition.new()\ntime_transition.switch_mode = AnimationNodeStateMachineTransition.SWITCH_MODE_AT_END\ntime_transition.advance_mode = AnimationNodeStateMachineTransition.ADVANCE_MODE_AUTO\n# Add custom wait time via expression\n```\n\n## 混合树\n\n### 复杂动画混合\n\n**用于动作的 OneShot：**\n```ini\n[sub_resource type=\"AnimationNodeOneShot\" id=\"AnimationNodeOneShot_attack\"]\nanimation = SubResource(\"AnimationNodeAnimation_attack\")\nfadein_time = 0.1\nfadeout_time = 0.15\nmix_mode = 0  # ONE_SHOT_MIX_MODE_BLEND\n```\n\n**用于平滑过渡的 Blend2：**\n```ini\n[sub_resource type=\"AnimationNodeBlend2\" id=\"AnimationNodeBlend2_action\"]\n```\n\n**用于叠加的 Add2：**\n```ini\n[sub_resource type=\"AnimationNodeAdd2\" id=\"AnimationNodeAdd2_recoil\"]\n# Adds recoil on top of base animation\n```\n\n**用于速度控制的 TimeScale：**\n```ini\n[sub_resource type=\"AnimationNodeTimeScale\" id=\"AnimationNodeTimeScale_run\"]\nscale = 1.0  # Modified at runtime\n```\n\n### 完整混合树示例\n\n```ini\n# Complex blend tree with layering\n[sub_resource type=\"AnimationNodeBlendTree\" id=\"AnimationNodeBlendTree_complex\"]\n\n# Input animations\nnodes\u002FAnimation\u002Fnode = SubResource(\"AnimationNodeAnimation_idle\")\nnodes\u002FAnimation\u002Fposition = Vector2(100, 100)\n\n# Time scale for speed control\nnodes\u002FTimeScale\u002Fnode = SubResource(\"AnimationNodeTimeScale_var\")\nnodes\u002FTimeScale\u002Fposition = Vector2(300, 100)\nnodes\u002FTimeScale\u002Finput_0 = SubResource(\"AnimationNodeAnimation_idle\")\n\n# OneShot for hit reaction (layered on top)\nnodes\u002FHitReaction\u002Fnode = SubResource(\"AnimationNodeOneShot_hit\")\nnodes\u002FHitReaction\u002Fposition = Vector2(500, 100)\nnodes\u002FHitReaction\u002Finput_0 = SubResource(\"AnimationNodeTimeScale_var\")\n\n# Add2 for weapon sway\nnodes\u002FWeaponSway\u002Fnode = SubResource(\"AnimationNodeAdd2_sway\")\nnodes\u002FWeaponSway\u002Fposition = Vector2(700, 100)\nnodes\u002FWeaponSway\u002Finput_0 = SubResource(\"AnimationNodeOneShot_hit\")\nnodes\u002FWeaponSway\u002Finput_1 = SubResource(\"AnimationNodeAnimation_sway\")\n\n# Output\nnodes\u002FOutput\u002Fposition = Vector2(900, 100)\nnode_connections = [&\"output\", 0, &\"WeaponSway\"]\n```\n\n**混合树脚本控制：**\n```gdscript\n# Control blend tree parameters\nfunc update_blend_tree():\n    # Update time scale based on movement speed\n    var speed = velocity.length()\n    var time_scale = clamp(speed \u002F base_speed, 0.5, 2.0)\n    animation_tree.set(\"parameters\u002FTimeScale\u002Fscale\", time_scale)\n\n    # Trigger OneShot\n    if is_hit:\n        animation_tree.set(\"parameters\u002FHitReaction\u002Factive\", true)\n        animation_tree.set(\"parameters\u002FHitReaction\u002Finternal_active\", true)\n\n    # Control Add2 amount (0.0 = no sway, 1.0 = full sway)\n    var sway_amount = clamp(speed \u002F max_speed, 0.0, 1.0)\n    animation_tree.set(\"parameters\u002FWeaponSway\u002Fadd_amount\", sway_amount)\n```\n\n## 示例\n\n### 2D 角色动画系统\n\n**完整设置：**\n```gdscript\n# character_animator.gd\nextends CharacterBody2D\n\n@onready var animation_tree: AnimationTree = $AnimationTree\n@onready var playback: AnimationNodeStateMachinePlayback\n\n@export var max_speed: float = 200.0\n@export var blend_smoothness: float = 5.0\n\nvar target_blend_position: Vector2 = Vector2.ZERO\nvar current_blend_position: Vector2 = Vector2.ZERO\n\nfunc _ready():\n    animation_tree.active = true\n    playback = animation_tree.get(\"parameters\u002Fplayback\")\n\nfunc _physics_process(delta):\n    # Get input\n    var input_dir = Input.get_vector(\"move_left\", \"move_right\", \"move_up\", \"move_down\")\n\n    # Calculate target blend position\n    if input_dir.length() > 0.1:\n        target_blend_position = input_dir\n        playback.travel(\"Locomotion\")\n    else:\n        target_blend_position = Vector2.ZERO\n        playback.travel(\"Idle\")\n\n    # Smooth blend position transition\n    current_blend_position = current_blend_position.lerp(target_blend_position, blend_smoothness * delta)\n    animation_tree.set(\"parameters\u002FLocomotion\u002Fblend_position\", current_blend_position)\n\n    # Handle actions\n    if Input.is_action_just_pressed(\"attack\"):\n        playback.travel(\"Attack\")\n\n    if Input.is_action_just_pressed(\"interact\"):\n        playback.travel(\"Interact\")\n\nfunc take_damage():\n    playback.travel(\"Hit\")\n\nfunc die():\n    playback.travel(\"Death\")\n```\n\n**生成的场景：**\n```ini\n# animated_character.tscn\n[gd_scene load_steps=10 format=3]\n\n[ext_resource type=\"Script\" path=\"res:\u002F\u002Fcharacter_animator.gd\" id=\"1_anim123\"]\n\n# Animation nodes\n[sub_resource type=\"AnimationNodeAnimation\" id=\"AnimationNodeAnimation_idle\"]\nanimation = &\"idle\"\n\n[sub_resource type=\"AnimationNodeAnimation\" id=\"AnimationNodeAnimation_attack\"]\nanimation = &\"attack\"\n\n[sub_resource type=\"AnimationNodeBlendSpace2D\" id=\"AnimationNodeBlendSpace2D_loco\"]\nblend_point_0\u002Fnode = SubResource(\"AnimationNodeAnimation_idle\")\nblend_point_0\u002Fpos = Vector2(0, 0)\n# ... more blend points\n\n# State machine\n[sub_resource type=\"AnimationNodeStateMachine\" id=\"AnimationNodeStateMachine_main\"]\nstates\u002FStart\u002Fposition = Vector2(150, 100)\nstates\u002FIdle\u002Fnode = SubResource(\"AnimationNodeAnimation_idle\")\nstates\u002FIdle\u002Fposition = Vector2(300, 100)\nstates\u002FLocomotion\u002Fnode = SubResource(\"AnimationNodeBlendSpace2D_loco\")\nstates\u002FLocomotion\u002Fposition = Vector2(500, 100)\nstates\u002FAttack\u002Fnode = SubResource(\"AnimationNodeAnimation_attack\")\nstates\u002FAttack\u002Fposition = Vector2(500, 300)\nstates\u002FEnd\u002Fposition = Vector2(700, 100)\n\n# Transitions\n[sub_resource type=\"AnimationNodeStateMachineTransition\" id=\"AnimationNodeStateMachineTransition_to_loco\"]\nadvance_condition = \"is_moving\"\n\n[sub_resource type=\"AnimationNodeStateMachineTransition\" id=\"AnimationNodeStateMachineTransition_to_idle\"]\nadvance_condition = \"is_moving\"\nnegated = true\n\n[node name=\"AnimatedCharacter\" type=\"CharacterBody2D\"]\nscript = ExtResource(\"1_anim123\")\n\n[node name=\"Sprite2D\" type=\"Sprite2D\" parent=\".\"]\n\n[node name=\"AnimationPlayer\" type=\"AnimationPlayer\" parent=\".\"]\n\n[node name=\"AnimationTree\" type=\"AnimationTree\" parent=\".\"]\nanim_player = NodePath(\"..\u002FAnimationPlayer\")\ntree_root = SubResource(\"AnimationNodeStateMachine_main\")\nparameters\u002Fplayback = SubResource(\"AnimationNodeStateMachinePlayback_main\")\nparameters\u002FLocomotion\u002Fblend_position = Vector2(0, 0)\nparameters\u002Fconditions\u002Fis_moving = false\n```\n\n### 战斗动画系统\n\n**攻击连招系统：**\n```gdscript\n# combat_animator.gd\nextends CharacterBody2D\n\n@onready var animation_tree: AnimationTree = $AnimationTree\n@onready var playback: AnimationNodeStateMachinePlayback\n\nvar combo_count: int = 0\nvar max_combo: int = 3\nvar combo_window: float = 0.5\nvar combo_timer: float = 0.0\n\nfunc _ready():\n    animation_tree.active = true\n    playback = animation_tree.get(\"parameters\u002Fplayback\")\n\nfunc _physics_process(delta):\n    # Update combo timer\n    if combo_timer > 0:\n        combo_timer -= delta\n        if combo_timer \u003C= 0:\n            combo_count = 0\n\n    # Handle attack input\n    if Input.is_action_just_pressed(\"attack\"):\n        perform_attack()\n\n    # Update animation conditions\n    animation_tree.set(\"parameters\u002Fconditions\u002Fin_combo\", combo_count > 0)\n\nfunc perform_attack():\n    match combo_count:\n        0:\n            playback.travel(\"Attack1\")\n        1:\n            playback.travel(\"Attack2\")\n        2:\n            playback.travel(\"Attack3\")\n        _:\n            combo_count = 0\n            playback.travel(\"Attack1\")\n\n    combo_count = (combo_count + 1) % max_combo\n    combo_timer = combo_window\n\nfunc reset_combo():\n    combo_count = 0\n    combo_timer = 0.0\n```\n\n**连招状态机：**\n```ini\n[sub_resource type=\"AnimationNodeStateMachine\" id=\"AnimationNodeStateMachine_combat\"]\nstates\u002FIdle\u002Fposition = Vector2(300, 100)\nstates\u002FAttack1\u002Fposition = Vector2(500, 100)\nstates\u002FAttack2\u002Fposition = Vector2(500, 200)\nstates\u002FAttack3\u002Fposition = Vector2(500, 300)\n\n# Attack1 -> Attack2 transition\n[sub_resource type=\"AnimationNodeStateMachineTransition\" id=\"AnimationNodeStateMachineTransition_a1_a2\"]\nswitch_mode = 1  # SWITCH_MODE_AT_END\nadvance_mode = 1\nadvance_condition = \"in_combo\"\n\n# Attack2 -> Attack3 transition\n[sub_resource type=\"AnimationNodeStateMachineTransition\" id=\"AnimationNodeStateMachineTransition_a2_a3\"]\nswitch_mode = 1\nadvance_mode = 1\nadvance_condition = \"in_combo\"\n\n# All attacks -> Idle (when combo ends)\n[sub_resource type=\"AnimationNodeStateMachineTransition\" id=\"AnimationNodeStateMachineTransition_end\"]\nswitch_mode = 1\nadvance_mode = 1\nnegated = true\nadvance_condition = \"in_combo\"\n```\n\n### NPC 随机待机变体动画\n\n```gdscript\n# npc_animator.gd\nextends CharacterBody2D\n\n@onready var animation_tree: AnimationTree = $AnimationTree\n@onready var playback: AnimationNodeStateMachinePlayback\n\nvar idle_variations: Array[String] = [\"Idle\", \"Idle2\", \"Idle3\"]\nvar idle_timer: float = 0.0\nvar next_idle_change: float = 5.0\n\nfunc _ready():\n    animation_tree.active = true\n    playback = animation_tree.get(\"parameters\u002Fplayback\")\n    pick_random_idle()\n\nfunc _physics_process(delta):\n    # Random idle variation\n    idle_timer += delta\n    if idle_timer >= next_idle_change and velocity.length() \u003C 0.1:\n        idle_timer = 0.0\n        next_idle_change = randf_range(3.0, 8.0)\n        pick_random_idle()\n\n    # Movement\n    if velocity.length() > 0.1:\n        playback.travel(\"Walk\")\n\nfunc pick_random_idle():\n    var random_idle = idle_variations[randi() % idle_variations.size()]\n    playback.travel(random_idle)\n```\n\n## 常用模式\n\n### 动画事件集成\n\n```gdscript\n# Connect animation events to gameplay\nfunc _ready():\n    animation_tree.animation_started.connect(_on_animation_started)\n    animation_tree.animation_finished.connect(_on_animation_finished)\n\nfunc _on_animation_started(anim_name: StringName):\n    match anim_name:\n        \"attack\":\n            # Disable movement during attack\n            can_move = false\n        \"dash\":\n            # Make invincible\n            is_invincible = true\n\nfunc _on_animation_finished(anim_name: StringName):\n    match anim_name:\n        \"attack\":\n            can_move = true\n        \"dash\":\n            is_invincible = false\n```\n\n### 动画驱动的移动\n\n```gdscript\n# Root motion implementation\nfunc _on_animation_tree_animation_started(anim_name: StringName):\n    if anim_name == &\"attack\":\n        # Enable root motion tracking\n        animation_tree.set(\"parameters\u002FAttack\u002Factive\", true)\n\nfunc _physics_process(delta):\n    # Apply root motion from animation\n    var root_motion: Transform3D = animation_tree.get_root_motion()\n    global_transform *= root_motion\n```\n\n### 平滑状态过渡\n\n```gdscript\n# Crossfade duration configuration\nvar transition = AnimationNodeStateMachineTransition.new()\ntransition.fade_duration = 0.2  # 200ms crossfade\n```\n\n## 安全注意事项\n\n- 访问参数前始终检查 AnimationTree 是否处于激活状态\n- 设置树之前验证 AnimationPlayer 包含所有需要的动画\n- 优雅处理缺失的混合位置（默认为中心）\n- 重新父级或切换场景时重置 AnimationTree\n- 在 queue_free() 前断开信号连接\n\n## 不适用场景\n\n在以下情况不要使用 AnimationTree：\n- 只有 2-3 个简单动画（过度设计）\n- 动画逻辑非常简单（仅播放\u002F停止）\n- 低端设备上性能至关重要\n- 需要逐帧直接控制\n\n改用直接 AnimationPlayer 控制：\n```gdscript\n# Simple animation control\nfunc _physics_process(delta):\n    if is_moving:\n        anim_player.play(\"walk\")\n    else:\n        anim_player.play(\"idle\")\n```\n\n## 集成\n\n可配合以下技能使用：\n- **godot-add-signals** - 将动画事件连接到游戏系统\n- **godot-extract-to-scenes** - 创建可复用的动画角色场景\n- **godot-setup-navigation** - 导航代理配合移动动画\n- **godot-migrate-tilemap** - 动画 TileMap 角色\n\n## 性能提示\n\n1. **限制混合点数量** - 通常 4-8 个点就足够\n2. **缓存参数路径** - 将参数路径存储为常量\n3. **禁用未使用的树** - 不在屏幕上时设置 `active = false`\n4. **使用 TimeScale** - 而非直接修改动画速度\n5. **批量过渡** - 尽可能将状态变化合并处理\n","# 设置 AnimationTree 状态机\n\n## 核心原则\n\n**动画是状态驱动的，不是帧驱动的。** 使用 AnimationTree 管理动画状态，使用 BlendSpace 进行平滑的参数混合，使用过渡实现状态切换。避免在游戏逻辑代码中直接调用 AnimationPlayer 播放。\n\n## 本技能的功能\n\n设置完整的 AnimationTree 系统：\n\n1. **AnimationTree Node 结构** - 创建树节点并绑定动画播放器\n2. **AnimationNodeStateMachine** - 构建包含入口\u002F出口状态的状态机图形\n3. **BlendSpace2D\u002F3D** - 基于速度\u002F输入配置运动混合\n4. **状态过渡** - 定义条件（布尔、表达式、基于时间）的状态切换\n5. **混合树** - 使用 OneShot、Add2、Blend2 节点创建复杂的动画混合\n\n## AnimationTree 设置\n\n### 基本 AnimationTree 配置\n\n**修改前（直接使用 AnimationPlayer）：**\n```gdscript\n# player_animation.gd - Manual animation management\nextends CharacterBody2D\n\n@onready var anim_player: AnimationPlayer = $AnimationPlayer\n\nfunc _physics_process(delta):\n    var velocity = Input.get_vector(\"ui_left\", \"ui_right\", \"ui_up\", \"ui_down\")\n\n    if velocity.length() > 0:\n        if not anim_player.current_animation == \"run\":\n            anim_player.play(\"run\")\n    else:\n        if not anim_player.current_animation == \"idle\":\n            anim_player.play(\"idle\")\n```\n\n**修改后（使用 AnimationTree）：**\n```gdscript\n# player_animation.gd - State-driven animation\nextends CharacterBody2D\n\n@onready var animation_tree: AnimationTree = $AnimationTree\n@onready var playback: AnimationNodeStateMachinePlayback\n\nfunc _ready():\n    animation_tree.active = true\n    playback = animation_tree.get(\"parameters\u002Fplayback\")\n\nfunc _physics_process(delta):\n    var input_dir = Input.get_vector(\"ui_left\", \"ui_right\", \"ui_up\", \"ui_down\")\n\n    # Update blend position for BlendSpace2D\n    animation_tree.set(\"parameters\u002Fblend_position\", input_dir)\n\n    # Transition states\n    if input_dir.length() > 0.1:\n        playback.travel(\"Locomotion\")\n    else:\n        playback.travel(\"Idle\")\n```\n\n**生成的场景：**\n```ini\n# player.tscn\n[gd_scene load_steps=6 format=3]\n\n[ext_resource type=\"Script\" path=\"res:\u002F\u002Fplayer_animation.gd\" id=\"1_abc123\"]\n\n[sub_resource type=\"AnimationNodeAnimation\" id=\"AnimationNodeAnimation_idle\"]\nanimation = &\"idle\"\n\n[sub_resource type=\"AnimationNodeBlendSpace2D\" id=\"AnimationNodeBlendSpace2D_loco\"]\nblend_point_0\u002Fnode = SubResource(\"AnimationNodeAnimation_idle\")\nblend_point_0\u002Fpos = Vector2(0, 0)\nblend_point_1\u002Fnode = SubResource(\"AnimationNodeAnimation_walk\")\nblend_point_1\u002Fpos = Vector2(0, 1)\nblend_point_2\u002Fnode = SubResource(\"AnimationNodeAnimation_run\")\nblend_point_2\u002Fpos = Vector2(0, 1.5)\n\n[sub_resource type=\"AnimationNodeStateMachine\" id=\"AnimationNodeStateMachine_main\"]\nstates\u002FIdle\u002Fnode = SubResource(\"AnimationNodeAnimation_idle\")\nstates\u002FIdle\u002Fposition = Vector2(300, 100)\nstates\u002FLocomotion\u002Fnode = SubResource(\"AnimationNodeBlendSpace2D_loco\")\nstates\u002FLocomotion\u002Fposition = Vector2(500, 100)\n\n[sub_resource type=\"AnimationNodeStateMachinePlayback\" id=\"AnimationNodeStateMachinePlayback_main\"]\n\n[node name=\"Player\" type=\"CharacterBody2D\"]\nscript = ExtResource(\"1_abc123\")\n\n[node name=\"AnimationPlayer\" type=\"AnimationPlayer\" parent=\".\"]\n\n[node name=\"AnimationTree\" type=\"AnimationTree\" parent=\".\"]\nanim_player = NodePath(\"..\u002FAnimationPlayer\")\ntree_root = SubResource(\"AnimationNodeStateMachine_main\")\nparameters\u002Fplayback = SubResource(\"AnimationNodeStateMachinePlayback_main\")\nparameters\u002Fblend_position = Vector2(0, 0)\n```\n\n### AnimationTree 激活\n\n```gdscript\n# Essential setup for AnimationTree\nfunc _ready():\n    # Activate the tree (must be done after node is ready)\n    animation_tree.active = true\n\n    # Get reference to state machine playback\n    playback = animation_tree.get(\"parameters\u002Fplayback\")\n\n    # Optional: Set initial state\n    playback.start(\"Idle\")\n```\n\n## AnimationNodeStateMachine\n\n### 状态机结构\n\n**状态机图形：**\n```ini\n# State machine nodes in .tscn format\n[sub_resource type=\"AnimationNodeStateMachine\" id=\"AnimationNodeStateMachine_character\"]\nstates\u002FStart\u002Fposition = Vector2(150, 100)\nstates\u002FEnd\u002Fposition = Vector2(800, 100)\n\n# Idle state (single animation)\nstates\u002FIdle\u002Fnode = SubResource(\"AnimationNodeAnimation_idle\")\nstates\u002FIdle\u002Fposition = Vector2(300, 100)\n\n# Locomotion (blend space)\nstates\u002FLocomotion\u002Fnode = SubResource(\"AnimationNodeBlendSpace2D_loco\")\nstates\u002FLocomotion\u002Fposition = Vector2(500, 100)\n\n# Attack (one-shot animation)\nstates\u002FAttack\u002Fnode = SubResource(\"AnimationNodeOneShot_attack\")\nstates\u002FAttack\u002Fposition = Vector2(500, 300)\n\n# Death state\nstates\u002FDeath\u002Fnode = SubResource(\"AnimationNodeAnimation_death\")\nstates\u002FDeath\u002Fposition = Vector2(700, 100)\n```\n\n### 状态过渡\n\n**过渡配置：**\n```ini\n# Transitions between states\n[sub_resource type=\"AnimationNodeStateMachine\" id=\"AnimationNodeStateMachine_character\"]\n\n# Idle -> Locomotion (auto on bool parameter)\ntransitions = [\"Idle\", \"Locomotion\", SubResource(\"AnimationNodeStateMachineTransition_idle_to_loco\")]\n\n# Locomotion -> Idle\ntransitions = [\"Locomotion\", \"Idle\", SubResource(\"AnimationNodeStateMachineTransition_loco_to_idle\")]\n\n# Any State -> Attack (using Attack trigger)\ntransitions = [\"Start\", \"Attack\", SubResource(\"AnimationNodeStateMachineTransition_attack\")]\n\n# Any State -> Death\ntransitions = [\"Start\", \"Death\", SubResource(\"AnimationNodeStateMachineTransition_death\")]\n```\n\n**过渡 Resource 定义：**\n```gdscript\n# Transition with condition\nvar transition = AnimationNodeStateMachineTransition.new()\ntransition.switch_mode = AnimationNodeStateMachineTransition.SWITCH_MODE_IMMEDIATE\ntransition.advance_mode = AnimationNodeStateMachineTransition.ADVANCE_MODE_AUTO\ntransition.advance_condition = \"is_moving\"\n\n# Transition with expression (Godot 4.1+)\ntransition.advance_expression = \"velocity.length() > 0.1\"\n\n# Transition with time condition\ntransition.switch_mode = AnimationNodeStateMachineTransition.SWITCH_MODE_AT_END\n```\n\n### 播放控制\n\n```gdscript\n# State machine playback script\nextends CharacterBody2D\n\n@onready var animation_tree: AnimationTree = $AnimationTree\nvar playback: AnimationNodeStateMachinePlayback\n\nfunc _ready():\n    animation_tree.active = true\n    playback = animation_tree.get(\"parameters\u002Fplayback\")\n\nfunc _physics_process(delta):\n    # Transition to locomotion state\n    if velocity.length() > 0.1:\n        playback.travel(\"Locomotion\")\n    else:\n        playback.travel(\"Idle\")\n\n    # Trigger attack (OneShot)\n    if Input.is_action_just_pressed(\"attack\"):\n        playback.travel(\"Attack\")\n\n    # Trigger death (immediate)\n    if health \u003C= 0:\n        playback.travel(\"Death\")\n\nfunc stop_movement():\n    # Stop at current state\n    playback.stop()\n\nfunc reset_to_idle():\n    # Start over from Start node\n    playback.start(\"Idle\")\n```\n\n## BlendSpace2D 配置\n\n### 运动混合空间\n\n**修改前（无混合）：**\n```gdscript\n# Discrete animations - jarring transitions\nfunc update_animation():\n    if velocity.length() \u003C 0.1:\n        anim_player.play(\"idle\")\n    elif velocity.length() \u003C 100:\n        anim_player.play(\"walk\")\n    else:\n        anim_player.play(\"run\")\n```\n\n**修改后（使用 BlendSpace2D）：**\n```gdscript\n# Smooth blending between all animations\nfunc _physics_process(delta):\n    # Normalize velocity for blend position (-1 to 1)\n    var blend_pos = velocity \u002F max_speed\n    animation_tree.set(\"parameters\u002FLocomotion\u002Fblend_position\", blend_pos)\n```\n\n**生成的 BlendSpace2D：**\n```ini\n# BlendSpace2D resource\n[sub_resource type=\"AnimationNodeBlendSpace2D\" id=\"AnimationNodeBlendSpace2D_loco\"]\n\n# Center - Idle\nblend_point_0\u002Fnode = SubResource(\"AnimationNodeAnimation_idle\")\nblend_point_0\u002Fpos = Vector2(0, 0)\n\n# Up - Walk North\nblend_point_1\u002Fnode = SubResource(\"AnimationNodeAnimation_walk_north\")\nblend_point_1\u002Fpos = Vector2(0, -1)\n\n# Down - Walk South\nblend_point_2\u002Fnode = SubResource(\"AnimationNodeAnimation_walk_south\")\nblend_point_2\u002Fpos = Vector2(0, 1)\n\n# Left - Walk West\nblend_point_3\u002Fnode = SubResource(\"AnimationNodeAnimation_walk_west\")\nblend_point_3\u002Fpos = Vector2(-1, 0)\n\n# Right - Walk East\nblend_point_4\u002Fnode = SubResource(\"AnimationNodeAnimation_walk_east\")\nblend_point_4\u002Fpos = Vector2(1, 0)\n\n# Diagonal blends (automatically interpolated)\nblend_point_5\u002Fnode = SubResource(\"AnimationNodeAnimation_walk_northeast\")\nblend_point_5\u002Fpos = Vector2(0.707, -0.707)\n\n# Blend mode\nblend_mode = 1  # BLEND_MODE_INTERPOLATED\nmin_space = Vector2(-1.5, -1.5)\nmax_space = Vector2(1.5, 1.5)\n```\n\n### BlendSpace2D 设置脚本\n\n```gdscript\n# Programmatically create BlendSpace2D\nfunc create_locomotion_blend_space() -> AnimationNodeBlendSpace2D:\n    var blend_space = AnimationNodeBlendSpace2D.new()\n\n    # Add idle animation at center\n    var idle_node = AnimationNodeAnimation.new()\n    idle_node.animation = \"idle\"\n    blend_space.add_blend_point(idle_node, Vector2.ZERO)\n\n    # Add directional walks\n    var walk_north = AnimationNodeAnimation.new()\n    walk_north.animation = \"walk_north\"\n    blend_space.add_blend_point(walk_north, Vector2(0, -1))\n\n    var walk_south = AnimationNodeAnimation.new()\n    walk_south.animation = \"walk_south\"\n    blend_space.add_blend_point(walk_south, Vector2(0, 1))\n\n    var walk_east = AnimationNodeAnimation.new()\n    walk_east.animation = \"walk_east\"\n    blend_space.add_blend_point(walk_east, Vector2(1, 0))\n\n    var walk_west = AnimationNodeAnimation.new()\n    walk_west.animation = \"walk_west\"\n    blend_space.add_blend_point(walk_west, Vector2(-1, 0))\n\n    # Configure blend triangles for proper interpolation\n    blend_space.add_triangle(0, 1, 4)  # Idle, North, East\n    blend_space.add_triangle(0, 4, 2)  # Idle, East, South\n    blend_space.add_triangle(0, 2, 3)  # Idle, South, West\n    blend_space.add_triangle(0, 3, 1)  # Idle, West, North\n\n    return blend_space\n```\n\n### 参数驱动的混合空间\n\n```gdscript\n# Update blend space based on input\u002Fvelocity\nfunc update_locomotion_blend():\n    var input_dir = Input.get_vector(\"move_left\", \"move_right\", \"move_up\", \"move_down\")\n\n    # Calculate blend position based on input\n    var blend_position = input_dir\n\n    # Apply to AnimationTree\n    animation_tree.set(\"parameters\u002FLocomotion\u002Fblend_position\", blend_position)\n\n    # Also update speed scale for walk\u002Frun distinction\n    var speed = velocity.length()\n    var speed_scale = clamp(speed \u002F base_speed, 0.5, 2.0)\n    animation_tree.set(\"parameters\u002FLocomotion\u002Fspeed_scale\", speed_scale)\n```\n\n## BlendSpace3D 配置\n\n### 3D 运动混合空间\n\n```ini\n# BlendSpace3D for 3D characters\n[sub_resource type=\"AnimationNodeBlendSpace3D\" id=\"AnimationNodeBlendSpace3D_loco3d\"]\n\n# Idle at center\nblend_point_0\u002Fnode = SubResource(\"AnimationNodeAnimation_idle_3d\")\nblend_point_0\u002Fpos = Vector3(0, 0, 0)\n\n# Cardinal directions\nblend_point_1\u002Fnode = SubResource(\"AnimationNodeAnimation_walk_forward\")\nblend_point_1\u002Fpos = Vector3(0, 0, 1)\n\nblend_point_2\u002Fnode = SubResource(\"AnimationNodeAnimation_walk_backward\")\nblend_point_2\u002Fpos = Vector3(0, 0, -1)\n\nblend_point_3\u002Fnode = SubResource(\"AnimationNodeAnimation_strafe_left\")\nblend_point_3\u002Fpos = Vector3(-1, 0, 0)\n\nblend_point_4\u002Fnode = SubResource(\"AnimationNodeAnimation_strafe_right\")\nblend_point_4\u002Fpos = Vector3(1, 0, 0)\n\n# Run variants at higher magnitude\nblend_point_5\u002Fnode = SubResource(\"AnimationNodeAnimation_run_forward\")\nblend_point_5\u002Fpos = Vector3(0, 0, 1.5)\n```\n\n**3D 角色动画脚本：**\n```gdscript\n# character_3d.gd\nextends CharacterBody3D\n\n@onready var animation_tree: AnimationTree = $AnimationTree\n\nfunc _physics_process(delta):\n    # Get local velocity relative to character rotation\n    var local_velocity = transform.basis.inverse() * velocity\n\n    # Normalize for blend position\n    var blend_pos = Vector3(\n        clamp(local_velocity.x \u002F max_speed, -1, 1),\n        0,\n        clamp(local_velocity.z \u002F max_speed, -1, 1)\n    )\n\n    # Update blend space\n    animation_tree.set(\"parameters\u002FLocomotion3D\u002Fblend_position\", blend_pos)\n\n    # Update animation speed based on actual velocity\n    var speed_factor = velocity.length() \u002F max_speed\n    animation_tree.set(\"parameters\u002FLocomotion3D\u002Fspeed_scale\", clamp(speed_factor, 0.5, 1.5))\n```\n\n## 状态过渡\n\n### 布尔条件过渡\n\n```gdscript\n# Setup boolean condition in AnimationTree\nfunc setup_conditions():\n    # Set condition values\n    animation_tree.set(\"parameters\u002Fconditions\u002Fis_moving\", velocity.length() > 0.1)\n    animation_tree.set(\"parameters\u002Fconditions\u002Fis_attacking\", Input.is_action_pressed(\"attack\"))\n    animation_tree.set(\"parameters\u002Fconditions\u002Fis_grounded\", is_on_floor())\n    animation_tree.set(\"parameters\u002Fconditions\u002Fis_dead\", health \u003C= 0)\n```\n\n**对应的场景配置：**\n```ini\n[sub_resource type=\"AnimationNodeStateMachineTransition\" id=\"AnimationNodeStateMachineTransition_idle_to_move\"]\nadvance_mode = 1  # ADVANCE_MODE_AUTO\nadvance_condition = \"is_moving\"\n\n[sub_resource type=\"AnimationNodeStateMachineTransition\" id=\"AnimationNodeStateMachineTransition_move_to_idle\"]\nadvance_mode = 1\nadvance_condition = \"is_moving\"\nnegated = true\n\n[sub_resource type=\"AnimationNodeStateMachineTransition\" id=\"AnimationNodeStateMachineTransition_attack\"]\nadvance_mode = 1\nadvance_condition = \"is_attacking\"\n```\n\n### 基于表达式的过渡\n\n```gdscript\n# Godot 4.1+ expression transitions\n# No need for manual condition setting\n\n# Transition expression examples:\n# \"velocity.length() > 0.1\"\n# \"health \u003C= 0\"\n# \"is_on_floor() and Input.is_action_pressed(\\\"jump\\\")\"\n# \"anim_time >= 0.8\" (requires anim_time parameter tracking)\n```\n\n**设置表达式过渡：**\n```gdscript\nfunc create_expression_transition(expression: String) -> AnimationNodeStateMachineTransition:\n    var transition = AnimationNodeStateMachineTransition.new()\n    transition.advance_mode = AnimationNodeStateMachineTransition.ADVANCE_MODE_AUTO\n    transition.advance_expression = expression\n    return transition\n\n# Usage\nvar jump_transition = create_expression_transition(\"is_on_floor() and Input.is_action_pressed('jump')\")\nstate_machine.add_transition(\"Idle\", \"Jump\", jump_transition)\n```\n\n### 基于时间的过渡\n\n```gdscript\n# Transition at end of animation\nvar end_transition = AnimationNodeStateMachineTransition.new()\nend_transition.switch_mode = AnimationNodeStateMachineTransition.SWITCH_MODE_AT_END\nend_transition.advance_mode = AnimationNodeStateMachineTransition.ADVANCE_MODE_AUTO\n\n# Transition after specific time\nvar time_transition = AnimationNodeStateMachineTransition.new()\ntime_transition.switch_mode = AnimationNodeStateMachineTransition.SWITCH_MODE_AT_END\ntime_transition.advance_mode = AnimationNodeStateMachineTransition.ADVANCE_MODE_AUTO\n# Add custom wait time via expression\n```\n\n## 混合树\n\n### 复杂动画混合\n\n**用于动作的 OneShot：**\n```ini\n[sub_resource type=\"AnimationNodeOneShot\" id=\"AnimationNodeOneShot_attack\"]\nanimation = SubResource(\"AnimationNodeAnimation_attack\")\nfadein_time = 0.1\nfadeout_time = 0.15\nmix_mode = 0  # ONE_SHOT_MIX_MODE_BLEND\n```\n\n**用于平滑过渡的 Blend2：**\n```ini\n[sub_resource type=\"AnimationNodeBlend2\" id=\"AnimationNodeBlend2_action\"]\n```\n\n**用于叠加的 Add2：**\n```ini\n[sub_resource type=\"AnimationNodeAdd2\" id=\"AnimationNodeAdd2_recoil\"]\n# Adds recoil on top of base animation\n```\n\n**用于速度控制的 TimeScale：**\n```ini\n[sub_resource type=\"AnimationNodeTimeScale\" id=\"AnimationNodeTimeScale_run\"]\nscale = 1.0  # Modified at runtime\n```\n\n### 完整混合树示例\n\n```ini\n# Complex blend tree with layering\n[sub_resource type=\"AnimationNodeBlendTree\" id=\"AnimationNodeBlendTree_complex\"]\n\n# Input animations\nnodes\u002FAnimation\u002Fnode = SubResource(\"AnimationNodeAnimation_idle\")\nnodes\u002FAnimation\u002Fposition = Vector2(100, 100)\n\n# Time scale for speed control\nnodes\u002FTimeScale\u002Fnode = SubResource(\"AnimationNodeTimeScale_var\")\nnodes\u002FTimeScale\u002Fposition = Vector2(300, 100)\nnodes\u002FTimeScale\u002Finput_0 = SubResource(\"AnimationNodeAnimation_idle\")\n\n# OneShot for hit reaction (layered on top)\nnodes\u002FHitReaction\u002Fnode = SubResource(\"AnimationNodeOneShot_hit\")\nnodes\u002FHitReaction\u002Fposition = Vector2(500, 100)\nnodes\u002FHitReaction\u002Finput_0 = SubResource(\"AnimationNodeTimeScale_var\")\n\n# Add2 for weapon sway\nnodes\u002FWeaponSway\u002Fnode = SubResource(\"AnimationNodeAdd2_sway\")\nnodes\u002FWeaponSway\u002Fposition = Vector2(700, 100)\nnodes\u002FWeaponSway\u002Finput_0 = SubResource(\"AnimationNodeOneShot_hit\")\nnodes\u002FWeaponSway\u002Finput_1 = SubResource(\"AnimationNodeAnimation_sway\")\n\n# Output\nnodes\u002FOutput\u002Fposition = Vector2(900, 100)\nnode_connections = [&\"output\", 0, &\"WeaponSway\"]\n```\n\n**混合树脚本控制：**\n```gdscript\n# Control blend tree parameters\nfunc update_blend_tree():\n    # Update time scale based on movement speed\n    var speed = velocity.length()\n    var time_scale = clamp(speed \u002F base_speed, 0.5, 2.0)\n    animation_tree.set(\"parameters\u002FTimeScale\u002Fscale\", time_scale)\n\n    # Trigger OneShot\n    if is_hit:\n        animation_tree.set(\"parameters\u002FHitReaction\u002Factive\", true)\n        animation_tree.set(\"parameters\u002FHitReaction\u002Finternal_active\", true)\n\n    # Control Add2 amount (0.0 = no sway, 1.0 = full sway)\n    var sway_amount = clamp(speed \u002F max_speed, 0.0, 1.0)\n    animation_tree.set(\"parameters\u002FWeaponSway\u002Fadd_amount\", sway_amount)\n```\n\n## 示例\n\n### 2D 角色动画系统\n\n**完整设置：**\n```gdscript\n# character_animator.gd\nextends CharacterBody2D\n\n@onready var animation_tree: AnimationTree = $AnimationTree\n@onready var playback: AnimationNodeStateMachinePlayback\n\n@export var max_speed: float = 200.0\n@export var blend_smoothness: float = 5.0\n\nvar target_blend_position: Vector2 = Vector2.ZERO\nvar current_blend_position: Vector2 = Vector2.ZERO\n\nfunc _ready():\n    animation_tree.active = true\n    playback = animation_tree.get(\"parameters\u002Fplayback\")\n\nfunc _physics_process(delta):\n    # Get input\n    var input_dir = Input.get_vector(\"move_left\", \"move_right\", \"move_up\", \"move_down\")\n\n    # Calculate target blend position\n    if input_dir.length() > 0.1:\n        target_blend_position = input_dir\n        playback.travel(\"Locomotion\")\n    else:\n        target_blend_position = Vector2.ZERO\n        playback.travel(\"Idle\")\n\n    # Smooth blend position transition\n    current_blend_position = current_blend_position.lerp(target_blend_position, blend_smoothness * delta)\n    animation_tree.set(\"parameters\u002FLocomotion\u002Fblend_position\", current_blend_position)\n\n    # Handle actions\n    if Input.is_action_just_pressed(\"attack\"):\n        playback.travel(\"Attack\")\n\n    if Input.is_action_just_pressed(\"interact\"):\n        playback.travel(\"Interact\")\n\nfunc take_damage():\n    playback.travel(\"Hit\")\n\nfunc die():\n    playback.travel(\"Death\")\n```\n\n**生成的场景：**\n```ini\n# animated_character.tscn\n[gd_scene load_steps=10 format=3]\n\n[ext_resource type=\"Script\" path=\"res:\u002F\u002Fcharacter_animator.gd\" id=\"1_anim123\"]\n\n# Animation nodes\n[sub_resource type=\"AnimationNodeAnimation\" id=\"AnimationNodeAnimation_idle\"]\nanimation = &\"idle\"\n\n[sub_resource type=\"AnimationNodeAnimation\" id=\"AnimationNodeAnimation_attack\"]\nanimation = &\"attack\"\n\n[sub_resource type=\"AnimationNodeBlendSpace2D\" id=\"AnimationNodeBlendSpace2D_loco\"]\nblend_point_0\u002Fnode = SubResource(\"AnimationNodeAnimation_idle\")\nblend_point_0\u002Fpos = Vector2(0, 0)\n# ... more blend points\n\n# State machine\n[sub_resource type=\"AnimationNodeStateMachine\" id=\"AnimationNodeStateMachine_main\"]\nstates\u002FStart\u002Fposition = Vector2(150, 100)\nstates\u002FIdle\u002Fnode = SubResource(\"AnimationNodeAnimation_idle\")\nstates\u002FIdle\u002Fposition = Vector2(300, 100)\nstates\u002FLocomotion\u002Fnode = SubResource(\"AnimationNodeBlendSpace2D_loco\")\nstates\u002FLocomotion\u002Fposition = Vector2(500, 100)\nstates\u002FAttack\u002Fnode = SubResource(\"AnimationNodeAnimation_attack\")\nstates\u002FAttack\u002Fposition = Vector2(500, 300)\nstates\u002FEnd\u002Fposition = Vector2(700, 100)\n\n# Transitions\n[sub_resource type=\"AnimationNodeStateMachineTransition\" id=\"AnimationNodeStateMachineTransition_to_loco\"]\nadvance_condition = \"is_moving\"\n\n[sub_resource type=\"AnimationNodeStateMachineTransition\" id=\"AnimationNodeStateMachineTransition_to_idle\"]\nadvance_condition = \"is_moving\"\nnegated = true\n\n[node name=\"AnimatedCharacter\" type=\"CharacterBody2D\"]\nscript = ExtResource(\"1_anim123\")\n\n[node name=\"Sprite2D\" type=\"Sprite2D\" parent=\".\"]\n\n[node name=\"AnimationPlayer\" type=\"AnimationPlayer\" parent=\".\"]\n\n[node name=\"AnimationTree\" type=\"AnimationTree\" parent=\".\"]\nanim_player = NodePath(\"..\u002FAnimationPlayer\")\ntree_root = SubResource(\"AnimationNodeStateMachine_main\")\nparameters\u002Fplayback = SubResource(\"AnimationNodeStateMachinePlayback_main\")\nparameters\u002FLocomotion\u002Fblend_position = Vector2(0, 0)\nparameters\u002Fconditions\u002Fis_moving = false\n```\n\n### 战斗动画系统\n\n**攻击连招系统：**\n```gdscript\n# combat_animator.gd\nextends CharacterBody2D\n\n@onready var animation_tree: AnimationTree = $AnimationTree\n@onready var playback: AnimationNodeStateMachinePlayback\n\nvar combo_count: int = 0\nvar max_combo: int = 3\nvar combo_window: float = 0.5\nvar combo_timer: float = 0.0\n\nfunc _ready():\n    animation_tree.active = true\n    playback = animation_tree.get(\"parameters\u002Fplayback\")\n\nfunc _physics_process(delta):\n    # Update combo timer\n    if combo_timer > 0:\n        combo_timer -= delta\n        if combo_timer \u003C= 0:\n            combo_count = 0\n\n    # Handle attack input\n    if Input.is_action_just_pressed(\"attack\"):\n        perform_attack()\n\n    # Update animation conditions\n    animation_tree.set(\"parameters\u002Fconditions\u002Fin_combo\", combo_count > 0)\n\nfunc perform_attack():\n    match combo_count:\n        0:\n            playback.travel(\"Attack1\")\n        1:\n            playback.travel(\"Attack2\")\n        2:\n            playback.travel(\"Attack3\")\n        _:\n            combo_count = 0\n            playback.travel(\"Attack1\")\n\n    combo_count = (combo_count + 1) % max_combo\n    combo_timer = combo_window\n\nfunc reset_combo():\n    combo_count = 0\n    combo_timer = 0.0\n```\n\n**连招状态机：**\n```ini\n[sub_resource type=\"AnimationNodeStateMachine\" id=\"AnimationNodeStateMachine_combat\"]\nstates\u002FIdle\u002Fposition = Vector2(300, 100)\nstates\u002FAttack1\u002Fposition = Vector2(500, 100)\nstates\u002FAttack2\u002Fposition = Vector2(500, 200)\nstates\u002FAttack3\u002Fposition = Vector2(500, 300)\n\n# Attack1 -> Attack2 transition\n[sub_resource type=\"AnimationNodeStateMachineTransition\" id=\"AnimationNodeStateMachineTransition_a1_a2\"]\nswitch_mode = 1  # SWITCH_MODE_AT_END\nadvance_mode = 1\nadvance_condition = \"in_combo\"\n\n# Attack2 -> Attack3 transition\n[sub_resource type=\"AnimationNodeStateMachineTransition\" id=\"AnimationNodeStateMachineTransition_a2_a3\"]\nswitch_mode = 1\nadvance_mode = 1\nadvance_condition = \"in_combo\"\n\n# All attacks -> Idle (when combo ends)\n[sub_resource type=\"AnimationNodeStateMachineTransition\" id=\"AnimationNodeStateMachineTransition_end\"]\nswitch_mode = 1\nadvance_mode = 1\nnegated = true\nadvance_condition = \"in_combo\"\n```\n\n### NPC 随机待机变体动画\n\n```gdscript\n# npc_animator.gd\nextends CharacterBody2D\n\n@onready var animation_tree: AnimationTree = $AnimationTree\n@onready var playback: AnimationNodeStateMachinePlayback\n\nvar idle_variations: Array[String] = [\"Idle\", \"Idle2\", \"Idle3\"]\nvar idle_timer: float = 0.0\nvar next_idle_change: float = 5.0\n\nfunc _ready():\n    animation_tree.active = true\n    playback = animation_tree.get(\"parameters\u002Fplayback\")\n    pick_random_idle()\n\nfunc _physics_process(delta):\n    # Random idle variation\n    idle_timer += delta\n    if idle_timer >= next_idle_change and velocity.length() \u003C 0.1:\n        idle_timer = 0.0\n        next_idle_change = randf_range(3.0, 8.0)\n        pick_random_idle()\n\n    # Movement\n    if velocity.length() > 0.1:\n        playback.travel(\"Walk\")\n\nfunc pick_random_idle():\n    var random_idle = idle_variations[randi() % idle_variations.size()]\n    playback.travel(random_idle)\n```\n\n## 常用模式\n\n### 动画事件集成\n\n```gdscript\n# Connect animation events to gameplay\nfunc _ready():\n    animation_tree.animation_started.connect(_on_animation_started)\n    animation_tree.animation_finished.connect(_on_animation_finished)\n\nfunc _on_animation_started(anim_name: StringName):\n    match anim_name:\n        \"attack\":\n            # Disable movement during attack\n            can_move = false\n        \"dash\":\n            # Make invincible\n            is_invincible = true\n\nfunc _on_animation_finished(anim_name: StringName):\n    match anim_name:\n        \"attack\":\n            can_move = true\n        \"dash\":\n            is_invincible = false\n```\n\n### 动画驱动的移动\n\n```gdscript\n# Root motion implementation\nfunc _on_animation_tree_animation_started(anim_name: StringName):\n    if anim_name == &\"attack\":\n        # Enable root motion tracking\n        animation_tree.set(\"parameters\u002FAttack\u002Factive\", true)\n\nfunc _physics_process(delta):\n    # Apply root motion from animation\n    var root_motion: Transform3D = animation_tree.get_root_motion()\n    global_transform *= root_motion\n```\n\n### 平滑状态过渡\n\n```gdscript\n# Crossfade duration configuration\nvar transition = AnimationNodeStateMachineTransition.new()\ntransition.fade_duration = 0.2  # 200ms crossfade\n```\n\n## 安全注意事项\n\n- 访问参数前始终检查 AnimationTree 是否处于激活状态\n- 设置树之前验证 AnimationPlayer 包含所有需要的动画\n- 优雅处理缺失的混合位置（默认为中心）\n- 重新父级或切换场景时重置 AnimationTree\n- 在 queue_free() 前断开信号连接\n\n## 不适用场景\n\n在以下情况不要使用 AnimationTree：\n- 只有 2-3 个简单动画（过度设计）\n- 动画逻辑非常简单（仅播放\u002F停止）\n- 低端设备上性能至关重要\n- 需要逐帧直接控制\n\n改用直接 AnimationPlayer 控制：\n```gdscript\n# Simple animation control\nfunc _physics_process(delta):\n    if is_moving:\n        anim_player.play(\"walk\")\n    else:\n        anim_player.play(\"idle\")\n```\n\n## 集成\n\n可配合以下技能使用：\n- **godot-add-signals** - 将动画事件连接到游戏系统\n- **godot-extract-to-scenes** - 创建可复用的动画角色场景\n- **godot-setup-navigation** - 导航代理配合移动动画\n- **godot-migrate-tilemap** - 动画 TileMap 角色\n\n## 性能提示\n\n1. **限制混合点数量** - 通常 4-8 个点就足够\n2. **缓存参数路径** - 将参数路径存储为常量\n3. **禁用未使用的树** - 不在屏幕上时设置 `active = false`\n4. **使用 TimeScale** - 而非直接修改动画速度\n5. **批量过渡** - 尽可能将状态变化合并处理\n",{"name":5,"type":32,"author":44,"license":14,"outputs":45,"version":46,"audience":47,"behavior":49,"category":51,"homepage":52,"keywords":53,"execution":61,"platforms":62,"difficulty":24,"repository":64,"description":65,"displayName":66,"integration":67,"permissions":68,"requirements":75},"Asreonn","AnimationTree 节点配置、AnimationNodeStateMachine 图形、BlendSpace2D\u002F3D 设置、过渡条件、动画控制器脚本","1.0.0",[48],"developers",{"validation":50,"git_commits":50,"auto_rollback":50},true,"game-development","https:\u002F\u002Fgithub.com\u002Fasreonn\u002Fgodot-superpowers#readme",[21,54,20,28,55,56,57,58,59,60],"animation","blendspace","blendspace2d","blendspace3d","transitions","animationtreeplayer","locomotion","全自动场景生成和脚本更新",[63,30,38],"macos","https:\u002F\u002Fgithub.com\u002Fasreonn\u002Fgodot-superpowers","用于设置 AnimationTree 节点的状态机驱动动画， 创建 AnimationNodeStateMachine 图形，配置 BlendSpace2D\u002F3D 进行运动混合，实现状态过渡条件， 或创建动画混合树进行复杂的动画混合。 支持玩家角色动画、NPC 和复杂动画系统。\n","设置 AnimationTree 状态机","与 godot-add-signals 配合处理动画事件，与 godot-extract-to-scenes 配合组织角色场景",{"git":50,"filesystem":69},{"read":70,"write":74},[71,72,73],".gd",".tscn",".tres",[72,73,71],"Git 仓库，Godot 4.x，AnimatedSprite3D 或带 AnimationPlayer 的 Sprite2D","main","18d0e63d1313ca87098f614aa7c1e2dcf6de79c7","backend\u002Fconfig_packs\u002Fgodot-dev\u002Fclaude\u002Fskills\u002Fgodot-setup-animationtree",1,"https:\u002F\u002Fgithub.com\u002Fwelflau\u002Fai-dev-system","https:\u002F\u002Fgithub.com\u002Fwelflau","2026-11-10 11:14:25",{"source":8,"skillName":5,"commands":84,"prompt":94,"zipAvailable":50},[85,88,91],{"tool":86,"command":87},"npx","npx skills add welflau\u002Fai-dev-system --skill godot-setup-animationtree",{"tool":89,"command":90},"bunx","bunx skills add welflau\u002Fai-dev-system --skill godot-setup-animationtree",{"tool":92,"command":93},"pnpm","pnpm dlx skills add welflau\u002Fai-dev-system --skill godot-setup-animationtree","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fwelflau\u002Fai-dev-system\u002Fblob\u002Fmain\u002Fbackend\u002Fconfig_packs\u002Fgodot-dev\u002Fclaude\u002Fskills\u002Fgodot-setup-animationtree\u002FSKILL.md",[],[97,131,163,188,214,237],{"skillNo":98,"name":99,"nameZh":6,"description":100,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":101,"licenseFileUrl":102,"sourceHtmlUrl":103,"categories":104,"keywords":110,"publishedAt":39},"01M6HSTDP4M3JFXEBK91VFB4PA","web-artifacts-builder","Suite of tools for creating elaborate, multi-component claude.ai HTML artifacts using modern frontend web technologies (React, Tailwind CSS, shadcn\u002Fui). Use for complex artifacts requiring state management, routing, or shadcn\u002Fui components - not for simple single-file HTML\u002FJSX artifacts.","Apache-2.0","https:\u002F\u002Fgithub.com\u002Fwelflau\u002Fai-dev-system\u002Fblob\u002Fmain\u002Fbackend\u002Fskills\u002Fmarketplace\u002Fcodebuddy-plugins-official\u002Fplugins\u002Fweb-artifacts-builder\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002Fwelflau\u002Fai-dev-system\u002Fblob\u002Fmain\u002Fbackend\u002Fskills\u002Fmarketplace\u002Fcodebuddy-plugins-official\u002Fplugins\u002Fweb-artifacts-builder\u002FSKILL.md",[105],{"categoryNo":106,"categoryName":107,"taxonomyType":108,"taxonomyTypeDesc":109},"01JBSEEDCAT000000000000009","前端开发","SCENARIO","使用场景",[111,112,113,114,115,116,117,118,119,120,121,36,122,123,124,125,126,127,128,129,130],"web artifacts builder","web","artifacts","artifacts builder","builder","frontend","css","components","react","routing","state management","file","Tailwind","use","single-file","simple","ui components","multi","for","single",{"skillNo":132,"name":133,"nameZh":6,"description":134,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":101,"licenseFileUrl":135,"sourceHtmlUrl":136,"categories":137,"keywords":147,"publishedAt":39},"01M6HSDXH0JSP8R3QTNY9XZ8HN","frontend-design","Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications (examples include websites, landing pages, dashboards, React components, HTML\u002FCSS layouts, or when styling\u002Fbeautifying any web UI). Generates creative, polished code and UI design that avoids generic AI aesthetics.","https:\u002F\u002Fgithub.com\u002Fwelflau\u002Fai-dev-system\u002Fblob\u002Fmain\u002Fbackend\u002Fskills\u002Fmarketplace\u002Fcodebuddy-plugins-official\u002Fplugins\u002Ffrontend-design\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002Fwelflau\u002Fai-dev-system\u002Fblob\u002Fmain\u002Fbackend\u002Fskills\u002Fmarketplace\u002Fcodebuddy-plugins-official\u002Fplugins\u002Ffrontend-design\u002FSKILL.md",[138,139,142],{"categoryNo":106,"categoryName":107,"taxonomyType":108,"taxonomyTypeDesc":109},{"categoryNo":140,"categoryName":141,"taxonomyType":108,"taxonomyTypeDesc":109},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":143,"categoryName":144,"taxonomyType":145,"taxonomyTypeDesc":146},"01JBSEEDCAT000000000000032","设计师","PROFESSION","适用职业",[116,148,149,117,112,118,119,150,151,152,113,153,154,155,124,156,157,158,159,160,161,162],"design","frontend design","react components","create","code","examples","applications","landing","ui design","pages","aesthetics","web ui","with","generic","when",{"skillNo":164,"name":165,"nameZh":6,"description":166,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":101,"licenseFileUrl":167,"sourceHtmlUrl":168,"categories":169,"keywords":171,"publishedAt":39},"01M6HSA77QYVP7A72HREGTDN2C","algorithmic-art","Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.","https:\u002F\u002Fgithub.com\u002Fwelflau\u002Fai-dev-system\u002Fblob\u002Fmain\u002Fbackend\u002Fskills\u002Fmarketplace\u002Fcodebuddy-plugins-official\u002Fplugins\u002Falgorithmic-art\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002Fwelflau\u002Fai-dev-system\u002Fblob\u002Fmain\u002Fbackend\u002Fskills\u002Fmarketplace\u002Fcodebuddy-plugins-official\u002Fplugins\u002Falgorithmic-art\u002FSKILL.md",[170],{"categoryNo":140,"categoryName":141,"taxonomyType":108,"taxonomyTypeDesc":109},[172,173,174,151,152,175,176,177,178,124,179,180,181,182,160,183,184,185,186,187,162],"algorithmic art","Art","algorithmic","flow","js","work","interactive","generative art","exploration","systems","users","Existing","request","generative","copyright","fields",{"skillNo":189,"name":190,"nameZh":6,"description":191,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":101,"licenseFileUrl":192,"sourceHtmlUrl":193,"categories":194,"keywords":196,"publishedAt":39},"01M6HS9HE0X390Y6RQKTY1YNGJ","theme-factory","Toolkit for styling artifacts with a theme. These artifacts can be slides, docs, reportings, HTML landing pages, etc. There are 10 pre-set themes with colors\u002Ffonts that you can apply to any artifact that has been creating, or can generate a new theme on-the-fly.","https:\u002F\u002Fgithub.com\u002Fwelflau\u002Fai-dev-system\u002Fblob\u002Fmain\u002Fbackend\u002Fskills\u002Fmarketplace\u002Fcodebuddy-plugins-official\u002Fexternal_plugins\u002Ftheme-factory\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002Fwelflau\u002Fai-dev-system\u002Fblob\u002Fmain\u002Fbackend\u002Fskills\u002Fmarketplace\u002Fcodebuddy-plugins-official\u002Fexternal_plugins\u002Ftheme-factory\u002FSKILL.md",[195],{"categoryNo":140,"categoryName":141,"taxonomyType":108,"taxonomyTypeDesc":109},[197,198,199,200,201,202,113,203,204,205,155,206,207,157,208,160,209,210,211,129,212,213],"theme factory","factory","theme","docs","toolkit","generate","SET","fly","slides","styling","artifact","themes","you","fonts","can","apply","new",{"skillNo":215,"name":216,"nameZh":6,"description":217,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":218,"categories":219,"keywords":223,"publishedAt":39},"01M6HS74GASM6FJ77F83EY679E","browsing","Use when you need direct browser control - teaches Chrome DevTools Protocol for controlling existing browser sessions, multi-tab management, form automation, and content extraction via use_browser MCP tool","https:\u002F\u002Fgithub.com\u002Fwelflau\u002Fai-dev-system\u002Fblob\u002Fmain\u002Fbackend\u002Fskills\u002Fmarketplace\u002Fcodebuddy-plugins-official\u002Fexternal_plugins\u002Fsuperpowers-chrome\u002Fskills\u002Fbrowsing\u002FSKILL.md",[220],{"categoryNo":221,"categoryName":222,"taxonomyType":108,"taxonomyTypeDesc":109},"01JBSEEDCAT000000000000023","Skill与智能体开发",[216,224,225,226,227,228,229,230,231,32,232,124,233,234,235,236,128,209,129,183],"MCP","automation","chrome","sessions","protocol","browser","devtools","chrome devtools","direct","browser control","control","via","form",{"skillNo":238,"name":239,"nameZh":6,"description":240,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":101,"licenseFileUrl":241,"sourceHtmlUrl":242,"categories":243,"keywords":250,"publishedAt":39},"01M6HS6BZT2CKDNQ6YF20DXN4T","slack-gif-creator","Knowledge and utilities for creating animated GIFs optimized for Slack. Provides constraints, validation tools, and animation concepts. Use when users request animated GIFs for Slack like \"make me a GIF of X doing Y for Slack.\"","https:\u002F\u002Fgithub.com\u002Fwelflau\u002Fai-dev-system\u002Fblob\u002Fmain\u002Fbackend\u002Fskills\u002Fmarketplace\u002Fcodebuddy-plugins-official\u002Fexternal_plugins\u002Fslack-gif-creator\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002Fwelflau\u002Fai-dev-system\u002Fblob\u002Fmain\u002Fbackend\u002Fskills\u002Fmarketplace\u002Fcodebuddy-plugins-official\u002Fexternal_plugins\u002Fslack-gif-creator\u002FSKILL.md",[244,247],{"categoryNo":245,"categoryName":246,"taxonomyType":108,"taxonomyTypeDesc":109},"01JBSEEDCAT000000000000005","邮件与沟通",{"categoryNo":248,"categoryName":249,"taxonomyType":108,"taxonomyTypeDesc":109},"01JBSEEDCAT000000000000016","图像与多媒体",[251,252,253,254,255,256,257,35,258,124,259,182,260,261,262,129,184,162],"slack gif creator","slack","gif","creator","validation","Tools","constraints","knowledge","me","make","Utilities","concepts"]