{
  "@context": "https://schema.org",
  "@type": "Dataset",
  "schemaVersion": "1.0",
  "id": "deepswapai-gif-loop-seam-fixtures-v1",
  "identifier": "deepswapai-gif-loop-seam-fixtures-v1",
  "version": "1.0.0",
  "title": "DeepSwapAI GIF loop seam delta reference fixtures",
  "alternateName": "First-to-last composited GIF frame seam benchmark",
  "description": "Seven reproducible reference cases for the raw mean absolute RGBA difference between the first and last composited GIF frames, including GIF89a disposal handling.",
  "datePublished": "2026-08-27",
  "dateModified": "2026-08-27",
  "canonicalUrl": "https://deepswapai.com/research#gif-loop-seam",
  "creator": "DeepSwapAI Product Team",
  "isAccessibleForFree": true,
  "license": "https://creativecommons.org/licenses/by/4.0/",
  "attribution": "DeepSwapAI GIF Loop Seam Delta Reference Fixtures v1, https://deepswapai.com/research#gif-loop-seam",
  "dataCatalogUrl": "https://deepswapai.com/research#catalog",
  "toolUrl": "https://deepswapai.com/gif-face-swap#gif-preflight",
  "citationFileUrl": "https://deepswapai.com/assets/gif-loop-seam/gif-loop-seam-fixtures-v1.bib",
  "methodSource": "https://www.w3.org/Graphics/GIF/spec-gif89a.txt",
  "measurement": {
    "name": "First-to-last composited-frame RGBA mean absolute difference",
    "formula": "100 * sum(abs(firstRGBA - lastRGBA)) / (width * height * 4 * 255)",
    "comparison": "first-vs-last-composited-frame",
    "disposalHandling": "GIF89a logical screen; disposal 2 restores the affected rectangle to background and disposal 3 restores the prior canvas.",
    "range": {
      "minimum": 0,
      "maximum": 100,
      "unit": "percent"
    }
  },
  "scope": "Reference fixtures for one raw loop-boundary measurement. No face detection, identity comparison, generated output, provider comparison, or quality grading is performed.",
  "limitations": [
    "A high delta can be intentional motion or a hard cut; a low delta can still hide flicker, blur, occlusion, or identity instability.",
    "The measurement compares only the first and last displayed canvases and does not summarize motion inside the loop.",
    "The RGBA average weights every pixel and channel equally and does not isolate a face or perceptual salience.",
    "The synthetic cases are unit-style controls, not a representative sample of real-world GIF content."
  ],
  "cases": [
    {
      "id": "identical-hold",
      "label": "Identical first and last frames",
      "purpose": "Zero-delta control.",
      "width": 4,
      "height": 4,
      "frameCount": 2,
      "background": [
        0,
        0,
        0,
        255
      ],
      "recipe": "Two opaque 4 x 4 frames with RGBA [40, 80, 120, 255].",
      "result": {
        "status": "measured",
        "rgbaMeanAbsoluteDifferencePct": 0,
        "pixelCount": 16,
        "pixelWork": 32,
        "comparison": "first-vs-last-composited-frame",
        "method": "mean-absolute-rgba-channel-difference",
        "disposalHandling": "gif89a-logical-screen"
      }
    },
    {
      "id": "uniform-rgb-shift-32",
      "label": "Uniform RGB shift by 32",
      "purpose": "Shows the effect of a small whole-frame color change while alpha stays constant.",
      "width": 4,
      "height": 4,
      "frameCount": 2,
      "background": [
        0,
        0,
        0,
        255
      ],
      "recipe": "Opaque black 4 x 4 frame followed by opaque RGB [32, 32, 32].",
      "result": {
        "status": "measured",
        "rgbaMeanAbsoluteDifferencePct": 9.411765,
        "pixelCount": 16,
        "pixelWork": 32,
        "comparison": "first-vs-last-composited-frame",
        "method": "mean-absolute-rgba-channel-difference",
        "disposalHandling": "gif89a-logical-screen"
      }
    },
    {
      "id": "hard-black-white-cut",
      "label": "Full-frame black-to-white cut",
      "purpose": "High-delta control for an intentional hard cut.",
      "width": 4,
      "height": 4,
      "frameCount": 2,
      "background": [
        0,
        0,
        0,
        255
      ],
      "recipe": "Opaque black 4 x 4 frame followed by opaque white.",
      "result": {
        "status": "measured",
        "rgbaMeanAbsoluteDifferencePct": 75,
        "pixelCount": 16,
        "pixelWork": 32,
        "comparison": "first-vs-last-composited-frame",
        "method": "mean-absolute-rgba-channel-difference",
        "disposalHandling": "gif89a-logical-screen"
      }
    },
    {
      "id": "quarter-frame-white-change",
      "label": "One-quarter local white change",
      "purpose": "Separates a local motion-like change from a full-frame cut.",
      "width": 4,
      "height": 4,
      "frameCount": 2,
      "background": [
        0,
        0,
        0,
        255
      ],
      "recipe": "Opaque black 4 x 4 frame followed by an opaque white 2 x 2 patch in the upper-left quadrant.",
      "result": {
        "status": "measured",
        "rgbaMeanAbsoluteDifferencePct": 18.75,
        "pixelCount": 16,
        "pixelWork": 32,
        "comparison": "first-vs-last-composited-frame",
        "method": "mean-absolute-rgba-channel-difference",
        "disposalHandling": "gif89a-logical-screen"
      }
    },
    {
      "id": "restore-to-background",
      "label": "GIF89a restore-to-background disposal",
      "purpose": "Verifies disposal type 2 before the final patch is composited.",
      "width": 2,
      "height": 1,
      "frameCount": 2,
      "background": [
        0,
        0,
        0,
        255
      ],
      "recipe": "Two-pixel red frame disposed to black background, then a one-pixel blue patch.",
      "result": {
        "status": "measured",
        "rgbaMeanAbsoluteDifferencePct": 37.5,
        "pixelCount": 2,
        "pixelWork": 4,
        "comparison": "first-vs-last-composited-frame",
        "method": "mean-absolute-rgba-channel-difference",
        "disposalHandling": "gif89a-logical-screen"
      }
    },
    {
      "id": "restore-to-previous",
      "label": "GIF89a restore-to-previous disposal",
      "purpose": "Verifies disposal type 3 before the final patch is composited.",
      "width": 2,
      "height": 1,
      "frameCount": 2,
      "background": [
        0,
        0,
        0,
        255
      ],
      "recipe": "Two-pixel red frame restored to the prior black canvas, then a one-pixel blue patch.",
      "result": {
        "status": "measured",
        "rgbaMeanAbsoluteDifferencePct": 37.5,
        "pixelCount": 2,
        "pixelWork": 4,
        "comparison": "first-vs-last-composited-frame",
        "method": "mean-absolute-rgba-channel-difference",
        "disposalHandling": "gif89a-logical-screen"
      }
    },
    {
      "id": "owned-animation-sample",
      "label": "Owned 27-frame animation sample",
      "purpose": "Real animated-GIF reference using decoded frames and GIF89a disposal rules.",
      "sourceUrl": "https://deepswapai.com/gifs/gif-face-swap1.gif",
      "sourceSha256": "65a0f7ad2dff00a2c39b69e54ac1f6b1ba688c033dd2d12f62b1567f96c87804",
      "sourceBytes": 386857,
      "width": 200,
      "height": 165,
      "frameCount": 27,
      "durationMs": 1080,
      "minimumFrameDelayMs": 40,
      "maximumFrameDelayMs": 40,
      "recipe": "Parse the owned GIF, decode every image frame to RGBA, apply logical-screen disposal, and compare the first and last displayed canvases.",
      "result": {
        "status": "measured",
        "rgbaMeanAbsoluteDifferencePct": 15.835339,
        "pixelCount": 33000,
        "pixelWork": 891000,
        "comparison": "first-vs-last-composited-frame",
        "method": "mean-absolute-rgba-channel-difference",
        "disposalHandling": "gif89a-logical-screen"
      }
    }
  ]
}
