@rr0/ufoathome 0.20.0 → 0.21.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -6
- package/dist-embed/{UfoRecorderMessages_fr-DeL1OXU3.js → UfoRecorderMessages_fr-Dvf46rNk.js} +1 -1
- package/dist-embed/rr0-ufo-recorder.mjs +228 -193
- package/dist-embed-eyewitness/rr0-eyewitness.mjs +229 -195
- package/dist-embed-scene/rr0-scene.mjs +226 -192
- package/dist-embed-ufo/rr0-ufo.mjs +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -332,6 +332,7 @@ interface SightingRecordingJson {
|
|
|
332
332
|
weatherTrack?: { keyframes: Array<{ t: number, weather: Weather }> }
|
|
333
333
|
weather?: Weather // legacy static fallback for recordings predating weatherTrack
|
|
334
334
|
weatherSource?: { id: string, name: string, url: string } // the meteorological record weatherTrack was looked up from — see Weather is looked up, not remembered. Absent = the witness's own account
|
|
335
|
+
instrument?: "eye" | "rectilinear-lens" // what it was observed THROUGH — see Instrument. Absent = the naked eye
|
|
335
336
|
soundTrack?: { keyframes: Array<{ t: number, sound: { kind: "none" | "hum" | "whistle" | "rumble" | "crackle", volume: number, pitchHz: number, src?: string } }> } // what the witness heard — see What it sounded like
|
|
336
337
|
decor?: DecorObject[] // buildings, trees, streetlights, vehicles, other witnesses — see src/engine/model/Decor.ts
|
|
337
338
|
}
|
|
@@ -521,16 +522,47 @@ of the windshield, or two full Moons. "About thirty meters long" is a conclusion
|
|
|
521
522
|
could not perceive either, and the two errors multiply. So a recording stores `angular` — how wide and how tall the
|
|
522
523
|
object *looked*, in degrees — and stores no real size and no real distance anywhere.
|
|
523
524
|
|
|
524
|
-
`bounds` is that angle projected onto the fixed 640x360 canvas at the pose's own field of view
|
|
525
|
-
editing gesture, hit-test and renderer keeps working
|
|
526
|
-
(`src/engine/persistence/SightingShapes.ts`) re-derives `bounds`
|
|
527
|
-
save, so a file survives a change of canvas
|
|
525
|
+
`bounds` is that angle projected onto the fixed 640x360 canvas at the pose's own field of view **and through the
|
|
526
|
+
recording's own instrument** (see below), which is what every editing gesture, hit-test and renderer keeps working
|
|
527
|
+
on. The angle is authoritative: `SightingShapes` (`src/engine/persistence/SightingShapes.ts`) re-derives `bounds`
|
|
528
|
+
from it on load and reads it back from `bounds` on save, so a file survives a change of canvas, of field of view or
|
|
529
|
+
of instrument, and if the two ever disagree the angle wins. `ImageProjection`
|
|
530
|
+
(`src/engine/instrument/ImageProjection.ts`) owns the conversion itself.
|
|
528
531
|
|
|
529
|
-
|
|
530
|
-
wide, not the 90px an author reaches for unaided. That is why the editor's **Try a size** / **at a distance of**
|
|
532
|
+
Through an eye at 60° across 360px, one degree is exactly 6px and the full Moon about 3.1px — so an object of 3.5m
|
|
533
|
+
at 90m is 13px wide, not the 90px an author reaches for unaided. That is why the editor's **Try a size** / **at a distance of**
|
|
531
534
|
fields exist: type a hypothesis, get the angle it implies on the canvas, and the meters are forgotten the moment
|
|
532
535
|
they have been applied. They are an authoring aid, never testimony.
|
|
533
536
|
|
|
537
|
+
### Instrument — an eye is not a lens
|
|
538
|
+
|
|
539
|
+
`instrument` says what the observation was made through, and it changes the geometry of every frame.
|
|
540
|
+
|
|
541
|
+
A camera lens maps a direction to its sensor as `r = f·tan θ`: straight lines stay straight, and everything away
|
|
542
|
+
from the axis is stretched by `sec²θ` — 42% at 33° off-centre, 105% at the corner of a 16:9 frame with a 60°
|
|
543
|
+
vertical field. That is *correct* for a photograph and only looks right from the projection centre, about half an
|
|
544
|
+
image-width from the screen. An eye does no such thing: it perceives an angle as an angle wherever it falls, so
|
|
545
|
+
`instrument: "eye"` renders `r = f·θ` — image distance proportional to angle, which is what lets a ruler held to
|
|
546
|
+
the screen mean something. (A slight tangential stretch of `θ/sin θ` remains, 6% at 33°; no flat image escapes
|
|
547
|
+
trading one distortion for another.)
|
|
548
|
+
|
|
549
|
+
three.js's camera can only do the pinhole, so `EquidistantProjectionPass` renders the scene into an offscreen
|
|
550
|
+
target with a deliberately wider field and resamples it in one fullscreen pass. Everything that *aims* at the scene
|
|
551
|
+
rather than drawing it — the decor raycasts behind `isScreenPointOccluded` and `decorDistancesAt` — goes through
|
|
552
|
+
`directionFor`, since a point on the visible image no longer means what the pinhole camera thinks it means.
|
|
553
|
+
|
|
554
|
+
This is also why a change of instrument **moves** shapes and not just resizes them (`SightingShapes.reproject`): a
|
|
555
|
+
pixel only names a direction once a projection is named. Leaving positions alone is exactly how an object drawn in
|
|
556
|
+
several parts comes apart — the fuselage grows and its row of windows stays put.
|
|
557
|
+
|
|
558
|
+
Every case file here declares `eye`, because every one of them was watched rather than filmed. Until this existed
|
|
559
|
+
they were all rendered as photographs, which is what made Socorro's dynamite shack read as twice the size it
|
|
560
|
+
subtends.
|
|
561
|
+
|
|
562
|
+
One residual worth naming: an angular extent is stored as its *on-axis* value, and applied to a shape wherever it
|
|
563
|
+
sits. For an object 9° off-axis subtending 9°, that is about 2.5% out. The overlay draws axis-aligned boxes and
|
|
564
|
+
cannot express more; it is a fifth of the error it replaces, and it shrinks towards the centre of the frame.
|
|
565
|
+
|
|
534
566
|
#### Where meters do come back
|
|
535
567
|
|
|
536
568
|
The only real distance a testimony can support is an **inequality**, and only where the witness saw the object
|
package/dist-embed/{UfoRecorderMessages_fr-DeL1OXU3.js → UfoRecorderMessages_fr-Dvf46rNk.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
const e={oval:"Ovale",polygon:"Polygone",addVertex:"Ajouter un sommet",deleteVertex:"Supprimer le sommet",notAPolygon:"Sélectionnez une seule forme polygonale",tooFewVertices:"Une forme a besoin d'au moins 3 points",color:"Couleur",transparency:"Transparence",halo:"Halo",shape:"Forme",shapeTitle:"Nom",objectSize:"Essayer une taille",objectDistance:"à une distance de",apparentSize:"soit {deg}° — {moons}× la Lune",utcOffset:"Fuseau horaire",utcOffsetPlaceholder:"d'après la longitude",objectSizePlaceholder:"largeur supposée",objectDistancePlaceholder:"distance supposée",realSizeBetween:"Largeur réelle : entre {min} et {max} m, d'après ce qu'il croise",realSizeAtLeast:"Largeur réelle : au moins {min} m, d'après ce qu'il passe derrière",realSizeAtMost:"Largeur réelle : au plus {max} m, d'après ce qu'il passe devant",realSizeUnknown:"Largeur réelle indéterminée : rien dans la scène ne croise sa ligne de visée",realSizeContradiction:"Contradiction : les passages déclarés ne peuvent pas être vrais ensemble",realDistanceHere:" — soit ici entre {min} et {max} m",addShape:"Ajouter une forme",deleteShape:"Supprimer la forme",play:"Lecture",pause:"Pause",noDuration:"Aucune durée d'observation",autoReplay:"Lecture automatique",group:"Grouper",ungroup:"Dégrouper",bringToFront:"Placer devant",sendToBack:"Placer derrière",contextMenuDelete:"Supprimer",confirmDeleteShape:"Supprimer {name} ? Cette action est irréversible.",confirmDeleteShapes:"Supprimer {count} formes ? Cette action est irréversible.",onlyOneShape:"Il n'y a qu'une seule forme",alreadyAtFront:"Cette forme est déjà la plus en avant",alreadyAtBack:"Cette forme est déjà la plus en arrière",needTwoShapesToGroup:"Sélectionnez au moins deux formes pour les grouper",notGrouped:"Cette forme ne fait pas partie d'un groupe",multipleShapesSelected:"Plusieurs formes sélectionnées — sélectionnez-en une seule pour modifier ceci",cloudBase:"Base des nuages",elevation:"Altitude",samplingRate:"Échantillonnage",duration:"Durée",durationPlaceholder:"durée de l'observation",durationImprecise:"Ces dates ne permettent pas de déterminer précisément une durée — saisissez-la manuellement.",export:"Exporter le JSON",importFile:"Charger un fichier JSON",importUrl:"Ou charger depuis une URL",importUrlPlaceholder:"https://…/sighting.json",importButton:"Charger",importError:"Impossible de charger cet enregistrement — vérifiez le fichier ou l'URL et réessayez.",record:"Enregistrer",stop:"Arrêter",according:"selon",sourceElevation:"Relief",sourceImagery:"Imagerie",placeName:"Lieu",placeNamePlaceholder:"Valensole, France",searchPlace:"Localiser",placeMatch:"Correspondances",placeSearching:"Recherche du lieu…",placeMatchFound:"lieu trouvé",placeMatchesFound:"lieux trouvés",placeNotFound:"Aucun lieu de ce nom",placeSearchFailed:"Recherche de lieu momentanément indisponible",utcOffsetImplausible:"Ce fuseau ne correspond pas à la longitude saisie, dont l'heure solaire est UTC{solar} — la scène et le relevé météo obéissent pourtant à ce qui est déclaré ici. Videz le champ pour le déduire de la longitude.",timeZoneManual:"décalage saisi",altitudeAboveSeaLevel:"Altitude du témoin au-dessus du niveau de la mer — le sol du lieu saisi en fixe le minimum : un témoin dans les Alpes n'est pas à 0 m.",groundAt:"sol à {m} m",latitude:"Latitude",longitude:"Longitude",heading:"Orientation",headingPlaceholder:"inconnu",pitch:"Inclinaison",observationTime:"Début de l'observation",observationEndTime:"Fin de l'observation",edtfInvalid:"Date/heure EDTF invalide (ex. 1965-07-01T05:00, 2025-06?, 2025~).",edtfPlaceholder:"AAAA-MM-JJThh:mm[?~%] ou hh:mm",observationTimeHint:"EDTF — ex. 1965-07-01T05:00, 2025-06? (incertain), 2025~ (approximatif), ou juste 05:00 si la date est inconnue",observationEndTimeHint:"EDTF — ex. 1965-07-01T05:10, 2025-06? (incertain), 2025~ (approximatif), ou juste 05:10 si la date est inconnue",presetsGroupLabel:"Forme de l'ovni",witnessId:"ID témoin",witnessDirName:"Répertoire du témoin",witnessTitle:"Titre du témoin",witnessLastName:"Nom de famille du témoin",witnessFirstNames:"Prénoms du témoin",caseId:"ID de l'affaire",description:"Description",tags:"Mots-clés",tagsPlaceholder:"séparés par des virgules",weather:"Météo",shapeGroup:"Forme",soundGroup:"Son",temporalGroup:"Date et heure",locationGroup:"Lieu",observationGroup:"Observation",witnessGroup:"Témoin",circumstancesGroup:"Circonstances",weatherInferred:"D'après les relevés",weatherInferredTitle:"La météo n'est pas un témoignage : c'est un fait mesurable, relevé pour la date, l'heure et le lieu de l'observation. Décochez pour saisir les conditions rapportées par le témoin, qui priment alors sur le relevé.",weatherLookingUp:"Recherche du relevé…",weatherNeedsDateAndPlace:"Date complète et lieu requis pour retrouver le relevé",weatherNoRecord:"Aucun relevé pour cette date et ce lieu",weatherLookupFailed:"Relevés météo momentanément inaccessibles",cloudCover:"Couverture nuageuse",cloudDarkness:"Obscurité des nuages",precipitationType:"Précipitations",precipitationNone:"Aucune",precipitationRain:"Pluie",precipitationSnow:"Neige",precipitationHail:"Grêle",precipitationIntensity:"Intensité",windDirection:"Direction du vent",windSpeed:"Force du vent",storm:"Orage",soundKind:"Son",soundNone:"Aucun (silencieux)",soundHum:"Bourdonnement",soundWhistle:"Sifflement",soundRumble:"Grondement",soundCrackle:"Crépitement",soundVolume:"Intensité sonore",soundPitch:"Hauteur",soundSrc:"Enregistrement",soundSrcPlaceholder:"URL d'un enregistrement réel",lensFlareBrightness:"Intensité lumineuse",cameraDevice:"Appareil photo/vidéo",decor:"Décor",decorBuilding:"Bâtiment",decorTree:"Arbre",decorStreetlight:"Lampadaire",decorVehicle:"Véhicule",decorWitness:"Autre témoin",addDecor:"Ajouter",deleteDecor:"Supprimer l'élément de décor",decorEast:"Distance à l'est",decorNorth:"Distance au nord",decorHeading:"Orientation",decorLit:"Allumé",decorTitle:"Nom",decorSightingUrl:"URL de l'enregistrement du témoin",viewTestimony:"Voir le témoignage",noWitnessRecording:"Aucune URL d'enregistrement définie pour ce témoin",masks:"Masque",addWitness:"Ajouter un témoin",decorFloors:"Étages",decorOccupiedFloor:"Étage occupé",decorWitnessSide:"Emplacement du témoin",decorWitnessSideNone:"Non présent",decorWindows:"Fenêtres",decorSideFront:"Avant",decorSideBehind:"Arrière",decorSideLeft:"Gauche",decorSideRight:"Droite",decorSideFrontLeft:"Avant-gauche",decorSideFrontRight:"Avant-droit",decorSideBehindLeft:"Arrière-gauche",decorSideBehindRight:"Arrière-droit"};export{e as ufoRecorderMessages_fr};
|
|
1
|
+
const e={oval:"Ovale",polygon:"Polygone",addVertex:"Ajouter un sommet",deleteVertex:"Supprimer le sommet",notAPolygon:"Sélectionnez une seule forme polygonale",tooFewVertices:"Une forme a besoin d'au moins 3 points",color:"Couleur",transparency:"Transparence",halo:"Halo",shape:"Forme",shapeTitle:"Nom",objectSize:"Essayer une taille",objectDistance:"à une distance de",apparentSize:"soit {deg}° — {moons}× la Lune",utcOffset:"Fuseau horaire",utcOffsetPlaceholder:"d'après la longitude",objectSizePlaceholder:"largeur supposée",objectDistancePlaceholder:"distance supposée",realSizeBetween:"Largeur réelle : entre {min} et {max} m, d'après ce qu'il croise",realSizeAtLeast:"Largeur réelle : au moins {min} m, d'après ce qu'il passe derrière",realSizeAtMost:"Largeur réelle : au plus {max} m, d'après ce qu'il passe devant",realSizeUnknown:"Largeur réelle indéterminée : rien dans la scène ne croise sa ligne de visée",realSizeContradiction:"Contradiction : les passages déclarés ne peuvent pas être vrais ensemble",realDistanceHere:" — soit ici entre {min} et {max} m",addShape:"Ajouter une forme",deleteShape:"Supprimer la forme",play:"Lecture",pause:"Pause",noDuration:"Aucune durée d'observation",autoReplay:"Lecture automatique",group:"Grouper",ungroup:"Dégrouper",bringToFront:"Placer devant",sendToBack:"Placer derrière",contextMenuDelete:"Supprimer",confirmDeleteShape:"Supprimer {name} ? Cette action est irréversible.",confirmDeleteShapes:"Supprimer {count} formes ? Cette action est irréversible.",onlyOneShape:"Il n'y a qu'une seule forme",alreadyAtFront:"Cette forme est déjà la plus en avant",alreadyAtBack:"Cette forme est déjà la plus en arrière",needTwoShapesToGroup:"Sélectionnez au moins deux formes pour les grouper",notGrouped:"Cette forme ne fait pas partie d'un groupe",multipleShapesSelected:"Plusieurs formes sélectionnées — sélectionnez-en une seule pour modifier ceci",cloudBase:"Base des nuages",elevation:"Altitude",samplingRate:"Échantillonnage",duration:"Durée",durationPlaceholder:"durée de l'observation",durationImprecise:"Ces dates ne permettent pas de déterminer précisément une durée — saisissez-la manuellement.",export:"Exporter le JSON",importFile:"Charger un fichier JSON",importUrl:"Ou charger depuis une URL",importUrlPlaceholder:"https://…/sighting.json",importButton:"Charger",importError:"Impossible de charger cet enregistrement — vérifiez le fichier ou l'URL et réessayez.",record:"Enregistrer",stop:"Arrêter",according:"selon",sourceElevation:"Relief",sourceImagery:"Imagerie",placeName:"Lieu",placeNamePlaceholder:"Valensole, France",searchPlace:"Localiser",placeMatch:"Correspondances",placeSearching:"Recherche du lieu…",placeMatchFound:"lieu trouvé",placeMatchesFound:"lieux trouvés",placeNotFound:"Aucun lieu de ce nom",placeSearchFailed:"Recherche de lieu momentanément indisponible",utcOffsetImplausible:"Ce fuseau ne correspond pas à la longitude saisie, dont l'heure solaire est UTC{solar} — la scène et le relevé météo obéissent pourtant à ce qui est déclaré ici. Videz le champ pour le déduire de la longitude.",timeZoneManual:"décalage saisi",altitudeAboveSeaLevel:"Altitude du témoin au-dessus du niveau de la mer — le sol du lieu saisi en fixe le minimum : un témoin dans les Alpes n'est pas à 0 m.",groundAt:"sol à {m} m",latitude:"Latitude",longitude:"Longitude",heading:"Orientation",headingPlaceholder:"inconnu",pitch:"Inclinaison",observationTime:"Début de l'observation",observationEndTime:"Fin de l'observation",edtfInvalid:"Date/heure EDTF invalide (ex. 1965-07-01T05:00, 2025-06?, 2025~).",edtfPlaceholder:"AAAA-MM-JJThh:mm[?~%] ou hh:mm",observationTimeHint:"EDTF — ex. 1965-07-01T05:00, 2025-06? (incertain), 2025~ (approximatif), ou juste 05:00 si la date est inconnue",observationEndTimeHint:"EDTF — ex. 1965-07-01T05:10, 2025-06? (incertain), 2025~ (approximatif), ou juste 05:10 si la date est inconnue",presetsGroupLabel:"Forme de l'ovni",witnessId:"ID témoin",witnessDirName:"Répertoire du témoin",witnessTitle:"Titre du témoin",witnessLastName:"Nom de famille du témoin",witnessFirstNames:"Prénoms du témoin",caseId:"ID de l'affaire",description:"Description",tags:"Mots-clés",tagsPlaceholder:"séparés par des virgules",weather:"Météo",shapeGroup:"Forme",soundGroup:"Son",temporalGroup:"Date et heure",locationGroup:"Lieu",observationGroup:"Observation",witnessGroup:"Témoin",circumstancesGroup:"Circonstances",weatherInferred:"D'après les relevés",weatherInferredTitle:"La météo n'est pas un témoignage : c'est un fait mesurable, relevé pour la date, l'heure et le lieu de l'observation. Décochez pour saisir les conditions rapportées par le témoin, qui priment alors sur le relevé.",weatherLookingUp:"Recherche du relevé…",weatherNeedsDateAndPlace:"Date complète et lieu requis pour retrouver le relevé",weatherNoRecord:"Aucun relevé pour cette date et ce lieu",weatherLookupFailed:"Relevés météo momentanément inaccessibles",cloudCover:"Couverture nuageuse",cloudDarkness:"Obscurité des nuages",precipitationType:"Précipitations",precipitationNone:"Aucune",precipitationRain:"Pluie",precipitationSnow:"Neige",precipitationHail:"Grêle",precipitationIntensity:"Intensité",windDirection:"Direction du vent",windSpeed:"Force du vent",storm:"Orage",soundKind:"Son",soundNone:"Aucun (silencieux)",soundHum:"Bourdonnement",soundWhistle:"Sifflement",soundRumble:"Grondement",soundCrackle:"Crépitement",soundVolume:"Intensité sonore",soundPitch:"Hauteur",soundSrc:"Enregistrement",soundSrcPlaceholder:"URL d'un enregistrement réel",lensFlareBrightness:"Intensité lumineuse",instrument:"Observé avec",cameraDevice:"Appareil photo/vidéo",decor:"Décor",decorBuilding:"Bâtiment",decorTree:"Arbre",decorStreetlight:"Lampadaire",decorVehicle:"Véhicule",decorWitness:"Autre témoin",addDecor:"Ajouter",deleteDecor:"Supprimer l'élément de décor",decorEast:"Distance à l'est",decorNorth:"Distance au nord",decorHeading:"Orientation",decorLit:"Allumé",decorTitle:"Nom",decorSightingUrl:"URL de l'enregistrement du témoin",viewTestimony:"Voir le témoignage",noWitnessRecording:"Aucune URL d'enregistrement définie pour ce témoin",masks:"Masque",addWitness:"Ajouter un témoin",decorFloors:"Étages",decorOccupiedFloor:"Étage occupé",decorWitnessSide:"Emplacement du témoin",decorWitnessSideNone:"Non présent",decorWindows:"Fenêtres",decorSideFront:"Avant",decorSideBehind:"Arrière",decorSideLeft:"Gauche",decorSideRight:"Droite",decorSideFrontLeft:"Avant-gauche",decorSideFrontRight:"Avant-droit",decorSideBehindLeft:"Arrière-gauche",decorSideBehindRight:"Arrière-droit"};export{e as ufoRecorderMessages_fr};
|