AgentSkillsCN

vfx-spell-effects

借助实用的烟雾、闪电、粒子、光晕、图层叠加等特效制作技巧,结合稳定流畅的 60 帧每秒性能,在 Apple 平台上打造媲美游戏品质的魔法特效。

SKILL.md
--- frontmatter
name: vfx-spell-effects
description: Build game-quality spell VFX on Apple platforms with practical recipes for smoke, lightning, particles, bloom, layering, and stable 60fps performance.
triggers:
  - spell effect
  - vfx particles
  - lightning bolt effect
  - smoke fog simulation
  - bloom glow shader
  - fire effect
  - magic aura
  - Metal particle system
  - impact explosion
  - spell composition
  - procedural lightning
  - ray marching fog
  - GPU compute particles
  - Vortex preset
  - game visual effects

VFX Spell Effects — Game-Quality Visual Effects for Apple Platforms

Decision Tree

code
What effect do you want?
|
|-- Smoke / Fog / Clouds?
|   |-- Soft procedural blobs? -> Canvas noise blobs (like OCMiniOrb smoke)
|   |-- Volumetric 3D fog? -> Ray marching (Metal fragment shader)
|   |-- Quick particle smoke? -> SpriteKit SKEmitterNode or Vortex
|   \-- Fluid dynamics? -> Metal compute (Navier-Stokes, advanced)
|   -> See: references/smoke-fog.md
|
|-- Lightning / Electricity?
|   |-- Single bolt? -> Midpoint displacement (most practical)
|   |-- Smooth arc? -> Lissajous curves
|   |-- Branching tree? -> Recursive fractal (Lichtenberg figures)
|   \-- Glow on bolt? -> Additive bloom post-process
|   -> See: references/lightning-electricity.md
|
|-- Particles (fire, sparks, magic)?
|   |-- Quick preset? -> Vortex (SwiftUI-native)
|   |-- 2D overlay? -> CAEmitterLayer or SpriteKit
|   |-- Full GPU control? -> Metal compute shader pipeline
|   |-- SwiftUI-only? -> Canvas + TimelineView
|   -> See: references/particles.md
|
|-- Bloom / Glow / Post-processing?
|   |-- SwiftUI quick glow? -> .shadow() + .blur() stacking
|   |-- HDR bloom pipeline? -> Threshold -> Gaussian blur -> Composite (Metal)
|   |-- Per-object glow? -> Render to texture + blur + additive blend
|   -> See: references/bloom-glow.md
|
|-- Composing a full spell?
|   |-- State machine? -> .idle -> .charging -> .casting -> .impact -> .dissipating
|   |-- Layer ordering? -> base + particles + glow + screen shake + audio
|   |-- Audio-reactive? -> Bind intensity to RMS amplitude
|   -> See: references/spell-composition.md
|
\-- Performance issue?
    |-- Dropped frames? -> Check particle count, blur radius, draw calls
    |-- GPU bottleneck? -> Profile with Xcode GPU debugger
    |-- CPU bottleneck? -> Move particle update to compute shader
    -> See: Performance Budget Rules below

Quick Reference

EffectBest APIApproachRef
Soft smoke blobsSwiftUI CanvasNoise-offset circles + alpha blendreferences/smoke-fog.md
Volumetric fogMetal fragmentRay march density field, 4-8 samplesreferences/smoke-fog.md
Lightning boltSwiftUI Canvas / MetalMidpoint displacement, 4-5 levelsreferences/lightning-electricity.md
Branching lightningCanvas + recursionFractal tree, angle +/-30degreferences/lightning-electricity.md
Fire particlesVortex / SpriteKitPre-built emitter, warm palettereferences/particles.md
Magic sparksMetal computeGPU particle pool, 500-2000 particlesreferences/particles.md
Impact explosionVortex + CanvasBurst emit + radial force + fadereferences/particles.md
Object glowSwiftUI .shadowStacked .shadow(radius:) callsreferences/bloom-glow.md
HDR bloomMetal render passThreshold + separable Gaussian + compositereferences/bloom-glow.md
Full spellComposite patternState machine + layer stack + timelinereferences/spell-composition.md

Performance Budget Rules (NON-NEGOTIABLE)

  1. 16ms frame budget -- Target 60fps. All VFX layers combined must complete within 16ms GPU + CPU time.
  2. Particle limits -- Mobile: 500-2000 active particles max. Desktop: up to 10,000 with compute shader. Never allocate mid-frame.
  3. Blur radius cap -- .blur(radius:) over 20pt on mobile tanks performance. Use downscaled render targets for large blurs.
  4. Draw call budget -- Keep under 10 draw calls for VFX overlay. Use Canvas (1 draw call per layer) or instanced rendering.
  5. Compute shader particles -- Mandatory for >500 particles. CPU-side for loops over particle arrays cause frame drops on mobile.
  6. Ray march samples -- 4-8 samples per ray for real-time fog. More than 12 is offline-quality territory.
  7. Bloom passes -- 3-5 blur passes with ping-pong buffers. Downscale to half/quarter resolution for blur.
  8. Pool, never allocate -- Pre-allocate particle arrays. Use recycle-bin pattern (free list). Zero heap allocation during gameplay.
  9. Reduce motion -- @Environment(\.accessibilityReduceMotion) guards ALL effect starts. Provide static fallback.
  10. Profile on device -- Simulator GPU timing is meaningless. Test on oldest supported hardware.

