mcpField
C
creating-slack-gifs

creating-slack-gifs

github.com/osmontero创意与媒体1678 次安装今天更新
代码仓库

关于 creating-slack-gifs

为 Slack GIF 制作提供知识与 Python 工具的技能,适用于需要绘制和优化动画的创作者。它包含 GIF 组装、验证、缓动和帧绘制辅助工具,并强调在实际尺寸下检查可辨识度。

主要功能

  1. 01GIFBuilder 帧组装与保存
  2. 02Slack 规格验证
  3. 03缓动函数与帧辅助工具
  4. 04PIL 图形绘制指导
  5. 05缩小尺寸与循环效果检查

适用场景

  1. 01制作 Slack 表情 GIF
  2. 02将上传图片制作成动画
  3. 03验证 GIF 规格及小尺寸可读性

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/osmontero/opencode-skills --skill creating-slack-gifs

安装后在 Claude Code 中输入/creating-slack-gifs确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

LICENSE.txt
core/
easing.py
frame_composer.py
gif_builder.py
validators.py

详细介绍


创建 Slack GIF

此技能提供用于创建符合 Slack 特定要求的动画 GIF 的实用工具和知识。

Slack 要求

尺寸:

  • 表情 GIF:128x128(推荐)
  • 消息 GIF:480x480

参数:

  • FPS:10-30(越低,文件越小)
  • 颜色:48-128(越少,文件越小)
  • 时长:表情 GIF 控制在 3 秒以内

核心工作流

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)

绘制图形

使用用户上传的图像

如果用户上传了图像,请考虑他们是想:

  • 直接使用(例如,“将其制作成动画”“将其拆分为帧”)
  • 以此为灵感(例如,“制作类似这样的内容”)

使用 PIL 加载并处理图像:

from PIL import Image

uploaded = Image.open('file.png')
# Use directly, or just as reference for colors/style
从头开始绘制

从头开始绘制图形时,请使用 PIL ImageDraw 基本图形:

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)

不要使用: Emoji 字体(跨平台表现不可靠),也不要假设此技能中包含预先打包的图形。

让图形更美观

图形应精致且富有创意,而不是简单粗糙。方法如下:

使用较粗的线条 - 绘制轮廓和线条时,始终设置 width=2 或更高。较细的线条(width=1)看起来会不流畅且显得业余。

增加视觉层次:

  • 为背景使用渐变(create_gradient_background)
  • 叠加多个形状以增加复杂度(例如,在一颗星星内再画一颗较小的星星)

让形状更有趣:

  • 不要只画一个普通圆形——添加高光、环形或图案
  • 可以为星星添加光晕(在后面绘制更大、半透明的星星)
  • 组合多个形状(星星 + 闪光、圆形 + 圆环)

注意颜色搭配:

  • 使用鲜艳、互补的颜色
  • 增加对比度(浅色形状配深色轮廓,深色形状配浅色轮廓)
  • 考虑整体构图

对于复杂形状(爱心、雪花等):

  • 组合使用多边形和椭圆
  • 仔细计算点的位置,确保对称
  • 添加细节(爱心可以有高光曲线,雪花可以有精巧的分支)

发挥创意,注重细节!优秀的 Slack GIF 应该看起来精致,而不是像占位图形。

可用工具

GIFBuilder(core.gif_builder)

组装帧并针对 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)

检查 GIF 是否符合 Slack 要求:

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)

让运动更加平滑,而非线性变化:

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)

为常见需求提供便捷函数:

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
)

动画概念

抖动/振动

通过振荡改变对象位置:

  • 使用 math.sin() 或 math.cos(),并传入帧索引
  • 添加少量随机变化,让效果更自然
  • 应用于 x 和/或 y 位置
脉动/心跳

有节奏地缩放对象:

  • 使用 math.sin(t * frequency * 2 * math.pi) 实现平滑脉动
  • 心跳效果:快速脉动两次,然后暂停(调整正弦波)
  • 在基础尺寸的 0.8 到 1.2 倍之间缩放
弹跳

对象下落并弹起:

  • 使用 interpolate(),并设置 easing='bounce_out' 实现落地效果
  • 下落时使用 easing='ease_in'(逐渐加速)
  • 每帧增加 y 方向速度以模拟重力
旋转

围绕中心旋转对象:

  • PIL:image.rotate(angle, resample=Image.BICUBIC)
  • 摇摆效果:使用正弦波改变角度,而非线性变化
淡入/淡出

逐渐显现或消失:

  • 创建 RGBA 图像并调整 alpha 通道
  • 或使用 Image.blend(image1, image2, alpha)
  • 淡入:alpha 从 0 变为 1
  • 淡出:alpha 从 1 变为 0
滑动

