slack-gif-creator

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Slack GIF Creator - Flexible Toolkit

Slack GIF 创建工具包 - 灵活的动图制作工具

A toolkit for creating animated GIFs optimized for Slack. Provides validators for Slack's constraints, composable animation primitives, and optional helper utilities. Apply these tools however needed to achieve the creative vision.
一款专为Slack优化的动图GIF创建工具包,包含Slack约束验证器、可组合的动画基础组件以及可选的辅助工具。可根据创意需求灵活使用这些工具。

Slack's Requirements

Slack的要求

Slack has specific requirements for GIFs based on their use:
Message GIFs:
  • Max size: ~2MB
  • Optimal dimensions: 480x480
  • Typical FPS: 15-20
  • Color limit: 128-256
  • Duration: 2-5s
Emoji GIFs:
  • Max size: 64KB (strict limit)
  • Optimal dimensions: 128x128
  • Typical FPS: 10-12
  • Color limit: 32-48
  • Duration: 1-2s
Emoji GIFs are challenging - the 64KB limit is strict. Strategies that help:
  • Limit to 10-15 frames total
  • Use 32-48 colors maximum
  • Keep designs simple
  • Avoid gradients
  • Validate file size frequently
Slack根据动图的使用场景制定了特定要求:
消息动图:
  • 最大文件大小:约2MB
  • 最佳尺寸:480x480
  • 典型帧率(FPS):15-20
  • 颜色限制:128-256色
  • 时长:2-5秒
表情动图:
  • 最大文件大小:64KB(严格限制)
  • 最佳尺寸:128x128
  • 典型帧率(FPS):10-12
  • 颜色限制:32-48色
  • 时长:1-2秒
表情动图制作难度较高——64KB的限制非常严格。以下策略可帮助压缩大小:
  • 总帧数限制在10-15帧
  • 最多使用32-48种颜色
  • 保持设计简洁
  • 避免使用渐变
  • 频繁验证文件大小

Toolkit Structure

工具包结构

This skill provides three types of tools:
  1. Validators - Check if a GIF meets Slack's requirements
  2. Animation Primitives - Composable building blocks for motion (shake, bounce, move, kaleidoscope)
  3. Helper Utilities - Optional functions for common needs (text, colors, effects)
Complete creative freedom is available in how these tools are applied.
本工具提供三类工具:
  1. 验证器 - 检查GIF是否符合Slack的要求
  2. 动画基础组件 - 可组合的动画构建模块(摇晃、弹跳、移动、万花筒效果等)
  3. 辅助工具 - 满足常见需求的可选功能(文本、颜色、特效)
可完全自由地组合使用这些工具。

Core Validators

核心验证器

To ensure a GIF meets Slack's constraints, use these validators:
python
from core.gif_builder import GIFBuilder
为确保GIF符合Slack的约束,请使用以下验证器:
python
from core.gif_builder import GIFBuilder

After creating your GIF, check if it meets requirements

创建GIF后,检查是否符合要求

builder = GIFBuilder(width=128, height=128, fps=10)
builder = GIFBuilder(width=128, height=128, fps=10)

... add your frames however you want ...

... 按需添加帧 ...

Save and check size

保存并检查大小

info = builder.save('emoji.gif', num_colors=48, optimize_for_emoji=True)
info = builder.save('emoji.gif', num_colors=48, optimize_for_emoji=True)

The save method automatically warns if file exceeds limits

保存方法会在文件超出限制时自动发出警告

info dict contains: size_kb, size_mb, frame_count, duration_seconds

info字典包含:size_kb, size_mb, frame_count, duration_seconds


**File size validator**:
```python
from core.validators import check_slack_size

**文件大小验证器**:
```python
from core.validators import check_slack_size

Check if GIF meets size limits

检查GIF是否符合大小限制

passes, info = check_slack_size('emoji.gif', is_emoji=True)
passes, info = check_slack_size('emoji.gif', is_emoji=True)

Returns: (True/False, dict with size details)

返回值:(True/False, 包含大小详情的字典)


**Dimension validator**:
```python
from core.validators import validate_dimensions

**尺寸验证器**:
```python
from core.validators import validate_dimensions

