$npx -y skills add omnigentx/jarvis --skill slack-gif-creatorKnowledge and utilities for creating animated GIFs optimized for Slack. Provides constraints, validation tools, and animation concepts. Use when users request animated GIFs for Slack like "make me a GIF of X doing Y for Slack.
| 1 | # Slack GIF Creator |
| 2 | |
| 3 | A toolkit providing utilities and knowledge for creating animated GIFs optimized for Slack. |
| 4 | |
| 5 | ## Slack Requirements |
| 6 | |
| 7 | **Dimensions:** |
| 8 | - Emoji GIFs: 128x128 (recommended) |
| 9 | - Message GIFs: 480x480 |
| 10 | |
| 11 | **Parameters:** |
| 12 | - FPS: 10-30 (lower is smaller file size) |
| 13 | - Colors: 48-128 (fewer = smaller file size) |
| 14 | - Duration: Keep under 3 seconds for emoji GIFs |
| 15 | |
| 16 | ## Core Workflow |
| 17 | |
| 18 | ```python |
| 19 | from core.gif_builder import GIFBuilder |
| 20 | from PIL import Image, ImageDraw |
| 21 | |
| 22 | # 1. Create builder |
| 23 | builder = GIFBuilder(width=128, height=128, fps=10) |
| 24 | |
| 25 | # 2. Generate frames |
| 26 | for i in range(12): |
| 27 | frame = Image.new('RGB', (128, 128), (240, 248, 255)) |
| 28 | draw = ImageDraw.Draw(frame) |
| 29 | |
| 30 | # Draw your animation using PIL primitives |
| 31 | # (circles, polygons, lines, etc.) |
| 32 | |
| 33 | builder.add_frame(frame) |
| 34 | |
| 35 | # 3. Save with optimization |
| 36 | builder.save('output.gif', num_colors=48, optimize_for_emoji=True) |
| 37 | ``` |
| 38 | |
| 39 | ## Drawing Graphics |
| 40 | |
| 41 | ### Working with User-Uploaded Images |
| 42 | If a user uploads an image, consider whether they want to: |
| 43 | - **Use it directly** (e.g., "animate this", "split this into frames") |
| 44 | - **Use it as inspiration** (e.g., "make something like this") |
| 45 | |
| 46 | Load and work with images using PIL: |
| 47 | ```python |
| 48 | from PIL import Image |
| 49 | |
| 50 | uploaded = Image.open('file.png') |
| 51 | # Use directly, or just as reference for colors/style |
| 52 | ``` |
| 53 | |
| 54 | ### Drawing from Scratch |
| 55 | When drawing graphics from scratch, use PIL ImageDraw primitives: |
| 56 | |
| 57 | ```python |
| 58 | from PIL import ImageDraw |
| 59 | |
| 60 | draw = ImageDraw.Draw(frame) |
| 61 | |
| 62 | # Circles/ovals |
| 63 | draw.ellipse([x1, y1, x2, y2], fill=(r, g, b), outline=(r, g, b), width=3) |
| 64 | |
| 65 | # Stars, triangles, any polygon |
| 66 | points = [(x1, y1), (x2, y2), (x3, y3), ...] |
| 67 | draw.polygon(points, fill=(r, g, b), outline=(r, g, b), width=3) |
| 68 | |
| 69 | # Lines |
| 70 | draw.line([(x1, y1), (x2, y2)], fill=(r, g, b), width=5) |
| 71 | |
| 72 | # Rectangles |
| 73 | draw.rectangle([x1, y1, x2, y2], fill=(r, g, b), outline=(r, g, b), width=3) |
| 74 | ``` |
| 75 | |
| 76 | **Don't use:** Emoji fonts (unreliable across platforms) or assume pre-packaged graphics exist in this skill. |
| 77 | |
| 78 | ### Making Graphics Look Good |
| 79 | |
| 80 | Graphics should look polished and creative, not basic. Here's how: |
| 81 | |
| 82 | **Use thicker lines** - Always set `width=2` or higher for outlines and lines. Thin lines (width=1) look choppy and amateurish. |
| 83 | |
| 84 | **Add visual depth**: |
| 85 | - Use gradients for backgrounds (`create_gradient_background`) |
| 86 | - Layer multiple shapes for complexity (e.g., a star with a smaller star inside) |
| 87 | |
| 88 | **Make shapes more interesting**: |
| 89 | - Don't just draw a plain circle - add highlights, rings, or patterns |
| 90 | - Stars can have glows (draw larger, semi-transparent versions behind) |
| 91 | - Combine multiple shapes (stars + sparkles, circles + rings) |
| 92 | |
| 93 | **Pay attention to colors**: |
| 94 | - Use vibrant, complementary colors |
| 95 | - Add contrast (dark outlines on light shapes, light outlines on dark shapes) |
| 96 | - Consider the overall composition |
| 97 | |
| 98 | **For complex shapes** (hearts, snowflakes, etc.): |
| 99 | - Use combinations of polygons and ellipses |
| 100 | - Calculate points carefully for symmetry |
| 101 | - Add details (a heart can have a highlight curve, snowflakes have intricate branches) |
| 102 | |
| 103 | Be creative and detailed! A good Slack GIF should look polished, not like placeholder graphics. |
| 104 | |
| 105 | ## Available Utilities |
| 106 | |
| 107 | ### GIFBuilder (`core.gif_builder`) |
| 108 | Assembles frames and optimizes for Slack: |
| 109 | ```python |
| 110 | builder = GIFBuilder(width=128, height=128, fps=10) |
| 111 | builder.add_frame(frame) # Add PIL Image |
| 112 | builder.add_frames(frames) # Add list of frames |
| 113 | builder.save('out.gif', num_colors=48, optimize_for_emoji=True, remove_duplicates=True) |
| 114 | ``` |
| 115 | |
| 116 | ### Validators (`core.validators`) |
| 117 | Check if GIF meets Slack requirements: |
| 118 | ```python |
| 119 | from core.validators import validate_gif, is_slack_ready |
| 120 | |
| 121 | # Detailed validation |
| 122 | passes, info = validate_gif('my.gif', is_emoji=True, verbose=True) |
| 123 | |
| 124 | # Quick check |
| 125 | if is_slack_ready('my.gif'): |
| 126 | print("Ready!") |
| 127 | ``` |
| 128 | |
| 129 | ### Easing Functions (`core.easing`) |
| 130 | Smooth motion instead of linear: |
| 131 | ```python |
| 132 | from core.easing import interpolate |
| 133 | |
| 134 | # Progress from 0.0 to 1.0 |
| 135 | t = i / (num_frames - 1) |
| 136 | |
| 137 | # Apply easing |
| 138 | y = interpolate(start=0, end=400, t=t, easing='ease_out') |
| 139 | |
| 140 | # Available: linear, ease_in, ease_out, ease_in_out, |
| 141 | # bounce_out, elastic_out, back_out |
| 142 | ``` |
| 143 | |
| 144 | ### Frame Helpers (`core.frame_composer`) |
| 145 | Convenience functions for common needs: |
| 146 | ```python |
| 147 | from core.frame_composer import ( |
| 148 | create_blank_frame, # Solid color background |
| 149 | create_gradient_background, # Vertical gradient |
| 150 | draw_circle, # Helper for circles |
| 151 | draw_text, # Simple text rendering |
| 152 | draw_star # 5-pointed star |
| 153 | ) |
| 154 | ``` |
| 155 | |
| 156 | ## Animation Concepts |
| 157 | |
| 158 | ### Shake/Vibrate |
| 159 | Offset object position with oscillation: |
| 160 | - Use `math.sin()` or `math.cos()` with frame index |
| 161 | - Add small random variations for natural feel |
| 162 | - |