⭐ Built in the Agent OS — get it inside the AI Profit BoardroomJoin AIPB →The user wants a single self-contained HTML file that renders an infinite Mandelbrot zoom. They want smooth shader coloring, click-to-zoom, hold for continuous zoom, and escape to reset. I need to output just the HTML, no markdown fences, inline all CSS and JS. I can load libraries from CDN, but probably better to do it in plain WebGL to avoid dependencies. Wait, the prompt says "You may load three.js or other libraries from a CDN." But a single self-contained HTML could use WebGL directly. However, three.js might be easier. But the user wants a single HTML file. Let's consider using WebGL2 with a fragment shader for the Mandelbrot set. Requirements: - Infinite Mandelbrot zoom: double precision may be needed for deep zooms. WebGL doesn't support double precision natively in fragment shader? Actually, GLSL ES 3.0 has no double type, but we can emulate double-double or use perturbation. However, for "infinite" we need deep zoom. Simple 32-bit float will break quickly (around 1e-7 zoom). To get deeper, we need double emulation or perturbation theory. But the user says "infinite", so we should try to support deep zoom. Implementing perturbation in WebGL is complex because you need to compute reference orbit on CPU and pass as texture/arrays. But maybe we can do a basic double-double arithmetic in GLSL for coordinates. That extends range to maybe 1e-14 or so, which is effectively deep enough for a demo. But "infinite" is impossible truly. We can do perturbation for arbitrary zoom. Hmm. Let's think about scope. The user wants a smooth shader coloring, click to zoom into that point, hold to zoom continuously, escape resets. It should render visible content on first frame. We can create a fullscreen WebGL2 canvas, fragment shader that computes Mandelbrot iteration count. Use smooth coloring based on log log escape radius. Use mouse click to set target center, animate zoom. Hold mouse to zoom continuously. Escape resets view. For deep zoom, we can implement perturbation: compute a reference orbit for the center point on CPU in JavaScript using arbitrary precision or double. Then in shader, use perturbation formulas: δz_{n+1} = 2 z_n δz_n + δz_n^2 + δc, where z_n is reference orbit and δc = c - c_ref. This allows deep zoom as long as δc is small. But reference orbit recomputation on each frame when center moves, and for deep zoom reference orbit length must be max iterations. Could be heavy. But we can do it incrementally. Alternatively, use native double emulation with vec2 representing double as two floats. Implement add, mul, etc. That gives about 30 decimal digits? Actually double-double gives ~30 digits? Let's see: two floats, high and low, gives about 48 bits of mantissa? Wait float has 24 bits mantissa. Double-double can give up to 48 bits mantissa, exponent range of float (~38 digits). That would allow zoom to around 1e-14 relative to size ~1? Actually 48 bits ~ 14 decimal digits. That's not huge. Standard double has 53 bits ~ 16 digits. Double-double adds extra precision but exponent range same. So 1e-14 relative to coordinate magnitude. If coordinate magnitude is ~1, deep zoom to 1e-14. That's decent but not infinite. Perturbation can go much deeper. But implementing perturbation in a single self-contained file is possible. Let's see if we can do it robustly enough. The shader needs reference orbit z_n for n up to max iterations. We can store in a 2D texture (or array texture) with RGBA32F. Max texture size is usually 16384, so can store ~268 million floats? No, 16384x16384 pixels = 268M texels, but RGBA32F is huge memory. We can store complex numbers in RG32F. Max iterations maybe 5000? We can store reference orbit in a 1D texture or uniform array. Uniform arrays are limited (e.g., 4096). Better use a texture: we can create a 1D texture or 2D texture of size N x 1 with internal format RG32F. WebGL2 supports texImage2D with internalFormat = RG32F, type FLOAT. Max texture dimension 16384, so max orbit length 16384. That's enough for deep zoom? For deep zoom, you may need many iterations. But we can start with max iterations 2000 and increase. At deep zoom, iterations can be huge. But for a demo, 2000-5000 is okay. However, reference orbit recomputation every frame for moving center is expensive if max iterations high. We can recompute only when needed (zoom changes, center changes). For continuous zoom, center may move slowly; we can recompute reference orbit occasionally or every frame if fast enough. JavaScript bigfloat recomputation of 5000 iterations is trivial. But we need high precision for deep zoom. We can use JavaScript's BigFloat? Not native. We can use arbitrary precision library? But we want no dependencies. We can implement perturbation using double-double in CPU? Hmm. Actually, we can avoid perturbation and use BigInt rational? That would be slow. Alternative: Use WebGL2's `ext_float_texture`? Already with RG32F. For CPU reference orbit, we need high precision. JavaScript number is double (53 bits). For zoom depth of 1e14, δc is ~1e-14, which is within double precision relative to coordinate ~1, so double reference orbit is fine. For deeper, double reference orbit may have errors. But we can use a simple high-precision arithmetic in JS (e.g., use decimal.js? No CDN maybe). We can implement a simple arbitrary precision complex number using arrays? That might be overkill. Maybe we can use the `decimal.js` library from CDN to compute reference orbit with high precision. The user allows loading libraries from CDN. We can load decimal.js from a CDN to compute reference orbit with arbitrary precision. But then we need to pass reference orbit as floats to shader. The shader uses perturbation with float32 δz, δc. δc can be computed in shader as difference between high-precision c and reference c? But shader only has float32. We need to pass c center and offset in high precision to shader. We can pass c as two vec2 (double-double) to shader, and reference orbit as float32 relative to center? Wait perturbation formula uses δc = c - c_ref. If c_ref is the center of the view and c is pixel coordinate. For deep zoom, c - c_ref is small (~zoom size). We can compute it in shader using high-precision double-double emulation for the subtraction, given the center in high precision (double-double). Then reference orbit z_n is computed for c_ref. Since c_ref is the center, its magnitude may be large (like full coordinate), but z_n values can be large. However, we only need z_n as float32 because δz is small and z_n is reference. Actually perturbation formula: δz_{n+1} = 2 z_n δz_n + δz_n^2 + δc. z_n can become large (up to 2), so float32 z_n is fine. δz and δc are small (size of pixel in complex plane). For deep zoom, size may be 1e-100, which is below float32 subnormal? Float32 min normal ~1e-38, min subnormal ~1e-45. So if zoom size < 1e-38, float32 cannot represent δc. But we can scale δz and δc to a normalized range? For perturbation, we can set δc' = δc / scale, δz' = δz / scale, and compute scaled iterations? Let's derive. If we want to handle arbitrary depth, we need to scale δc and δz to be representable. Let ε be the half-size of view (e.g., 1e-100). We can represent pixel offsets in normalized device coordinates [-1,1] and multiply by ε in shader. But ε as float32 underflows. However, we can pass ε as a double-double (or log scale) and compute δc in double-double in shader. Double-double can represent numbers down to ~1e-38 with high precision? Actually exponent range same as float, so cannot represent 1e-100. We need arbitrary exponent. We can pass scale as `scale = ε * 2^k`? Hmm. Maybe we can represent δc in terms of normalized coordinate times scale, using a logarithmic representation: store `logScale` and compute δc = exp(logScale) * normCoord in shader? But GLSL has exp() with float32, result underflows. We can split scale into mantissa and exponent: scale = m * 2^e, where m in [0.5,1). Then δc = m * (normCoord * 2^e). We can compute multiplication by 2^e using `ldexp` (not available in GLSL but can do `x * exp2(float(e))`). If e is large negative, exp2(e) underflows. But we can incorporate e into the iteration using scaling of δz. Alternatively, we can perform perturbation in a scaled coordinate system: Let δc = s * u, δz = s * v, where s is a small scale and u, v are normalized coordinates (order 1). Then recurrence: s v_{n+1} = 2 z_n (s v_n) + (s v_n)^2 + s u => v_{n+1} = 2 z_n v_n + s v_n^2 + u. So if s is very small, the s v_n^2 term may underflow in float32? We can store s as float32 if s > 1e-38; for smaller s, we can drop the quadratic term because s v_n^2 is negligible compared to u and 2 z_n v_n. For deep zoom, the linear approximation is enough: v_{n+1} ≈ 2 z_n v_n + u. This is the "series approximation" / perturbation linearization. But we need to handle the quadratic term when s is representable. Actually we can choose s = view size; if view size < 1e-38, s underflows. We can scale v by a factor such that s is representable: choose s0 = view size * 2^K for some K to bring into [1,2), and define v' = v / 2^K? Let's derive. Let actual δc = ε * u, where u ∈ [-1,1]. ε may be tiny. We want to compute δz_n = ε * w_n, where w_n is normalized. Recurrence: ε w_{n+1} = 2 z_n (ε w_n) + (ε w_n)^2 + ε u => w_{n+1} = 2 z_n w_n + ε w_n^2 + u. Now ε is tiny; if ε < 1e-38, the ε w_n^2 term vanishes in float32. But the recurrence for w_n uses u (order 1) and 2 z_n w_n (z_n up to 2). w_n may grow. For deep zoom, w_n can become huge if orbit escapes; but escape detection uses |δz_n|? Actually we need |z_n + δz_n| > 2. Since δz_n = ε w_n, for small ε, δz_n is tiny until w_n ~ 1/ε, which may be huge. But escape occurs when z_n itself is near escape? Wait perturbation works when reference orbit (center) is non-escaping (bounded). Then pixels escape when δz grows enough that z_n + δz_n escapes. For deep zoom, δz needed to escape may be extremely small, but w_n needed may be huge. However, w_n recurrence with float32 may overflow if w_n > ~1e38. But if ε = 1e-100, escape w_n ~ 1e100, overflow. Hmm. But maybe we don't need to handle arbitrary deep zoom. The user says "infinite" but likely expects a visually infinite zoom effect, not mathematically exact to arbitrary depth. We can implement a reasonably deep zoom with double-double coordinates or perturbation with float32 offsets for a decent range. We can also implement an automatic re-centering/period detection to avoid precision issues? Or use the "exponential map" trick? Hmm. Given the constraints, perhaps the best approach is to use WebGL2 with a fragment shader that uses emulated double precision (double-double) for coordinate arithmetic and iteration. That gives zoom depth to about 1e-14 relative to coordinate magnitude of ~1. We can also map the complex plane to a logarithmic scale to make it appear infinite? No. Alternatively, use a shader with 32-bit float and allow zooming until precision artifacts appear, then reset or just stop? But user wants infinite. Maybe we can implement a hybrid: compute Mandelbrot using perturbation with reference orbit computed on CPU using JavaScript's BigInt fixed-point arithmetic, and store orbit in a texture. Pass pixel offsets as normalized double-double relative to center, and use scaling to keep numbers in range. This can support deep zoom if we re-scale δz dynamically. Let's think about a robust but not overly complex solution. Simplify: Use perturbation with float32 δz, δc, reference orbit from CPU double. This supports zoom down to where δc ~ 1e-38 (view size ~ 1e-38). That's already extremely deep (over 100 zooms by factor 0.1 each). It will appear infinite for practical purposes. The reference orbit computed in double works for c_ref coordinates up to magnitude ~2. For deep zoom, c_ref is the center, which stays within the Mandelbrot set region near some point, magnitude maybe <2. The reference orbit values z_n remain bounded by 2 (for non-escaping center). Actually for points inside the set, |z_n| <= 2. For points near boundary but inside, z_n can be close to 2. So float32 z_n is fine. δc = pixel offset = view size * normalized coord. For view size < 1e-38, δc underflows to 0 in float32, so all pixels look same. But we can limit min view size to 1e-38? That's still huge depth. Or we can use a scaling factor. We can implement the shader using a scaling trick: instead of computing δc = size * coord directly, we can pre-multiply the normalized coordinate by a factor and store size separately? No, the product is what matters. Actually, we can pass `scale` as a double-double to shader and compute δc in double-double. Double-double product of a tiny size (1e-100) and a float32 coordinate (1.0) can represent 1e-100 because the high part is 0 and low part is 1e-100? Wait low part is a float32, so it cannot store 1e-100 either. Double-double uses two floats: high + low. If high = 0, low is a float32, cannot be 1e-100. So no. To represent numbers smaller than float32 min, we need a different representation, like exponent splitting. But we can avoid by limiting zoom. Maybe a simpler approach: Use WebGL2 with `EXT_color_buffer_float` and render to a float texture, but still shader arithmetic is float32. Could we use WebGPU? It supports f64? Not in fragment shaders generally. Given the difficulty, I think the most pragmatic solution is to use a fragment shader with single-precision but with a clever coordinate representation: store center as `vec2` of `highp float` and zoom level as `float`. Use pan/zoom but when zoom gets too deep, artifacts appear. To mitigate, we can use a "Mandelbrot set is self-similar" trick? No. Alternatively, we can use the GPU to compute Mandelbrot using perturbation with reference orbit in a texture and use `highp float` for δz. For deep zoom, we can scale δz and δc by a power-of-two factor to keep them in float range. Let's explore scaling more carefully. We want to compute δz_n for each pixel. Let the view have size ε (half-width). Let u be normalized pixel coordinate in [-1,1]. Then δc = ε u. Let ε = m * 2^e, where m ∈ [0.5,1). We can choose m and integer e. For e very negative, 2^e underflows. But we can redefine variables to absorb 2^e. Let δz_n = 2^e * w_n. Then recurrence: δz_{n+1} = 2 z_n δz_n + δz_n^2 + δc. 2^e w_{n+1} = 2 z_n (2^e w_n) + (2^e w_n)^2 + m 2^e u. Divide by 2^e: w_{n+1} = 2 z_n w_n + 2^e w_n^2 + m u. Now e is large negative, so 2^e is tiny but representable if e > -126? For e = -200, 2^e underflows. But note that 2^e w_n^2 term may be negligible. If we drop it, we get linear recurrence w_{n+1} = 2 z_n w_n + m u. This is exact in the limit ε→0. For finite ε, error is small when 2^e w_n^2 is negligible compared to other terms. Since m u ~ O(1), and w_n may grow. The quadratic term is 2^e w_n^2. As long as w_n << 1/sqrt(2^e) = 2^{-e/2}, it's negligible. If e = -200, that's 2^100 huge, so w_n can be huge before quadratic matters. So dropping it is fine for deep zoom. But we also need escape condition: actual z = z_n + δz_n = z_n + 2^e w_n. For e very negative, δz_n is tiny. Escape detection |z| > 2: since z_n is bounded by 2 (for bounded reference), we need δz_n to push it above 2. If z_n is exactly near 2, w_n needs to be ~ (2 - |z_n|) / 2^e. If e = -200, 2 - |z_n| may be as small as 2^e? Then w_n ~ 1. If 2 - |z_n| is smaller, w_n may be >1. But w_n can become large. However, w_n computed with float32 may overflow if >1e38. Is that possible? For escape, |z_n + 2^e w_n| > 2. Since |z_n| <= 2, we need |2^e w_n| > 2 - |z_n| (roughly). If 2 - |z_n| is extremely small (like 2^e * 1e38), then w_n ~1e38. But how small can 2 - |z_n| be for a bounded orbit? It can be arbitrarily small for points near boundary with high iteration. So w_n needed can be huge. But in practice, escape occurs at some iteration n where z_n is not necessarily extremely close to 2. For deep zoom, the pixel may escape at iteration N where z_N is at some distance from 2. The required δz_N may be ~1e-100, so w_N = δz_N / 2^e ~ maybe 1. Actually if ε = 2^e, then δz_N ~ 1e-100 and w_N ~ u (order 1). Wait no: δc = ε u = 2^e u. For deep zoom, escape occurs when δz_N is some value that makes z_N + δz_N escape. That δz_N may be much larger than δc but still of order ε times some factor. The factor w_N may be large but not astronomically. In linear perturbation, w_n can grow exponentially with iteration count. For high iterations (thousands), w_n can be huge. But if it grows too huge, float32 overflow. However, for escaping pixels, once |z_n + δz_n| > 2, we can stop. We can detect escape using |δz_n| > 2 - |z_n| (with care). If w_n grows huge before escape, overflow. But maybe we can use a relative threshold: if |z_n| is close to 2, small δz causes escape. The required w_n is (2 - |z_n|)/ε. Since ε = 2^e, if 2 - |z_n| is not smaller than ε, w_n <= 1. If it is smaller, w_n >1. But for escape to happen at iteration n, typically |z_n| is at a local maximum near escape. Could be close. But w_n may be up to maybe 1e10 for 1e10 zoom? That would overflow eventually? Hmm. This is getting complex. Maybe a well-known approach: use perturbation with arbitrary precision reference and compute δz in "highp float" but rescale δz when it gets too small/large. There's a technique called "rebasing": periodically recompute reference orbit at a new center and reset δz. Since the center moves as we zoom in, we can rebase often to keep δc and δz within range. For continuous zoom, the center moves slowly, and we can recompute reference orbit every frame or every few frames. If we rebase to the current center, δc for each pixel is at most half the view size. As we zoom, view size decreases; when it gets below 1e-38, δc underflows. But we can rebase and also scale? If view size < float32 min, we can't represent offsets. So we need a different representation for offsets. Maybe we can use a logarithmic parameterization for zoom: instead of representing view size in world units, represent it as an exponent and use a scaled coordinate system where the actual complex plane coordinate is `center + 2^exponent * normalized_coord`. For exponent less than -126, the actual offset is subnormal in float32, but we can keep normalized_coord as float and exponent as integer. In the recurrence, we can work with scaled variables as above and drop quadratic term. This can handle arbitrary exponent if we drop quadratic term. But we also need to handle w_n overflow. We can let w_n be float32 and hope it's enough. For deep zoom, maybe w_n stays within float32 range because the linear recurrence with u O(1) and z_n bounded yields w_n bounded by something like product of 2|z_n|. For bounded orbits, |z_n| <= 2, so |w_n| can grow like ~4^n in worst case, which overflows quickly. But typical z_n are not always near 2. For points near boundary, it can be. However, if w_n overflows, that pixel would have escaped long before? Not necessarily. Let's consider using perturbation with rebasing and scaling but also use `highp float` (float32). It might work for a large range. But implementing robustly in a single file is nontrivial. Given the user likely expects a cool interactive demo rather than a deep-zoom scientific renderer, maybe a single-precision shader with smooth coloring and continuous zoom is sufficient. Many online Mandelbrot explorers use single precision and zoom to ~1e-7 before artifacts. The user said "infinite" but maybe we can use a trick to make it appear infinite: as zoom gets too deep, we can wrap around or reset? No, they didn't ask for that. We could combine single-precision with a "deep zoom" using perturbation for a decent range. Let's aim for a hybrid that is not too complex but supports deeper than single precision. Use CPU reference orbit computed with double precision and pass as texture. Use perturbation in shader with `highp float`. This extends zoom to ~1e-14? Actually δc = view size * coord. If view size down to 1e-45 (float32 min subnormal), then actual offset is representable. But center coordinate in double has 53 bits, so reference orbit accurate to ~1e-16 relative. For view size <1e-16, the reference orbit errors matter? The perturbation formula uses z_n reference. If z_n has error ~1e-16, then δz computed from δc ~1e-20 may be wrong. But visually maybe okay. For view size down to 1e-38 (float32 limit), double reference orbit is insufficient? Actually reference orbit error ~1e-16 absolute, and δc ~1e-38, so perturbation error from reference orbit may dominate. Hmm. We need high-precision reference orbit for deep zoom. But maybe we can compute it with arbitrary precision using decimal.js. That would allow deep zoom. But then δc in shader is float32 limited to 1e-38. So max depth 1e-38. That's already huge. Let's settle on float32 perturbation with high-precision reference orbit from decimal.js. That gives a deep zoom to ~1e-38, which appears infinite. We can limit min zoom to 1e-38 or similar, and maybe use scaling to go a bit deeper. But 1e-38 is enough. Wait, if we use decimal.js to compute reference orbit, we need to pass it to shader as float32 texture. The reference orbit values z_n are bounded by 2, so float32 is fine. The high precision is used to ensure z_n accurate to ~1e-38 relative to the tiny δc. Actually we need z_n accurate enough that 2 z_n δz term is correct. If δz ~1e-38, z_n error must be <1 to not dominate. Double z_n error ~1e-16, multiplied by δz ~1e-38 gives ~1e-54, which is below float32 precision. Wait float32 precision at 1e-38 is ~1e-46 (relative 1e-7). So double reference is enough. Actually for δc ~1e-38, we need z_n accurate to maybe 1e-30? Double gives 1e-16 absolute, which when multiplied by δz ~1e-38 yields 1e-54, negligible compared to δz^2? Hmm. The recurrence terms: 2 z_n δz_n ~ O(1e-38), δz_n^2 ~ O(1e-76), δc ~1e-38. So the 2 z_n δz term dominates. Error in z_n of 1e-16 times δz_n ~1e-38 gives 1e-54, negligible compared to 1e-38. So double reference orbit is sufficient for δc down to float32 min. Great. So we don't need decimal.js. We can compute reference orbit with double (JS number) and it works for view size down to ~1e-45. Actually we need to compute z_n accurately for c_ref. For points inside set, z_n stays bounded. Double precision orbit is accurate for a reasonable number of iterations (maybe thousands). For deep zoom near boundary, high iteration count and sensitivity may cause double orbit to diverge from true orbit after many iterations. But for perturbation with δc small, relative error may be okay. There's a known issue: double precision reference orbit may be inaccurate for very deep zooms (depth >1e16). But for depth <1e16, double is enough. Since our shader offset limit is 1e-38, but double reference only good to maybe 1e-16, we might get artifacts below 1e-16. However, visually it may still look okay for a while. To extend deeper, we'd need arbitrary precision reference orbit. But maybe we can implement a simple arbitrary precision reference orbit in JS using fixed-point big integers? Let's see. We could use JavaScript's `BigInt` to compute z_n in rational or fixed point. But iterating z = z^2 + c with complex arbitrary precision is possible with BigInt scaled by a power of 2. However, the numbers can get huge (though bounded by 2 for inside points). We can represent real and imaginary parts as BigInt with a fixed scale (e.g., 2^P). Then multiplication and addition are exact. For c_ref, we need it to high precision. We can store center as a high-precision complex number. But our view center is determined by mouse clicks and zoom; we can represent it as a rational or BigInt. Starting from default center 0,0 and zooming by factors. Mouse click picks a point in view. We need to compute center + offset with high precision. We can represent center and zoom size as BigInt scaled by a global exponent. This is doable but adds complexity. Maybe we can use decimal.js from CDN to handle arbitrary precision center and reference orbit. That simplifies high-precision arithmetic. We can load decimal.js and set precision to, say, 60 digits. Then compute reference orbit and pass to shader. The shader still uses float32 for δc, limiting depth to ~1e-38, but 60 digits is enough. Actually 1e-38 is only 38 digits, so 60 digits is overkill. But we also need to compute pixel offsets accurately: pixel offset = view_size * normalized_coord. view_size is a Decimal. We can compute high-precision offset and then convert to float32? That loses precision. We need to pass offset to shader as float32. For depth 1e-38, float32 can represent it. We can compute δc in JS with Decimal and pass as float32. But for continuous zoom, we can keep center as Decimal and size as Decimal. Each frame, compute per-pixel offset in shader as `size * coord`. But size as float32 underflows. We can pass size as float32 only above limit. If we want deeper, no. Alternative: pass center as float32? Then precision limited. We need to pass center and size in a way shader can compute offsets for deep zoom. Since shader can't hold subnormal size, we can't go deeper than 1e-38 with direct multiplication. But maybe we can use the scaling trick in shader: pass `size_mantissa` (float) and `size_exponent` (int). Compute `offset = size_mantissa * coord * exp2(size_exponent)`. If size_exponent < -126, `exp2` underflows to 0. However, we can use the scaled recurrence as above: define w_n = δz_n / 2^exponent. Then recurrence: w_{n+1} = 2 z_n w_n + (2^exponent) w_n^2 + size_mantissa * coord. The term `2^exponent` underflows if exponent < -126. But if it underflows, we can treat it as 0 (the quadratic term is negligible). So we can compute `s = exp2(exponent)` and if exponent is too small, s = 0. The recurrence becomes linear. This allows arbitrary exponent! We just need to store w_n as float32. But w_n may overflow eventually. However, for deep zoom, maybe w_n stays within range until escape. Let's test conceptually. Suppose exponent e = -200, size_mantissa m ~0.5. Recurrence w_{n+1} = 2 z_n w_n + m u. This is like a linearized perturbation. If the reference orbit z_n is bounded, w_n behaves like a sum of products. For escaping pixels, w_n grows. How large can it get before escape? Escape condition: |z_n + 2^e w_n| > 2. Since 2^e is tiny, w_n must be huge to make a difference if z_n is not extremely close to 2. If z_n is bounded away from 2, say |z_n| < 1.9, then to escape we need 2^e |w_n| > 0.1 => |w_n| > 0.1 / 2^e = 0.1 * 2^200 ≈ 8e59. That overflows float32. So for pixels that escape while z_n is not near 2, w_n overflows. But do such pixels exist? If the reference center is inside the set, z_n stays bounded. A pixel offset δc small may cause its orbit to diverge at some iteration N. At iteration N, z_N + δz_N escapes. Typically, the reference orbit at iteration N may be near the boundary of radius 2 (because δz_N is tiny, so z_N must be close to 2 for the sum to exceed 2). Actually if |z_N| is not near 2, δz_N would need to be large, but because δz grows from tiny δc, by the time it becomes large, z_N may be near 2. For deep zoom, escaping pixels correspond to points where the reference orbit comes close to 2 at iteration N. The closeness scales with δc. So w_N = δz_N / 2^e may be of order (2 - |z_N|)/2^e. Since δc ~ 2^e, and the needed δz_N to escape when z_N is at distance d from 2 is ~ d (if direction aligns). So w_N ~ d / 2^e. For escape to happen with δc ~ 2^e, d must be ~ 2^e, so w_N ~ 1. Thus w_n stays moderate. Good. So linear perturbation with w_n float32 may work for deep zoom, as long as the reference orbit is accurate enough to know when z_n is within 2^e of radius 2. But double reference orbit has error ~1e-16, which for e=-200 (2^e ~6e-61) is huge compared to 2^e. We need reference orbit accuracy comparable to 2^e, i.e., >61 digits. So double reference is not enough for e=-200. We need arbitrary precision reference orbit. So a deep zoom renderer needs arbitrary precision reference orbit. We can compute that with decimal.js. Then use linear perturbation in shader with scaling. This can support very deep zoom. But implementing robustly is complex: need to handle both quadratic term when exponent not too small, and linear term when deep. However, maybe we can avoid arbitrary precision reference orbit by making the center always a point with a periodic orbit? No. Given the user request is likely for a visually impressive demo, not a research-grade deep zoom, I think a single-precision direct shader is acceptable. But the phrase "infinite Mandelbrot zoom" suggests they want to zoom forever. We can perhaps use a clever trick: when zoom reaches a certain depth, we can reset the coordinate scale while keeping the view? That would cause a jump. Or we can use a "billboard" of a pre-rendered deep zoom image and scale it? No. Maybe we can use the fact that the Mandelbrot set has mini copies at all scales, and we can dynamically re-center to a mini-Mandelbrot that is large enough to avoid precision issues. But that requires locating mini-copies, which is nontrivial. Given the complexity, I think the best answer is a high-quality single-precision WebGL2 renderer with smooth coloring, click/hold zoom, and escape reset. It won't be truly infinite but will be a nice fly-through. I can mention in code comments that it uses single precision. But the user didn't ask for comments. They want the file. However, maybe I can implement a more advanced version using perturbation with double-precision reference orbit (JS number) and support deeper zoom than single precision. Let's see how much more complex that is. It requires: - Compute reference orbit for current center each frame (or when changed) up to max iterations. - Store in a float texture. - In shader, for each pixel, compute δc = c - c_ref, where c = center + size * coord. Since center and c_ref are the same (we use current center as reference), δc = size * coord. So we just need size and coord. Great. We don't need to subtract two close large numbers. We can compute δc directly as size * coord in shader. If size is float32, max depth ~1e-38. But we can pass size as float32. That's deeper than direct center+size*coord with center also float32? Actually direct shader also computes c = center + size*coord. If center is fixed and size small, the addition center + tiny offset loses precision because center is large (maybe ~0.5). Float32 precision at 0.5 is ~3e-8, so offsets smaller than 3e-8 are lost. That's the limit for direct single-precision: ~1e-7 relative. With perturbation, we avoid adding offset to center;