---
name: ufoathome-recording
description: Build a UFO@home recording (the sighting JSON file replayed at ufoathome.org) from the documents of a UFO/UAP sighting case, such as reports, questionnaires, statements, sketches, maps and photos of the place. Use when asked to reconstruct, simulate, replay or model what an observer saw for UFO@home, or to write or fix a sighting.json / observer-*.json file.
---

# Recording a sighting for UFO@home

A UFO@home recording is one JSON file stating what one observer saw: when, where, which way they
looked, and the phenomenon as directions and apparent sizes over time. The player computes the rest
(the real sky of that moment, the ground, the weather, the optics of the eye or the camera) from
it. Your job is to state the account precisely and honestly, not to illustrate it.

Written for UFO@home 0.113.0. Format reference: https://ufoathome.org/docs/format/ ,
schema: `references/sighting.schema.json` (also https://ufoathome.org/sighting.schema.json ),
smallest valid example: `references/example-minimal.json`.

## The one rule that matters

Every value is one of three things, and you say which:

- **stated**: the observer said it (a bare value means this);
- **derived**: worked out from what they said plus something checkable (a map, a measured
  drawing, a road's width, a clock correction). Write it as
  `{"value": ..., "basis": "derived", "rationale": "the working, with the numbers"}`;
- **assumed**: chosen so the reconstruction has a value at all, on nothing the observer said.
  Write it as `{"value": ..., "basis": "assumed", "rationale": "what it was chosen for"}`.

A wrong value marked "assumed" is a question for the author. A guess passed off as stated is a
fabricated account, the one thing this format exists to prevent. When in doubt, mark it weaker. Do
not wrap plumbing (`version`, `id`, `sourceId`).

## Method

1. **Read every document, and cite as you go** (document and page). Note each contradiction between
   them (times, distances, directions, durations) instead of silently picking one; pick one for the
   file, and say which and why.
2. **Place and time.** Coordinates of where the observer stood, from the case's own map or survey
   first (a KMZ, a plan), a geocoder last. The local time their clock showed, corrected if the
   investigator measured the clock. The time zone and the legal offset on that date.
3. **The phenomenon, in angles.** The best source is a drawing the observer made or approved on a
   photograph of the place: find the photo's scale (a stated field of view, or two landmarks of
   known bearing) and measure, with code, the shape's centre, width, height and tilt at each stage.
   Otherwise convert the account's comparisons. One keyframe per moment the account distinguishes.
4. **The observer.** Where they stood and which way they looked, at each moment (a head turned
   towards the phenomenon is a pose change), walking or driving if they were.
5. **What surrounds them**, only as far as the account uses it: the objects the phenomenon stood
   before or went behind, the vehicle they were in, the other people present. The weather they
   described, and the record it can be checked against (the ERA5 reanalysis, for instance
   https://archive-api.open-meteo.com/v1/archive with hourly cloud cover, precipitation and wind,
   named in `weatherSource`; the last five days are not in ERA5 yet, and https://historical-forecast-api.open-meteo.com/v1/forecast answers for them). Sound, if they said anything about it.
6. **Say what it was, and who said it.** What the observer themselves concluded (a craft standing on
   its legs, a being of a certain height) goes in `interpretation`, as bodies in metres tested
   against the angles. Someone else's reading, an investigator's or yours, is not part of the account:
   it is another recording of the case, listed in its `case.json` as an event of type
   `sighting` marked `interpretationOf`, which names the account's event by its `id` in the case
   (give that event an `id`, `"trent"`: it is local to the case, not the recording's own). A natural cause the account suggests is stated there too
   (`interpretation.launches` for a rocket's exhaust in the twilight, `reentries` for a satellite
   or stage breaking up), never drawn into the shapes. Do not write what the player works out from
   the date and the place: the sky, the planets, the Moon, eclipses, satellites, the relief
   (https://ufoathome.org/docs/sources/ lists them).
7. **One recording per observer.** When several people saw it, write a recording for each and a case
   file that names them (https://ufoathome.org/docs/format/#several-observers-the-case). People,
   vehicles, trees and buildings come from the catalogue
   https://ufoathome.org/models/index.json , by `model.id`: never invent a model, and never leave a
   person to the built-in shape. A model publishes its own settings (a costume colour, a hull
   colour, retracted landing gear) under `modelParameters`: state one only when the account does.
8. **Say what the file is about.** `summary` (a sentence or two, in the account's language) and
   `image` (the observer's own drawing or a photograph of the place, when the documents hold
   one) are what a shared link shows; the case file takes the same two. Without them the link shows
   the logo and who saw it.
9. **Write the file**, then **validate it**: `python3 scripts/validate.py recording.json` must say
   `valid`, and so must `case.json` (it checks that every `interpretationOf` names an event of the
   case, and that no `id` is borne twice). It catches misspelt keys and words a closed list does not have; it cannot catch a
   wrong direction.
10. **Hand over** the file with a short report: the values you derived and how, the list of assumed
   values, the contradictions, and the questions to put back to the observer or the investigator.
   Tell the user to play it at https://ufoathome.org/play/ ("From your computer", choosing the
   photos it names along with it) and to check that the phenomenon sits where the drawings put it;
   then to correct it with you, or in the editor at https://ufoathome.org/edit/ for fine placement.
   Only the observer can say it looks like what they saw.

## Format rules

1. Sizes are ANGULAR, in degrees (`angular`: {widthDeg, heightDeg}), never metric: the format stores
   no physical size, because an observer perceives an angle and a size only follows from a distance
   nobody measured. Convert the comparisons an account gives (the full Moon and the Sun about 0.5
   degrees across, a thumbnail at arm's length about 1.5, a fist about 10), or measure them: a
   drawing made on a photograph of the place, with a known field of view or a landmark of known
   bearing, gives degrees per pixel. Where nothing gives a size, work from what the scene implies
   and put the range in the rationale.
2. A shape is PLACED by `aim`, the direction of its centre in the observer's sky: `azimuthDeg`
   clockwise from true north and `altitudeDeg` above the horizon. Not the way the observer faced,
   which is the pose's heading and pitch. `bounds` (pixels) is recomputed on load from `aim` and
   `angular`; leave it out. `angle` tilts the shape, in radians, positive clockwise on screen.
   Derive directions from the geography where it allows (a map, the bearing of a road, a landmark
   the observer named); where nothing bears on the altitude, assume something low and plausible and
   mark it "assumed".
3. Times are the local legal time at the place, as the observer's clock read it. Give the IANA
   `timeZone` their clock was on ("Europe/Paris") AND `utcOffsetHours`, the legal offset on that
   date, summer time included (+2 for France in June 2012, +1 in 1965): the player places the sky
   from the number alone, and without it approximates the offset from the longitude, which knows
   nothing of legal time. A time corrected by the investigator (a clock found fast) is "derived".
4. Duration: `durationSeconds` is the one length the reconstruction is played at, a bare number. For a
   vague length ("a few minutes"), state it in `durationText` (an ISO 8601 duration with a doubt, `"PT3M~"`, or a
   range, `"PT5M/PT10M"`) and put the length chosen to play at in `durationSeconds`, with its provenance. Use
   `durationSeconds` alone for a length that was timed or bounded.
5. `timeline.keyframes` is [{t, shapes: [{sourceId, shape}]}], t in milliseconds from the start of
   the recording. Give a keyframe only for a moment the account distinguishes (where it arrived,
   when it changed, where it went); the player interpolates between them. A keyframe need only
   restate what changes: every field a shape leaves out is held from the keyframe before. To make a
   shape vanish, keyframe it at `transparency: 1`. `milestones` ([{t, label, note}]) name the
   moments the account itself names ("A", "B"), shown on the seek bar.
6. A shape is `kind` "oval" or "polygon" (a polygon's `points` are pixels from the top-left of its
   box, spanning the box: they are stretched with it), `title` (what the observer called it),
   `angular` and `aim`. Add `color`, `haloScale` (a glow around it), `brightness` (0 a light
   you can look at, 1 one you cannot) and `blur` (0 hard edges, 1 none) only when the account
   describes them; left out, they assert nothing.
7. `description` is the account itself, in prose: what the observer said, in their words where the
   documents quote them, one string or one per language ({"fr": ..., "en": ...}). Not your
   analysis: measurements, contradictions and reasoning belong in the values, their rationales,
   and your report.
8. `tags` are stored in English whatever the account's language, because two recordings that share
   a tag have to match on it. Reuse the vocabulary already in use where it fits (landing, trace, aerial observation, project sign, paralysis, contact, occupants, close encounter, photograph, radar, electromagnetic effect); pass
   classification codes and case references through unchanged ("RR3", "NL", "GEIPAN D1").
   `paralysis` changes the replay (the view is held still): use it only when the account says the
   observer could not move.
9. `decor` is the scenery the account names, and `eastM`/`northM` are metres from where the
   observer stood at the start. Something the observer is INSIDE (their car) goes at 0,0 and carries
   `observerSide` ("front-left" for a European driver's seat); anything else must be away from
   0,0, or it is drawn on the lens. Give `sizeM` ({widthM, lengthM, heightM}) where known. The
   relief and the roads of the map are drawn for you: add decor for what the account uses (the wood the phenomenon stood before, the car, the other people present, as kind
   "observer"). When the account says the phenomenon went behind something, that object's
   `occludesSourceIds` names the shape. Roads the map lacks go in `roads`.
10. `observerTrack` ({keyframes: [{t, pose}]}) is where the observer stood and which way they looked,
   over time: `lat`, `lng`, `elevationM` (metres above the local ground, 0 for someone standing
   on it: the eye's own height is added), `headingDeg` and `pitchDeg` (the direction they LOOKED,
   same conventions as `aim`), `fovDeg` (the vertical field shown, about 60 for the naked eye).
   A walk is a series of poses; a head turned towards the phenomenon is two poses a fraction of a
   second apart. `instrument` is "eye" unless a camera was used.
11. `account` is about the observer and how the account travelled: `observerAgeYears` (at the
   time), `observerOccupation` (in their words), `source` (how it reached whoever wrote the
   recording: on-site, interview, telephone, questionnaire, letter, social-media, press) and `followedUp`
   (whether they were gone back to). Where the account can be read goes in `sources`, in the
   shape of an RR0 source: [{type ("book" | "article", none for a web page or a post), title,
   authors, url, publication: {publisher, time}, index}]. Always give the documents you worked from. Each other person present is a `decor` object of kind
   "observer".
12. Absent is not zero. An observer who says the thing was silent gets a `soundTrack` whose keyframe
   holds a sound of kind "none"; an account that never mentions sound gets no soundTrack. The same
   holds for the weather: `weatherTrack` states what the observer saw of the sky (cover, rain,
   wind); when it comes from a record (ERA5, a METAR, a station), `weatherSource` names it.
13. `lightPollution` (a number) is how bright the night sky of the place is, towns and all: the
   zenith of a moonless night in magnitudes per square arcsecond, as a Sky Quality Meter reads it or
   as the World Atlas of artificial sky brightness gives it ("SQM", Falchi et al. 2016). 22 is a
   natural sky, and absent means one. "derived" when looked up in the atlas (name it in the
   rationale), "stated" when the observer measured it. It brightens the sky, hides the Milky Way
   and takes stars away; never write a brighter sky than the source gives.
14. The observer's own estimate in metres ("60 m long, 175 m away, 10 m up") is not an observation
   but a conclusion: it goes in `interpretation` (bodies in metres, see the format page), never in
   the shapes. When it contradicts the angles the observer measured, keep it anyway and say so in
   your report: the player's comparison is what shows the contradiction.

## Things that have gone wrong before

- Setting `aim` to the direction the observer faced rather than to the phenomenon's own direction
  puts every keyframe at the centre of the view.
- Moving `bounds` does nothing: `aim` and `angular` decide where the shape is and how big.
- An elevation above sea level in `elevationM` lifts the observer into the air: it is above the
  ground.
- Metres in the shapes (a "60 m object" as a size) are a conclusion, not an observation: they belong
  in `interpretation`.
- `description` filled with your analysis instead of the account: keep the account there, and your
  working in the rationales and the report.

## Privacy

An account is personal data. Use initials or the case's own anonymisation unless the observer is
already public or agreed to be named, and never put details that identify a private person in
`observer`, `description` or `account` beyond what the published case file itself shows.
