@rr0/ufoathome 0.17.1 → 0.19.0
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 +164 -2
- package/dist-embed/UfoRecorderMessages_fr-BbT_cujZ.js +1 -0
- package/dist-embed/rr0-ufo-recorder.mjs +364 -208
- package/dist-embed-eyewitness/rr0-eyewitness.mjs +191 -191
- package/dist-embed-scene/rr0-scene.mjs +192 -192
- package/dist-embed-ufo/rr0-ufo.mjs +3 -3
- package/package.json +1 -1
- package/dist-embed/UfoRecorderMessages_fr-CzIWyNRZ.js +0 -1
package/README.md
CHANGED
|
@@ -82,7 +82,8 @@ The lightweight component (~9KB): a canvas plus Play/Pause/Loop/seek controls. U
|
|
|
82
82
|
|
|
83
83
|
Playback matches the observation's *real reported duration* when it's known: set `time`/`endTime`, or `time`/
|
|
84
84
|
`durationSeconds`, in the [data format](#data-format) (`durationSeconds` takes precedence over `endTime` if both are
|
|
85
|
-
given
|
|
85
|
+
given — but in the recorder, editing either date clears an explicit `durationSeconds` the pair can replace, so the
|
|
86
|
+
more recent edit is the one that wins rather than being silently outranked). Watching a 5-minute sighting then takes 5 real minutes, not however long the recording itself took to
|
|
86
87
|
author (e.g. a quick mouse drag) — drag the seek bar directly to skip ahead. The start/end labels around the seek
|
|
87
88
|
bar show real clock times when `time` has an hour (e.g. `02:45` → `02:50`); otherwise they show `0:00` → the
|
|
88
89
|
duration actually available (the declared one if known, else the recording's own length). Playback loops by
|
|
@@ -232,6 +233,15 @@ scale a case's witness list actually has. If a witness has no `witness.title`, i
|
|
|
232
233
|
the URL itself as a last resort. A mismatched `caseId` across the listed witnesses logs a console warning (doesn't
|
|
233
234
|
block) — likely means unrelated recordings got listed together by mistake.
|
|
234
235
|
|
|
236
|
+
**Where two witnesses described different things, the recordings have to show it.** Not that they
|
|
237
|
+
must differ — witnesses often agree, and two matching recordings are then simply true. But a
|
|
238
|
+
difference that exists in the record and not in the files makes the witness picker a control that
|
|
239
|
+
does nothing, and nothing *looks* broken. Chiles-Whitted shipped that way for months: one testimony
|
|
240
|
+
under two names. Its two pilots drew the object differently for Project Sign — the captain a slim
|
|
241
|
+
ribbed cigar with a pointed nose and no windows, the co-pilot a blunt cylinder with two rows of
|
|
242
|
+
lit windows — and only the co-pilot, in the right seat, saw the terminal phase (McDonald's 1968
|
|
243
|
+
cross-check). Each file now carries its own witness's account.
|
|
244
|
+
|
|
235
245
|
| Member | Kind | Description |
|
|
236
246
|
|---|---|---|
|
|
237
247
|
| `src` | attribute | URL of a single `sighting.json` or a witness manifest (above), fetched automatically on connect and whenever the attribute changes |
|
|
@@ -290,7 +300,7 @@ interface SightingRecordingJson {
|
|
|
290
300
|
endTime?: { year?: number, month?: number, day?: number, hour?: number, minute?: number, second?: number } // alternative to durationSeconds
|
|
291
301
|
durationSeconds?: number // alternative to endTime; takes precedence if both are set
|
|
292
302
|
utcOffsetHours?: number // the LEGAL time zone the witness's clock was on (+1 for France in 1965, -7 for New Mexico in April 1964). Absent = approximated from the longitude, which cannot know legal time or a daylight-saving switch
|
|
293
|
-
place?: { lat: number, lng: number }[]
|
|
303
|
+
place?: { lat: number, lng: number, name?: string }[] // `name` is the fully qualified place name the coordinates were resolved from — see Naming a place
|
|
294
304
|
witness?: { id?: string, dirName?: string, title?: string, lastName?: string, firstNames?: string[] } // every field optional — supply whichever is known; omit entirely for an anonymous witness
|
|
295
305
|
caseId?: string // shared by every witness's own sighting.json for the same case — see <rr0-eyewitness>
|
|
296
306
|
description?: string
|
|
@@ -321,6 +331,8 @@ interface SightingRecordingJson {
|
|
|
321
331
|
witnessTrack?: { keyframes: Array<{ t: number, pose: { lat?: number, lng?: number, elevationM: number, headingDeg?: number, pitchDeg: number, fovDeg: number } }> }
|
|
322
332
|
weatherTrack?: { keyframes: Array<{ t: number, weather: Weather }> }
|
|
323
333
|
weather?: Weather // legacy static fallback for recordings predating weatherTrack
|
|
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
|
+
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
|
|
324
336
|
decor?: DecorObject[] // buildings, trees, streetlights, vehicles, other witnesses — see src/engine/model/Decor.ts
|
|
325
337
|
}
|
|
326
338
|
```
|
|
@@ -329,6 +341,156 @@ A shape left out of a later keyframe is **held** at its last recorded state, not
|
|
|
329
341
|
keyframe is at `t=5000` is already painted, in that state, from `t=0` (hold-first/hold-last at both ends of a
|
|
330
342
|
source's own range). To make something stop being visible, keyframe it with `transparency: 1`.
|
|
331
343
|
|
|
344
|
+
### What it sounded like
|
|
345
|
+
|
|
346
|
+
Half of what makes these accounts strange is the sound — most often its absence. `soundTrack` records it on the
|
|
347
|
+
same clock as the shapes, because a sound rarely starts when the object does: a craft sitting silently on the
|
|
348
|
+
ground and heard only as it lifts off is two keyframes, `kind: "none"` at the start and a hum at the instant it
|
|
349
|
+
took off.
|
|
350
|
+
|
|
351
|
+
`volume` (0..1, how loud the witness could describe it, never a dB figure) and `pitchHz` blend between keyframes;
|
|
352
|
+
`kind` and `src` are **held**, like every other discrete field in this format — so the example above really is
|
|
353
|
+
silent right up to that second keyframe. To record a sound emerging gradually instead, give it two keyframes of
|
|
354
|
+
its own kind (hum at volume 0, then hum at full).
|
|
355
|
+
|
|
356
|
+
`kind: "none"` is a statement — the witness reported hearing nothing. A recording with no `soundTrack` at all is
|
|
357
|
+
the different, weaker case: nobody was asked. Both replay as silence, and neither invents a noise.
|
|
358
|
+
|
|
359
|
+
Sounds are **synthesized** from that description (a drone, a whistle, a rumble, a crackle — `pitchHz` is the tone
|
|
360
|
+
itself for the pitched ones and where the noise sits for the others), exactly as a described shape is drawn from
|
|
361
|
+
its description, and at no cost in bundled assets. A recording that actually captured the sound can point `src` at
|
|
362
|
+
the audio file, which then plays instead — at the price of an embed that is no longer self-contained, and a URL
|
|
363
|
+
that must be CORS-readable.
|
|
364
|
+
|
|
365
|
+
Sound plays during playback only, and only after a real click somewhere in the player: browsers refuse to start
|
|
366
|
+
audio without one.
|
|
367
|
+
|
|
368
|
+
### Naming a place
|
|
369
|
+
|
|
370
|
+
Testimony names a place. It says "on the Valensole plateau", "near Socorro", "over Montgomery" —
|
|
371
|
+
never 43.8379 / 5.9840. So the Location group leads with a **Place** field: type a name, press Enter
|
|
372
|
+
(or **Locate**), and the latitude and longitude below are filled from
|
|
373
|
+
[Nominatim](https://nominatim.openstreetmap.org/), OpenStreetMap's own geocoder — which, unlike the
|
|
374
|
+
gazetteer-style services, knows the hamlets, farms and airfields that cases actually happen at.
|
|
375
|
+
A name is often ambiguous, so every candidate stays listed in **Matches** and the best one is
|
|
376
|
+
applied straight away; picking another moves the witness. Results are named in the reader's own
|
|
377
|
+
language, and credited as their licence requires.
|
|
378
|
+
|
|
379
|
+
What gets stored is the *qualified* name the search resolved (`place[].name`), not the two words
|
|
380
|
+
typed — half the interesting cases happen near a village that shares its name with four others, and
|
|
381
|
+
a later reader needs to land on the same spot. A name no geocoder knows is kept as typed, so a
|
|
382
|
+
recording can still say "the lavender field east of the farm" beside coordinates entered by hand.
|
|
383
|
+
|
|
384
|
+
The field reads both ways: move the latitude or longitude by hand and a resolved name is re-derived
|
|
385
|
+
from the new coordinates, or cleared if there is no place there. A name left describing somewhere
|
|
386
|
+
the sighting is no longer at is worse than no name — the recording would state, in writing, that it
|
|
387
|
+
happened there. A name the witness typed themselves is never replaced.
|
|
388
|
+
|
|
389
|
+
**Altitude is above sea level**, and the ground at the location sets its floor: a witness in the
|
|
390
|
+
Alps is not at 0 m, and an editor that offers it invites a recording that says so. The ground's own
|
|
391
|
+
height is read from whichever elevation source is live and shown beside the field. What gets stored
|
|
392
|
+
is unchanged — `ObserverPose.elevationM` stays a height above the local ground, which is what the
|
|
393
|
+
terrain patch is built around.
|
|
394
|
+
|
|
395
|
+
### Time zones
|
|
396
|
+
|
|
397
|
+
An hour of `utcOffsetHours` is an hour of Earth's rotation *and* a different row of the weather
|
|
398
|
+
record. Pick the witness's own zone (`Europe/Paris`, `America/Denver`, …) and the offset is derived
|
|
399
|
+
from that zone's rules **at the observation's date**: Valensole in July 1965 resolves to UTC+1, not
|
|
400
|
+
the UTC+2 the same place gives today — France only reintroduced summer time in 1976. Change the date
|
|
401
|
+
and it is derived again. The recording stores both: `timeZone` is the rule, `utcOffsetHours` is the
|
|
402
|
+
number it produced, and every consumer keeps reading only the number.
|
|
403
|
+
|
|
404
|
+
The rules come from the platform's own IANA database. What it cannot fix is a zone whose
|
|
405
|
+
*boundaries* are coarse: Montgomery, Alabama is `America/Chicago`, which observed summer time in
|
|
406
|
+
1948 while Alabama did not. That is why the zone is chosen by the witness rather than derived from
|
|
407
|
+
the coordinates — and why the plain entered offset remains available for exactly those cases.
|
|
408
|
+
|
|
409
|
+
The search runs only when asked, never per keystroke: Nominatim's usage policy allows the first and
|
|
410
|
+
rules out the second.
|
|
411
|
+
|
|
412
|
+
### Who answered is part of the answer
|
|
413
|
+
|
|
414
|
+
Every kind of real-world data this editor pulls in — places, weather, ground relief, aerial imagery
|
|
415
|
+
— is chosen by a picker sitting **where that data is reported**, with the attribution its licence
|
|
416
|
+
requires next to it:
|
|
417
|
+
|
|
418
|
+
> 2 places found according to `[Nominatim ▾]` © OpenStreetMap
|
|
419
|
+
>
|
|
420
|
+
> From `[ERA5 (Open-Meteo) ▾]` © Copernicus/ECMWF, 2026-08-21 15:30 UTC
|
|
421
|
+
|
|
422
|
+
Those pickers *are* the credits. Naming who the data comes from and letting it be chosen are the
|
|
423
|
+
same act: a static "© OpenStreetMap" tucked beside a field says where today's answer came from but
|
|
424
|
+
hides that it is a choice, and a picker with no attribution credits nobody. Relief and imagery have
|
|
425
|
+
no sentence to sit in, so they get a row under the coordinates whose ground they describe.
|
|
426
|
+
|
|
427
|
+
Most registries hold a single entry today (imagery holds two, Esri and EOX Sentinel-2 cloudless) —
|
|
428
|
+
which is the point: the seam is visible before it is used, and adding an implementation means adding
|
|
429
|
+
one entry to a registry (`placeSources.ts`, `weatherSources.ts`, `terrainSources.ts`), not new
|
|
430
|
+
markup.
|
|
431
|
+
|
|
432
|
+
A stale offset renders midnight over Paris and gives no clue why, so an offset that cannot belong to
|
|
433
|
+
the declared longitude is flagged on the field, with the meridian's own solar time in the tooltip.
|
|
434
|
+
|
|
435
|
+
Deliberately a wide net rather than a precise one. Legal time genuinely departs from solar time,
|
|
436
|
+
sometimes by hours (all of China runs on UTC+8), and the historical rules are worse — the check must
|
|
437
|
+
never cry wolf at a correct "France on UTC+1 in 1965". It flags only what no country has ever done,
|
|
438
|
+
and only as a warning: the recording states the witness's clock, and nothing here knows better than
|
|
439
|
+
the witness.
|
|
440
|
+
|
|
441
|
+
### Weather is looked up, not remembered
|
|
442
|
+
|
|
443
|
+
The Circumstances group is the one part of this editor that isn't testimony. Weather is a
|
|
444
|
+
measurable fact about a place at an instant, and the recording already states both — so instead of
|
|
445
|
+
leaving a witness (or an author reconstructing a case decades later) to set a cloud-cover slider
|
|
446
|
+
from memory, the editor looks the conditions up from [ERA5](https://open-meteo.com/en/docs/historical-weather-api),
|
|
447
|
+
the ECMWF reanalysis, hourly and worldwide from 1940 on. The fields then show the record's own
|
|
448
|
+
values, **read-only**, above a line naming the dataset and the exact UTC instant they describe (a
|
|
449
|
+
wrong `utcOffsetHours` shows up there before it shows up in the rendered sky). The request that
|
|
450
|
+
produced them is kept in `weatherSource.url`, so the claim stays checkable years later.
|
|
451
|
+
|
|
452
|
+
Two of the fields have no direct counterpart in the record and are *derived* — `cloudDarkness`,
|
|
453
|
+
which is a look rather than a measurement (weighted by which layers hold the cloud, plus rain and
|
|
454
|
+
thunderstorm), and `cloudBaseM`, placed at the lowest deck holding a real share of the sky, from
|
|
455
|
+
Espy's temperature/dew-point spread for a low deck. Both are documented in
|
|
456
|
+
`src/engine/weather/providers/OpenMeteoWeatherProvider.ts`.
|
|
457
|
+
|
|
458
|
+
Unchecking **From weather records** hands the fields back to the witness: the looked-up values stay
|
|
459
|
+
as a starting point, `weatherSource` is dropped, and no later lookup may overwrite them — the same
|
|
460
|
+
"declared outranks deduced" rule [Behind a cloud](#behind-a-cloud) follows. A recording that names
|
|
461
|
+
a `weatherSource` is replayed exactly as authored and never looked up again, so a published case
|
|
462
|
+
file reads identically offline. Nothing is ever locked without a record to show for it: before 1940,
|
|
463
|
+
or with no network, the fields stay editable and the line says which of the two it is.
|
|
464
|
+
|
|
465
|
+
The `weatherTrack` follows the observation rather than flattening it: a keyframe at its start, one
|
|
466
|
+
at every whole hour it runs through, and one at its end. The record is read *between* its hourly
|
|
467
|
+
rows, not snapped to the nearest one — so Wilcox's two hours carry a cloud deck lifting from 800 m
|
|
468
|
+
to 913 m, and even a four-minute sighting gets a track that moves instead of one value repeated.
|
|
469
|
+
(For a short observation the record often genuinely says nothing changed. That is an answer, not a
|
|
470
|
+
missing feature.)
|
|
471
|
+
|
|
472
|
+
The keyframes are placed on the clock playback actually runs on — `timeline.duration` once
|
|
473
|
+
something has been recorded, and the observation's own declared length before that (the same rule
|
|
474
|
+
`Player.durationOverrideMs` implements). That clock *changes length as authoring proceeds*: the
|
|
475
|
+
first recorded shape turns a fifteen-hour span into a few seconds, so the track is re-derived
|
|
476
|
+
whenever it does. Getting either half wrong looks the same from outside — a sighting whose weather
|
|
477
|
+
never changes.
|
|
478
|
+
|
|
479
|
+
It follows the witness too, not just the clock. Half of aviation testimony is given from a cockpit,
|
|
480
|
+
and an aircraft under observation for an hour is a long way from where it started — so each sample
|
|
481
|
+
is looked up at the position the `witnessTrack` puts the witness at that instant. Positions inside
|
|
482
|
+
one ERA5 grid cell (~28 km) are one query, and several cells still travel in a single request, so
|
|
483
|
+
a stationary witness costs exactly what it always did.
|
|
484
|
+
|
|
485
|
+
`scripts/infer-case-weather.ts` runs the same lookup over case files on disk:
|
|
486
|
+
|
|
487
|
+
```bash
|
|
488
|
+
npx tsx scripts/infer-case-weather.ts --dry-run path/to/sighting.json
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
It rewrites only `weatherTrack` and `weatherSource`, splicing them into the file's own text so the
|
|
492
|
+
diff shows the weather and nothing else.
|
|
493
|
+
|
|
332
494
|
### Behind a cloud
|
|
333
495
|
|
|
334
496
|
`behindCloud` is how a recording says "it disappeared into a cloud" — keyframed like any other
|
|
@@ -0,0 +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:"Taille réelle",objectDistance:"Distance",apparentSize:"soit {deg}° — {moons}× la Lune",utcOffset:"Fuseau horaire",utcOffsetPlaceholder:"d'après la longitude",objectSizePlaceholder:"largeur rapportée",objectDistancePlaceholder:"distance rapportée",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é.",weatherFrom:"D'après",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};
|