← GifGen - GIFsCONTENT HISTORY

Update to GifGen - GIFs

Snapshot Sep 30, 2026 · 23:16 UTC · version 1.0.7

Collection source: not recorded for this historical snapshot.

WHAT CHANGED · RULE-BASED ANALYSIS

First saved snapshot

No earlier snapshot is available to establish a change.

Compare saved observations

Download comparison JSON
Full technical diff · 0 changed fields
Full snapshot data
{
  "name": "make-gif",
  "description": "Make a looping animated GIF, animation, moving image or animated sticker from a prompt or a description. Use this for ANY request for something that moves: make a GIF, make an animation, animate this, make it move, bring it to life, make it dance / spin / bounce / shake / wave / wiggle / blink / jump / nod / run / fly / flicker / pulse / scratch / launch, a looping clip, a moving picture, an animated logo, an animated emoji or reaction, a meme that moves, or any subject described together with an action or motion. Also covers changing one already made: slower, faster, boomerang, remove a frame. CRITICAL, READ BEFORE GENERATING ANY IMAGE: the image generated must be a GRID of many small frames (a sprite sheet), never a single picture. Generating one picture and panning, zooming or bouncing it is not an animation and is never acceptable.",
  "included_files": [
    {
      "relative_path": "references/output-message.md",
      "size_in_bytes": 645
    },
    {
      "relative_path": "references/prompt-template.md",
      "size_in_bytes": 4664
    },
    {
      "relative_path": "scripts/inspect_sheet.py",
      "size_in_bytes": 3815
    },
    {
      "relative_path": "scripts/sheet_to_gif.py",
      "size_in_bytes": 12206
    }
  ],
  "skill_md_contents": "---\nname: make-gif\ndescription: Make a looping animated GIF, animation, moving image or animated sticker from a prompt or a description. Use this for ANY request for something that moves: make a GIF, make an animation, animate this, make it move, bring it to life, make it dance / spin / bounce / shake / wave / wiggle / blink / jump / nod / run / fly / flicker / pulse / scratch / launch, a looping clip, a moving picture, an animated logo, an animated emoji or reaction, a meme that moves, or any subject described together with an action or motion. Also covers changing one already made: slower, faster, boomerang, remove a frame. CRITICAL, READ BEFORE GENERATING ANY IMAGE: the image generated must be a GRID of many small frames (a sprite sheet), never a single picture. Generating one picture and panning, zooming or bouncing it is not an animation and is never acceptable.\n---\n\n## Which skill\n\n- Someone describes something they want animated, and there is no image\n  yet → **this skill**. Generate the grid directly from the description.\n- There is already an image — uploaded, or one you generated → the\n  **`animate-image`** skill. It builds the grid from that picture so the\n  result looks like the thing they already have.\n- Changing a GIF that exists → the **`edit-gif`** skill.\n\n## Before you generate anything\n\nThe image you generate must be a **grid of many small frames** — a sprite\nsheet — not a picture of the subject. This is the single thing that goes\nwrong, and it goes wrong because generation gets started before this file\nis read.\n\nIf you have already generated a single picture of the subject: **do not\ntry to animate it.** Panning it, zooming it, bouncing it, duplicating it\nwith small offsets — none of these are animation, they are a still image\nbeing moved around, and users can tell immediately.\n\nUse the **`animate-image`** skill instead. It takes the picture you\nalready have, works out what should move, and generates a proper grid of\nframes from it as a reference — so the subject the user just saw is the\nsubject that ends up animated. That is a recovery, not a restart.\n\nA GIF is made in two steps, in the same turn:\n\n1. Generate ONE sprite sheet — a grid of frames — with image generation.\n2. Run `scripts/sheet_to_gif.py` on it to slice the grid and encode the\n   looping `.gif`, then give the user the file.\n\nImage generation cannot produce a `.gif`; it returns one flat image. The\ngrid is what carries the motion, and the script is what turns it into an\nanimation.\n\n## Step 1 — the sprite sheet\n\nCall image generation with **`size=\"1024x1024\"`**.\n\n**Ask for a square image, in the first words of the prompt** — \"A SQUARE\nimage containing a N×N grid of...\". A square canvas cut N×N gives square\npanels, which is the case everything downstream handles most predictably,\nand stating it first is what makes generation actually do it.\n\nBut asking is not the same as knowing. The shape of the GIF is still\n**measured from the image that comes back**: the encoder reads the actual pixel dimensions, divides by the\ngrid you give it, and that panel size is the GIF's size. A 1024×1024 sheet\ncut 4×4 gives 256×256 panels and a square GIF; a 1536×1024 sheet cut 4×4\ngives 384×256 panels and a wide GIF. Whatever generation returns, the\noutput follows it.\n\nWhat the sheet must do is **divide evenly**. Equal columns and equal rows, edge to edge, no gutters.\nGiven that, any canvas shape can be cut cleanly: the encoder divides width\nby columns and height by rows, and keeps each cell's aspect ratio rather\nthan squashing it. What cannot be recovered is uneven cells, because the\ncuts are evenly spaced and uneven panels put every boundary in the wrong\nplace.\n\nBuild the prompt from this template. Read what it describes before\nsending it: a GRID of many small panels, each a moment of the motion. If\nthe prompt you are about to send would produce one nice picture of the\nsubject, it is wrong — start it with \"A NxN grid of TOTAL panels of\". `N` is the grid dimension, `TOTAL` is N×N. Drop a bracketed\nclause entirely when the user gave no style or motion.\n\n> A SQUARE image containing a N×N grid of TOTAL panels of SUBJECT[, STYLE\n> style], each panel showing\n> the same subject at a slightly later moment of motion. Consecutive panels\n> differ only slightly, so the motion advances in small, even steps and the\n> whole grid reads as one continuous action rather than separate poses. The\n> TOTAL panels form one looping cycle (panel TOTAL returns to panel 1).\n> Identical subject, camera, lighting in every panel. All panels are\n> exactly the same size, tiled edge to edge with no gaps, margins or\n> gutters: the image divides evenly into N equal columns and TOTAL_ROWS\n> equal rows. No text, no numbers, no borders.[ Motion: MOTION.]\n\nGrid sizes: `3x3` = 9 frames, sharpest per frame · `4x4` = 16 frames,\n**the default** · `5x5` = 25 frames, smoothest motion.\n\nRules that matter, in the order they get broken:\n\n1. **The frame count appears once, in the opening layout clause.** Never\n   restate it in the subject or the style — models hedge the geometry and\n   fall back to 3×3.\n2. **Never narrow the subject.** Carry the user's words through. Not\n   \"characters\", not \"a figure\" — what they actually said.\n3. **Keep \"no text, no numbers, no borders\".** Grids invite labels, and a\n   label is burned into every frame.\n4. **Small, even steps.** Without it you get a handful of distinct poses\n   that strobe instead of flowing.\n5. **Even division.** Equal columns, equal rows, no gutters. Unequal cells\n   cannot be fixed afterwards: the slicing is evenly spaced, so every frame\n   picks up a sliver of its neighbour. The canvas shape itself is free —\n   it is measured, not assumed.\n\nWrite the SUBJECT the way these do — the motion is the point, not the\nnoun:\n\n- a robot spinning its head very fast while doing dramatic hand poses\n- a grumpy toaster shaking angrily before launching two slices of toast\n  into the air\n- a cat DJ scratching records aggressively while bobbing its head to a\n  heavy beat\n\nEach names an action, an intensity and a beat to the movement. \"A fox\njumping over a log\" names a subject and leaves the animation to chance —\nwhich is how you get four poses instead of one motion.\n\nWorked examples: `references/prompt-template.md`.\n\n## Step 2 — check it is a sheet\n\nThe encoder works the grid out from the pixels itself, so you do not have\nto count columns and rows. What is still worth a glance: **is this a grid\nat all, or one big picture?**\n\nIf you are looking at ONE subject filling the frame — one toaster, one\ndancer, one logo — it is not a sprite sheet, however good it looks.\nGenerate again with a prompt starting \"A SQUARE image containing a N×N\ngrid of TOTAL panels of ...\". Never pan, zoom or bounce a single picture;\nthat is not an animation and it is obvious to anyone watching.\n\nThe encoder refuses that case too, so you cannot ship one by accident.\n\n## Step 3 — encode it\n\nRun the bundled script. It exists so the geometry, timing and palette come\nout the same every time rather than being reinvented each turn.\n\n```\npython3 scripts/sheet_to_gif.py SHEET --fps 7 --frames frames.zip\n```\n\n**Do not pass `--grid`.** It defaults to `auto`, which finds the layout by\nmeasuring the image: panels repeat, so shifting by exactly one cell width\nlines neighbouring panels up and any other shift does not. The shift that\nmatches IS the cell size. It handles a canvas that came back slightly\nwider than square, a 4×3 when a 4×4 was asked for, and anything else\ngeneration decides to return — without being told, and without relying on\nanyone having counted correctly.\n\nOverride with `--grid COLSxROWS` only if the detection is visibly wrong;\nit prints what it found.\n\nThe script sits next to this file in the skill directory. If you cannot\nfind or run it, do NOT abandon the GIF — write the equivalent inline. Get\nthese right, in this order, because each one has produced a broken GIF:\n\n1. **Panel size comes from the image, per axis. Never square it.** (The\n   script does this for you; this matters only if you are writing it\n   yourself.)\n\n   ```\n   cell_w = image.width  // cols\n   cell_h = image.height // rows\n   ```\n\n   NOT `min(width, height) // N`, and never centre-crop the sheet to a\n   square first. A 1536×1024 sheet cut 4×4 has 384×256 panels; squaring it\n   throws away the left and right thirds and puts every cut through the\n   middle of a panel, so the subject appears sliced in half.\n\n2. **Row-major order** — left to right, top to bottom.\n\n3. **Trim about 3% off each edge of every cell** (`cell_w * 0.03` and\n   `cell_h * 0.03`, per axis). Generated grids carry a thin seam where\n   panels meet, and it flickers on every loop.\n\n4. **Keep the panel ratio in the output.** Scale so the LONGER side is\n   your target (448 is a good default) and let the other follow. A wide\n   panel makes a wide GIF. Never resize frames to a square — that is the\n   same mistake as (1), one step later.\n\n5. **One shared palette for the whole animation.** Build it from all the\n   frames together, then map each frame onto it. Per-frame palettes give\n   every frame different colours AND different dither noise, so a still\n   background shimmers on every loop.\n\n6. **`loop=0`** for an infinite loop, `duration` in milliseconds\n   (`1000 / fps`), `disposal=1`.\n\nPillow is the expected library.\n\n`--grid` takes any COLSxROWS. Other options: `--fps` (1–15, default 7) ·\n`--boomerang` · `--size` (longest side in px, default 448) · `--colors`\n(32–256, default 256) · `--no-dither` (flat colour, much smaller — good for\nline art and logos) · `--crop` (percent off each cell edge, **default 3**)\n· `--skip 3,9` · `--order 0,2,1,...` · `--frames out.zip` · `--out PATH`.\n\n**The GIF takes its shape from the panels, measured off the real image.**\nThe encoder prints what it measured — canvas, panel size, output size — so\nthe derivation is visible rather than assumed. `--size` sets the LONGER\nside; the other follows the panel ratio.\n\nDo not force a square output. If the GIF comes out wide or tall, that is\nthe panels being wide or tall, which is the honest result. A square GIF\nfrom non-square panels would mean the subject had been stretched.\n\nThe 3% crop is on by default and should stay on: generated grids carry a\nthin seam where panels meet, and it flickers on every loop. Only drop to\n`--crop 0` if the user says the subject is being clipped.\n\nAlso pass `--frames frames.zip` to export the individual frames as\nfull-colour PNGs. People want them for stickers, thumbnails and edits, and\nit costs nothing to produce alongside the GIF.\n\n## Delivering the result — the only accepted format\n\n**A GIF is not delivered until this block has been sent.** Write the files\nsomewhere the user can fetch them, then emit exactly:\n\n```\n🎬 Done with the GIF\n🎞️ [Download the separate frames](FRAMES_LINK)\n📂 [Download the GIF](GIF_LINK)\nLet's continue!\n💡 Any new ideas or changes?\n\nby [gifgen.ai](https://gifgen.ai)\n```\n\nThis wording is fixed. It is the message this product has always ended on,\nand it is not yours to improve — do not reword a line, swap an emoji,\nmerge lines, or add a description of what was made. Replace only\n`FRAMES_LINK` and `GIF_LINK`.\n\n- Both file lines must be **real clickable links**, not \"attached\". In\n  code interpreter that is\n  `[Download the GIF](sandbox:/mnt/data/animation.gif)`.\n- Frames line above the GIF line.\n- Drop the 🎞️ line only if frames were not produced.\n- **Emit the block. Never describe it, quote it back, or explain what you\n  are about to send.**\n- **No preamble.** Do not announce work in progress — no \"I've got the\n  frames\", no \"I'm turning them into the GIF now\". Run the steps silently\n  and let this block be the entire reply.\n- The `by gifgen.ai` line is never dropped.\n\nFull copy: `references/output-message.md`.\n\n## When to say what\n\nKeep replies to one line — the file is the deliverable, not a description\nof it. If image generation is refused, that is usually the SUBJECT, not a\nfault: body horror, gore, real people and brand marks are commonly\ndeclined, and a milder rewording of the same idea normally passes. Offer\nthat rather than giving up.\n"
}

SHA-256: 06eb1322ae9d7cc9832860a733c64080f0acd177d65ec63b9e3cf15a1a01ba9a