{
  "units": {
    "geometry": "metres",
    "volumes": "millilitres",
    "time": "seconds"
  },
  "fps": 30,
  "frames": 180,
  "resolution": [
    800,
    600
  ],
  "camera": {
    "type": "perspective",
    "lens_mm": 45,
    "sensor_width_mm": 36,
    "intrinsics": [
      [
        1000,
        0,
        400
      ],
      [
        0,
        1000,
        300
      ],
      [
        0,
        0,
        1
      ]
    ],
    "pose_file": "camera_poses.json",
    "convention": "Blender camera: -Z forward, +Y up; world Z up; world_to_camera matrices"
  },
  "observation": {
    "scored_endpoint_frames": [
      66,
      120
    ],
    "away_orientation_hold_frames": [
      76,
      111
    ],
    "hold_duration_s": 1.2,
    "pan_out_frames": [
      67,
      75
    ],
    "pan_back_frames": [
      112,
      119
    ]
  },
  "source": {
    "inner_radius_m": 0.046,
    "interior_height_m": 0.18,
    "base_center_m": [
      -0.16,
      0,
      0.235
    ],
    "graduations_ml": 100,
    "initial_volume_ml": "Read from reference; not supplied",
    "flow_schedule": "UNKNOWN; may vary while unobserved"
  },
  "cup": {
    "inner_radius_m": 0.034,
    "interior_height_m": 0.09,
    "base_center_m": [
      0,
      0,
      0.008
    ],
    "capacity_ml": 326.8512996794821,
    "graduations_ml": 50,
    "initial_volume_ml": "Read from reference; not supplied"
  },
  "model": {
    "type": "Analytical volume conservation, visualized in Blender",
    "no_external_sources_or_losses": true,
    "cup_stationary": true,
    "retained_volume": "min(cup capacity, initial cup volume + cumulative inflow)",
    "spill_volume": "max(0, initial cup volume + cumulative inflow - cup capacity)",
    "source_loss_equals_cup_gain_plus_spill": true,
    "stream_transit_and_hold_up": "neglected",
    "ripple_and_droplet_tracers": "visual only; not included in volume accounting",
    "water_draw_radius_clearance_m": 0.0001,
    "puddle_visualization_depth_m": 0.002,
    "puddle_shape": "procedural visualization; exact boundary is not scored"
  },
  "unknowns": [
    "unobserved_poured_ml",
    "unobserved_retained_ml",
    "unobserved_spilled_ml",
    "overflow_occurred"
  ],
  "time_origin": "Frame 1 is t=0; t=(frame-1)/30 seconds."
}
