{
  "schemaVersion": 1,
  "contentVersion": "ca42e61ede0a24f789d7287a0001244ad22f4abf",
  "id": "docs/reference/interactive-media",
  "collection": "docs",
  "title": "Interactive media and embeds",
  "description": "Author accessible image comparisons, repository and release cards, and privacy-conscious social embeds.",
  "canonicalUrl": "https://encode.wiki/reference/interactive-media/",
  "apiUrl": "https://encode.wiki/api/v1/documents/docs/reference/interactive-media.json",
  "markdownUrl": "https://encode.wiki/api/v1/markdown/docs/reference/interactive-media.md",
  "status": "current",
  "tags": [
    "images",
    "embeds",
    "contributing"
  ],
  "license": "CC BY-SA 4.0",
  "dates": {
    "lastVerified": "2026-10-08T00:00:00.000Z"
  },
  "authors": [],
  "sources": [
    {
      "title": "X Embedded Posts documentation",
      "url": "https://docs.x.com/x-for-websites/embedded-posts/overview",
      "accessedAt": "2026-08-21T00:00:00.000Z"
    },
    {
      "title": "X oEmbed API and privacy options",
      "url": "https://docs.x.com/x-for-websites/oembed-api",
      "accessedAt": "2026-08-21T00:00:00.000Z"
    },
    {
      "title": "Bluesky oEmbed and Post Embed Widget",
      "url": "https://docs.bsky.app/docs/advanced-guides/oembed",
      "accessedAt": "2026-08-22T00:00:00.000Z"
    },
    {
      "title": "LinkedIn post embedding and public visibility",
      "url": "https://www.linkedin.com/help/linkedin/answer/a529065/embed-content-from-the-linkedin-feed",
      "accessedAt": "2026-08-22T00:00:00.000Z"
    },
    {
      "title": "GitHub REST API",
      "url": "https://docs.github.com/en/rest",
      "accessedAt": "2026-08-22T00:00:00.000Z"
    },
    {
      "title": "GitLab REST API resources",
      "url": "https://docs.gitlab.com/api/api_resources/",
      "accessedAt": "2026-08-22T00:00:00.000Z"
    },
    {
      "title": "Forgejo API usage",
      "url": "https://forgejo.org/docs/latest/user/api/usage/",
      "accessedAt": "2026-08-22T00:00:00.000Z"
    }
  ],
  "headings": [
    {
      "depth": 2,
      "text": "Before-and-after image slider",
      "anchor": "before-and-after-image-slider"
    },
    {
      "depth": 2,
      "text": "Expandable prose images",
      "anchor": "expandable-prose-images"
    },
    {
      "depth": 2,
      "text": "X post embeds",
      "anchor": "x-post-embeds"
    },
    {
      "depth": 2,
      "text": "Bluesky post embeds",
      "anchor": "bluesky-post-embeds"
    },
    {
      "depth": 2,
      "text": "LinkedIn post embeds",
      "anchor": "linkedin-post-embeds"
    },
    {
      "depth": 2,
      "text": "Repository and release cards",
      "anchor": "repository-and-release-cards"
    },
    {
      "depth": 3,
      "text": "Project cards",
      "anchor": "project-cards"
    },
    {
      "depth": 3,
      "text": "Refresh the snapshot",
      "anchor": "refresh-the-snapshot"
    },
    {
      "depth": 3,
      "text": "Repository, issue and pull request cards",
      "anchor": "repository-issue-and-pull-request-cards"
    },
    {
      "depth": 3,
      "text": "Release cards",
      "anchor": "release-cards"
    }
  ],
  "sections": [
    {
      "id": "_preamble",
      "title": "Page introduction",
      "depth": 0,
      "canonicalUrl": "https://encode.wiki/reference/interactive-media/",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/reference/interactive-media/_preamble.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/reference/interactive-media/_preamble.md",
      "checksum": "4da2f01f2136f33d1229be6479b4e6650cddd6990b73e4267e433798cc381b16",
      "bytes": 370
    },
    {
      "id": "before-and-after-image-slider",
      "title": "Before-and-after image slider",
      "depth": 2,
      "anchor": "before-and-after-image-slider",
      "canonicalUrl": "https://encode.wiki/reference/interactive-media/#before-and-after-image-slider",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/reference/interactive-media/before-and-after-image-slider.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/reference/interactive-media/before-and-after-image-slider.md",
      "checksum": "197672776e81440a2310b589ce8e2fd175d101fd1864d2ee01e15c0b2572cb0e",
      "bytes": 913
    },
    {
      "id": "expandable-prose-images",
      "title": "Expandable prose images",
      "depth": 2,
      "anchor": "expandable-prose-images",
      "canonicalUrl": "https://encode.wiki/reference/interactive-media/#expandable-prose-images",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/reference/interactive-media/expandable-prose-images.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/reference/interactive-media/expandable-prose-images.md",
      "checksum": "8c8398147fc7af6ccadd5394b1f8b8c145193bb10552ee2071c3598027b4ddef",
      "bytes": 643
    },
    {
      "id": "x-post-embeds",
      "title": "X post embeds",
      "depth": 2,
      "anchor": "x-post-embeds",
      "canonicalUrl": "https://encode.wiki/reference/interactive-media/#x-post-embeds",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/reference/interactive-media/x-post-embeds.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/reference/interactive-media/x-post-embeds.md",
      "checksum": "c030ddc554320a66d65c5925c7bca48fa019c60a8f8af166ce48a6f103b163b0",
      "bytes": 900
    },
    {
      "id": "bluesky-post-embeds",
      "title": "Bluesky post embeds",
      "depth": 2,
      "anchor": "bluesky-post-embeds",
      "canonicalUrl": "https://encode.wiki/reference/interactive-media/#bluesky-post-embeds",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/reference/interactive-media/bluesky-post-embeds.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/reference/interactive-media/bluesky-post-embeds.md",
      "checksum": "35c71cc1085154ccd4195f3556c40508a842fece0a320af95939e163ffca143b",
      "bytes": 722
    },
    {
      "id": "linkedin-post-embeds",
      "title": "LinkedIn post embeds",
      "depth": 2,
      "anchor": "linkedin-post-embeds",
      "canonicalUrl": "https://encode.wiki/reference/interactive-media/#linkedin-post-embeds",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/reference/interactive-media/linkedin-post-embeds.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/reference/interactive-media/linkedin-post-embeds.md",
      "checksum": "ac3cce3db6e127e721ba07985daa0a10e1ad4eb50d6b56cb4078d9a14393398b",
      "bytes": 906
    },
    {
      "id": "repository-and-release-cards",
      "title": "Repository and release cards",
      "depth": 2,
      "anchor": "repository-and-release-cards",
      "canonicalUrl": "https://encode.wiki/reference/interactive-media/#repository-and-release-cards",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/reference/interactive-media/repository-and-release-cards.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/reference/interactive-media/repository-and-release-cards.md",
      "checksum": "c56796dd12a93f2dc89fb5265ac5523098892677ebd61b8ec2219a1bee5fe234",
      "bytes": 5505
    },
    {
      "id": "project-cards",
      "title": "Project cards",
      "depth": 3,
      "anchor": "project-cards",
      "canonicalUrl": "https://encode.wiki/reference/interactive-media/#project-cards",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/reference/interactive-media/project-cards.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/reference/interactive-media/project-cards.md",
      "checksum": "d97717b33de933237ca891517921b57c0a69e89651fe5d727529105c9ae9c17a",
      "bytes": 2047
    },
    {
      "id": "refresh-the-snapshot",
      "title": "Refresh the snapshot",
      "depth": 3,
      "anchor": "refresh-the-snapshot",
      "canonicalUrl": "https://encode.wiki/reference/interactive-media/#refresh-the-snapshot",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/reference/interactive-media/refresh-the-snapshot.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/reference/interactive-media/refresh-the-snapshot.md",
      "checksum": "8bb273260d05e150977f953e6e3084ae6b64cb5060907d5b5bd3a29621ec3823",
      "bytes": 715
    },
    {
      "id": "repository-issue-and-pull-request-cards",
      "title": "Repository, issue and pull request cards",
      "depth": 3,
      "anchor": "repository-issue-and-pull-request-cards",
      "canonicalUrl": "https://encode.wiki/reference/interactive-media/#repository-issue-and-pull-request-cards",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/reference/interactive-media/repository-issue-and-pull-request-cards.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/reference/interactive-media/repository-issue-and-pull-request-cards.md",
      "checksum": "4884b43b753970617957c3c26db385359ac1a1f5dfdbf031e8e1027af0cf0e7d",
      "bytes": 1631
    },
    {
      "id": "release-cards",
      "title": "Release cards",
      "depth": 3,
      "anchor": "release-cards",
      "canonicalUrl": "https://encode.wiki/reference/interactive-media/#release-cards",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/reference/interactive-media/release-cards.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/reference/interactive-media/release-cards.md",
      "checksum": "3187b172025531a1612d98065109ead3919cba0801fff904849be40bb42d9426",
      "bytes": 772
    }
  ],
  "outboundReferences": [
    "/media/examples/gradient-banded.svg",
    "/media/examples/gradient-reference.svg",
    "https://code.videolan.org/videolan/x264",
    "https://codeberg.org/forgejo/forgejo",
    "https://codeberg.org/forgejo/forgejo/pulls/1",
    "https://github.com/psy-ex/svt-av1-psy",
    "https://github.com/psy-ex/svt-av1-psy/releases/tag/v3.0.2",
    "https://github.com/xiph/rav1e",
    "https://github.com/xiph/rav1e/releases/tag/v0.8.1",
    "https://gitlab.com/AOMediaCodec/SVT-AV1",
    "https://gitlab.com/AOMediaCodec/SVT-AV1/-/issues/2182",
    "https://x.com/Interior/status/463440424141459456"
  ],
  "checksum": "49891387c7fd47e0b8b10c8c1299431f4e84625e70113af33613ccf59255aead",
  "contentFormat": "markdown",
  "markdown": "import {\n  forgejoPullPreview,\n  githubReleasePreview,\n  githubRepositoryPreview,\n  gitlabIssuePreview,\n} from '../../../data/examples/forge-previews';\n\nEncode Wiki provides focused components for encoding-oriented visual evidence. Their no-JavaScript states retain the underlying images or links, and their enhanced controls work with touch, mouse, and keyboard input.\n\n## Before-and-after image slider\n\nDrag the divider, tap a position, or focus the comparison and use the arrow keys. Both images must be local site assets with matching dimensions so the comparison remains stable and does not disclose reader data to another host.\n\n> **Image comparison — Illustrative banding and shape degradation.** [Open the before image](/media/examples/gradient-reference.svg) · [Open the after image](/media/examples/gradient-banded.svg)\n\n```mdx\nimport ImageComparison from '../../../components/ImageComparison.astro';\n\n<ImageComparison\n  beforeSrc=\"/media/comparisons/reference.png\"\n  beforeAlt=\"Describe the reference image.\"\n  beforeLabel=\"Reference\"\n  afterSrc=\"/media/comparisons/encoded.avif\"\n  afterAlt=\"Describe the encoded result and visible differences.\"\n  afterLabel=\"Encoded\"\n  caption=\"Frame 120: reference compared with the test encode\"\n  width={1920}\n  height={1080}\n/>\n```\n\n## Expandable prose images\n\nOrdinary images inside page content are expandable automatically. Click or focus the example below and press Enter or Space. A native dialog shows the largest source the browser selected and retains an “Open original image” link.\n\n<img\n  src=\"/media/examples/gradient-reference.svg\"\n  alt=\"Smooth reference gradient used to demonstrate the page image lightbox.\"\n  width=\"960\"\n  height=\"540\"\n  loading=\"lazy\"\n/>\n\nCarousel, chart, and comparison images are excluded because those components already own their interactions. Add `data-no-image-expand` to an image or ancestor when expansion would be inappropriate.\n\n## X post embeds\n\nX posts are supported without loading a third-party script during ordinary page reading. The reader must choose **Load post** before the site requests X's official widget. The integration requests X's do-not-personalize mode and always preserves a direct post link if the widget is blocked or unavailable.\n\n> **External post:** [Example post from the US Department of the Interior](https://x.com/Interior/status/463440424141459456)\n\n```mdx\nimport XPostEmbed from '../../../components/XPostEmbed.astro';\n\n<XPostEmbed\n  url=\"https://x.com/account/status/1234567890123456789\"\n  label=\"Describe why this post is relevant\"\n  hideMedia={false}\n  hideThread={true}\n/>\n```\n\nOnly HTTPS post URLs on `x.com` and `twitter.com` are accepted. Other providers should receive a provider-specific, consent-gated component and a Content Security Policy review instead of an unrestricted raw iframe.\n\n## Bluesky post embeds\n\nBluesky posts use the provider's oEmbed endpoint and widget only after the reader chooses **Load post**. The response is reduced to an allowlisted blockquote before Bluesky's widget scans it. A direct link remains available if the post is private, deleted, blocked, or unavailable.\n\n<BlueskyPostEmbed\n  url=\"https://bsky.app/profile/bsky.app/post/3mnzpi4dv7s25\"\n  label=\"Example post from Bluesky\"\n/>\n\n```mdx\nimport BlueskyPostEmbed from '../../../components/BlueskyPostEmbed.astro';\n\n<BlueskyPostEmbed\n  url=\"https://bsky.app/profile/account.example/post/3example\"\n  label=\"Describe why this Bluesky post is relevant\"\n/>\n```\n\nOnly `https://bsky.app/profile/{account}/post/{id}` URLs are accepted.\n\n## LinkedIn post embeds\n\nLinkedIn posts are also consent gated. The component creates LinkedIn's official post iframe only after the reader chooses **Load post**. LinkedIn only makes public posts available for embedding and does not support every post format.\n\n<LinkedInPostEmbed\n  url=\"https://www.linkedin.com/posts/linkedin_stay-up-to-date-on-your-linkedin-activity-activity-6124295313319538688-ILYg\"\n  label=\"Example public post from LinkedIn\"\n  height={480}\n/>\n\n```mdx\nimport LinkedInPostEmbed from '../../../components/LinkedInPostEmbed.astro';\n\n<LinkedInPostEmbed\n  url=\"https://www.linkedin.com/feed/update/urn:li:activity:1234567890123456789\"\n  label=\"Describe why this LinkedIn post is relevant\"\n  height={480}\n/>\n```\n\nThe `url` may be a public post URL, a `feed/update` URL, LinkedIn's copied iframe URL, or a post URN such as `urn:li:activity:…`. Heights from 240 to 900 pixels are accepted.\n\n## Repository and release cards\n\nForge cards are compact, static HTML built from `src/data/forge/snapshot.json`, a committed snapshot of public forge metadata. Builds never contact a forge, and readers contact one only when they follow a link. If a repository or resource is missing from the snapshot, the card renders as a plain link.\n\n### Project cards\n\n`ProjectCard` is the card at the top of each tool page. It shows the repository, its description, the latest release (or latest version tag) and its date, the date of the last commit and the license. On shared hosts such as GitHub, GitLab.com and Codeberg it also shows the star count. A badge appears only when the project is archived or had no commits in the year before the snapshot.\n\n> **Repository:** [xiph/rav1e](https://github.com/xiph/rav1e). The fastest and safest AV1 encoder. Latest release: [v0.8.1](https://github.com/xiph/rav1e/releases/tag/v0.8.1), Jun 16, 2025. Last commit: Aug 31, 2026. License: BSD-2-Clause. Stars: 4,160.\n\n> **Repository:** [psy-ex/svt-av1-psy](https://github.com/psy-ex/svt-av1-psy) (Archived). The Scalable Video Technology for AV1 (SVT-AV1 Encoder and Decoder) with perceptual enhancements for psychovisually optimal AV1 encoding. Latest release: [v3.0.2](https://github.com/psy-ex/svt-av1-psy/releases/tag/v3.0.2), Apr 20, 2025. Last commit: Feb 12, 2026. License: BSD-3-Clause-Clear. Stars: 396.\n\n> **Repository:** [videolan/x264](https://code.videolan.org/videolan/x264) (No commits since Sep 2025). x264, the best and fastest H.264 encoder. Last commit: Sep 10, 2025. License: GPL-2.0-or-later.\n\n```mdx\nimport ProjectCard from '../../../components/ProjectCard.astro';\n\n<ProjectCard repository=\"https://github.com/xiph/rav1e\" />\n<ProjectCard repository=\"https://gitlab.com/AOMediaCodec/SVT-AV1\" tag=\"v4.2.0\" />\n<ProjectCard\n  repository=\"https://code.videolan.org/videolan/x264\"\n  provider=\"gitlab\"\n  release={false}\n/>\n```\n\nSet `release={false}` for projects that publish neither releases nor version tags, and `tag` to show a specific release instead of the latest. `src/data/forge/tool-projects.json` maps each tool page to its upstream repository and records whether the project publishes releases, only version tags, or neither. `node scripts/insert-project-cards.mjs` adds the import and card to every mapped page that lacks one; `--check` reports missing cards without writing.\n\n### Refresh the snapshot\n\n```sh\npnpm forge:refresh\nGITHUB_TOKEN=… pnpm forge:refresh --only rav1e\n```\n\nThe refresh script reads the tool mapping and every `ForgeCard`, `ReleaseCard` and `ProjectCard` in the content (cards in code blocks and cards with example data are skipped), queries the GitHub, GitLab and Forgejo APIs, and records `fetchedAt` for each entry. Anonymous requests work, but GitHub allows only 60 an hour. `GITHUB_TOKEN` is sent only to `api.github.com` and `GITLAB_TOKEN` only to `gitlab.com`; other hosts are queried anonymously. Pass `--wait` to sleep through rate limits and `--only <text>` to refresh matching URLs. Entries that fail keep their previous data and the script exits non-zero.\n\n### Repository, issue and pull request cards\n\n`ForgeCard` accepts a repository, issue, pull request or merge request URL. The examples below pass `preview` data from `src/data/examples/forge-previews.ts` instead of reading the snapshot.\n\n> **Repository:** [xiph/rav1e](https://github.com/xiph/rav1e). The fastest and safest AV1 encoder. Last commit: Aug 31, 2026. License: BSD-2-Clause. Stars: 4,160.\n\n> **Forge link:** [#2182 SVT-AV1](https://gitlab.com/AOMediaCodec/SVT-AV1/-/issues/2182). Repository: [AOMediaCodec/SVT-AV1](https://gitlab.com/AOMediaCodec/SVT-AV1).\n\n> **Forge link:** [#1 forgejo](https://codeberg.org/forgejo/forgejo/pulls/1). Repository: [forgejo/forgejo](https://codeberg.org/forgejo/forgejo).\n\n```mdx\nimport ForgeCard from '../../../components/ForgeCard.astro';\n\n<ForgeCard url=\"https://github.com/xiph/rav1e\" />\n<ForgeCard url=\"https://github.com/owner/project/issues/123\" />\n<ForgeCard url=\"https://gitlab.com/group/project/-/merge_requests/42\" />\n<ForgeCard url=\"https://codeberg.org/owner/project/pulls/7\" />\n```\n\nIssue and pull or merge request cards show the reference, title, state, repository, author, update date, comment count and labels. GitHub, GitLab.com, GitGud, Codeberg and Forgejo's own instance are detected automatically. Use a provider hint for other self-hosted instances:\n\n```mdx\n<ForgeCard url=\"https://git.example.org/group/project/-/issues/12\" provider=\"gitlab\" />\n<ForgeCard url=\"https://code.example.org/owner/project/pulls/12\" provider=\"forgejo\" />\n```\n\nThe refresh script only queries HTTPS URLs on public DNS names and refuses hosts that resolve to private or local addresses.\n\n### Release cards\n\n`ReleaseCard` accepts a repository base URL. Omit `tag` for the latest published release at the time of the snapshot, or set it for a specific release.\n\n> **Forge link:** [v0.8.1](https://github.com/xiph/rav1e/releases/tag/v0.8.1) (Latest). Repository: [xiph/rav1e](https://github.com/xiph/rav1e). Published: Jun 16, 2025.\n\n```mdx\nimport ReleaseCard from '../../../components/ReleaseCard.astro';\n\n<ReleaseCard repository=\"https://github.com/xiph/rav1e\" />\n<ReleaseCard repository=\"https://github.com/xiph/rav1e\" tag=\"v0.7.1\" />\n<ReleaseCard repository=\"https://gitgud.io/group/project\" provider=\"gitlab\" />\n```\n\nRelease cards show the release name and tag, the publication state (pre-releases and drafts are labelled), the author, date and asset count.\n"
}