Check dimensions

检查尺寸

passes, info = validate_dimensions(128, 128, is_emoji=True)
passes, info = validate_dimensions(128, 128, is_emoji=True)

Returns: (True/False, dict with dimension details)

返回值:(True/False, 包含尺寸详情的字典)


**Complete validation**:
```python
from core.validators import validate_gif, is_slack_ready

**完整验证**:
```python
from core.validators import validate_gif, is_slack_ready

Run all validations

运行所有验证

all_pass, results = validate_gif('emoji.gif', is_emoji=True)
all_pass, results = validate_gif('emoji.gif', is_emoji=True)

Or quick check

或快速检查

if is_slack_ready('emoji.gif', is_emoji=True): print("Ready to upload!")
undefined
if is_slack_ready('emoji.gif', is_emoji=True): print("可上传至Slack!")
undefined

Animation Primitives

动画基础组件

These are composable building blocks for motion. Apply these to any object in any combination:
这些是可组合的动画构建模块,可应用于任意对象的任意组合:

Shake

摇晃

python
from templates.shake import create_shake_animation
python
from templates.shake import create_shake_animation

Shake an emoji

让表情摇晃

frames = create_shake_animation( object_type='emoji', object_data={'emoji': '😱', 'size': 80}, num_frames=20, shake_intensity=15, direction='both' # or 'horizontal', 'vertical' )
undefined
frames = create_shake_animation( object_type='emoji', object_data={'emoji': '😱', 'size': 80}, num_frames=20, shake_intensity=15, direction='both' # 可选:'horizontal'(水平), 'vertical'(垂直) )
undefined

Bounce

弹跳

python
from templates.bounce import create_bounce_animation
python
from templates.bounce import create_bounce_animation

Bounce a circle

让圆形弹跳

frames = create_bounce_animation( object_type='circle', object_data={'radius': 40, 'color': (255, 100, 100)}, num_frames=30, bounce_height=150 )
undefined
frames = create_bounce_animation( object_type='circle', object_data={'radius': 40, 'color': (255, 100, 100)}, num_frames=30, bounce_height=150 )
undefined

Spin / Rotate

旋转

python
from templates.spin import create_spin_animation, create_loading_spinner
python
from templates.spin import create_spin_animation, create_loading_spinner

Clockwise spin

顺时针旋转

frames = create_spin_animation( object_type='emoji', object_data={'emoji': '🔄', 'size': 100}, rotation_type='clockwise', full_rotations=2 )
frames = create_spin_animation( object_type='emoji', object_data={'emoji': '🔄', 'size': 100}, rotation_type='clockwise', full_rotations=2 )

Wobble rotation

摇摆旋转

frames = create_spin_animation(rotation_type='wobble', full_rotations=3)
frames = create_spin_animation(rotation_type='wobble', full_rotations=3)

Loading spinner

加载动画

frames = create_loading_spinner(spinner_type='dots')
undefined
frames = create_loading_spinner(spinner_type='dots')
undefined

Pulse / Heartbeat

脉冲/心跳

python
from templates.pulse import create_pulse_animation, create_attention_pulse
python
from templates.pulse import create_pulse_animation, create_attention_pulse

Smooth pulse

平滑脉冲

frames = create_pulse_animation( object_data={'emoji': '❤️', 'size': 100}, pulse_type='smooth', scale_range=(0.8, 1.2) )
frames = create_pulse_animation( object_data={'emoji': '❤️', 'size': 100}, pulse_type='smooth', scale_range=(0.8, 1.2) )

Heartbeat (double-pump)

心跳(双脉冲)

frames = create_pulse_animation(pulse_type='heartbeat')
frames = create_pulse_animation(pulse_type='heartbeat')

Attention pulse for emoji GIFs

表情动图的提醒脉冲

frames = create_attention_pulse(emoji='⚠️', num_frames=20)
undefined
frames = create_attention_pulse(emoji='⚠️', num_frames=20)
undefined

Fade

淡入淡出

python
from templates.fade import create_fade_animation, create_crossfade
python
from templates.fade import create_fade_animation, create_crossfade

Fade in

淡入

frames = create_fade_animation(fade_type='in')
frames = create_fade_animation(fade_type='in')

Fade out

淡出

frames = create_fade_animation(fade_type='out')
frames = create_fade_animation(fade_type='out')

Crossfade between two emojis

两个表情之间的交叉淡入淡出

frames = create_crossfade( object1_data={'emoji': '😊', 'size': 100}, object2_data={'emoji': '😂', 'size': 100} )
undefined
frames = create_crossfade( object1_data={'emoji': '😊', 'size': 100}, object2_data={'emoji': '😂', 'size': 100} )
undefined

Zoom

缩放

python
from templates.zoom import create_zoom_animation, create_explosion_zoom
python
from templates.zoom import create_zoom_animation, create_explosion_zoom

Zoom in dramatically

大幅放大

frames = create_zoom_animation( zoom_type='in', scale_range=(0.1, 2.0), add_motion_blur=True )
frames = create_zoom_animation( zoom_type='in', scale_range=(0.1, 2.0), add_motion_blur=True )

Zoom out

缩小

frames = create_zoom_animation(zoom_type='out')
frames = create_zoom_animation(zoom_type='out')

Explosion zoom

爆炸式缩放

frames = create_explosion_zoom(emoji='💥')
undefined
frames = create_explosion_zoom(emoji='💥')
undefined

Explode / Shatter

爆炸/碎裂

python
from templates.explode import create_explode_animation, create_particle_burst
python
from templates.explode import create_explode_animation, create_particle_burst

Burst explosion

爆发式爆炸

frames = create_explode_animation( explode_type='burst', num_pieces=25 )
frames = create_explode_animation( explode_type='burst', num_pieces=25 )

Shatter effect

碎裂效果

frames = create_explode_animation(explode_type='shatter')
frames = create_explode_animation(explode_type='shatter')

Dissolve into particles

溶解为粒子

frames = create_explode_animation(explode_type='dissolve')
frames = create_explode_animation(explode_type='dissolve')

Particle burst

粒子爆发

frames = create_particle_burst(particle_count=30)
undefined
frames = create_particle_burst(particle_count=30)
undefined

Wiggle / Jiggle

扭动/抖动

python
from templates.wiggle import create_wiggle_animation, create_excited_wiggle
python
from templates.wiggle import create_wiggle_animation, create_excited_wiggle

Jello wobble

果冻晃动

frames = create_wiggle_animation( wiggle_type='jello', intensity=1.0, cycles=2 )
frames = create_wiggle_animation( wiggle_type='jello', intensity=1.0, cycles=2 )

Wave motion

波浪运动

frames = create_wiggle_animation(wiggle_type='wave')
frames = create_wiggle_animation(wiggle_type='wave')

Excited wiggle for emoji GIFs

表情动图的兴奋抖动

frames = create_excited_wiggle(emoji='🎉')
undefined
frames = create_excited_wiggle(emoji='🎉')
undefined

Slide

滑动

python
from templates.slide import create_slide_animation, create_multi_slide
python
from templates.slide import create_slide_animation, create_multi_slide

Slide in from left with overshoot

从左侧滑入并带过冲效果

frames = create_slide_animation( direction='left', slide_type='in', overshoot=True )
frames = create_slide_animation( direction='left', slide_type='in', overshoot=True )

Slide across

横向滑动

frames = create_slide_animation(direction='left', slide_type='across')
frames = create_slide_animation(direction='left', slide_type='across')

Multiple objects sliding in sequence

多个对象按顺序滑动

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)
undefined
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)
undefined

