diff --git a/app/globals.css b/app/globals.css index 7cbee69..04df8b0 100644 --- a/app/globals.css +++ b/app/globals.css @@ -1,6 +1,6 @@ @import "tailwindcss"; @import "tw-animate-css"; -@source "../node_modules/streamdown/dist/*.js"; +/* @source "../node_modules/streamdown/dist/*.js"; */ @custom-variant dark (&:is(.dark *)); @@ -277,17 +277,17 @@ } [data-streamdown="code-block"] { - @apply my-3 overflow-hidden rounded-lg border border-primary-border bg-primary-bg [corner-shape:squircle]; + @apply my-3 p-0 gap-0 flex flex-col rounded-lg border-0 ring ring-primary-border shadow-xs; } [data-streamdown="code-block-header"] { - @apply flex items-center justify-between border-b border-primary-border bg-primary-bg p-3 text-xs text-ink-primary; + @apply flex items-center justify-between [&>span]:font-sans h-auto px-3 py-4 -my-2 bg-tertiary-bg border-0 text-xs text-ink-primary; } [data-streamdown="code-block-body"] { - @apply overflow-x-auto p-3 bg-primary-bg text-sm leading-relaxed; + @apply overflow-x-auto border-0 p-3 bg-primary-bg ring ring-tertiary-border text-sm leading-relaxed; } [data-streamdown="inline-code"] { - @apply rounded-sm bg-primary-bg px-1 py-0.5 text-sm text-ink-primary; + @apply rounded-sm bg-primary-bg border border-primary-border px-1 py-0.5 text-sm text-ink-secondary; } [data-streamdown="link"] { @@ -327,39 +327,29 @@ } [data-streamdown="table-wrapper"] { - @apply my-3 overflow-x-auto; + @apply my-3 border-0 p-0 gap-0 flex flex-col ring ring-secondary-border overflow-x-auto [&_div]:border-0; } [data-streamdown="table"] { - @apply w-full text-sm; + @apply w-full text-sm border-0 p-0 gap-0 bg-tertiary-bg; } [data-streamdown="table-header"] { - @apply border-b border-primary-border bg-primary-bg; + @apply [&_tr]:border-0 [&_tr]:bg-tertiary-bg [&_th]:px-4 [&_th]:py-2 [&>tr]:-my-2; +} + +[data-streamdown="table-body"] { + @apply rounded-xl overflow-hidden; + clip-path: inset(0 round 12px); } [data-streamdown="table-header-cell"] { - @apply px-3 py-1.5 text-left font-medium text-ink-primary; + @apply px-3 py-1.5 text-left font-medium text-ink-primary overflow-hidden; } [data-streamdown="table-row"] { - @apply border-b border-primary-border; + @apply border-b border-primary-border overflow-hidden; } [data-streamdown="table-cell"] { - @apply px-3 py-1.5 text-ink-primary; + @apply px-3 py-1.5 text-ink-primary bg-primary-bg overflow-hidden; } [data-streamdown="image"] { @apply max-w-full rounded-md; } - -/* ─── Shiki dual-theme code blocks ─── - CodeBlock highlights with { light: github-light, dark: github-dark } and - defaultColor:false, so shiki emits per-token CSS variables instead of a fixed - color. Activate light by default and swap to dark under the .dark class. Only - the text color switches — the
 keeps its own bg-secondary surface. */
-.shiki,
-.shiki span {
-  color: var(--shiki-light);
-}
-
-.dark .shiki,
-.dark .shiki span {
-  color: var(--shiki-dark);
-}
diff --git a/app/layout.tsx b/app/layout.tsx
index 941fcc1..aace71f 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,7 +1,7 @@
 import type { Metadata } from "next";
 import { IBM_Plex_Mono, Inter } from "next/font/google";
 import { Providers } from "@/components/providers";
