← Documentation

Le fichier d'observation

Un enregistrement est un fichier JSON, que l'éditeur l'ait écrit ou vous. Voici ce qu'il peut contenir, et ce que veut dire chaque champ.

Un enregistrement est un simple fichier JSON. Rien dedans n'est un blob binaire, un identifiant dans une base de données, ni une référence à ce site — vous pouvez en écrire un à la main, en engendrer depuis vos propres archives, ou en comparer deux dans une relecture de code.

Chaque extrait ci-dessous est en lecture seule, et chacun connaît le format : placez le curseur dans un objet et faites Ctrl+Espace (⌥+I sur Mac) pour lister toutes les clés qui pourraient y figurer, avec ce que le modèle dit de chacune.

L'observation#

ChampSens
versionToujours 1
idQuel compte rendu c'est, unique parmi tous les enregistrements : le jour, puis qui l'a vu ("1964-04-24-ZamoraLonnie"), ou le lieu pour un observateur anonyme ("1964-04-24-Socorro"). Ce par quoi un dossier le désigne n'est pas cet id mais celui de son événement (voir plus bas).
time, endTime{ year, month, day, hour, minute, second, raw }, chaque partie facultative — c'est ainsi que le format énonce « 1954 » ou « vers 05:00 ». raw est la date telle qu'écrite en EDTF, et c'est elle qui fait foi : "1948-07-24T02:45~" (approximative), "2025-06?" (incertaine), "1965-07-01%" (les deux), "19XX" (une année masquée), ou "05:00" seul pour une heure dont on a oublié la date. Les nombres sont tenus en accord avec elle pour ce qui calcule (le ciel, l'horloge). C'est un sous-ensemble d'EDTF (niveau 0, ces qualificatifs sur la date entière, années masquées) ; @rr0/time est le modèle EDTF complet de RR0, dans lequel l'outillage d'UFO@home convertit les dates d'un enregistrement season (spring, summer, autumn ou winter) dit une date connue seulement comme « au printemps 2022 » (EDTF 2022-21), où month et day sont omis.
durationSecondsUne alternative à endTime, et c'est elle qui l'emporte si les deux sont là
durationTextLa durée telle qu'elle a été énoncée quand elle n'était pas exacte : une durée ISO 8601 avec un doute (PT10M~) ou une plage (PT5M/PT10M). durationSeconds est alors l'unique durée à laquelle on joue, choisie à partir d'elle
utcOffsetHoursL'heure LÉGALE de la montre de l'observateur (+1 pour la France en 1965). Absent, elle est approchée depuis la longitude, qui ne peut connaître ni l'heure légale ni un changement d'heure
timeZoneLe fuseau IANA dont le décalage a été dérivé ("Europe/Paris") : la règle, là où utcOffsetHours est le nombre qu'elle donnait à cette date. Seul le nombre sert à placer le ciel ; le fuseau permet de dériver à nouveau le décalage quand la date change
place[{ lat, lng, name }] — name est le nom qualifié depuis lequel les coordonnées ont été résolues
observer{ id, title, lastName, firstNames }, tous facultatifs ; à omettre entièrement pour un observateur anonyme. id est une référence à la personne (sur RR0, son répertoire : "ZamoraLonnie") ; les autres champs la décrivent quand personne ne lui en a encore donné
descriptionLe récit en prose — une chaîne, ou une par langue (voir plus bas)
image, summary, summaryTimeCe qui tient lieu de l'observation là où elle n'est que citée, jamais jouée : la carte qu'affiche un lien partagé (voir Partager). image est une image, une adresse (absolue, relative au fichier, ou un chemin RR0 depuis la racine du site) ; summary une phrase ou deux, une chaîne ou une par langue. Absents, la carte montre le logo et dit qui l'a vue, dans quel dossier et quand, pour autant que le fichier le dise. summaryTime est la seconde de l'enregistrement où l'on photographie l'image de la carte (0 par défaut : la première image), pour un enregistrement dont la première image ne montre pas le phénomène ; seul l'outil de capture du projet le lit, jamais le lecteur
tagsUne liste de chaînes, écrites en anglais : ce sont des termes techniques, et deux enregistrements qui en partagent un doivent s'y égaler. Chaque lecteur les voit dans sa langue lorsqu'une traduction est connue, ce qui est le cas aujourd'hui de landing, trace, aerial observation, project sign, paralysis, contact, occupants, close encounter, photograph, radar, electromagnetic effect. La liste n'est pas fermée : tout autre tag est affiché tel qu'écrit, et les codes de classement ("RR3", "NL") ou les références de dossier ("Blue Book 8729") s'écrivent tels quels. Un seul change le rejeu : paralysis immobilise la vue de l'observateur
accountQui l'a vu et comment le récit a circulé : observerAgeYears (à l'époque), observerOccupation, source (comment il est parvenu à qui a écrit l'enregistrement : on-site, interview, telephone, questionnaire, letter, social-media, press) et followedUp (si l'observateur a été revu ensuite)
sourcesOù lire le récit tel qu'il a été donné, sous la forme d'une source RR0 : [{ type, title, authors, url, publication: { publisher, time }, index }], type valant book ou article, ou rien pour une page web ou un post, qui n'est alors que son url. Affichées dans le panneau ? du lecteur, en lien quand elles ont une adresse ; reprises telles quelles dans un dossier RR0
milestonesLes moments nommés du récit, affichés sur la barre de lecture : [{ t, label, note }], label étant la lettre ou le numéro qu'utilise le récit lui-même ("A", "B") ou deux ou trois mots, note ce qui s'est passé alors, dans les mots du récit si possible (une chaîne, ou une par langue)
roadsLes routes ou chemins que dessine le plan du récit, quand la carte ne les a pas : [{ id, title, surface, widthM, path, source }], surface valant paved, gravel ou dirt, path étant l'axe en [{ eastM, northM }] depuis le lieu de l'observateur au départ, et source le plan ou le relevé d'où il est tiré

Plusieurs observateurs : le dossier#

Chaque observateur a son propre enregistrement, et un enregistrement ne dit pas à quel dossier il appartient : un compte rendu se suffit à lui-même. Ce qui les montre ensemble est le dossier, qui les désigne : le case.json d'un dossier RR0, qui énonce le titre, la date et la classification du cas, et liste tout ce qui lui est arrivé en events. Ses événements de type sighting sont ses comptes rendus, chacun pointant vers l'enregistrement d'un observateur :

