# Message rendering — handoff

## Summary

Built-in plugins parse and render message bodies: custom markdown (block + inline), HTML sanitization, syntax highlighting, matrix.to links, emoji shortcodes, bad-word filter hooks, and PDF preview support.

## User-facing behavior

- Messages render formatted text, code blocks with Prism highlighting
- Clickable matrix.to / room links
- Custom emoji from packs inline
- Spoiler/highlight/color extensions where enabled

## Architecture

```
RenderMessageContent.tsx
  → react-custom-html-parser.tsx
  → plugins/markdown/ (block + inline parsers)
  → plugins/react-prism/ReactPrism.tsx
  → plugins/emoji.ts, matrix-to.ts, color.ts
msgContent.ts — content type detection
```

## Key files

| Path | Role |
|------|------|
| `cinny/src/app/components/RenderMessageContent.tsx` | Main render entry |
| `cinny/src/app/plugins/react-custom-html-parser.tsx` | HTML → React |
| `cinny/src/app/plugins/markdown/` | Markdown rules + parsers |
| `cinny/src/app/plugins/react-prism/ReactPrism.tsx` | Code highlighting |
| `cinny/src/app/plugins/emoji.ts` | Emoji shortcodes |
| `cinny/src/app/plugins/matrix-to.ts` | matrix.to link handling |
| `cinny/src/app/plugins/bad-words.ts` | Content filter hook |
| `cinny/src/app/plugins/color.ts` | Text color |
| `cinny/src/app/utils/sanitize.ts` | HTML sanitization |
| `cinny/src/app/features/room/msgContent.ts` | Message content helpers |

## Data model

None — pure functions over message content JSON.

## Dependencies

- `prismjs` (via react-prism)
- `pdfjs-dist` wrapper for PDF thumbnails
- `millify` for number formatting in embeds

## Integration points

- **room-timeline**: all message bodies
- **forum**: `forumRichText.ts`, `ForumMessageBody.tsx`
- **custom-emoji-packs**: emoji plugin reads pack data
- **embed-filters**: separate from body render — URL preview gating

## Testing

### Manual

1. Send markdown: bold, code fence, link.
2. Verify matrix.to link navigates in-app.
3. Custom emoji shortcode renders image.
4. XSS attempt in message — should sanitize.

### Automated

- None

## Known issues & gotchas

- Markdown rules split block vs inline — order matters in parser
- `bad-words.ts` may be no-op depending on config
- HTML from other clients may not match Paarrot markdown subset

## Future work

- CommonMark test suite
- Lazy-load Prism languages

## Related docs

- [room-timeline HANDOFF](../room-timeline/HANDOFF.md)
- [custom-emoji-packs HANDOFF](../custom-emoji-packs/HANDOFF.md)

## Add your extra things here

- `plugins/markdown/block/rules.ts` and `inline/rules.ts` — start here for new syntax
- `via-servers.ts` for link join hints