Key Patterns

State Machine for Spell Lifecycle

swift
enum SpellPhase: String, CaseIterable {
    case idle, charging, casting, impact, dissipating
}

@Observable
class SpellState {
    var phase: SpellPhase = .idle
    var intensity: Float = 0.0  // 0.0-1.0
    var elapsed: TimeInterval = 0.0

    func advance(dt: TimeInterval) {
        elapsed += dt
        switch phase {
        case .charging:   intensity = min(1.0, Float(elapsed / 0.5))
        case .casting:    intensity = 1.0
        case .impact:     intensity = max(0.0, 1.0 - Float(elapsed / 0.3))
        case .dissipating: intensity = max(0.0, 0.5 - Float(elapsed / 0.6))
        case .idle:       intensity = 0.0
        }
    }
}

Canvas-Based Effect Layer

swift
struct EffectLayer: View {
    let state: SpellState
    @Environment(\.accessibilityReduceMotion) private var reduceMotion

    var body: some View {
        if !reduceMotion && state.phase != .idle {
            TimelineView(.animation(minimumInterval: 1.0 / 60.0)) { ctx in
                Canvas { context, size in
                    // Draw effect here -- single draw call
                    let t = ctx.date.timeIntervalSinceReferenceDate
                    drawEffect(context: context, size: size, time: t, intensity: state.intensity)
                }
            }
        }
    }
}

Midpoint Displacement Lightning (Minimal)

swift
func generateBolt(from: CGPoint, to: CGPoint, levels: Int = 5, jaggedness: CGFloat = 0.4) -> [CGPoint] {
    var points = [from, to]
    for level in 0..<levels {
        var newPoints = [points[0]]
        let scale = jaggedness * pow(0.5, CGFloat(level))
        for i in 0..<(points.count - 1) {
            let mid = CGPoint(
                x: (points[i].x + points[i+1].x) / 2 + CGFloat.random(in: -1...1) * scale * from.distance(to: to),
                y: (points[i].y + points[i+1].y) / 2 + CGFloat.random(in: -1...1) * scale * from.distance(to: to)
            )
            newPoints.append(mid)
            newPoints.append(points[i+1])
        }
        points = newPoints
    }
    return points
}

References

FileContent
references/smoke-fog.mdNoise-based smoke, ray marching fog, Canvas blobs, Metal fluid dynamics
references/lightning-electricity.mdFractal midpoint displacement, Lissajous arcs, branching trees, glow rendering
references/particles.mdAPI comparison, GPU particle architecture, emission patterns, pool pattern, Vortex presets
references/bloom-glow.mdHDR bloom pipeline, threshold/blur/composite, Metal + SwiftUI integration
references/spell-composition.mdState machine, layer stacking, audio-reactive binding, timing curves, full spell examples

External Resources

Related Skills

  • orb -- OCMiniOrb implementation (smoke layer, fractal layer, glow compositing)
  • swiftui-animation -- Animation curves, springs, Metal shader integration in SwiftUI
  • swiftui-performance-audit -- Runtime GPU/CPU profiling when effects cause frame drops

Technique Map

  • Effect type routing — Smoke/fog, lightning, particles, bloom, full spell; because each has distinct API and approach.
  • State machine for lifecycle — idle→charging→casting→impact→dissipating; because spells have phases; state drives intensity.
  • 16ms frame budget — 60fps non-negotiable; because dropped frames break immersion.
  • Particle limits — 500-2000 mobile; 10k desktop with compute; because CPU particle loops tank mobile.
  • Canvas for overlay — Single draw call per layer; because draw call budget matters.
  • Pool, never allocate — Recycle bin pattern; because mid-frame allocation causes hitches.
  • Reduce motion guard — Static fallback when accessibilityReduceMotion; because necessary for compliance.
  • Midpoint displacement — For lightning; 4-5 levels; because simple, effective, performant.

Technique Notes

References: smoke-fog, lightning-electricity, particles, bloom-glow, spell-composition. APIs: Vortex, SpriteKit, Metal compute, Canvas. Profile on device; simulator GPU timing meaningless. Related: orb, swiftui-animation, swiftui-performance-audit.


Prompt Architect Overlay

Role Definition: VFX spell effects builder. Game-quality smoke, lightning, particles, bloom, spell composition. 60fps performance rules. Apple platforms.

Input Contract: Accepts effect type (smoke, lightning, fire, glow, full spell), target API (Vortex, Metal, Canvas), or performance issue. Platform, particle count, style.

Output Contract: Decision tree result. Quick reference row. Code pattern (state machine, canvas layer, midpoint displacement). Performance budget rules. Reference to deep-dive. Related skills.

Edge Cases & Fallbacks: If performance issue→check particle count, blur radius, draw calls. If >500 particles→compute shader mandatory. If bloom→downscale for blur passes. If reduce motion→guard all effects; provide static fallback.