Skip to content

feat: play external GIF embeds inline - #2

Open
devjerry0 wants to merge 4 commits into
feat/external-gif-verificationfrom
feat/external-gif-playback
Open

devjerry0 wants to merge 4 commits into
feat/external-gif-verificationfrom
feat/external-gif-playback

Conversation

@devjerry0

@devjerry0 devjerry0 commented Oct 26, 2026 •

Copy link
Copy Markdown
Owner

Summary

Renders Giphy share links and verified external GIF URLs inline from their hosts. GIFs autoplay while visible, unload offscreen, respect reduced motion, and allow two manual retries after failures.

Stack 3/6, split from closed #891. Depends on feat/external-gif-verification. This PR is in the fork to keep the review diff limited to this layer; open it upstream after its dependency lands.

Changes

Diff against this PR's base: 24 files, +1,510/-7. 59% of changed lines are tests, fixtures, or test support.

  • Expose GIF embeds and their frontend renderer together, including API serialization. No upload, conversion, hosting, or provider keys.
  • Retain card dimensions during loading, Stop, and failure. Keep the 28px Stop control accessible by hover, focus, and touch.
  • Cover poster/animation loading, safe sources in every playback mode, reduced motion, source changes, stale callbacks, and bounded manual retries.

Visual explanation

flowchart TD
    E["Server-authorized GIF embed"] --> G{"Visible and safe HTTPS source?"}
    G -- No --> S["Animation unloaded; card size retained"]
    G -- Yes --> M{"Reduced motion?"}
    M -- Yes --> P["Press Play"]
    M -- No --> A["Load and play animation"]
    P --> A
    A -- Stop or offscreen --> S
    A -- Load failure --> R["Up to two user-initiated retries"]
    R -- Retry --> A
    R -- Limit reached --> F["Failure state retained"]
Loading

Stack and merge order

  1. Fetch boundaries and service contract — upstream
  2. External GIF verification
  3. Inline GIF playback
  4. Cached, queued draft API
  5. Composer link previews
  6. Optional mutation checks

Layers 2–6 target their immediate predecessor in the fork. Submit them upstream in order after their dependency lands; each review diff contains only its layer.

Validation

PreviewLink now lives under App\Contracts\Services (namespace-only follow-up, head 861687968f7b4909830b5113313092844cf238c8). Focused fetching/verification suites and the final stack’s required checks passed after the move; the earlier per-layer results and implementation review below remain the baseline.

Container checks passed on PHP 8.5.12: 4,601 PHP tests / 25,282 assertions, 100% PHP coverage and type coverage, 223 Node tests, and 631 component tests across 50 files. PHPStan, TypeScript, lint, and production build pass (19 lint warnings, no errors).

Lint: Pint, Rector --dry-run --debug (same rules, serial execution), and Bun lint. Other commands: composer test:types, composer test:type-coverage, full parallel Pest CI coverage at exactly 100%, bun run test:unit, and bun run build.

Visual evidence

Inline GIF card in the feed

Desktop Chrome, dark theme, cropped to the relevant card/composer. Captured from the reassembled stack; no post was published and the existing draft was preserved.

Screen.Recording.2026-10-21.at.12.38.12.mp4

The existing desktop recording shows Giphy/direct-GIF autoplay and Stop/restart.

Device verification

Desktop Chrome smoke only. No hardware/simulator mobile verification or renewed full viewport/theme/CLS matrix is claimed.

Independent review

Independent code review: PASS, base 9a4b22f473e3d73e6fd1e5180a38e892afa212ed, head b8d3f368a56be51feb0d414d0b6a821565b5d34a. Full visual/device review remains incomplete.

Limitations

Hosted CI has not been verified for this new PR. The existing visual/device evidence gaps remain disclosed above.

Codex-Thread: 01a15b08-d4ad-7e72-8725-b3ea1fde71ce

Expose Giphy and verified GIF embeds atomically with frontend playback, reduced motion and manual retries.

Codex-Thread: 01a15b08-d4ad-7e72-8725-b3ea1fde71ce
Keep each layer based on the updated predecessor without rewriting history.

Codex-Thread: 01a15b08-d4ad-7e72-8725-b3ea1fde71ce
Keep the layer based on its updated predecessor without rewriting history.

Codex-Thread: 01a15b08-d4ad-7e72-8725-b3ea1fde71ce
Codex-Thread: 01a15b08-d4ad-7e72-8725-b3ea1fde71ce
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant