···8787**`src/routes/__root.tsx`:**
8888- Page title is still "TanStack Start Starter" — should be "Dudesky"
89899090+## Before threading: two features to add
9191+9292+### 1. Images in posts
9393+9494+Bluesky posts can have image embeds. The embed lives at `item.post.embed` — when it's an image embed, the type is `app.bsky.embed.images#view` and it has an `images` array where each entry has `thumb` (URL), `fullsize` (URL), and `alt` (string).
9595+9696+Add `images` to the mapped return in `getTimeline`:
9797+9898+```ts
9999+images: (item.post.embed as { images?: { thumb: string; fullsize: string; alt: string }[] } | undefined)?.images ?? []
100100+```
101101+102102+Then render them below the post text — a simple responsive grid of `<img>` tags with `src={thumb}` and `alt={alt}` works for starters.
103103+104104+### 2. Link previews
105105+106106+Bluesky posts can have an external embed (link preview card) at `item.post.embed`. Discriminate on `$type` — the value for a link preview is `'app.bsky.embed.external#view'`. The embed's `external` object has `uri`, `title`, `description`, and optionally `thumb` (image URL).
107107+108108+Add `linkPreview` to the mapped return:
109109+110110+```ts
111111+const embed = item.post.embed as { $type?: string; external?: { uri: string; title: string; description: string; thumb?: string } } | undefined
112112+linkPreview: embed?.$type === 'app.bsky.embed.external#view' ? (embed.external ?? null) : null
113113+```
114114+115115+Render as a card below the post text — thumbnail on the left, title + description + domain on the right, full card is a link to `uri`. Use `.island-shell` or a bordered inset style.
116116+117117+Note: a post has at most one embed — it's images OR a link preview, not both. Use `$type` to discriminate: `'app.bsky.embed.images#view'` for images, `'app.bsky.embed.external#view'` for link previews.
118118+90119## Next: threaded reply views
9112092121Goal: clicking a post opens a thread view showing the post, its ancestors (parent chain), and its replies.