Flip

翻转

python
from templates.flip import create_flip_animation, create_quick_flip
python
from templates.flip import create_flip_animation, create_quick_flip

Horizontal flip between two emojis

两个表情之间的水平翻转

frames = create_flip_animation( object1_data={'emoji': '😊', 'size': 120}, object2_data={'emoji': '😂', 'size': 120}, flip_axis='horizontal' )
frames = create_flip_animation( object1_data={'emoji': '😊', 'size': 120}, object2_data={'emoji': '😂', 'size': 120}, flip_axis='horizontal' )

Vertical flip

垂直翻转

frames = create_flip_animation(flip_axis='vertical')
frames = create_flip_animation(flip_axis='vertical')

Quick flip for emoji GIFs

表情动图的快速翻转

frames = create_quick_flip('👍', '👎')
undefined
frames = create_quick_flip('👍', '👎')
undefined

Morph / Transform

变形/转换

python
from templates.morph import create_morph_animation, create_reaction_morph
python
from templates.morph import create_morph_animation, create_reaction_morph

Crossfade morph

交叉淡入淡出变形

frames = create_morph_animation( object1_data={'emoji': '😊', 'size': 100}, object2_data={'emoji': '😂', 'size': 100}, morph_type='crossfade' )
frames = create_morph_animation( object1_data={'emoji': '😊', 'size': 100}, object2_data={'emoji': '😂', 'size': 100}, morph_type='crossfade' )

