Renderer 는 SSE 와 UI 사이의 contract. Bad renderer — 모든 token 마다 append + UI 잠금 + cancel 무시. Good renderer — frame budget 안에서 append + cancel() 노출 + done 시 flush. 차이는 사용자가 직접 느껴.
16ms frame budget
50 token/sec 에서 매 token 마다 React re-render 박으면 reconciliation 이 chokes. 16ms requestAnimationFrame tick 에 한 번씩 flush — 사용자 눈은 못 잡지만 React 는 살아남아. cwkPippa frontend 가 정확히 이 패턴.
Cancellation 이 second contract
사용자가 'Stop'. Renderer 가 (1) SSE stream close (server 도 generation 멈춤), (2) accumulated text 를 UI 에 flush, (3) partial output 보존 (blank 안 만듦). Cancel wiring 없으면 'Stop' 은 응답을 시야에서 가리는 것뿐 — 모델은 server-side 에서 토큰 계속 태움.
cwkPippa 의 render
per-message accumulator + 16ms requestAnimationFrame flush loop. Cancel first-class — abort signal 이 SSE consumer 까지 wired, abort 시에도 partial text 가 JSONL 에 보존. 같은 패턴이 어떤 React/Streamlit 앱에서도 통함.