vfx-effects

SKILL.md

Roblox Visual Effects (VFX)

When implementing VFX, use these patterns for impactful and performant effects.

Particle Effects

Anime Hit VFX

local function createHitEffect(position, direction, intensity)
    intensity = intensity or 1

    -- Impact flash
    local flash = Instance.new("Part")
    flash.Shape = Enum.PartType.Ball
    flash.Size = Vector3.new(0.1, 0.1, 0.1)
    flash.Position = position
    flash.Anchored = true
    flash.CanCollide = false
    flash.Material = Enum.Material.Neon
    flash.Color = Color3.new(1, 1, 1)
    flash.Parent = workspace.Effects

    -- Scale up and fade
    local tweenInfo = TweenInfo.new(0.15, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
    TweenService:Create(flash, tweenInfo, {
        Size = Vector3.new(3, 3, 3) * intensity,
        Transparency = 1
    }):Play()

    -- Radial lines (speedlines)
    local numLines = 8
    for i = 1, numLines do
        local angle = (i / numLines) * math.pi * 2
        local lineDir = Vector3.new(math.cos(angle), 0, math.sin(angle))

        local line = Instance.new("Part")
        line.Size = Vector3.new(0.1, 0.1, 2)
        line.CFrame = CFrame.lookAt(position, position + lineDir) * CFrame.new(0, 0, -1)
        line.Anchored = true
        line.CanCollide = false
        line.Material = Enum.Material.Neon
        line.Color = Color3.new(1, 0.9, 0.8)
        line.Parent = workspace.Effects

        TweenService:Create(line, TweenInfo.new(0.2), {
            Size = Vector3.new(0.05, 0.05, 5) * intensity,
            CFrame = line.CFrame * CFrame.new(0, 0, -3),
            Transparency = 1
        }):Play()

        Debris:AddItem(line, 0.3)
    end

    -- Screen shake
    shakeCamera(0.3, intensity * 5)

    Debris:AddItem(flash, 0.2)
end

Slash Trail

local function createSlashTrail(weapon, duration)
    local attachment0 = weapon:FindFirstChild("TrailAttachment0")
    local attachment1 = weapon:FindFirstChild("TrailAttachment1")

    if not attachment0 or not attachment1 then
        -- Create attachments at blade ends
        attachment0 = Instance.new("Attachment")
        attachment0.Name = "TrailAttachment0"
        attachment0.Position = Vector3.new(0, 0, 2)  -- Tip
        attachment0.Parent = weapon

        attachment1 = Instance.new("Attachment")
        attachment1.Name = "TrailAttachment1"
        attachment1.Position = Vector3.new(0, 0, 0)  -- Base
        attachment1.Parent = weapon
    end

    local trail = Instance.new("Trail")
    trail.Attachment0 = attachment0
    trail.Attachment1 = attachment1
    trail.Lifetime = 0.3
    trail.MinLength = 0
    trail.FaceCamera = true
    trail.Color = ColorSequence.new({
        ColorSequenceKeypoint.new(0, Color3.new(1, 1, 1)),
        ColorSequenceKeypoint.new(1, Color3.new(0.8, 0.8, 1))
    })
    trail.Transparency = NumberSequence.new({
        NumberSequenceKeypoint.new(0, 0),
        NumberSequenceKeypoint.new(0.5, 0.3),
        NumberSequenceKeypoint.new(1, 1)
    })
    trail.WidthScale = NumberSequence.new({
        NumberSequenceKeypoint.new(0, 1),
        NumberSequenceKeypoint.new(1, 0.2)
    })
    trail.Parent = weapon

    -- Disable after duration
    task.delay(duration, function()
        trail.Enabled = false
        Debris:AddItem(trail, trail.Lifetime)
    end)

    return trail
end

Aura Effect

local function createAura(character, color, intensity)
    local hrp = character:FindFirstChild("HumanoidRootPart")
    if not hrp then return end

    local attachment = Instance.new("Attachment")
    attachment.Parent = hrp

    local particles = Instance.new("ParticleEmitter")
    particles.Color = ColorSequence.new(color)
    particles.Size = NumberSequence.new({
        NumberSequenceKeypoint.new(0, 0.5),
        NumberSequenceKeypoint.new(0.5, 1),
        NumberSequenceKeypoint.new(1, 0)
    })
    particles.Transparency = NumberSequence.new({
        NumberSequenceKeypoint.new(0, 0.5),
        NumberSequenceKeypoint.new(1, 1)
    })
    particles.Lifetime = NumberRange.new(0.5, 1)
    particles.Rate = 50 * intensity
    particles.Speed = NumberRange.new(2, 4)
    particles.SpreadAngle = Vector2.new(180, 180)
    particles.Acceleration = Vector3.new(0, 5, 0)
    particles.EmissionDirection = Enum.NormalId.Top
    particles.Parent = attachment

    -- Point light for glow
    local light = Instance.new("PointLight")
    light.Color = color
    light.Brightness = intensity
    light.Range = 10
    light.Parent = hrp

    return {
        stop = function()
            particles.Enabled = false
            TweenService:Create(light, TweenInfo.new(0.5), {Brightness = 0}):Play()
            Debris:AddItem(attachment, 1)
            Debris:AddItem(light, 0.5)
        end
    }
end

Camera Effects

Screen Shake

local ShakeModule = {}
local currentShake = Vector3.new()

function ShakeModule.shake(duration, magnitude, frequency)
    frequency = frequency or 20

    local startTime = os.clock()
    local conn
    conn = RunService.RenderStepped:Connect(function()
        local elapsed = os.clock() - startTime
        if elapsed > duration then
            currentShake = Vector3.new()
            conn:Disconnect()
            return
        end

        -- Decay over time
        local decay = 1 - (elapsed / duration)
        local shake = magnitude * decay

        -- Random offset
        currentShake = Vector3.new(
            (math.random() - 0.5) * 2 * shake,
            (math.random() - 0.5) * 2 * shake,
            0
        )
    end)
end

function ShakeModule.getOffset()
    return currentShake
end

-- Apply in camera update
RunService.RenderStepped:Connect(function()
    local offset = ShakeModule.getOffset()
    camera.CFrame = camera.CFrame * CFrame.new(offset)
end)

Hit Stop (Frame Freeze)

local function hitStop(duration)
    duration = duration or 0.05

    -- Store original time scale
    local originalSpeed = 1

    -- Slow down animations
    for _, player in ipairs(Players:GetPlayers()) do
        local character = player.Character
        if character then
            local humanoid = character:FindFirstChildOfClass("Humanoid")
            if humanoid then
                local animator = humanoid:FindFirstChildOfClass("Animator")
                if animator then
                    for _, track in ipairs(animator:GetPlayingAnimationTracks()) do
                        track:AdjustSpeed(0.01)
                    end
                end
            end
        end
    end

    task.wait(duration)

    -- Restore
    for _, player in ipairs(Players:GetPlayers()) do
        local character = player.Character
        if character then
            local humanoid = character:FindFirstChildOfClass("Humanoid")
            if humanoid then
                local animator = humanoid:FindFirstChildOfClass("Animator")
                if animator then
                    for _, track in ipairs(animator:GetPlayingAnimationTracks()) do
                        track:AdjustSpeed(1)
                    end
                end
            end
        end
    end
end

Zoom Punch Effect

local function zoomPunch(intensity, duration)
    intensity = intensity or 5
    duration = duration or 0.1

    local camera = workspace.CurrentCamera
    local originalFOV = camera.FieldOfView

    -- Quick zoom in
    TweenService:Create(camera, TweenInfo.new(duration * 0.3, Enum.EasingStyle.Quad, Enum.EasingDirection.Out), {
        FieldOfView = originalFOV - intensity
    }):Play()

    task.wait(duration * 0.3)

    -- Slower return
    TweenService:Create(camera, TweenInfo.new(duration * 0.7, Enum.EasingStyle.Quad, Enum.EasingDirection.Out), {
        FieldOfView = originalFOV
    }):Play()
end

Lighting Effects

Dynamic Muzzle Flash

local function muzzleFlash(attachment)
    -- Light
    local light = Instance.new("PointLight")
    light.Color = Color3.new(1, 0.9, 0.5)
    light.Brightness = 5
    light.Range = 15
    light.Parent = attachment

    -- Flash particle
    local flash = Instance.new("ParticleEmitter")
    flash.Texture = "rbxassetid://123456789"  -- Muzzle flash texture
    flash.Size = NumberSequence.new(1.5)
    flash.Lifetime = NumberRange.new(0.05)
    flash.Rate = 0
    flash.Speed = NumberRange.new(0)
    flash.Parent = attachment

    flash:Emit(1)

    -- Fade light
    TweenService:Create(light, TweenInfo.new(0.1), {Brightness = 0}):Play()

    Debris:AddItem(light, 0.15)
    Debris:AddItem(flash, 0.1)
end

Lightning Flash

local function lightningFlash()
    local lighting = game:GetService("Lighting")
    local originalAmbient = lighting.Ambient

    -- Flash white
    lighting.Ambient = Color3.new(1, 1, 1)

    task.wait(0.05)
    lighting.Ambient = originalAmbient
    task.wait(0.1)
    lighting.Ambient = Color3.new(0.8, 0.8, 0.8)
    task.wait(0.05)
    lighting.Ambient = originalAmbient
end

Mesh & Material Effects

Dissolve Effect

local function dissolve(part, duration)
    -- Create a dissolve texture
    local surfaceGui = Instance.new("SurfaceGui")
    surfaceGui.Face = Enum.NormalId.Front
    surfaceGui.LightInfluence = 0

    local frame = Instance.new("Frame")
    frame.Size = UDim2.new(1, 0, 1, 0)
    frame.BackgroundTransparency = 1
    frame.Parent = surfaceGui

    local gradient = Instance.new("UIGradient")
    gradient.Rotation = 90
    gradient.Parent = frame

    surfaceGui.Parent = part

    -- Animate gradient offset
    local startTime = os.clock()
    local conn
    conn = RunService.RenderStepped:Connect(function()
        local elapsed = os.clock() - startTime
        local t = elapsed / duration

        if t >= 1 then
            part:Destroy()
            conn:Disconnect()
            return
        end

        gradient.Offset = Vector2.new(0, t * 2 - 1)
        part.Transparency = t
    end)
end

Outline Effect

local function addOutline(character, color, thickness)
    thickness = thickness or 0.05

    for _, part in ipairs(character:GetDescendants()) do
        if part:IsA("BasePart") and part.Name ~= "HumanoidRootPart" then
            local outline = part:Clone()
            outline.Name = "Outline"
            outline.Size = part.Size + Vector3.new(thickness, thickness, thickness)
            outline.Material = Enum.Material.SmoothPlastic
            outline.Color = color
            outline.CanCollide = false
            outline.Massless = true
            outline.Transparency = 0

            local weld = Instance.new("WeldConstraint")
            weld.Part0 = part
            weld.Part1 = outline
            weld.Parent = outline

            outline.Parent = part
        end
    end
end

UI Visual Effects

Damage Numbers

local function showDamageNumber(position, damage, isCrit)
    local billboardGui = Instance.new("BillboardGui")
    billboardGui.Size = UDim2.new(0, 100, 0, 50)
    billboardGui.StudsOffset = Vector3.new(0, 2, 0)
    billboardGui.Adornee = nil
    billboardGui.AlwaysOnTop = true

    local label = Instance.new("TextLabel")
    label.Size = UDim2.new(1, 0, 1, 0)
    label.BackgroundTransparency = 1
    label.Text = tostring(math.floor(damage))
    label.TextColor3 = isCrit and Color3.new(1, 0.8, 0) or Color3.new(1, 1, 1)
    label.TextStrokeTransparency = 0
    label.TextStrokeColor3 = Color3.new(0, 0, 0)
    label.TextScaled = true
    label.Font = Enum.Font.GothamBold
    label.Parent = billboardGui

    -- Position in world
    local part = Instance.new("Part")
    part.Anchored = true
    part.CanCollide = false
    part.Transparency = 1
    part.Size = Vector3.new(0.1, 0.1, 0.1)
    part.Position = position
    part.Parent = workspace.Effects

    billboardGui.Adornee = part
    billboardGui.Parent = part

    -- Animate: rise and fade
    local startY = position.Y
    local startTime = os.clock()

    local conn
    conn = RunService.RenderStepped:Connect(function()
        local elapsed = os.clock() - startTime
        local t = elapsed / 1

        if t >= 1 then
            part:Destroy()
            conn:Disconnect()
            return
        end

        -- Rise with easing
        local easeT = 1 - (1 - t) ^ 2
        part.Position = Vector3.new(position.X, startY + easeT * 3, position.Z)

        -- Fade out
        label.TextTransparency = t
        label.TextStrokeTransparency = t

        -- Scale pop for crits
        if isCrit and t < 0.2 then
            local scale = 1 + math.sin(t * 5 * math.pi) * 0.3
            label.TextSize = 24 * scale
        end
    end)
end

Cooldown Sweep

local function createCooldownUI(button, cooldownDuration)
    local overlay = Instance.new("Frame")
    overlay.Name = "CooldownOverlay"
    overlay.Size = UDim2.new(1, 0, 1, 0)
    overlay.BackgroundColor3 = Color3.new(0, 0, 0)
    overlay.BackgroundTransparency = 0.5
    overlay.Parent = button

    local gradient = Instance.new("UIGradient")
    gradient.Rotation = -90
    gradient.Transparency = NumberSequence.new({
        NumberSequenceKeypoint.new(0, 0),
        NumberSequenceKeypoint.new(0.5, 0),
        NumberSequenceKeypoint.new(0.501, 1),
        NumberSequenceKeypoint.new(1, 1)
    })
    gradient.Parent = overlay

    -- Animate
    local startTime = os.clock()
    local conn
    conn = RunService.RenderStepped:Connect(function()
        local elapsed = os.clock() - startTime
        local t = elapsed / cooldownDuration

        if t >= 1 then
            overlay:Destroy()
            conn:Disconnect()
            return
        end

        -- Rotate gradient to create sweep effect
        gradient.Rotation = -90 + (t * 360)
    end)
end

Advanced VFX

Beam Weapon

local function createBeam(startAttachment, endPosition, duration)
    local endPart = Instance.new("Part")
    endPart.Anchored = true
    endPart.CanCollide = false
    endPart.Transparency = 1
    endPart.Size = Vector3.new(0.1, 0.1, 0.1)
    endPart.Position = endPosition
    endPart.Parent = workspace.Effects

    local endAttachment = Instance.new("Attachment")
    endAttachment.Parent = endPart

    local beam = Instance.new("Beam")
    beam.Attachment0 = startAttachment
    beam.Attachment1 = endAttachment
    beam.Width0 = 0.5
    beam.Width1 = 0.3
    beam.FaceCamera = true
    beam.Color = ColorSequence.new(Color3.new(1, 0, 0))
    beam.Transparency = NumberSequence.new(0)
    beam.LightEmission = 1
    beam.LightInfluence = 0
    beam.TextureSpeed = 5
    beam.Parent = startAttachment

    -- Fade out
    task.delay(duration * 0.7, function()
        TweenService:Create(beam, TweenInfo.new(duration * 0.3), {
            Transparency = NumberSequence.new(1)
        }):Play()
    end)

    Debris:AddItem(endPart, duration)
    Debris:AddItem(beam, duration)

    return beam
end

Lightning Chain

local function createLightningChain(startPos, endPos, segments)
    segments = segments or 8

    local parts = {}
    local direction = endPos - startPos
    local segmentLength = direction.Magnitude / segments

    for i = 1, segments do
        local t1 = (i - 1) / segments
        local t2 = i / segments

        local p1 = startPos + direction * t1
        local p2 = startPos + direction * t2

        -- Add random offset (except for endpoints)
        if i > 1 then
            local jitter = segmentLength * 0.5
            p1 = p1 + Vector3.new(
                (math.random() - 0.5) * jitter,
                (math.random() - 0.5) * jitter,
                (math.random() - 0.5) * jitter
            )
        end

        local segment = Instance.new("Part")
        segment.Anchored = true
        segment.CanCollide = false
        segment.Material = Enum.Material.Neon
        segment.Color = Color3.new(0.7, 0.8, 1)

        local dist = (p2 - p1).Magnitude
        segment.Size = Vector3.new(0.1, 0.1, dist)
        segment.CFrame = CFrame.lookAt((p1 + p2) / 2, p2)
        segment.Parent = workspace.Effects

        table.insert(parts, segment)
    end

    -- Quick flash and fade
    task.delay(0.05, function()
        for _, part in ipairs(parts) do
            TweenService:Create(part, TweenInfo.new(0.1), {Transparency = 1}):Play()
        end
    end)

    task.delay(0.15, function()
        for _, part in ipairs(parts) do
            part:Destroy()
        end
    end)
end
Weekly Installs
2
Installed on
codex2
claude-code2
windsurf1
opencode1
cursor1
antigravity1