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#
| Field | Meaning |
|---|---|
version | Always 1 |
time, endTime | { year, month, day, hour, minute, second }, every part optional — that is how the format states “1954” or “around 05:00” |
durationSeconds | An alternative to endTime, and it wins if both are given |
utcOffsetHours | The 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 |
caseId | Shared by every witness's own file for the same case — what lets a manifest group them |
description, tags | Free 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#
| Field | Meaning |
|---|---|
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, exposureSeconds | What it was observed through, and how long the shutter was open. Absent means the naked eye |
decor | Scenery 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:
| File | What to look at in it |
|---|---|
witness-chiles.json | A real case: a witness, a case id shared with a second recording, ten keyframes, a looked-up weatherTrack with its weatherSource |
sky-test-halos.json | No phenomenon at all — a sky set up by its weather, with a witnessTrack of four poses that pans across the display |
sky-test-aircraft.json | An instrument and an exposureSeconds, and a decor aircraft with a track and seven lights at their real flash rates |
instrument-instamatic.json | The 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.
behindCloudandoccludesSourceIdsare 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.