smithery.ai

effects

Reference this when implementing effects for abilities, animations, and state-based behaviors.

First seen May 2, 2026

Installation

$ npx skills add https://smithery.ai

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 6,100 B
  • docs SUMMARY.md 109 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

CSL Effect System

Effects temporarily take control of an entity to execute complex behaviors (dashes, attacks, death sequences). Works with Players, NPCs, or any entity.

Creating an Effect

My_Effect :: class : Effect_Base {
    target_position: v2;

    effect_start :: method() {
        player_specific.freeze_player = true;
        player.animator.state_machine.set_trigger("my_animation");
    }

    effect_update :: method(dt: float) {
        entity.lerp_local_position(target_position, 20 * dt);
        if get_elapsed_time() > 1.0 {
            remove_effect(false);
            return; // Effect is invalid after removal -- must return immediately
        }
    }

    effect_end :: method(interrupt: bool) {
        if !interrupt {
            entity.set_local_position(target_position);
        }
        player.animator.state_machine.set_trigger("RESET");
    }
}

Activating Effects

Active effects (setactiveeffect) -- one at a time, setting a new one ends the current with interrupt = true:

effect := new(My_Effect);
effect.target_position = target.world_position;
entity.set_active_effect(effect);

Passive effects (addpassiveeffect) -- multiple allowed, stack (slows, buffs):

slow_effect := new(Slow_Effect);
slow_effect.speed_multiplier = 0.5;
slow_effect.set_duration(4); // Auto-remove after 4 seconds
entity.add_passive_effect(slow_effect);

Effect_Base Fields

Effect_Base :: class {
    entity: Entity;
    player: Player; // null for NPCs

    player_specific: struct {
        freeze_player: bool; // Zero out Player Movement_Agent velocity (use for eat/interact)
        disable_movement_inputs: bool; // Ignore input but code can still move (use for dash/roll)
    };

    start_time: float #read_only;
    next_effect: Effect_Base #read_only;
    prev_effect: Effect_Base #read_only;
}

Callbacks (each optional)

  • effectstart -- Set freeze/movement flags, trigger animations, store initial state, call setduration.
  • effect_update(dt: float)
  • effectlateupdate(dt: float) -- Post-update UI, camera effects, or local-only visuals. Screen UI is valid here for effects attached to a Player because player effects run from coreplayerlateupdate; guard UI with player.islocalorserver().
  • effectend(interrupt: bool) -- Restore saved state, reset animations with player.animator.statemachine.set_trigger("RESET").

Checking Effects

if has_effect(entity, Slow_Effect) {
    agent.movement_speed *= 0.5;
}

Examples

Movement Effect (Dash/Roll)

Roll_Effect :: class : Effect_Base {
    direction: v2;
    original_friction: float;

    effect_start :: method() {
        player_specific.disable_movement_inputs = true;
        original_friction = player.agent.friction;
        player.agent.friction = 0;
        player.animator.state_machine.set_trigger("dodge_roll");
        player.set_facing_right(direction.x > 0);
        set_duration(0.5);
    }

    effect_update :: method(dt: float) {
        player.agent.velocity = direction * 8;
    }

    effect_end :: method(interrupt: bool) {
        player.agent.friction = original_friction;
    }
}

Attack Effect (Hit Detection)

Same structure as RollEffect, but add an alreadyhit_list to avoid hitting the same target twice:

already_hit_list: [..]Player;

effect_update :: method(dt: float) {
    for other: component_iterator(Player) {
        if other.team == player.team continue;
        if !in_range(other.entity.world_position - player.entity.world_position, 0.75) continue;
        if already_hit_list.contains(other) continue;
        other.take_damage(1); // user-defined damage method
        already_hit_list.append(other);
    }
    player.agent.velocity = direction * 10;
    if get_elapsed_time() > 0.3 {
        remove_effect(false);
        return;
    }
}

Death/Respawn Effect

Death_Effect :: class : Effect_Base {
    effect_start :: method() {
        player_specific.freeze_player = true;
        player.add_name_invisibility_reason("death");
        player.animator.state_machine.set_trigger("death");
    }

    effect_update :: method(dt: float) {
        time_until_respawn := 5.0 - get_elapsed_time();
        if time_until_respawn <= 0 {
            remove_effect(false);
            return;
        }
    }

    effect_end :: method(interrupt: bool) {
        player.remove_name_invisibility_reason("death");
        respawn_player(player); // user-defined respawn proc
        reset_player_health(player); // replace with your game's health reset logic
        player.animator.state_machine.set_trigger("RESET");
    }

    effect_late_update :: method(dt: float) {
        if player.is_local_or_server() {
            time_until_respawn := 5.0 - get_elapsed_time();
            ts := UI.default_text_settings();
            ts.size = 64;
            rect := UI.get_screen_rect().bottom_center_rect().offset(0, 150);
            UI.text(rect, ts, `Respawning in {time_until_respawn.(int) + 1}`);
        }
    }
}

NPC Effects

For NPCs, player is null. Store a reference to the NPC component and use entity for transforms.

NPC_Death_Effect :: class : Effect_Base {
    npc: NPC;

    effect_update :: method(dt: float) {
        t := Ease.out_quad(Ease.T(get_elapsed_time(), 1.0));
        npc.sprite.color.w = lerp(1.0, 0.0, t);
        if get_elapsed_time() > 5.0 {
            entity.destroy();
        }
    }
}

// Usage:
effect := new(NPC_Death_Effect);
effect.npc = this;
entity.set_active_effect(effect);

Skip normal behavior while an effect is active:

ao_update :: method(dt: float) {
    if entity.get_active_effect() != null return;
    // Normal behaviour...
}

Checking Effects

effect := entity.get_active_effect();
if effect != null && effect.#type == Eating_Effect {
    effect.(Eating_Effect).chomp();
}

remove_all_effects(entity);