Response Stream
Reveals text chunk-by-chunk to mimic an LLM's streaming response. Two modes: typewriter (cumulative) or fade (per-word).
Examples
Typewriter mode
One chunk per animation frame. Speed is on a 1–100 scale.
<pk-response-stream
[textStream]="text"
mode="typewriter"
[speed]="40"
/>Fade mode
Each word fades in independently. Feels softer for long-form output.
<pk-response-stream
[textStream]="text"
mode="fade"
[speed]="40"
/>Live streaming (continues, doesn't restart)
Simulates an LLM streaming response: chunks arrive every ~150ms and append to the bound signal. The typewriter continues from where it left off rather than restarting on every update.
// Consumer signal updated as chunks arrive
const text = signal('');
function appendChunk(chunk: string) {
text.update(v => v + chunk);
}
// Template
<pk-response-stream
[textStream]="text()"
mode="typewriter"
[speed]="60"
/>Big chunks, slow cadence
A larger paragraph-sized chunk arrives every 1000ms — closer to a real LLM that streams complete sentences. Same continuation behaviour: typewriter advances through the new content without restarting.
// Paragraph-sized chunk every 1000ms
const text = signal('');
function appendParagraph(chunk: string) {
text.update(v => v + chunk);
}
// Template — higher speed keeps the catch-up visible at 1s pacing
<pk-response-stream
[textStream]="text()"
mode="typewriter"
[speed]="80"
/>Adaptive pacing + finished handshake
adaptive scales the reveal speed with the backlog: it types character-by-character while caught up with the stream and accelerates when chunks arrive faster than the reveal. Set done when the source stream ends and the component emits finished exactly once after the last character is revealed — the moment to swap in your final rendering (e.g. markdown) without cutting the animation short.
// Consumer accumulates chunks and flags the end of the stream
const text = signal('');
const done = signal(false);
const finished = signal(false);
// On each SSE/WebSocket chunk: text.update(v => v + chunk)
// When the stream ends: done.set(true)
// Template — swap to the final rendering once `finished` fires
@if (finished()) {
<div [innerHTML]="renderedMarkdown()"></div>
} @else {
<pk-response-stream
[textStream]="text()"
[adaptive]="true"
[done]="done()"
(finished)="finished.set(true)"
/>
}Installation
Add the response-stream component (and the cn() utility) to your project.
ng generate ngx-prompt-kit:response-streamComponent API
PkResponseStream
| Prop | Type | Default | Description |
|---|---|---|---|
| textStream | string | '' | The full text to reveal incrementally. |
| mode | "typewriter" | "fade" | "typewriter" | Reveal style. |
| speed | number | 20 | 1–100. Higher = faster. |
| adaptive | boolean | false | Scale reveal speed with the backlog: types character-by-character while caught up, accelerates when the stream outpaces the reveal, never dumps. |
| done | boolean | false | Tell the component the source stream has ended. Enables the finished output. |
| fadeDuration | number | — | Override per-segment fade duration in ms. |
| segmentDelay | number | — | Override per-segment delay in ms. |
| characterChunkSize | number | — | Override characters revealed per frame. |
| completed | output<void> | — | Fires each time the reveal catches up with the current textStream value. |
| finished | output<void> | — | Fires exactly once when done is true and every received character has been revealed. |
| class | string | — | Extra classes for the wrapper. |