Diagnosis of the bumpiness: the old pulse wasn't smoothed by the compositor, so the browser re-rasterized the dot at every integer pixel size — an 8 px dot crossing 80%→100% only spans ~2 real pixels, hence visible jumps. All candidates below run on a promoted compositor layer (will-change): the GPU interpolates the rasterized texture continuously, i.e. genuine sub-pixel growth. Cycle slowed to 3.6s and the easing is near-sinusoidal so velocity never jumps. Motion range: smallish (55%) → max (100%), as requested.
XL dot (0.28em), capitals, centred middle dot, motion = ① grow. This is the exact rendering both sites would ship.
All grow smallish → max on the same 3.6s near-sinusoidal cycle. ④ is the old pulse kept as an honest A/B reference.
XL dot system carried to the app icon — the dot-alone at XL weight is the strongest tiny-size mark.