Slack GIF Creator
Overview
This skill provides a flexible toolkit for creating animated GIFs optimized for Slack. It includes validators for Slack's size and dimension constraints, composable animation primitives (shake, bounce, spin, pulse, fade, zoom, explode, wiggle, slide, flip, morph, move, kaleidoscope), and helper utilities for text, color, and visual effects. The goal is creative freedom within Slack's technical constraints.
Slack Requirements
Message GIFs
- Max size: ~2MB
- Optimal dimensions: 480x480
- Typical FPS: 15-20
- Color limit: 128-256
- Duration: 2-5 seconds
Emoji GIFs
- Max size: 64KB (strict limit)
- Optimal dimensions: 128x128
- Typical FPS: 10-12
- Color limit: 32-48
- Duration: 1-2 seconds
Emoji GIFs are challenging due to the 64KB limit. Strategies that help: limit to 10-15 frames, use 32-48 colors maximum, keep designs simple, avoid gradients, and validate file size frequently.
Toolkit Structure
- Validators -- Check if a GIF meets Slack requirements
- Animation Primitives -- Composable building blocks for motion
- Helper Utilities -- Optional functions for text, colors, and effects
Core Validators
GIF Builder with Size Check
from core.gif_builder import GIFBuilder
builder = GIFBuilder(width=128, height=128, fps=10)
# ... add frames ...
info = builder.save('emoji.gif', num_colors=48, optimize_for_emoji=True)
# info contains: size_kb, size_mb, frame_count, duration_seconds
File Size Validation
from core.validators import check_slack_size, validate_gif, is_slack_ready
# Quick check
passes, info = check_slack_size('emoji.gif', is_emoji=True)
# Dimension check
passes, info = validate_dimensions(128, 128, is_emoji=True)
# Complete validation
all_pass, results = validate_gif('emoji.gif', is_emoji=True)
# One-liner
if is_slack_ready('emoji.gif', is_emoji=True):
print("Ready to upload!")
Animation Primitives
Shake
from templates.shake import create_shake_animation
frames = create_shake_animation(
object_type='emoji',
object_data={'emoji': '😱', 'size': 80},
num_frames=20,
shake_intensity=15,
direction='both' # or 'horizontal', 'vertical'
)
Bounce
from templates.bounce import create_bounce_animation
frames = create_bounce_animation(
object_type='circle',
object_data={'radius': 40, 'color': (255, 100, 100)},
num_frames=30,
bounce_height=150
)
Spin / Rotate
from templates.spin import create_spin_animation, create_loading_spinner
frames = create_spin_animation(
object_type='emoji',
object_data={'emoji': '🔄', 'size': 100},
rotation_type='clockwise', # or 'wobble'
full_rotations=2
)
frames = create_loading_spinner(spinner_type='dots')
Pulse / Heartbeat
from templates.pulse import create_pulse_animation, create_attention_pulse
frames = create_pulse_animation(
object_data={'emoji': '❤️', 'size': 100},
pulse_type='smooth', # or 'heartbeat'
scale_range=(0.8, 1.2)
)
frames = create_attention_pulse(emoji='⚠️', num_frames=20)
Fade / Crossfade
from templates.fade import create_fade_animation, create_crossfade
frames = create_fade_animation(fade_type='in') # or 'out'
frames = create_crossfade(
object1_data={'emoji': '😊', 'size': 100},
object2_data={'emoji': '😂', 'size': 100}
)
Zoom / Explosion Zoom
from templates.zoom import create_zoom_animation, create_explosion_zoom
frames = create_zoom_animation(
zoom_type='in',
scale_range=(0.1, 2.0),
add_motion_blur=True
)
frames = create_explosion_zoom(emoji='💥')
Explode / Shatter
from templates.explode import create_explode_animation, create_particle_burst
frames = create_explode_animation(
explode_type='burst', # or 'shatter', 'dissolve'
num_pieces=25
)
frames = create_particle_burst(particle_count=30)
Wiggle / Jiggle
from templates.wiggle import create_wiggle_animation, create_excited_wiggle
frames = create_wiggle_animation(
wiggle_type='jello', # or 'wave'
intensity=1.0,
cycles=2
)
frames = create_excited_wiggle(emoji='🎉')
Slide
from templates.slide import create_slide_animation, create_multi_slide
frames = create_slide_animation(
direction='left',
slide_type='in', # or 'across'
overshoot=True
)
objects = [
{'data': {'emoji': '🎯', 'size': 60}, 'direction': 'left', 'final_pos': (120, 240)},
{'data': {'emoji': '🎪', 'size': 60}, 'direction': 'right', 'final_pos': (240, 240)}
]
frames = create_multi_slide(objects, stagger_delay=5)
Flip
from templates.flip import create_flip_animation, create_quick_flip
frames = create_flip_animation(
object1_data={'emoji': '😊', 'size': 120},
object2_data={'emoji': '😂', 'size': 120},
flip_axis='horizontal' # or 'vertical'
)
frames = create_quick_flip('👍', '👎')
Morph / Transform
from templates.morph import create_morph_animation
frames = create_morph_animation(
object1_data={'emoji': '😊', 'size': 100},
object2_data={'emoji': '😂', 'size': 100},
morph_type='crossfade' # or 'scale', 'spin_morph'
)
Move Effect
from templates.move import create_move_animation
# Linear movement
frames = create_move_animation(
object_data={'emoji': '🚀', 'size': 60},
start_pos=(50, 240), end_pos=(430, 240),
motion_type='linear', easing='ease_out'
)
# Arc (parabolic), circular, or wave motion also supported
Kaleidoscope
from templates.kaleidoscope import apply_kaleidoscope, create_kaleidoscope_animation
kaleido_frame = apply_kaleidoscope(frame, segments=8)
frames = create_kaleidoscope_animation(
base_frame=my_frame,
num_frames=30, segments=8, rotation_speed=1.0
)
Composing Primitives
Primitives can be freely combined:
# Bounce + shake on impact
for i in range(num_frames):
frame = create_blank_frame(480, 480, bg_color)
t_bounce = i / (num_frames - 1)
y = interpolate(start_y, ground_y, t_bounce, 'bounce_out')
if y >= ground_y - 5:
shake_x = math.sin(i * 2) * 10
x = center_x + shake_x
else:
x = center_x
draw_emoji(frame, 'ball', (x, y), size=60)
builder.add_frame(frame)
Helper Utilities
Text Rendering
from core.typography import draw_text_with_outline, TYPOGRAPHY_SCALE
draw_text_with_outline(
frame, "BONK!",
position=(240, 100),
font_size=TYPOGRAPHY_SCALE['h1'],
text_color=(255, 68, 68),
outline_color=(0, 0, 0),
outline_width=4,
centered=True
)
Color Palettes
from core.color_palettes import get_palette
palette = get_palette('vibrant') # or 'pastel', 'dark', 'neon', 'professional'
bg_color = palette['background']
text_color = palette['primary']
Visual Effects
from core.visual_effects import ParticleSystem, create_impact_flash
particles = ParticleSystem()
particles.emit_sparkles(x=240, y=200, count=15)
particles.update()
particles.render(frame)
frame = create_impact_flash(frame, position=(240, 200), radius=100)
Easing Functions
from core.easing import interpolate
y = interpolate(start=0, end=400, t=progress, easing='ease_in')
# Available: linear, ease_in, ease_out, ease_in_out, bounce_out, elastic_out, back_out
Optimization Strategies
Message GIFs (over 2MB)
- Reduce frames (lower FPS or shorter duration)
- Reduce colors (128 to 64)
- Reduce dimensions (480x480 to 320x320)
- Enable duplicate frame removal
Emoji GIFs (over 64KB)
- Limit to 10-12 frames total
- Use 32-40 colors maximum
- Avoid gradients (solid colors compress better)
- Simplify design (fewer elements)
- Use
optimize_for_emoji=Truein save method
Creative Process
- Understand the vision -- What should happen? What is the mood?
- Design the animation -- Break into phases (anticipation, action, reaction)
- Apply primitives as needed -- Shake, bounce, move, effects -- mix freely
- Validate constraints -- Check file size, especially for emoji GIFs
- Iterate if needed -- Reduce frames/colors if over size limits
Dependencies
pip install pillow imageio numpy