-import "streamdown/styles.css";
+// import "streamdown/styles.css";
 import "./globals.css";
 const inter = Inter({
   variable: "--font-inter",
diff --git a/bun.lock b/bun.lock
index 1fa79c8..c9fef0a 100644
--- a/bun.lock
+++ b/bun.lock
@@ -10,6 +10,7 @@
         "@ai-sdk/react": "^3.0.220",
         "@base-ui/react": "^1.6.0",
         "@intentface/chat": "workspace:*",
+        "@streamdown/code": "^1.1.1",
         "@tiptap/core": "^3.27.1",
         "@tiptap/extension-document": "^3.27.1",
         "@tiptap/extension-paragraph": "^3.27.1",
@@ -449,24 +450,26 @@
 
     "@oxc-transform/binding-win32-x64-msvc": ["@oxc-transform/binding-win32-x64-msvc@0.93.0", "", { "os": "win32", "cpu": "x64" }, "sha512-6QN3DEaEw3eWioWEFRgNsTvYq8czYSnpkjB2za+/WdLN0g5FzOl2ZEfNiPrBWIPnSmjUmDWtWVWcSjwY7fX5/Q=="],
 
-    "@shikijs/core": ["@shikijs/core@4.3.0", "", { "dependencies": { "@shikijs/primitive": "4.3.0", "@shikijs/types": "4.3.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-EooU3i9F6IAE8kEu+AnGf9DFZWkQBZ+hJn3tLVbsH+61mtQiva5biai66fAA6nvFPXkLgvrh7BrR7YcJU83xQQ=="],
+    "@shikijs/core": ["@shikijs/core@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA=="],
 
-    "@shikijs/engine-javascript": ["@shikijs/engine-javascript@4.3.0", "", { "dependencies": { "@shikijs/types": "4.3.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.6" } }, "sha512-hTv/KiFf2tpiqlACPiztGGurEARWIutB8YUhcrA1pUC7VzzwKO+g5crUocrLztrZ5ro5Z4hbXg7bYclETn3gSQ=="],
+    "@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA=="],
 
-    "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@4.3.0", "", { "dependencies": { "@shikijs/types": "4.3.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-1vMdN3gHfnKfLYwecUI2ITJI4RhHt96xEaJumVn7Heb0IlJ8WQMIH0Voak+2j22BpSNKdnOfB/pCTPnPm2gq7A=="],
+    "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g=="],
 
-    "@shikijs/langs": ["@shikijs/langs@4.3.0", "", { "dependencies": { "@shikijs/types": "4.3.0" } }, "sha512-rnlqFbBRSys9bT4gl/5rw9RnS0W/I84ZldXPkO7cvlEMoV85TyF/aU01N7/NbSR776RNLjrJKjfFUXJR6wN1Cg=="],
+    "@shikijs/langs": ["@shikijs/langs@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0" } }, "sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg=="],
 
     "@shikijs/primitive": ["@shikijs/primitive@4.3.0", "", { "dependencies": { "@shikijs/types": "4.3.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-CPkz64PTa5diRW1ggzMZH9VM/du4RNChYgVtgqrFcgruvIybmCvySv8GkiHSczUHXYuuR8TdKEwFx+UnZMpgdg=="],
 
-    "@shikijs/themes": ["@shikijs/themes@4.3.0", "", { "dependencies": { "@shikijs/types": "4.3.0" } }, "sha512-Avgt05YiT+Y3prjIc9lmQxhJzHBcCfR6cjiFW4OyaMBbt2A6trX5rfjUzx+Vj/mE9qpArYjatnqo9XPjQNW/AQ=="],
+    "@shikijs/themes": ["@shikijs/themes@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0" } }, "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA=="],
 
-    "@shikijs/types": ["@shikijs/types@4.3.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oc8b9U2SYvofKZk8e/737nIX0qwf6eV2vHFATeObAu7r+mUVpLs8Re0BmVkIjAWAYgkmG/CzLNo7rzuBzRu/wQ=="],
+    "@shikijs/types": ["@shikijs/types@3.23.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ=="],
 
     "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="],
 
     "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
 