{
  "id": "ChilesWhitted",
  "title": "Chiles et Whitted",
  "time": "1948-07-24 02:45",
  "events": [
    { "type": "event", "eventType": "sighting", "url": "observer-chiles.json" },
    { "type": "event", "eventType": "sighting", "url": "observer-whitted.json" }
  ]
}
ChampSens
idL'identifiant du dossier lui-même. Sur rr0.org c'est le répertoire du dossier, et il peut être omis ; un fichier de cas isolé l'énonce
title, timeLe nom du cas, et sa date comme RR0 l'écrit ("1948-07-24 02:45", "1954"). Le lecteur nomme un cas qu'il ouvre par son titre
eventsLa chronologie du cas. Seuls les sighting sont rejoués, chacun par son url, lue relativement à l'adresse du fichier de cas (si bien que le même cas marche depuis la page de son dossier comme depuis n'importe où) ; ceux marqués interpretationOf sont des lectures de l'un d'eux (voir plus bas) ; les autres (un article, un film, un aveu) sont ceux de RR0 Un événement porte un id quand une lecture le désigne, et seulement alors : il appartient au dossier, donc il doit être unique parmi les événements du dossier et nulle part ailleurs, et une référence se lit dans le fichier qui l'écrit. Un interpretationOf qu'aucun événement ne porte est lu, comme avant, comme l'id que déclare un enregistrement que le dossier liste ; celui qui ne correspond à aucun des deux est une faute du dossier, que le lecteur signale sur sa console, l'éditeur au-dessus de ses enregistrements, et le validate.py du skill quand on lui donne le fichier du dossier.
image, summaryCe que montre un lien partagé vers le dossier, comme pour un enregistrement (voir Partager) : une image, et une phrase ou deux, une chaîne ou une par langue

Donnez-le à <rr0-sighting src> ou au lecteur, et chaque observateur se choisit dans une liste. Un enregistrement peut être donné directement, sans dossier, mais un dossier à un seul compte rendu marche de la même façon et nomme ce qu'il montre. Essayez avec case-chiles-whitted.json (le jouer).

Le dire en plusieurs langues#

Un enregistrement se transmet d'un lecteur à un autre : chaque champ écrit par un auteur peut donc porter une chaîne par langue au lieu d'une seule — description, le title d'une forme ou d'un élément de décor, le label et la note d'un repère.

{
  "description": {
    "fr": "Tout le compte rendu de Lonnie Zamora, d'un seul tenant…",
    "en": "Lonnie Zamora's whole account, of a piece…"
  }
}

Les clés sont des étiquettes de langue telles qu'un navigateur les donne (fr, en, pt-BR), et aucune n'est obligatoire. Une chaîne simple reste parfaitement valide et signifie « dans la langue où cela a été écrit » — ce qu'est tout enregistrement antérieur. Un lecteur dont aucune langue n'est présente reçoit ce que le fichier A, plutôt qu'un champ vide : une traduction manquante ne doit jamais transformer ce qu'un observateur a dit en ce qu'il n'a pas dit.

La langue reçue est celle du navigateur, sauf si la page en dit autre chose : un lang sur l'élément lui-même, ou sur ce qui l'entoure, est pris d'abord — un article qui déclare sa langue a déjà énoncé dans quelle langue son lecteur le lit. La liste du navigateur vient ensuite : déclarer une langue force donc un choix sans jeter les autres.

L'éditeur montre une langue, celle du lecteur, et n'écrit que dans celle-là — ouvrir le fichier dans l'autre langue et taper est donc la façon d'ajouter une traduction, et un auteur ne peut pas effacer celle d'un autre.

Ce qui a été vu#

timeline.keyframes est une liste de { t, shapes }, t en millisecondes depuis le début. Chaque forme porte un sourceId — plusieurs formes peuvent partager une chronologie (le phénomène, une flamme qui traîne, une seconde lumière) — et une shape :

{
  "kind": "oval",
  "bounds": { "x": 0, "y": 0, "width": 0, "height": 0 },
  "color": "#39ff14",
  "angle": 0,
  "transparency": 0,
  "haloScale": 1.5,
  "brightness": 0,
  "blur": 0,
  "selected": false,
  "title": "le phénomène",
  "angular": { "widthDeg": 1.2, "heightDeg": 0.4 },
  "aim": { "azimuthDeg": 353.6, "altitudeDeg": 0.6 }
}
ChampSens
kindoval, ou polygon, qui prend alors aussi points : [{ x, y }] en pixels depuis le coin haut gauche de bounds, couvrant sa largeur et sa hauteur, pour que le contour s'étire avec lui quand l'angle redimensionne la boîte
titleSon nom, affiché au survol ; une chaîne, ou une par langue
colorN'importe quelle couleur CSS
angleSon inclinaison, en radians autour de son propre centre, positive dans le sens horaire à l'écran
transparencyDe 0 opaque à 1 invisible
haloScaleLa lueur autour ; 0 pour aucune
brightnessL'éblouissement : un voile, les aigrettes du diaphragme, un cœur saturé au blanc
blurÀ quel point l'observateur a dit les contours indistincts
angularSa taille apparente en degrés — voir plus bas
aimOù il était dans le ciel de l'observateur : la direction de son centre, azimuthDeg dans le sens horaire depuis le nord vrai et altitudeDeg au-dessus de l'horizon. Pas la direction où regardait l'observateur, qui est le headingDeg et le pitchDeg de la pose — voir plus bas

aim le place, angular le dimensionne. bounds est la projection des deux sur le canevas fixe de 640×360, au cap et au champ de la pose, à travers l'instrument de l'enregistrement ; il est redérivé au chargement, si bien qu'un fichier survit à un changement de canevas, de champ, d'instrument, ou de direction du regard. Si les pixels et les angles divergent, les angles gagnent : déplacer bounds dans un fichier ne fait rien tant que aim est là. Un fichier écrit à la main peut omettre bounds entièrement.

timeline.order est l'ordre de tracé de l'arrière vers l'avant, timeline.groups les identifiants groupés. Les deux sont facultatifs.

Tout ce qu'il y a autour#