将对象从屏幕外移至指定位置:

  • 起始位置:画面边界之外
  • 结束位置:目标位置
  • 使用 interpolate(),并设置 easing='ease_out' 实现平滑停止
  • 要实现过冲效果,请使用 easing='back_out'
缩放

通过缩放和定位实现缩放效果:

  • 放大:从 0.1 缩放至 2.0,并裁剪中心部分
  • 缩小:从 2.0 缩放至 1.0
  • 可添加运动模糊增强戏剧效果(PIL 滤镜)
爆炸/粒子喷发

创建向外辐射的粒子:

  • 以随机角度和速度生成粒子
  • 更新每个粒子:x += vx、y += vy
  • 添加重力:vy += gravity_constant
  • 随时间淡出粒子(降低 alpha)

优化策略

仅在用户要求缩小文件体积时,才采用以下几种方法:

  1. 减少帧数 - 降低 FPS(例如 10 而不是 20)或缩短时长
  2. 减少颜色 - 使用 num_colors=48 而不是 128
  3. 缩小尺寸 - 使用 128x128 而不是 480x480
  4. 移除重复帧 - 在 save() 中使用 remove_duplicates=True
  5. 表情符号模式 - 使用 optimize_for_emoji=True 自动优化
# Maximum optimization for emoji
builder.save(
    'emoji.gif',
    num_colors=48,
    optimize_for_emoji=True,
    remove_duplicates=True
)

理念

此技能提供:

  • 知识:Slack 的要求和动画概念
  • 实用工具:GIFBuilder、验证器、缓动函数
  • 灵活性:使用 PIL 基元创建动画逻辑

此技能不提供:

  • 固定的动画模板或预制函数
  • 表情符号字体渲染(在不同平台上的表现不可靠)
  • 技能内置的预制图形库

关于用户上传内容的说明:此技能不包含预制图形,但如果用户上传了图片,请使用 PIL 加载并处理图片;根据用户的请求判断他们是想直接使用图片,还是仅将其作为灵感。

发挥创意!组合不同概念(弹跳 + 旋转、脉动 + 滑动等),充分运用 PIL 的功能。

验证 — 展示前

Slack 消息中的表情符号显示尺寸大约为 22×22 px。一张 128×128 的设计图即使以原尺寸查看时很清晰,在实际显示尺寸下也可能变成难以辨认的一团;这是最常见的问题。

from PIL import Image
from core.validators import validate_gif

passes, info = validate_gif('out.gif', is_emoji=True, verbose=True)
print(info)                       # dimensions, frame count, file size, color count

# What Slack actually shows — inspect this, not the 128px version
im = Image.open('out.gif')
im.seek(0); im.convert('RGB').resize((22, 22), Image.LANCZOS).resize(
    (176, 176), Image.NEAREST).save('/tmp/emoji-actual-size.png')

读取 /tmp/emoji-actual-size.png,并确认主体仍可辨认。然后检查:

  • 在 22px 下仍可辨认。 轮廓要清晰。小于约 4px 的描边细节会完全消失。
  • 在两种背景下都清晰。 Slack 有浅色和深色主题——检查 GIF 在 #ffffff 和 #1a1d21 背景上的效果。深色主体在透明背景上会在深色模式中消失。
  • 循环流畅。 最后一帧必须自然衔接第一帧。循环图像每次重复时出现明显跳变,是最令人分心的缺陷。
  • 表情符号小于 128 KB(Slack 的硬性限制),消息 GIF 小于 2 MB。
  • 快速播放时动作仍清晰。 以 10 fps 播放时,12 帧动画时长为 1.2s。如果关键瞬间只占 2 帧,就没人能看清。
  • 闪烁频率不超过 3 Hz。 快速闪烁的表情符号会在繁忙频道中造成真实的癫痫风险。

无缝循环检查——对于循环动画,第一帧和最后一帧应当几乎相同:

import numpy as np
frames = []
im = Image.open('out.gif')
for i in range(im.n_frames):
    im.seek(i); frames.append(np.asarray(im.convert('RGB'), dtype=float))
delta = np.abs(frames[0] - frames[-1]).mean()
print(f"loop seam delta: {delta:.1f}")     # under ~6 is a clean cycle

先决条件

运行任何 Python 脚本前,请激活 opencode 虚拟环境:

source ~/.local/opencode-venv/bin/activate

然后正常使用 python3 core/...。所有依赖项(Pillow、imageio、imageio-ffmpeg、numpy)均由 opencode Python venv 集中管理。

相关技能

  • designing-frontend-interfaces — designing-frontend-interfaces/references/motion.md 介绍缓动方式的选择和编排;designing-frontend-interfaces/references/color-and-theme.md 介绍如何构建能适应 48 色量化的调色板
  • designing-canvas-art — canvas-fonts/ 提供 GIF 需要文字时可用的真实字体;designing-canvas-art/references/rendering.md 介绍 PIL 合成技巧

评论

支持 Markdown