+    "@streamdown/code": ["@streamdown/code@1.1.1", "", { "dependencies": { "shiki": "^3.19.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0" } }, "sha512-i7HTNuDgZWb+VdrNVOam9gQhIc5MSSDXKWXgbUrn/4vSRaSMM+Rtl10MQj4wLWPNpF7p80waJsAqFP8HZfb0Jg=="],
+
     "@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="],
 
     "@tailwindcss/node": ["@tailwindcss/node@4.3.2", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "5.21.6", "jiti": "^2.7.0", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.3.2" } }, "sha512-yWP/sqEcBLaD8JuA6zNwxoYKr75qxTioYwlRwekj5Jr/I5GXnoJfjetH/psLUIv74cYTH2lBUEzBkinthoYcBg=="],
@@ -1277,7 +1280,7 @@
 
     "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
 
-    "shiki": ["shiki@4.3.0", "", { "dependencies": { "@shikijs/core": "4.3.0", "@shikijs/engine-javascript": "4.3.0", "@shikijs/engine-oniguruma": "4.3.0", "@shikijs/langs": "4.3.0", "@shikijs/themes": "4.3.0", "@shikijs/types": "4.3.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-NKKjWzR6LIGL3sXBrWDw9sDS9cxx42/DkysaNqJEeOWE8Kix5gpak0bc00OfDVEO4oyXSyz8+aRaqKoBD1yo7A=="],
+    "shiki": ["shiki@3.23.0", "", { "dependencies": { "@shikijs/core": "3.23.0", "@shikijs/engine-javascript": "3.23.0", "@shikijs/engine-oniguruma": "3.23.0", "@shikijs/langs": "3.23.0", "@shikijs/themes": "3.23.0", "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA=="],
 
     "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
 
@@ -1413,6 +1416,8 @@
 
     "@manypkg/get-packages/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="],
 
+    "@shikijs/primitive/@shikijs/types": ["@shikijs/types@4.3.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oc8b9U2SYvofKZk8e/737nIX0qwf6eV2vHFATeObAu7r+mUVpLs8Re0BmVkIjAWAYgkmG/CzLNo7rzuBzRu/wQ=="],
+
     "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.11.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" }, "bundled": true }, "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ=="],
 
     "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.11.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw=="],
@@ -1435,6 +1440,8 @@
 
     "d3-sankey/d3-shape": ["d3-shape@1.3.7", "", { "dependencies": { "d3-path": "1" } }, "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw=="],
 
