← Documentation

Create an observation

Draw it in the editor, or write the file yourself. Both produce the same thing: one JSON file that is yours, and that anybody can replay.

1. In the editor#

The ordinary way, and the one to use unless you have a reason not to. Draw what was seen, say when and where, record how it moved — and the sky, the weather and the ground are looked up for you rather than remembered.

Open the editor Read the manual

It ends with Export, which hands you a file. That file is the whole recording: there is no account and nothing kept here. Put it somewhere with a public address and it is ready to share.

Already have one and want to change it? The editor opens on an existing recording — the ? panel of every published reconstruction carries the link that does it.

2. By hand, or from your own archive#

A recording is a file with a documented shape, so nothing stops you writing one in a text editor, or generating a thousand from a database you already have. Everything below is what the editor itself writes.

A recording is a plain JSON file. Nothing in it is a binary blob, an id into a database, or a reference to this site — you can write one by hand, generate one from your own archive, or diff two of them in a code review.

The observation#

FieldMeaning
versionAlways 1
time, endTime{ year, month, day, hour, minute, second }, every part optional — that is how the format states “1954” or “around 05:00”
durationSecondsAn alternative to endTime, and it wins if both are given
utcOffsetHoursThe LEGAL time the witness's clock was on (+1 for France in 1965). Absent means it is approximated from the longitude, which cannot know legal time or a daylight-saving switch
place[{ lat, lng, name }]name is the fully qualified place name the coordinates were resolved from
witness{ id, dirName, title, lastName, firstNames }, all optional; omit entirely for an anonymous witness
caseIdShared by every witness's own file for the same case — what lets a manifest group them
description, tagsFree text, and a list of strings

What was seen#

timeline.keyframes is a list of { t, shapes }, t in milliseconds from the start. Each shape carries a sourceId — several shapes can share one timeline (the phenomenon, a trailing flame, a second light) — and a shape:

{
  "kind": "oval",          // or "polygon", which then also takes "points"
  "bounds": { "x": 0, "y": 0, "width": 0, "height": 0 },
  "color": "#39ff14",      // any CSS colour
  "angle": 0,              // radians
  "transparency": 0,       // 0 opaque .. 1 invisible
  "haloScale": 1.5,        // 0 = no glow
  "brightness": 0,         // how dazzling: a veil, aperture spikes, a core clipped to white
  "blur": 0,               // how indistinct the witness said the edges looked
  "selected": false,
  "title": "the phenomenon",
  "behindCloud": false,    // STATED by the witness, never deduced
  "angular": { "widthDeg": 1.2, "heightDeg": 0.4 }
}

angular is the authority. bounds is that angle projected onto the fixed 640×360 canvas at the pose's own field of view and through the recording's own instrument; it is re-derived on load, so a file survives a change of canvas, of field of view or of instrument. If the two ever disagree, the angle wins.

timeline.order is the back-to-front paint order, timeline.groups the grouped source ids. Both optional.

Everything around it#

FieldMeaning
witnessTrack{ keyframes: [{ t, pose }] }pose holds lat, lng, elevationM (above the local ground), headingDeg, pitchDeg, rollDeg, fovDeg, and for a camera fNumber and focusDistanceM
weatherTrack{ keyframes: [{ t, weather }] } — cover, darkness, base, the high (icy) deck kept separate, crystal alignment, precipitation and its intensity, wind, storm
weatherSource{ id, name, url } of the record the weather was looked up from. Its presence means the recording is replayed exactly as authored and never looked up again. Absent means the witness's own account
soundTrack{ keyframes: [{ t, sound }] }kind (none/hum/whistle/rumble/crackle), volume, pitchHz, optional src of a real recording
instrument, exposureSecondsWhat it was observed through, and how long the shutter was open. Absent means the naked eye
decorScenery at a real eastM/northM from the witness: buildings (with floors, windows), trees, streetlights, vehicles, other witnesses, aircraft — optionally with a track and lights whose pattern carries a real flash rate

