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색 사용
- 디자인을 단순하게 유지
- 그라데이션 피하기
- 파일 크기를 자주 확인
툴킷 구조
이 스킬은 세 가지 유형의 도구를 제공합니다:
- 검증기 - 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)
)
# 심장 박동 (이중 펌프)
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')
# 두 이모지 간 크로스페이드
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
# 두 이모지 간 수평 뒤집기
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 # 5각 별
)
# 그라데이션 배경
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.
...
[번역을 위해 잘림]