{
  "id": 16329515,
  "title": "44 seconds to render a shoe: six fixes, and the biggest one was a single toDataURL call",
  "url": "https://urgent.news/2026/10/24/44-seconds-to-render-a-shoe-six-fixes-and-the-biggest-one-was-a",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-10-24T13:39:29.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/bukestudio/44-seconds-to-render-a-shoe-six-fixes-and-the-biggest-one-was-a-single-todataurl-call-3b1i"
  },
  "original_language": "en",
  "account": "This report covers the story of optimizing the rendering of custom printed sneakers in a customizer tool. The initial load time for a shoe preview was an unusably slow 44 seconds. The slow performance was due to the browser downloading large image files in the background, decoding them at full resolution, and then executing unnecessary work. There were six main fixes implemented to improve the rendering speed.\n\n1. The first fix involved decoding 16 MB of images that were not visible. The code used to generate a thumbnail of each angle was generating a 1800x1800 PNG image, which is about 5.6 MB as a base64 data URL. By replacing the 1800x1800 PNG with a 256x256 JPEG image on a white background, the image size was reduced to 15 KB per angle, resulting in a 15x reduction in image size.\n\n2. The second fix addressed the use of PNG images with alpha channels, which were not needed for the preview. The images were converted to WebP format with a quality of 84, reducing the image size from 51.4 MB to 3.0 MB while maintaining visual quality.\n\n3. The third fix was to avoid downloading base images that were not needed for rendering. One of the angles had a 4000x4000 image that could not be mapped onto the shoe panels. By checking if a mesh was available for each angle, the unnecessary download was eliminated, saving 5 MB of data from the critical path.\n\n4. The fourth fix involved optimizing the mask loading process. The render loop was downloading and processing 29 masks sequentially, causing significant latency. By kicking off all 29 mask loads concurrently using Promises and a Set, the process became asynchronous, significantly reducing the time taken for mask processing.\n\n5. The fifth fix aimed to improve the user experience by preventing the main thread from being blocked during the rendering process. By adding a short delay (using setTimeout with a 0ms delay) between rendering iterations, the main thread was given time to update the UI and allow for smooth scrolling and interaction.\n\n6. The final fix involved restructuring the rendering process to render one angle at a time, showing the progress to the user. The original process downloaded all 5 base images and masks, rendered all 5 angles, and then displayed the result. This sequential execution led to a 44-second load time. By splitting the process into two passes - downloading and processing the images in the background, and then rendering and displaying the result, the user could see the progress and interact with the tool while waiting for rendering.",
  "summary": "I build a customizer for printed sneakers. You upload an artwork, it gets split across the leather panels of a shoe, and you see the result on the actual shoe before buying. The geometry is the interesting part — that's the first post and the second . This post is about the other half: it worked, and it was unusably slow. Cold load, first preview: 44 seconds . Here is what actually fixed it —…",
  "key_points": [],
  "editors_take": null,
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}