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("アップロード準備完了!")
アニメーションプリミティブ
これらは動きのための合成可能な構成要素です。任意のオブジェクトに任意の組み合わせで適用できます:
シェイク
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'
)
バウンス
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
)
スピン / 回転
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')
パルス / ハートビート
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)
)
# ハートビート(ダブルポンプ)
frames = create_pulse_animation(pulse_type='heartbeat')
# 絵文字GIF用の注意喚起パルス
frames = create_attention_pulse(emoji='⚠️', num_frames=20)
フェード
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}
)
ズーム
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='💥')
爆発 / 粉砕
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)
ウィグル / ジグル
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='🎉')
スライド
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)
フリップ
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('👍', '👎')
モーフ / 変形
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')
移動エフェクト
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)
カレイドスコープエフェクト
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色を使用
- グラデーションを避ける(単色の方が圧縮効率が良い)
- デザインをシンプルにする(要素を減らす)
- 保存メソッドで
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)
テキストDo効果
builder = GIFBuilder(320, 240, 15)
for i in range(20):
frame = create_gradient_background(320, 240, (30, 30, 80), (0, 0, 20))
progress = i / 19
# テキストのスケールアップ
scale = 1.0 + (1.0 - progress) * 0.5
font_size = int(48 * scale)
draw_text_with_outline(
frame, "BOOM!",
position=(160, 120),
font_size=font_size,
text_color=(255, 200, 50),
outline_color=(200, 50, 0),
outline_width=4,
centered=True
)
builder.add_frame(frame)
builder.save('text_impact.gif', num_colors=128)
衝撃波を伴う爆発
builder = GIFBuilder(240, 240, 15)
for i in range(25):
frame = Image.new('RGB', (240, 240), (20, 20, 40))
progress = i / 24
# 爆発の放射状広がり
max_radius = 100
radius = max_radius * min(progress * 1.5, 1.0)
shockwave = create_shockwave_rings(
frame, position=(120, 120),
radii=[radius * 0.5, radius * 0.75, radius]
)
frame = shockwave if shockwave is not None else frame
# フレームにパーティクルを描画(デモ)
for _ in range(10):
angle = random.uniform(0, 2 * math.pi)
dist = radius * random.uniform(0.8, 1.2)
x = int(120 + math.cos(angle) * dist)
y = int(120 + math.sin(angle) * dist)
if 0 <= x < 240 and 0 <= y < 240:
frame.putpixel((x, y), (255, 255, 100))
builder.add_frame(frame)
builder.save('explosion.gif', num_colors=64)