Skip to content

Commit 32151a0

Browse files
committed
fix(blog): stream demo bullets and code chip per-character to match the typing cadence
1 parent df54aa1 commit 32151a0

1 file changed

Lines changed: 31 additions & 12 deletions

File tree

apps/sim/content/blog/agent-as-yjs-peer/components/agent-peer-demo.tsx

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -187,16 +187,21 @@ function renderBlockNodes(
187187
const key = `${blockStart}-${si}`
188188

189189
if ('code' in seg) {
190-
if (!didPlace && revealed >= start && revealed < end) {
191-
nodes.push(<Caret key={`${key}-c`} who={AGENT} />)
192-
didPlace = true
193-
}
190+
// Type the chip in character by character, at the same cadence as the surrounding text, with
191+
// the caret moving through it. The box reserves its full width up front (the unrevealed tail is
192+
// visibility:hidden inside it) so the card never reflows. Revealing it as one chunk instead made
193+
// it either freeze-and-jump (caret parked before an empty gap) or fly past as a skipped unit.
194+
const reached = revealed >= start
195+
const shown = reached ? Math.min(raw.length, revealed - start) : 0
196+
const atBoundary = !didPlace && reached && shown < raw.length
197+
if (atBoundary) didPlace = true
194198
nodes.push(
195-
<code
196-
key={key}
197-
style={{ ...codeStyle, visibility: revealed >= end ? 'visible' : 'hidden' }}
198-
>
199-
{raw}
199+
<code key={key} style={{ ...codeStyle, visibility: reached ? 'visible' : 'hidden' }}>
200+
{reached ? raw.slice(0, shown) : raw}
201+
{atBoundary && <Caret key={`${key}-c`} who={AGENT} />}
202+
{reached && shown < raw.length && (
203+
<span style={{ visibility: 'hidden' }}>{raw.slice(shown)}</span>
204+
)}
200205
</code>
201206
)
202207
} else {
@@ -254,13 +259,27 @@ function AgentDoc({ revealed }: { revealed: number }) {
254259

255260
for (let bi = 0; bi < AGENT_BLOCKS.length; bi++) {
256261
const block = AGENT_BLOCKS[bi]
257-
const res = renderBlockNodes(block, offset, revealed, placed, bi === AGENT_BLOCKS.length - 1)
262+
const blockStart = offset
263+
const res = renderBlockNodes(
264+
block,
265+
blockStart,
266+
revealed,
267+
placed,
268+
bi === AGENT_BLOCKS.length - 1
269+
)
258270
placed = res.placed
259-
offset += block.segs.reduce((m, s) => m + segText(s).length, 0)
271+
offset = blockStart + block.segs.reduce((m, s) => m + segText(s).length, 0)
260272

261273
if (block.kind === 'li') {
274+
// The bullet is the <li>'s own list marker, so hiding the item's text with visibility:hidden
275+
// would still leave an empty bullet showing. Hide the whole item until the caret reaches it, so
276+
// each bullet appears with its line rather than all of them up front. The hidden item still
277+
// reserves its height, so the card never changes size.
262278
list.push(
263-
<li key={`li-${bi}`} style={{ marginTop: 0 }}>
279+
<li
280+
key={`li-${bi}`}
281+
style={{ marginTop: 0, visibility: revealed >= blockStart ? 'visible' : 'hidden' }}
282+
>
264283
{res.nodes}
265284
</li>
266285
)

0 commit comments

Comments
 (0)