Scale morph (shrink while other grows)

缩放变形(一个缩小同时另一个放大)

frames = create_morph_animation(morph_type='scale')
frames = create_morph_animation(morph_type='scale')

Spin morph (3D flip-like)

旋转变形(类3D翻转)

frames = create_morph_animation(morph_type='spin_morph')
undefined
frames = create_morph_animation(morph_type='spin_morph')
undefined

Move Effect

移动效果

python
from templates.move import create_move_animation
python
from templates.move import create_move_animation

Linear movement

线性移动

frames = create_move_animation( object_type='emoji', object_data={'emoji': '🚀', 'size': 60}, start_pos=(50, 240), end_pos=(430, 240), motion_type='linear', easing='ease_out' )
frames = create_move_animation( object_type='emoji', object_data={'emoji': '🚀', 'size': 60}, start_pos=(50, 240), end_pos=(430, 240), motion_type='linear', easing='ease_out' )

Arc movement (parabolic trajectory)

弧线移动(抛物线轨迹)

frames = create_move_animation( object_type='emoji', object_data={'emoji': '⚽', 'size': 60}, start_pos=(50, 350), end_pos=(430, 350), motion_type='arc', motion_params={'arc_height': 150} )
frames = create_move_animation( object_type='emoji', object_data={'emoji': '⚽', 'size': 60}, start_pos=(50, 350), end_pos=(430, 350), motion_type='arc', motion_params={'arc_height': 150} )

Circular movement

圆周移动

