gc.kimbaba.com.tw/Lobby · desktop web view 1864×863, DPR 1 · measured 2026-07-23
Requests counted in-browser via PerformanceResourceTiming; every file then
re-fetched server-side to read true byte size and pixel dimensions from its header.
Headline numbers
625
image requests
530
unique files
31.59 MB
unique payload
36.48 MB
incl. duplicate requests
95
duplicate requests
4.89 MB
wasted on duplicates
414 MB
decoded image RAM
127.20 MB
RAM saved at 384px, no quality loss
The headline problem is pixel dimensions, not file count. 405 of the 530 files are
480 × 480 game icons. Below the 500 px breakpoint the lobby sizes them with
width: 27.2vw, so the physical pixels an iPhone needs is
viewportWidth × 0.272 × DPR — and the worst case across the entire iPhone range
is 359 px (16 Pro Max). Even the largest, densest iPhone is handed about a third more
pixels than it can show. Dropping to 384 × 384 takes game icons from
353 MB to 226 MB of decoded RAM with no visible change.
Weight by purpose
Category
Files
Unique bytes
Incl. dupes ≈
Game icons
402
21.67 MB
24.45 MB
Event banners
70
4.15 MB
6.22 MB
Feature modules
21
3.98 MB
3.98 MB
App UI
28
1.67 MB
1.67 MB
Trackers / misc
9
0.11 MB
0.16 MB
Total
530
31.59 MB
36.48 MB
Dimension distribution — how many distinct sizes are actually in play
Pixel size
Files
Bytes
480 × 480
405
21.84 MB
1200 × 600
26
2.22 MB
600 × 300
23
0.87 MB
800 × 400
10
0.53 MB
400 × 200
8
0.16 MB
240 × 80
8
0.02 MB
144 × 144
6
0.04 MB
312 × 624
6
3.57 MB
1 × 1
4
0.00 MB
720 × 720
4
0.45 MB
640 × 160
4
0.08 MB
1008 × 192
3
0.17 MB
72 × 72
2
0.02 MB
80 × 80
2
0.01 MB
Game icons by provider — 402 files, 21.67 MB
Provider
Icons
Bytes
BNG
164
8.72 MB
QT
88
4.57 MB
CQ9
42
2.43 MB
RSGSW
14
0.74 MB
TAG
10
0.68 MB
BL
12
0.58 MB
VA
9
0.55 MB
GIO
11
0.53 MB
FC
7
0.43 MB
OSEG
7
0.40 MB
ATG
7
0.40 MB
RK5
5
0.32 MB
FVG
4
0.22 MB
BLE
3
0.17 MB
KBB
3
0.16 MB
ZG
3
0.16 MB
RG
3
0.14 MB
YB
3
0.14 MB
BOD
2
0.11 MB
BT
2
0.11 MB
I8
2
0.10 MB
SYSGAME
1
0.04 MB
What the duplicates actually cost — and what they do not
93 URLs are fetched more than once in a single load, for 95 redundant requests and
4.89 MB of avoidable transfer — 13% of everything the page pulls down.
Where the duplication happens
URLs
Wasted transfer
Game icons
50
2.78 MB
Event banners
39
2.07 MB
Trackers / misc
4
0.05 MB
The damage
Cold cache costs the full 4.89 MB. First-time visitors, anyone whose cache
was evicted, and every LINE LIFF in-app session that starts with a fresh WebView cache
pays this in real bandwidth. On mobile data that is the difference between a
31.59 MB page and a 36.48 MB one.
Warm cache still costs a request slot. A cache hit is not free — the browser
still creates the <img>, resolves the URL and consults the cache, and
the request still occupies a slot in the connection pool. During the initial burst these
95 extras contend with the 600+ genuine requests at exactly the moment the lobby is
trying to paint.
Head-of-line contention during first paint. All 618 first-3-second requests go to
one host. Whatever the multiplexing limit is on that connection, 95 of the slots are
spent re-fetching bytes the page already has, delaying icons the user can actually see.
Extra CDN and origin billing for requests that deliver nothing new, multiplied by
every session.
What duplicates do not cost
They do not double memory. The browser keys its decoded-bitmap cache by URL, so a
file requested three times is still decoded once and held once. That is why the
414 MB decoded-RAM figure above is driven entirely by pixel dimensions, not by the
duplicate count. Fixing duplicates is a bandwidth and latency win; fixing dimensions
is the memory win. They are separate problems and both are worth doing.
Where they come from
Game icons (50 URLs, 2.78 MB). The same icon appears in more than one rail —
a promoted/hot list and the All grid — and each list builds its own URL from
Provider + Code.toLowerCase() and creates its own image. The
lists are concatenated without a dedupe pass, so a popular game is fetched once per list
it appears in.
Event banners (39 URLs, 2.07 MB). Each banner is pulled once by an
<img> and again by a CSS background-image on the same
element or its wrapper.
A single Set over the merged preload list, plus dropping either the
<img> or the CSS copy of each banner, removes essentially all of it. No
rendering changes required — the same pixels end up on screen.
Memory cost on iPhone — the platform that actually hurts
476 <img> elements decode to 414.6 MB of RGBA bitmap. A decoded image costs
width × height × 4 bytes in RAM no matter how well it compresses — so a 56 KB
WebP at 480 × 480 occupies 0.88 MB of memory, about 16× its file size. That figure is
identical on every device, because it depends on the source pixels, not the screen.
A desktop shrugs it off; an iPhone WebView does not.
How big is a game icon on an actual iPhone?
Below the 500 px breakpoint the lobby sizes every icon with
.gameCard-area .s-card { width: 27.2vw } — a fraction of viewport width, not a
fixed box. So the physical pixels an icon needs is
viewportWidth × 0.272 × devicePixelRatio. Every iPhone in portrait is under
500 px, so all of them use this rule. (At ≥ 500 px it becomes a fixed 145 px, and 128 px on
desktop.)
iPhone
CSS width
DPR
Slot (CSS px)
Pixels needed
share of the 480 px shipped
iPhone SE (3rd gen), 8
375
2×
102
204
iPhone 11, XR
414
2×
113
225
iPhone 13 mini
375
3×
102
306
iPhone 14, 13, 12
390
3×
106
318
iPhone 16, 15, 14 Pro
393
3×
107
321
iPhone 15 Pro Max, 14 Pro Max
430
3×
117
351
iPhone 16 Pro Max
440
3×
120
359
The worst case across the whole iPhone range is 359 physical pixels
(16 Pro Max: 440 × 0.272 × 3). Every icon ships at 480 × 480. So even the largest,
densest iPhone is being handed about a third more pixels than it can display — and every
other iPhone considerably more than that.
What each option costs and saves
File sizes below are measured, not estimated: 60 random 480 × 480 icons were
downloaded, resized with Lanczos and re-encoded as WebP. Quality 80 was chosen because
re-encoding the originals at 480/q80 lands at 94% of their current size — i.e. the source
files sit at roughly q82, so q80 is a like-for-like comparison rather than a quality cut.
Downscaling never blurs; only upscaling does. Any row whose pixel count meets
359 is visually lossless on every iPhone.
Ship at
Verdict
All 402 icons on disk
Decoded RAM
RAM saved
Why
480 × 480
Today
21.67 MB
353.32 MB
—
ships as-is
384 × 384
Recommended
14.82 MB
226.12 MB
−36%
covers every iPhone incl. 16 Pro Max, with headroom
360 × 360
Tighter
13.67 MB
198.74 MB
−44%
exactly covers the 359 px worst case, no headroom
320 × 320
Aggressive
11.49 MB
157.03 MB
−56%
1.12× upscale on Pro Max only — barely perceptible
256 × 256
Too far
8.36 MB
100.50 MB
−72%
1.40× upscale on every DPR-3 iPhone — visibly soft
Recommendation: 384 × 384. It is exactly 3× a 128 px slot, clears the 359 px
worst case with room to spare, and is visually identical on every iPhone because nothing is
ever upscaled. Measured result: game icons drop from 21.67 MB to 14.82 MB on
disk and from 353.32 MB to 226.12 MB in decoded RAM — a
127.20 MB memory saving on the exact platform you care about, with no visible
change.
If you want to push further, 320 × 320 saves 196.29 MB of RAM and only upscales
on Pro Max models, by 1.12× — in practice imperceptible on a 3× display. 256 × 256 is too
far: it upscales 1.40× on every DPR-3 iPhone, which is where softness starts to show. An
earlier draft of this report recommended 256 based on a desktop DPR-1 measurement; that was
the wrong baseline and is corrected here.
Best of both: a srcset with 256 / 384 variants lets DPR-1 and DPR-2 devices take
the small file while DPR-3 iPhones take the large one — no device over-fetches, and nothing
is ever upscaled.
Other ways to cut memory
Serve icons at the size they are shown. The single biggest lever — 384 × 384
instead of 480 × 480, as derived above.
Keep off-screen tiles out of the DOM. 476 decoded images for a viewport that shows
about 36 is the core problem; lazy-loading plus windowing the grid means the browser only
ever holds a screenful or two of bitmaps.
Add content-visibility:auto to off-screen grid rows so the compositor
is free to drop rasters for tiles that have scrolled away, instead of retaining them.
Use decoding="async" on grid images so decode work does not block the
main thread during the initial burst of 600+ requests.
Deduplicate the request list. 95 redundant fetches do not add decoded memory (the
cache dedupes the bitmap) but they do add 4.89 MB of transfer and contend for the
same connection pool during first paint.
Reconsider the 312 × 624 jackpot banners. Four of them are on the page at
0.78 MB decoded each, and the source files are named after their own weight
(_900kb, _500kb, _300kb) — a strong hint they were
exported by hand rather than by a build step.
Findings
480 × 480 icons in a 128 × 128 slot. 405 files ship at 480 × 480; 400 of them
render at 128 × 128 (measured, DPR 1), 20 at 104 × 104, one hero at 280 × 280. Game
icons are 21.67 MB of the 31.59 MB total — the biggest single lever on this page.
8 files exceed 200 KB, together 4.36 MB. The worst are the
jackpot / big-win banners literally named after their own weight —
鐵木真_900kb.webp is 923 KB at 312 × 624 — plus two 1920-px-wide desktop
chrome strips (header-bg-desktop 400 KB, footer-bg-desktop
403 KB) that are only 84 px and 64 px tall.
95 duplicate requests cost 4.89 MB. 93 URLs are fetched more than once in one
load: 50 game icons (an icon in both a promoted rail and the All grid refetches instead
of reusing) and 39 event banners.
Event banners ship in two encodings. Each banner exists as .webp
(loaded by <img>) and again as .jpg/.png
(loaded by CSS background-image) — 70 unique files for roughly 35 banners.
The CSS copies are also invisible to any <img>-based lazy-loading
strategy.
Everything loads up front. 618 of the 626 measured requests (98.7%) fire within 3 seconds.
Scrolling the full 11,078 px lobby triggered exactly one extra image, and there are
485 <img> tags in the DOM for a viewport showing about 36.
Coverage check — was anything missed?
The inventory is built from PerformanceResourceTiming, which is the same set the
DevTools Network panel shows, including cache hits. Three cross-checks were run against a
fresh load to confirm nothing slipped past the filter:
Non-image resources re-examined. Of 807 total resources, 617 matched the image
filter and 190 did not. Every one of those 190 was hand-checked: 62 scripts, 78 fetch,
41 XHR, 7 link, 2 css. The only borderline entries were a
.wasm, an .aac soundtrack, a /403check ping and
three tracker scripts — no images among them.
Images that never touch the network. The DOM has zero
data:<img> tags, zero <svg>, zero
<canvas>, zero <iframe>, zero video posters and
zero CSS mask-image. The only embedded images are 6 base64 PNGs
(~21 KB total) inlined in the CSS bundle, which are counted as part of the
stylesheet rather than as image requests.
The extension's own network log was rejected as a source — it is a rolling
buffer that had evicted down to 30 entries by the time the page settled, so it cannot
see a full page load. The Performance API buffer was raised to 50,000 entries at
resource #26, well before the 250-entry default would have started dropping.
Counts vary by a few images between loads because the promo carousel and popup rotate;
this inventory is one representative load.
All 530 site images — grouped into categories; filter, sort and resize with the controls