Problem
Typing in the composer becomes noticeably slow when a very tall PNG is attached. Typing works normally in other threads.
Observed on macOS, T3 Code Nightly 0.0.39-nightly.20260906.1293.
The affected image was:
- Dimensions: 2304 × 32766 pixels, approximately 75.5 megapixels.
- PNG file size: 5,967,750 bytes.
- Estimated decoded RGBA size: 288 MiB, before any additional browser or GPU copies.
The original image and all personal data are excluded from this report.
Reproduction
- Create a synthetic PNG with dimensions 2304 × 32766. Use varied content so the compressed file is approximately 6 MB. A solid-color PNG can test decoded-image pressure but will not reproduce the same storage cost.
- Open a new thread and attach the PNG.
- Type continuously, then type with pauses longer than 300 ms.
- Observe whether characters appear late or typing stalls.
- Compare with a draft without attachments and with a resized copy of the same synthetic image.
For a stronger comparison, test with background tasks idle and record a renderer performance trace during typing.
Expected: Typing stays responsive regardless of attachment dimensions.
Actual: The draft containing the large image has substantial input lag. Other threads remain responsive.
Investigation
Source maps shipped with the affected build show two relevant paths:
-
The thumbnail uses the original image URL. In ChatComposer.tsx, the expanded attachment preview renders <img src={image.previewUrl}> inside a 64 × 64 container. This path does not itself generate a smaller thumbnail. The source dimensions create potential decode and rendering pressure despite the small displayed preview.
-
Draft persistence includes the image payload. The affected draft stores the PNG as a base64 data URL, approximately 7.96 MB. In composerDraftStore.ts, prompt edits update the draft store. Persistence serializes the persisted draft state, including attachments, through JSON.stringify. In lib/storage.ts, createDeferredStorage writes it to synchronous localStorage after a 300 ms debounce.
The debounce reduces write frequency, but the serialization and storage write still run on the renderer thread. It does not make those operations asynchronous.
These are plausible causes, not yet isolated by a controlled image-removal test. The persistence path covers the whole draft store, so it could also affect other threads while the image-bearing draft remains saved.
Measurement limits
Diagnostics recorded renderer peaks of 94.1% CPU and 791 MB resident memory during the investigation window. These were not isolated to typing and do not establish causation.
Background directory scans were also active during part of the investigation and could have contributed to overall load. A short native renderer sample did not identify the responsible JavaScript function.
UI automation call timings are not valid measurements of key-to-paint latency and are intentionally omitted.
Suggested fix
- Generate a bounded-resolution thumbnail for attachment previews and keep the original separately for sending.
- Store attachment blobs separately from prompt text, preferably in asynchronous storage or the existing attachment-upload system.
- Persist attachment references with the draft so prompt edits do not serialize the full image again.
- Keep thumbnail generation and image conversion out of the per-keystroke render path.
- Use a targeted renderer trace to determine whether decoding, painting, serialization, or storage dominates.
Validation
Compare no attachment, a normal screenshot, and the synthetic tall PNG. Check continuous typing and typing with pauses longer than 300 ms.
Verify that:
- Typing does not repeatedly decode the original or rewrite its base64 payload.
- Input latency remains close to the no-attachment case.
- Draft text and attachments survive navigation and restart.
- Sending still uses the original image.
Prepared with GPT-6 using Codex.
Problem
Typing in the composer becomes noticeably slow when a very tall PNG is attached. Typing works normally in other threads.
Observed on macOS, T3 Code Nightly
0.0.39-nightly.20260906.1293.The affected image was:
The original image and all personal data are excluded from this report.
Reproduction
For a stronger comparison, test with background tasks idle and record a renderer performance trace during typing.
Expected: Typing stays responsive regardless of attachment dimensions.
Actual: The draft containing the large image has substantial input lag. Other threads remain responsive.
Investigation
Source maps shipped with the affected build show two relevant paths:
The thumbnail uses the original image URL. In
ChatComposer.tsx, the expanded attachment preview renders<img src={image.previewUrl}>inside a 64 × 64 container. This path does not itself generate a smaller thumbnail. The source dimensions create potential decode and rendering pressure despite the small displayed preview.Draft persistence includes the image payload. The affected draft stores the PNG as a base64 data URL, approximately 7.96 MB. In
composerDraftStore.ts, prompt edits update the draft store. Persistence serializes the persisted draft state, including attachments, throughJSON.stringify. Inlib/storage.ts,createDeferredStoragewrites it to synchronouslocalStorageafter a 300 ms debounce.The debounce reduces write frequency, but the serialization and storage write still run on the renderer thread. It does not make those operations asynchronous.
These are plausible causes, not yet isolated by a controlled image-removal test. The persistence path covers the whole draft store, so it could also affect other threads while the image-bearing draft remains saved.
Measurement limits
Diagnostics recorded renderer peaks of 94.1% CPU and 791 MB resident memory during the investigation window. These were not isolated to typing and do not establish causation.
Background directory scans were also active during part of the investigation and could have contributed to overall load. A short native renderer sample did not identify the responsible JavaScript function.
UI automation call timings are not valid measurements of key-to-paint latency and are intentionally omitted.
Suggested fix
Validation
Compare no attachment, a normal screenshot, and the synthetic tall PNG. Check continuous typing and typing with pauses longer than 300 ms.
Verify that:
Prepared with GPT-6 using Codex.