# refactor\(web\): chat markdown images and videos live in their own module · PR \#22694 · pingdotgg/t3code

[View on GitCafe](https://git.cafe/pingdotgg/t3code/pull/22694)

Repository: [pingdotgg/t3code](https://git.cafe/pingdotgg/t3code)

Visibility: public

State: merged

Source repository: pingdotgg/t3code

Source branch: refactor/chat-markdown-media

Target branch: refactor/chat-markdown-links

Head commit: 9b84cb8097645f14d8b7163ee7a6ba0d608f79d9

[Discussion and reviews](https://git.cafe/pingdotgg/t3code/pull/22694)

[Commits](https://git.cafe/pingdotgg/t3code/pull/22694/commits?format=markdown)

[Files changed](https://git.cafe/pingdotgg/t3code/pull/22694/diffs?format=markdown)

## Description

---

ChatMarkdown.tsx was a 3,560-line file that held every markdown renderer. This stack splits it into focused modules so each piece is readable on its own.

The image, video and asset-image renderers move to `chat/ChatMarkdownMedia.tsx`, along with their fallbacks, sizing helpers and the in-link context. MessagesTimeline and V2ItemInspector now import `ChatMarkdownAssetImage` from there.

This is a pure move. Each renderer was already its own component, so no render boundary changes. Behavior is unchanged.

| | Before | After |
|---|---|---|
| `ChatMarkdown.tsx` lines | 2068 | 1626 |
| New files | | chat/ChatMarkdownMedia.tsx (466) |
| Renders | unchanged: no component, subscription or context boundary moved | unchanged |

Renders were not measured for this layer. It changes no render boundaries: the components, their props, and the two contexts stay exactly as they were.

Tests run:
- `vp test run --project browser src/components/ChatMarkdown.browser.test.tsx src/components/ChatMarkdown.permissions.browser.test.tsx` (11 passed)
- `vp test run --project unit src/reactCompilerCoverage.test.ts` for every touched file (0 bailouts)
- `tsc --noEmit` for apps/web, and `vp lint` on changed files

🤖 Generated with [Claude Code](https://claude.com/claude-code)