+    "fumadocs-core/shiki": ["shiki@4.3.0", "", { "dependencies": { "@shikijs/core": "4.3.0", "@shikijs/engine-javascript": "4.3.0", "@shikijs/engine-oniguruma": "4.3.0", "@shikijs/langs": "4.3.0", "@shikijs/themes": "4.3.0", "@shikijs/types": "4.3.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-NKKjWzR6LIGL3sXBrWDw9sDS9cxx42/DkysaNqJEeOWE8Kix5gpak0bc00OfDVEO4oyXSyz8+aRaqKoBD1yo7A=="],
+
     "fumadocs-mdx/js-yaml": ["js-yaml@4.3.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q=="],
 
     "mermaid/marked": ["marked@16.4.2", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA=="],
@@ -1455,6 +1462,18 @@
 
     "d3-sankey/d3-shape/d3-path": ["d3-path@1.0.9", "", {}, "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="],
 
+    "fumadocs-core/shiki/@shikijs/core": ["@shikijs/core@4.3.0", "", { "dependencies": { "@shikijs/primitive": "4.3.0", "@shikijs/types": "4.3.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-EooU3i9F6IAE8kEu+AnGf9DFZWkQBZ+hJn3tLVbsH+61mtQiva5biai66fAA6nvFPXkLgvrh7BrR7YcJU83xQQ=="],
+
+    "fumadocs-core/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@4.3.0", "", { "dependencies": { "@shikijs/types": "4.3.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.6" } }, "sha512-hTv/KiFf2tpiqlACPiztGGurEARWIutB8YUhcrA1pUC7VzzwKO+g5crUocrLztrZ5ro5Z4hbXg7bYclETn3gSQ=="],
+
+    "fumadocs-core/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@4.3.0", "", { "dependencies": { "@shikijs/types": "4.3.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-1vMdN3gHfnKfLYwecUI2ITJI4RhHt96xEaJumVn7Heb0IlJ8WQMIH0Voak+2j22BpSNKdnOfB/pCTPnPm2gq7A=="],
+
+    "fumadocs-core/shiki/@shikijs/langs": ["@shikijs/langs@4.3.0", "", { "dependencies": { "@shikijs/types": "4.3.0" } }, "sha512-rnlqFbBRSys9bT4gl/5rw9RnS0W/I84ZldXPkO7cvlEMoV85TyF/aU01N7/NbSR776RNLjrJKjfFUXJR6wN1Cg=="],
+
+    "fumadocs-core/shiki/@shikijs/themes": ["@shikijs/themes@4.3.0", "", { "dependencies": { "@shikijs/types": "4.3.0" } }, "sha512-Avgt05YiT+Y3prjIc9lmQxhJzHBcCfR6cjiFW4OyaMBbt2A6trX5rfjUzx+Vj/mE9qpArYjatnqo9XPjQNW/AQ=="],
+
+    "fumadocs-core/shiki/@shikijs/types": ["@shikijs/types@4.3.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oc8b9U2SYvofKZk8e/737nIX0qwf6eV2vHFATeObAu7r+mUVpLs8Re0BmVkIjAWAYgkmG/CzLNo7rzuBzRu/wQ=="],
+
     "next/postcss/nanoid": ["nanoid@3.3.15", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA=="],
 
     "read-yaml-file/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="],
diff --git a/components/ai/composer.tsx b/components/ai/composer.tsx
index ea130db..556ae48 100644
--- a/components/ai/composer.tsx
+++ b/components/ai/composer.tsx
@@ -84,7 +84,7 @@ const ComposerContainer = ({ className, ...props }: ComposerContainerProps) => (
       // Positioned so it paints above the context window peeking out from
       // behind its top edge. Edge is shadow-drawn (shadow-border), not a
       // border, matching the playground cards.
-      "relative bg-primary-bg rounded-4xl border border-primary-border shadow-xs [corner-shape:squircle] cursor-text transition-colors",
+      "relative bg-primary-bg rounded-2xl border border-primary-border shadow-xs cursor-text transition-colors",
       className,
     )}
     {...props}
@@ -188,6 +188,7 @@ type ComposerTextareaProps = {
 
 const ComposerTextarea = ({ className, disabled = false, ...props }: ComposerTextareaProps) => (
    (
       // coordinates); portaled to the body, so it never reserves layout in the composer.
       // Match the composer Container's width via the positioner's --anchor-width var.
       "absolute z-50 w-(--anchor-width) overflow-hidden",
-      "rounded-4xl border border-primary-border bg-primary-bg [corner-shape:squircle]",
+      "rounded-2xl border border-primary-border bg-primary-bg",
       "transition-[opacity,transform] duration-150 ease-out",
       "data-starting-style:opacity-0 data-ending-style:opacity-0",
       // Slide from the anchored edge: default (above) drops in from below; flipped
@@ -396,7 +398,7 @@ const ComposerPopover = ({ className, ...props }: ComposerPopoverProps) => {
         // off the anchor token with a stronger shadow. `absolute` is the base positioning
         // context (the positioner then writes left/top in page coordinates); z-50 keeps
         // the portaled popover above the thread.
-        "absolute z-50 w-72 overflow-hidden border border-primary-border bg-primary-bg rounded-4xl shadow-lg [corner-shape:squircle]",
+        "absolute z-50 w-72 overflow-hidden border border-primary-border bg-primary-bg rounded-2xl shadow-lg",
         "transition-[opacity,transform,filter] duration-150 ease-out",
         "data-closed:opacity-0 data-closed:blur-[3px]",
         // Slide from the anchored edge — opens upward by default, downward when flipped.
diff --git a/components/docs/intentface.css b/components/docs/intentface.css
index 3808cfd..8151b74 100644
--- a/components/docs/intentface.css
+++ b/components/docs/intentface.css
@@ -1,5 +1,3 @@
-@source "../node_modules/streamdown/dist/*.js";
-
 @custom-variant dark (&:is(.dark *));
 
 :root {
diff --git a/components/ui/markdown.tsx b/components/ui/markdown.tsx
index 31cf575..0d84a5c 100644
--- a/components/ui/markdown.tsx
+++ b/components/ui/markdown.tsx
@@ -1,3 +1,4 @@
+import { code } from "@streamdown/code";
 import type { ComponentProps } from "react";
 import type { Components } from "streamdown";
 import { Streamdown } from "streamdown";
@@ -63,12 +64,14 @@ const Markdown = ({
   ...props
 }: ComponentProps) => (
   *:first-child]:mt-0 [&>*:last-child]:mb-0",
+      "px-px text-md [&_p]:whitespace-pre-wrap [&>*:first-child]:mt-0 [&>*:last-child]:mb-0",
       className,
     )}
+    shikiTheme={["github-light", "vesper"]}
     {...props}
   />
 );
diff --git a/package.json b/package.json
index beb3d7c..cf0886d 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,7 @@
     "@ai-sdk/react": "^3.0.220",
     "@base-ui/react": "^1.6.0",
     "@intentface/chat": "workspace:*",
+    "@streamdown/code": "^1.1.1",
     "@tiptap/core": "^3.27.1",
     "@tiptap/extension-document": "^3.27.1",
     "@tiptap/extension-paragraph": "^3.27.1",
diff --git a/packages/chat/src/chip-markdown.ts b/packages/chat/src/chip-markdown.ts
index b5e3d8a..0852e83 100644
--- a/packages/chat/src/chip-markdown.ts
+++ b/packages/chat/src/chip-markdown.ts
@@ -51,6 +51,13 @@ export const encodeChipMarkdown = (chip: ChipData): string => {
 };
 
 export const parseChipSegments = (text: string): ChipSegment[] => {
+  // Fast path — every chip token contains this literal, and most message text
+  // carries no chips; an includes() probe is far cheaper than a regex scan of
+  // the full text (which the streaming row would otherwise repeat per token).
+  if (!text.includes("](chip:")) {
+    return text.length > 0 ? [{ type: "text", text }] : [];
+  }
+
   const segments: ChipSegment[] = [];
   let lastIndex = 0;
   for (const match of text.matchAll(CHIP_REF_PATTERN)) {
diff --git a/packages/chat/src/message.tsx b/packages/chat/src/message.tsx
index ff626bc..c2a0d84 100644
--- a/packages/chat/src/message.tsx
+++ b/packages/chat/src/message.tsx
@@ -99,20 +99,27 @@ const MessageText = ({
   renderChip,
   ...elementProps
 }: MessageTextProps) => {
-  const segments = parseChipSegments(children);
-
-  const segmentNodes = segments.map((segment, index) =>
-    segment.type === "text" ? (
-      {renderText ? renderText(segment.text, index) : segment.text}
-    ) : (
-      
-        {renderChip ? (
-          renderChip(segment, index)
+  // Settled rows re-render for reasons other than their text (data-last flips,
+  // parent context) — memoizing on the text keeps them from re-parsing and
+  // rebuilding the segment tree each time.
+  const segmentNodes = useMemo(
+    () =>
+      parseChipSegments(children).map((segment, index) =>
+        segment.type === "text" ? (
+          
+            {renderText ? renderText(segment.text, index) : segment.text}
+          
         ) : (
-          {segment.label}
-        )}
-      
-    ),
+          
+            {renderChip ? (
+              renderChip(segment, index)
+            ) : (
+              {segment.label}
+            )}
+          
+        ),
+      ),
+    [children, renderText, renderChip],
   );
 
   return useRenderElement(