ai-startup-skills
AI 제품을 만드는 스타트업을 위한 7단계 에이전트 스킬: 검증 → 비즈플랜 → 정책 → 로드쇼 → 고객 확보 → 가격 책정 → 등록
UFO@home은 목격자가 묘사한 UFO 형태·이동·해당 시간·위치의 실제 하늘을 재현하는 무료 오픈소스 도구입니다
UFO@home is a free, open-source tool that replays a UFO sighting as its witness described it — the shape, its movement, and the real sky of that date, time and place.
기타TypeScript · PythonGitHub @RR0온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기A tool for reporting UFO sightings visually
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
UFO@home lets a UFO observer record the shape, appearance and movement of what they saw, and replay it
against the real sky, weather and place of the observation, instead of relying only on a written or spoken account.
Everything about using it lives on ufoathome.org, which is built from this
repository (see The site) so that it always describes the version it ships with:
• Demos: every published reconstruction, running.
• Player and editor.
• Documentation: embedding the components (, ,
), the recording format, the data sources, sharing a recording.
• Roadmap and FAQ.README 전문 보기 ↗UFO@home lets a UFO observer record the shape, appearance and movement of what they saw, and replay it against the real sky, weather and place of the observation, instead of relying only on a written or spoken account.
Everything about using it lives on ufoathome.org, which is built from this repository (see The site) so that it always describes the version it ships with:
<rr0-sighting>, <rr0-scene>,
<rr0-sighting-editor>), the recording format, the data sources, sharing a recording.The components are published on npm as @rr0/ufoathome.
This README only covers what a contributor needs: installing, fetching the data, testing, debugging, releasing.
The project's history is in the Wiki.
Node ≥ 20 (Node 22 recommended, as pinned in netlify.toml).
git clone https://github.com/RR0/UfoAtHome.git
cd UfoAtHome
npm install
npm test
Nothing else is needed to develop, test or build: every catalogue the browser uses is committed (see
Data). No .env either: the only keys the project knows of are the ones a reader types into the
editor themselves (e.g. an Anthropic key to draft a recording from its description), which never leave their
browser.
| Path | What |
|---|---|
src/engine/ | Framework-agnostic core: model (Shape, Timeline, Sighting), recording, playback, persistence, astronomy, atmosphere, weather, place, assessment. No DOM, no three.js. |
src/render/ | 2D canvas drawing: the texture of each phenomenon plane, editing handles, the observer map. |
src/render3d/ | The three.js scene (SceneRenderer) and its systems: sky, terrain, decor, bodies, clouds, optics, phenomena. |
src/component/ | The Web Components. SceneElement (<rr0-scene>) composes the playback layer UfoElement; SightingElement and SightingEditorElement compose a SceneElement. Vanilla custom elements, no framework. |
src/assets/ | The star catalogue tiers (generated) and sounds. The other catalogues are generated modules in src/engine/astronomy/. |
src/generated/ | Derived from the TypeScript by npm run build:schema; gitignored, never edited. |
public/demo-data/ | The published recordings (observer-*.json, case-*.json) and the examples the docs quote. |
public/models/, public/roads/, public/tle/, public/reentries/, public/fireballs/, public/light-pollution/, public/aircraft/ | Archived glTF models, road networks, orbital elements, re-entries, recorded fireballs, night-sky brightness tiles and a slice of air traffic, served next to the bundles (see public/models/README.md). |
site/ | The ufoathome.org generator (see The site). |
scripts/ | One-off data builds, case maintenance, GPU checks and performance harnesses. |
Every data build is a one-off step: its output is committed, and neither build, test nor prepublishOnly
runs it. Re-run one only when its source or its script changes, and commit the result. Raw inputs go under
scripts/data/, which is gitignored (except scripts/data/novae/, kept so that catalogue stays reproducible).
Each script's header comment says what it takes, what it deliberately leaves out, and why.
| Command | Source | Input | Output |
|---|---|---|---|
npm run build:stars | HYG Database v4.1 | download hyg/CURRENT/hygdata_v41.csv to scripts/data/ | src/assets/stars-mag7.5* |
npm run build:lunar-limb | LOLA LDEM_16 (NASA, shape map of the Moon, 16 samples a degree) | download LDEM_16.IMG and .LBL to scripts/data/lola/ | src/assets/lunar-relief.bin.gz |
npm run build:comets | JPL Horizons (network) | cached in scripts/data/horizons/ | src/engine/astronomy/cometCatalog.ts |
npm run build:novae | AAVSO/Strope 2010 curves, SN 1987A | committed in scripts/data/novae/ | src/engine/astronomy/novaCatalog.ts |
npm run build:satellites | CelesTrak SATCAT (network) | cached as scripts/data/satcat.csv | src/engine/astronomy/satelliteCatalog.ts |
npm run build:tle | Laurent Chabin's TLE archive | a local copy in scripts/data/tle/<year>/, plus qs.mag and Stellarium's satellites.json | public/tle/ |
npm run build:roads | OpenStreetMap via Overpass (network) | one query per recording, cached in scripts/data/roads/ | public/roads/ |
npm run build:reentries [cords.csv] [satcat.csv] | (The Aerospace Corporation) and the SATCAT's decay days (CC BY 4.0) |
build:novae, build:tle and build:aircraft run on plain node (it strips the types), the others on tsx.
build:tle calls unzip and build:roads calls curl: on Windows, run those two from Git Bash or WSL.
The stand-in 3D models of the crafts of Socorro, Valensole, Chiles-Whitted, McMinnville, Braine-le-Comte,
Silly-le-Long and Trans-en-Provence are also built from the accounts, by scripts with no npm alias
(scripts/build-<case>-craft.ts), each saying in its header which of its details are assumed:
npx tsx scripts/build-socorro-craft.ts
The realistic people of the catalogue (and the beings of Valensole and Cussac, derived from them) are built in
Blender with MPFB from the MakeHuman system assets (CC0): see scripts/people/README.md.
Like every model, their output is committed.
The picture a shared link to a recording shows is a real frame of the simulation, photographed by a script that needs
Chrome (so outside the sandbox, with Playwright) and is not part of the site build. A recording says which second it is
taken at with summaryTime; --sheet writes a few instants to choose from, and --link writes the image fields from
the photographs already taken. The header of scripts/share-cards/ShareCards.ts has
the command lines. A case needs no card: the edge function takes the picture of its first account.
The recordings under public/demo-data/ are also served by rr0.org's case pages, which embed them by a relative
address. Keep both copies identical with:
npm run sync:cases # copy into ../rr0.org's case dossiers, reporting what changed
npm run sync:cases -- --check # change nothing, fail if anything drifted
A case's readings name the account they read by the id of its event in the case (see the format page); after editing a
case-*.json by hand, python3 site/skill/validate.py public/demo-data/case-x.json says whether every reference still
names an event.
A recording keeps the weather record's answer rather than a link to it. To ask again:
npx tsx scripts/infer-case-weather.ts public/demo-data/observer-socorro.json --dry-run
npx tsx scripts/refresh-case-weather.ts # every recording whose weather came from a record
Only weatherTrack and weatherSource are rewritten, spliced into the file's text so the diff shows nothing
else. Run sync:cases afterwards.
The editor does not know the fields of the things it edits: each kind of element says what it lets an author set, and a generic form (src/component/ParameterForm.ts) draws it. A kind publishes a ParameterSet (src/engine/interpretation/Parameters.ts): per parameter, a key into the element's JSON (dotted: plume.collarShare), a label and hint as a SaidText (one string per language, English as the fallback), a type (number with required min, max and step, choice, text, boolean, colour), its unit, and optionally effective, the value in force when the element states none (a default, or what other values imply), which the empty field shows greyed. The form follows the project's field rules: it writes on input, puts the unit after the field, and holds a number to its bounds. See LaunchParameters.ts, DecorParameterSets.ts, CloudParameterSets.ts BodyParameterSets.ts and DecorBaseParameterSets.ts for whole kinds (a decor object's floors, windows, a bridge's railing; a catalogue model adds its own through ModelParameters.parameters, written under modelParameters and applied to the file's materials by ModelParameters.bindings — a figure's costume colour, a tree's foliage colour (materials, tinted on copies), an airliner's retracted landing gear (nodes, hidden) — since a model carries its own colours and the plain colour is for the built-in shapes only. test/scripts/ModelParameters.test.ts checks that every binding matches what the file holds; a cloud layer's coverage is stored from 0 to 1 and typed in percent through scale; a body's position, size and attitude at the playhead are edited as a flat view of that instant, which becomes a keyframe: BodyKeyframes), and ParameterRegistry.publish for an asset that brings its own. Adding a field to a kind is adding an entry to its description; adding a kind is a description and a part in the editor that shows it (see LaunchEditor.ts).
npm test # vitest, jsdom, test/**/*.test.ts
npm run test:watch
npx vitest run test/engine/Timeline.test.ts # one file
npx vitest run -t "interpolates" # tests whose name matches
jsdom has no WebGL: render3d tests exercise three.js objects, shaders' inputs and pure logic, not pixels.
What only a real graphics card can tell is checked by the pages under checks/ (see below). A test that passes
both with and without the change it guards protects nothing: check it fails first.
npm run dev
opens the engine demo (index.html, Vite on 5173, or PORT if set): an editor wired to the sources with hot
reload, a sample recording, and a synthetic cloud scenario with the volume/surface renderer switch. Pages under
checks/ are served by the same server:
/checks/atmosphere.html: the sky's GPU tables against the CPU reference and the Monte Carlo skies. Run it after
any change to AtmosphereProfile, SkyScattering or AtmosphereTables, or from a terminal with
node scripts/checks/atmosphere-gpu.mjs.To debug a published recording in the real site rather than in the demo page:
npm run build:site
npm run site:serve # dist-site on http://localhost:5181
and open /play/?sighting=/demo-data/<file>.json (or /edit/?sighting=…). npm run site:watch rebuilds the pages
when site/ or public/demo-data/ change.
Tips:
gl.readPixels() right after a frame instead.The harnesses under scripts/perf/ drive a real Chromium through Playwright, which is not a dependency:
point PLAYWRIGHT_MODULE at an installation. They run headed, since a headless Chromium renders on the CPU and
measures nothing about the card.
| Script | Measures |
|---|---|
scripts/perf/profile-scene.mjs <recording> <out> | a CPU profile of one scene playing (dev server) |
scripts/perf/demo-table.mjs [recordings…] | fps, draws, CPU/GPU time per recording (built site) |
scripts/perf/gpu-breakdown.mjs <recordings…> | GPU time of a still frame, one scene part switched off at a time |
scripts/perf/page-scroll.mjs <url> <label> <seconds> | frame intervals and long tasks while scrolling a page |
Output goes to perf-out/ (gitignored). Each script's header lists its variables. Measure before and after any
rendering change, on the same scene, size and pixel ratio. See docs/performance.md for the
render contract and past findings.
npm run build:all # schema, engine demo, and the three embeds
npm run build:site # the embeds, then ufoathome.org into dist-site/
| Bundle | Config | Output | Registers |
|---|---|---|---|
@rr0/ufoathome/sighting | vite.embed-sighting.config.ts | dist-embed-sighting/rr0-sighting.mjs | <rr0-sighting> (+ <rr0-scene>) |
@rr0/ufoathome/scene | vite.embed-scene.config.ts | dist-embed-scene/rr0-scene.mjs | <rr0-scene> |
@rr0/ufoathome/editor | vite.embed-sighting-editor.config.ts | dist-embed-sighting-editor/rr0-sighting-editor.mjs | <rr0-sighting-editor> (+ <rr0-scene>) |
Each is self-contained (three.js and a star catalogue each) and self-registers on import. Heavy optional parts (the body editor, the JSON editor) are dynamic imports: check they stay separate chunks.
ufoathome.org is generated by site/build.ts from site/content/, one module per page
holding both languages side by side (English at the root, French under /fr/), so a sentence and its
translation cannot drift apart. It is not a Vite build: pages load the embed bundles as they are, under stable
names under /lib/, because they hand out copy-pasteable <script src> lines. The one Vite-built piece is the
Player's JSON editor (site/scripts/jsonEditor.ts, CodeMirror, loaded lazily). _redirects and _headers are
generated into dist-site/ too; do not add them to netlify.toml.
A change to the components' API or to the recording format is documented there, in DocsComponentPage.ts,
DocsFormatPage.ts and friends, in the same commit.
The pages are illustrated with screenshots of the real interface, one WebP per language (the interface shown is in the
reader's language) in site/shots/. site/Shots.ts says which heading each one follows and what its caption is, in the
four languages; the build floats them right and left in turn and fails if a heading or a file is missing.
scripts/site-shots/shots.mjs says how each is taken, and node scripts/site-shots/capture.mjs [--lang fr] [name ...]
takes them from a running dist-site (SITE=http://localhost:3000). The editor needs WebGL, so the capture runs in a
headed Chromium, hence outside the sandbox. Change the interface, retake the shots it appears in.
npm test, then npm run build:site and check the result with npm run site:serve.npm version <patch|minor> --no-git-tag-version, commit the bump as <version>.npm publish (prepublishOnly rebuilds the schema and the three embeds, and runs the tests).git push, then npm run deploy:site: the site is built locally and uploaded to ufoathome.org (Netlify's git
builds are stopped, so a push alone deploys nothing). Needs netlify login or NETLIFY_AUTH_TOKEN.npm run sync:cases and deploy rr0.org.MIT. Third-party data and models keep their own licences: see CREDITS.md and ufoathome.org/docs/sources.
test/Vitest suites mirroring src/ (engine, render, render3d, component, site). |
checks/ | Pages that must run on a real GPU (see Debugging). |
docs/ | Developer notes: performance, past audits. |
doc/web/ | The 2003 Java applet's documentation, kept for history. |
CORDS' CSV export, archived by hand (the site is behind Cloudflare) in scripts/data/reentries/, and scripts/data/satcat.csv |
public/reentries/ (an index, one file per year) |
npm run build:fireballs [traj_summary_all.txt] | Global Meteor Network trajectory summary (CC BY 4.0), the fireballs of absolute magnitude -3 or brighter | scripts/data/gmn/traj_summary_all.txt | public/fireballs/ (an index, one file per month). FRIPON's detections are archived beside it but never published: its site asks to be contacted first |
npm run build:light-pollution <World_Atlas_2015.tif> | World Atlas of the artificial night sky brightness (Falchi et al. 2016, CC BY-NC 4.0: its use on a public site is still to be settled) | the 3 GB GeoTIFF, from GFZ | public/light-pollution/ (small tiles and an index) |
npm run fetch:aircraft [--build] YYYY-MM-DD... then npm run build:aircraft | ADSB.lol open historical data (ODbL), 3 to 4 GB a day | the release parts, fetched into scripts/data/adsb/ (resumable) | scripts/data/adsb/out/, an archive indexed by day, hour and 1° tile, to host as static files |
npm run build:aircraft-demo <archive> <out> <day> <hour> <lat> <lng> | the archive above | one UTC hour of one day, the tiles within 150 km of a place | public/aircraft/, which a demo reads beside the page without the archive being hosted |
npm run build:sky-reference | Monte Carlo (a few minutes) | none | test/engine/atmosphere/sky-reference.json |
npm run build:schema | the recording's TypeScript types | none | src/generated/sightingSchema.json (run automatically before dev, tests and builds) |