Slack GIF Creator - フレキシブルツールキット
Slack用に最適化されたアニメーションGIFを作成するためのツールキットです。Slackの制約をチェックするバリデータ、合成可能なアニメーションプリミティブ、およびオプションのヘルパーユーティリティを提供します。これらのツールを必要に応じて自由に適用し、創造的なビジョンを実現してください。
Slackの要件
Slackでは、GIFの用途に応じて次のような具体的な要件があります。
メッセージGIF:
- 最大サイズ: ~2MB
- 最適寸法: 480x480
- 標準FPS: 15-20
- 色数制限: 128-256
- 再生時間: 2-5秒
絵文字GIF:
- 最大サイズ: 64KB(厳格な制限)
- 最適寸法: 128x128
- 標準FPS: 10-12
- 色数制限: 32-48
- 再生時間: 1-2秒
絵文字GIFは難しい - 64KBの制限は厳格です。以下の戦略が役立ちます:
- 合計フレーム数を10〜15に制限する
- 最大色数を32〜48にする
- デザインをシンプルに保つ
- グラデーションを避ける
- ファイルサイズを頻繁に検証する
ツールキットの構成
このスキルは3種類のツールを提供します。
- バリデータ - GIFがSlackの要件を満たしているかチェック
- アニメーションプリミティブ - 動きのための合成可能な構成要素(揺れ、バウンス、移動、万華鏡)
- ヘルパーユーティリティ - テキスト、色、エフェクトなど、一般的なニーズに対応するオプション機能
これらのツールの適用方法については、完全な創造的自由があります。
コアバリデータ
GIFがSlackの制約を満たしていることを確認するには、以下のバリデータを使用します。
from core.gif_builder import GIFBuilder
# GIF作成後、要件を満たしているかチェック
builder = GIFBuilder(width=128, height=128, fps=10)
# ... 好きな方法でフレームを追加 ...
# 保存してサイズを確認
info = builder.save('emoji.gif', num_colors=48, optimize_for_emoji=True)
# saveメソッドは自動的にファイルが制限を超えた場合に警告を出します
# info辞書の内容: size_kb, size_mb, frame_count, duration_seconds
ファイルサイズバリデータ:
from core.validators import check_slack_size
# GIFがサイズ制限を満たしているかチェック
passes, info = check_slack_size('emoji.gif', is_emoji=True)
# 戻り値: (True/False, サイズ詳細を含む辞書)
寸法バリデータ:
from core.validators import validate_dimensions
# 寸法をチェック
passes, info = validate_dimensions(128, 128, is_emoji=True)
# 戻り値: (True/False, 寸法詳細を含む辞書)
完全な検証:
from core.validators import validate_gif, is_slack_ready
# すべての検証を実行
all_pass, results = validate_gif('emoji.gif', is_emoji=True)
# または簡易チェック
if is_slack_ready('emoji.gif', is_emoji=True):
print("アップロード準備完了!")
アニメーションプリミティブ
これらは動きのための合成可能な構成要素です。任意のオブジェクトに任意の組み合わせで適用できます。
揺れ(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' # または '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',
full_rotations=2
)
# ぐらつき回転
frames = create_spin_animation(rotation_type='wobble', full_rotations=3)
# ローディングスピナー
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',
scale_range=(0.8, 1.2)
)
# ハートビート(2回打ち)
frames = create_pulse_animation(pulse_type='heartbeat')
# 絵文字GIF用の注目パルス
frames = create_attention_pulse(emoji='⚠️', num_frames=20)
フェード(Fade)
from templates.fade import create_fade_animation, create_crossfade
# フェードイン
frames = create_fade_animation(fade_type='in')
# フェードアウト
frames = create_fade_animation(fade_type='out')
# 2つの絵文字間のクロスフェード
frames = create_crossfade(
object1_data={'emoji': '😊', 'size': 100},
object2_data={'emoji': '😂', 'size': 100}
)
ズーム(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_zoom_animation(zoom_type='out')
# 爆発ズーム
frames = create_explosion_zoom(emoji='💥')
爆発 / 粉砕(Explode / Shatter)
from templates.explode import create_explode_animation, create_particle_burst
# 破裂爆発
frames = create_explode_animation(
explode_type='burst',
num_pieces=25
)
# 粉砕エフェクト
frames = create_explode_animation(explode_type='shatter')
# パーティクルに溶解
frames = create_explode_animation(explode_type='dissolve')
# パーティクルバースト
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',
intensity=1.0,
cycles=2
)
# 波の動き
frames = create_wiggle_animation(wiggle_type='wave')
# 絵文字GIF用の興奮したウィグル
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',
overshoot=True
)
# 横断スライド
frames = create_slide_animation(direction='left', slide_type='across')
# 複数オブジェクトの連続スライド
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
# 2つの絵文字間の水平フリップ
frames = create_flip_animation(
object1_data={'emoji': '😊', 'size': 120},
object2_data={'emoji': '😂', 'size': 120},
flip_axis='horizontal'
)
# 垂直フリップ
frames = create_flip_animation(flip_axis='vertical')
# 絵文字GIF用のクイックフリップ
frames = create_quick_flip('👍', '👎')
モーフ / 変形(Morph / Transform)
from templates.morph import create_morph_animation, create_reaction_morph
# クロスフェードモーフ
frames = create_morph_animation(
object1_data={'emoji': '😊', 'size': 100},
object2_data={'emoji': '😂', 'size': 100},
morph_type='crossfade'
)
# スケールモーフ(片方が縮みながらもう片方が成長)
frames = create_morph_animation(morph_type='scale')
# スピンモーフ(3Dフリップ風)
frames = create_morph_animation(morph_type='spin_morph')
移動エフェクト(Move Effect)
from templates.move import create_move_animation
# 直線移動
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, 350),
end_pos=(430, 350),
motion_type='arc',
motion_params={'arc_height': 150}
)
# 円運動
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 # 完全な円
}
)
# 波の動き
frames = create_move_animation(
motion_type='wave',
motion_params={
'wave_amplitude': 50,
'wave_frequency': 2
}
)
# または低レベルのイージング関数を使用
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)
万華鏡エフェクト(Kaleidoscope Effect)
from templates.kaleidoscope import apply_kaleidoscope, create_kaleidoscope_animation
# 単一フレームに適用
kaleido_frame = apply_kaleidoscope(frame, segments=8)
# またはアニメーション万華鏡を作成
frames = create_kaleidoscope_animation(
base_frame=my_frame, # またはNoneでデモパターン
num_frames=30,
segments=8,
rotation_speed=1.0
)
# シンプルなミラーエフェクト(より高速)
from templates.kaleidoscope import apply_simple_mirror
mirrored = apply_simple_mirror(frame, mode='quad') # 4方向ミラー
# モード: 'horizontal', 'vertical', 'quad', 'radial'
プリミティブを自由に合成するには、以下のパターンに従います:
# 例: インパクト時にバウンス+揺れ
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)
ヘルパーユーティリティ
これらは一般的なニーズに対応するオプションのヘルパーです。必要に応じて、これらを使用、変更、または独自の実装に置き換えてください。
GIFビルダー(組み立てと最適化)
from core.gif_builder import GIFBuilder
# 任意の設定でビルダーを作成
builder = GIFBuilder(width=480, height=480, fps=20)
# フレームを追加(作成方法は自由)
for frame in my_frames:
builder.add_frame(frame)
# 最適化して保存
builder.save('output.gif',
num_colors=128,
optimize_for_emoji=False)
主な機能:
- 自動色量子化
- 重複フレーム除去
- Slack制限に対するサイズ警告
- 絵文字モード(積極的な最適化)
テキストレンダリング
絵文字のような小さなGIFでは、テキストの可読性が課題です。一般的な解決策として、アウトラインを追加する方法があります:
from core.typography import draw_text_with_outline, TYPOGRAPHY_SCALE
# アウトライン付きテキスト(可読性向上)
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では問題なく動作します。
カラーマネジメント
プロフェッショナルな見た目のGIFでは、一貫性のあるカラーパレットを使用することがよくあります:
from core.color_palettes import get_palette
# 既成のパレットを取得
palette = get_palette('vibrant') # または 'pastel', 'dark', 'neon', 'professional'
bg_color = palette['background']
text_color = palette['primary']
accent_color = palette['accent']
色を直接扱うには、RGBタプルを使用します。ユースケースに合わせて自由に設定してください。
ビジュアルエフェクト
インパクトのある瞬間のためのオプションエフェクト:
from core.visual_effects import ParticleSystem, create_impact_flash, create_shockwave_rings
# パーティクルシステム
particles = ParticleSystem()
particles.emit_sparkles(x=240, y=200, count=15)
particles.emit_confetti(x=240, y=200, count=20)
# 各フレームの更新とレンダリング
particles.update()
particles.render(frame)
# フラッシュエフェクト
frame = create_impact_flash(frame, position=(240, 200), radius=100)
# 衝撃波リング
frame = create_shockwave_rings(frame, position=(240, 200), radii=[30, 60, 90])
イージング関数
スムーズな動きには、線形補間ではなくイージングを使用します:
from core.easing import interpolate
# 落下するオブジェクト(加速)
y = interpolate(start=0, end=400, t=progress, easing='ease_in')
# 着地するオブジェクト(減速)
y = interpolate(start=0, end=400, t=progress, easing='ease_out')
# バウンス
y = interpolate(start=0, end=400, t=progress, easing='bounce_out')
# オーバーシュート(弾性)
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 を参照。
フレーム構成
必要に応じて基本的な描画ユーティリティ:
from core.frame_composer import (
create_gradient_background, # グラデーション背景
draw_emoji_enhanced, # 影付き絵文字
draw_circle_with_shadow, # 奥行きのある図形
draw_star # 五芒星
)
# グラデーション背景
frame = create_gradient_background(480, 480, top_color, bottom_color)
# 影付き絵文字
draw_emoji_enhanced(frame, '🎉', position=(200, 200), size=80, shadow=True)
最適化戦略
GIFが大きすぎる場合:
メッセージGIF(2MB超)の場合:
- フレーム数を減らす(FPSを下げる、または再生時間を短く)
- 色数を減らす(128 → 64色)
- 寸法を小さくする(480x480 → 320x320)
- 重複フレーム除去を有効にする
絵文字GIF(64KB超)の場合 - 積極的に:
- 合計フレーム数を10〜12に制限
- 色数を32〜40に制限
- グラデーションを避ける(ベタ塗りの方が圧縮効率が良い)
- デザインをシンプルに(要素を減らす)
- saveメソッドで
optimize_for_emoji=Trueを使用
構成例
シンプルなリアクション(パルス)
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)
# 検証
from core.validators import check_slack_size
check_slack_size('reaction.gif', is_emoji=True)
注意事項
- このツールキットは創造的な自由を前提としています。 提供されたツールを組み合わせて、任意のアニメーションGIFを作成できます。
- すべてのGIFはSlackにアップロードする前にバリデータで検証することをお勧めします。
- 絵文字GIFの64KB制限は非常に厳格です。最適化戦略を積極的に適用してください。
- 各プリミティブのパラメータは、目的の効果に合わせて自由に調整してください。
ライセンス
このプロジェクトはMITライセンスの下で提供されています。詳細はLICENSEファイルを参照してください。
貢献
貢献は歓迎します!問題やプルリクエストがある場合は、リポジトリのIssueトラッカーに報告してください。