frames = create_move_animation( object_type='emoji', object_data={'emoji': '🌍', 'size': 50}, motion_type='circle', motion_params={ 'center': (240, 240), 'radius': 120, 'angle_range': 360 # full circle } )
frames = create_move_animation( object_type='emoji', object_data={'emoji': '🌍', 'size': 50}, motion_type='circle', motion_params={ 'center': (240, 240), 'radius': 120, 'angle_range': 360 # 完整圆周 } )

Wave movement

波浪移动

frames = create_move_animation( motion_type='wave', motion_params={ 'wave_amplitude': 50, 'wave_frequency': 2 } )
frames = create_move_animation( motion_type='wave', motion_params={ 'wave_amplitude': 50, 'wave_frequency': 2 } )

Or use low-level easing functions

或使用底层缓动函数

from core.easing import interpolate, calculate_arc_motion
for i in range(num_frames): t = i / (num_frames - 1) x = interpolate(start_x, end_x, t, easing='ease_out') # Or: x, y = calculate_arc_motion(start, end, height, t)
undefined
from core.easing import interpolate, calculate_arc_motion
for i in range(num_frames): t = i / (num_frames - 1) x = interpolate(start_x, end_x, t, easing='ease_out') # 或:x, y = calculate_arc_motion(start, end, height, t)
undefined

Kaleidoscope Effect

万花筒效果

python
from templates.kaleidoscope import apply_kaleidoscope, create_kaleidoscope_animation
python
from templates.kaleidoscope import apply_kaleidoscope, create_kaleidoscope_animation

Apply to a single frame

应用到单帧

kaleido_frame = apply_kaleidoscope(frame, segments=8)
kaleido_frame = apply_kaleidoscope(frame, segments=8)

Or create animated kaleidoscope

或创建万花筒动画

frames = create_kaleidoscope_animation( base_frame=my_frame, # or None for demo pattern num_frames=30, segments=8, rotation_speed=1.0 )
frames = create_kaleidoscope_animation( base_frame=my_frame, # 或传入None使用演示图案 num_frames=30, segments=8, rotation_speed=1.0 )

Simple mirror effects (faster)

简单镜像效果(速度更快)

from templates.kaleidoscope import apply_simple_mirror
mirrored = apply_simple_mirror(frame, mode='quad') # 4-way mirror
from templates.kaleidoscope import apply_simple_mirror
mirrored = apply_simple_mirror(frame, mode='quad') # 4向镜像

modes: 'horizontal', 'vertical', 'quad', 'radial'

模式可选:'horizontal'(水平), 'vertical'(垂直), 'quad'(四向), 'radial'(径向)


**To compose primitives freely, follow these patterns:**
```python

**如需自由组合基础组件,请遵循以下模式:**
```python

Example: Bounce + shake for impact

示例:弹跳+摇晃增强冲击力

for i in range(num_frames): frame = create_blank_frame(480, 480, bg_color)
# Bounce motion
t_bounce = i / (num_frames - 1)
y = interpolate(start_y, ground_y, t_bounce, 'bounce_out')

# Add shake on impact (when y reaches ground)
if y >= ground_y - 5:
    shake_x = math.sin(i * 2) * 10
    x = center_x + shake_x
else:
    x = center_x

draw_emoji(frame, '⚽', (x, y), size=60)
builder.add_frame(frame)
undefined
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')

# 触地时添加摇晃(当y接近地面时)
if y >= ground_y - 5:
    shake_x = math.sin(i * 2) * 10
    x = center_x + shake_x
else:
    x = center_x

draw_emoji(frame, '⚽', (x, y), size=60)
builder.add_frame(frame)
undefined

Helper Utilities

辅助工具

These are optional helpers for common needs. Use, modify, or replace these with custom implementations as needed.
这些是满足常见需求的可选工具。可根据需要使用、修改或替换为自定义实现。

GIF Builder (Assembly & Optimization)

GIF构建器(组装与优化)

python
from core.gif_builder import GIFBuilder
python
from core.gif_builder import GIFBuilder

Create builder with your chosen settings

使用自定义设置创建构建器

builder = GIFBuilder(width=480, height=480, fps=20)
builder = GIFBuilder(width=480, height=480, fps=20)

Add frames (however you created them)

添加帧(无论你如何创建的帧)

for frame in my_frames: builder.add_frame(frame)
for frame in my_frames: builder.add_frame(frame)

Save with optimization

带优化保存

builder.save('output.gif', num_colors=128, optimize_for_emoji=False)

Key features:
- Automatic color quantization
- Duplicate frame removal
- Size warnings for Slack limits
- Emoji mode (aggressive optimization)
builder.save('output.gif', num_colors=128, optimize_for_emoji=False)

核心特性:
- 自动颜色量化
- 重复帧移除
- Slack大小限制警告
- 表情模式(深度优化)

Text Rendering

文本渲染

For small GIFs like emojis, text readability is challenging. A common solution involves adding outlines:
python
from core.typography import draw_text_with_outline, TYPOGRAPHY_SCALE
对于表情动图这类小尺寸GIF,文本可读性是一大挑战。常用解决方案是添加轮廓:
python
from core.typography import draw_text_with_outline, TYPOGRAPHY_SCALE

Text with outline (helps readability)

带轮廓的文本(提升可读性)

draw_text_with_outline( frame, "BONK!", position=(240, 100), font_size=TYPOGRAPHY_SCALE['h1'], # 60px text_color=(255, 68, 68), outline_color=(0, 0, 0), outline_width=4, centered=True )

To implement custom text rendering, use PIL's `ImageDraw.text()` which works fine for larger GIFs.
draw_text_with_outline( frame, "BONK!", position=(240, 100), font_size=TYPOGRAPHY_SCALE['h1'], # 60px text_color=(255, 68, 68), outline_color=(0, 0, 0), outline_width=4, centered=True )

如需实现自定义文本渲染,可使用PIL的`ImageDraw.text()`,它在大尺寸GIF上表现良好。

Color Management

颜色管理

Professional-looking GIFs often use cohesive color palettes:
python
from core.color_palettes import get_palette
专业的GIF通常使用协调的调色板:
python
from core.color_palettes import get_palette

Get a pre-made palette

获取预制调色板

palette = get_palette('vibrant') # or 'pastel', 'dark', 'neon', 'professional'
bg_color = palette['background'] text_color = palette['primary'] accent_color = palette['accent']

To work with colors directly, use RGB tuples - whatever works for the use case.
palette = get_palette('vibrant') # 可选:'pastel'(马卡龙), 'dark'(深色), 'neon'(霓虹), 'professional'(专业)
bg_color = palette['background'] text_color = palette['primary'] accent_color = palette['accent']

如需直接操作颜色,可使用RGB元组——根据需求选择即可。

Visual Effects

视觉特效

Optional effects for impact moments:
python
from core.visual_effects import ParticleSystem, create_impact_flash, create_shockwave_rings
用于增强冲击力的可选特效:
python
from core.visual_effects import ParticleSystem, create_impact_flash, create_shockwave_rings

Particle system

粒子系统

particles = ParticleSystem() particles.emit_sparkles(x=240, y=200, count=15) particles.emit_confetti(x=240, y=200, count=20)
particles = ParticleSystem() particles.emit_sparkles(x=240, y=200, count=15) particles.emit_confetti(x=240, y=200, count=20)

Update and render each frame

更新并渲染每帧

particles.update() particles.render(frame)
particles.update() particles.render(frame)

Flash effect

闪光效果

frame = create_impact_flash(frame, position=(240, 200), radius=100)
frame = create_impact_flash(frame, position=(240, 200), radius=100)

Shockwave rings

冲击波环

frame = create_shockwave_rings(frame, position=(240, 200), radii=[30, 60, 90])
undefined
frame = create_shockwave_rings(frame, position=(240, 200), radii=[30, 60, 90])
undefined

Easing Functions

缓动函数

Smooth motion uses easing instead of linear interpolation:
python
from core.easing import interpolate
平滑运动需使用缓动而非线性插值:
python
from core.easing import interpolate

Object falling (accelerates)

物体下落(加速)

y = interpolate(start=0, end=400, t=progress, easing='ease_in')
y = interpolate(start=0, end=400, t=progress, easing='ease_in')

Object landing (decelerates)

物体落地(减速)

y = interpolate(start=0, end=400, t=progress, easing='ease_out')
y = interpolate(start=0, end=400, t=progress, easing='ease_out')

Bouncing

弹跳

y = interpolate(start=0, end=400, t=progress, easing='bounce_out')
y = interpolate(start=0, end=400, t=progress, easing='bounce_out')

Overshoot (elastic)

过冲(弹性)

scale = interpolate(start=0.5, end=1.0, t=progress, easing='elastic_out')

Available easings: `linear`, `ease_in`, `ease_out`, `ease_in_out`, `bounce_out`, `elastic_out`, `back_out` (overshoot), and more in `core/easing.py`.
scale = interpolate(start=0.5, end=1.0, t=progress, easing='elastic_out')

可用缓动类型:`linear`(线性)、`ease_in`(淡入)、`ease_out`(淡出)、`ease_in_out`(淡入淡出)、`bounce_out`(弹跳)、`elastic_out`(弹性)、`back_out`(过冲)等,更多请查看`core/easing.py`。

Frame Composition

帧合成

Basic drawing utilities if you need them:
python
from core.frame_composer import (
    create_gradient_background,  # Gradient backgrounds
    draw_emoji_enhanced,         # Emoji with optional shadow
    draw_circle_with_shadow,     # Shapes with depth
    draw_star                    # 5-pointed stars
)
如需基础绘图工具,可使用以下工具:
python
from core.frame_composer import (
    create_gradient_background,  # 渐变背景
    draw_emoji_enhanced,         # 带可选阴影的表情
    draw_circle_with_shadow,     # 带深度的形状
    draw_star                    # 五角星
)

Gradient background

渐变背景

frame = create_gradient_background(480, 480, top_color, bottom_color)
frame = create_gradient_background(480, 480, top_color, bottom_color)

Emoji with shadow

带阴影的表情

draw_emoji_enhanced(frame, '🎉', position=(200, 200), size=80, shadow=True)
undefined
draw_emoji_enhanced(frame, '🎉', position=(200, 200), size=80, shadow=True)
undefined

Optimization Strategies

优化策略

When your GIF is too large:
For Message GIFs (>2MB):
  1. Reduce frames (lower FPS or shorter duration)
  2. Reduce colors (128 → 64 colors)
  3. Reduce dimensions (480x480 → 320x320)
  4. Enable duplicate frame removal
For Emoji GIFs (>64KB) - be aggressive:
  1. Limit to 10-12 frames total
  2. Use 32-40 colors maximum
  3. Avoid gradients (solid colors compress better)
  4. Simplify design (fewer elements)
  5. Use
    optimize_for_emoji=True
    in save method
当GIF文件过大时:
消息动图(>2MB):
  1. 减少帧数(降低帧率或缩短时长)
  2. 减少颜色(从128色→64色)
  3. 缩小尺寸(从480x480→320x320)
  4. 启用重复帧移除
表情动图(>64KB)——需激进优化:
  1. 总帧数限制在10-12帧
  2. 最多使用32-40种颜色
  3. 避免渐变(纯色压缩效果更好)
  4. 简化设计(减少元素)
  5. 保存时使用
    optimize_for_emoji=True
    参数

Example Composition Patterns

示例组合模式

Simple Reaction (Pulsing)

简单反应动图(脉冲)

python
builder = GIFBuilder(128, 128, 10)

for i in range(12):
    frame = Image.new('RGB', (128, 128), (240, 248, 255))

    # Pulsing scale
    scale = 1.0 + math.sin(i * 0.5) * 0.15
    size = int(60 * scale)

    draw_emoji_enhanced(frame, '😱', position=(64-size//2, 64-size//2),
                       size=size, shadow=False)
    builder.add_frame(frame)

builder.save('reaction.gif', num_colors=40, optimize_for_emoji=True)
python
builder = GIFBuilder(128, 128, 10)

for i in range(12):
    frame = Image.new('RGB', (128, 128), (240, 248, 255))

    # 脉冲缩放
    scale = 1.0 + math.sin(i * 0.5) * 0.15
    size = int(60 * scale)

    draw_emoji_enhanced(frame, '😱', position=(64-size//2, 64-size//2),
                       size=size, shadow=False)
    builder.add_frame(frame)

builder.save('reaction.gif', num_colors=40, optimize_for_emoji=True)

Validate

验证

from core.validators import check_slack_size check_slack_size('reaction.gif', is_emoji=True)
undefined
from core.validators import check_slack_size check_slack_size('reaction.gif', is_emoji=True)
undefined

Action with Impact (Bounce + Flash)

带冲击力的动作(弹跳+闪光)

python
builder = GIFBuilder(480, 480, 20)
python
builder = GIFBuilder(480, 480, 20)

Phase 1: Object falls

阶段1:物体下落

for i in range(15): frame = create_gradient_background(480, 480, (240, 248, 255), (200, 230, 255)) t = i / 14 y = interpolate(0, 350, t, 'ease_in') draw_emoji_enhanced(frame, '⚽', position=(220, int(y)), size=80) builder.add_frame(frame)
for i in range(15): frame = create_gradient_background(480, 480, (240, 248, 255), (200, 230, 255)) t = i / 14 y = interpolate(0, 350, t, 'ease_in') draw_emoji_enhanced(frame, '⚽', position=(220, int(y)), size=80) builder.add_frame(frame)

Phase 2: Impact + flash

阶段2:撞击+闪光

for i in range(8): frame = create_gradient_background(480, 480, (240, 248, 255), (200, 230, 255))
# Flash on first frames
if i < 3:
    frame = create_impact_flash(frame, (240, 350), radius=120, intensity=0.6)

draw_emoji_enhanced(frame, '⚽', position=(220, 350), size=80)

# Text appears
if i > 2:
    draw_text_with_outline(frame, "GOAL!", position=(240, 150),
                          font_size=60, text_color=(255, 68, 68),
                          outline_color=(0, 0, 0), outline_width=4, centered=True)

builder.add_frame(frame)
builder.save('goal.gif', num_colors=128)
undefined
for i in range(8): frame = create_gradient_background(480, 480, (240, 248, 255), (200, 230, 255))
# 前几帧添加闪光
if i < 3:
    frame = create_impact_flash(frame, (240, 350), radius=120, intensity=0.6)

draw_emoji_enhanced(frame, '⚽', position=(220, 350), size=80)

# 后续帧显示文本
if i > 2:
    draw_text_with_outline(frame, "GOAL!", position=(240, 150),
                          font_size=60, text_color=(255, 68, 68),
                          outline_color=(0, 0, 0), outline_width=4, centered=True)

builder.add_frame(frame)
builder.save('goal.gif', num_colors=128)
undefined

Combining Primitives (Move + Shake)

组合基础组件(移动+摇晃)

python
from templates.shake import create_shake_animation
python
from templates.shake import create_shake_animation

Create shake animation

创建摇晃动画

shake_frames = create_shake_animation( object_type='emoji', object_data={'emoji': '😰', 'size': 70}, num_frames=20, shake_intensity=12 )
shake_frames = create_shake_animation( object_type='emoji', object_data={'emoji': '😰', 'size': 70}, num_frames=20, shake_intensity=12 )

Create moving element that triggers the shake

创建触发摇晃的移动元素

builder = GIFBuilder(480, 480, 20) for i in range(40): t = i / 39
if i < 20:
    # Before trigger - use blank frame with moving object
    frame = create_blank_frame(480, 480, (255, 255, 255))
    x = interpolate(50, 300, t * 2, 'linear')
    draw_emoji_enhanced(frame, '🚗', position=(int(x), 300), size=60)
    draw_emoji_enhanced(frame, '😰', position=(350, 200), size=70)
else:
    # After trigger - use shake frame
    frame = shake_frames[i - 20]
    # Add the car in final position
    draw_emoji_enhanced(frame, '🚗', position=(300, 300), size=60)

builder.add_frame(frame)
builder.save('scare.gif')
undefined
builder = GIFBuilder(480, 480, 20) for i in range(40): t = i / 39
if i < 20:
    # 触发前 - 空白帧+移动对象
    frame = create_blank_frame(480, 480, (255, 255, 255))
    x = interpolate(50, 300, t * 2, 'linear')
    draw_emoji_enhanced(frame, '🚗', position=(int(x), 300), size=60)
    draw_emoji_enhanced(frame, '😰', position=(350, 200), size=70)
else:
    # 触发后 - 使用摇晃帧
    frame = shake_frames[i - 20]
    # 添加处于最终位置的汽车
    draw_emoji_enhanced(frame, '🚗', position=(300, 300), size=60)

builder.add_frame(frame)
builder.save('scare.gif')
undefined

Philosophy

设计理念

This toolkit provides building blocks, not rigid recipes. To work with a GIF request:
  1. Understand the creative vision - What should happen? What's the mood?
  2. Design the animation - Break it into phases (anticipation, action, reaction)
  3. Apply primitives as needed - Shake, bounce, move, effects - mix freely
  4. Validate constraints - Check file size, especially for emoji GIFs
  5. Iterate if needed - Reduce frames/colors if over size limits
The goal is creative freedom within Slack's technical constraints.
本工具包提供构建模块,而非固定模板。处理GIF请求时请遵循以下步骤:
  1. 理解创意需求 - 要呈现什么内容?氛围如何?
  2. 设计动画 - 将动画拆分为多个阶段(铺垫、动作、反应)
  3. 按需应用基础组件 - 摇晃、弹跳、移动、特效——自由组合
  4. 验证约束 - 检查文件大小,尤其是表情动图
  5. 按需迭代 - 若超出大小限制,减少帧数/颜色
目标是在Slack的技术约束内实现创意自由。

Dependencies

依赖项

To use this toolkit, install these dependencies only if they aren't already present:
bash
pip install pillow imageio numpy
如需使用本工具包,若尚未安装以下依赖项,请执行安装:
bash
pip install pillow imageio numpy