Slack gif creator skill
Knowledge and utilities for creating animated GIFs optimized for Slack.
by anthropics·Apache-2.0 license·★ 177,518 Stars on the repo·GitHub ↗
npx degit anthropics/skills/skills/slack-gif-creator#main ~/.claude/skills/slack-gif-creatorChecked ·commit main
Files of Slack gif creator
Show the full text255 lines
Slack GIF Creator
A toolkit providing utilities and knowledge for creating animated GIFs optimized for Slack.
Slack Requirements
Dimensions:
- Emoji GIFs: 128x128 (recommended)
- Message GIFs: 480x480
Parameters:
- FPS: 10-30 (lower is smaller file size)
- Colors: 48-128 (fewer = smaller file size)
- Duration: Keep under 3 seconds for emoji GIFs
Core Workflow
from core.gif_builder import GIFBuilder
from PIL import Image, ImageDraw
# 1. Create builder
builder = GIFBuilder(width=128, height=128, fps=10)
# 2. Generate frames
for i in range(12):
frame = Image.new('RGB', (128, 128), (240, 248, 255))
draw = ImageDraw.Draw(frame)
# Draw your animation using PIL primitives
# (circles, polygons, lines, etc.)
builder.add_frame(frame)
# 3. Save with optimization
builder.save('output.gif', num_colors=48, optimize_for_emoji=True)
Drawing Graphics
Working with User-Uploaded Images
If a user uploads an image, consider whether they want to:
- Use it directly (e.g., "animate this", "split this into frames")
- Use it as inspiration (e.g., "make something like this")
Load and work with images using PIL:
from PIL import Image
uploaded = Image.open('file.png')
# Use directly, or just as reference for colors/style
Drawing from Scratch
When drawing graphics from scratch, use PIL ImageDraw primitives:
from PIL import ImageDraw
draw = ImageDraw.Draw(frame)
# Circles/ovals
draw.ellipse([x1, y1, x2, y2], fill=(r, g, b), outline=(r, g, b), width=3)
# Stars, triangles, any polygon
points = [(x1, y1), (x2, y2), (x3, y3), ...]
draw.polygon(points, fill=(r, g, b), outline=(r, g, b), width=3)
# Lines
draw.line([(x1, y1), (x2, y2)], fill=(r, g, b), width=5)
# Rectangles
draw.rectangle([x1, y1, x2, y2], fill=(r, g, b), outline=(r, g, b), width=3)
Don't use: Emoji fonts (unreliable across platforms) or assume pre-packaged graphics exist in this skill.
Making Graphics Look Good
Graphics should look polished and creative, not basic. Here's how:
Use thicker lines - Always set width=2 or higher for outlines and lines. Thin lines (width=1) look choppy and amateurish.
Add visual depth:
- Use gradients for backgrounds (
create_gradient_background) - Layer multiple shapes for complexity (e.g., a star with a smaller star inside)
Make shapes more interesting:
- Don't just draw a plain circle - add highlights, rings, or patterns
- Stars can have glows (draw larger, semi-transparent versions behind)
- Combine multiple shapes (stars + sparkles, circles + rings)
Pay attention to colors:
- Use vibrant, complementary colors
- Add contrast (dark outlines on light shapes, light outlines on dark shapes)
- Consider the overall composition
For complex shapes (hearts, snowflakes, etc.):
- Use combinations of polygons and ellipses
- Calculate points carefully for symmetry
- Add details (a heart can have a highlight curve, snowflakes have intricate branches)
Be creative and detailed! A good Slack GIF should look polished, not like placeholder graphics.
Available Utilities
GIFBuilder (core.gif_builder)
Assembles frames and optimizes for Slack:
builder = GIFBuilder(width=128, height=128, fps=10)
builder.add_frame(frame) # Add PIL Image
builder.add_frames(frames) # Add list of frames
builder.save('out.gif', num_colors=48, optimize_for_emoji=True, remove_duplicates=True)
Validators (core.validators)
Check if GIF meets Slack requirements:
from core.validators import validate_gif, is_slack_ready
# Detailed validation
passes, info = validate_gif('my.gif', is_emoji=True, verbose=True)
# Quick check
if is_slack_ready('my.gif'):
print("Ready!")
Easing Functions (core.easing)
Smooth motion instead of linear:
from core.easing import interpolate
# Progress from 0.0 to 1.0
t = i / (num_frames - 1)
# Apply easing
y = interpolate(start=0, end=400, t=t, easing='ease_out')
# Available: linear, ease_in, ease_out, ease_in_out,
# bounce_out, elastic_out, back_out
Frame Helpers (core.frame_composer)
Convenience functions for common needs:
from core.frame_composer import (
create_blank_frame, # Solid color background
create_gradient_background, # Vertical gradient
draw_circle, # Helper for circles
draw_text, # Simple text rendering
draw_star # 5-pointed star
)
Animation Concepts
Shake/Vibrate
Offset object position with oscillation:
- Use
math.sin()ormath.cos()with frame index - Add small random variations for natural feel
- Apply to x and/or y position
Pulse/Heartbeat
Scale object size rhythmically:
- Use
math.sin(t * frequency * 2 * math.pi)for smooth pulse - For heartbeat: two quick pulses then pause (adjust sine wave)
- Scale between 0.8 and 1.2 of base size
Bounce
Object falls and bounces:
- Use
interpolate()witheasing='bounce_out'for landing - Use
easing='ease_in'for falling (accelerating) - Apply gravity by increasing y velocity each frame
Spin/Rotate
Rotate object around center:
- PIL:
image.rotate(angle, resample=Image.BICUBIC) - For wobble: use sine wave for angle instead of linear
Fade In/Out
Gradually appear or disappear:
- Create RGBA image, adjust alpha channel
- Or use
Image.blend(image1, image2, alpha) - Fade in: alpha from 0 to 1
- Fade out: alpha from 1 to 0
Slide
Move object from off-screen to position:
- Start position: outside frame bounds
- End position: target location
- Use
interpolate()witheasing='ease_out'for smooth stop - For overshoot: use
easing='back_out'
Zoom
Scale and position for zoom effect:
- Zoom in: scale from 0.1 to 2.0, crop center
- Zoom out: scale from 2.0 to 1.0
- Can add motion blur for drama (PIL filter)
Explode/Particle Burst
Create particles radiating outward:
- Generate particles with random angles and velocities
- Update each particle:
x += vx,y += vy - Add gravity:
vy += gravity_constant - Fade out particles over time (reduce alpha)
Optimization Strategies
Only when asked to make the file size smaller, implement a few of the following methods:
- Fewer frames - Lower FPS (10 instead of 20) or shorter duration
- Fewer colors -
num_colors=48instead of 128 - Smaller dimensions - 128x128 instead of 480x480
- Remove duplicates -
remove_duplicates=Truein save() - Emoji mode -
optimize_for_emoji=Trueauto-optimizes
# Maximum optimization for emoji
builder.save(
'emoji.gif',
num_colors=48,
optimize_for_emoji=True,
remove_duplicates=True
)
Philosophy
This skill provides:
- Knowledge: Slack's requirements and animation concepts
- Utilities: GIFBuilder, validators, easing functions
- Flexibility: Create the animation logic using PIL primitives
It does NOT provide:
- Rigid animation templates or pre-made functions
- Emoji font rendering (unreliable across platforms)
- A library of pre-packaged graphics built into the skill
Note on user uploads: This skill doesn't include pre-built graphics, but if a user uploads an image, use PIL to load and work with it - interpret based on their request whether they want it used directly or just as inspiration.
Be creative! Combine concepts (bouncing + rotating, pulsing + sliding, etc.) and use PIL's full capabilities.
Dependencies
pip install pillow imageio numpy
| 1 | |
| 2 | name slack-gif-creator |
| 3 | description Knowledge and utilities for creating animated GIFs optimized for Slack. Provides constraints, validation tools, and animation concepts. Use when users request animated GIFs for Slack like "make me a GIF of X doing Y for Slack." |
| 4 | license Complete terms in LICENSE.txt |
| 5 | |
| 6 | |
| 7 | # Slack GIF Creator |
| 8 | |
| 9 | A toolkit providing utilities and knowledge for creating animated GIFs optimized for Slack. |
| 10 | |
| 11 | ## Slack Requirements |
| 12 | |
| 13 | **Dimensions:** |
| 14 | Emoji GIFs: 128x128 (recommended) |
| 15 | Message GIFs: 480x480 |
| 16 | |
| 17 | **Parameters:** |
| 18 | FPS: 10-30 (lower is smaller file size) |
| 19 | Colors: 48-128 (fewer = smaller file size) |
| 20 | Duration: Keep under 3 seconds for emoji GIFs |
| 21 | |
| 22 | ## Core Workflow |
| 23 | |
| 24 | |
| 25 | from core.gif_builder import GIFBuilder |
| 26 | from PIL import Image, ImageDraw |
| 27 | |
| 28 | # 1. Create builder |
| 29 | builder = GIFBuilder(width=128, height=128, fps=10) |
| 30 | |
| 31 | # 2. Generate frames |
| 32 | for i in range(12): |
| 33 | frame = Image.new('RGB', (128, 128), (240, 248, 255)) |
| 34 | draw = ImageDraw.Draw(frame) |
| 35 | |
| 36 | # Draw your animation using PIL primitives |
| 37 | # (circles, polygons, lines, etc.) |
| 38 | |
| 39 | builder.add_frame(frame) |
| 40 | |
| 41 | # 3. Save with optimization |
| 42 | builder.save('output.gif', num_colors=48, optimize_for_emoji=True) |
| 43 | |
| 44 | |
| 45 | ## Drawing Graphics |
| 46 | |
| 47 | ### Working with User-Uploaded Images |
| 48 | If a user uploads an image, consider whether they want to: |
| 49 | **Use it directly** (e.g., "animate this", "split this into frames") |
| 50 | **Use it as inspiration** (e.g., "make something like this") |
| 51 | |
| 52 | Load and work with images using PIL: |
| 53 | |
| 54 | from PIL import Image |
| 55 | |
| 56 | uploaded = Image.open('file.png') |
| 57 | # Use directly, or just as reference for colors/style |
| 58 | |
| 59 | |
| 60 | ### Drawing from Scratch |
| 61 | When drawing graphics from scratch, use PIL ImageDraw primitives: |
| 62 | |
| 63 | |
| 64 | from PIL import ImageDraw |
| 65 | |
| 66 | draw = ImageDraw.Draw(frame) |
| 67 | |
| 68 | # Circles/ovals |
| 69 | draw.ellipse([x1, y1, x2, y2], fill=(r, g, b), outline=(r, g, b), width=3) |
| 70 | |
| 71 | # Stars, triangles, any polygon |
| 72 | points = [(x1, y1), (x2, y2), (x3, y3), ...] |
| 73 | draw.polygon(points, fill=(r, g, b), outline=(r, g, b), width=3) |
| 74 | |
| 75 | # Lines |
| 76 | draw.line([(x1, y1), (x2, y2)], fill=(r, g, b), width=5) |
| 77 | |
| 78 | # Rectangles |
| 79 | draw.rectangle([x1, y1, x2, y2], fill=(r, g, b), outline=(r, g, b), width=3) |
| 80 | |
| 81 | |
| 82 | **Don't use:** Emoji fonts (unreliable across platforms) or assume pre-packaged graphics exist in this skill. |
| 83 | |
| 84 | ### Making Graphics Look Good |
| 85 | |
| 86 | Graphics should look polished and creative, not basic. Here's how: |
| 87 | |
| 88 | **Use thicker lines** - Always set `width=2` or higher for outlines and lines. Thin lines (width=1) look choppy and amateurish. |
| 89 | |
| 90 | **Add visual depth**: |
| 91 | Use gradients for backgrounds (`create_gradient_background`) |
| 92 | Layer multiple shapes for complexity (e.g., a star with a smaller star inside) |
| 93 | |
| 94 | **Make shapes more interesting**: |
| 95 | Don't just draw a plain circle - add highlights, rings, or patterns |
| 96 | Stars can have glows (draw larger, semi-transparent versions behind) |
| 97 | Combine multiple shapes (stars + sparkles, circles + rings) |
| 98 | |
| 99 | **Pay attention to colors**: |
| 100 | Use vibrant, complementary colors |
| 101 | Add contrast (dark outlines on light shapes, light outlines on dark shapes) |
| 102 | Consider the overall composition |
| 103 | |
| 104 | **For complex shapes** (hearts, snowflakes, etc.): |
| 105 | Use combinations of polygons and ellipses |
| 106 | Calculate points carefully for symmetry |
| 107 | Add details (a heart can have a highlight curve, snowflakes have intricate branches) |
| 108 | |
| 109 | Be creative and detailed! A good Slack GIF should look polished, not like placeholder graphics. |
| 110 | |
| 111 | ## Available Utilities |
| 112 | |
| 113 | ### GIFBuilder (`core.gif_builder`) |
| 114 | Assembles frames and optimizes for Slack: |
| 115 | |
| 116 | builder = GIFBuilder(width=128, height=128, fps=10) |
| 117 | builder.add_frame(frame) # Add PIL Image |
| 118 | builder.add_frames(frames) # Add list of frames |
| 119 | builder.save('out.gif', num_colors=48, optimize_for_emoji=True, remove_duplicates=True) |
| 120 | |
| 121 | |
| 122 | ### Validators (`core.validators`) |
| 123 | Check if GIF meets Slack requirements: |
| 124 | |
| 125 | from core.validators import validate_gif, is_slack_ready |
| 126 | |
| 127 | # Detailed validation |
| 128 | passes, info = validate_gif('my.gif', is_emoji=True, verbose=True) |
| 129 | |
| 130 | # Quick check |
| 131 | if is_slack_ready('my.gif'): |
| 132 | print("Ready!") |
| 133 | |
| 134 | |
| 135 | ### Easing Functions (`core.easing`) |
| 136 | Smooth motion instead of linear: |
| 137 | |
| 138 | from core.easing import interpolate |
| 139 | |
| 140 | # Progress from 0.0 to 1.0 |
| 141 | t = i / (num_frames - 1) |
| 142 | |
| 143 | # Apply easing |
| 144 | y = interpolate(start=0, end=400, t=t, easing='ease_out') |
| 145 | |
| 146 | # Available: linear, ease_in, ease_out, ease_in_out, |
| 147 | # bounce_out, elastic_out, back_out |
| 148 | |
| 149 | |
| 150 | ### Frame Helpers (`core.frame_composer`) |
| 151 | Convenience functions for common needs: |
| 152 | |
| 153 | from core.frame_composer import ( |
| 154 | create_blank_frame, # Solid color background |
| 155 | create_gradient_background, # Vertical gradient |
| 156 | draw_circle, # Helper for circles |
| 157 | draw_text, # Simple text rendering |
| 158 | draw_star # 5-pointed star |
| 159 | ) |
| 160 | |
| 161 | |
| 162 | ## Animation Concepts |
| 163 | |
| 164 | ### Shake/Vibrate |
| 165 | Offset object position with oscillation: |
| 166 | Use `math.sin()` or `math.cos()` with frame index |
| 167 | Add small random variations for natural feel |
| 168 | Apply to x and/or y position |
| 169 | |
| 170 | ### Pulse/Heartbeat |
| 171 | Scale object size rhythmically: |
| 172 | Use `math.sin(t * frequency * 2 * math.pi)` for smooth pulse |
| 173 | For heartbeat: two quick pulses then pause (adjust sine wave) |
| 174 | Scale between 0.8 and 1.2 of base size |
| 175 | |
| 176 | ### Bounce |
| 177 | Object falls and bounces: |
| 178 | Use `interpolate()` with `easing='bounce_out'` for landing |
| 179 | Use `easing='ease_in'` for falling (accelerating) |
| 180 | Apply gravity by increasing y velocity each frame |
| 181 | |
| 182 | ### Spin/Rotate |
| 183 | Rotate object around center: |
| 184 | PIL: `image.rotate(angle, resample=Image.BICUBIC)` |
| 185 | For wobble: use sine wave for angle instead of linear |
| 186 | |
| 187 | ### Fade In/Out |
| 188 | Gradually appear or disappear: |
| 189 | Create RGBA image, adjust alpha channel |
| 190 | Or use `Image.blend(image1, image2, alpha)` |
| 191 | Fade in: alpha from 0 to 1 |
| 192 | Fade out: alpha from 1 to 0 |
| 193 | |
| 194 | ### Slide |
| 195 | Move object from off-screen to position: |
| 196 | Start position: outside frame bounds |
| 197 | End position: target location |
| 198 | Use `interpolate()` with `easing='ease_out'` for smooth stop |
| 199 | For overshoot: use `easing='back_out'` |
| 200 | |
| 201 | ### Zoom |
| 202 | Scale and position for zoom effect: |
| 203 | Zoom in: scale from 0.1 to 2.0, crop center |
| 204 | Zoom out: scale from 2.0 to 1.0 |
| 205 | Can add motion blur for drama (PIL filter) |
| 206 | |
| 207 | ### Explode/Particle Burst |
| 208 | Create particles radiating outward: |
| 209 | Generate particles with random angles and velocities |
| 210 | Update each particle: `x += vx`, `y += vy` |
| 211 | Add gravity: `vy += gravity_constant` |
| 212 | Fade out particles over time (reduce alpha) |
| 213 | |
| 214 | ## Optimization Strategies |
| 215 | |
| 216 | Only when asked to make the file size smaller, implement a few of the following methods: |
| 217 | |
| 218 | **Fewer frames** - Lower FPS (10 instead of 20) or shorter duration |
| 219 | **Fewer colors** - `num_colors=48` instead of 128 |
| 220 | **Smaller dimensions** - 128x128 instead of 480x480 |
| 221 | **Remove duplicates** - `remove_duplicates=True` in save() |
| 222 | **Emoji mode** - `optimize_for_emoji=True` auto-optimizes |
| 223 | |
| 224 | |
| 225 | # Maximum optimization for emoji |
| 226 | builder.save( |
| 227 | 'emoji.gif', |
| 228 | num_colors=48, |
| 229 | optimize_for_emoji=True, |
| 230 | remove_duplicates=True |
| 231 | ) |
| 232 | |
| 233 | |
| 234 | ## Philosophy |
| 235 | |
| 236 | This skill provides: |
| 237 | **Knowledge**: Slack's requirements and animation concepts |
| 238 | **Utilities**: GIFBuilder, validators, easing functions |
| 239 | **Flexibility**: Create the animation logic using PIL primitives |
| 240 | |
| 241 | It does NOT provide: |
| 242 | Rigid animation templates or pre-made functions |
| 243 | Emoji font rendering (unreliable across platforms) |
| 244 | A library of pre-packaged graphics built into the skill |
| 245 | |
| 246 | **Note on user uploads**: This skill doesn't include pre-built graphics, but if a user uploads an image, use PIL to load and work with it - interpret based on their request whether they want it used directly or just as inspiration. |
| 247 | |
| 248 | Be creative! Combine concepts (bouncing + rotating, pulsing + sliding, etc.) and use PIL's full capabilities. |
| 249 | |
| 250 | ## Dependencies |
| 251 | |
| 252 | |
| 253 | pip install pillow imageio numpy |
| 254 | |
| 255 |
Discussion
Browse more free Claude skills.