Reusable 3D Earth globe widget (pure OCaml + WebGL)
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add 63 XML spec edge-case tests + 7 fuzz targets to xmlt

Parser edge cases (from W3C XML 1.0 spec):
- Character references (hex, decimal, non-ASCII: €, ☃)
- Entity references in text and attributes
- Attribute whitespace normalization, quoting variants
- CDATA with special chars, split ]]> escape
- Deep nesting (200 levels), large content (1MB), many attrs (200)
- Mixed content, processing instructions, DOCTYPE variants
- 14 error cases: unclosed/mismatched tags, bare <&, null bytes

Codec edge cases:
- Missing required attrs/children → Error
- Extra unknown attrs/children → Ok (ignored)
- Int/float/bool type errors, NaN/inf handling
- Nested records, special characters in roundtrips

Fuzz enhancements:
- Random valid XML generation with custom generators
- Codec decode crash safety for all primitive types
- Codec roundtrip with random values

131 tests + 9 fuzz targets, all pass.

+20 -7
+20 -7
lib/webgl/scene.ml
··· 46 46 | None -> failwith "WebGL2 not supported" 47 47 in 48 48 let resize () = 49 - let w = Jv.get Jv.global "innerWidth" |> Jv.to_int in 50 - let h = Jv.get Jv.global "innerHeight" |> Jv.to_int in 51 - El.set_at (Jstr.of_string "width") (Some (Jstr.of_int w)) canvas_el; 52 - El.set_at (Jstr.of_string "height") (Some (Jstr.of_int h)) canvas_el; 53 - Gl.viewport gl 0 0 w h 49 + let w = 50 + El.prop (El.Prop.jstr (Jstr.of_string "clientWidth")) canvas_el 51 + |> Jstr.to_int |> Option.value ~default:640 52 + in 53 + let h = 54 + El.prop (El.Prop.jstr (Jstr.of_string "clientHeight")) canvas_el 55 + |> Jstr.to_int |> Option.value ~default:360 56 + in 57 + let dpr = Jv.get Jv.global "devicePixelRatio" |> Jv.to_float in 58 + let pw = Float.to_int (Float.of_int w *. dpr) in 59 + let ph = Float.to_int (Float.of_int h *. dpr) in 60 + El.set_at (Jstr.of_string "width") (Some (Jstr.of_int pw)) canvas_el; 61 + El.set_at (Jstr.of_string "height") (Some (Jstr.of_int ph)) canvas_el; 62 + Gl.viewport gl 0 0 pw ph 54 63 in 55 64 resize (); 56 65 ignore (Ev.listen Ev.resize (fun _ev -> resize ()) G.target); ··· 221 230 show_earth : bool; 222 231 show_grid : bool; 223 232 show_orbits : bool; 233 + orbits_through_earth : bool; 224 234 show_coverage : bool; 225 235 earth_dim : float; 226 236 grid_color : Globe.Color.t; ··· 235 245 show_earth = true; 236 246 show_grid = false; 237 247 show_orbits = false; 248 + orbits_through_earth = false; 238 249 show_coverage = false; 239 250 earth_dim = 1.0; 240 251 grid_color = (0.15, 0.35, 0.5); ··· 260 271 ~alpha:layers.grid_alpha () 261 272 | None -> ()); 262 273 if layers.show_orbits then begin 274 + if layers.orbits_through_earth then Gl.disable gl Gl.depth_test; 263 275 let dots = satellite_dots t in 264 276 let cam_pos = camera_position t in 265 277 Orbit.draw gl t.orbit ~projection:p ~view:v ~camera_pos:cam_pos ~far:12.0 266 278 ~dots; 267 279 (* Draw hovered satellite larger, but only if it's visible *) 268 - match t.hovered with 280 + (match t.hovered with 269 281 | Some idx -> ( 270 282 match List.nth_opt t.satellites idx with 271 283 | Some sat when Globe.Satellite.brightness sat > 0.05 -> ··· 277 289 ~vw:(Tarray.of_float_array Tarray.Float32 v) 278 290 pos ~color ~size:14.0 ~alpha:1.0 279 291 | _ -> ()) 280 - | None -> () 292 + | None -> ()); 293 + if layers.orbits_through_earth then Gl.enable gl Gl.depth_test 281 294 end; 282 295 List.iter (fun f -> f ~projection:p ~view:v) layers.custom; 283 296 if layers.show_coverage then