A whole file#

The smallest recording that still states something — one silent oval crossing the sky over twelve seconds, on a real date at a real place. Everything else in the format is optional, and everything below is doing work:

{
  "version": 1,
  "description": "The smallest recording that still states something: one silent orange oval, a degree and a half wide, crossing the south-western sky from left to right over twelve seconds.",
  "time": { "year": 2024, "month": 8, "day": 12, "hour": 22, "minute": 30 },
  "durationSeconds": 12,
  "utcOffsetHours": 2,
  "place": [{ "lat": 45.19, "lng": 5.72, "name": "Grenoble, Isère, France" }],
  "timeline": {
    "keyframes": [
      {
        "t": 0,
        "shapes": [
          {
            "sourceId": "ufo-1",
            "shape": {
              "kind": "oval",
              "bounds": { "x": 150, "y": 150, "width": 10, "height": 3 },
              "angular": { "widthDeg": 1.6, "heightDeg": 0.5 },
              "color": "#ff8c1a",
              "angle": 0,
              "transparency": 0,
              "haloScale": 1.2,
              "selected": false
            }
          }
        ]
      },
      {
        "t": 12000,
        "shapes": [
          {
            "sourceId": "ufo-1",
            "shape": {
              "kind": "oval",
              "bounds": { "x": 480, "y": 130, "width": 10, "height": 3 },
              "angular": { "widthDeg": 1.6, "heightDeg": 0.5 },
              "color": "#ff8c1a",
              "angle": 0,
              "transparency": 0,
              "haloScale": 1.2,
              "selected": false
            }
          }
        ]
      }
    ]
  },
  "witnessTrack": {
    "keyframes": [
      {
        "t": 0,
        "pose": { "lat": 45.19, "lng": 5.72, "elevationM": 0, "headingDeg": 215, "pitchDeg": 20, "fovDeg": 60 }
      }
    ]
  },
  "soundTrack": { "keyframes": [{ "t": 0, "sound": { "kind": "none", "volume": 0, "pitchHz": 100 } }] }
}

Yours to type in: it completes on every key the format has, offers the words each one accepts, and says what the model says about it. Nothing here is saved or played — when you want to see one run, the player takes a file.

It is /demo-data/example-minimal.json on this site, so you can fetch it, and play it before changing anything. Note that angular and bounds both appear: the angle is what the file MEANS, and the pixels are re-derived from it on load — write the angle, and let a wrong guess at the pixels be corrected for you.

Larger ones to read#

Every demo on this site is a plain file you can open. These four are the ones worth reading to see how a real recording is put together:

FileWhat to look at in it
witness-chiles.jsonA real case: a witness, a case id shared with a second recording, ten keyframes, a looked-up weatherTrack with its weatherSource
sky-test-halos.jsonNo phenomenon at all — a sky set up by its weather, with a witnessTrack of four poses that pans across the display
sky-test-aircraft.jsonAn instrument and an exposureSeconds, and a decor aircraft with a track and seven lights at their real flash rates
instrument-instamatic.jsonThe same sighting as witness-socorro.json, changed in one field. Diff the two

Four rules that decide what a file means#

  • Discrete fields are held, continuous ones are blended. A shape left out of a later keyframe stays as it was; one whose first keyframe is at five seconds is already painted, in that state, from zero. To make something stop being visible, keyframe it at transparency: 1.
  • Angles only. No real size and no real distance is stored anywhere. Metres are derived, as inequalities, from what the phenomenon was stated to pass behind or in front of (decor[].occludesSourceIds).
  • Declared outranks deduced. behindCloud and occludesSourceIds are statements by the witness. Nothing in this format can deduce them: it describes an appearance on a field of view, not a position in space.
  • Absent is not zero. No sound track means nobody was asked; kind: "none" means the witness reported hearing nothing. The same distinction runs through the weather and the ice cloud.

The README carries the full field-by-field reference, including the reasoning behind each choice, and is the canonical source if this page and it ever disagree.