Ruankao Multimedia Application Designer (Intermediate) study materials
Ruankao Multimedia Application Designer (Intermediate) study resources

A Character Animation Atlas That Crashes Low-End Android Devices

Ruankao Multimedia Application Designer (Intermediate) · Put your knowledge to work in context.

All case studies

A Character Animation Atlas That Crashes Low-End Android Devices

A language-learning app uses a cartoon mascot, "Professor Byte", with 14 animations (idle, wave, celebrate, think, and so on). The design studio has delivered one 4096×4096 PNG sprite atlas in RGBA8888 plus a set of 30 individual PNG frame sequences for the same character. Testers report the app crashes with OutOfMemoryError on Android devices with 2 GB RAM, always while opening a lesson that plays three animations at once. The splash screen, a vertical gradient from #1A2B4C to #2F5D8A across 1080 px, shows visible stripes on some phones but not others. The studio also wants to add seasonal costume variants (hat, scarf, robe) - nine combinations of the base character. Launch is six weeks away, the studio is contracted for two more revisions, and the product owner refuses to cut any animation.

1. Quantify the memory cost of the delivered atlas and explain the crash. Recommend a concrete remediation that keeps all 14 animations.

Read the worked answer

Quantify first. A decoded texture costs width × height × bytes per pixel, regardless of how well the PNG compressed on disk.

  • 4096 × 4096 × 4 bytes (RGBA8888) = 67.1 MB, i.e. 64 MiB, for a single atlas.
  • If the engine generates mipmaps, add about one third: ~85 MiB.
  • On a 2 GB device the per-app heap or GPU texture budget is a small slice of that total, and three animations playing simultaneously may each be requesting a page or a duplicate.

Disk size is irrelevant here - a 3 MB PNG expands to tens of megabytes at decode time. That is the crash.

Remediation options, in order of value:

  1. Subdivide. Slice the single atlas into pages of at most 2048 × 2048 = 16 MiB each, and load only the page(s) an animation needs. Four pages of 16 MiB cost less at any instant than one 64 MiB page, and unload cleanly between lessons.
  2. Compress the texture. ASTC 6×6 or ETC2 gives roughly 4:1 to 8:1 on GPU memory (2048² drops to ~2–4 MiB), with some block artefacts on fine line art. Test on the mascot's outlines before committing.
  3. Trim and pack. Strip fully transparent padding with a tight rectangle per frame and store the pivot offsets in a data file; character sprites are often 40–60% empty pixels.
  4. Reuse a single instance rather than one per animation state, and preload on the lesson transition screen instead of mid-animation.

Add an automated budget check to the build: fail if decoded texture memory exceeds a fixed ceiling, so the next asset delivery cannot regress silently.

2. Diagnose the striped splash gradient and specify a fix that does not depend on which phone the user owns.

Read the worked answer

Diagnosis: banding from insufficient code values, not a bug in the PNG.

Do the arithmetic on the blue channel, which dominates this gradient: #1A2B4C → #2F5D8A means blue goes from 76 to 138, a delta of 62 code values, spread across 1080 px. Each step is therefore about 17 px wide and one code value tall. Because the eye is very sensitive to mach bands at edges of low-contrast ramps, a 17 px flat stripe is clearly visible - but only on panels whose gamma, bit depth and dithering behaviour make it so. That explains the device dependence.

Why it is not just the panel. An 8-bit framebuffer can only represent 256 levels per channel. If the UI toolkit interpolates in sRGB space rather than linear light, the perceptual steps become uneven and worse in dark regions, which is exactly where #1A2B4C sits.

Fixes, cheapest and most reliable first:

  1. Add a noise dither, ±1 LSB of blue-channel random or ordered noise at render time. This converts a hard edge into a stochastic texture the visual system averages out. Cost is essentially zero and it works on every device.
  2. Render the gradient procedurally in a shader in linear space, with output dithering, instead of scaling a bitmap. This removes the resolution dependence entirely.
  3. If it must stay a bitmap, ship a 16-bit or high-resolution source and let the compositor downsample, and prefer a lossless or high-quality format (WebP lossless, AVIF) over a low-quality JPEG that adds its own 8×8 blocking on top of the banding.
  4. Design-level mitigation: reduce the ramp length or add a subtle texture overlay, so the same 62 code values span fewer pixels.

Verify on a cheap LCD at low brightness, which is where banding usually shows worst.

3. The studio wants nine costume variants of the base character. Compare extending the sprite atlas against switching to skeletal animation, using the delivered assets as evidence.

Read the worked answer

Sprite approach, costed. The base character needs, say, 14 animations × an average of 12 frames = 168 frames. At 512 × 512 RGBA that is 1 MiB per frame decoded: ~168 MiB for one costume, and nine costumes would be ~1.5 GiB of atlas data - untenable on a 2 GB device and painful even on flagships. Costumes only change the torso/head silhouette, so most of that is duplicated pixels.

Skeletal approach. The character is decomposed into bones and a small set of mesh attachments (head, torso, upper arm, hat, scarf). The 14 animations become keyframed bone rotations, a few kilobytes of JSON or binary each. Costume variants become alternative attachments swapped on the same skeleton, so nine variants add nine small textures rather than nine full atlases. Memory becomes roughly constant in the number of animations and linear only in the number of attachments actually on screen.

Trade-offs to state honestly:

  • Skeletal animation needs a runtime (Spine, DragonBones, or a custom one) and adds engineering and licensing overhead; the six-week deadline is real.
  • Deformation quality differs: skeletal rigs can look rubbery on extreme squash-and-stretch; sprite sheets preserve hand-drawn appeal frame for frame.
  • Authoring workflow changes: the studio must deliver rig files, not PNG sequences, which affects the two remaining contracted revisions.

Recommendation for this project: migrate the three or four animations that are reused most (idle, wave, think, celebrate) and the costume-bearing body parts to a skeletal rig, keep the remaining one-off animations as trimmed, paged sprite sheets, and require an automated decoded-memory budget in CI. This satisfies the product owner's no-cuts constraint while making the costume matrix affordable.