Slack Gif Creator
Walkthrough zu den Agentenfähigkeiten zum Generieren thematischer Slack-GIF-Pakete, zum Verwalten von Eingabeaufforderungen, Frame-Pipelines und Überprüfungschecklisten.
Quelle: Inhalt angepasst von Anthropics/Skills (MIT).
Ein Toolkit mit Dienstprogrammen und Wissen zum Erstellen animierter GIFs, die für Slack optimiert sind.
Slack-Anforderungen
Abmessungen:
- Emoji-GIFs: 128 x 128 (empfohlen)
- Nachrichten-GIFs: 480x480
Parameter:
- FPS: 10–30 (niedriger bedeutet kleinere Dateigröße)
- Farben: 48-128 (weniger = kleinere Dateigröße)
- Dauer: Für Emoji-GIFs unter 3 Sekunden halten
Kern-Workflow
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)Zeichnen von Grafiken
Arbeiten mit vom Benutzer hochgeladenen Bildern
Wenn ein Benutzer ein Bild hochlädt, überlegen Sie, ob er Folgendes tun möchte:
- Direkt verwenden (z. B. „animiere dies“, „teile dies in Frames auf“)
- Verwenden Sie es als Inspiration (z. B. „Mach so etwas“)
Bilder mit PIL laden und bearbeiten:
from PIL import Image
uploaded = Image.open('file.png')
# Use directly, or just as reference for colors/styleVon Grund auf zeichnen
Wenn Sie Grafiken von Grund auf zeichnen, verwenden Sie PIL ImageDraw-Grundelemente:
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)Verwenden Sie nicht: Emoji-Schriftarten (plattformübergreifend unzuverlässig) oder gehen Sie davon aus, dass in diesem Skill vorgefertigte Grafiken vorhanden sind.
Grafiken gut aussehen lassen
Grafiken sollten elegant und kreativ aussehen, nicht einfach. So geht's:
Verwenden Sie dickere Linien – Stellen Sie für Umrisse und Linien immerwidth=2oder höher ein. Dünne Linien (Breite = 1) wirken abgehackt und amateurhaft.
Visuelle Tiefe hinzufügen:
- Verläufe für Hintergründe verwenden (
create_gradient_background) - Mehrere Formen überlagern, um die Komplexität zu erhöhen (z. B. ein Stern mit einem kleineren Stern darin)
Machen Sie Formen interessanter:
- Zeichnen Sie nicht nur einen einfachen Kreis, sondern fügen Sie Hervorhebungen, Ringe oder Muster hinzu
- Sterne können leuchten (zeichnen Sie größere, halbtransparente Versionen dahinter)
- Kombinieren Sie mehrere Formen (Sterne + Glitzer, Kreise + Ringe)
Achten Sie auf die Farben:
- Verwenden Sie lebendige Komplementärfarben
- Kontrast hinzufügen (dunkle Umrisse auf hellen Formen, helle Umrisse auf dunklen Formen)
- Berücksichtigen Sie die Gesamtzusammensetzung
Für komplexe Formen (Herzen, Schneeflocken usw.):
- Verwenden Sie Kombinationen aus Polygonen und Ellipsen
- Berechnen Sie die Punkte sorgfältig, um die Symmetrie zu gewährleisten
- Fügen Sie Details hinzu (ein Herz kann eine Highlight-Kurve haben, Schneeflocken können komplizierte Zweige haben)
Seien Sie kreativ und detailliert! Ein gutes Slack-GIF sollte elegant aussehen und nicht wie Platzhaltergrafiken.
Verfügbare Dienstprogramme
GIFBuilder (core.gif_builder)
Stellt Frames zusammen und optimiert sie für 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)Validatoren (core.validators)
Überprüfen Sie, ob GIF die Slack-Anforderungen erfüllt:
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!")Beschleunigungsfunktionen (core.easing)
Sanfte Bewegung statt linear:
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_outRahmenhelfer (core.frame_composer)
Komfortfunktionen für den allgemeinen Bedarf:
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
)Animationskonzepte
Schütteln/Vibrieren
Objektposition mit Oszillation verschieben:
- Verwenden Sie
math.sin()odermath.cos()mit Frame-Index - Fügen Sie kleine, zufällige Variationen hinzu, um ein natürliches Gefühl zu erzielen
- Auf x- und/oder y-Position anwenden
Puls/Herzschlag
Objektgröße rhythmisch skalieren:
- Verwenden Sie
math.sin(t * frequency * 2 * math.pi)für einen gleichmäßigen Puls - Für Herzschlag: zwei schnelle Impulse, dann Pause (Sinuswelle anpassen)
- Skala zwischen 0,8 und 1,2 der Grundgröße
Hüpfen
Objekt fällt und springt zurück:
- Verwenden Sie
interpolate()miteasing='bounce_out'für die Landung - Verwenden Sie
easing='ease_in'zum Fallen (Beschleunigen) - Wenden Sie die Schwerkraft an, indem Sie die Y-Geschwindigkeit in jedem Frame erhöhen
Drehen/Rotieren
Objekt um die Mitte drehen:
- PIL:
image.rotate(angle, resample=Image.BICUBIC) - Für Wobble: Verwenden Sie für den Winkel eine Sinuswelle anstelle einer linearen Welle
Ein-/Ausblenden
Allmählich erscheinen oder verschwinden:
- RGBA-Bild erstellen, Alphakanal anpassen
- Oder verwenden Sie
Image.blend(image1, image2, alpha) - Einblenden: Alpha von 0 bis 1
- Ausblenden: Alpha von 1 bis 0
Rutsche
Objekt von außerhalb des Bildschirms an Position verschieben:
- Startposition: außerhalb der Rahmengrenzen
- Endposition: Zielort
- Verwenden Sie
interpolate()miteasing='ease_out'für einen sanften Stopp - Bei Überschreitung:
easing='back_out'verwenden
Zoomen
Skalierung und Position für Zoomeffekt:
- Vergrößern: Skalierung von 0,1 bis 2,0, Schnittmitte
- Verkleinern: Skalierung von 2,0 bis 1,0
- Kann Bewegungsunschärfe für Dramatik hinzufügen (PIL-Filter)
Explodieren/Partikelexplosion
Nach außen strahlende Partikel erzeugen:
- Erzeugen Sie Partikel mit zufälligen Winkeln und Geschwindigkeiten
- Aktualisieren Sie jedes Partikel:
x += vx,y += vy - Schwerkraft hinzufügen:
vy += gravity_constant - Partikel im Laufe der Zeit ausblenden (Alpha reduzieren)
Optimierungsstrategien
Implementieren Sie nur dann einige der folgenden Methoden, wenn Sie aufgefordert werden, die Dateigröße zu verkleinern:
- Weniger Frames – Niedrigere FPS (10 statt 20) oder kürzere Dauer
- Weniger Farben -
num_colors=48statt 128 - Kleinere Abmessungen – 128x128 statt 480x480
- Duplikate entfernen -
remove_duplicates=Truein save() - Emoji-Modus –
optimize_for_emoji=Trueoptimiert automatisch
# Maximum optimization for emoji
builder.save(
'emoji.gif',
num_colors=48,
optimize_for_emoji=True,
remove_duplicates=True
)Philosophie
Diese Fähigkeit bietet:
- Wissen: Anforderungen und Animationskonzepte von Slack
- Dienstprogramme: GIFBuilder, Validatoren, Beschleunigungsfunktionen
- Flexibilität: Erstellen Sie die Animationslogik mithilfe von PIL-Primitiven
Es bietet NICHT:
- Starre Animationsvorlagen oder vorgefertigte Funktionen
- Emoji-Schriftart-Rendering (plattformübergreifend unzuverlässig)
- Eine Bibliothek mit vorgefertigten Grafiken, die in den Skill integriert sind
Hinweis zu Benutzer-Uploads: Dieser Skill beinhaltet keine vorgefertigten Grafiken, aber wenn ein Benutzer ein Bild hochlädt, verwenden Sie PIL, um es zu laden und damit zu arbeiten – interpretieren Sie basierend auf seiner Anfrage, ob er es direkt oder nur als Inspiration verwenden möchte.
Seien Sie kreativ! Kombinieren Sie Konzepte (Springen + Rotieren, Pulsieren + Gleiten usw.) und nutzen Sie die vollen Möglichkeiten von PIL.
Abhängigkeiten
pip install pillow imageio numpyRessourcendateien
LIZENZ.txt
Binäre Ressource
core/easing.py
Binäre Ressource
core/frame_composer.py
core/frame_composer.py herunterladen
#!/usr/bin/env python3
"""
Frame Composer - Utilities for composing visual elements into frames.
Provides functions for drawing shapes, text, emojis, and compositing elements
together to create animation frames.
"""
from typing import Optional
import numpy as np
from PIL import Image, ImageDraw, ImageFont
def create_blank_frame(
width: int, height: int, color: tuple[int, int, int] = (255, 255, 255)
) -> Image.Image:
"""
Create a blank frame with solid color background.
Args:
width: Frame width
height: Frame height
color: RGB color tuple (default: white)
Returns:
PIL Image
"""
return Image.new("RGB", (width, height), color)
def draw_circle(
frame: Image.Image,
center: tuple[int, int],
radius: int,
fill_color: Optional[tuple[int, int, int]] = None,
outline_color: Optional[tuple[int, int, int]] = None,
outline_width: int = 1,
) -> Image.Image:
"""
Draw a circle on a frame.
Args:
frame: PIL Image to draw on
center: (x, y) center position
radius: Circle radius
fill_color: RGB fill color (None for no fill)
outline_color: RGB outline color (None for no outline)
outline_width: Outline width in pixels
Returns:
Modified frame
"""
draw = ImageDraw.Draw(frame)
x, y = center
bbox = [x - radius, y - radius, x + radius, y + radius]
draw.ellipse(bbox, fill=fill_color, outline=outline_color, width=outline_width)
return frame
def draw_text(
frame: Image.Image,
text: str,
position: tuple[int, int],
color: tuple[int, int, int] = (0, 0, 0),
centered: bool = False,
) -> Image.Image:
"""
Draw text on a frame.
Args:
frame: PIL Image to draw on
text: Text to draw
position: (x, y) position (top-left unless centered=True)
color: RGB text color
centered: If True, center text at position
Returns:
Modified frame
"""
draw = ImageDraw.Draw(frame)
# Uses Pillow's default font.
# If the font should be changed for the emoji, add additional logic here.
font = ImageFont.load_default()
if centered:
bbox = draw.textbbox((0, 0), text, font=font)
text_width = bbox[2] - bbox[0]
text_height = bbox[3] - bbox[1]
x = position[0] - text_width // 2
y = position[1] - text_height // 2
position = (x, y)
draw.text(position, text, fill=color, font=font)
return frame
def create_gradient_background(
width: int,
height: int,
top_color: tuple[int, int, int],
bottom_color: tuple[int, int, int],
) -> Image.Image:
"""
Create a vertical gradient background.
Args:
width: Frame width
height: Frame height
top_color: RGB color at top
bottom_color: RGB color at bottom
Returns:
PIL Image with gradient
"""
frame = Image.new("RGB", (width, height))
draw = ImageDraw.Draw(frame)
# Calculate color step for each row
r1, g1, b1 = top_color
r2, g2, b2 = bottom_color
for y in range(height):
# Interpolate color
ratio = y / height
r = int(r1 * (1 - ratio) + r2 * ratio)
g = int(g1 * (1 - ratio) + g2 * ratio)
b = int(b1 * (1 - ratio) + b2 * ratio)
# Draw horizontal line
draw.line([(0, y), (width, y)], fill=(r, g, b))
return frame
def draw_star(
frame: Image.Image,
center: tuple[int, int],
size: int,
fill_color: tuple[int, int, int],
outline_color: Optional[tuple[int, int, int]] = None,
outline_width: int = 1,
) -> Image.Image:
"""
Draw a 5-pointed star.
Args:
frame: PIL Image to draw on
center: (x, y) center position
size: Star size (outer radius)
fill_color: RGB fill color
outline_color: RGB outline color (None for no outline)
outline_width: Outline width
Returns:
Modified frame
"""
import math
draw = ImageDraw.Draw(frame)
x, y = center
# Calculate star points
points = []
for i in range(10):
angle = (i * 36 - 90) * math.pi / 180 # 36 degrees per point, start at top
radius = size if i % 2 == 0 else size * 0.4 # Alternate between outer and inner
px = x + radius * math.cos(angle)
py = y + radius * math.sin(angle)
points.append((px, py))
# Draw star
draw.polygon(points, fill=fill_color, outline=outline_color, width=outline_width)
return framecore/gif_builder.py
core/gif_builder.py herunterladen
Binäre Ressource
core/validators.py
core/validators.py herunterladen
#!/usr/bin/env python3
"""
Validators - Check if GIFs meet Slack's requirements.
These validators help ensure your GIFs meet Slack's size and dimension constraints.
"""
from pathlib import Path
def validate_gif(
gif_path: str | Path, is_emoji: bool = True, verbose: bool = True
) -> tuple[bool, dict]:
"""
Validate GIF for Slack (dimensions, size, frame count).
Args:
gif_path: Path to GIF file
is_emoji: True for emoji (128x128 recommended), False for message GIF
verbose: Print validation details
Returns:
Tuple of (passes: bool, results: dict with all details)
"""
from PIL import Image
gif_path = Path(gif_path)
if not gif_path.exists():
return False, {"error": f"File not found: {gif_path}"}
# Get file size
size_bytes = gif_path.stat().st_size
size_kb = size_bytes / 1024
size_mb = size_kb / 1024
# Get dimensions and frame info
try:
with Image.open(gif_path) as img:
width, height = img.size
# Count frames
frame_count = 0
try:
while True:
img.seek(frame_count)
frame_count += 1
except EOFError:
pass
# Get duration
try:
duration_ms = img.info.get("duration", 100)
total_duration = (duration_ms * frame_count) / 1000
fps = frame_count / total_duration if total_duration > 0 else 0
except:
total_duration = None
fps = None
except Exception as e:
return False, {"error": f"Failed to read GIF: {e}"}
# Validate dimensions
if is_emoji:
optimal = width == height == 128
acceptable = width == height and 64 <= width <= 128
dim_pass = acceptable
else:
aspect_ratio = (
max(width, height) / min(width, height)
if min(width, height) > 0
else float("inf")
)
dim_pass = aspect_ratio <= 2.0 and 320 <= min(width, height) <= 640
results = {
"file": str(gif_path),
"passes": dim_pass,
"width": width,
"height": height,
"size_kb": size_kb,
"size_mb": size_mb,
"frame_count": frame_count,
"duration_seconds": total_duration,
"fps": fps,
"is_emoji": is_emoji,
"optimal": optimal if is_emoji else None,
}
# Print if verbose
if verbose:
print(f"\nValidating {gif_path.name}:")
print(
f" Dimensions: {width}x{height}"
+ (
f" ({'optimal' if optimal else 'acceptable'})"
if is_emoji and acceptable
else ""
)
)
print(
f" Size: {size_kb:.1f} KB"
+ (f" ({size_mb:.2f} MB)" if size_mb >= 1.0 else "")
)
print(
f" Frames: {frame_count}"
+ (f" @ {fps:.1f} fps ({total_duration:.1f}s)" if fps else "")
)
if not dim_pass:
print(
f" Note: {'Emoji should be 128x128' if is_emoji else 'Unusual dimensions for Slack'}"
)
if size_mb > 5.0:
print(f" Note: Large file size - consider fewer frames/colors")
return dim_pass, results
def is_slack_ready(
gif_path: str | Path, is_emoji: bool = True, verbose: bool = True
) -> bool:
"""
Quick check if GIF is ready for Slack.
Args:
gif_path: Path to GIF file
is_emoji: True for emoji GIF, False for message GIF
verbose: Print feedback
Returns:
True if dimensions are acceptable
"""
passes, _ = validate_gif(gif_path, is_emoji, verbose)
return passesAnforderungen.txt
Anforderungen.txt herunterladen
pillow>=10.0.0
imageio>=2.31.0
imageio-ffmpeg>=0.4.9
numpy>=1.24.0Siehe in GitHub
Frontend-Design
Erstellen Sie unverwechselbare Frontend-Schnittstellen in Produktionsqualität mit hoher Designqualität. Verwenden Sie diese Fähigkeit, wenn der Benutzer Webkomponenten, Seiten, Artefakte, Poster oder Anwendungen erstellen möchte (Beispiele hierfür sind Websites, Zielseiten, Dashboards, React-Komponenten, HTML-/CSS-Layouts oder wenn Sie eine Web-Benutzeroberfläche gestalten/verschönern). Erzeugt kreatives, ausgefeiltes Code- und UI-Design, das generische KI-Ästhetik vermeidet.
Webartefakt-Builder
Agentenfähigkeit zum Bündeln von React- und Tailwind-Artefakten in einzelnen HTML-Ausgaben mit Shadcn-Komponenten und Automatisierungsskripten.
claudeskills Docs