diff --git a/apps/website/src/components/landing/EmbedFrame.tsx b/apps/website/src/components/landing/EmbedFrame.tsx
new file mode 100644
index 000000000..f0100d4ec
--- /dev/null
+++ b/apps/website/src/components/landing/EmbedFrame.tsx
@@ -0,0 +1,109 @@
+'use client';
+import { useState } from 'react';
+import { tokens } from '@cacheplane/design-tokens';
+
+interface EmbedFrameProps {
+ src: string;
+ title: string;
+ height?: number;
+}
+
+function ExpandIcon() {
+ return (
+
+ );
+}
+
+function CloseIcon() {
+ return (
+
+ );
+}
+
+export function EmbedFrame({ src, title, height = 400 }: EmbedFrameProps) {
+ const [fullscreen, setFullscreen] = useState(false);
+
+ if (fullscreen) {
+ return (
+
+
+
+ {title}
+
+
+
+
+
+ );
+ }
+
+ return (
+
+
+
+
+
+
+
+ );
+}
diff --git a/apps/website/src/components/landing/HighlightedCode.tsx b/apps/website/src/components/landing/HighlightedCode.tsx
index f1b7d8b44..55959cba3 100644
--- a/apps/website/src/components/landing/HighlightedCode.tsx
+++ b/apps/website/src/components/landing/HighlightedCode.tsx
@@ -14,7 +14,7 @@ export async function HighlightedCode({ code, lang = 'typescript' }: Highlighted
return (
);
diff --git a/apps/website/src/components/landing/angular/AngularComparison.tsx b/apps/website/src/components/landing/angular/AngularComparison.tsx
index 31cdb3014..2820c854e 100644
--- a/apps/website/src/components/landing/angular/AngularComparison.tsx
+++ b/apps/website/src/components/landing/angular/AngularComparison.tsx
@@ -4,15 +4,15 @@ import { motion } from 'framer-motion';
import { tokens } from '@cacheplane/design-tokens';
const ROWS = [
- { capability: 'SSE streaming', theirs: 'Manual wiring', ours: 'Signal-native via agent()' },
- { capability: 'State management', theirs: 'Custom signals', ours: 'Built-in reactive state' },
- { capability: 'Thread persistence', theirs: 'DIY localStorage', ours: 'Built-in threadId signal + restore' },
- { capability: 'Interrupt handling', theirs: 'Manual Command.RESUME', ours: 'interrupt() signal + approve/edit/cancel' },
- { capability: 'Tool call rendering', theirs: 'Raw events', ours: 'Structured tool call state' },
- { capability: 'Time travel', theirs: 'Not included', ours: 'Built-in state history' },
- { capability: 'Testing', theirs: 'Against live API', ours: 'MockStreamTransport, offline, <100ms' },
- { capability: 'OnPush compatibility', theirs: 'Requires workarounds', ours: 'Native signal support' },
- { capability: 'DeepAgent support', theirs: 'Not included', ours: 'Full multi-agent orchestration' },
+ { capability: 'SSE streaming', theirs: 'Raw Client + for-await loop', ours: 'Signal-native via agent()' },
+ { capability: 'State management', theirs: 'Manual BehaviorSubject → Signal', ours: 'Built-in reactive state' },
+ { capability: 'Thread persistence', theirs: 'DIY localStorage + API calls', ours: 'Built-in threadId signal + restore' },
+ { capability: 'Interrupt handling', theirs: 'Manual Command.RESUME wiring', ours: 'interrupt() signal + approve/edit/cancel' },
+ { capability: 'Tool call rendering', theirs: 'Parse raw SSE events', ours: 'Structured tool call state' },
+ { capability: 'Time travel', theirs: 'Build from scratch', ours: 'Built-in state history' },
+ { capability: 'Testing', theirs: 'Against live API', ours: 'MockAgentTransport, offline, <100ms' },
+ { capability: 'OnPush compatibility', theirs: 'Custom change detection workarounds', ours: 'Native signal support' },
+ { capability: 'React parity', theirs: 'useStream() is React-only', ours: 'agent() — full useStream() parity for Angular' },
];
export function AngularComparison() {
@@ -37,7 +37,7 @@ export function AngularComparison() {
fontSize: 'clamp(26px,3.5vw,42px)', fontWeight: 800, lineHeight: 1.1,
color: tokens.colors.textPrimary,
}}>
- LangGraph Angular SDK vs @cacheplane/angular
+ @langchain/langgraph-sdk vs @cacheplane/angular
@@ -57,7 +57,7 @@ export function AngularComparison() {
display: 'grid', gridTemplateColumns: 'minmax(100px, 1fr) minmax(120px, 1fr) minmax(120px, 1fr)',
background: 'rgba(255,255,255,.3)', borderBottom: `1px solid ${tokens.glass.border}`, padding: '14px 24px',
}}>
- {['Capability', 'LangGraph Angular SDK', '@cacheplane/angular'].map((h, i) => (
+ {['Capability', '@langchain/langgraph-sdk', '@cacheplane/angular'].map((h, i) => (
-
-
-
+
))}
diff --git a/apps/website/src/components/landing/angular/AngularProblemSolution.tsx b/apps/website/src/components/landing/angular/AngularProblemSolution.tsx
index 7b099cf37..dc26a374a 100644
--- a/apps/website/src/components/landing/angular/AngularProblemSolution.tsx
+++ b/apps/website/src/components/landing/angular/AngularProblemSolution.tsx
@@ -4,11 +4,11 @@ import { motion } from 'framer-motion';
import { tokens } from '@cacheplane/design-tokens';
const PAIN_POINTS = [
- 'Zone.js interference with SSE event streams',
- 'Manual subscription management and cleanup',
- 'Custom SSE wiring that breaks under load',
- 'Incompatibility with OnPush change detection',
- 'No deterministic test story for streaming',
+ 'Raw Client + for-await SSE loop — no Angular integration',
+ 'Manual BehaviorSubject → Signal wiring for each state slice',
+ 'Thread persistence, interrupt handling built from scratch',
+ 'No OnPush-compatible signal API — custom change detection workarounds',
+ 'Testing against live LangGraph API — slow, flaky, non-deterministic',
];
const SOLUTIONS = [
@@ -42,13 +42,13 @@ export function AngularProblemSolution() {
fontSize: '0.58rem', fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.07em',
padding: '2px 9px', borderRadius: 5, color: '#fff', background: '#b71c1c', marginBottom: 16,
}}>
- Without @cacheplane/angular
+ With @langchain/langgraph-sdk alone
- Your LangGraph agent works. Your Angular frontend doesn't stream it.
+ The JS SDK gives you a Client. You build everything else.
{PAIN_POINTS.map(p => (
diff --git a/apps/website/src/components/landing/chat-landing/ChatLandingFeaturesGrid.tsx b/apps/website/src/components/landing/chat-landing/ChatLandingFeaturesGrid.tsx
index 783375779..c12c9f77f 100644
--- a/apps/website/src/components/landing/chat-landing/ChatLandingFeaturesGrid.tsx
+++ b/apps/website/src/components/landing/chat-landing/ChatLandingFeaturesGrid.tsx
@@ -2,6 +2,7 @@
'use client';
import { motion } from 'framer-motion';
import { tokens } from '@cacheplane/design-tokens';
+import { EmbedFrame } from '../EmbedFrame';
const FEATURES = [
{ title: 'Messages', desc: 'Streaming message display with token-by-token rendering. Markdown support, auto-scroll, and accessible message list.', iframePath: 'chat/core-capabilities/messages/overview/python' },
@@ -68,15 +69,11 @@ export function ChatLandingFeaturesGrid() {
{feat.desc}
-
-
-
+
))}
diff --git a/apps/website/src/components/landing/render/RenderFeaturesGrid.tsx b/apps/website/src/components/landing/render/RenderFeaturesGrid.tsx
index fc67081ca..1397413d7 100644
--- a/apps/website/src/components/landing/render/RenderFeaturesGrid.tsx
+++ b/apps/website/src/components/landing/render/RenderFeaturesGrid.tsx
@@ -2,6 +2,7 @@
'use client';
import { motion } from 'framer-motion';
import { tokens } from '@cacheplane/design-tokens';
+import { EmbedFrame } from '../EmbedFrame';
const FEATURES = [
{ title: 'Spec Rendering', desc: 'Render declarative UI specs from agent output. The agent emits JSON, your Angular components materialize it.', iframePath: 'render/core-capabilities/spec-rendering/overview/python' },
@@ -69,15 +70,11 @@ export function RenderFeaturesGrid() {
{feat.desc}
-
-
-
+
))}