ChampSens
observerTrack{ keyframes: [{ t, pose }] } — pose porte lat, lng, elevationM (au-dessus du sol local), headingDeg, pitchDeg, rollDeg, fovDeg, et pour un appareil fNumber et focusDistanceM. Joué comme une personne bouge : exactement la pose énoncée à chaque keyframe, et entre elles un mouvement qui prend de la vitesse, la garde à travers les keyframes qui continuent de bouger, et ralentit avant une pause — deux keyframes au même endroit, ou au même cap. Un regard part et s'arrête immobile ; une marche ou un trajet déjà engagés à la première keyframe continuent. S'arrêter et repartir à pied ajoutent leur secousse, un hochement de tête amorti en une seconde et demie, qui passe dans l'image autant que l'instrument le laisse passer (à peine pour un œil, entièrement pour un appareil tenu à la main). Et un corps au repos n'est jamais tout à fait immobile : debout ou en attente, la vue oscille de quelques millimètres et dérive d'un dixième de degré, lentement, de la même façon au même instant — sauf pour un observateur que le compte rendu dit paralysé (tag paralysis). Le pitchDeg énoncé est la façon dont l'observateur regardait dans le repère de ce qui le portait : tant qu'il se déplace, le lecteur ajoute la pente de la route sous la trace (lue sur le relief, positive en montée, atténuée quand le regard s'écarte de sa route), si bien qu'une côte relève la vue et que le chip Inclinaison énonce la somme filter est ce qui était tenu devant l'instrument, un id de FILTERS comme solar-visual pour une éclipse. Il est tenu entre deux images clés, non fondu (personne ne porte la moitié de lunettes), et on l'ôte en énonçant "none".
weatherTrack{ keyframes: [{ t, weather }] } — l'état du ciel le long de l'enregistrement : précipitation, vent, orage, et les nuages en couches à hauteur réelle, chacune pouvant porter des nuages individuels placés en mètres. Chaque champ d'un weather est dans la section suivante
weatherSource{ id, name, url } du relevé d'où vient la météo. Sa présence signifie que l'enregistrement est rejoué tel qu'il a été composé et n'est jamais reconsulté. Absent : le récit de l'observateur lui-même
lightPollutionLa brillance du ciel nocturne du lieu, villes comprises : le zénith d'une nuit sans Lune en magnitudes par seconde d'arc carrée, tel qu'un Sky Quality Meter le lit ou que l'atlas mondial de la brillance artificielle du ciel nocturne le donne (son chiffre « SQM », Falchi et al. 2016, que lightpollutionmap.info affiche pour tout lieu). 22 est un ciel naturel, une banlieue vers 19, un centre-ville 17. Absent : un ciel naturel. La part des villes, ce qui reste une fois ôtés les 22 naturels, s'ajoute au ciel comme de la lumière : plus forte vers l'horizon, où l'air bas en renvoie davantage, et dessinée du blanc chaud d'une lampe à 3000 K. Elle noie la Voie lactée et la lumière zodiacale, et retire des étoiles, de l'écart entre les étoiles les plus faibles qu'un œil distingue (Crumey 2014) : environ deux magnitudes à 19. La Lune en fait désormais autant. "derived" quand la valeur vient de l'atlas, "stated" quand l'observateur l'a mesurée. L'éditeur la remplit d'après l'atlas pour une observation de 2015 ou après, en "derived" avec l'atlas nommé, et ne remplace jamais une valeur saisie à la main ; avant 2015 il ne demande rien, le ciel ayant été plus sombre que celui de l'atlas
observerMapSi la carte d'où se tenait l'observateur s'ouvre d'emblée quand l'enregistrement est joué ou édité : true ou false. Absent : le lecteur décide, ouverte pour un observateur qui s'est déplacé, fermée pour un qui est resté sur place. Une page qui intègre le lecteur a le dernier mot (son attribut show-observer-map). L'éditeur l'écrit quand la carte y est ouverte ou fermée, pour qu'un lecteur voie ce que l'auteur a laissé
soundTrack{ keyframes: [{ t, sound }] } — kind (none/hum/whistle/rumble/crackle), volume, pitchHz, et un src facultatif vers un vrai enregistrement. volume et pitchHz glissent d'une image clé à l'autre, kind et src changent à l'image clé. Un src sur un autre site doit être servi à toute origine (CORS)
referencesPhotos des lieux posées sur la scène : src (une adresse, ou une URL data: pour une photo ajoutée depuis un disque), kind (photo/panorama), registration (headingDeg, pitchDeg, rollDeg, fovDeg), opacity, credit/creditUrl, t et drawing facultatifs, from ({ lat, lng }, d'où elle a été prise : le lecteur l'efface en fondu quand l'observateur s'éloigne de ce point ; absent, elle ne s'efface jamais), et les landmarks sur lesquels elle a été recalée (id, label, picture en { u, v } depuis le coin haut gauche, scene en { azimuthDeg, altitudeDeg })
tracesCe qu'un enquêteur a dessiné sur les lieux, importé de son fichier Google Earth (KML ou KMZ) et affiché sur la scène comme étant le sien, jamais comme une partie de la reconstitution : [{ id, title, kind, points, altitude, color, source }], kind valant point, line ou polygon, points les sommets en [{ lat, lng, altM }] tels que le fichier les portait, altitude la façon de lire altM (ground, par défaut, relative au sol sous chaque point, ou absolute au-dessus du niveau de la mer), color un #rrggbb et source à qui il appartient
instrument, exposureSecondsÀ travers quoi l'observation a été faite, et combien de temps l'obturateur est resté ouvert. Absent : l'œil nu. instrument vaut eye, rectilinear-lens (un appareil de modèle inconnu), roamer-1-120, instamatic-126, slr-35mm-50, slr-35mm-zoom, phone-landscape, phone-portrait ; exposureSeconds est une valeur pour tout l'enregistrement, tenue dans la plage de l'appareil
isoLa sensibilité du film ou du capteur de la photo, quand on la connaît : 400 pour un film 400 ISO. Absent : celle de l'appareil (100 pour le négatif couleur d'un reflex, 64 pour celui d'un Instamatic). La photo d'un appareil ne répond pas comme un œil : un film ne s'adapte pas au ciel, il reçoit une exposition (la lumière, fois le temps de pose, divisée par le carré de l'ouverture) et y répond selon sa propre courbe (douce pour un négatif, plus raide pour une diapositive, droite puis arrêtée net au blanc pour un capteur). Une pose de nuit sort donc avec un ciel noir, et ce qui y brillait ressort
swayCombien le corps qui tient l'instrument fait bouger la vue hors de la marche : 1 pour une personne debout ou assise, 0 pour un appareil sur trépied, entre les deux ou au-delà pour moins ou plus. Absent, c'est 1 — sauf pour un observateur que le compte rendu dit paralysé (tag paralysis), pour qui c'est 0, et pour une pose de plus d'une demi-seconde, qu'aucune main ne tient immobile : c'est un trépied, et 0 aussi
vehicleLe véhicule où se trouvait l'observateur, quand le décor ne le dessine pas : { kind, windowsOpen, noise }, kind valant car, van, truck, motorcycle ou generic. Entendu de l'intérieur : son moteur suit le trajet de l'observateur — le rapport selon la vitesse, le régime selon le rapport, l'effort selon qu'il accélère ou ralentit — avec le roulement et le vent, étouffés par un habitacle fermé, entrant par des vitres ouvertes ; noise est son niveau face à un véhicule ordinaire de son genre (1 par défaut). C'est aussi ce qui garde actif le bouton de son du lecteur quand le fichier n'a pas de soundTrack : le bouton répond de tout ce que joue la scène — ce moteur, un engine du décor, la pluie et le vent — et pas seulement de la piste
decorLe décor, à une vraie distance eastM/northM de l'observateur : bâtiments (avec floors, windows), arbres, buissons, lampadaires, véhicules, ponts, lignes aériennes, autres observateurs, aéronefs — éventuellement avec une track et des lights dont le pattern porte une vraie cadence d'éclats. Voir ci-dessous

Un objet du décor s'énonce en mètres, comme tout ce qui n'est pas le phénomène :

ChampSens
eastM, northM, headingDegOù il se tient par rapport à l'observateur, et vers où regarde son avant, en degrés depuis le nord vrai dans le sens horaire
sizeM{ widthM, lengthM, heightM } selon ses propres axes, la longueur étant le sens où il regarde. Chaque axe est facultatif : celui que personne n'a mesuré garde la proportion de la forme intégrée
modelUn vrai modèle 3D à la place de la forme intégrée : une entrée du catalogue par id, ou un fichier glTF/GLB à url (qui l'emporte, doit être lisible depuis toute origine, et exige alors son credit ; une adresse relative se lit depuis le fichier qui l'énonce). Il ne décide jamais de la taille : il est mis à l'échelle, proportions gardées, sur le premier axe mesuré parmi longueur, hauteur et largeur, ou sur la taille réelle que lui donne le catalogue. Vu de l'intérieur, et chaque fois que le modèle ne peut être obtenu, c'est la forme intégrée qui est dessinée. Un observer ou une entity qui n'en nomme aucun n'est jamais dessiné en forme intégrée : c'est une des personnes réalistes du catalogue, choisie par son id (un enfant, ou un être qu'une déposition décrit, nomme son propre modèle) headingOffsetDeg tourne le modèle chargé autour de son axe vertical pour que son nez pointe où la scène l'attend (0 regarde le nord pour un cap de 0) ; une entrée du catalogue apporte le sien. credit est { title, author, license, sourceUrl } : license telle que son auteur l'énonce ("CC BY 4.0") et sourceUrl d'où il vient, pour que l'affirmation soit vérifiable.
bridgePour un "bridge" : comment il est construit. sizeM.lengthM est toute sa longueur le long de la route, remblais compris, widthM la largeur du tablier et heightM la hauteur de la chaussée sur le tablier au-dessus du sol ; spanM est la portée libre sous le tablier, la route courant de chaque côté sur un remblai de terre qui descend jusqu'au sol ; deckThicknessM l'épaisseur de la dalle (1,2 par défaut) ; railing { heightM, postSpacingM, rails } le garde-corps des deux rives, poteaux et lisses dont les ouvertures sont des rectangles (1,05 m, 1,5 m et 2 lisses par défaut). Dessiné à ces cotes, jamais étiré
wirePour un "wire" (une ligne électrique ou téléphonique) : sizeM.lengthM est la portée entre ses poteaux, le long de son headingDeg, et heightM la hauteur du fil le plus bas ; strands [{ heightM, acrossM }] en suspend plusieurs (des fils superposés partagent un acrossM, ceux d'une traverse diffèrent) ; poles vaut both (par défaut), start ou end (l'extrémité dont le cap s'éloigne ou vers laquelle il pointe : l'autre est ancrée sur un bâtiment) ou none ; diameterM (8 mm par défaut) et poleHeightM (un demi-mètre au-dessus du fil le plus haut). Droite, sans flèche, et dessinée à ces mesures, jamais étirée
track[{ t, eastM, northM, altitudeM, headingDeg }] quand il se déplace, altitudeM au-dessus de l'observateur. La position est interpolée entre les images clés ; le cap est tenu de l'une à la suivante
lightsSes feux : id, offsetM { x, y, z } depuis son centre (droite, haut, avant), color, intensity (1 pour un feu de navigation ordinaire) et un pattern : { "kind": "steady" }, ou { "kind": "flash", perMinute, dutyCycle, phase }, la cadence telle que l'énoncent les règlements, la part allumée de chaque cycle (environ 0,5 pour un clignotant à filament, 0,01 pour un stroboscope) et un décalage de 0 à 1 entre feux. L'éditeur les remplit depuis des modèles : avion de ligne, hélicoptère, phares de voiture, feux de détresse, gyrophares, lampadaire
engineUn véhicule qu'on entend tourner : { kind, noise }, comme vehicle plus haut. Son moteur suit sa propre track, entendu depuis l'observateur, plus faible et plus sourd avec la distance
aircraftSoundUn aéronef (kind aircraft) qu'on entend en vol, c'est-à-dire quand sa track quitte le sol : le genre de bruit qu'il fait, un type d'aéronef (airliner-narrow par défaut, airliner-wide, regional-jet, helicopter-light, light-piston…) ou silent pour un appareil qui n'en fait pas. Ce que dit son modèle s'applique quand le champ est absent (les maquettes d'un phénomène sont silencieuses). Il s'entend comme les aéronefs d'un relevé de trafic : plus faible et plus sourd avec la distance, en retard du temps que met le son à venir (environ trois secondes par kilomètre) donc entendu là où il était, plus aigu quand il approche et plus grave quand il s'éloigne, et masqué par le bruit du lieu
occludesSourceIdsLes phénomènes devant lesquels l'observateur a dit qu'il se tenait — voir les règles plus bas
facadeGenre building seulement : { color?, plain? }. color est le mur, "#rrggbb" ; sauf si plain vaut true, des fenêtres sont dessinées à chaque étage et une porte au rez-de-chaussée de la face avant. Dessinée à la sizeM énoncée (les trois côtés doivent l'être), jamais étirée, et pas pour un bâtiment qui a un observateur dedans. L'éditeur prend la couleur dans la matière que la carte énonce pour les murs (pierre, brique, béton, parpaing, bois), ou un enduit là où elle n'en énonce pas. Absent : la simple boîte.
roofGenre building seulement : { shape, riseM, color?, ridge? }. shape vaut "flat" (la boîte), "gable" (deux pentes jusqu'à un faîte le long du grand côté, ou de la profondeur avec ridge: "depth") ou "hip" (quatre pentes) ; riseM est la hauteur du faîte au-dessus de l'égout, donc les murs font sizeM.heightM moins cela ; color est le toit vu d'en haut, "#rrggbb". L'éditeur les lit dans le laser et la photo aérienne du relevé. Absent : toit plat de la couleur des murs.
originLe relevé dont cet objet a été tiré, par l'id de son fournisseur ("ign-lidar-topo"), quand l'éditeur l'a pris du relevé du lieu et que l'auteur ne l'a pas placé à la main : un arbre, un bâtiment, un pont ou une portée de ligne. Choisir un autre relevé, ou aucun, ou un autre lieu, remplace ou retire ce qui porte une origin, et jamais ce qui n'en porte pas
surveyedOnLe jour (AAAA-MM-JJ) du relevé le plus récent dont cet objet est tiré, quand il vient d'un relevé (voir origin) : l'éditeur avertit quand il est postérieur à l'observation.
lit, litKeyframesSi la lampe d'un lampadaire ou les phares d'un véhicule sont allumés. litKeyframes est [{ t, lit }], trié par t, pour un éclairage allumé ou éteint pendant l'enregistrement ; sans lui, lit vaut pour toute la durée. Ignoré pour un bâtiment, un arbre ou un observateur
observerSide, observerFacing, observerKeyframes, occupiedFloorL'observateur à l'intérieur de l'objet, pour un building ou un véhicule (un seul objet à la fois le contient). observerSide dit où il est : front, behind, left, right, front-left, front-right, behind-left ou behind-right, l'occupant d'un véhicule étant à l'une de ses quatre portières. observerFacing est la vitre par laquelle il regarde quand ce n'est pas celle de sa place : un conducteur est assis en front-left et regarde par le pare-brise, front. observerKeyframes, [{ t, side, facing }], dit où il est assis au fil du temps, chacune tenue jusqu'à la suivante, et une image clé sans side veut dire dehors à partir de là, comme un conducteur qui descend. occupiedFloor est l'étage d'un bâtiment où il se trouve, de 0 (rez-de-chaussée) à floors
modelParametersLes réglages du modèle dont l'objet est dessiné, par la clé sous laquelle l'entrée du catalogue publie chacun : { "costumeColor": "#5a6b3a" } pour les vêtements d'une personne, foliageColor pour un arbre, hullColor pour un engin, gearUp pour un avion de ligne en vol. Un modèle apporte les siens (l'éditeur dessine un champ pour chacun) ; un objet dessiné comme une forme intégrée n'en a pas, il est peint par color
sightingUrlPour un observer : l'adresse de l'enregistrement propre à cet observateur, quand elle est connue, afin que le menu de la scène puisse proposer de voir son témoignage

Ce que c'était : les interprétations#

Un enregistrement énonce des angles, et un corps en mètres ne fait jamais partie de ce qui a été vu. C'est une affirmation à son sujet, et elle se met à l'épreuve en la posant dans la scène et en la regardant depuis l'endroit où se tenait l'observateur : elle projette son ombre, le sol peut la cacher, et son contour est confronté à chaque instant à ce que l'observateur a dit. Une interprétation s'affiche seule, comme le monde qu'elle affirme ; quand on demande la comparaison (le bouton ◌, ou compare-account sur <rr0-sighting>), le lecteur dessine à côté tout ce que l'observateur a vu, en contours pointillés, et indique l'écart de direction et combien de fois plus large et plus haut chaque corps paraît, en rouge quand un observateur n'aurait pas pu se tromper d'autant.

La lecture de l'observateur lui-même va dans l'enregistrement, en interpretation. Celle d'un autre n'est pas dans le compte rendu : c'est une autre observation, listée dans le dossier (voir plus bas). Un compte rendu dont l'observateur a dit ce que c'était se dessine en volume, comme il l'a dit ; celui qui ne dit rien en mètres se dessine avec les angles qu'il énonce. Le lecteur le propose, ainsi que chaque interprétation d'analyste, une à la fois.

{
  "interpretation": {
    "title": "Un engin posé sur ses pieds",
    "bodies": [{
      "id": "craft",
      "explains": ["ufo-1"],
      "model": { "id": "ellipsoid" },
      "track": [
        { "t": 52000, "eastM": -571.6, "northM": -965.5, "onGround": true,
          "sizeM": { "widthM": 3.36, "lengthM": 3.36, "heightM": 1.73 },
          "appearance": { "color": "#e8e6df", "albedo": 0.7 } },
        { "t": 83000, "azimuthDeg": 195.9, "altitudeDeg": 4.1, "distanceM": 44 }
      ]
    }]
  }
}
ChampSens
explainsLes sourceId des phénomènes que ce corps prétend être
modelUne forme construite ici (ellipsoid, sphere, disc, cylinder, cone, box, torus, figure), un modèle du catalogue par son id, ou un fichier glTF à url avec son credit ; une url relative se lit depuis le fichier qui la donne, pas depuis la page. Étiré à sizeM dans tous les cas headingOffsetDeg et credit ({ title, author, license, sourceUrl }) sont ceux du modèle d'un objet du décor.
trackOù il est et à quoi il ressemble à chaque t. Une position s'énonce soit dans le monde (eastM/northM depuis l'endroit où se tenait l'observateur au début, comme le décor, avec onGround ou altitudeAboveGroundM), soit depuis l'observateur à cet instant (azimuthDeg, altitudeDeg, distanceM). Un corps onGround est posé sur le relief ; une direction sans distance rencontre alors le sol là où cette ligne le rencontre. sizeM, attitude (headingDeg, pitchDeg, rollDeg) et appearance (color, albedo, luminanceCdM2, transparency de 0 à 1, haloScale en multiple de l'éblouissement de sa lumière propre) valent jusqu'à ce qu'une keyframe suivante les énonce à nouveau, et se mélangent entre deux keyframes. present: false retire le corps de la scène à partir de cette keyframe, et present: true l'y ramène. Une flame (lengthM, widthM, color à la sortie, tipColor, luminanceCdM2) s'allume à la keyframe qui l'énonce, sort du nœud du modèle nommé exhaust (ou de celui que nomme son node), éclaire ce qui l'entoure, soulève de la poussière là où elle touche le sol si raisesDust le dit, et s'éteint avec une luminanceCdM2 de 0
motionsDans une keyframe : où en est chacun des mouvements propres de son modèle, par le nom du mouvement — les animations du fichier glTF. 0 est le début d'un mouvement, 1 sa fin, et un mouvement qui se répète continue au-delà de 1 : { "legs-turn": 7 }, c'est sept tours. Le modèle dit ce qui bouge et comment ; la piste dit quand. Chaque mouvement se mélange entre les keyframes qui l'énoncent, quelles que soient les keyframes qui déplacent le corps entre-temps, se maintient après la dernière et vaut 0 avant la première. Le départ de Valensole s'écrit ainsi : { "t": 246000, "motions": { "pivot-retract": 0 } }, { "t": 248000, "motions": { "pivot-retract": 1, "legs-turn": 0 } }, … { "t": 262000, "motions": { "legs-turn": 7 } }
lightsDans une keyframe : la luminance, en cd/m², de chacun des feux propres de son modèle, par le nom du matériau du feu dans le fichier glTF, pour qu'un même corps porte des feux qui font chacun autre chose, un blanc fixe à chaque bout et un rouge qui clignote entre les deux. Le modèle dit où est chaque feu, sa taille et sa couleur ; la piste dit quelle luminance et quand. Chaque feu se mélange entre les keyframes qui le nomment et se maintient après la dernière : une bascule, ce sont donc deux keyframes à une milliseconde d'écart. Un feu qu'aucune keyframe ne nomme brille à sa part de appearance.luminanceCdM2. Un feu trop petit pour se voir se voit par son éblouissement, et ce qui se trouve entre lui et l'œil, la coque du corps lui-même ou un pont, le cache. Le feu rouge de Silly-le-Long : { "t": 499, "lights": { "front-red": 1500 } }, { "t": 500, "lights": { "front-red": 0 } }
outlineNodeLe nœud du modèle qui est ce que l'observateur a dessiné ("hull" pour un engin dont les pieds ne figurent pas dans le dessin) : ce sur quoi son contour est mesuré
smokeSur l'interprétation elle-même : ce qu'elle met à brûler au sol, en { eastM, northM, fromT, untilT? }, vu par sa fumée qu'emporte le vent de l'enregistrement halfLifeS dit à quelle vitesse elle retombe, en secondes pour perdre la moitié de son épaisseur (20 par défaut) : un feu de broussailles flambe puis couve. Elle ne s'arrête jamais tout à fait avant untilT.
reentriesSur l'interprétation elle-même : les rentrées atmosphériques qu'elle dit avoir été vues, un satellite ou un étage de fusée se désagrégeant en morceaux qui brûlent. Pas des corps : une rentrée brûle entre 70 et 100 km d'altitude et se voit à des centaines de kilomètres, elle est donc placée sur la Terre et vue à travers sa courbure depuis l'endroit où se tenait l'observateur. Sa track donne le point de tête à des instants de l'enregistrement, { t, lat, lng, altitudeKm }, reliés par des grands cercles ; chacun de ses fragments suit le même chemin lagS secondes derrière, se voit de fromT jusqu'à s'éteindre à untilT, brille de sa absoluteMagnitude (à 100 km, comme pour un bolide) ramenée à sa distance réelle, de sa couleur color, avec une traînée des trainS dernières secondes de son chemin. Sa lumière est la sienne : elle se voit que le Soleil l'atteigne ou non. object nomme ce qui est retombé (name, cosparId, norad). Rien n'est propagé depuis des éléments orbitaux, faux de plusieurs minutes sur la dernière orbite : le chemin est ce que les sources établissent, avec sa provenance
launchesSur l'interprétation elle-même : les lancements de fusée dont elle dit que l'échappement a été vu, éclairé par un Soleil couché pour le sol mais pas pour le panache, la « méduse spatiale ». Placés sur la Terre comme une rentrée : leur track donne l'étage à des instants de l'enregistrement, { t, lat, lng, altitudeKm } (elle peut commencer avant l'enregistrement), et burnFromT et burnUntilT les secondes où le moteur a brûlé. Le panache est une file de bouffées lâchées le long de ce chemin, chacune s'étalant avec l'âge ; ce qui se voit de chacune est la lumière du Soleil qu'elle diffuse vers l'observateur. L'ombre de la Terre (où le Soleil éclaire ou non à la hauteur de la bouffée, et combien d'air sa lumière a frôlé, ce qui la rougit ou la bleuit), l'angle de diffusion et l'étalement sont calculés depuis le vrai Soleil à la vraie date : rien n'en est déclaré. Un plume facultatif remplace les valeurs par défaut : exhaustKgPerS (273, un Merlin Vacuum), condensedShare (0,1, le seul nombre que personne n'a mesuré), particleRadiusUm, expansionKmPerS, initialRadiusKm, lifetimeS, et pour la collerette (le gaz fraîchement éjecté, large et vite disparu, à côté de la traînée étroite qui reste) collarShare (0,85), collarExpansionKmPerS (2,5), collarLifetimeS (20). vehicle nomme ce qui a volé et, dans engine, le moteur dont c'est l'échappement : thrustKN et specificImpulseS (dont se déduisent le débit d'échappement et sa vitesse, donc la largeur de la collerette) et propellant (rp1-lox, methane-lox, hydrogen-lox, hypergolic ou solid, qui dit quelle part devient des particules et de quelle taille). Ce que dit plume l'emporte sur ce que dit le moteur. Le panache a besoin de la date de l'enregistrement : sans elle il n'y a pas de Soleil pour l'éclairer vehicle.mission nomme la mission qu'il effectuait ("Starlink Group 10-49").

Une autre lecture : une interprétation est une autre observation#

La lecture qu'un autre fait d'un compte rendu (celle d'un analyste, d'un enquêteur, une comparaison faite pour la mettre à l'épreuve) n'est pas dans le compte rendu : c'est une autre observation, celle qui a eu lieu telle que son auteur la tient. Elle est donc listée dans le dossier comme l'original, en événement de type sighting, marqué comme lecture par interpretationOf, et a un enregistrement à elle à url :

{
  "id": "McMinnville1950",
  "events": [
    { "type": "event", "eventType": "sighting", "id": "trent", "title": "Paul Trent", "url": "observer-mcminnville.json" },
    { "type": "event", "eventType": "sighting",
      "interpretationOf": "trent",
      "time": "2013-06",
      "by": [{ "people": "CousynAntoine" }, { "people": "LouangeFrancois" }],
      "title": "A model on a thread under the line",
      "url": "interpretation-mcminnville-2.json" }
  ]
}
ChampSens
interpretationOfL'id de l'événement du dossier dont c'est une lecture ("trent"), ou une liste d'ids quand une lecture sert plusieurs comptes rendus (les photographies et un gros plan). Ce qui la distingue d'un compte rendu : les événements sans ce champ sont les observateurs du dossier
timeQuand l'interprétation a été élaborée, comme RR0 écrit un temps ("2013-06") : pas quand l'observation a eu lieu
byQui l'avance : { "people": id } ou { "org": id }, qui désignent une entrée qui vit ailleurs (sur RR0, un répertoire de personnes ou d'organisations), ou une personne décrite en valeur. Absent pour une comparaison que personne n'avance
titleComment la lecture s'appelle dans le menu du lecteur et le sélecteur de l'éditeur : quelques mots, une chaîne ou une par langue
urlSon enregistrement, lu relativement à l'adresse du fichier du dossier, comme celui d'un observateur

L'enregistrement à url est un enregistrement comme les autres. Il partage le lieu, l'heure et la pose de l'observateur du compte rendu qu'il lit, si bien qu'un corps placé depuis l'observateur, ou en mètres depuis l'endroit où il se tenait, veut dire la même chose dans les deux ; il ne dessine aucune forme (une timeline vide) ; et il porte les corps dans son propre interpretation, décrit plus haut. Les explains d'un corps désignent les formes du compte rendu.

{
  "version": 1,
  "id": "1950-05-11-TrentPaul-interpretation-2",
  "time": { "year": 1950, "month": 5, "day": 11, "hour": 19, "minute": 45 },
  "utcOffsetHours": -7,
  "place": [{ "value": { "lat": 45.104167, "lng": -123.330556 } }],
  "observerTrack": { "keyframes": [{ "t": 0, "pose": { "lat": 45.104167, "lng": -123.330556, "headingDeg": 41.3, "pitchDeg": 14.85, "fovDeg": 33.4 } }] },
  "tags": ["interpretation"],
  "timeline": { "keyframes": [], "order": [], "groups": [] },
  "interpretation": {
    "title": "A model on a thread under the line",
    "bodies": [{
      "id": "model",
      "explains": ["ufo-1"],
      "model": { "id": "disc" },
      "track": [
        { "t": 0, "eastM": -52, "northM": 118, "altitudeAboveGroundM": 7.5,
          "sizeM": { "widthM": 0.3, "lengthM": 0.3, "heightM": 0.1 } }
      ]
    }]
  }
}

Le lecteur liste les observateurs du dossier d'après les événements sans interpretationOf et propose chaque lecture à côté du compte rendu qu'elle désigne, une à la fois (le bouton ◌ la mesure contre le compte rendu). Un enregistrement seul n'a d'autre lecture que son propre interpretation. L'ancienne forme, un événement de type interpretation qui désigne l'enregistrement dans sighting avec ses corps sur place ou dans un fichier à url, est encore lue. L'éditeur ouvre un dossier : son sélecteur au-dessus du rendu liste les comptes rendus et les lectures, chacun s'ouvrant comme l'enregistrement qu'il est, avec un bouton pour ajouter une lecture (un nouvel enregistrement qui partage le lieu, l'heure et la pose du compte rendu, et un événement pour lui), un pour la supprimer, et un pour exporter le dossier et chaque enregistrement ajouté ou modifié en zip. Essayez avec case-mcminnville.json (le jouer, l'éditer).

La météo, et ses nuages#

Un point weather énonce l'état du ciel à un instant de l'horloge de l'enregistrement ; entre deux points chaque nombre est interpolé, le type de précipitation et l'orage sont maintenus. Il porte :

ChampSens
cloudLayersLes nuages, en liste de couches — voir plus bas. Absent : ce sont les anciens champs des lignes voisines qui les décrivent, adaptés en une couche d'eau et un voile de cirrus ; une liste vide : un ciel dégagé que quelqu'un a regardé
cloudCover, lowerCloudCover, highCloudCoverFractions de ciel (0–1) : le total, les couches d'eau seules, le voile glacé seul. Écrits par les enregistrements d'avant les couches, et encore tenus à jour par l'éditeur comme résumé de celles-ci
cloudBaseM, cloudDarknessLa base unique de la même époque, en mètres au-dessus du sol de référence, et une teinte unique (0 blanc, 1 très sombre)
iceCrystalAlignment0–1, la régularité de la chute des cristaux de glace — ce qui fait d'un anneau nu des parhélies, des arcs et un pilier. Aucun relevé ne le mesure ; une couche de cirrus porte le sien
relativeHumidity0–1, près du sol. Elle décide de la blancheur du ciel clair : la brume gonfle d'eau à mesure que l'air approche de la saturation. Un relevé consulté la porte (tirée de la température et du point de rosée d'ERA5) ; absente, une brume ordinaire
precipitationType, precipitationIntensitynone/rain/snow/hail, et 0–1. Énoncée à une keyframe, jouée comme elle tombe : une averse commence à la keyframe qui la déclenche par ses premières gouttes, et n'atteint l'intensité énoncée pas plus vite qu'une vraie pluie (de rien au plus fort en vingt secondes) ; elle s'arrête de même. Un changement que les keyframes étalent davantage est suivi tel quel precipitationAmount (0–1, absent veut dire tout) dit quelle part de cette précipitation tombe déjà.
windDirectionDeg, windSpeedLe vent général : le cap VERS lequel il souffle, dans le sens horaire depuis le nord, et des mètres par seconde. C'est lui qui porte les nuages — depuis l'instant zéro, si bien qu'une recherche et une relecture donnent le même ciel
stormÉclairs et tonnerre, au bon retard

Chaque couche de cloudLayers est une nappe de nuages à une hauteur réelle, et reste elle-même d'un point à l'autre :

ChampSens
idStable d'un point à l'autre — les couches s'apparient par lui, jamais par leur rang dans la liste. Une couche présente à un point et absente au suivant s'estompe ; les réordonner ne change rien
typecumulus, stratus, stratocumulus, cirrus ou unknown. Il décide de la forme des sommets et de la finesse du voile ; un cirrus est aussi celui qui réfracte les halos. Il bascule au point, il n'est pas interpolé
baseM, thicknessMEn mètres. La base est au-dessus du sol de RÉFÉRENCE de l'enregistrement, pas au-dessus d'un observateur qui grimpe ; un observateur plus haut que la base est dans la nappe ou au-dessus, et le ciel est dessiné en conséquence
coverage0–1, et cela veut dire ce que cela dit : la fraction du ciel que cette couche couvre, quelle que soit la taille de ses nuages
sizeMLa largeur caractéristique d'un nuage, en mètres. Indépendante de la couverture : une même fraction de ciel peut être beaucoup de petits nuages ou quelques gros
density0–2, l'opacité de la matière nuageuse ; 0 est transparent. Indépendante de la couverture elle aussi
darkness0 blanc à 1 très sombre. Absent : le cloudDarkness du point
seedLequel des motifs, parmi les innombrables que les mêmes nombres peuvent dessiner. Absent : un motif dérivé de l'id, ce qui est la raison pour laquelle l'id ne doit pas changer
windDirectionDeg, windSpeedLe vent propre à cette couche, lorsqu'il diffère du vent général — c'est le cas de la couche haute d'ordinaire. Absent : le vent général
iceCrystalAlignmentPour un cirrus seulement
instancesLes nuages individuels de cette couche — voir plus bas

Un nuage individuel dans instances est un nuage de sa couche que le fichier place exactement, parce que le récit le fait : celui derrière lequel le phénomène est passé, celui qui était là et nulle part ailleurs. Il est dessiné comme un nuage de sa couche — même texture, même seuil — et ne se distingue de ses voisins que par sa position et sa taille ; il est là même quand la coverage de la couche est nulle. Il suit le vent de la couche comme les autres, et il masque un phénomène devant lequel il passe.

ChampSens
idStable d'un point à l'autre, même règle que pour une couche
eastM, northMOù était son centre à l'instant zéro, en mètres depuis le point de départ de l'observateur. Le vent l'emporte de là
baseM, thicknessMSa propre base et sa propre hauteur, en mètres — un nuage peut être plus bas ou plus haut que sa nappe
widthM, depthM, rotationDegSon emprise, en mètres, et le cap vers lequel cette emprise est tournée
density, darknessLes siens ; une obscurité absente est celle de la couche
{
  "weather": {
    "cloudLayers": [
      {
        "id": "low", "type": "cumulus",
        "baseM": 1500, "thicknessM": 800,
        "coverage": 0.55, "sizeM": 1400, "density": 1, "darkness": 0.15,
        "instances": [
          { "id": "the-one", "eastM": 0, "northM": 4200,
            "baseM": 1500, "thicknessM": 800,
            "widthM": 1900, "depthM": 1300, "rotationDeg": 12, "density": 1 }
        ]
      },
      { "id": "high", "type": "cirrus", "baseM": 8000, "thicknessM": 400,
        "coverage": 0.2, "sizeM": 2200, "density": 0.35, "iceCrystalAlignment": 0.65 }
    ],
    "precipitationType": "none", "precipitationIntensity": 0,
    "windDirectionDeg": 90, "windSpeed": 5, "storm": false
  }
}

Un enregistrement dont la météo a été relevée (il a un weatherSource) garde la réponse du relevé, pas un lien vers lui : ERA5 donne les bandes basse, moyenne et haute en trois couches nommées record-low, record-mid et record-high, la base basse estimée depuis l'écart entre température et point de rosée, les deux autres à 3 500 m et 8 000 m. Leur type est unknown (cirrus pour la haute), leur taille et leur densité sont des hypothèses de dessin : une réanalyse sait quelle part de chaque bande était couverte, pas à quoi les nuages ressemblaient. Redemandez le relevé depuis l'éditeur et les couches sont réécrites ; modifiez une couche à la main et l'enregistrement devient celui de l'auteur, la source retirée.

D'où vient chaque valeur#

Toute valeur d'un enregistrement peut s'écrire nue, ou enveloppée de sa provenance :

{
  "durationSeconds": {
    "value": 15,
    "basis": "derived",
    "rationale": "13 à 18 s dans la synthèse de l'enquêteur ; le milieu retenu"
  }
}

basis vaut stated (l'observateur l'a dit, et c'est ce que signifie une valeur nue), derived (déduit de ce qu'il a dit et de quelque chose de vérifiable : la largeur d'une route, une carte, un dessin mesuré ; rationale donne le calcul) ou assumed (choisi pour que la reconstitution ait une valeur, sur rien que l'observateur ait dit). La liste des valeurs assumed est la liste de ce qu'il faut retourner demander à l'observateur ou au dossier : c'est pourquoi elle vaut d'être écrite même quand rien d'autre ne l'est.

Vérifier un fichier#

Le format est aussi publié en JSON Schema, engendré depuis les mêmes types que le lecteur : toutes les clés qu'il connaît, ce que chacune peut contenir, et les mots qu'accepte une liste fermée. Une clé mal orthographiée ou une valeur inconnue y échoue. Il ne dit rien de ce qui peut être omis, question de sens à laquelle répond cette page. Pour voir le résultat, ouvrez le fichier dans le lecteur, depuis un lien, ou depuis votre disque avec les images et modèles qu'il nomme. Le lecteur le vérifie de la même façon au chargement, et dit derrière un ⚠ sur l'image ce qu'il n'a pas pu jouer comme écrit : une clé que rien ne lit, un mot hors de sa liste, et ce qu'il a dû inventer parce que la première keyframe d'une forme l'omettait (un champ tenu depuis la keyframe précédente relève de la règle ci-dessus, pas d'un problème).

Un fichier entier#

Le plus petit enregistrement qui énonce encore quelque chose — un ovale silencieux traversant le ciel en douze secondes, à une date réelle et en un lieu réel. Tout le reste du format est facultatif, et tout ce qui suit sert à quelque chose :

{
  "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
            }
          }
        ]
      }
    ]
  },
  "observerTrack": {
    "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 } }] }
}

Pour le modifier et le voir jouer, collez-le dans l'éditeur, qui complète sur chaque clé du format, propose les mots que chacune accepte, et dit ce que le modèle en dit.

C'est /demo-data/example-minimal.json sur ce site : vous pouvez le récupérer, et le jouer avant d'y toucher. Remarquez que angular et bounds y figurent tous deux : l'angle est ce que le fichier SIGNIFIE, et les pixels en sont redérivés au chargement — écrivez l'angle, et laissez corriger une mauvaise estimation des pixels.

De plus gros, à lire#

Chaque démo de ce site est un simple fichier que vous pouvez ouvrir. Ces quatre-là valent la lecture pour voir comment un vrai enregistrement est bâti :

FichierCe qu'il faut y regarder
observer-chiles.jsonUn vrai dossier : un observateur, un identifiant de dossier partagé avec un second enregistrement, dix keyframes, un weatherTrack relevé avec son weatherSource
sky-test-halos.jsonAucun phénomène — un ciel réglé par un weatherTrack dont les images clés font varier l'alignement des cristaux, la couverture de cirrus et une couche de cumulus, vu par un observerTrack qui balaie le cortège puis s'arrête
sky-test-clouds.jsonTrois couches nuageuses avec altitude, épaisseur, taille, densité et vent en mètres, évoluant sur la timeline météo — et dans la première une entrée instances : un nuage du champ, placé et dimensionné en mètres, qui grossit et s'assombrit sur les deux minutes
sky-test-aircraft.jsonUn instrument, un exposureSeconds et un iso, et un décor d'aéronef avec sa track et neuf lights à leurs cadences réelles, phares d'atterrissage compris
sky-test-reentry.jsonAucun phénomène : une interpretation sans corps et avec une reentries, le lanceur de Zond 4 se désagrégeant au-dessus du Kentucky en 1968, son chemin dérivé, son horaire, ses hauteurs et son éclat supposés, chaque valeur avec sa provenance
sky-test-launch-plume.jsonAucun phénomène : une interpretation sans corps et avec une launches, l'échappement de Starlink Groupe 10-49 (Falcon 9, 25 août 2026, 5 h 33 EDT) éclairé dans le crépuscule et vu de Hoboken (New Jersey), le chemin de l'étage supposé avec sa provenance, l'ombre, l'étalement et la lumière calculés
instrument-instamatic.jsonLa même observation que observer-socorro.json, à un champ près. Comparez les deux

Quatre règles qui décident du sens d'un fichier#

  • Les champs discrets sont tenus, les continus sont interpolés. Une forme absente d'un keyframe ultérieur reste dans son état, et de même tout champ qu'un keyframe omet dans une forme qu'il énonce : un keyframe qui ne donne qu'un nouvel aim déplace la forme et garde tout le reste (énoncer bounds sans aim ni angular est lu comme la déplacer par ses pixels) ; une forme dont le premier keyframe est à cinq secondes est déjà peinte, dans cet état, dès zéro. Pour qu'une chose cesse d'être visible, posez-lui un keyframe à transparency: 1.
  • Des angles, rien d'autre. Aucune taille ni distance réelle n'est stockée où que ce soit. Les mètres sont déduits, en inégalités, de ce que le phénomène a été déclaré passer derrière ou devant (decor[].occludesSourceIds).
  • L'énoncé l'emporte sur le déduit. occludesSourceIds contient des affirmations de l'observateur. Rien dans ce format ne peut les déduire : il décrit une apparence dans un champ de vision, pas une position dans l'espace.
  • Absent n'est pas zéro. Pas de piste sonore signifie que personne n'a posé la question ; kind: "none" signifie que l'observateur a déclaré n'avoir rien entendu. La même distinction traverse la météo et les nuages de glace.

Cette page est la référence du format. Le raisonnement derrière chaque champ est dans les commentaires de documentation de son type, que les extraits ci-dessus proposent à la complétion, et dans le code source.