@nerdev/skillset 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +351 -0
- package/bin/skillset.mjs +205 -0
- package/curations/README.md +53 -0
- package/curations/TEMPLATE/WHY.md +23 -0
- package/curations/TEMPLATE/overlay/SKILL.md +6 -0
- package/curations/impeccable/WHY.md +34 -0
- package/curations/impeccable/overlay/SKILL.md +116 -0
- package/package.json +43 -0
- package/scripts/ste-gate.mjs +39 -0
- package/scripts/ste-lint.py +201 -0
- package/scripts/sync.mjs +174 -0
- package/skills/ai-agent/agent-docs-writer/SKILL.md +105 -0
- package/skills/ai-agent/agent-docs-writer/references/principles.md +73 -0
- package/skills/ai-agent/agent-docs-writer/templates/AGENTS.template.md +44 -0
- package/skills/ai-agent/agent-docs-writer/templates/README.template.md +19 -0
- package/skills/ai-agent/ultra-context-engine/SKILL.md +941 -0
- package/skills/architecture/blueprint/SKILL.md +191 -0
- package/skills/architecture/code-tour/SKILL.md +204 -0
- package/skills/architecture/progress-guard/SKILL.md +148 -0
- package/skills/architecture/search-first/SKILL.md +97 -0
- package/skills/backend/api-design/SKILL.md +456 -0
- package/skills/backend/auth/SKILL.md +596 -0
- package/skills/backend/database/SKILL.md +431 -0
- package/skills/backend/realtime/SKILL.md +670 -0
- package/skills/backend/security/SKILL.md +590 -0
- package/skills/business/brag/SKILL.md +177 -0
- package/skills/business/brag/assets/music/README.md +20 -0
- package/skills/business/brag/assets/music/cues/happy-beats-business-moves-vol-1-by-ende-dot-app.music-cues.json +3846 -0
- package/skills/business/brag/assets/music/cues/happy-beats-business-moves-vol-1-by-ende-dot-app.music-cues.md +35 -0
- package/skills/business/brag/assets/music/cues/happy-beats-business-moves-vol-10-by-ende-dot-app.music-cues.json +1826 -0
- package/skills/business/brag/assets/music/cues/happy-beats-business-moves-vol-10-by-ende-dot-app.music-cues.md +35 -0
- package/skills/business/brag/assets/music/cues/happy-beats-business-moves-vol-11-by-ende-dot-app.music-cues.json +2266 -0
- package/skills/business/brag/assets/music/cues/happy-beats-business-moves-vol-11-by-ende-dot-app.music-cues.md +35 -0
- package/skills/business/brag/assets/music/cues/happy-beats-business-moves-vol-12-by-ende-dot-app.music-cues.json +2806 -0
- package/skills/business/brag/assets/music/cues/happy-beats-business-moves-vol-12-by-ende-dot-app.music-cues.md +35 -0
- package/skills/business/brag/assets/music/cues/happy-beats-business-moves-vol-9-by-ende-dot-app.music-cues.json +2796 -0
- package/skills/business/brag/assets/music/cues/happy-beats-business-moves-vol-9-by-ende-dot-app.music-cues.md +35 -0
- package/skills/business/brag/assets/music/happy-beats-business-moves-vol-1-by-ende-dot-app.mp3 +0 -0
- package/skills/business/brag/assets/music/happy-beats-business-moves-vol-10-by-ende-dot-app.mp3 +0 -0
- package/skills/business/brag/assets/music/happy-beats-business-moves-vol-11-by-ende-dot-app.mp3 +0 -0
- package/skills/business/brag/assets/music/happy-beats-business-moves-vol-12-by-ende-dot-app.mp3 +0 -0
- package/skills/business/brag/assets/music/happy-beats-business-moves-vol-9-by-ende-dot-app.mp3 +0 -0
- package/skills/business/brag/assets/sfx/casino/card-fan-1.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/card-fan-2.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/card-place-1.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/card-place-2.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/card-place-3.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/card-place-4.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/card-shove-1.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/card-shove-2.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/card-shove-3.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/card-shove-4.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/card-shuffle.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/card-slide-1.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/card-slide-2.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/card-slide-3.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/card-slide-4.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/card-slide-5.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/card-slide-6.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/card-slide-7.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/card-slide-8.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/cards-pack-open-1.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/cards-pack-open-2.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/chip-lay-1.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/chip-lay-2.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/chip-lay-3.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/chips-collide-1.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/chips-collide-2.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/chips-collide-3.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/chips-collide-4.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/chips-handle-1.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/chips-handle-2.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/chips-handle-3.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/chips-handle-4.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/chips-handle-6.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/chips-stack-1.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/chips-stack-2.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/chips-stack-3.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/chips-stack-4.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/chips-stack-5.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/chips-stack-6.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/dice-grab-1.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/dice-grab-2.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/dice-shake-1.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/dice-shake-2.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/dice-shake-3.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/dice-throw-1.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/dice-throw-2.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/dice-throw-3.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/die-throw-1.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/die-throw-2.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/die-throw-3.ogg +0 -0
- package/skills/business/brag/assets/sfx/casino/die-throw-4.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/footstep_carpet_000.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/footstep_carpet_003.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/footstep_carpet_004.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/footstep_concrete_000.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/footstep_concrete_001.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/footstep_concrete_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/footstep_concrete_003.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/footstep_concrete_004.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/footstep_grass_000.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/footstep_grass_001.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/footstep_grass_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/footstep_grass_003.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/footstep_grass_004.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/footstep_snow_000.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/footstep_snow_001.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/footstep_snow_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/footstep_snow_003.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/footstep_snow_004.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/footstep_wood_000.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/footstep_wood_001.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/footstep_wood_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/footstep_wood_003.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/footstep_wood_004.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactBell_heavy_000.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactBell_heavy_003.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactBell_heavy_004.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactGeneric_light_000.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactGeneric_light_001.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactGeneric_light_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactGeneric_light_003.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactGeneric_light_004.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactGlass_heavy_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactGlass_light_001.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactGlass_light_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactGlass_light_003.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactGlass_medium_000.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactGlass_medium_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactGlass_medium_004.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactMetal_heavy_000.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactMetal_heavy_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactMetal_heavy_004.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactMetal_light_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactMetal_light_003.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactMetal_medium_000.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactMetal_medium_001.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactMetal_medium_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactMetal_medium_003.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactMetal_medium_004.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactMining_001.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPlank_medium_000.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPlank_medium_001.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPlank_medium_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPlank_medium_003.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPlank_medium_004.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPlate_heavy_000.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPlate_heavy_001.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPlate_heavy_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPlate_heavy_003.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPlate_heavy_004.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPlate_light_000.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPlate_light_001.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPlate_light_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPlate_light_003.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPlate_light_004.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPlate_medium_000.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPlate_medium_001.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPlate_medium_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPlate_medium_003.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPlate_medium_004.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPunch_heavy_000.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPunch_heavy_001.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPunch_heavy_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPunch_heavy_003.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPunch_heavy_004.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPunch_medium_000.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPunch_medium_001.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPunch_medium_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPunch_medium_003.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactPunch_medium_004.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactSoft_heavy_000.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactSoft_heavy_001.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactSoft_heavy_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactSoft_heavy_003.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactSoft_heavy_004.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactSoft_medium_000.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactSoft_medium_001.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactSoft_medium_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactSoft_medium_003.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactSoft_medium_004.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactTin_medium_000.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactTin_medium_001.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactTin_medium_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactTin_medium_003.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactTin_medium_004.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactWood_heavy_000.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactWood_heavy_001.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactWood_heavy_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactWood_heavy_003.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactWood_heavy_004.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactWood_light_000.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactWood_light_001.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactWood_light_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactWood_light_003.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactWood_light_004.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactWood_medium_000.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactWood_medium_001.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactWood_medium_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactWood_medium_003.ogg +0 -0
- package/skills/business/brag/assets/sfx/impact/impactWood_medium_004.ogg +0 -0
- package/skills/business/brag/assets/sfx/interface/bong_001.ogg +0 -0
- package/skills/business/brag/assets/sfx/interface/click_001.ogg +0 -0
- package/skills/business/brag/assets/sfx/interface/click_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/interface/click_003.ogg +0 -0
- package/skills/business/brag/assets/sfx/interface/click_004.ogg +0 -0
- package/skills/business/brag/assets/sfx/interface/click_005.ogg +0 -0
- package/skills/business/brag/assets/sfx/interface/drop_001.ogg +0 -0
- package/skills/business/brag/assets/sfx/interface/drop_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/interface/drop_003.ogg +0 -0
- package/skills/business/brag/assets/sfx/interface/error_005.ogg +0 -0
- package/skills/business/brag/assets/sfx/interface/error_006.ogg +0 -0
- package/skills/business/brag/assets/sfx/interface/glitch_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/interface/glitch_004.ogg +0 -0
- package/skills/business/brag/assets/sfx/interface/select_008.ogg +0 -0
- package/skills/business/brag/assets/sfx/interface/switch_001.ogg +0 -0
- package/skills/business/brag/assets/sfx/interface/switch_002.ogg +0 -0
- package/skills/business/brag/assets/sfx/interface/switch_004.ogg +0 -0
- package/skills/business/brag/assets/sfx/interface/switch_005.ogg +0 -0
- package/skills/business/brag/assets/sfx/interface/switch_006.ogg +0 -0
- package/skills/business/brag/assets/sfx/interface/switch_007.ogg +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-001.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-002.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-003.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-004.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-005.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-006.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-007.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-008.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-009.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-010.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-011.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-012.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-013.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-014.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-015.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-016.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-017.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-018.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-019.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-020.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-021.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-022.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-023.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-024.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-025.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-026.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-027.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-028.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-029.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-030.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-031.wav +0 -0
- package/skills/business/brag/assets/sfx/keyboard/keypress-032.wav +0 -0
- package/skills/business/brag/assets/sfx/sfx-analysis.json +15584 -0
- package/skills/business/brag/assets/sfx/sfx-analysis.md +75 -0
- package/skills/business/brag/assets/sfx/ui/click1.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/click2.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/click3.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/click4.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/click5.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/mouseclick1.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/rollover1.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/rollover2.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/rollover4.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/rollover5.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch1.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch10.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch11.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch12.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch13.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch14.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch15.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch16.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch17.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch18.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch19.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch2.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch20.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch21.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch22.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch23.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch24.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch25.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch26.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch27.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch28.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch29.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch3.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch30.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch31.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch32.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch33.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch34.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch35.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch36.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch37.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch38.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch4.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch5.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch6.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch7.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch8.ogg +0 -0
- package/skills/business/brag/assets/sfx/ui/switch9.ogg +0 -0
- package/skills/business/brag/references/audio.md +307 -0
- package/skills/business/brag/references/step-1-inspect.md +133 -0
- package/skills/business/brag/references/step-2-plan.md +234 -0
- package/skills/business/brag/references/step-3-compose.md +210 -0
- package/skills/business/brag/references/step-4-deliver.md +168 -0
- package/skills/business/brag/references/tones.md +231 -0
- package/skills/business/brag/scripts/analyze_music_cues.py +309 -0
- package/skills/business/brag/scripts/pyproject.toml +14 -0
- package/skills/business/brag/scripts/uv.lock +819 -0
- package/skills/business/copywriting/SKILL.md +178 -0
- package/skills/business/customer-research/SKILL.md +259 -0
- package/skills/business/freelancing/SKILL.md +679 -0
- package/skills/business/launch/SKILL.md +273 -0
- package/skills/business/marketing-psychology/SKILL.md +364 -0
- package/skills/business/pricing/SKILL.md +233 -0
- package/skills/business/resume-revamp-jake-ats/SKILL.md +64 -0
- package/skills/business/startup-founder/SKILL.md +400 -0
- package/skills/business/startup-founder/references/funding.md +48 -0
- package/skills/business/startup-founder/references/further-reading.md +132 -0
- package/skills/business/startup-founder/references/gtm-tools.md +57 -0
- package/skills/business/startup-founder/references/legal-india.md +36 -0
- package/skills/business/startup-founder/references/marketing/README.md +16 -0
- package/skills/business/startup-founder/references/marketing/cold-email.md +172 -0
- package/skills/business/startup-founder/references/marketing/competitors.md +245 -0
- package/skills/business/startup-founder/references/marketing/customer-research.md +276 -0
- package/skills/business/startup-founder/references/marketing/free-tools.md +168 -0
- package/skills/business/startup-founder/references/marketing/launch.md +343 -0
- package/skills/business/startup-founder/references/marketing/marketing-plan.md +270 -0
- package/skills/business/startup-founder/references/marketing/pricing.md +237 -0
- package/skills/business/startup-founder/references/marketing/product-marketing.md +250 -0
- package/skills/business/startup-founder/references/validation.md +267 -0
- package/skills/devops/deployments/SKILL.md +339 -0
- package/skills/devops/git-ci/SKILL.md +372 -0
- package/skills/devops/performance/SKILL.md +523 -0
- package/skills/devops/testing/SKILL.md +558 -0
- package/skills/engineering/code-review/SKILL.md +149 -0
- package/skills/engineering/coding-standards/SKILL.md +229 -0
- package/skills/engineering/product-engineering/SKILL.md +219 -0
- package/skills/engineering/senior-engineer-prompts/SKILL.md +145 -0
- package/skills/engineering/tdd-workflow/SKILL.md +178 -0
- package/skills/engineering/verification-loop/SKILL.md +199 -0
- package/skills/nerdev/nerdev-abstraction/SKILL.md +412 -0
- package/skills/nerdev/nerdev-docs/SKILL.md +527 -0
- package/skills/nerdev/nerdev-docs/templates/adr-template.md +39 -0
- package/skills/nerdev/nerdev-docs/templates/contributing-template.md +140 -0
- package/skills/nerdev/nerdev-docs/templates/deploy-template.md +426 -0
- package/skills/nerdev/nerdev-docs/templates/design-template.md +105 -0
- package/skills/nerdev/nerdev-docs/templates/incident-template.md +66 -0
- package/skills/nerdev/nerdev-monorepo/SKILL.md +522 -0
- package/skills/quality/output-skill/SKILL.md +49 -0
- package/skills/quality/unslop/SKILL.md +67 -0
- package/skills/ui/animaxxing/SKILL.md +58 -0
- package/skills/ui/animaxxing/agents/openai.yaml +7 -0
- package/skills/ui/animaxxing/references/effect-restoration.md +26 -0
- package/skills/ui/animaxxing/references/motion-vocabulary.md +142 -0
- package/skills/ui/animaxxing/references/recipes/blast-off.md +119 -0
- package/skills/ui/animaxxing/references/recipes/particle-effects.md +718 -0
- package/skills/ui/animaxxing/references/recipes/particle-field.md +428 -0
- package/skills/ui/animaxxing/references/recipes/route-letters.md +205 -0
- package/skills/ui/animaxxing/references/recipes/speak-in.md +181 -0
- package/skills/ui/animaxxing/references/recipes/split-entrances.md +345 -0
- package/skills/ui/animaxxing/references/recipes/wave.md +144 -0
- package/skills/ui/animaxxing/references/text-stability.md +68 -0
- package/skills/ui/animaxxing/references/verification.md +44 -0
- package/skills/ui/ask-animation/SKILL.md +178 -0
- package/skills/ui/ask-base-ui/SKILL.md +400 -0
- package/skills/ui/ask-cmdk/SKILL.md +315 -0
- package/skills/ui/ask-command-menu/SKILL.md +262 -0
- package/skills/ui/ask-drawer/SKILL.md +235 -0
- package/skills/ui/ask-form/SKILL.md +229 -0
- package/skills/ui/ask-gsap/SKILL.md +435 -0
- package/skills/ui/ask-modal/SKILL.md +145 -0
- package/skills/ui/ask-motion/SKILL.md +339 -0
- package/skills/ui/ask-rhf/SKILL.md +388 -0
- package/skills/ui/ask-sonner/API.md +64 -0
- package/skills/ui/ask-sonner/SKILL.md +88 -0
- package/skills/ui/ask-table/SKILL.md +253 -0
- package/skills/ui/ask-tanstack-table/SKILL.md +490 -0
- package/skills/ui/ask-toast/SKILL.md +163 -0
- package/skills/ui/ask-vaul/SKILL.md +291 -0
- package/skills/ui/ask-virtual-list/SKILL.md +304 -0
- package/skills/ui/ask-virtuoso/SKILL.md +332 -0
- package/skills/ui/email-craft/SKILL.md +258 -0
- package/skills/ui/frontend-craftsmanship/SKILL.md +462 -0
- package/skills/ui/gsap-astro/SKILL.md +56 -0
- package/skills/ui/gsap-astro/agents/openai.yaml +7 -0
- package/skills/ui/gsap-astro/references/client-router-navigation.md +139 -0
- package/skills/ui/gsap-astro/references/initialization.md +87 -0
- package/skills/ui/gsap-astro/references/motion-system.md +152 -0
- package/skills/ui/gsap-astro/references/scripts-and-islands.md +65 -0
- package/skills/ui/gsap-astro/references/verification.md +44 -0
- package/skills/ui/gsap-core/SKILL.md +254 -0
- package/skills/ui/gsap-frameworks/SKILL.md +266 -0
- package/skills/ui/gsap-nextjs/SKILL.md +51 -0
- package/skills/ui/gsap-nextjs/agents/openai.yaml +7 -0
- package/skills/ui/gsap-nextjs/references/app-router-navigation.md +189 -0
- package/skills/ui/gsap-nextjs/references/initialization.md +87 -0
- package/skills/ui/gsap-nextjs/references/motion-system.md +158 -0
- package/skills/ui/gsap-nextjs/references/verification.md +40 -0
- package/skills/ui/gsap-nuxt/SKILL.md +56 -0
- package/skills/ui/gsap-nuxt/agents/openai.yaml +7 -0
- package/skills/ui/gsap-nuxt/references/initialization.md +87 -0
- package/skills/ui/gsap-nuxt/references/motion-system.md +161 -0
- package/skills/ui/gsap-nuxt/references/navigation.md +145 -0
- package/skills/ui/gsap-nuxt/references/page-transitions.md +107 -0
- package/skills/ui/gsap-nuxt/references/verification.md +42 -0
- package/skills/ui/gsap-performance/SKILL.md +79 -0
- package/skills/ui/gsap-plugins/SKILL.md +433 -0
- package/skills/ui/gsap-react/SKILL.md +136 -0
- package/skills/ui/gsap-react-router/SKILL.md +55 -0
- package/skills/ui/gsap-react-router/agents/openai.yaml +7 -0
- package/skills/ui/gsap-react-router/references/initialization.md +87 -0
- package/skills/ui/gsap-react-router/references/motion-system.md +158 -0
- package/skills/ui/gsap-react-router/references/react-router-navigation.md +165 -0
- package/skills/ui/gsap-react-router/references/route-lifetime.md +74 -0
- package/skills/ui/gsap-react-router/references/verification.md +42 -0
- package/skills/ui/gsap-scrolltrigger/SKILL.md +296 -0
- package/skills/ui/gsap-sveltekit/SKILL.md +54 -0
- package/skills/ui/gsap-sveltekit/agents/openai.yaml +7 -0
- package/skills/ui/gsap-sveltekit/references/initialization.md +87 -0
- package/skills/ui/gsap-sveltekit/references/motion-system.md +156 -0
- package/skills/ui/gsap-sveltekit/references/page-lifetime.md +63 -0
- package/skills/ui/gsap-sveltekit/references/sveltekit-navigation.md +160 -0
- package/skills/ui/gsap-sveltekit/references/verification.md +41 -0
- package/skills/ui/gsap-tanstack-router/SKILL.md +56 -0
- package/skills/ui/gsap-tanstack-router/agents/openai.yaml +7 -0
- package/skills/ui/gsap-tanstack-router/references/initialization.md +87 -0
- package/skills/ui/gsap-tanstack-router/references/motion-system.md +160 -0
- package/skills/ui/gsap-tanstack-router/references/route-lifetime.md +66 -0
- package/skills/ui/gsap-tanstack-router/references/tanstack-navigation.md +156 -0
- package/skills/ui/gsap-tanstack-router/references/verification.md +41 -0
- package/skills/ui/gsap-timeline/SKILL.md +107 -0
- package/skills/ui/gsap-utils/SKILL.md +284 -0
- package/skills/ui/gsap-vanilla/SKILL.md +63 -0
- package/skills/ui/gsap-vanilla/agents/openai.yaml +7 -0
- package/skills/ui/gsap-vanilla/references/cross-document-navigation.md +54 -0
- package/skills/ui/gsap-vanilla/references/initialization.md +87 -0
- package/skills/ui/gsap-vanilla/references/motion-system.md +150 -0
- package/skills/ui/gsap-vanilla/references/page-load.md +96 -0
- package/skills/ui/gsap-vanilla/references/spa-navigation.md +70 -0
- package/skills/ui/gsap-vanilla/references/verification.md +41 -0
- package/skills/ui/house-style/SKILL.md +366 -0
- package/skills/ui/imagegen/SKILL.md +49 -0
- package/skills/ui/imagegen/references/brandkit.md +48 -0
- package/skills/ui/imagegen/references/image-to-code.md +56 -0
- package/skills/ui/imagegen/references/mobile.md +58 -0
- package/skills/ui/imagegen/references/web.md +63 -0
- package/skills/ui/impeccable/SKILL.md +116 -0
- package/skills/ui/impeccable/reference/adapt.md +318 -0
- package/skills/ui/impeccable/reference/adapt.native.md +58 -0
- package/skills/ui/impeccable/reference/android.md +46 -0
- package/skills/ui/impeccable/reference/animate.md +89 -0
- package/skills/ui/impeccable/reference/audit.md +137 -0
- package/skills/ui/impeccable/reference/audit.native.md +139 -0
- package/skills/ui/impeccable/reference/bolder.md +33 -0
- package/skills/ui/impeccable/reference/clarify.md +94 -0
- package/skills/ui/impeccable/reference/colorize.md +86 -0
- package/skills/ui/impeccable/reference/craft-floor.md +44 -0
- package/skills/ui/impeccable/reference/craft.md +5 -0
- package/skills/ui/impeccable/reference/critique.md +806 -0
- package/skills/ui/impeccable/reference/degraded/asset-producer.md +37 -0
- package/skills/ui/impeccable/reference/degraded/documenter.md +24 -0
- package/skills/ui/impeccable/reference/degraded/finish-reviewer.md +38 -0
- package/skills/ui/impeccable/reference/degraded/manual-edit-applier.md +92 -0
- package/skills/ui/impeccable/reference/delight.md +70 -0
- package/skills/ui/impeccable/reference/distill.md +111 -0
- package/skills/ui/impeccable/reference/doctor.md +54 -0
- package/skills/ui/impeccable/reference/document.md +416 -0
- package/skills/ui/impeccable/reference/extract.md +69 -0
- package/skills/ui/impeccable/reference/generate.md +101 -0
- package/skills/ui/impeccable/reference/harden.md +345 -0
- package/skills/ui/impeccable/reference/hooks.md +111 -0
- package/skills/ui/impeccable/reference/init.md +131 -0
- package/skills/ui/impeccable/reference/ios.md +51 -0
- package/skills/ui/impeccable/reference/layout.md +84 -0
- package/skills/ui/impeccable/reference/live-setup.md +104 -0
- package/skills/ui/impeccable/reference/live.md +325 -0
- package/skills/ui/impeccable/reference/new-work.md +145 -0
- package/skills/ui/impeccable/reference/onboard.md +234 -0
- package/skills/ui/impeccable/reference/operate.md +61 -0
- package/skills/ui/impeccable/reference/optimize.md +258 -0
- package/skills/ui/impeccable/reference/overdrive.md +127 -0
- package/skills/ui/impeccable/reference/polish.md +105 -0
- package/skills/ui/impeccable/reference/quieter.md +99 -0
- package/skills/ui/impeccable/reference/routing.md +24 -0
- package/skills/ui/impeccable/reference/shape.md +59 -0
- package/skills/ui/impeccable/reference/typeset.md +80 -0
- package/skills/ui/impeccable/reference/visualize.md +46 -0
- package/skills/ui/impeccable/scripts/VERSION +1 -0
- package/skills/ui/impeccable/scripts/command-metadata.json +98 -0
- package/skills/ui/impeccable/scripts/data/font-index-failures.json +121 -0
- package/skills/ui/impeccable/scripts/data/font-index.json +1 -0
- package/skills/ui/impeccable/scripts/impeccable +206 -0
- package/skills/ui/impeccable/scripts/impeccable.cmd +214 -0
- package/skills/ui/impeccable/scripts/live-browser-dom.js +167 -0
- package/skills/ui/impeccable/scripts/live-browser-ignores.js +242 -0
- package/skills/ui/impeccable/scripts/live-browser-session.js +144 -0
- package/skills/ui/impeccable/scripts/live-browser.js +13510 -0
- package/skills/ui/impeccable/scripts/modern-screenshot.umd.js +14 -0
- package/skills/ui/motion/SKILL.md +207 -0
- package/skills/ui/pick-ui-library/SKILL.md +85 -0
- package/skills/ui/product-messaging/SKILL.md +163 -0
- package/skills/ui/product-site/SKILL.md +465 -0
- package/skills/ui/prototype/PICKER.md +197 -0
- package/skills/ui/prototype/SKILL.md +98 -0
- package/skills/ui/refero-design/SKILL.md +534 -0
- package/skills/ui/refero-design/agents/openai.yaml +4 -0
- package/skills/ui/refero-design/references/anti-ai-slop.md +292 -0
- package/skills/ui/refero-design/references/color.md +563 -0
- package/skills/ui/refero-design/references/copywriting.md +222 -0
- package/skills/ui/refero-design/references/craft-details.md +525 -0
- package/skills/ui/refero-design/references/example-workflow.md +264 -0
- package/skills/ui/refero-design/references/icons.md +166 -0
- package/skills/ui/refero-design/references/mcp-tools.md +258 -0
- package/skills/ui/refero-design/references/motion.md +504 -0
- package/skills/ui/refero-design/references/typography.md +737 -0
- package/skills/ui/refero-design/references/visual-workflow.md +105 -0
- package/skills/ui/style-animaxxing/SKILL.md +48 -0
- package/skills/ui/style-animaxxing/agents/openai.yaml +7 -0
- package/skills/ui/style-animaxxing/references/motion-vocabulary.md +51 -0
- package/skills/ui/style-animaxxing/references/tokens.md +288 -0
- package/skills/ui/style-animaxxing/references/typography-and-layout.md +149 -0
- package/skills/ui/style-animaxxing/references/verification.md +38 -0
- package/skills/ui/typography-picker/SKILL.md +305 -0
- package/skills/ui/ui-core/SKILL.md +345 -0
- package/skills/ui/ui-core/references/accessibility.md +85 -0
- package/skills/ui/ui-core/references/build.md +666 -0
- package/skills/ui/ui-core/references/copy.md +70 -0
- package/skills/ui/ui-core/references/dark-mode.md +76 -0
- package/skills/ui/ui-core/references/direction.md +99 -0
- package/skills/ui/ui-core/references/redesign.md +74 -0
- package/skills/ui/ui-core/references/responsive.md +77 -0
- package/skills/ui/ui-core/references/styles.md +42 -0
- package/skills/ui/ui-core/references/system.md +190 -0
- package/skills/ui/ui-core/references/verify.md +37 -0
- package/skills/ui/ui-engineering/SKILL.md +436 -0
- package/skills/ui/ui-engineering/references/avatars.md +74 -0
- package/skills/ui/ui-engineering/references/card-patterns.md +66 -0
- package/skills/ui/ui-engineering/references/floating-actions.md +65 -0
- package/skills/ui/ui-engineering/references/navigation.md +81 -0
- package/skills/ui/ui-engineering/references/overlays.md +74 -0
- package/skills/ui/ui-engineering/references/pagination.md +71 -0
- package/skills/ui/ui-engineering/references/progress-indicators.md +77 -0
- package/skills/ui/ui-engineering/references/quality-bar.md +293 -0
- package/skills/ui/ui-engineering/references/search.md +68 -0
- package/skills/ui/ui-engineering/references/tailwind-architecture.md +81 -0
- package/skills/ui/ui-theme-picker/SKILL.md +522 -0
- package/skills/ui/ui-theme-picker/references/component-sources.md +223 -0
- package/skills/ui/ui-theme-picker/references/styles.md +298 -0
- package/skills/ui/vitepress-docs/SKILL.md +439 -0
- package/skills/ui/vitepress-docs/references/components.md +333 -0
- package/skills/ui/vitepress-docs/references/layout.md +128 -0
- package/skills/ui/vitepress-docs/references/tokens.md +87 -0
- package/skills/ui/vitepress-docs/references/typography.md +76 -0
- package/skills/workflow/careful/SKILL.md +48 -0
- package/skills/workflow/context-restore/SKILL.md +69 -0
- package/skills/workflow/context-save/SKILL.md +96 -0
- package/skills/workflow/health/SKILL.md +99 -0
- package/skills/workflow/learn/SKILL.md +95 -0
- package/skills/workflow/office-hours/SKILL.md +136 -0
- package/skills/workflow/ship/SKILL.md +95 -0
- package/vendor.json +80 -0
|
@@ -0,0 +1,718 @@
|
|
|
1
|
+
# Recipe: particle effects
|
|
2
|
+
|
|
3
|
+
Failure contract: apply [effect restoration](../effect-restoration.md) when adapting this module. The framework controller chooses recovery timing; this effect must undo even partial setup.
|
|
4
|
+
|
|
5
|
+
Five treatments on the [particle field](particle-field.md). Each defines how its element assembles on entrance, what plays while it idles, what happens under the pointer, and what a blast looks like. The framework skill's controller runs the phases through `attachParticleEffect`; these modules never decide when.
|
|
6
|
+
|
|
7
|
+
| Effect | Element | Layer | Bleed | Idle |
|
|
8
|
+
|---|---|---|---|---|
|
|
9
|
+
| `marquee` | secondary call to action (outline) | over | 160 | six lights chase the outline; glints |
|
|
10
|
+
| `reactor` | primary call to action (solid) | under | 180 | embers rise from the button; a slow heartbeat outline |
|
|
11
|
+
| `resolve` | card | over | 140 | one light wanders the outline; glints |
|
|
12
|
+
| `slipstream` | an onward link (Next →) | over | 160 | hairlines drift past left to right |
|
|
13
|
+
| `ignite` | text on a rule: a command, a giant field | over | 200 | embers and glints off the underline |
|
|
14
|
+
|
|
15
|
+
Dependencies: `gsap`, `./field`.
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import gsap from "gsap";
|
|
19
|
+
import { perimeterLength, perimeterPoint, type ParticleField } from "./field";
|
|
20
|
+
import type { ParticleEffectDefinition, ParticleEffectInstance } from "./attach";
|
|
21
|
+
|
|
22
|
+
const rnd = gsap.utils.random;
|
|
23
|
+
export type ButtonEffect = ParticleEffectDefinition<ParticleEffectInstance> & { layer: "under" | "over" };
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## marquee
|
|
27
|
+
|
|
28
|
+
Lights gather from all around and land evenly along the outline, the button pops in, the sign ignites with a burst, and the runners set off.
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
const RUNNERS = 6;
|
|
32
|
+
/** Runner speed along the outline, px/s. */
|
|
33
|
+
const RUNNER_SPEED = 110;
|
|
34
|
+
/** How much faster the runners go under the pointer. */
|
|
35
|
+
const RUNNER_RUSH = 4;
|
|
36
|
+
|
|
37
|
+
export const marquee: ButtonEffect = {
|
|
38
|
+
layer: "over",
|
|
39
|
+
bleed: 160,
|
|
40
|
+
create(field, button) {
|
|
41
|
+
const runners: { t: number }[] = [];
|
|
42
|
+
const state = { rush: 1, hovering: false };
|
|
43
|
+
let twinkleIn = 0.4;
|
|
44
|
+
let sprayAcc = 0;
|
|
45
|
+
|
|
46
|
+
const ambient = (dt: number) => {
|
|
47
|
+
const { box, radius } = field;
|
|
48
|
+
const total = perimeterLength(box, radius);
|
|
49
|
+
for (const run of runners) {
|
|
50
|
+
run.t = (run.t + (RUNNER_SPEED * state.rush * dt) / total) % 1;
|
|
51
|
+
const pt = perimeterPoint(box, radius, run.t);
|
|
52
|
+
// The head is bright; each frame leaves a dot that fades, so the faster the runner the longer its tail.
|
|
53
|
+
field.spawn({ x: pt.x, y: pt.y, size: 2.8, alpha: 1, life: 0.4 * (0.6 + state.rush / RUNNER_RUSH), shrink: true });
|
|
54
|
+
}
|
|
55
|
+
if (state.hovering) {
|
|
56
|
+
// Sparkler: fine sparks fly off the outline while the pointer is on it.
|
|
57
|
+
sprayAcc += 90 * dt;
|
|
58
|
+
while (sprayAcc >= 1) {
|
|
59
|
+
sprayAcc -= 1;
|
|
60
|
+
const pt = perimeterPoint(box, radius, Math.random());
|
|
61
|
+
const speed = rnd(60, 180);
|
|
62
|
+
const jitter = rnd(-0.6, 0.6);
|
|
63
|
+
field.spawn({
|
|
64
|
+
x: pt.x, y: pt.y,
|
|
65
|
+
vx: (pt.nx + jitter * pt.ny) * speed, vy: (pt.ny - jitter * pt.nx) * speed,
|
|
66
|
+
size: rnd(0.8, 1.6), alpha: rnd(0.6, 1), life: rnd(0.3, 0.7), drag: 0.08, gravity: 60, shape: "spark",
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
twinkleIn -= dt;
|
|
71
|
+
if (twinkleIn <= 0) {
|
|
72
|
+
twinkleIn = rnd(0.25, 0.7) / (state.hovering ? 3 : 1);
|
|
73
|
+
twinkle(perimeterPoint(box, radius, Math.random()));
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
function twinkle(pt: { x: number; y: number }) {
|
|
78
|
+
const size = rnd(4, 9);
|
|
79
|
+
field.spawn({
|
|
80
|
+
x: pt.x, y: pt.y, size, shape: "star", rotation: rnd(0, Math.PI), spin: rnd(-1.5, 1.5), life: rnd(0.45, 0.8), fade: false,
|
|
81
|
+
update: (p) => { const k = Math.sin((p.age / p.life) * Math.PI); p.size = size * k; p.alpha = k; },
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function idle() {
|
|
86
|
+
runners.length = 0;
|
|
87
|
+
for (let k = 0; k < RUNNERS; k++) runners.push({ t: k / RUNNERS });
|
|
88
|
+
field.addEmitter(ambient);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function flash(count: number, speed: [number, number]) {
|
|
92
|
+
const { box, radius } = field;
|
|
93
|
+
for (let i = 0; i < count; i++) {
|
|
94
|
+
const pt = perimeterPoint(box, radius, i / count + rnd(-0.01, 0.01));
|
|
95
|
+
const v = rnd(speed[0], speed[1]);
|
|
96
|
+
field.spawn({ x: pt.x, y: pt.y, vx: pt.nx * v, vy: pt.ny * v, size: rnd(1, 2.2), life: rnd(0.35, 0.7), drag: 0.04, shape: "spark" });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
enter(delay) {
|
|
102
|
+
field.sync();
|
|
103
|
+
field.particles.length = 0;
|
|
104
|
+
runners.length = 0;
|
|
105
|
+
const { box, radius } = field;
|
|
106
|
+
const cx = box.x + box.w / 2;
|
|
107
|
+
const cy = box.y + box.h / 2;
|
|
108
|
+
const tl = gsap.timeline({ delay });
|
|
109
|
+
gsap.set(button, { autoAlpha: 0, scale: 0.5, transformOrigin: "50% 50%" });
|
|
110
|
+
|
|
111
|
+
const count = 72;
|
|
112
|
+
for (let i = 0; i < count; i++) {
|
|
113
|
+
const target = perimeterPoint(box, radius, i / count);
|
|
114
|
+
const angle = rnd(0, Math.PI * 2);
|
|
115
|
+
const dist = rnd(180, 340);
|
|
116
|
+
const p = field.spawn({ x: cx + Math.cos(angle) * dist, y: cy + Math.sin(angle) * dist, size: rnd(1.4, 2.8), alpha: 0, life: Infinity, fade: false });
|
|
117
|
+
tl.to(
|
|
118
|
+
p,
|
|
119
|
+
{
|
|
120
|
+
x: target.x, y: target.y, alpha: 1, duration: rnd(0.55, 0.85), ease: "power3.inOut",
|
|
121
|
+
onComplete: () => { p.life = 0.5; p.age = 0; p.fade = true; p.shrink = true; },
|
|
122
|
+
},
|
|
123
|
+
rnd(0, 0.25),
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
tl.to(button, { autoAlpha: 1, scale: 1, duration: 0.5, ease: "back.out(1.7)" }, 0.55);
|
|
127
|
+
tl.call(() => { flash(40, [80, 200]); idle(); }, [], 0.95);
|
|
128
|
+
return tl;
|
|
129
|
+
},
|
|
130
|
+
exit() { field.removeEmitter(ambient); runners.length = 0; field.release(0.25); },
|
|
131
|
+
blast() {
|
|
132
|
+
field.removeEmitter(ambient);
|
|
133
|
+
runners.length = 0;
|
|
134
|
+
flash(90, [350, 900]);
|
|
135
|
+
for (let i = 0; i < 12; i++) twinkle(perimeterPoint(field.box, field.radius, Math.random()));
|
|
136
|
+
},
|
|
137
|
+
idle,
|
|
138
|
+
hover(on) {
|
|
139
|
+
state.hovering = on;
|
|
140
|
+
gsap.to(state, { rush: on ? RUNNER_RUSH : 1, duration: on ? 0.35 : 0.8, ease: on ? "power3.out" : "power2.inOut", overwrite: true });
|
|
141
|
+
if (on) flash(36, [120, 260]);
|
|
142
|
+
},
|
|
143
|
+
destroy() { field.removeEmitter(ambient); gsap.killTweensOf(state); },
|
|
144
|
+
};
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## reactor
|
|
150
|
+
|
|
151
|
+
Sparks spiral in from a wide ring and collapse into the button; it pops in and the collapse rebounds outward as a shockwave. Idle, it breathes embers.
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
const EMBER_RATE = { idle: 9, hover: 70 };
|
|
155
|
+
const EMBER_RISE = { idle: 55, hover: 220 };
|
|
156
|
+
const PULSE_EVERY = 2.6;
|
|
157
|
+
|
|
158
|
+
export const reactor: ButtonEffect = {
|
|
159
|
+
layer: "under",
|
|
160
|
+
bleed: 180,
|
|
161
|
+
create(field, button) {
|
|
162
|
+
const state = { rate: EMBER_RATE.idle, rise: EMBER_RISE.idle, hovering: false };
|
|
163
|
+
let emberAcc = 0;
|
|
164
|
+
let pulseIn = 1.2;
|
|
165
|
+
|
|
166
|
+
const ambient = (dt: number) => {
|
|
167
|
+
const { box } = field;
|
|
168
|
+
// Embers start inside the button, hidden behind it, and surface as they rise past its top edge.
|
|
169
|
+
emberAcc += state.rate * dt;
|
|
170
|
+
while (emberAcc >= 1) {
|
|
171
|
+
emberAcc -= 1;
|
|
172
|
+
field.spawn({
|
|
173
|
+
x: box.x + rnd(4, box.w - 4), y: box.y + rnd(2, box.h - 2),
|
|
174
|
+
vx: rnd(-10, 10) * (state.hovering ? 3 : 1), vy: -rnd(state.rise * 0.6, state.rise * 1.3),
|
|
175
|
+
size: rnd(1.2, 2.8), alpha: rnd(0.7, 1), life: rnd(1.1, 2.1), gravity: -12,
|
|
176
|
+
wobble: rnd(6, 16), wobbleFreq: rnd(1.5, 4), phase: rnd(0, Math.PI * 2),
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
pulseIn -= dt;
|
|
180
|
+
if (pulseIn <= 0) {
|
|
181
|
+
pulseIn = PULSE_EVERY;
|
|
182
|
+
if (!state.hovering) shockwave(28, 1.3, 0.35);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
function shockwave(spread: number, duration: number, alpha: number) {
|
|
187
|
+
field.spawn({
|
|
188
|
+
x: 0, y: 0, shape: "outline", size: 0, alpha, life: duration,
|
|
189
|
+
update: (p) => { p.size = spread * gsap.parseEase("power2.out")(p.age / p.life); },
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function erupt(count: number, speed: [number, number]) {
|
|
194
|
+
const { box, radius } = field;
|
|
195
|
+
for (let i = 0; i < count; i++) {
|
|
196
|
+
const pt = perimeterPoint(box, radius, Math.random());
|
|
197
|
+
const v = rnd(speed[0], speed[1]);
|
|
198
|
+
const jitter = rnd(-0.5, 0.5);
|
|
199
|
+
const square = Math.random() < 0.35;
|
|
200
|
+
field.spawn({
|
|
201
|
+
x: pt.x, y: pt.y,
|
|
202
|
+
vx: (pt.nx + jitter * pt.ny) * v, vy: (pt.ny - jitter * pt.nx) * v - 40,
|
|
203
|
+
size: square ? rnd(1.5, 3) : rnd(1, 2.4), shape: square ? "square" : "dot",
|
|
204
|
+
rotation: rnd(0, Math.PI), spin: rnd(-12, 12), life: rnd(0.5, 1.1), drag: 0.12, gravity: 320,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
enter(delay) {
|
|
211
|
+
field.sync();
|
|
212
|
+
field.particles.length = 0;
|
|
213
|
+
const { box } = field;
|
|
214
|
+
const cx = box.x + box.w / 2;
|
|
215
|
+
const cy = box.y + box.h / 2;
|
|
216
|
+
const tl = gsap.timeline({ delay });
|
|
217
|
+
gsap.set(button, { autoAlpha: 0, scale: 0.5, transformOrigin: "50% 50%" });
|
|
218
|
+
|
|
219
|
+
const count = 110;
|
|
220
|
+
for (let i = 0; i < count; i++) {
|
|
221
|
+
const orbit = { radius: rnd(200, 320), angle: rnd(0, Math.PI * 2) };
|
|
222
|
+
const landing = { x: rnd(-box.w * 0.4, box.w * 0.4), y: rnd(-box.h * 0.4, box.h * 0.4) };
|
|
223
|
+
const p = field.spawn({ x: cx + Math.cos(orbit.angle) * orbit.radius, y: cy + Math.sin(orbit.angle) * orbit.radius, size: rnd(1, 2.4), alpha: 0, life: Infinity, fade: false, shape: "spark" });
|
|
224
|
+
const turn = rnd(1.2, 2.4) * (Math.random() < 0.5 ? -1 : 1);
|
|
225
|
+
tl.to(
|
|
226
|
+
orbit,
|
|
227
|
+
{
|
|
228
|
+
radius: 0, angle: orbit.angle + turn, duration: rnd(0.6, 0.9), ease: "power3.in",
|
|
229
|
+
onUpdate() {
|
|
230
|
+
const k = 1 - orbit.radius / 320;
|
|
231
|
+
const nx = cx + landing.x * k + Math.cos(orbit.angle) * orbit.radius;
|
|
232
|
+
const ny = cy + landing.y * k + Math.sin(orbit.angle) * orbit.radius;
|
|
233
|
+
// Velocity only orients the spark's tail; position is set here.
|
|
234
|
+
p.vx = (nx - p.x) * 60; p.vy = (ny - p.y) * 60;
|
|
235
|
+
p.x = nx; p.y = ny;
|
|
236
|
+
p.alpha = Math.min(1, this.progress() * 3);
|
|
237
|
+
},
|
|
238
|
+
onComplete: () => { p.life = 0.12; p.age = 0; p.fade = true; p.vx = 0; p.vy = 0; },
|
|
239
|
+
},
|
|
240
|
+
rnd(0, 0.2),
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
tl.to(button, { autoAlpha: 1, scale: 1, duration: 0.45, ease: "back.out(2.2)" }, 0.82);
|
|
244
|
+
tl.call(() => { shockwave(60, 0.7, 0.9); erupt(44, [140, 320]); }, [], 0.84);
|
|
245
|
+
tl.call(() => shockwave(90, 0.9, 0.5), [], 0.96);
|
|
246
|
+
tl.call(() => field.addEmitter(ambient), [], 1.05);
|
|
247
|
+
return tl;
|
|
248
|
+
},
|
|
249
|
+
exit() { field.removeEmitter(ambient); field.release(0.25); },
|
|
250
|
+
blast() {
|
|
251
|
+
field.removeEmitter(ambient);
|
|
252
|
+
shockwave(120, 0.6, 1);
|
|
253
|
+
gsap.delayedCall(0.08, () => shockwave(160, 0.7, 0.6));
|
|
254
|
+
gsap.delayedCall(0.16, () => shockwave(200, 0.8, 0.3));
|
|
255
|
+
erupt(140, [400, 1000]);
|
|
256
|
+
},
|
|
257
|
+
idle() { field.addEmitter(ambient); },
|
|
258
|
+
hover(on) {
|
|
259
|
+
state.hovering = on;
|
|
260
|
+
gsap.to(state, { rate: on ? EMBER_RATE.hover : EMBER_RATE.idle, rise: on ? EMBER_RISE.hover : EMBER_RISE.idle, duration: on ? 0.3 : 0.9, ease: on ? "power3.out" : "power2.inOut", overwrite: true });
|
|
261
|
+
gsap.to(button, { scale: on ? 1.04 : 1, duration: 0.3, ease: on ? "back.out(2)" : "power2.out", overwrite: "auto" });
|
|
262
|
+
if (on) { shockwave(40, 0.5, 0.8); erupt(56, [160, 360]); }
|
|
263
|
+
},
|
|
264
|
+
destroy() { field.removeEmitter(ambient); gsap.killTweensOf(state); },
|
|
265
|
+
};
|
|
266
|
+
},
|
|
267
|
+
};
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## resolve
|
|
271
|
+
|
|
272
|
+
Particles stream in from far off and settle into a dot grid over the card's face, row by row like a scan; the card fades up beneath them and the grid dissolves.
|
|
273
|
+
|
|
274
|
+
```ts
|
|
275
|
+
/** Spacing of the dot grid the card resolves from, in px. */
|
|
276
|
+
const GRID = 16;
|
|
277
|
+
const CARD_RUNNERS = { idle: 1, hover: 4 };
|
|
278
|
+
const CARD_RUNNER_SPEED = { idle: 50, hover: 260 };
|
|
279
|
+
|
|
280
|
+
export const resolve: ButtonEffect = {
|
|
281
|
+
layer: "over",
|
|
282
|
+
bleed: 140,
|
|
283
|
+
create(field, card) {
|
|
284
|
+
const runners: { t: number }[] = [];
|
|
285
|
+
const state = { speed: CARD_RUNNER_SPEED.idle, hovering: false };
|
|
286
|
+
let glintIn = 0.6;
|
|
287
|
+
let sprayAcc = 0;
|
|
288
|
+
|
|
289
|
+
const ambient = (dt: number) => {
|
|
290
|
+
const { box, radius } = field;
|
|
291
|
+
const total = perimeterLength(box, radius);
|
|
292
|
+
for (const run of runners) {
|
|
293
|
+
run.t = (run.t + (state.speed * dt) / total) % 1;
|
|
294
|
+
const pt = perimeterPoint(box, radius, run.t);
|
|
295
|
+
field.spawn({ x: pt.x, y: pt.y, size: state.hovering ? 2.4 : 1.8, life: state.hovering ? 0.45 : 0.6, shrink: true });
|
|
296
|
+
}
|
|
297
|
+
if (state.hovering) {
|
|
298
|
+
sprayAcc += 40 * dt;
|
|
299
|
+
while (sprayAcc >= 1) {
|
|
300
|
+
sprayAcc -= 1;
|
|
301
|
+
const pt = perimeterPoint(box, radius, Math.random());
|
|
302
|
+
const speed = rnd(40, 120);
|
|
303
|
+
field.spawn({ x: pt.x, y: pt.y, vx: pt.nx * speed, vy: pt.ny * speed, size: rnd(0.8, 1.4), life: rnd(0.3, 0.6), drag: 0.1, shape: "spark" });
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
glintIn -= dt;
|
|
307
|
+
if (glintIn <= 0) {
|
|
308
|
+
glintIn = rnd(0.6, 1.6) / (state.hovering ? 4 : 1);
|
|
309
|
+
glint(perimeterPoint(box, radius, Math.random()));
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
function glint(pt: { x: number; y: number }) {
|
|
314
|
+
const size = rnd(3, 7);
|
|
315
|
+
field.spawn({
|
|
316
|
+
x: pt.x, y: pt.y, size, shape: "star", rotation: rnd(0, Math.PI), spin: rnd(-1, 1), life: rnd(0.4, 0.7), fade: false,
|
|
317
|
+
update: (p) => { const k = Math.sin((p.age / p.life) * Math.PI); p.size = size * k; p.alpha = k; },
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function setRunners(count: number) {
|
|
322
|
+
runners.length = 0;
|
|
323
|
+
for (let k = 0; k < count; k++) runners.push({ t: k / count });
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function flash(count: number, speed: [number, number]) {
|
|
327
|
+
const { box, radius } = field;
|
|
328
|
+
for (let i = 0; i < count; i++) {
|
|
329
|
+
const pt = perimeterPoint(box, radius, i / count + rnd(-0.01, 0.01));
|
|
330
|
+
const v = rnd(speed[0], speed[1]);
|
|
331
|
+
field.spawn({ x: pt.x, y: pt.y, vx: pt.nx * v, vy: pt.ny * v, size: rnd(1, 2), life: rnd(0.3, 0.6), drag: 0.05, shape: "spark" });
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function idle() { setRunners(CARD_RUNNERS.idle); field.addEmitter(ambient); }
|
|
336
|
+
|
|
337
|
+
return {
|
|
338
|
+
enter(delay) {
|
|
339
|
+
field.sync();
|
|
340
|
+
field.particles.length = 0;
|
|
341
|
+
runners.length = 0;
|
|
342
|
+
const { box } = field;
|
|
343
|
+
const cx = box.x + box.w / 2;
|
|
344
|
+
const cy = box.y + box.h / 2;
|
|
345
|
+
const tl = gsap.timeline({ delay });
|
|
346
|
+
gsap.set(card, { autoAlpha: 0, scale: 0.94, transformOrigin: "50% 50%" });
|
|
347
|
+
|
|
348
|
+
const cols = Math.max(2, Math.floor(box.w / GRID));
|
|
349
|
+
const rows = Math.max(2, Math.floor(box.h / GRID));
|
|
350
|
+
const padX = (box.w - (cols - 1) * GRID) / 2;
|
|
351
|
+
const padY = (box.h - (rows - 1) * GRID) / 2;
|
|
352
|
+
const settle = 0.75;
|
|
353
|
+
for (let r = 0; r < rows; r++) {
|
|
354
|
+
for (let c = 0; c < cols; c++) {
|
|
355
|
+
const tx = box.x + padX + c * GRID;
|
|
356
|
+
const ty = box.y + padY + r * GRID;
|
|
357
|
+
const angle = rnd(0, Math.PI * 2);
|
|
358
|
+
const dist = rnd(160, 420);
|
|
359
|
+
const p = field.spawn({ x: cx + Math.cos(angle) * dist, y: cy + Math.sin(angle) * dist, size: rnd(1, 1.8), alpha: 0, life: Infinity, fade: false });
|
|
360
|
+
tl.to(
|
|
361
|
+
p,
|
|
362
|
+
{
|
|
363
|
+
x: tx, y: ty, alpha: rnd(0.6, 1), duration: rnd(0.45, 0.7), ease: "power3.inOut",
|
|
364
|
+
onComplete: () => { p.life = 0.45; p.age = 0; p.fade = true; p.shrink = true; },
|
|
365
|
+
},
|
|
366
|
+
(r / rows) * 0.25 + rnd(0, 0.06),
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
tl.to(card, { autoAlpha: 1, scale: 1, duration: 0.45, ease: "power3.out" }, settle);
|
|
371
|
+
tl.call(() => { flash(24, [40, 120]); idle(); }, [], settle + 0.25);
|
|
372
|
+
return tl;
|
|
373
|
+
},
|
|
374
|
+
exit() { field.removeEmitter(ambient); runners.length = 0; field.release(0.25); },
|
|
375
|
+
blast() { field.removeEmitter(ambient); runners.length = 0; flash(60, [250, 700]); },
|
|
376
|
+
idle,
|
|
377
|
+
hover(on) {
|
|
378
|
+
state.hovering = on;
|
|
379
|
+
setRunners(on ? CARD_RUNNERS.hover : CARD_RUNNERS.idle);
|
|
380
|
+
gsap.to(state, { speed: on ? CARD_RUNNER_SPEED.hover : CARD_RUNNER_SPEED.idle, duration: on ? 0.3 : 0.7, ease: on ? "power3.out" : "power2.inOut", overwrite: true });
|
|
381
|
+
if (on) flash(28, [80, 200]);
|
|
382
|
+
},
|
|
383
|
+
destroy() { field.removeEmitter(ambient); gsap.killTweensOf(state); },
|
|
384
|
+
};
|
|
385
|
+
},
|
|
386
|
+
};
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
Cards in a grid enter with `index * 0.09` stagger on `idle`, so the route's own items have landed before the grid resolves.
|
|
390
|
+
|
|
391
|
+
## slipstream
|
|
392
|
+
|
|
393
|
+
The link rides a slipstream: hairlines rush past it from left to right. It arrives from the left through a gust and docks with a puff of sparks off the arrow. Idle, a line or two drifts past; under the pointer the wind picks up and the link leans into it. Pressed, everything blows off to the right.
|
|
394
|
+
|
|
395
|
+
```ts
|
|
396
|
+
const STREAK_RATE = { idle: 5, hover: 60 };
|
|
397
|
+
const STREAK_SPEED = { idle: 90, hover: 520 };
|
|
398
|
+
/** How far, in px, the link leans into the wind under the pointer. */
|
|
399
|
+
const LEAN = 4;
|
|
400
|
+
|
|
401
|
+
export const slipstream: ButtonEffect = {
|
|
402
|
+
layer: "over",
|
|
403
|
+
bleed: 160,
|
|
404
|
+
create(field, button) {
|
|
405
|
+
const state = { rate: STREAK_RATE.idle, speed: STREAK_SPEED.idle, hovering: false };
|
|
406
|
+
let streakAcc = 0;
|
|
407
|
+
let sparkIn = 1;
|
|
408
|
+
|
|
409
|
+
/** One level hairline crossing the band, left to right. */
|
|
410
|
+
function streak(x: number, speed: number, life = rnd(0.5, 0.9), alpha = rnd(0.3, 0.7)) {
|
|
411
|
+
const { box } = field;
|
|
412
|
+
field.spawn({ x, y: box.y + rnd(-6, box.h + 6), vx: speed, size: gsap.utils.clamp(3, 28, speed * 0.04), alpha, life, shape: "streak", shrink: true });
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/** Sparks leaving the arrow's tip at the right edge. */
|
|
416
|
+
function tip(count: number, speed: [number, number]) {
|
|
417
|
+
const { box } = field;
|
|
418
|
+
for (let i = 0; i < count; i++) {
|
|
419
|
+
const v = rnd(speed[0], speed[1]);
|
|
420
|
+
field.spawn({ x: box.x + box.w - 4, y: box.y + box.h / 2 + rnd(-4, 4), vx: v, vy: rnd(-v * 0.18, v * 0.18), size: rnd(0.8, 1.6), life: rnd(0.3, 0.6), drag: 0.1, shape: "spark" });
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const ambient = (dt: number) => {
|
|
425
|
+
const { box } = field;
|
|
426
|
+
streakAcc += state.rate * dt;
|
|
427
|
+
while (streakAcc >= 1) {
|
|
428
|
+
streakAcc -= 1;
|
|
429
|
+
streak(box.x - rnd(20, 120), state.speed * rnd(0.7, 1.3));
|
|
430
|
+
}
|
|
431
|
+
sparkIn -= dt;
|
|
432
|
+
if (sparkIn <= 0) {
|
|
433
|
+
sparkIn = rnd(0.8, 2.2) / (state.hovering ? 8 : 1);
|
|
434
|
+
tip(state.hovering ? 3 : 1, [state.speed, state.speed * 2]);
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
function idle() { field.addEmitter(ambient); }
|
|
439
|
+
|
|
440
|
+
return {
|
|
441
|
+
enter(delay) {
|
|
442
|
+
field.sync();
|
|
443
|
+
field.particles.length = 0;
|
|
444
|
+
const { box } = field;
|
|
445
|
+
const tl = gsap.timeline({ delay });
|
|
446
|
+
gsap.set(button, { autoAlpha: 0, x: -48 });
|
|
447
|
+
for (let i = 0; i < 44; i++) {
|
|
448
|
+
tl.call(() => streak(box.x - rnd(40, 160), rnd(500, 900), rnd(0.35, 0.6), rnd(0.4, 0.9)), [], rnd(0, 0.35));
|
|
449
|
+
}
|
|
450
|
+
tl.to(button, { autoAlpha: 1, x: 0, duration: 0.55, ease: "power4.out" }, 0.1);
|
|
451
|
+
tl.call(() => { tip(14, [200, 480]); idle(); }, [], 0.5);
|
|
452
|
+
return tl;
|
|
453
|
+
},
|
|
454
|
+
exit() { field.removeEmitter(ambient); field.release(0.25); },
|
|
455
|
+
blast() {
|
|
456
|
+
field.removeEmitter(ambient);
|
|
457
|
+
const { box } = field;
|
|
458
|
+
for (let i = 0; i < 60; i++) streak(box.x + rnd(-80, box.w), rnd(700, 1400), rnd(0.3, 0.6), rnd(0.5, 1));
|
|
459
|
+
tip(50, [500, 1200]);
|
|
460
|
+
},
|
|
461
|
+
idle,
|
|
462
|
+
hover(on) {
|
|
463
|
+
state.hovering = on;
|
|
464
|
+
gsap.to(state, { rate: on ? STREAK_RATE.hover : STREAK_RATE.idle, speed: on ? STREAK_SPEED.hover : STREAK_SPEED.idle, duration: on ? 0.3 : 0.8, ease: on ? "power3.out" : "power2.inOut", overwrite: true });
|
|
465
|
+
gsap.to(button, { x: on ? LEAN : 0, duration: 0.3, ease: on ? "back.out(2)" : "power2.out", overwrite: "auto" });
|
|
466
|
+
if (on) tip(10, [200, 500]);
|
|
467
|
+
},
|
|
468
|
+
destroy() { field.removeEmitter(ambient); gsap.killTweensOf(state); },
|
|
469
|
+
};
|
|
470
|
+
},
|
|
471
|
+
};
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
On press, `blast()` and tween the link `x: 64, autoAlpha: 0` while the framework skill's navigation proceeds.
|
|
475
|
+
|
|
476
|
+
## ignite
|
|
477
|
+
|
|
478
|
+
A block of text set on a rule, such as an install command or a large form field. On entrance a runner streaks along the underline and the text is revealed in its wake. Idle, glints drift up off the rule; under the pointer or focus it runs hot. `blast()` lights the whole rule at once and throws sparks skyward. It reads its baseline from the bottom of the target, so give the target the rule as a bottom border.
|
|
479
|
+
|
|
480
|
+
```ts
|
|
481
|
+
import type { Particle } from "./field";
|
|
482
|
+
|
|
483
|
+
/** Embers per second off the underline, idle and hot. */
|
|
484
|
+
const EMBER_RATE = { idle: 4, hot: 26 };
|
|
485
|
+
/** Seconds between idle glints. */
|
|
486
|
+
const GLINT_EVERY: [number, number] = [0.5, 1.4];
|
|
487
|
+
|
|
488
|
+
export const ignite: ParticleEffectDefinition<ParticleEffectInstance> = {
|
|
489
|
+
bleed: 200,
|
|
490
|
+
create(field: ParticleField, target: HTMLElement) {
|
|
491
|
+
const state = { rate: EMBER_RATE.idle, hot: false };
|
|
492
|
+
let emberAcc = 0;
|
|
493
|
+
let glintIn = 0.6;
|
|
494
|
+
|
|
495
|
+
function baseline(): number {
|
|
496
|
+
const { box } = field;
|
|
497
|
+
return box.y + box.h;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
const ambient = (dt: number) => {
|
|
501
|
+
const { box } = field;
|
|
502
|
+
const y = baseline();
|
|
503
|
+
emberAcc += state.rate * dt;
|
|
504
|
+
while (emberAcc >= 1) {
|
|
505
|
+
emberAcc -= 1;
|
|
506
|
+
field.spawn({
|
|
507
|
+
x: box.x + rnd(0, box.w),
|
|
508
|
+
y: y + rnd(-1, 1),
|
|
509
|
+
vx: rnd(-6, 6),
|
|
510
|
+
vy: -rnd(20, 60) * (state.hot ? 2 : 1),
|
|
511
|
+
size: rnd(0.8, 2),
|
|
512
|
+
alpha: rnd(0.5, 1),
|
|
513
|
+
life: rnd(0.9, 1.8),
|
|
514
|
+
gravity: -10,
|
|
515
|
+
wobble: rnd(4, 12),
|
|
516
|
+
wobbleFreq: rnd(1.5, 3.5),
|
|
517
|
+
phase: rnd(0, Math.PI * 2),
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
glintIn -= dt;
|
|
521
|
+
if (glintIn <= 0) {
|
|
522
|
+
glintIn = rnd(GLINT_EVERY[0], GLINT_EVERY[1]) / (state.hot ? 3 : 1);
|
|
523
|
+
glint(box.x + rnd(0, box.w), y);
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
|
|
527
|
+
function glint(x: number, y: number) {
|
|
528
|
+
const size = rnd(4, 10);
|
|
529
|
+
field.spawn({
|
|
530
|
+
x,
|
|
531
|
+
y,
|
|
532
|
+
size,
|
|
533
|
+
shape: "star",
|
|
534
|
+
rotation: rnd(0, Math.PI),
|
|
535
|
+
spin: rnd(-1.5, 1.5),
|
|
536
|
+
life: rnd(0.4, 0.8),
|
|
537
|
+
fade: false,
|
|
538
|
+
update: (p) => {
|
|
539
|
+
const k = Math.sin((p.age / p.life) * Math.PI);
|
|
540
|
+
p.size = size * k;
|
|
541
|
+
p.alpha = k;
|
|
542
|
+
},
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/** Sparks fanning up and out from a point, as if struck. */
|
|
547
|
+
function strike(x: number, y: number, count: number, speed: [number, number]) {
|
|
548
|
+
for (let i = 0; i < count; i++) {
|
|
549
|
+
const angle = -Math.PI / 2 + rnd(-1.1, 1.1);
|
|
550
|
+
const v = rnd(speed[0], speed[1]);
|
|
551
|
+
field.spawn({
|
|
552
|
+
x,
|
|
553
|
+
y,
|
|
554
|
+
vx: Math.cos(angle) * v,
|
|
555
|
+
vy: Math.sin(angle) * v,
|
|
556
|
+
size: rnd(0.9, 2.2),
|
|
557
|
+
alpha: rnd(0.7, 1),
|
|
558
|
+
life: rnd(0.35, 0.8),
|
|
559
|
+
drag: 0.06,
|
|
560
|
+
gravity: 420,
|
|
561
|
+
shape: "spark",
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
glint(x, y);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/** A hairline flare that spreads outward along the rule from a point. */
|
|
568
|
+
function ripple(x: number, y: number, reach: number, duration: number) {
|
|
569
|
+
for (const dir of [-1, 1]) {
|
|
570
|
+
field.spawn({
|
|
571
|
+
x,
|
|
572
|
+
y,
|
|
573
|
+
size: 0,
|
|
574
|
+
alpha: 1,
|
|
575
|
+
shape: "streak",
|
|
576
|
+
life: duration,
|
|
577
|
+
update: (p) => {
|
|
578
|
+
const k = gsap.parseEase("power3.out")(p.age / p.life);
|
|
579
|
+
p.size = 6 + reach * k * 0.5;
|
|
580
|
+
p.x = x + dir * reach * k * 0.5;
|
|
581
|
+
},
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
function idle() {
|
|
587
|
+
field.addEmitter(ambient);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
return {
|
|
591
|
+
enter(delay) {
|
|
592
|
+
field.sync();
|
|
593
|
+
field.particles.length = 0;
|
|
594
|
+
const { box } = field;
|
|
595
|
+
const y = baseline();
|
|
596
|
+
const tl = gsap.timeline({ delay });
|
|
597
|
+
gsap.set(target, { autoAlpha: 0, clipPath: "inset(-20% 100% -20% 0)" });
|
|
598
|
+
|
|
599
|
+
// A runner streaks the length of the rule and the command appears
|
|
600
|
+
// behind it, with sparks kicked up as it goes.
|
|
601
|
+
const run = { x: box.x };
|
|
602
|
+
let head: Particle | null = null;
|
|
603
|
+
tl.set(target, { autoAlpha: 1 }, 0);
|
|
604
|
+
tl.to(
|
|
605
|
+
run,
|
|
606
|
+
{
|
|
607
|
+
x: box.x + box.w,
|
|
608
|
+
duration: 0.7,
|
|
609
|
+
ease: "power2.inOut",
|
|
610
|
+
onStart() {
|
|
611
|
+
head = field.spawn({
|
|
612
|
+
x: box.x,
|
|
613
|
+
y,
|
|
614
|
+
size: 2.6,
|
|
615
|
+
alpha: 1,
|
|
616
|
+
life: Infinity,
|
|
617
|
+
fade: false,
|
|
618
|
+
shape: "spark",
|
|
619
|
+
});
|
|
620
|
+
},
|
|
621
|
+
onUpdate() {
|
|
622
|
+
if (!head) {
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
head.vx = (run.x - head.x) * 60;
|
|
626
|
+
head.x = run.x;
|
|
627
|
+
for (let i = 0; i < 3; i++) {
|
|
628
|
+
field.spawn({
|
|
629
|
+
x: run.x + rnd(-6, 0),
|
|
630
|
+
y: y + rnd(-1, 1),
|
|
631
|
+
vx: -rnd(20, 120),
|
|
632
|
+
vy: -rnd(20, 140),
|
|
633
|
+
size: rnd(0.8, 1.8),
|
|
634
|
+
life: rnd(0.3, 0.7),
|
|
635
|
+
drag: 0.08,
|
|
636
|
+
gravity: 240,
|
|
637
|
+
shape: "spark",
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
gsap.set(target, {
|
|
641
|
+
clipPath: `inset(-20% ${(1 - this.progress()) * 100}% -20% 0)`,
|
|
642
|
+
});
|
|
643
|
+
},
|
|
644
|
+
onComplete: () => {
|
|
645
|
+
if (head) {
|
|
646
|
+
head.life = 0.1;
|
|
647
|
+
head.age = 0;
|
|
648
|
+
head.fade = true;
|
|
649
|
+
head.vx = 0;
|
|
650
|
+
}
|
|
651
|
+
},
|
|
652
|
+
},
|
|
653
|
+
0,
|
|
654
|
+
);
|
|
655
|
+
tl.set(target, { clearProps: "clipPath" }, 0.72);
|
|
656
|
+
tl.call(
|
|
657
|
+
() => {
|
|
658
|
+
ripple(box.x + box.w, y, 240, 0.5);
|
|
659
|
+
for (let i = 0; i < 6; i++) {
|
|
660
|
+
glint(box.x + rnd(0, box.w), y);
|
|
661
|
+
}
|
|
662
|
+
idle();
|
|
663
|
+
},
|
|
664
|
+
[],
|
|
665
|
+
0.72,
|
|
666
|
+
);
|
|
667
|
+
return tl;
|
|
668
|
+
},
|
|
669
|
+
exit() {
|
|
670
|
+
field.removeEmitter(ambient);
|
|
671
|
+
field.release(0.25);
|
|
672
|
+
},
|
|
673
|
+
blast() {
|
|
674
|
+
field.removeEmitter(ambient);
|
|
675
|
+
const { box } = field;
|
|
676
|
+
const y = baseline();
|
|
677
|
+
// The rule lights end to end and the command is thrown skyward.
|
|
678
|
+
for (let i = 0; i < 6; i++) {
|
|
679
|
+
ripple(box.x + rnd(0, box.w), y, 300, 0.6);
|
|
680
|
+
}
|
|
681
|
+
const columns = Math.max(6, Math.round(box.w / 18));
|
|
682
|
+
for (let i = 0; i <= columns; i++) {
|
|
683
|
+
const x = box.x + (box.w * i) / columns;
|
|
684
|
+
strike(x, y - rnd(0, box.h * 0.6), 9, [260, 720]);
|
|
685
|
+
}
|
|
686
|
+
strike(box.x + box.w, y, 40, [300, 900]);
|
|
687
|
+
for (let i = 0; i < 14; i++) {
|
|
688
|
+
glint(box.x + rnd(0, box.w), y + rnd(-box.h, 0));
|
|
689
|
+
}
|
|
690
|
+
},
|
|
691
|
+
idle,
|
|
692
|
+
hover(on) {
|
|
693
|
+
state.hot = on;
|
|
694
|
+
gsap.to(state, {
|
|
695
|
+
rate: on ? EMBER_RATE.hot : EMBER_RATE.idle,
|
|
696
|
+
duration: on ? 0.3 : 0.8,
|
|
697
|
+
overwrite: true,
|
|
698
|
+
});
|
|
699
|
+
if (on) {
|
|
700
|
+
ripple(field.box.x + field.box.w / 2, baseline(), 200, 0.45);
|
|
701
|
+
}
|
|
702
|
+
},
|
|
703
|
+
destroy() {
|
|
704
|
+
field.removeEmitter(ambient);
|
|
705
|
+
gsap.killTweensOf(state);
|
|
706
|
+
},
|
|
707
|
+
};
|
|
708
|
+
},
|
|
709
|
+
};
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
On copy or submit, `blast()`, kick the block with a short `x`/`y` jitter, and call `idle()` about a second later.
|
|
713
|
+
|
|
714
|
+
## Controller contract
|
|
715
|
+
|
|
716
|
+
Pass the selected definition to `attachParticleEffect(wrapper, canvas, target, effect)` from [particle-field.md](particle-field.md). The owner calls the returned controls for the relevant phase and reveals a hidden wrapper once its target is prepared.
|
|
717
|
+
|
|
718
|
+
A new treatment supplies `layer`, `bleed`, and `create(field, target)` returning `enter`, `exit`, `blast`, `idle`, `hover`, and `destroy`. Keep it monochrome and inexpensive at rest.
|