From 1a4bc7fd8bf779e07081f13cae49aee9e4e5f025 Mon Sep 17 00:00:00 2001 From: alowpoly Date: Sun, 4 Oct 2026 23:00:19 -0300 Subject: [PATCH 1/4] feat(telescope): add a published picture to a page as one more dataset --- packages/telescope-cli/AGENTS.md | 5 + packages/telescope-cli/README.md | 2 + packages/telescope-cli/src/cli.test.mts | 2 + packages/telescope-cli/src/help.mts | 7 +- packages/telescope-cli/src/new-object/cli.mts | 7 + .../telescope-cli/src/new-object/drafts.mts | 10 +- .../src/new-object/new-object.test.mts | 2 +- .../telescope-cli/src/new-object/orbit.mts | 2 +- .../src/new-object/pictures/esa-image.mts | 64 ++++++ .../src/new-object/pictures/picture-bank.mts | 159 ++++++++++++++ .../src/new-object/pictures/pictures.mts | 140 +++++++++++++ .../src/new-object/pictures/pictures.test.mts | 195 ++++++++++++++++++ .../src/new-object/pictures/registration.mts | 73 +++++++ 13 files changed, 660 insertions(+), 8 deletions(-) create mode 100644 packages/telescope-cli/src/new-object/pictures/esa-image.mts create mode 100644 packages/telescope-cli/src/new-object/pictures/picture-bank.mts create mode 100644 packages/telescope-cli/src/new-object/pictures/pictures.mts create mode 100644 packages/telescope-cli/src/new-object/pictures/pictures.test.mts create mode 100644 packages/telescope-cli/src/new-object/pictures/registration.mts diff --git a/packages/telescope-cli/AGENTS.md b/packages/telescope-cli/AGENTS.md index 8fefa81a04d..c752692a5b6 100644 --- a/packages/telescope-cli/AGENTS.md +++ b/packages/telescope-cli/AGENTS.md @@ -39,6 +39,11 @@ own through `workspace-commands/new-object.mts`, `new-object-cli.mts` is the sta The generated solar geometry (`src/platform/solar-geometry.mts`) stays generated: the entries load it with `solar-epoch.mts` and pass the epoch down, so no module here imports it. +A published picture as one more dataset of a page is `src/new-object/pictures/`: `--from-esa` and a spec's `pictures`. `esa-image.mts` reads +ESA's picture pages and the sky tags in a JPEG, `registration.mts` owns the arithmetic from those tags and one pixel to a recipe's +observation, plane and rim, `picture-bank.mts` writes one entry's records from the bank it is like, and `pictures.mts` drafts, writes +and bakes. It never writes a sentence a reader sees and never picks a value for a color: those are the spec's, written by a person. + The star survey behind `telescope stars GALAXY` is `src/stars/`. It and the generator's `--from-table` route (`src/new-object/archives/tables/table-stars.mts`) read VizieR's table metadata and SIMBAD through the same two modules, `vizier-tables.mts` and `simbad-tap.mts` beside it; a star class is a branch of SIMBAD's own type tree, never a diff --git a/packages/telescope-cli/README.md b/packages/telescope-cli/README.md index f7aff20268c..6df2ac332b7 100644 --- a/packages/telescope-cli/README.md +++ b/packages/telescope-cli/README.md @@ -38,6 +38,8 @@ In a terminal, `explore` shows the observations, unknown metadata, unsupported r `telescope simulations OBJECT` lists the Zenodo dataset records that name the object and speak of a simulation or a model, each with its license, size and files. It downloads nothing, and a listed record is a lead. To show one, read its paper and write an entry for `node packages/telescope-cli/src/new-object/new-object-cli.mts --simulation entries.json` ([simulation-dataset.mts](src/new-object/simulation/simulation-dataset.mts) documents the entry). That command checks the record's license, that it names the object and that it lists the file, and writes the dataset with its labels. It never fetches the release whole: two range requests bring the file's first bytes (its header and coordinate variables) and the bytes of the selected grid into the body's source directory, each declared with its byte range in the source manifest. A 3.5 GB run costs about 130 kB. The [published simulations](../../.agents/skills/celestial-skill/references/scientific-faithfulness.md#published-simulations) rule gives the conditions. +`telescope new-object --from-esa PAGE_ID=PICTURE_URL... --out SPEC.json` drafts a published picture as one more dataset of a page that already shows a shaped layer bank: a picture ESA publishes for Hubble or Webb (`m57=https://esawebb.org/images/weic2320c/`). It reads the picture's page (title, credit, release date, colors) and the sky tags in its JPEG, finds the star the picture shows where the tags put the page's place, and names the bank the picture will lie on like: the one the page opens on. A picture that does not hold the page's place is refused. A person then writes the dataset's sentences and, under `geometry`, what this picture's light takes on those walls: printed values, each with its source. `telescope new-object SPEC.json` writes the new bank's records, the picture, the page's dataset and a README whose measured lines are filled in; `--bake` bakes the banks and their pages in one chain. A spec can be run again after a change, and the README a person wrote is kept. The entry's fields are in [picture-bank.mts](src/new-object/pictures/picture-bank.mts). + `telescope stars GALAXY` counts the stars SIMBAD lists inside a galaxy's catalogued outline by class (Cepheids, RR Lyrae stars, long-period variables, supergiants), names the papers they come from, and reads VizieR's tables of those papers for what a placed star needs: a period and a position of its own. It also names the single stars of no class that SIMBAD holds there with no parallax and no proper motion, the most cited first: a star one paper studied alone (M51-DS1) is often typed a plain star, and is drafted by hand from that paper. Last, it asks the papers API (OpenAlex, with arXiv when OpenAlex's daily budget is spent; the same index `telescope papers` reads) for the works whose title or abstract names the galaxy and a kind of star, those with the star in the title first: SIMBAD and VizieR take months to hold a new paper and never hold some, so a 2026 paper of Cepheids in M61 and M77 and a 2003 paper of one star in NGC 253's halo were found only there. It downloads nothing, and a star SIMBAD lists inside the outline may still be in front of the galaxy. A table it calls ready drafts a star: `telescope new-object --from-table cepheid:m81=J/ApJ/743/176/table1 --out spec.json` writes the spec of one Cepheid of that table, placed where its sight line crosses the disc the galaxy is drawn as ([table-stars.mts](src/new-object/archives/tables/table-stars.mts) documents the row choices). A table that gives every row its galaxy's centre, as a reanalysis does, places its stars at SIMBAD's position of the SIMBAD name CDS added to each row. A table that lists each star by its detector pixel (a chip, X and Y, as the Hubble Cepheid papers do) needs the exposure those pixels were measured on, which only the paper says: `--from-table "cepheid:m66=J/ApJ/529/723/appen#exposure=mast:HST/product/u35i0101r_c0m.fits,firstPixel=1"` reads that chip's header from MAST by byte range (11,520 bytes of a 10 MB file) and places the star where the header's world coordinates put the pixel. `firstPixel` is the coordinate the paper's software gives the centre of the first pixel: 1 for DAOPHOT and ALLFRAME, 0.5 for HSTphot. The position is Hubble's pointing as archived, not registered against a catalogue: on the one exposure checked, a supernova with a catalogued position fell 1.2″ from it ([image-pixel.mts](src/new-object/archives/images/image-pixel.mts)); a hand-written spec does the same with `position.archive: "mast"`. Coordinates a paper prints in a table that neither VizieR nor SIMBAD holds yet are used as printed with `position.archive: "paper"`: the paper is cited by its DOI and nothing is archived. When you know the scientific acceptance criteria, save an explicit request: diff --git a/packages/telescope-cli/src/cli.test.mts b/packages/telescope-cli/src/cli.test.mts index 11f592e2d63..0521929d4dd 100644 --- a/packages/telescope-cli/src/cli.test.mts +++ b/packages/telescope-cli/src/cli.test.mts @@ -83,6 +83,8 @@ test('new-object bakes a spec after generating it, or objects already in the tre const draft=parseCli(['new-object','--from-debcat','47 Tuc V69','CM Dra','--out','spec.json']);assert.equal(draft.command,'new-object');if(draft.command!=='new-object')return; assert.deepEqual([draft.from,draft.names],['debcat',['47 Tuc V69','CM Dra']]); assert.throws(()=>parseCli(['new-object','--from-apokasc','--out','spec.json']),/--from-apokasc NAME\.\.\. --out SPEC\.json/u); + const picture=parseCli(['new-object','--from-esa','m57=https://esawebb.org/images/weic2320c/','--out','spec.json']);assert.equal(picture.command,'new-object');if(picture.command!=='new-object')return; + assert.deepEqual([picture.from,picture.names],['esa',['m57=https://esawebb.org/images/weic2320c/']]); }); test('local import has one bounded data-only entry point',()=>{ const parsed=parseCli(['import','spec.json','--out','run','--json']);assert.equal(parsed.command,'import');if(parsed.command!=='import')return; diff --git a/packages/telescope-cli/src/help.mts b/packages/telescope-cli/src/help.mts index 8d06858ec53..555fa4d9eb3 100644 --- a/packages/telescope-cli/src/help.mts +++ b/packages/telescope-cli/src/help.mts @@ -20,7 +20,7 @@ Human entry points: telescope leads TARGET | --class CLASS [--json] [--out DIRECTORY] telescope stars GALAXY [--json] [--out DIRECTORY] telescope new-object SPEC.json [--check] [--skip-existing] [--json] - telescope new-object --from-archive HOST... | --from-debcat SYSTEM... | --from-apokasc KIC... | --from-cepheids NAME... | --from-k2 EPIC... | --from-tess TIC... | --from-gaia SOURCE_ID... | --from-hipparcos HIP... | --from-iau all|NAME... | --from-chara HD... | --from-npoi HD... | --from-sh0es HOST[/ID]... | --from-m31cepheids all|V1|ID... | --from-m33cepheids all|ID... | --from-table CLASS:GALAXY=TABLE[#ROW]... --out SPEC.json + telescope new-object --from-archive HOST... | --from-debcat SYSTEM... | --from-apokasc KIC... | --from-cepheids NAME... | --from-k2 EPIC... | --from-tess TIC... | --from-gaia SOURCE_ID... | --from-hipparcos HIP... | --from-iau all|NAME... | --from-chara HD... | --from-npoi HD... | --from-sh0es HOST[/ID]... | --from-m31cepheids all|V1|ID... | --from-m33cepheids all|ID... | --from-table CLASS:GALAXY=TABLE[#ROW]... | --from-esa PAGE_ID=PICTURE_URL... --out SPEC.json telescope ascl SOFTWARE [--json] telescope ascl --product PRODUCT.json|RUN/pick-N/result.json [--json] telescope wwt-fits EXPLORE.json --pick N --level N --x X --y Y --out DIRECTORY @@ -50,7 +50,10 @@ Only prose is left marked TODO(new-object), unless the spec carries drafted text NASA Exoplanet Archive's default parameter sets (their transiting planets, with drafted text); --from-debcat drafts both stars of an eclipsing binary from DEBCat, --from-apokasc a Kepler-field giant from APOKASC-3, --from-cepheids a Cepheid from Groenewegen (2013), --from-k2 a K2-field giant and --from-tess a TESS giant from Khan et al. (2023), --from-gaia any star from Gaia DR3 FLAME, --from-hipparcos a Hipparcos star from the model-atmosphere fit to its light (McDonald et al. 2017), --from-iau the stars the IAU has named that the universe lacks, each by the first of those routes that measures it, --from-chara a nearby star whose disc CHARA measured (Boyajian et al. 2012), --from-npoi a bright star whose disc the NPOI measured (Baines et al. 2018, 2021), --from-sh0es the Cepheids Hubble found in a SN Ia host galaxy (Hoffmann et al. 2016), --from-m31cepheids Hubble's V1 and the Cepheids Hubble measured in Andromeda (Li et al. 2021), --from-m33cepheids those it measured in Triangulum (Breuval et al. 2023), --from-table a star of another galaxy from any VizieR table that lists it with a period (cepheid:m81=J/ApJ/743/176/table1), placed in its galaxy by the table's position, by SIMBAD's, or by the table's detector pixel on the exposure the request names (#exposure=mast:HST/product/FILE.fits,firstPixel=N), each naming what the spec still needs from the paper; --check runs the bake's first steps on -what was generated; --skip-existing leaves objects already in the universe alone. The spec format is in packages/telescope-cli/src/new-object/spec.mts. +what was generated; --skip-existing leaves objects already in the universe alone. --from-esa drafts a picture ESA publishes for Hubble or Webb as one more +dataset of a page that shows a shaped layer bank (m57=https://esawebb.org/images/weic2320c/): it reads the picture's page and the sky tags in its JPEG, finds the +star the picture shows at the page's place, and leaves the sentences and what each color takes on the bank's walls to write; a spec of pictures writes each +picture's bank and its page's dataset, may be run again, and bakes with SPEC.json --bake. The spec format is in packages/telescope-cli/src/new-object/spec.mts. Papers lists up to 20 OpenAlex works that name the target, by any spelling of its catalogue names, in their title or abstract, with the instrument and any one of the --about phrases (singular or plural); --fulltext asks for the works whose indexed full text names them. It uses arXiv's Atom API when OpenAlex is unavailable or its daily budget is spent, and the diff --git a/packages/telescope-cli/src/new-object/cli.mts b/packages/telescope-cli/src/new-object/cli.mts index 14a87c76bb1..5f61dc624f4 100644 --- a/packages/telescope-cli/src/new-object/cli.mts +++ b/packages/telescope-cli/src/new-object/cli.mts @@ -22,6 +22,8 @@ export function parseNewObjectOptions(value:unknown):NewObjectOptions{ return {...string('spec'),...strings('ids'),...string('from'),...strings('names'),...string('out'),check:flag('check'),bake:flag('bake'),refresh:flag('refresh'),skipExisting:flag('skipExisting'),json:flag('json')}; } +const holdsPictures=async(spec:string)=>{const {readFile}=await import('node:fs/promises'),value:unknown=JSON.parse(await readFile(spec,'utf8'));return typeof value==='object'&&value!==null&&'pictures' in value;}; + /** The result text and exit code for one parsed `new-object` command. */ export async function newObjectCommand(options:NewObjectOptions,root:string,stderr:(text:string)=>void):Promise<{readonly text:string;readonly code:number}>{ let text:string,code:number; @@ -38,6 +40,11 @@ export async function newObjectCommand(options:NewObjectOptions,root:string,stde }else if(options.from){ const result=await writeDrafts(options.from,options.names??[],options.out!,{root,archive:liveArchive,progress:line=>stderr(`${line}\n`)}); text=options.json?`${JSON.stringify(result)}\n`:`${result.report.join('\n')}\n${result.entries} entries written to ${result.path}\n`;code=result.entries?0:3; + }else if(await holdsPictures(options.spec!)){ + // A spec of published pictures: each one a dataset on a page that shows a shaped layer bank (pictures/pictures.mts). + const {runPictures,bakePictures,formatPictures}=await import('./pictures/pictures.mts'),results=await runPictures(options.spec!,{root,archive:liveArchive,progress}),good=results.filter(result=>!result.failed); + const baked=options.bake&&good.length?await bakePictures(good,{root,progress}):true; + text=options.json?`${JSON.stringify(results)}\n`:formatPictures(results,options.spec!,baked&&options.bake&&good.length>0);code=baked&&good.length===results.length?0:1; }else{ const results=await runNewObject(options.spec!,{root,progress:line=>stderr(`${line}\n`),skipExisting:options.skipExisting,solarEpoch:await loadSolarEpoch(root)}); const good=results.filter(result=>!result.failed).map(result=>result.id),baked=(options.check||options.bake)&&good.length?await prepareObjects(good,{root,progress,...(options.bake?{}:{to:'page'})}):true; diff --git a/packages/telescope-cli/src/new-object/drafts.mts b/packages/telescope-cli/src/new-object/drafts.mts index 3bfe7de288e..6e08f7a1961 100644 --- a/packages/telescope-cli/src/new-object/drafts.mts +++ b/packages/telescope-cli/src/new-object/drafts.mts @@ -5,7 +5,7 @@ import { mkdir, writeFile } from 'node:fs/promises'; import { dirname, resolve } from 'node:path'; import type { Archive } from './archives/archives.mts'; -export interface Drafts { readonly stars: readonly unknown[]; readonly report: readonly string[] } +export interface Drafts { readonly stars: readonly unknown[]; readonly pictures?: readonly unknown[]; readonly report: readonly string[] } interface Context { readonly root: string; readonly progress: (line: string) => void; readonly archive: Archive } export const DRAFT_ROUTES: Readonly Promise }>> = { // Transiting planet hosts from the NASA Exoplanet Archive's default parameter sets (from-archive.mts). @@ -38,6 +38,8 @@ export const DRAFT_ROUTES: Readonly (await import('./archives/m33-cepheids.mts')).draftsFromM33Cepheids(names, archive, root) }, // A star of another galaxy from any VizieR table that lists it with a position and a period (tables/table-stars.mts); `telescope stars GALAXY` finds the tables. table: { names: 'CLASS:GALAXY=TABLE[#ROW]', draft: async (names, { archive, root }) => (await import('./archives/tables/table-stars.mts')).draftsFromTable(names, archive, root) }, + // A picture ESA publishes for Hubble or Webb, as one more dataset of a page that shows a shaped layer bank (pictures/pictures.mts). + esa: { names: 'HOST=PAGE_URL', draft: async (names, context) => (await import('./pictures/pictures.mts')).draftsFromEsa(names, context) }, }; /** Draft `names` through `route` and write the spec file at `out`. */ @@ -45,7 +47,7 @@ export async function writeDrafts(route: string, names: readonly string[], out: const source = DRAFT_ROUTES[route]; if (!source) throw new TypeError(`No draft route ${route}; the routes are ${Object.keys(DRAFT_ROUTES).map(key => `--from-${key}`).join(', ')}.`); if (!names.length) throw new TypeError(`Usage: new-object --from-${route} ${source.names}... --out spec.json`); - const { stars, report } = await source.draft(names, context), path = resolve(context.root, out); - await mkdir(dirname(path), { recursive: true }); await writeFile(path, `${JSON.stringify({ stars }, null, 2)}\n`); - return { path, entries: stars.length, report }; + const { stars, pictures, report } = await source.draft(names, context), path = resolve(context.root, out); + await mkdir(dirname(path), { recursive: true }); await writeFile(path, `${JSON.stringify(pictures ? { pictures } : { stars }, null, 2)}\n`); + return { path, entries: (pictures ?? stars).length, report }; } diff --git a/packages/telescope-cli/src/new-object/new-object.test.mts b/packages/telescope-cli/src/new-object/new-object.test.mts index eceee79d670..5d5c223337b 100644 --- a/packages/telescope-cli/src/new-object/new-object.test.mts +++ b/packages/telescope-cli/src/new-object/new-object.test.mts @@ -865,7 +865,7 @@ test('APOKASC-3 and Groenewegen (2013) rows draft single stars through the one r const { physicalValues } = await import('./generate.mts'), values = physicalValues(measured, { sourceId: '1', ra: 0, dec: 0, g: 13, hasXpSampled: false }); assert.deepEqual([values.gm, values.logg], [0, 1.2]); assert.match(values.massText, /No mass is measured, so GM is 0/u); - assert.deepEqual(Object.keys(DRAFT_ROUTES), ['archive', 'debcat', 'apokasc', 'cepheids', 'k2', 'tess', 'gaia', 'hipparcos', 'iau', 'chara', 'npoi', 'sh0es', 'm31cepheids', 'm33cepheids', 'table']); + assert.deepEqual(Object.keys(DRAFT_ROUTES), ['archive', 'debcat', 'apokasc', 'cepheids', 'k2', 'tess', 'gaia', 'hipparcos', 'iau', 'chara', 'npoi', 'sh0es', 'm31cepheids', 'm33cepheids', 'table', 'esa']); await assert.rejects(writeDrafts('gcvs', ['X'], 'output/x.json', { root, progress: () => {}, archive: {} as Archive }), /No draft route gcvs; the routes are --from-archive, --from-debcat, --from-apokasc, --from-cepheids, --from-k2, --from-tess, --from-gaia/u); }); diff --git a/packages/telescope-cli/src/new-object/orbit.mts b/packages/telescope-cli/src/new-object/orbit.mts index 9bdd099ea3f..1825c6976ff 100644 --- a/packages/telescope-cli/src/new-object/orbit.mts +++ b/packages/telescope-cli/src/new-object/orbit.mts @@ -20,7 +20,7 @@ export interface HostedOrbit { } const round = (value: number, digits: number) => Number(value.toFixed(digits)); /** The archive writes reference labels as HTML: accented author names arrive as entities. */ -const NAMED_ENTITIES: Record = { amp: '&', lt: '<', gt: '>', quot: '"', apos: "'", nbsp: ' ', aacute: 'á', eacute: 'é', iacute: 'í', oacute: 'ó', uacute: 'ú', agrave: 'à', egrave: 'è', ntilde: 'ñ', uuml: 'ü', ouml: 'ö', auml: 'ä', ccedil: 'ç', szlig: 'ß', oslash: 'ø', aring: 'å', Aacute: 'Á', Eacute: 'É', Oslash: 'Ø', ecirc: 'ê', ocirc: 'ô', acirc: 'â', scaron: 'š', zcaron: 'ž', ccaron: 'č' }; +const NAMED_ENTITIES: Record = { amp: '&', lt: '<', gt: '>', quot: '"', apos: "'", nbsp: ' ', aacute: 'á', eacute: 'é', iacute: 'í', oacute: 'ó', uacute: 'ú', agrave: 'à', egrave: 'è', ntilde: 'ñ', uuml: 'ü', ouml: 'ö', auml: 'ä', ccedil: 'ç', szlig: 'ß', oslash: 'ø', aring: 'å', Aacute: 'Á', Eacute: 'É', Oslash: 'Ø', ecirc: 'ê', ocirc: 'ô', acirc: 'â', scaron: 'š', zcaron: 'ž', ccaron: 'č', mu: 'µ', deg: '°' }; export const decodeEntities = (text: string) => text.replace(/&(#x[0-9a-f]+|#\d+|[a-zA-Z]+);/gu, (whole, code: string) => code.startsWith('#x') ? String.fromCodePoint(parseInt(code.slice(2), 16)) : code.startsWith('#') ? String.fromCodePoint(Number(code.slice(1))) : NAMED_ENTITIES[code] ?? whole); const mod360 = (value: number) => ((value % 360) + 360) % 360; diff --git a/packages/telescope-cli/src/new-object/pictures/esa-image.mts b/packages/telescope-cli/src/new-object/pictures/esa-image.mts new file mode 100644 index 00000000000..7255083c620 --- /dev/null +++ b/packages/telescope-cli/src/new-object/pictures/esa-image.mts @@ -0,0 +1,64 @@ +/** A picture ESA publishes for Hubble or Webb (esahubble.org, esawebb.org): what its page says of it, and the sky tags + * its JPEG carries. The page gives the title, the credit, the release date and the colors; the file gives its own size, + * and in its embedded Astronomy Visualization Metadata the scale, the direction of north and one place on the sky. */ +import { decodeEntities } from '../orbit.mts'; +import type { Archive } from '../archives/archives.mts'; + +/** A JPEG's sky tags, for the file as downloaded: degrees a pixel, north's turn counter-clockwise from up, and the sky + * place (right ascension, declination) of one pixel, counted from the picture's bottom left. */ +export interface SkyTags { readonly scaleDeg: number; readonly rotationDeg: number; readonly reference: readonly [number, number]; readonly referencePixel: readonly [number, number] } +export interface PictureColor { readonly band: string; readonly shown: string; readonly line?: string; readonly wavelength: string; readonly instrument: string } +export interface EsaPage { readonly id: string; readonly telescope: 'Hubble' | 'Webb'; readonly page: string; readonly download: string; readonly rights: string; + readonly title: string; readonly credit: string; readonly released: string; readonly original: readonly [number, number]; readonly colors: readonly PictureColor[] } + +const SITES: Readonly> = { 'esahubble.org': 'Hubble', 'esawebb.org': 'Webb' }; +const words = (html: string) => decodeEntities(html.replace(/<[^>]*>/gu, ' ')).replace(/\s+/gu, ' ').trim(); + +/** The picture a page address names: `https://esawebb.org/images/weic2320c/`. */ +export function esaPictureAddress(address: string): Pick { + const found = /^https:\/\/(esahubble\.org|esawebb\.org)\/images\/([a-z0-9-]+)\/?$/u.exec(address); + if (!found) throw new TypeError(`${JSON.stringify(address)} is not a picture's page at esahubble.org or esawebb.org (https://esawebb.org/images//).`); + const [, site, id] = found as unknown as [string, string, string]; + return { id, telescope: SITES[site]!, page: `https://${site}/images/${id}/`, download: `https://cdn.${site}/archives/images/large/${id}.jpg`, rights: `https://${site}/copyright/` }; +} + +/** What a picture's page says of it. A field the page lacks is refused by name: the generator writes none of them itself. */ +export function parseEsaPage(address: string, html: string): EsaPage { + const picture = esaPictureAddress(address), lacks = (what: string): never => { throw new TypeError(`${picture.page}: the page has no ${what} to read.`); }; + const lines = html.replace(//gu, '').replace(/<[^>]*>/gu, '\n').split('\n').map(words).filter(Boolean); + const after = (label: string) => lines[lines.indexOf(label) + 1] ?? ''; + const title = words(/([^<]*)<\/title>/u.exec(html)?.[1] ?? '').split(' | ')[0]! || lacks('title'); + const credit = words(/<div class="credit">([\s\S]*?)<\/div>/u.exec(html)?.[1] ?? '').replace(/\.$/u, '') || lacks('credit'); + const size = /^(\d+) x (\d+) px$/u.exec(lines.includes('Size:') ? after('Size:') : '') ?? lacks('"Size: W x H px"'); + const released = /^\d{1,2} [A-Z][a-z]+ \d{4}/u.exec(lines.includes('Release date:') ? after('Release date:') : '')?.[0] ?? lacks('release date'); + // The colors table: a row is the band with the color it is shown in and the line's name where the page gives one, the wavelength, and the telescope with its instrument. + const table = /<h3[^>]*>Colours &(?:amp;)? filters<\/h3>\s*<table[\s\S]*?<\/table>/u.exec(html)?.[0] ?? '', colors: PictureColor[] = []; + for (const row of table.matchAll(/<tr>([\s\S]*?)<\/tr>/gu)) { + const cells = [...row[1]!.matchAll(/<td>([\s\S]*?)<\/td>/gu)].map(cell => cell[1]!); + if (cells.length !== 3) continue; + const [band, wavelength, facility] = cells as [string, string, string], line = words(/class="band_instrument">([\s\S]*?)<\/span>/u.exec(band)?.[1] ?? ''); + const [, instrument = ''] = facility.split(/<br\s*\/?>/u).map(words); + colors.push({ band: words(band).split(' ')[0]!, shown: /class="band_([A-Za-z]+)"/u.exec(band)?.[1] ?? '', ...(line ? { line } : {}), wavelength: words(wavelength), instrument }); + } + if (!colors.length) lacks('"Colours & filters" table'); + return { ...picture, title, credit, released, original: [Number(size[1]), Number(size[2])], colors }; +} + +/** The sky tags in a JPEG's bytes, for a file `width` pixels across: a publisher's smaller copy carries the tags of its + * original, whose scale and reference pixel are brought to this file's own pixels. */ +export function skyTags(bytes: Buffer, width: number, height: number, name: string): SkyTags { + const text = bytes.toString('latin1'); + const tag = (key: string, count: number) => { const found = new RegExp(`<avm:${key}>([\\s\\S]*?)</avm:${key}>`, 'u').exec(text) ?? new RegExp(`avm:${key}="([^"]*)"`, 'u').exec(text); + const values = found?.[1]!.replace(/<[^>]+>/gu, ' ').trim().split(/\s+/u).map(Number) ?? []; + if (values.length < count || !values.slice(0, count).every(Number.isFinite)) throw new TypeError(`${name} carries no avm:${key}: the picture has no sky tags to place it by.`); + return values; }; + const [taggedWidth, taggedHeight] = tag('Spatial.ReferenceDimension', 2) as [number, number], shrink = taggedWidth / width; + if (Math.abs(taggedHeight / shrink - height) > 1) throw new TypeError(`${name} is ${width} x ${height} px; its sky tags describe ${taggedWidth} x ${taggedHeight}, another shape.`); + const pixel = tag('Spatial.ReferencePixel', 2), place = tag('Spatial.ReferenceValue', 2); + return { scaleDeg: Math.abs(tag('Spatial.Scale', 1)[0]!) * shrink, rotationDeg: tag('Spatial.Rotation', 1)[0]!, reference: [place[0]!, place[1]!], referencePixel: [pixel[0]! / shrink, pixel[1]! / shrink] }; +} + +/** A picture's page, read through the telescope's archive transfer. */ +export async function readEsaPage(address: string, archive: Archive): Promise<EsaPage> { + return parseEsaPage(address, await archive.text(esaPictureAddress(address).page)); +} diff --git a/packages/telescope-cli/src/new-object/pictures/picture-bank.mts b/packages/telescope-cli/src/new-object/pictures/picture-bank.mts new file mode 100644 index 00000000000..0d6fac4f1aa --- /dev/null +++ b/packages/telescope-cli/src/new-object/pictures/picture-bank.mts @@ -0,0 +1,159 @@ +/** One published picture as a dataset of a page that already shows a shaped layer bank. A spec entry names the page, the + * picture and the bank whose walls, surface or rings the picture lies on (`like`); the records of the new bank are that + * bank's with this picture's own registration, and the page gains a dataset. The generator reads and computes: every + * sentence a reader sees (the dataset's title and text, what is chosen and why) is the spec's, written by a person. */ +import { isRecord, requireArray, requireFiniteNumber, requireRecord, requireString } from '@cssearth/core'; +import { INVESTIGATION_LEDGER_SCHEMA, OBJECT_SCHEMA, PREPARED_IMAGE_LAYER_BANK_SCHEMA } from '@cssearth/objects'; +import { json, type PackageFiles } from '../dataset.mts'; +import { TODO } from '../scaffold.mts'; +import type { EsaPage, PictureColor, SkyTags } from './esa-image.mts'; +import { registerPicture, RIM_FROM, type Place, type Registration } from './registration.mts'; + +/** A layer bank's own dataset is named `optical` whatever its light: the page's dataset carries the reader's name for it. */ +export const BANK_DATASET = 'optical'; +/** The widest face a picture is baked at unless its entry says otherwise: the Ring Nebula's near-infrared bank is 4.9 MB at + * this size (2026-10-04). */ +export const FACE_PIXELS = 1500; +const LICENSE = 'CC-BY-4.0', ID = /^[a-z0-9]+(?:-[a-z0-9]+)*$/u, STATUSES = ['included', 'excluded', 'deferred'] as const; + +/** A source an entry cites; `checked` is the day a person read it, the run's day when absent. */ +export interface PictureSource { readonly catalogueId: string; readonly url: string; readonly label: string; readonly locator: string; readonly checked?: string } +export interface LedgerEntry { readonly id: string; readonly subject: string; readonly status: typeof STATUSES[number]; readonly finding: string; readonly evidence: readonly string[] } +export interface PictureEntry { + readonly host: string; readonly image: string; readonly bank: string; readonly like: string; + readonly dataset: { readonly id: string; readonly label: string; readonly title: string; readonly summary: string; readonly description: string }; + /** The wavelengths the picture shows; the page's own table when absent. */ + readonly colors?: readonly string[]; + /** The pixel, from the picture's top left, of the star that stands at the page's place; the tags' own pixel when absent. */ + readonly star?: readonly [number, number]; + /** How that star was found in the picture, as a draft reports it: "the largest patch of saturated pixels within 1 arcsec, 29 px". */ + readonly starFound?: string; + readonly facePixels?: number; + /** Laid over the like bank's recipe geometry: the values this picture's light takes on the same walls; null removes one. */ + readonly geometry?: Readonly<Record<string, unknown>>; + readonly displayModel?: string; + readonly sources: readonly PictureSource[]; readonly ledger: readonly LedgerEntry[]; +} +type Json = Record<string, unknown>; +export interface PictureInputs { + readonly page: EsaPage; readonly tags: SkyTags; readonly dimensions: readonly [number, number]; + /** Where the tags alone put the recipe's target, and how the entry's star was found when the draft found it. */ + readonly tagged: readonly [number, number]; + readonly like: { readonly recipe: Json; readonly manifest: Json; readonly presentation: Json; readonly provenance: Json }; + readonly host: { readonly content: Json; readonly text: Json }; + readonly checked: string; +} + +/** A spec file's `pictures`. An entry a draft left unfinished is refused by the field still to write. */ +export function parsePictures(value: unknown): PictureEntry[] { + const entries = requireArray(requireRecord(value, 'picture spec').pictures, 'pictures').map((entry, index): PictureEntry => { + const at = `pictures[${index}]`, input = requireRecord(entry, at), text = (record: Json, key: string, where: string) => requireString(record[key], `${where}.${key}`).trim(); + const unwritten = (found: unknown, where: string): void => { if (typeof found === 'string' && found.includes('TODO(')) throw new TypeError(`${where} is still to write: ${found}`); + if (Array.isArray(found)) found.forEach((one, i) => unwritten(one, `${where}[${i}]`)); else if (isRecord(found)) for (const [key, one] of Object.entries(found)) unwritten(one, `${where}.${key}`); }; + unwritten(input, at); + const id = (key: string) => { const found = text(input, key, at); if (!ID.test(found)) throw new TypeError(`${at}.${key} ${JSON.stringify(found)} is not an object id (lower case, digits, hyphens).`); return found; }; + const dataset = requireRecord(input.dataset, `${at}.dataset`), datasetId = text(dataset, 'id', `${at}.dataset`); + if (!ID.test(datasetId)) throw new TypeError(`${at}.dataset.id ${JSON.stringify(datasetId)} is not a dataset id (lower case, digits, hyphens).`); + const pair = (found: unknown, where: string) => { const list = requireArray(found, where).map(one => requireFiniteNumber(one, where)); if (list.length !== 2) throw new TypeError(`${where} must be two numbers: x and y from the picture's top left.`); return [list[0]!, list[1]!] as const; }; + return { host: id('host'), image: text(input, 'image', at), bank: id('bank'), like: id('like'), + dataset: { id: datasetId, label: text(dataset, 'label', `${at}.dataset`), title: text(dataset, 'title', `${at}.dataset`), summary: text(dataset, 'summary', `${at}.dataset`), description: text(dataset, 'description', `${at}.dataset`) }, + ...(input.colors === undefined ? {} : { colors: requireArray(input.colors, `${at}.colors`).map(one => requireString(one, `${at}.colors`)) }), + ...(input.star === undefined ? {} : { star: pair(input.star, `${at}.star`) }), ...(input.starFound === undefined ? {} : { starFound: text(input, 'starFound', at) }), + ...(input.facePixels === undefined ? {} : { facePixels: requireFiniteNumber(input.facePixels, `${at}.facePixels`) }), + ...(input.geometry === undefined ? {} : { geometry: requireRecord(input.geometry, `${at}.geometry`) }), + ...(input.displayModel === undefined ? {} : { displayModel: text(input, 'displayModel', at) }), + sources: (input.sources === undefined ? [] : requireArray(input.sources, `${at}.sources`)).map((one, i) => { const where = `${at}.sources[${i}]`, source = requireRecord(one, where); + return { catalogueId: text(source, 'catalogueId', where), url: text(source, 'url', where), label: text(source, 'label', where), locator: text(source, 'locator', where), ...(source.checked === undefined ? {} : { checked: text(source, 'checked', where) }) }; }), + ledger: (input.ledger === undefined ? [] : requireArray(input.ledger, `${at}.ledger`)).map((one, i) => { const where = `${at}.ledger[${i}]`, row = requireRecord(one, where), status = text(row, 'status', where) as LedgerEntry['status']; + if (!STATUSES.includes(status)) throw new TypeError(`${where}.status must be one of ${STATUSES.join(', ')}.`); + return { id: text(row, 'id', where), subject: text(row, 'subject', where), status, finding: text(row, 'finding', where), evidence: requireArray(row.evidence, `${where}.evidence`).map(link => requireString(link, `${where}.evidence`)) }; }) }; + }); + const repeated = entries.map(entry => entry.bank).filter((bank, index, all) => all.indexOf(bank) !== index); + if (repeated.length) throw new TypeError(`Picture banks repeat: ${repeated.join(', ')}.`); + return entries; +} + +/** The wavelengths a page's table lists, in its order, each once; and a list of them as a reader's phrase: "7.7, 12 and 18 µm". */ +export const pageColors = (colors: readonly PictureColor[]) => [...new Set(colors.map(color => color.wavelength))]; +export function colorsPhrase(colors: readonly string[]) { + const parts = colors.map(color => /^(\S+) (\S+)$/u.exec(color)), unit = parts[0]?.[2], shared = parts.every(part => part && part[2] === unit) && colors.length > 1; + const list = shared ? parts.map(part => part![1]!) : [...colors]; + return `${list.length > 1 ? `${list.slice(0, -1).join(', ')} and ${list.at(-1)}` : list[0] ?? ''}${shared ? ` ${unit}` : ''}`; +} +export const pictureRecordId = (page: Pick<EsaPage, 'id' | 'telescope'>) => `esa${page.telescope.toLowerCase()}-${page.id}`; + +/** `over` laid on `base`, key by key: a record goes into the record under it, any other value takes its place, and null removes it. */ +const lay = (base: Json, over: Readonly<Record<string, unknown>>): Json => { for (const [key, value] of Object.entries(over)) { if (value === null) delete base[key]; else base[key] = isRecord(value) && isRecord(base[key]) ? lay({ ...base[key] }, value) : value; } return base; }; +const copy = <T,>(value: T): T => structuredClone(value); + +/** Every record of one picture's bank and its page's dataset; `carried` are the like bank's other inputs, to copy beside + * the picture. `readme` is written only where the bank has none. */ +export function pictureFiles(entry: PictureEntry, inputs: PictureInputs): { readonly files: PackageFiles; readonly readme: string; readonly carried: readonly { readonly from: string; readonly to: string }[]; readonly registration: Registration; readonly todo: readonly string[] } { + const { page, tags, dimensions: [width, height], like, host, checked } = inputs, { bank, dataset } = entry, files: PackageFiles = new Map(), at = `src/objects/${bank}`, likeAt = `src/objects/${entry.like}/`; + const likeRecipe = copy(like.recipe), target = requireRecord(likeRecipe.target, `${entry.like} recipe target`) as unknown as Place, likeSource = requireRecord(likeRecipe.source, `${entry.like} recipe source`); + const star = entry.star ?? inputs.tagged, registration = registerPicture(tags, [width, height], star, target), { observation, plane, pixelArcsec, circleArcsec } = registration; + const publisher = `ESA/${page.telescope}`, record = pictureRecordId(page), colors = entry.colors ?? pageColors(page.colors), instruments = [...new Set(page.colors.map(color => color.instrument).filter(Boolean))]; + const pixels = `${width} × ${height}`, field = `${(observation.fieldOfViewDeg[0] * 60).toFixed(2)} × ${(observation.fieldOfViewDeg[1] * 60).toFixed(2)} arcmin`, shown = `${instruments.join(' and ')} at ${colorsPhrase(colors)}`; + const direction = `${pixelArcsec.toFixed(4)} arcsec per pixel and north ${Math.abs(tags.rotationDeg).toFixed(1)}° ${tags.rotationDeg >= 0 ? 'left' : 'right'} of vertical`, centre = `${observation.centerRaDeg}°, ${observation.centerDecDeg}°`; + const fromTags = (Math.hypot(star[0] - inputs.tagged[0], star[1] - inputs.tagged[1]) * pixelArcsec).toFixed(2); + const registered = entry.star + ? `The file's embedded sky tags for scale and direction, ${direction}, and the star for place: the star in the picture, ${entry.starFound ? `${entry.starFound}, ` : ''}pixel ${star.join(', ')}, is set at the recipe's target, so the frame's centre is ${centre}. The tags alone put the star ${fromTags} arcsec from where the picture shows it.` + : `The file's embedded sky tags, used as they are: ${direction}, the frame's centre at ${centre}. Not measured against a star here.`; + const mark = entry.star ? 'the star' : 'the recipe\'s target', rim = `between ${(RIM_FROM * circleArcsec).toFixed(1)} and ${circleArcsec} arcsec from ${mark}`; + + // The bank: the like bank's recipe with this picture, its registration and what the entry lays over the geometry. + const recipe = { ...likeRecipe, id: bank, source: { path: 'source.jpg', dimensions: [width, height], originalDimensions: page.original, publisherUrl: page.page, downloadUrl: page.download, credit: page.credit, license: LICENSE }, observation, + geometry: lay({ ...requireRecord(likeRecipe.geometry, `${entry.like} recipe geometry`), ...plane }, entry.geometry ?? {}), + bake: { ...requireRecord(likeRecipe.bake, `${entry.like} recipe bake`), maxFacePixels: entry.facePixels ?? Math.min(Math.max(width, height), FACE_PIXELS) } }; + files.set(`${at}/source/recipe.json`, json(recipe)); + files.set(`${at}/object.json`, json({ schema: OBJECT_SCHEMA, id: bank, type: 'image-layer-bank', properties: { preparation: { source: 'source/recipe.json' }, host: entry.host }, prepared: { format: PREPARED_IMAGE_LAYER_BANK_SCHEMA, url: 'prepared/image-layers.json' } })); + + // The manifest: the picture, then every other input the like bank reads, each beside this bank. + const likePicture = `${likeAt}source/${requireString(likeSource.path, `${entry.like} recipe source.path`)}`, moved = (path: unknown) => requireString(path, `${entry.like} manifest path`).replace(likeAt, `${at}/`); + const others = requireArray(like.manifest.inputs, `${entry.like} manifest inputs`).map(input => requireRecord(input, `${entry.like} manifest input`)).filter(input => input.path !== likePicture); + const manifest = { ...copy(like.manifest), inputs: [{ id: BANK_DATASET, path: `${at}/source/source.jpg`, origin: page.download, sourceUrl: page.page, title: page.title, credit: page.credit, displayCredit: publisher, + acquisition: `The publisher's JPEG (${width} x ${height} px), downloaded unchanged; not tracked. Its scale and direction on the sky are the file's embedded tags; its place is ${entry.star ? 'set by the star' : 'the tags\' own'} (recipe observation). A display composite, not a calibrated scientific array.`, + sourceBinding: { kind: 'catalogued', references: [{ catalogueId: record, role: 'material', evidence: `${at}/source/provenance.json` }] }, dependencies: [], datasetId: BANK_DATASET, license: `${LICENSE}; retain the complete recorded credit.`, + capture: { attributions: [{ kind: 'facility', facilityId: page.telescope.toLowerCase(), evidence: page.page }] } }, ...others.map(input => ({ ...input, path: moved(input.path) }))], + documents: requireArray(like.manifest.documents, `${entry.like} manifest documents`).map(document => { const one = requireRecord(document, `${entry.like} manifest document`); return { ...one, path: moved(one.path) }; }), generatedIntermediates: [] }; + files.set(`${at}/source/manifest.json`, json(manifest)); + files.set(`${at}/source/presentation.json`, json({ ...copy(like.presentation), objectId: bank, defaultDataset: BANK_DATASET, bank: { path: `${at}/prepared/image-layers.json` }, + recipes: [{ id: 'image-layer-recipe', path: `${at}/source/recipe.json` }, { id: 'source-evidence', path: `${at}/source/provenance.json` }], sharedInputs: [], + datasets: [{ id: BANK_DATASET, label: dataset.label, title: dataset.title, description: dataset.description, summary: dataset.summary, detail: `${pixels} px`, + facts: [{ id: 'bands', label: 'Colors', value: colorsPhrase(colors) }, { id: 'source-pixels', label: 'Source pixels', value: pixels }, { id: 'coverage', label: 'Field', value: field }, { id: 'license', label: 'License', value: LICENSE }], + input: BANK_DATASET, preview: { path: `${at}/source/source.jpg`, url: page.download } }] })); + const displayModel = entry.displayModel ?? requireString(like.provenance.displayModel, `${entry.like} provenance displayModel`); + files.set(`${at}/source/provenance.json`, json({ schema: 'cssearth-image-layer-provenance@1', title: page.title, publisher, sourceId: page.id, sourcePage: page.page, download: page.download, credit: page.credit, license: LICENSE, + original: { dimensions: page.original, bands: [page.telescope, ...instruments, ...colors], fieldOfViewDeg: observation.fieldOfViewDeg }, checkedSource: { kind: 'Published JPEG', dimensions: [width, height] }, + geometryEvidence: { inclinationDeg: plane.inclinationDeg, lineOfNodesPaDeg: plane.lineOfNodesPaDeg, reference: `A picture of the sky: the plane is the picture's own tangent plane, perpendicular to the sight line through the picture's centre, so it faces the Sun. That centre is ${registration.starFromCentreArcsec.toFixed(1)} arcsec from ${mark}, which is the whole of the recipe's inclination. Not the orientation of the object itself.` }, + registration: { method: registered, pixelArcsec: Number(pixelArcsec.toPrecision(4)), northClockwiseDeg: observation.northClockwiseDeg }, displayModel, + coverage: `The published frame inside a circle about ${mark}: the picture fades out ${rim}, the largest circle the frame holds, so no straight edge shows.`, + acquisition: { url: page.download, dimensions: [width, height], operation: 'Download the publisher\'s JPEG; no crop or resample.' } })); + files.set(`${at}/investigations.json`, json({ schema: INVESTIGATION_LEDGER_SCHEMA, objectId: bank, entries: [ + { id: page.id, subject: `${publisher} ${page.id}`, status: 'included', finding: `${page.title}: ${shown}; ${pixels} px over ${field}, released ${page.released}. ${registered}`, evidence: [page.page, page.rights] }, ...entry.ledger] })); + files.set(`src/sources/${record}.json`, json({ id: record, kind: 'data-product', identityLevel: 'work', title: page.title, identifiers: [{ type: `${publisher} image`, value: page.id }], + links: [{ role: 'landing', url: page.page, label: 'Published source' }, { role: 'original', url: page.download, label: `JPEG, ${width} x ${height} px` }, { role: 'rights', url: page.rights, label: 'Reuse terms' }], + evidence: [{ url: page.page, checkedOn: checked, locator: `${width} x ${height} px over ${field}; ${shown}; released ${page.released}. ${registered}` }], publisher, relations: [], + statements: [{ kind: 'credit', text: page.credit, scope: 'Published source', evidence: page.page }, { kind: 'rights', text: 'Creative Commons Attribution 4.0 International; the full credit must be shown.', scope: 'Published source', evidence: page.rights }] })); + + // The page: one more dataset, shown from this bank. + const content = copy(host.content), datasets = requireRecord(content.datasets, `${entry.host} content datasets`), controls = requireArray(datasets.controls, `${entry.host} dataset controls`).map(control => requireRecord(control, `${entry.host} dataset control`)); + datasets.controls = [...controls.filter(control => control.id !== dataset.id), { id: dataset.id, label: dataset.label, thumbnail: `${entry.host}-dataset-${dataset.id}.webp`, volume: { objectId: bank, datasetId: BANK_DATASET, surface: dataset.id }, + source: { id: `${bank}-${BANK_DATASET}`, path: `../../${bank}/source/manifest.json`, url: page.page }, falseColor: true }]; + files.set(`src/objects/${entry.host}/source/content/object.json`, json(content)); + const text = copy(host.text), texts = requireRecord(text.datasets, `${entry.host} text datasets`), picture: PictureSource = { catalogueId: record, url: page.page, label: `${publisher} ${page.id}: ${page.credit}`, locator: page.title }; + // A source the page's dataset already cites in the same words keeps the day it was read: a run that changes nothing writes nothing. + const before = texts[dataset.id], cited = isRecord(before) && Array.isArray(before.sources) ? before.sources.filter(isRecord) : []; + const read = (source: PictureSource) => { const day = cited.find(one => one.catalogueId === source.catalogueId && one.url === source.url && one.label === source.label && one.locator === source.locator)?.checked; return typeof day === 'string' ? day : undefined; }; + texts[dataset.id] = { title: dataset.title, detail: `${pixels} px`, summary: dataset.summary, sources: [picture, ...entry.sources].map(source => ({ catalogueId: source.catalogueId, url: source.url, label: source.label, checked: source.checked ?? read(source) ?? checked, locator: source.locator })) }; + files.set(`src/objects/${entry.host}/text.json`, json(text)); + + const name = requireString(like.presentation.name, `${entry.like} presentation name`), parsecs = `${registration.widthPc.toFixed(2)} pc wide at ${Math.round(target.distancePc)} pc`; + const readme = `# ${name}, ${dataset.label}\n\n${TODO}: one paragraph. What the picture is, what it lies on (the [${entry.like}](../${entry.like}/README.md) bank's walls), and what is chosen here and not measured.\n\n## Sources\n\n| Selected source | Input and meaning |\n| --- | --- |\n` + + `| [${publisher} ${page.id}](${page.page}) | [Record](../../sources/${record}.json). ${page.title}: ${shown}; ${pixels} px over ${field} (\`source/source.jpg\`, the publisher's JPEG, restored from its origin). Credit: ${page.credit}. A display composite, not calibrated photometry. |\n` + + entry.sources.map(source => `| [${source.label}](${source.url}) | [Record](../../sources/${source.catalogueId}.json). ${source.locator} |\n`).join('') + + `\n## The picture\n\n- **Registration:** ${registered}\n- **Depth:** ${TODO}: what the picture's light lies on, and which printed value each color takes.\n- **Size:** ${field}, ${parsecs}.\n- **Rim:** the picture fades out ${rim}, the largest circle the frame holds.\n` + + `\n## Evidence\n\n${TODO}: the page with this dataset selected, captured headless, and what the capture shows.\n\n## Known problems\n\n- ${TODO}: what is chosen and not measured.\n- Colors are the publisher's display composite, not a measurement.\n`; + return { files, readme, carried: others.map(input => ({ from: requireString(input.path, `${entry.like} manifest path`), to: moved(input.path) })), registration, + todo: [`write ${at}/README.md`, `name the ${bank} bank in src/objects/${entry.host}/README.md`] }; +} diff --git a/packages/telescope-cli/src/new-object/pictures/pictures.mts b/packages/telescope-cli/src/new-object/pictures/pictures.mts new file mode 100644 index 00000000000..4a6d90a684e --- /dev/null +++ b/packages/telescope-cli/src/new-object/pictures/pictures.mts @@ -0,0 +1,140 @@ +/** `telescope new-object` for published pictures: draft a spec from ESA's picture pages, write each entry's layer bank + * and its page's dataset, and bake them. One entry is one picture on a page that already shows a shaped bank + * (picture-bank.mts); the spec may be run again, and what a person wrote beside the records (the README) is kept. */ +import { spawn } from 'node:child_process'; +import { copyFile, mkdir, readFile, stat, writeFile } from 'node:fs/promises'; +import { dirname, resolve } from 'node:path'; +import sharp from 'sharp'; +import { isRecord, requireArray, requireRecord, requireString } from '@cssearth/core'; +import { fetchPublication, type Archive } from '../archives/archives.mts'; +import { TODO } from '../scaffold.mts'; +import { esaPictureAddress, readEsaPage, skyTags, type EsaPage } from './esa-image.mts'; +import { colorsPhrase, pageColors, parsePictures, pictureFiles, type PictureEntry } from './picture-bank.mts'; +import { locateStar, registerPicture, taggedPixel, type Place } from './registration.mts'; + +interface Context { readonly root: string; readonly archive: Archive; readonly progress: (line: string) => void } +export interface PictureResult { readonly id: string; readonly host: string; readonly dataset: string; readonly files: number; readonly todo: readonly string[]; readonly failed?: string } +type Json = Record<string, unknown>; + +const exists = (path: string) => stat(path).then(() => true, () => false); +const reason = (error: unknown) => (error as Error).message.split('\n')[0]!; +const readJson = async (root: string, path: string, what: string): Promise<Json> => { let text: string; try { text = await readFile(resolve(root, path), 'utf8'); } catch { throw new Error(`${what}: ${path} does not exist.`); } return requireRecord(JSON.parse(text), path); }; +/** What a reader calls an instrument's light, for a draft's dataset id and label; the instrument's own name otherwise. */ +const LIGHT: Readonly<Record<string, string>> = { NIRCam: 'near infrared', MIRI: 'mid infrared' }; + +/** The publisher's JPEG, read once: kept in the ignored `output/new-object/pictures/` between a draft and its run. */ +async function pictureBytes(page: EsaPage, { root, archive, progress }: Context) { + const kept = resolve(root, 'output/new-object/pictures', `${page.id}.jpg`); + if (await exists(kept)) return readFile(kept); + progress(` ${page.id}: reading ${page.download}`); + const bytes = await archive.bytes(page.download); + await mkdir(dirname(kept), { recursive: true }); await writeFile(kept, bytes); + return bytes; +} +async function pictureOnSky(page: EsaPage, target: Place, context: Context) { + const bytes = await pictureBytes(page, context), { data, info } = await sharp(bytes, { limitInputPixels: false }).removeAlpha().raw().toBuffer({ resolveWithObject: true }); + if (info.channels !== 3) throw new Error(`${page.download}: a picture of ${info.channels} channel(s), not a color picture.`); + const tags = skyTags(bytes, info.width, info.height, page.download); + return { bytes, tags, rgb: data, dimensions: [info.width, info.height] as const, tagged: taggedPixel(tags, info.height, target) }; +} +const bankOf = (content: Json, host: string) => { const datasets = requireRecord(content.datasets, `${host} content datasets`), controls = requireArray(datasets.controls, `${host} dataset controls`).map(control => requireRecord(control, `${host} dataset control`)); + const shown = [controls.find(control => control.id === datasets.defaultDataset), ...controls].find(control => isRecord(control?.volume)); + if (!shown) throw new Error(`${host}: the page shows no layer bank a picture could lie on like.`); + return requireString(requireRecord(shown.volume, `${host} dataset volume`).objectId, `${host} dataset volume.objectId`); }; + +/** `--from-esa HOST=PAGE...`: one entry a picture, on the walls of the bank its page opens on, with the star the picture + * shows at the page's place. The sentences a reader sees are left to write. */ +export async function draftsFromEsa(names: readonly string[], context: Context): Promise<{ readonly stars: readonly unknown[]; readonly pictures: readonly unknown[]; readonly report: readonly string[] }> { + const pictures: unknown[] = [], report: string[] = []; + for (const asked of names) { + try { + const [host, address] = asked.split(/=(.*)/su) as [string, string | undefined]; + if (!address) throw new Error(`${asked}: name a page and its picture as HOST=https://esawebb.org/images/<id>/.`); + const page = await readEsaPage(address, context.archive), like = bankOf(await readJson(context.root, `src/objects/${host}/source/content/object.json`, `${host}: no such page`), host); + const target = requireRecord((await readJson(context.root, `src/objects/${like}/source/recipe.json`, `${like}: not a layer bank`)).target, `${like} recipe target`) as unknown as Place; + const sky = await pictureOnSky(page, target, context), pixelArcsec = sky.tags.scaleDeg * 3600, star = locateStar(sky.rgb, ...sky.dimensions, pixelArcsec, sky.tagged); + registerPicture(sky.tags, sky.dimensions, star?.pixel ?? sky.tagged, target); + const name = requireString((await readJson(context.root, `src/objects/${like}/source/presentation.json`, like)).name, `${like} presentation name`), colors = pageColors(page.colors); + const instruments = [...new Set(page.colors.map(color => color.instrument).filter(Boolean))], light = instruments.length === 1 ? LIGHT[instruments[0]!] ?? instruments[0]! : instruments.join(' + '); + const slug = (words: string) => words.toLowerCase().replace(/[^a-z0-9]+/gu, '-'), write = (what: string) => `${TODO}: ${what}`; + pictures.push({ host, image: page.page, bank: `${host}-${slug(instruments.join(' '))}-layers`, like, + dataset: { id: slug(light), label: `${page.telescope} · ${light}`, title: write('the dataset\'s title'), summary: write('one sentence under the title'), description: write('what the picture shows and what it lies on') }, + colors, ...(star ? { star: star.pixel.map(value => Number(value.toFixed(1))), starFound: star.found } : {}), geometry: {}, sources: [], ledger: [] }); + report.push(`${page.id} on ${host}, like ${like}: ${page.title}; ${sky.dimensions.join(' x ')} px, ${instruments.join(' and ')} at ${colorsPhrase(colors)}. ` + (star + ? `The star: ${star.found}, at ${star.pixel.map(value => value.toFixed(1)).join(', ')}, ${(Math.hypot(star.pixel[0] - sky.tagged[0], star.pixel[1] - sky.tagged[1]) * pixelArcsec).toFixed(2)} arcsec from where the tags put the page's place. Remove "star" and "starFound" where the page stands at no star.` + : 'No star near the page\'s place: the picture is placed by its tags.') + ` What its colors show: telescope papers ${JSON.stringify(name)} --instrument ${instruments[0]}`); + } catch (error) { report.push(`${asked}: not drafted: ${reason(error)}`); } + } + return { stars: [], pictures, report }; +} + +/** A record in src/sources for every source an entry cites: the one there, or one read from arXiv or Crossref by its link. */ +async function sourceRecords(entry: PictureEntry, { root, archive }: Context) { + const records = new Map<string, string>(); + for (const source of entry.sources) { + const path = `src/sources/${source.catalogueId}.json`; + if (await exists(resolve(root, path))) continue; + const publication = /arxiv\.org\/abs\/|doi\.org\//u.test(source.url) ? await fetchPublication(archive, source.url) : undefined; + if (!publication) throw new Error(`${entry.bank}: ${path} does not exist, and ${source.url} is not an arXiv or DOI link to write it from.`); + const { publicationRecord } = await import('../generate.mts'); + records.set(path, `${JSON.stringify(publicationRecord({ ...publication, id: source.catalogueId }), null, 2)}\n`); + } + return records; +} + +/** Write one entry: its bank's records, picture and other inputs, and its page's dataset. */ +async function writePicture(entry: PictureEntry, context: Context): Promise<PictureResult> { + const { root } = context, at = `src/objects/${entry.bank}`, inTree = (path: string) => resolve(root, path); + const page = await readEsaPage(entry.image, context.archive); + if (await exists(inTree(at))) { const made = await readJson(root, `${at}/source/recipe.json`, `${entry.bank} exists and is not a layer bank`); + if (requireRecord(made.source, `${entry.bank} recipe source`).publisherUrl !== page.page) throw new Error(`${at} already exists and shows another picture; the generator rewrites only the records of the picture it is given.`); } + if (entry.like === entry.bank) throw new Error(`${entry.bank}: a bank cannot be like itself.`); + const like = { recipe: await readJson(root, `src/objects/${entry.like}/source/recipe.json`, `${entry.like}: not a layer bank`), manifest: await readJson(root, `src/objects/${entry.like}/source/manifest.json`, entry.like), + presentation: await readJson(root, `src/objects/${entry.like}/source/presentation.json`, entry.like), provenance: await readJson(root, `src/objects/${entry.like}/source/provenance.json`, entry.like) }; + const host = { content: await readJson(root, `src/objects/${entry.host}/source/content/object.json`, `${entry.host}: no such page`), text: await readJson(root, `src/objects/${entry.host}/text.json`, entry.host) }; + const sky = await pictureOnSky(page, requireRecord(like.recipe.target, `${entry.like} recipe target`) as unknown as Place, context), records = await sourceRecords(entry, context); + const { files, readme, carried, todo } = pictureFiles(entry, { page, tags: sky.tags, dimensions: sky.dimensions, tagged: sky.tagged, like, host, checked: new Date().toISOString().slice(0, 10) }); + for (const { from } of carried) if (!await exists(inTree(from))) throw new Error(`${entry.bank}: ${from}, which the ${entry.like} bank reads, is not restored; its manifest names where it comes from.`); + let written = 0; + const put = async (path: string, value: string | Buffer) => { await mkdir(dirname(inTree(path)), { recursive: true }); await writeFile(inTree(path), value); written++; }; + for (const [path, value] of [...files, ...records]) if (!path.startsWith('src/sources/') || !await exists(inTree(path))) await put(path, value); + if (!await exists(inTree(`${at}/README.md`))) await put(`${at}/README.md`, readme); + await put(`${at}/source/source.jpg`, sky.bytes); + // The like bank's other inputs stand beside this bank too; one that Git ignores there is ignored here. + const ignore = inTree('.gitignore'), ignored = (await readFile(ignore, 'utf8')).split('\n'); + for (const { from, to } of carried) { await copyFile(inTree(from), inTree(to)); written++; + if (ignored.includes(from) && !ignored.includes(to)) { ignored.splice(ignored.indexOf(from) + 1, 0, `# The same file beside the ${entry.bank} bank; restored from the same origin (${at}/source/manifest.json).`, to); await writeFile(ignore, ignored.join('\n')); } } + // What is left for a person: the bank's README while it holds a line to write, and the page's README until it names the bank. + const holds = async (path: string, words: string) => (await readFile(inTree(path), 'utf8').catch(() => '')).includes(words), left = [await holds(`${at}/README.md`, TODO), !await holds(`src/objects/${entry.host}/README.md`, `../${entry.bank}/`)]; + return { id: entry.bank, host: entry.host, dataset: entry.dataset.id, files: written, todo: todo.filter((_, index) => left[index]) }; +} + +/** Every picture of a spec file, written. One that fails is reported with its reason and the rest go on. */ +export async function runPictures(specPath: string, context: Context): Promise<PictureResult[]> { + const entries = parsePictures(JSON.parse(await readFile(resolve(specPath), 'utf8'))), results: PictureResult[] = []; + for (const entry of entries) { + try { esaPictureAddress(entry.image); results.push(await writePicture(entry, context)); context.progress(` ${entry.bank}: written`); } + catch (error) { results.push({ id: entry.bank, host: entry.host, dataset: entry.dataset.id, files: 0, todo: [], failed: reason(error) }); context.progress(` ${entry.bank}: FAILED, not written: ${reason(error)}`); } + } + return results; +} + +/** Bake the banks and their pages: each bank's layers and presentation, each page's hosted context, then the pages' + * prepared files in one run (the reader-text step checks every page against its prepared datasets), the catalogue and the + * world. Stops at the first step that fails. */ +export async function bakePictures(results: readonly PictureResult[], { root, progress }: Pick<Context, 'root' | 'progress'>): Promise<boolean> { + const banks = results.map(result => result.id), hosts = [...new Set(results.map(result => result.host))], node = (...args: string[]) => ['node', ...args]; + const steps = [node('packages/bake/cli/check-stale-builds.mts', '--run'), ...banks.flatMap(bank => [node('packages/bake/cli/prepare-image-layers.mts', `src/objects/${bank}`), node('site/build/prepare/prepare-volume-presentation.mts', `--object=${bank}`)]), + ...hosts.map(host => node('site/build/prepare/companion-context.mts', host)), node('packages/bake/cli/prepare-object.mts', ...hosts, '--from', 'catalogue', '--to', 'markers'), node('site/build/prepare/prepare-catalog.mts'), + node('packages/bake/cli/prepare-object.mts', ...hosts, '--from', 'world'), node('packages/bake/cli/prepare-navigation.mts', '--catalog-only')]; + for (const [command, ...args] of steps as [string, ...string[]][]) { + progress(`== ${args.join(' ')}`); + // A step's own output is progress: it goes where the telescope's does, and the result text stays the telescope's. + const code = await new Promise<number | null>(done => { spawn(command, args, { cwd: root, stdio: ['ignore', 2, 2] }).on('error', () => done(null)).on('close', done); }); + if (code !== 0) { progress(`FAILED: ${command} ${args.join(' ')}`); return false; } + } + return true; +} + +export const formatPictures = (results: readonly PictureResult[], spec: string, baked: boolean) => `${results.map(result => result.failed ? `${result.id} (picture): FAILED, not written: ${result.failed}` + : `${result.id} (picture, the ${result.dataset} dataset of ${result.host}): ${result.files} files.${result.todo.length ? `\n Still to write: ${result.todo.join('; ')}.` : ''}`).join('\n')}\n${baked ? `${results.filter(result => !result.failed).length} picture(s) baked.` : `Then bake: telescope new-object ${spec} --bake`}\n`; diff --git a/packages/telescope-cli/src/new-object/pictures/pictures.test.mts b/packages/telescope-cli/src/new-object/pictures/pictures.test.mts new file mode 100644 index 00000000000..7bd359e3b0f --- /dev/null +++ b/packages/telescope-cli/src/new-object/pictures/pictures.test.mts @@ -0,0 +1,195 @@ +import assert from 'node:assert/strict'; +import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { dirname, join } from 'node:path'; +import sharp from 'sharp'; +import { sourceTest } from '@cssearth/objects/node/source-test'; +import type { Archive } from '../archives/archives.mts'; +import { TODO } from '../scaffold.mts'; +import { esaPictureAddress, parseEsaPage, skyTags, type EsaPage, type SkyTags } from './esa-image.mts'; +import { colorsPhrase, parsePictures, pictureFiles } from './picture-bank.mts'; +import { draftsFromEsa, runPictures } from './pictures.mts'; +import { locateStar, registerPicture, taggedPixel } from './registration.mts'; + +const test = sourceTest(); +const WEBB = 'https://esawebb.org/images/weic0000a/'; +// The two layouts ESA's sites give a picture's page: Webb's names the shown color in a hidden span, Hubble's in the class alone. +const row = (band: string, wavelength: string, instrument: string) => `<tr><td>${band}</td><td>${wavelength}</td><td>\n Some Space Telescope\n <br/><span class="band_instrument">${instrument}</span></td></tr>`; +const page = (title: string, credit: string, rows: string) => `<html><head><title>${title} | ESA/WebbCredit:\n

${credit}

+
Release date:21 August 2023, 16:00
Size:40 x 30 px
+

Colours & filters

${rows}
BandWavelengthTelescope
`; +const WEBB_PAGE = page('A nebula (MIRI image)', 'ESA/Webb, NASA, CSA, A. Person', row('\n Infrared\n (Blue)
PAH', '7.7 μm', 'MIRI') + row(' Infrared (Red)', '18 μm', 'MIRI')); + +test('a picture\'s page gives its title, credit, date, size and colors, on either site\'s markup', () => { + const webb = parseEsaPage(WEBB, WEBB_PAGE); + assert.deepEqual({ ...webb, colors: undefined }, { id: 'weic0000a', telescope: 'Webb', page: WEBB, download: 'https://cdn.esawebb.org/archives/images/large/weic0000a.jpg', rights: 'https://esawebb.org/copyright/', + title: 'A nebula (MIRI image)', credit: 'ESA/Webb, NASA, CSA, A. Person', released: '21 August 2023', original: [40, 30], colors: undefined }); + assert.deepEqual(webb.colors, [{ band: 'Infrared', shown: 'Blue', line: 'PAH', wavelength: '7.7 µm', instrument: 'MIRI' }, { band: 'Infrared', shown: 'Red', wavelength: '18 µm', instrument: 'MIRI' }]); + const hubble = parseEsaPage('https://esahubble.org/images/heic0000a', page('A nebula', 'NASA, ESA, and A. O’Person (A University).', row('Optical
OIII', '502 nm', 'WFC3'))); + assert.deepEqual([hubble.telescope, hubble.page, hubble.credit.startsWith('NASA, ESA, and A. O'), hubble.credit.endsWith('(A University)')], ['Hubble', 'https://esahubble.org/images/heic0000a/', true, true]); + assert.deepEqual(hubble.colors, [{ band: 'Optical', shown: 'Green', line: 'OIII', wavelength: '502 nm', instrument: 'WFC3' }]); + assert.equal(colorsPhrase(['7.7 µm', '12 µm', '18 µm']), '7.7, 12 and 18 µm'); + assert.equal(colorsPhrase(['502 nm', '1.6 µm']), '502 nm and 1.6 µm'); +}); + +test('a page that lacks a field, or an address that is no picture\'s page, is refused by name', () => { + assert.throws(() => esaPictureAddress('https://esawebb.org/news/weic2320/'), /not a picture's page/u); + assert.throws(() => parseEsaPage(WEBB, WEBB_PAGE.replace('class="credit"', 'class="other"')), /weic0000a\/: the page has no credit/u); + assert.throws(() => parseEsaPage(WEBB, WEBB_PAGE.replace('40 x 30 px', 'large')), /no "Size: W x H px"/u); + assert.throws(() => parseEsaPage(WEBB, WEBB_PAGE.replace(//u, '')), /no "Colours & filters" table/u); +}); + +// ESA/Webb weic2320c, the Ring Nebula in the mid infrared: the sky tags its JPEG carries. +const RING_TAGS: SkyTags = { scaleDeg: 0.000030865735733094474, rotationDeg: -132.91999999999948, reference: [283.39639957968876, 33.029010843598876], referencePixel: [628.5, 507.5] }; +const list = (values: readonly number[]) => `${values.map(value => `\n ${value}`).join('')}\n`; +const xmp = (tags: SkyTags, [width, height]: readonly [number, number]) => `${list(tags.reference)}${list([width, height])}` + + `${list(tags.referencePixel)}${list([-tags.scaleDeg, tags.scaleDeg])}${tags.rotationDeg}`; + +test('a JPEG\'s sky tags are read for the file as it is, and a smaller copy takes its original\'s', () => { + const bytes = Buffer.from(xmp(RING_TAGS, [1257, 1015]), 'latin1'); + assert.deepEqual(skyTags(bytes, 1257, 1015, 'ring.jpg'), RING_TAGS); + const half = skyTags(Buffer.from(xmp(RING_TAGS, [2514, 2030]), 'latin1'), 1257, 1015, 'ring.jpg'); + assert.deepEqual([half.scaleDeg, half.referencePixel], [RING_TAGS.scaleDeg * 2, [314.25, 253.75]]); + assert.deepEqual(skyTags(Buffer.from(''), 10, 8, 'x.jpg'), + { scaleDeg: 0.5, rotationDeg: 3, reference: [1, 2], referencePixel: [5, 4] }); + assert.throws(() => skyTags(bytes, 1257, 900, 'ring.jpg'), /ring\.jpg is 1257 x 900 px; its sky tags describe 1257 x 1015/u); + assert.throws(() => skyTags(Buffer.from('no tags'), 10, 10, 'bare.jpg'), /bare\.jpg carries no avm:Spatial\.ReferenceDimension/u); +}); + +const RING = { centerRaDeg: 283.39624524513, centerDecDeg: 33.02914523473, distancePc: 790.014153719229 }; + +test('a picture is registered by its tags and one pixel: the Ring Nebula\'s mid-infrared recipe', () => { + const made = registerPicture(RING_TAGS, [1257, 1015], [627.5, 513.5], RING); + assert.deepEqual(made.observation, { centerRaDeg: 283.396433, centerDecDeg: 33.0290199, fieldOfViewDeg: [0.03879823, 0.03132872], northClockwiseDeg: 132.92 }); + assert.deepEqual(made.plane, { inclinationDeg: 0.001, lineOfNodesPaDeg: 218.521, thicknessKpc: 2.67e-7, supportRadiusKpc: 0.00021295, supportTaperFraction: 0.9 }); + // The tags' own pixel for the star's place is within half a pixel of the star the picture shows; and the reference pixel is its own place. + const tagged = taggedPixel(RING_TAGS, 1015, RING); + assert.ok(Math.hypot(tagged[0] - 627.5, tagged[1] - 513.5) < 0.5, tagged.join(', ')); + assert.deepEqual(taggedPixel(RING_TAGS, 1015, { centerRaDeg: RING_TAGS.reference[0], centerDecDeg: RING_TAGS.reference[1] }), [627.5, 507.5]); + assert.throws(() => registerPicture(RING_TAGS, [1257, 1015], [1300.2, 400], RING), /The picture, 1257 x 1015 px, does not hold the place it is to stand at: pixel 1300\.2, 400\.0/u); +}); + +/** A dark picture with one soft source: `peak` levels at its middle, and every pixel within `core` pixels of it saturated. */ +function sourceAt(width: number, height: number, [x, y]: readonly [number, number], peak: number, core = 0) { + const rgb = new Uint8Array(3 * width * height).fill(20); + for (let py = 0; py < height; py++) for (let px = 0; px < width; px++) { const from = Math.hypot(px - x, py - y), level = from <= core ? 255 : Math.min(255, 20 + peak * Math.exp(-from * from / 8)); rgb.fill(Math.round(level), 3 * (py * width + px), 3 * (py * width + px) + 3); } + return rgb; +} + +test('the star a picture shows is its saturated patch, or else its strongest peak, near where the tags put it', () => { + const patch = locateStar(sourceAt(80, 60, [41, 29], 200, 3), 80, 60, 0.1, [38, 27]); + assert.deepEqual(patch?.pixel, [41, 29]); assert.match(patch!.found, /largest patch of saturated pixels within 1 arcsec of where the tags put it, 29 px/u); + const peak = locateStar(sourceAt(80, 60, [41.3, 29.6], 120), 80, 60, 0.1, [38, 27]); + assert.ok(peak && Math.hypot(peak.pixel[0] - 41.3, peak.pixel[1] - 29.6) < 0.2, String(peak?.pixel)); assert.match(peak.found, /peak within 3 arcsec of where the tags put it/u); + assert.equal(locateStar(new Uint8Array(3 * 80 * 60).fill(20), 80, 60, 0.1, [38, 27]), undefined); + // A saturated star farther than an arcsecond from the place is another star. + assert.equal(locateStar(sourceAt(80, 60, [70, 50], 200, 3), 80, 60, 0.02, [20, 20]), undefined); +}); + +const ENTRY = { host: 'm57', image: 'https://esawebb.org/images/weic2320c/', bank: 'm57-miri-layers', like: 'm57-layers', dataset: { id: 'mid-infrared', label: 'Webb · mid infrared', title: 'A title', summary: 'A summary.', description: 'A description.' } }; + +test('a spec entry a draft left unfinished, or one with a wrong id, is refused by its field', () => { + assert.equal(parsePictures({ pictures: [ENTRY] })[0]!.bank, 'm57-miri-layers'); + assert.throws(() => parsePictures({ pictures: [{ ...ENTRY, dataset: { ...ENTRY.dataset, summary: `${TODO}: one sentence` } }] }), /pictures\[0\]\.dataset\.summary is still to write/u); + assert.throws(() => parsePictures({ pictures: [{ ...ENTRY, geometry: { shape: { basis: `${TODO}: why` } } }] }), /pictures\[0\]\.geometry\.shape\.basis is still to write/u); + assert.throws(() => parsePictures({ pictures: [{ ...ENTRY, bank: 'M57 layers' }] }), /pictures\[0\]\.bank "M57 layers" is not an object id/u); + assert.throws(() => parsePictures({ pictures: [{ ...ENTRY, star: [1] }] }), /pictures\[0\]\.star must be two numbers/u); + assert.throws(() => parsePictures({ pictures: [ENTRY, ENTRY] }), /Picture banks repeat: m57-miri-layers/u); +}); + +test('the generator makes the recipe and manifest the Ring Nebula\'s mid-infrared bank ships, from what differs from the Hubble bank', async () => { + const json = async (path: string) => JSON.parse(await readFile(new URL(`../../../../../${path}`, import.meta.url), 'utf8')) as Record; + const at = 'src/objects/m57-miri-layers', shipped = await json(`${at}/source/recipe.json`), like = { recipe: await json('src/objects/m57-layers/source/recipe.json'), manifest: await json('src/objects/m57-layers/source/manifest.json'), + presentation: await json('src/objects/m57-layers/source/presentation.json'), provenance: await json('src/objects/m57-layers/source/provenance.json') }; + // The entry says what this picture's colors take on the Hubble dataset's shell: the shell's source and reasoning, and the ring's and the lobe's speeds. + const [entry] = parsePictures({ pictures: [{ ...ENTRY, star: [627.5, 513.5], facePixels: 1257, geometry: { shape: { basis: shipped.geometry.shape.basis, ring: { expansionKmS: shipped.geometry.shape.ring.expansionKmS }, lobe: { expansionKmS: shipped.geometry.shape.lobe.expansionKmS } } } }] }); + const ring: EsaPage = { ...esaPictureAddress(ENTRY.image), title: 'Webb captures detailed beauty of Ring Nebula (MIRI image)', credit: 'ESA/Webb, NASA, CSA, M. Barlow, N. Cox, R. Wesson', released: '21 August 2023', original: [1257, 1015], + colors: [{ band: 'Infrared', shown: 'Blue', wavelength: '7.7 µm', instrument: 'MIRI' }] }; + const made = pictureFiles(entry!, { page: ring, tags: RING_TAGS, dimensions: [1257, 1015], tagged: taggedPixel(RING_TAGS, 1015, RING), like, host: { content: await json('src/objects/m57/source/content/object.json'), text: await json('src/objects/m57/text.json') }, checked: '2026-10-04' }); + const file = (path: string) => JSON.parse(String(made.files.get(path))) as Record; + assert.deepEqual(file(`${at}/source/recipe.json`), shipped); + assert.deepEqual(file(`${at}/source/manifest.json`), await json(`${at}/source/manifest.json`)); + assert.deepEqual(file('src/objects/m57/source/content/object.json'), await json('src/objects/m57/source/content/object.json')); + assert.deepEqual(made.carried, []); +}); + +/** A checkout holding one page and the layer bank it shows, and an archive that serves one picture's page and JPEG. */ +async function checkout() { + const root = await mkdtemp(join(tmpdir(), 'cssearth-pictures-')), put = async (path: string, value: unknown) => { await mkdir(dirname(join(root, path)), { recursive: true }); await writeFile(join(root, path), typeof value === 'string' ? value : `${JSON.stringify(value, null, 2)}\n`); }; + const like = 'src/objects/nebula-layers'; + await put(`${like}/source/recipe.json`, { schema: 'cssearth-image-layer-recipe@1', id: 'nebula-layers', source: { path: 'starless.jpg' }, observation: {}, target: { centerRaDeg: 10, centerDecDeg: 20, distancePc: 1000 }, + geometry: { kind: 'inclined-disk', inclinationDeg: 1, unit: 'pc', shape: { source: 'publication-a', basis: 'The Hubble basis.', ring: { semiMajorArcsec: 1, expansionKmS: [1, 2, 3] }, old: true } }, bake: { maxFacePixels: 1024, flat: true }, provenance: { path: 'provenance.json' } }); + await put(`${like}/source/manifest.json`, { schema: 'cssearth-volume-source-manifest@2', pathBase: 'repository', inputs: [{ id: 'optical', path: `${like}/source/starless.jpg`, generator: 'a script' }, { id: 'speeds', path: `${like}/source/speeds.dat`, origin: 'https://example.test/speeds.dat' }], + documents: [{ id: 'recipe', path: `${like}/source/recipe.json` }], generatedIntermediates: [] }); + await put(`${like}/source/presentation.json`, { schema: 'cssearth-volume-presentation-source@2', objectId: 'nebula-layers', name: 'A Nebula', datasets: [{ id: 'optical' }] }); + await put(`${like}/source/provenance.json`, { displayModel: 'On the shell\'s two walls.' }); + await put(`${like}/source/speeds.dat`, '1 2 3\n'); + await put('.gitignore', `node_modules\n${like}/source/speeds.dat\noutput\n`); + await put('src/objects/nebula/source/content/object.json', { datasets: { defaultDataset: 'optical', controls: [{ id: 'optical', volume: { objectId: 'nebula-layers', datasetId: 'optical', surface: 'optical' } }] } }); + await put('src/objects/nebula/text.json', { datasets: { optical: { title: 'Hubble' } } }); + await put('src/sources/publication-a.json', { id: 'publication-a' }); + // 0.36 arcsec a pixel, north up, the tags' reference at the page's place: a saturated star stands 2.5 px right of where they put it. + const tags: SkyTags = { scaleDeg: 0.0001, rotationDeg: 0, reference: [10, 20], referencePixel: [20.5, 15.5] }; + const jpeg = Buffer.concat([await sharp(Buffer.from(sourceAt(40, 30, [22, 15], 200, 1.5)), { raw: { width: 40, height: 30, channels: 3 } }).jpeg({ quality: 100, chromaSubsampling: '4:4:4' }).toBuffer(), Buffer.from(xmp(tags, [40, 30]), 'latin1')]); + const asked: string[] = [], archive: Archive = { text: async url => { asked.push(url); if (url !== WEBB) throw new Error(`no ${url}`); return WEBB_PAGE; }, bytes: async url => { asked.push(url); return jpeg; }, exists: async () => true }; + return { root, archive, asked, context: { root, archive, progress: () => {} }, read: async (path: string) => readFile(join(root, path), 'utf8'), json: async (path: string) => JSON.parse(await readFile(join(root, path), 'utf8')) as Record, put }; +} + +test('a draft names the page\'s bank and the star, a run writes the bank and the page\'s dataset, and a second run keeps what a person wrote', async () => { + const { root, context, asked, read, json, put } = await checkout(); + try { + const draft = await draftsFromEsa([`nebula=${WEBB}`, 'nowhere'], context), [drafted] = draft.pictures as Record[]; + assert.deepEqual({ ...drafted, dataset: { ...drafted!.dataset, title: '', summary: '', description: '' } }, { host: 'nebula', image: WEBB, bank: 'nebula-miri-layers', like: 'nebula-layers', + dataset: { id: 'mid-infrared', label: 'Webb · mid infrared', title: '', summary: '', description: '' }, colors: ['7.7 µm', '18 µm'], star: [22, 15], starFound: 'the largest patch of saturated pixels within 1 arcsec of where the tags put it, 9 px', geometry: {}, sources: [], ledger: [] }); + assert.match(draft.report[0]!, /weic0000a on nebula, like nebula-layers: A nebula \(MIRI image\); 40 x 30 px, MIRI at 7\.7 and 18 µm\. The star: the largest patch of saturated pixels within 1 arcsec of where the tags put it, 9 px, at 22\.0, 15\.0, 0\.92 arcsec from where the tags put the page's place/u); + assert.match(draft.report[1]!, /nowhere: not drafted: nowhere: name a page and its picture as HOST=/u); + await put('spec.json', draft); + await assert.rejects(runPictures(join(root, 'spec.json'), context), /pictures\[0\]\.dataset\.title is still to write/u); + // A person writes the sentences and what this picture's light takes on the like bank's walls. + const entry = { ...drafted, dataset: { ...drafted!.dataset, title: 'A Nebula in the mid infrared', summary: 'One sentence.', description: 'What it shows.' }, geometry: { shape: { basis: 'The mid-infrared basis.', ring: { expansionKmS: [4, 5, 6] }, old: null } }, + sources: [{ catalogueId: 'publication-a', url: 'https://example.test/a', label: 'A et al. (2020)', locator: 'Sect. 2', checked: '2026-01-02' }], ledger: [{ id: 'speeds', subject: 'Speeds', status: 'included', finding: 'Chosen.', evidence: ['https://example.test/a'] }] }; + await put('spec.json', { pictures: [entry] }); + const [first] = await runPictures(join(root, 'spec.json'), context), at = 'src/objects/nebula-miri-layers'; + assert.deepEqual({ ...first, files: 0 }, { id: 'nebula-miri-layers', host: 'nebula', dataset: 'mid-infrared', files: 0, todo: [`write ${at}/README.md`, 'name the nebula-miri-layers bank in src/objects/nebula/README.md'] }); + assert.equal(asked.filter(url => url.endsWith('.jpg')).length, 1, 'the picture is read once, for the draft'); + const recipe = await json(`${at}/source/recipe.json`); + assert.deepEqual(recipe.source, { path: 'source.jpg', dimensions: [40, 30], originalDimensions: [40, 30], publisherUrl: WEBB, downloadUrl: 'https://cdn.esawebb.org/archives/images/large/weic0000a.jpg', credit: 'ESA/Webb, NASA, CSA, A. Person', license: 'CC-BY-4.0' }); + assert.deepEqual(recipe.geometry.shape, { source: 'publication-a', basis: 'The mid-infrared basis.', ring: { semiMajorArcsec: 1, expansionKmS: [4, 5, 6] } }); + assert.deepEqual([recipe.id, recipe.target.distancePc, recipe.bake, recipe.observation.northClockwiseDeg, recipe.geometry.kind], ['nebula-miri-layers', 1000, { maxFacePixels: 40, flat: true }, 0, 'inclined-disk']); + // The star, 2.5 px right of the frame's middle and half a pixel below it, stands at the page's place: with north up and east to the left, the frame's centre is that far east and north of it. + assert.ok(Math.abs(recipe.observation.centerRaDeg - (10 + 2.5 * 0.0001 / Math.cos(20 * Math.PI / 180))) < 2e-7 && Math.abs(recipe.observation.centerDecDeg - (20 + 0.5 * 0.0001)) < 2e-7, JSON.stringify(recipe.observation)); + const manifest = await json(`${at}/source/manifest.json`); + assert.deepEqual(manifest.inputs.map((input: { path: string }) => input.path), [`${at}/source/source.jpg`, `${at}/source/speeds.dat`]); + assert.deepEqual([manifest.inputs[0].sourceBinding.references[0].catalogueId, manifest.inputs[0].capture.attributions[0].facilityId, manifest.documents[0].path], ['esawebb-weic0000a', 'webb', `${at}/source/recipe.json`]); + assert.equal(await read(`${at}/source/speeds.dat`), '1 2 3\n'); + assert.deepEqual((await read('.gitignore')).split('\n').slice(1, 4), ['src/objects/nebula-layers/source/speeds.dat', `# The same file beside the nebula-miri-layers bank; restored from the same origin (${at}/source/manifest.json).`, `${at}/source/speeds.dat`]); + assert.deepEqual((await json(`${at}/object.json`)).properties, { preparation: { source: 'source/recipe.json' }, host: 'nebula' }); + const presentation = await json(`${at}/source/presentation.json`); + assert.deepEqual([presentation.objectId, presentation.name, presentation.datasets[0].id, presentation.datasets[0].label, presentation.datasets[0].facts[0].value], ['nebula-miri-layers', 'A Nebula', 'optical', 'Webb · mid infrared', '7.7 and 18 µm']); + const provenance = await json(`${at}/source/provenance.json`); + assert.equal(provenance.displayModel, 'On the shell\'s two walls.'); + assert.match(provenance.registration.method, /the star in the picture, the largest patch of saturated pixels within 1 arcsec of where the tags put it, 9 px, pixel 22, 15, is set at the recipe's target, so the frame's centre is [\d.]+°, [\d.]+°\. The tags alone put the star 0\.92 arcsec from where the picture shows it\./u); + assert.deepEqual((await json(`${at}/investigations.json`)).entries.map((one: { id: string }) => one.id), ['weic0000a', 'speeds']); + assert.equal((await json('src/sources/esawebb-weic0000a.json')).statements[0].text, 'ESA/Webb, NASA, CSA, A. Person'); + const page = (await json('src/objects/nebula/source/content/object.json')).datasets.controls; + assert.deepEqual(page[1], { id: 'mid-infrared', label: 'Webb · mid infrared', thumbnail: 'nebula-dataset-mid-infrared.webp', volume: { objectId: 'nebula-miri-layers', datasetId: 'optical', surface: 'mid-infrared' }, + source: { id: 'nebula-miri-layers-optical', path: '../../nebula-miri-layers/source/manifest.json', url: WEBB }, falseColor: true }); + const text = (await json('src/objects/nebula/text.json')).datasets; + assert.deepEqual([Object.keys(text), text['mid-infrared'].title, text['mid-infrared'].sources.map((source: { catalogueId: string }) => source.catalogueId)], [['optical', 'mid-infrared'], 'A Nebula in the mid infrared', ['esawebb-weic0000a', 'publication-a']]); + assert.deepEqual([text['mid-infrared'].sources[0].checked, text['mid-infrared'].sources[1].checked], [new Date().toISOString().slice(0, 10), '2026-01-02']); + const readme = await read(`${at}/README.md`); + assert.ok(readme.startsWith('# A Nebula, Webb · mid infrared\n') && readme.includes(TODO) && readme.includes('| [A et al. (2020)](https://example.test/a) | [Record](../../sources/publication-a.json). Sect. 2 |'), readme); + // Run again with a value changed: the records follow the spec, the README a person wrote stays, and the page holds one such dataset. + await put(`${at}/README.md`, '# Written by a person\n'); await put('src/objects/nebula/README.md', 'Its datasets show [one](../nebula-layers/README.md) and [another](../nebula-miri-layers/README.md).\n'); await put('spec.json', { pictures: [{ ...entry, facePixels: 32 }] }); + const dated = await json('src/objects/nebula/text.json'); dated.datasets['mid-infrared'].sources[0].checked = '2026-01-01'; await put('src/objects/nebula/text.json', dated); + const [second] = await runPictures(join(root, 'spec.json'), context); + assert.deepEqual([second!.todo, (await json(`${at}/source/recipe.json`)).bake.maxFacePixels, await read(`${at}/README.md`), (await json('src/objects/nebula/source/content/object.json')).datasets.controls.length, (await read('.gitignore')).split('\n').length], + [[], 32, '# Written by a person\n', 2, 6]); + assert.equal((await json('src/objects/nebula/text.json')).datasets['mid-infrared'].sources[0].checked, '2026-01-01', 'a source cited in the same words keeps the day it was read'); + // A bank that shows another picture is never rewritten; a source with no record and no paper link is refused by its path. + await put(`${at}/source/recipe.json`, { ...recipe, source: { ...recipe.source, publisherUrl: 'https://esawebb.org/images/other/' } }); + assert.match((await runPictures(join(root, 'spec.json'), context))[0]!.failed!, /src\/objects\/nebula-miri-layers already exists and shows another picture/u); + await put('spec.json', { pictures: [{ ...entry, bank: 'nebula-other-layers', sources: [{ catalogueId: 'publication-b', url: 'https://example.test/b', label: 'B', locator: 'p. 1' }] }] }); + assert.match((await runPictures(join(root, 'spec.json'), context))[0]!.failed!, /nebula-other-layers: src\/sources\/publication-b\.json does not exist, and https:\/\/example\.test\/b is not an arXiv or DOI link/u); + } finally { await rm(root, { recursive: true, force: true }); } +}); diff --git a/packages/telescope-cli/src/new-object/pictures/registration.mts b/packages/telescope-cli/src/new-object/pictures/registration.mts new file mode 100644 index 00000000000..d883d5f6dfe --- /dev/null +++ b/packages/telescope-cli/src/new-object/pictures/registration.mts @@ -0,0 +1,73 @@ +/** Where a published picture lies on the sky and in its layer bank's recipe. The file's sky tags give its scale and the + * direction of north; one pixel set at one place on the sky gives its position: the star the picture shows, or, where it + * shows none, the pixel the tags themselves give that place. The recipe's plane is the picture's own tangent plane. */ +import type { SkyTags } from './esa-image.mts'; + +const RAD = Math.PI / 180; +/** The picture fades out over the outer tenth of the largest circle about the star that the frame holds. */ +export const RIM_FROM = 0.9; +/** A star's saturated patch starts within this many arcseconds of where the tags put it; a peak is looked for this far. */ +const PATCH_WITHIN_ARCSEC = 1, PEAK_WITHIN_ARCSEC = 3, SATURATED = 250; + +export interface Place { readonly centerRaDeg: number; readonly centerDecDeg: number; readonly distancePc: number } +export interface Registration { + /** The recipe's `observation`. */ + readonly observation: { readonly centerRaDeg: number; readonly centerDecDeg: number; readonly fieldOfViewDeg: readonly [number, number]; readonly northClockwiseDeg: number }; + /** The recipe's plane and rim: the tangent plane at the frame's centre, and the largest circle about the star in the frame. */ + readonly plane: { readonly inclinationDeg: number; readonly lineOfNodesPaDeg: number; readonly thicknessKpc: number; readonly supportRadiusKpc: number; readonly supportTaperFraction: number }; + readonly pixelArcsec: number; readonly starFromCentreArcsec: number; readonly circleArcsec: number; readonly widthPc: number; +} + +/** The pixel, counted from the picture's top left, where its sky tags put a place on the sky. The tags count pixels from + * the bottom left with the first pixel's middle at 1, as FITS does. */ +export function taggedPixel(tags: SkyTags, height: number, place: Pick): [number, number] { + const rot = tags.rotationDeg * RAD, east = ((place.centerRaDeg - tags.reference[0] + 540) % 360 - 180) * Math.cos(place.centerDecDeg * RAD) / tags.scaleDeg, north = (place.centerDecDeg - tags.reference[1]) / tags.scaleDeg; + return [tags.referencePixel[0] - 1 - east * Math.cos(rot) - north * Math.sin(rot), height - (tags.referencePixel[1] - east * Math.sin(rot) + north * Math.cos(rot))]; +} + +/** The star a picture shows near `near`, a pixel: the largest patch of saturated pixels that starts within 1 arcsec of it, + * at the patch's middle; or, where nothing there is saturated, the peak within 3 arcsec that stands highest above its + * surroundings, at the middle of its light. Undefined when the picture shows neither. `rgb` is three bytes a pixel. */ +export function locateStar(rgb: Uint8Array, width: number, height: number, pixelArcsec: number, near: readonly [number, number]): { readonly pixel: [number, number]; readonly found: string } | undefined { + const inside = (x: number, y: number) => x >= 0 && y >= 0 && x < width && y < height, saturated = (p: number) => rgb[3 * p]! >= SATURATED && rgb[3 * p + 1]! >= SATURATED && rgb[3 * p + 2]! >= SATURATED; + const within = PATCH_WITHIN_ARCSEC / pixelArcsec, seen = new Uint8Array(width * height); let patch = { pixels: 0, x: 0, y: 0 }; + for (let y = Math.max(0, Math.round(near[1] - within)); y <= Math.min(height - 1, near[1] + within); y++) for (let x = Math.max(0, Math.round(near[0] - within)); x <= Math.min(width - 1, near[0] + within); x++) { + const start = y * width + x; if (seen[start] || !saturated(start) || Math.hypot(x - near[0], y - near[1]) > within) continue; + let pixels = 0, sumX = 0, sumY = 0; const stack = [start]; seen[start] = 1; + for (let p = stack.pop(); p !== undefined; p = stack.pop()) { const px = p % width, py = (p - px) / width; pixels++; sumX += px; sumY += py; + for (const [dx, dy] of [[1, 0], [-1, 0], [0, 1], [0, -1]] as const) { const q = (py + dy) * width + px + dx; if (!inside(px + dx, py + dy) || seen[q] || !saturated(q)) continue; seen[q] = 1; stack.push(q); } } + if (pixels > patch.pixels) patch = { pixels, x: sumX / pixels, y: sumY / pixels }; + } + if (patch.pixels) return { pixel: [patch.x, patch.y], found: `the largest patch of saturated pixels within ${PATCH_WITHIN_ARCSEC} arcsec of where the tags put it, ${patch.pixels} px` }; + // A peak tops the 5 by 5 pixels about it; it is weighed by how far it stands above the mean of the 15 by 15 about it. A saturated + // one is a star already passed over: farther than the first rule looks. + const light = (x: number, y: number) => { const p = 3 * (y * width + x); return (rgb[p]! + rgb[p + 1]! + rgb[p + 2]!) / 3; }, reach = Math.round(PEAK_WITHIN_ARCSEC / pixelArcsec); let peak = { above: 10, x: -1, y: -1 }; + for (let y = Math.round(near[1]) - reach; y <= near[1] + reach; y++) for (let x = Math.round(near[0]) - reach; x <= near[0] + reach; x++) { + if (!inside(x - 7, y - 7) || !inside(x + 7, y + 7) || saturated(y * width + x)) continue; + const here = light(x, y); let top = true, sum = 0; + for (let dy = -7; dy <= 7 && top; dy++) for (let dx = -7; dx <= 7; dx++) { const value = light(x + dx, y + dy); sum += value; if (Math.abs(dx) <= 2 && Math.abs(dy) <= 2 && value > here) { top = false; break; } } + if (top && here - sum / 225 > peak.above) peak = { above: here - sum / 225, x, y }; + } + if (peak.x < 0) return undefined; + let sumX = 0, sumY = 0, weights = 0; const floor = light(peak.x, peak.y) - 0.6 * peak.above; + for (let dy = -4; dy <= 4; dy++) for (let dx = -4; dx <= 4; dx++) { const weight = Math.max(0, light(peak.x + dx, peak.y + dy) - floor); sumX += weight * (peak.x + dx); sumY += weight * (peak.y + dy); weights += weight; } + return { pixel: [sumX / weights, sumY / weights], found: `the peak within ${PEAK_WITHIN_ARCSEC} arcsec of where the tags put it that stands highest above its surroundings, by ${peak.above.toFixed(0)} of 255` }; +} + +/** A picture `width` by `height` pixels whose pixel `star` stands at `place`: the recipe's observation, plane and rim. */ +export function registerPicture(tags: SkyTags, [width, height]: readonly [number, number], star: readonly [number, number], place: Place): Registration { + // The picture fades out in a circle about that pixel: a frame that does not hold it is a picture of somewhere else in the object. + if (!(star[0] >= 1 && star[1] >= 1 && star[0] <= width - 2 && star[1] <= height - 2)) throw new RangeError(`The picture, ${width} x ${height} px, does not hold the place it is to stand at: pixel ${star.map(value => value.toFixed(1)).join(', ')}.`); + const rot = tags.rotationDeg * RAD, north = [-Math.sin(rot), -Math.cos(rot)] as const, east = [-Math.cos(rot), Math.sin(rot)] as const, dx = star[0] - (width - 1) / 2, dy = star[1] - (height - 1) / 2; + const pixelArcsec = tags.scaleDeg * 3600, starEast = pixelArcsec * (dx * east[0] + dy * east[1]), starNorth = pixelArcsec * (dx * north[0] + dy * north[1]); + const fieldOfViewDeg = [Number((width * tags.scaleDeg).toPrecision(7)), Number((height * tags.scaleDeg).toPrecision(7))] as const; + const kpcPerDeg = place.distancePc / 1e3 * RAD, pcPerArcsec = kpcPerDeg * 1000 / 3600, widthPc = fieldOfViewDeg[0] * kpcPerDeg * 1000, starFromCentreArcsec = Math.hypot(starEast, starNorth); + const circleArcsec = Math.floor(10 * pixelArcsec * Math.min(star[0], width - 1 - star[0], star[1], height - 1 - star[1])) / 10; + return { + observation: { centerRaDeg: Number((place.centerRaDeg - starEast / 3600 / Math.cos(place.centerDecDeg * RAD)).toFixed(7)), centerDecDeg: Number((place.centerDecDeg - starNorth / 3600).toFixed(7)), fieldOfViewDeg, northClockwiseDeg: Number((-tags.rotationDeg).toFixed(3)) }, + // The plane faces the Sun along the sight line through the frame's centre: its tilt at the star is the star's distance from that centre. + plane: { inclinationDeg: Number(Math.max(starFromCentreArcsec / 3600, 0.001).toPrecision(4)), lineOfNodesPaDeg: Number((((Math.atan2(-starEast, -starNorth) / RAD + 90) % 360 + 360) % 360).toFixed(3)), + thicknessKpc: Number((widthPc / 2e6).toPrecision(3)), supportRadiusKpc: Number((circleArcsec * pcPerArcsec / 1000).toPrecision(5)), supportTaperFraction: RIM_FROM }, + pixelArcsec, starFromCentreArcsec, circleArcsec, widthPc, + }; +} From a901054204c47f5d8e8393aa17543b194a8ab9bc Mon Sep 17 00:00:00 2001 From: alowpoly Date: Sun, 4 Oct 2026 23:00:19 -0300 Subject: [PATCH 2/4] fix(objects): remake three dataset banks' records with the picture generator --- packages/bake/authoring/ngc-3132/grid-fit.mts | 4 ++-- src/objects/m57-miri-layers/README.md | 2 +- src/objects/m57-miri-layers/inventory.json | 4 ++-- src/objects/m57-miri-layers/investigations.json | 2 +- src/objects/m57-miri-layers/source/provenance.json | 6 +++--- src/objects/m57-nircam-layers/README.md | 2 +- src/objects/m57-nircam-layers/inventory.json | 4 ++-- src/objects/m57-nircam-layers/investigations.json | 5 ++--- .../m57-nircam-layers/source/provenance.json | 14 +++++++------- src/objects/ngc-3132-miri-layers/README.md | 2 +- src/objects/ngc-3132-miri-layers/inventory.json | 4 ++-- .../ngc-3132-miri-layers/investigations.json | 2 +- .../ngc-3132-miri-layers/source/provenance.json | 6 +++--- src/sources/esawebb-weic2207c.json | 2 +- src/sources/esawebb-weic2320b.json | 2 +- src/sources/esawebb-weic2320c.json | 2 +- 16 files changed, 31 insertions(+), 32 deletions(-) diff --git a/packages/bake/authoring/ngc-3132/grid-fit.mts b/packages/bake/authoring/ngc-3132/grid-fit.mts index 638dd4f9b33..5830fe02da5 100644 --- a/packages/bake/authoring/ngc-3132/grid-fit.mts +++ b/packages/bake/authoring/ngc-3132/grid-fit.mts @@ -59,10 +59,10 @@ const file = await readFile(resolve(sourceDirectory, 'source.jpg')), tags = file const tag = (name: string) => { const found = new RegExp(`([\\s\\S]*?)`, 'u').exec(tags) ?? new RegExp(`avm:${name}="([^"]*)"`, 'u').exec(tags); if (!found) throw new Error(`source.jpg has no avm:${name}.`); return found[1]!.replace(/<[^>]+>/gu, ' ').trim().split(/\s+/u).map(Number); }; const pixelArcsec = Math.abs(tag('Spatial.Scale')[0]!) * 3600, rotation = tag('Spatial.Rotation')[0]! * rad; const full = await sharp(file).removeAlpha().raw().toBuffer({ resolveWithObject: true }), fullWidth = full.info.width, fullHeight = full.info.height; -// Where the tags alone put the star: the recipe's target, from the tags' reference place and pixel (counted from the bottom). +// Where the tags alone put the star: the recipe's target, from the tags' reference place and pixel (counted from the bottom left, the first pixel's middle at 1, as FITS counts). const target = (JSON.parse(await readFile(resolve(sourceDirectory, 'recipe.json'), 'utf8')) as { target: { centerRaDeg: number; centerDecDeg: number } }).target, reference = tag('Spatial.ReferenceValue'), referencePixel = tag('Spatial.ReferencePixel'), degrees = Math.abs(tag('Spatial.Scale')[0]!); const eastPixels = (target.centerRaDeg - reference[0]!) * Math.cos(target.centerDecDeg * rad) / degrees, northPixels = (target.centerDecDeg - reference[1]!) / degrees; -const tagged = [referencePixel[0]! - eastPixels * Math.cos(rotation) - northPixels * Math.sin(rotation), fullHeight - (referencePixel[1]! - eastPixels * Math.sin(rotation) + northPixels * Math.cos(rotation))] as const, within = Math.round(STAR_WITHIN_ARCSEC / pixelArcsec); +const tagged = [referencePixel[0]! - 1 - eastPixels * Math.cos(rotation) - northPixels * Math.sin(rotation), fullHeight - (referencePixel[1]! - eastPixels * Math.sin(rotation) + northPixels * Math.cos(rotation))] as const, within = Math.round(STAR_WITHIN_ARCSEC / pixelArcsec); // The star: the largest patch of saturated pixels that starts within that reach of the place. const saturated = (p: number) => full.data[3 * p]! >= 250 && full.data[3 * p + 1]! >= 250 && full.data[3 * p + 2]! >= 250, seen = new Uint8Array(fullWidth * fullHeight); let star = { pixels: 0, x: 0, y: 0, from: 0 }; for (let y = Math.max(0, Math.round(tagged[1] - within)); y <= Math.min(fullHeight - 1, tagged[1] + within); y++) for (let x = Math.max(0, Math.round(tagged[0] - within)); x <= Math.min(fullWidth - 1, tagged[0] + within); x++) { const start = y * fullWidth + x; if (seen[start] || !saturated(start) || Math.hypot(x - tagged[0], y - tagged[1]) > within) continue; let pixels = 0, sumX = 0, sumY = 0; const stack = [start]; seen[start] = 1; diff --git a/src/objects/m57-miri-layers/README.md b/src/objects/m57-miri-layers/README.md index 5f41818f8d2..dd099d9fde5 100644 --- a/src/objects/m57-miri-layers/README.md +++ b/src/objects/m57-miri-layers/README.md @@ -13,7 +13,7 @@ ESA/Webb's mid-infrared picture of the Ring Nebula, on the walls of its ionised ## The picture -- **Registration:** the file's embedded sky tags give scale and direction, 0.1111″ per pixel and north 132.9° right of vertical. The star gives the place: the central star in the picture is set at the place the Ring Nebula's page stands at. The tags alone put it 0.21″ away. +- **Registration:** the file's embedded sky tags give scale and direction, 0.1111″ per pixel and north 132.9° right of vertical. The star gives the place: the central star in the picture is set at the place the Ring Nebula's page stands at. The tags alone put it 0.04″ away. - **The shell:** the Hubble dataset's: 44″ by 30″ on the sky with its long axis at position angle 60°, its pole tipped 6.5° from the sight line, and a lobe through its opening within 19.7″ of the star. - **In the Main Ring:** the red and green channels are ionised gas, [S III] its brightest line. They take the ring's [N II] and [S II] speed, 19 km/s, which is 29.2″ along the sight line: [S III] is the shell's lower-ionisation light, against the cavity's [S IV]. The blue channel is molecular hydrogen and takes the molecular shell's speed along the sight line, 24.6 km/s, 37.8″. - **Through the opening:** the red channel is [O IV], made by the 55 eV that also makes He II; it takes the Lobes' He II speed, 20 km/s, 30.8″ along the sight line. The green and blue channels hold [S IV], made by the 35 eV that also makes [O III]; they take the Lobes' [O III] speed, 28 km/s, 43.1″. diff --git a/src/objects/m57-miri-layers/inventory.json b/src/objects/m57-miri-layers/inventory.json index c1b71d2f2f2..31c0984fbc3 100644 --- a/src/objects/m57-miri-layers/inventory.json +++ b/src/objects/m57-miri-layers/inventory.json @@ -10,8 +10,8 @@ { "location": "prepared", "filename": "image-layers.json", - "bytes": 301398, - "sha256": "c43e388331f55df1f14caffd5e580aa8071c8f787b2867d0e5688e42e629322d" + "bytes": 301474, + "sha256": "8777e77c12593244daabc8fa680fbce323008d49cb9b128cac4b15826f7978ce" }, { "location": "prepared", diff --git a/src/objects/m57-miri-layers/investigations.json b/src/objects/m57-miri-layers/investigations.json index ef3ade1b95e..ca0a9bb15f9 100644 --- a/src/objects/m57-miri-layers/investigations.json +++ b/src/objects/m57-miri-layers/investigations.json @@ -6,7 +6,7 @@ "id": "weic2320c", "subject": "ESA/Webb weic2320c", "status": "included", - "finding": "Webb captures detailed beauty of Ring Nebula (MIRI image): MIRI at 5.6, 7.7, 10, 11, 12, 15, 18, 21 and 25 µm; 1257 × 1015 px over 2.33 × 1.88 arcmin, released 21 August 2023. The file's embedded sky tags for scale and direction, 0.1111 arcsec per pixel and north 132.9° right of vertical, and the star for place: the central star in the picture, pixel 627.5, 513.5, is set at the place the Ring Nebula's page stands at, so the frame's centre is 283.396433°, 33.0290199°. The tags alone put the star 0.21 arcsec from where the picture shows it.", + "finding": "Webb captures detailed beauty of Ring Nebula (MIRI image): MIRI at 5.6, 7.7, 10, 11, 12, 15, 18, 21 and 25 µm; 1257 × 1015 px over 2.33 × 1.88 arcmin, released 21 August 2023. The file's embedded sky tags for scale and direction, 0.1111 arcsec per pixel and north 132.9° right of vertical, and the star for place: the star in the picture, the peak within 3 arcsec of where the tags put it that stands highest above its surroundings, by 94 of 255, pixel 627.5, 513.5, is set at the recipe's target, so the frame's centre is 283.396433°, 33.0290199°. The tags alone put the star 0.04 arcsec from where the picture shows it.", "evidence": [ "https://esawebb.org/images/weic2320c/", "https://esawebb.org/copyright/" diff --git a/src/objects/m57-miri-layers/source/provenance.json b/src/objects/m57-miri-layers/source/provenance.json index 890fac48c91..1f8728d49c3 100644 --- a/src/objects/m57-miri-layers/source/provenance.json +++ b/src/objects/m57-miri-layers/source/provenance.json @@ -40,15 +40,15 @@ "geometryEvidence": { "inclinationDeg": 0.001, "lineOfNodesPaDeg": 218.521, - "reference": "A picture of the sky: the plane is the picture's own tangent plane, perpendicular to the sight line through the picture's centre, so it faces the Sun. That centre is 0.7 arcsec from the star, which is the whole of the recipe's inclination. Not the orientation of the nebula, which is the shell's." + "reference": "A picture of the sky: the plane is the picture's own tangent plane, perpendicular to the sight line through the picture's centre, so it faces the Sun. That centre is 0.7 arcsec from the star, which is the whole of the recipe's inclination. Not the orientation of the object itself." }, "registration": { - "method": "The file's embedded sky tags for scale and direction, 0.1111 arcsec per pixel and north 132.9° right of vertical, and the star for place: the central star in the picture, pixel 627.5, 513.5, is set at the place the Ring Nebula's page stands at, so the frame's centre is 283.396433°, 33.0290199°. The tags alone put the star 0.21 arcsec from where the picture shows it.", + "method": "The file's embedded sky tags for scale and direction, 0.1111 arcsec per pixel and north 132.9° right of vertical, and the star for place: the star in the picture, the peak within 3 arcsec of where the tags put it that stands highest above its surroundings, by 94 of 255, pixel 627.5, 513.5, is set at the recipe's target, so the frame's centre is 283.396433°, 33.0290199°. The tags alone put the star 0.04 arcsec from where the picture shows it.", "pixelArcsec": 0.1111, "northClockwiseDeg": 132.92 }, "displayModel": "Inside the outline of the ionised shell of O'Dell et al. (2013) the picture's light lies on that shell's two walls, in front of the star and behind it, each color at the depth of the speed of the gas it shows; inside the shell's opening it lies on the walls of the lobes. The walls share the smooth light; the fine detail is on the nearer one. Outside the shell's outline the halo lies on the picture's plane.", - "coverage": "The published frame inside a circle about the star: the picture fades out between 50.0 and 55.6 arcsec, the largest circle the frame holds, so no straight edge shows.", + "coverage": "The published frame inside a circle about the star: the picture fades out between 50.0 and 55.6 arcsec from the star, the largest circle the frame holds, so no straight edge shows.", "acquisition": { "url": "https://cdn.esawebb.org/archives/images/large/weic2320c.jpg", "dimensions": [ diff --git a/src/objects/m57-nircam-layers/README.md b/src/objects/m57-nircam-layers/README.md index 6697ced991e..dff1e9ae9a1 100644 --- a/src/objects/m57-nircam-layers/README.md +++ b/src/objects/m57-nircam-layers/README.md @@ -13,7 +13,7 @@ ESA/Webb's near-infrared picture of the Ring Nebula, laid on the shell of molecu ## The picture -- **Registration:** the file's embedded sky tags give scale and direction, 0.0314″ per pixel and north 140.2° right of vertical. The star gives the place: the central star in the picture is set at the place the Ring Nebula's page stands at. The tags alone put it 0.13″ away. +- **Registration:** the file's embedded sky tags give scale and direction, 0.0314″ per pixel and north 140.2° right of vertical. The star gives the place: the central star in the picture is set at the place the Ring Nebula's page stands at. The tags alone put it 0.10″ away. - **The shell:** an ellipsoid about the star, 47.0″ by 32.5″ on the sky with its long axis at position angle 70°, and 38.5″ along the sight line: 0.82 of the long axis, 24.6 km/s under the shell's law of 30 km/s at 47.0″. The red and green channels, molecular hydrogen, lie on its two walls, in front of the star and behind it. - **The ionised ring:** the blue channel holds the 1.62 µm filter's ionised gas. Inside the shell's outline it takes the Main Ring's [N II] speed, 19 km/s, which is 29.8″ along the sight line. A choice made here: hydrogen shines through the whole ionised ring, and [N II], the faster of the ring's two printed speeds, is its outer part. - **Through the opening:** the shell is open at both poles. Within 19.7″ of the star, the radius of the ellipsoid Kastner et al. cut the opening with, the picture shows the ionised gas of the central cavity. There every channel takes the Lobes' [O III] speed, 28 km/s, 43.9″ along the sight line. A choice made here: the middle of the three speeds O'Dell et al. give the Lobes. diff --git a/src/objects/m57-nircam-layers/inventory.json b/src/objects/m57-nircam-layers/inventory.json index 9c55636bb10..d38af8cff5c 100644 --- a/src/objects/m57-nircam-layers/inventory.json +++ b/src/objects/m57-nircam-layers/inventory.json @@ -10,8 +10,8 @@ { "location": "prepared", "filename": "image-layers.json", - "bytes": 301894, - "sha256": "0e68534f9124385f4d6016b59187f7bf2d9016a4a200f8f1597f470aedd9cbce" + "bytes": 301913, + "sha256": "d326d713c63a3d4b1f7f91adbb8342a6b75ecc419e9418e4f97735854a35ab6f" }, { "location": "prepared", diff --git a/src/objects/m57-nircam-layers/investigations.json b/src/objects/m57-nircam-layers/investigations.json index 8a86b6ad2ba..dda64fccf87 100644 --- a/src/objects/m57-nircam-layers/investigations.json +++ b/src/objects/m57-nircam-layers/investigations.json @@ -6,7 +6,7 @@ "id": "weic2320b", "subject": "ESA/Webb weic2320b", "status": "included", - "finding": "Webb captures detailed beauty of Ring Nebula (NIRCam image): NIRCam at 1.62, 2.12, 3.0 and 3.35 µm; 4097 × 4156 px over 2.14 × 2.17 arcmin, released 21 August 2023. The file's embedded sky tags for scale and direction, 0.0314 arcsec per pixel and north 140.2° right of vertical, and the star for place: the central star in the picture, pixel 2123, 1991.4, is set at the place the Ring Nebula's page stands at, so the frame's centre is 283.3950727°, 33.0293034°. The tags alone put the star 0.13 arcsec from where the picture shows it.", + "finding": "Webb captures detailed beauty of Ring Nebula (NIRCam image): NIRCam at 1.62, 2.12, 3.0 and 3.35 µm; 4097 × 4156 px over 2.14 × 2.17 arcmin, released 21 August 2023. The file's embedded sky tags for scale and direction, 0.0314 arcsec per pixel and north 140.2° right of vertical, and the star for place: the star in the picture, the middle of the central star's light, pixel 2123, 1991.4, is set at the recipe's target, so the frame's centre is 283.3950727°, 33.0293034°. The tags alone put the star 0.10 arcsec from where the picture shows it.", "evidence": [ "https://esawebb.org/images/weic2320b/", "https://esawebb.org/copyright/" @@ -57,8 +57,7 @@ "finding": "Kastner et al. (2025, Sect. III.2.2) find that some filaments seen inside the ring in Webb's pictures are molecular knots moving at 45 to 50 km/s along the sight line. They print no table of them; here they lie on the lobe's near wall with the rest of the detail.", "evidence": [ "https://arxiv.org/abs/2501.12223" - ], - "revisitWhen": "The knots' places and speeds are published as a table." + ] }, { "id": "weic2320c", diff --git a/src/objects/m57-nircam-layers/source/provenance.json b/src/objects/m57-nircam-layers/source/provenance.json index f32b6a31bfc..7135a280072 100644 --- a/src/objects/m57-nircam-layers/source/provenance.json +++ b/src/objects/m57-nircam-layers/source/provenance.json @@ -15,10 +15,10 @@ "bands": [ "Webb", "NIRCam", - "F162M", - "F212N", - "F300M", - "F335M" + "1.62 µm", + "2.12 µm", + "3.0 µm", + "3.35 µm" ], "fieldOfViewDeg": [ 0.035726, @@ -35,15 +35,15 @@ "geometryEvidence": { "inclinationDeg": 0.001, "lineOfNodesPaDeg": 9.142, - "reference": "A picture of the sky: the plane is the picture's own tangent plane, perpendicular to the sight line through the picture's centre, so it faces the Sun. That centre is 3.6 arcsec from the star, which is the whole of the recipe's inclination. Not the orientation of the nebula, which is the shell's." + "reference": "A picture of the sky: the plane is the picture's own tangent plane, perpendicular to the sight line through the picture's centre, so it faces the Sun. That centre is 3.6 arcsec from the star, which is the whole of the recipe's inclination. Not the orientation of the object itself." }, "registration": { - "method": "The file's embedded sky tags for scale and direction, 0.0314 arcsec per pixel and north 140.2° right of vertical, and the star for place: the central star in the picture, pixel 2123, 1991.4, is set at the place the Ring Nebula's page stands at, so the frame's centre is 283.3950727°, 33.0293034°. The tags alone put the star 0.13 arcsec from where the picture shows it.", + "method": "The file's embedded sky tags for scale and direction, 0.0314 arcsec per pixel and north 140.2° right of vertical, and the star for place: the star in the picture, the middle of the central star's light, pixel 2123, 1991.4, is set at the recipe's target, so the frame's centre is 283.3950727°, 33.0293034°. The tags alone put the star 0.10 arcsec from where the picture shows it.", "pixelArcsec": 0.03139, "northClockwiseDeg": 140.2 }, "displayModel": "Inside the outline of the molecular shell of Kastner et al. (2025) the picture's light lies on that shell's two walls, in front of the star and behind it; inside the shell's polar opening it lies on the walls of the ionised lobes (O'Dell et al. 2013). The walls share the smooth light; the fine detail, the knots, is on the nearer one. Outside the shell's outline the halo lies on the picture's plane.", - "coverage": "The published frame inside a circle about the star: the picture fades out between 55.7 and 61.9 arcsec, the largest circle the frame holds, so no straight edge shows.", + "coverage": "The published frame inside a circle about the star: the picture fades out between 55.7 and 61.9 arcsec from the star, the largest circle the frame holds, so no straight edge shows.", "acquisition": { "url": "https://cdn.esawebb.org/archives/images/large/weic2320b.jpg", "dimensions": [ diff --git a/src/objects/ngc-3132-miri-layers/README.md b/src/objects/ngc-3132-miri-layers/README.md index 98f7e9ddf9a..3d8a09cb8b7 100644 --- a/src/objects/ngc-3132-miri-layers/README.md +++ b/src/objects/ngc-3132-miri-layers/README.md @@ -12,7 +12,7 @@ ESA/Webb's mid-infrared picture of the Southern Ring Nebula (NGC 3132), at the d ## The picture -- **Registration:** the file's embedded sky tags give scale and direction, 0.1099″ per pixel and north 124.65° right of vertical. The star gives the place: the largest patch of saturated pixels within 1″ of where the tags put SIMBAD's place, 29 pixels, is set at that place. The tags alone put it 0.29″ away. +- **Registration:** the file's embedded sky tags give scale and direction, 0.1099″ per pixel and north 124.65° right of vertical. The star gives the place: the largest patch of saturated pixels within 1″ of where the tags put SIMBAD's place, 29 pixels, is set at that place. The tags alone put it 0.26″ away. - **The walls:** the near-infrared dataset's, unchanged: the grid's first axis the sight line with its high end toward the Sun, its second axis at position angle 325.5°, its third at 55.5°, its middle 1″ west and 0.5″ south of the star. On each sight line the nearer half of the gas's emission and the farther half each stand at their own middle, and share the picture's smooth light. - **A second check of the placement:** [grid-fit.mts](../../../packages/bake/authoring/ngc-3132/grid-fit.mts), run on this picture, finds the grid's second axis at 324.5° and its third at 54.5°, its middle 0.5″ west and 1″ south of the star. The grid's emission correlates 0.580 with this picture; half a turn on gives 0.136 and the other handedness 0.316 at best. Another instrument, other wavelengths, the same turn within a degree. - **The gas and this light:** the grid is the ionised gas, from H-alpha and [N II]. Whatever makes this picture's light, dust and molecules included, takes the same depths here. diff --git a/src/objects/ngc-3132-miri-layers/inventory.json b/src/objects/ngc-3132-miri-layers/inventory.json index b7cb97899dc..7bc4a8be730 100644 --- a/src/objects/ngc-3132-miri-layers/inventory.json +++ b/src/objects/ngc-3132-miri-layers/inventory.json @@ -10,8 +10,8 @@ { "location": "prepared", "filename": "image-layers.json", - "bytes": 301634, - "sha256": "adf333ebbf4a988eb0e87af1f99f0f05d7b6977e72c6e0ddf04fd17d78d634a3" + "bytes": 301698, + "sha256": "5a9c9c0d5eecf75ae310abe265d7352f0951a43a1dfcb07e60eb6cf9f9259d03" }, { "location": "prepared", diff --git a/src/objects/ngc-3132-miri-layers/investigations.json b/src/objects/ngc-3132-miri-layers/investigations.json index 600faa8061a..6989e0ae0fd 100644 --- a/src/objects/ngc-3132-miri-layers/investigations.json +++ b/src/objects/ngc-3132-miri-layers/investigations.json @@ -6,7 +6,7 @@ "id": "weic2207c", "subject": "ESA/Webb weic2207c", "status": "included", - "finding": "Southern Ring Nebula (MIRI Image): MIRI at 7.7, 11.3, 12 and 18 µm; 1306 × 1133 px over 2.39 × 2.07 arcmin, released 12 July 2022. The file's embedded sky tags for scale and direction, 0.1099 arcsec per pixel and north 124.65° right of vertical, and the star for place: the middle of the bright central star's saturated pixels, pixel 663.3, 553.5, is set at SIMBAD's place for NGC 3132, so the frame's centre is 151.7566982°, -40.4364794°. The tags alone put the star 0.29 arcsec away.", + "finding": "Southern Ring Nebula (MIRI Image): MIRI at 7.7, 11.3, 12 and 18 µm; 1306 × 1133 px over 2.39 × 2.07 arcmin, released 12 July 2022. The file's embedded sky tags for scale and direction, 0.1099 arcsec per pixel and north 124.7° right of vertical, and the star for place: the star in the picture, the largest patch of saturated pixels within 1 arcsec of where the tags put it, 29 px, pixel 663.3, 553.5, is set at the recipe's target, so the frame's centre is 151.7566982°, -40.4364794°. The tags alone put the star 0.26 arcsec from where the picture shows it.", "evidence": [ "https://esawebb.org/images/weic2207c/", "https://esawebb.org/copyright/" diff --git a/src/objects/ngc-3132-miri-layers/source/provenance.json b/src/objects/ngc-3132-miri-layers/source/provenance.json index 968a7535696..6f56e809042 100644 --- a/src/objects/ngc-3132-miri-layers/source/provenance.json +++ b/src/objects/ngc-3132-miri-layers/source/provenance.json @@ -35,15 +35,15 @@ "geometryEvidence": { "inclinationDeg": 0.001, "lineOfNodesPaDeg": 353.825, - "reference": "A picture of the sky: the plane is the picture's own tangent plane, perpendicular to the sight line through the picture's centre, so it faces the Sun. That centre is 1.8 arcsec from the star, which is the whole of the recipe's inclination. Not the orientation of the nebula, which is the density grid's." + "reference": "A picture of the sky: the plane is the picture's own tangent plane, perpendicular to the sight line through the picture's centre, so it faces the Sun. That centre is 1.8 arcsec from the star, which is the whole of the recipe's inclination. Not the orientation of the object itself." }, "registration": { - "method": "The file's embedded sky tags for scale and direction, 0.1099 arcsec per pixel and north 124.65° right of vertical, and the star for place: the middle of the bright central star's saturated pixels, pixel 663.3, 553.5, is set at SIMBAD's place for NGC 3132, so the frame's centre is 151.7566982°, -40.4364794°. The tags alone put the star 0.29 arcsec away.", + "method": "The file's embedded sky tags for scale and direction, 0.1099 arcsec per pixel and north 124.7° right of vertical, and the star for place: the star in the picture, the largest patch of saturated pixels within 1 arcsec of where the tags put it, 29 px, pixel 663.3, 553.5, is set at the recipe's target, so the frame's centre is 151.7566982°, -40.4364794°. The tags alone put the star 0.26 arcsec from where the picture shows it.", "pixelArcsec": 0.1099, "northClockwiseDeg": 124.652 }, "displayModel": "Inside the outline of the density grid of Monteiro et al. (2025), each sight line's light lies on two walls: the nearer half of the gas's emission along it and the farther half, each at its own middle. The two share the picture's smooth light; its fine detail is on the nearer one. Over the outer tenth of the way from the star to the gas's outline the walls are led onto the picture's plane, where the picture outside the outline lies. The central star's own light, which ends 2.1 arcsec from it in this picture, stays at the star: all of it within 1.05 arcsec, less and less out to 2.1.", - "coverage": "The published frame inside a circle about the star: the picture fades out between 54.7 and 60.8 arcsec, the largest circle the frame holds, so no straight edge shows.", + "coverage": "The published frame inside a circle about the star: the picture fades out between 54.7 and 60.8 arcsec from the star, the largest circle the frame holds, so no straight edge shows.", "acquisition": { "url": "https://cdn.esawebb.org/archives/images/large/weic2207c.jpg", "dimensions": [ diff --git a/src/sources/esawebb-weic2207c.json b/src/sources/esawebb-weic2207c.json index f2b9275af7f..2874cf79dd4 100644 --- a/src/sources/esawebb-weic2207c.json +++ b/src/sources/esawebb-weic2207c.json @@ -30,7 +30,7 @@ { "url": "https://esawebb.org/images/weic2207c/", "checkedOn": "2026-10-04", - "locator": "1306 x 1133 px over 2.39 × 2.07 arcmin; MIRI 7.7, 11.3, 12 and 18 µm (the page prints the second as 1.13 µm); released 12 July 2022. The file's embedded sky tags for scale and direction, 0.1099 arcsec per pixel and north 124.65° right of vertical, and the star for place: the middle of the bright central star's saturated pixels, pixel 663.3, 553.5, is set at SIMBAD's place for NGC 3132, so the frame's centre is 151.7566982°, -40.4364794°. The tags alone put the star 0.29 arcsec away." + "locator": "1306 x 1133 px over 2.39 × 2.07 arcmin; MIRI 7.7, 11.3, 12 and 18 µm (the page prints the second as 1.13 µm); released 12 July 2022. The file's embedded sky tags for scale and direction, 0.1099 arcsec per pixel and north 124.65° right of vertical, and the star for place: the middle of the bright central star's saturated pixels, pixel 663.3, 553.5, is set at SIMBAD's place for NGC 3132, so the frame's centre is 151.7566982°, -40.4364794°. The tags alone put the star 0.26 arcsec away." } ], "publisher": "ESA/Webb", diff --git a/src/sources/esawebb-weic2320b.json b/src/sources/esawebb-weic2320b.json index ee0c3e52e97..549fc4ea7cd 100644 --- a/src/sources/esawebb-weic2320b.json +++ b/src/sources/esawebb-weic2320b.json @@ -30,7 +30,7 @@ { "url": "https://esawebb.org/images/weic2320b/", "checkedOn": "2026-10-04", - "locator": "4097 x 4156 px over 2.14 × 2.17 arcmin; NIRCam 1.62, 2.12, 3.0 and 3.35 µm; released 21 August 2023. The file's embedded sky tags for scale and direction, 0.0314 arcsec per pixel and north 140.2° right of vertical, and the star for place: the central star in the picture, pixel 2123, 1991.4, is set at the place the Ring Nebula's page stands at, so the frame's centre is 283.3950727°, 33.0293034°. The tags alone put the star 0.13 arcsec from where the picture shows it." + "locator": "4097 x 4156 px over 2.14 × 2.17 arcmin; NIRCam 1.62, 2.12, 3.0 and 3.35 µm; released 21 August 2023. The file's embedded sky tags for scale and direction, 0.0314 arcsec per pixel and north 140.2° right of vertical, and the star for place: the central star in the picture, pixel 2123, 1991.4, is set at the place the Ring Nebula's page stands at, so the frame's centre is 283.3950727°, 33.0293034°. The tags alone put the star 0.10 arcsec from where the picture shows it." } ], "publisher": "ESA/Webb", diff --git a/src/sources/esawebb-weic2320c.json b/src/sources/esawebb-weic2320c.json index e9ff8970530..55c5c4fe41a 100644 --- a/src/sources/esawebb-weic2320c.json +++ b/src/sources/esawebb-weic2320c.json @@ -30,7 +30,7 @@ { "url": "https://esawebb.org/images/weic2320c/", "checkedOn": "2026-10-04", - "locator": "1257 x 1015 px over 2.33 × 1.88 arcmin; MIRI 5.6, 7.7, 10, 11, 12, 15, 18, 21 and 25 µm; released 21 August 2023. The file's embedded sky tags for scale and direction, 0.1111 arcsec per pixel and north 132.9° right of vertical, and the star for place: the central star in the picture, pixel 627.5, 513.5, is set at the place the Ring Nebula's page stands at, so the frame's centre is 283.396433°, 33.0290199°. The tags alone put the star 0.21 arcsec from where the picture shows it." + "locator": "1257 x 1015 px over 2.33 × 1.88 arcmin; MIRI 5.6, 7.7, 10, 11, 12, 15, 18, 21 and 25 µm; released 21 August 2023. The file's embedded sky tags for scale and direction, 0.1111 arcsec per pixel and north 132.9° right of vertical, and the star for place: the central star in the picture, pixel 627.5, 513.5, is set at the place the Ring Nebula's page stands at, so the frame's centre is 283.396433°, 33.0290199°. The tags alone put the star 0.04 arcsec from where the picture shows it." } ], "publisher": "ESA/Webb", From d18a23ccecc5b1b63685f595684a0a8395cac67d Mon Sep 17 00:00:00 2001 From: alowpoly Date: Sun, 4 Oct 2026 23:13:16 -0300 Subject: [PATCH 3/4] fix(telescope): read the page's filters heading in either spelling --- packages/telescope-cli/src/new-object/pictures/esa-image.mts | 2 +- .../telescope-cli/src/new-object/pictures/pictures.test.mts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/telescope-cli/src/new-object/pictures/esa-image.mts b/packages/telescope-cli/src/new-object/pictures/esa-image.mts index 7255083c620..c0669263930 100644 --- a/packages/telescope-cli/src/new-object/pictures/esa-image.mts +++ b/packages/telescope-cli/src/new-object/pictures/esa-image.mts @@ -32,7 +32,7 @@ export function parseEsaPage(address: string, html: string): EsaPage { const size = /^(\d+) x (\d+) px$/u.exec(lines.includes('Size:') ? after('Size:') : '') ?? lacks('"Size: W x H px"'); const released = /^\d{1,2} [A-Z][a-z]+ \d{4}/u.exec(lines.includes('Release date:') ? after('Release date:') : '')?.[0] ?? lacks('release date'); // The colors table: a row is the band with the color it is shown in and the line's name where the page gives one, the wavelength, and the telescope with its instrument. - const table = /]*>Colours &(?:amp;)? filters<\/h3>\s*/u.exec(html)?.[0] ?? '', colors: PictureColor[] = []; + const table = /]*>Colou?rs &(?:amp;)? filters<\/h3>\s*/u.exec(html)?.[0] ?? '', colors: PictureColor[] = []; for (const row of table.matchAll(/([\s\S]*?)<\/tr>/gu)) { const cells = [...row[1]!.matchAll(/([\s\S]*?)<\/td>/gu)].map(cell => cell[1]!); if (cells.length !== 3) continue; diff --git a/packages/telescope-cli/src/new-object/pictures/pictures.test.mts b/packages/telescope-cli/src/new-object/pictures/pictures.test.mts index 7bd359e3b0f..47f7f0df0cd 100644 --- a/packages/telescope-cli/src/new-object/pictures/pictures.test.mts +++ b/packages/telescope-cli/src/new-object/pictures/pictures.test.mts @@ -17,7 +17,7 @@ const WEBB = 'https://esawebb.org/images/weic0000a/'; const row = (band: string, wavelength: string, instrument: string) => `${band}${wavelength}\n Some Space Telescope\n
${instrument}`; const page = (title: string, credit: string, rows: string) => `${title} | ESA/WebbCredit:\n

${credit}

Release date:21 August 2023, 16:00
Size:40 x 30 px
-

Colours & filters

${rows}
BandWavelengthTelescope
`; +

Colours & filters

${rows}
BandWavelengthTelescope
`; const WEBB_PAGE = page('A nebula (MIRI image)', 'ESA/Webb, NASA, CSA, A. Person', row('\n Infrared\n (Blue)
PAH', '7.7 μm', 'MIRI') + row(' Infrared (Red)', '18 μm', 'MIRI')); test('a picture\'s page gives its title, credit, date, size and colors, on either site\'s markup', () => { From 93fa6fd0cba7e8e42aa4d348f7557c688e5487f3 Mon Sep 17 00:00:00 2001 From: alowpoly Date: Sun, 4 Oct 2026 23:23:44 -0300 Subject: [PATCH 4/4] fix(local-group): leave the Magellanic Clouds' clusters out of the structures field --- src/objects/local-group-structures/README.md | 42 ++++++----- .../evidence/2026-10-04/app-views.jpg | Bin 88790 -> 0 bytes .../evidence/2026-10-05/app-views.jpg | Bin 0 -> 80071 bytes .../evidence/2026-10-05/clouds.jpg | Bin 0 -> 30411 bytes .../local-group-structures/inventory.json | 4 +- .../source/dots/stack.json | 2 +- .../source/field/merge.json | 6 +- .../source/lmc-clusters/points.json | 34 --------- .../source/manifest.json | 66 ------------------ .../source/presentation.json | 52 +------------- .../source/smc-clusters/points.json | 34 --------- ...bica-2008-magellanic-extended-objects.json | 52 -------------- 12 files changed, 28 insertions(+), 264 deletions(-) delete mode 100644 src/objects/local-group-structures/evidence/2026-10-04/app-views.jpg create mode 100644 src/objects/local-group-structures/evidence/2026-10-05/app-views.jpg create mode 100644 src/objects/local-group-structures/evidence/2026-10-05/clouds.jpg delete mode 100644 src/objects/local-group-structures/source/lmc-clusters/points.json delete mode 100644 src/objects/local-group-structures/source/smc-clusters/points.json delete mode 100644 src/sources/bica-2008-magellanic-extended-objects.json diff --git a/src/objects/local-group-structures/README.md b/src/objects/local-group-structures/README.md index 5fb4d3d3c4f..68242f171fb 100644 --- a/src/objects/local-group-structures/README.md +++ b/src/objects/local-group-structures/README.md @@ -1,9 +1,8 @@ # The Local Group's structures Dots for the structures of the [Local Group](../local-group/README.md) that are large enough to see from outside a -galaxy: the globular cluster systems of M31 and the Milky Way, the star clusters of the Magellanic Clouds and the -Sagittarius stream. It has no page. The world draws it once the camera is outside the Milky Way, like the -[Nearby Universe's galaxies](../nearby-universe-galaxies/README.md). It holds 3,959 dots in 33 KB. +galaxy: the globular cluster systems of M31 and the Milky Way and the Sagittarius stream. It has no page. The world draws it once the camera is outside the Milky Way, like the +[Nearby Universe's galaxies](../nearby-universe-galaxies/README.md). It holds 1,245 dots in 13 KB. ## Sources @@ -11,48 +10,47 @@ Sagittarius stream. It has no page. The world draws it once the camera is outsid | --- | --- | --- | | 441 | [Caldwell & Romanowsky (2016)](https://cdsarc.cds.unistra.fr/viz-bin/cat/J/ApJ/824/42) | [Record](../../sources/caldwell-2016-m31-globular-clusters.json). The J2000 positions of M31's globular clusters. Their depths follow the published profile as [M31's own bank](../m31-globular-clusters/README.md) draws them. | | 165 | [Baumgardt & Vasiliev (2021)](https://doi.org/10.1093/mnras/stab1474) | [Record](../../sources/baumgardt-vasiliev-2021-gc-distances.json). The positions and distances of the Milky Way's globular clusters, the table the [galaxy's own bank](../milky-way-volume/README.md) reads. | -| 2,270 and 444 | [Bica et al. (2008)](https://cdsarc.cds.unistra.fr/viz-bin/cat/J/MNRAS/389/678) | [Record](../../sources/bica-2008-magellanic-extended-objects.json). Table 3: the J2000 positions of the ordinary star clusters (type C) of the Large and the Small Magellanic Cloud. Sect. 3 gives the split of the sky: 4 h < RA < 6 h 40 min is the Large Cloud, 23 h 40 min < RA < 1 h 20 min the Small one. | -| | [Pietrzyński et al. (2019)](https://ui.adsabs.harvard.edu/abs/2019Natur.567..200P) | [Record](../../sources/publication-pietrzynski2019natur-567-200p.json). The Large Cloud's distance, 49.59 kpc. | -| | [Graczyk et al. (2020)](https://arxiv.org/abs/2010.08754) | [Record](../../sources/publication-graczyk2020apj-904-13g.json). The Small Cloud's distance, 62.44 kpc. | | 639 | [Ramos et al. (2022)](https://cdsarc.cds.unistra.fr/viz-bin/cat/J/A+A/666/A64) | [Record](../../sources/ramos-2022-sagittarius-stream.json). Table C1: Gaia EDR3 stars with the probability that each belongs to the Sagittarius stream (`ProbSGR`), and a photometric distance for the RR Lyrae (`DistWGBPRP`). | ## Processing -1. `packages/bake/cli/prepare-catalogue-points.mts` prepares five banks, one per [recipe](source/). M31's and the Milky - Way's read the tables their galaxies' own banks read. The Magellanic and stream tables are CDS TAP queries written in - each recipe; the downloaded files are not tracked. +1. `packages/bake/cli/prepare-catalogue-points.mts` prepares three banks, one per [recipe](source/). M31's and the Milky + Way's read the tables their galaxies' own banks read. The stream's table is a CDS TAP query written in its recipe; the + downloaded file is not tracked. 2. M31's clusters take the depths of M31's own bank: the recipe copies its profile and seeds the draws with that bank's id (`frame.seed`, [catalogue-spheroid.ts](../../../packages/bake/src/volume/node/catalogue-spheroid.ts)), so a cluster is at the same place in both: every dot here is within 0.1 pc of its twin in that bank (decoded and compared on 2026-10-04). The Milky Way's clusters are at their measured distances. -3. Every Magellanic cluster sits at its Cloud's distance. -4. The stream keeps the 2,553 RR Lyrae with a distance above zero and `ProbSGR` above 0.9, each at its own distance. +3. The stream keeps the 2,553 RR Lyrae with a distance above zero and `ProbSGR` above 0.9, each at its own distance. They lie between 7 and 92 kpc from the Sun, half of them within 29 kpc. -5. `merge-catalogue-points.mts` joins the banks ([merge](source/field/merge.json)) and keeps one stream star in four, in +4. `merge-catalogue-points.mts` joins the banks ([merge](source/field/merge.json)) and keeps one stream star in four, in catalogue order. `stack-catalogue-points.mts` writes the one file the world draws ([stack](source/dots/stack.json)). -Values chosen here, not measured: the 4,000 dot ceiling and the one-in-four thinning that keeps the field under it; the -0.9 probability threshold; the colors (orange for globular clusters, blue-white for the Magellanic clusters, warm white -for the stream, each the color the Milky Way's dots of that kind already have); the dot sizes. +Values chosen here, not measured: the one-in-four thinning of the stream; the 0.9 probability threshold; the colors +(orange for globular clusters, warm white for the stream, each the color the Milky Way's dots of that kind already +have); the dot sizes. ## Evidence -![The Local Group page as it opens, M31 pulled back, and the Milky Way pulled back](evidence/2026-10-04/app-views.jpg) +![The Local Group page as it opens, M31 pulled back, and the Milky Way pulled back](evidence/2026-10-05/app-views.jpg) -The app on 2026-10-04. Left: the Local Group page as it opens, 7.3 million light-years from the Sun, with the Milky Way +The app on 2026-10-05. Left: the Local Group page as it opens, 7.3 million light-years from the Sun, with the Milky Way at the left and M31 at the lower right. Middle: M31 pulled back one wheel step, with the Milky Way and the Magellanic Clouds beyond it. Right: the Milky Way pulled back one wheel step, 289,000 light-years from the Sun, with its globular -clusters in orange, the Sagittarius stream to the right of the centre and the Large Magellanic Cloud's clusters at the -top. +clusters in orange and the Sagittarius stream to the right of the centre. + +![The Magellanic Clouds' markers with the field's former clusters, and without them](evidence/2026-10-05/clouds.jpg) + +The two Clouds from ten wheel steps out of the Milky Way's page, in headless Chromium on 2026-10-05. Left: with the 2,714 +Magellanic clusters the field drew until that day, which covered the Clouds' markers. Right: the field as it is now. ## Known problems - The field is drawn only from outside the Milky Way. Inside it the galaxy draws its own clusters and stars. -- No Magellanic cluster has a distance of its own here, so each Cloud is a flat sheet of clusters at one distance. The - catalogue's 55 ordinary clusters of the Bridge between the Clouds are not drawn. +- The Magellanic Clouds' star clusters are not drawn. Until 2026-10-05 the field held the 2,714 ordinary clusters of + Bica et al. (2008), every one at its Cloud's distance: at the Local Group's scale they covered the two Clouds' markers. - M31's depths are drawn from a profile, not measured; see [M31's bank](../m31-globular-clusters/README.md). - A stream star's distance is good to about 9%, which stretches every clump along the line to the Sun. Only RR Lyrae have a distance in the table, so the stream's other stars are not drawn. -- The Bica et al. catalogue lists the clusters known in 2008. [Inputs](source/manifest.json) · [Delivered files](inventory.json) diff --git a/src/objects/local-group-structures/evidence/2026-10-04/app-views.jpg b/src/objects/local-group-structures/evidence/2026-10-04/app-views.jpg deleted file mode 100644 index 0a89b82b03142400492ed3554919cc3ac948b961..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 88790 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 z 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 diff --git a/src/objects/local-group-structures/evidence/2026-10-05/app-views.jpg b/src/objects/local-group-structures/evidence/2026-10-05/app-views.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d69c5e91f7949c5bc291aed3d93c4a4d7f529312 GIT binary patch literal 80071 zcmbrmcOaE*{6Bu*=Qu`2R%GSS$tXf(C62wf3VArFtYjBL$4ntJBzq-ADI*n*%#fK8 zWn|MZ3sK+eKI$2t@8|pb=lAaEocr9@eXaL+y~lO;{2KZ-0;xh2fG`voN=ghBHTbh< z4-L(pJ&d$;;1A>ey-a(-fBW}w>|+6c1rBg>9uN>YbnuYKaWS#us!FP7&iEjM!2iDo zc?B_1qq_GDp<#Xq#RQ|7;9rdpHv~gy7$N8n!6-BZ6^4=;v~rSL{@n;6tr*H*!w?-B zhER-XM$qjix&wkxTd8ZSW_p-8a6?{hK;CcO&OscaUt-VxGcXMi7hY_c4Y3uG@6ZH0 z&!?gTez)$$ul|DY3fq4kM!s1fh=K&M3}(qflp7Fjl8+}5F2$3d5CEU@w~WBF)3p0s zBf&3px56)|d#@6Nsg$dCe$L=cN~QNqfcv^27{|%-VHI;5V$ZJdj~0RipoC2#e8FeQ1d^}D)2dk&%&`|n z5Fqq}q*Mq>g{z53zmWr(1mv3%v>-&K+{tju9fIvjJUK5w5Dn3vDr*a#9Y@;!5Zhs} znm%!`jWy&J4e@saTglBwIYbC9wEq;4M!pHp9k@0}HNFaQPTM``7Jvi;pU6ygA|0L2 zQC7AV_tToe{COm}plBZ~nbL~Ji8RR7)!_Z)n&);O7 z4=x0t1HrRDiGCY@?jqlqn;~`th_(nqge>nzgrG5Sm$n;xfGwLpB&AyAt^w{w+yPAx zw9B6Fef-Be^YloN42g$(x_GDwEUHH4*xWP=&wGA*FD@g!x7NY6G}vlQ4Rw0D`o0)~ z9t~0NGIxf&dl(5BhO(N49;hRb9N;MpAK)#-6F@|yNCd*eJiGv;20bgh6C(-dq#mz? z7!awkXQTB#P|1oK)iC2Br&L&+rdn&hF}ELL7sAZr+%mvWWC6IHg~FDUy!(EJQV z+7x4kz8^%}>8V2C+CMtUb|)npe%I2|3E_xhc<^iuWp$uovS5c`}6 z(VC&HQiLixh^RIqByT{lCZ=-P0RcRC*9;6JdsYwVcKce8`xvm5c+S(=XjQq|b7Lp9 zDx`#a+Ku4q5CWtPwmP8a)20O_z}E^^k5+qs-`<$LvSjWChVMp9mPa-THQ1U;W#GqF z477rWju2Mg*TFST<7}4-U0&&iywgcwh5yp>O9Y4o@DqYK9qjYcsN5K7#7bWZo)NOX zm3P~pM*(>ns>VZ@V&npuLTn#o9ny~?T=sljs6zw|py{_=x456ppZ@gm2UY8>J96uV z=O2s&-?|fZT2pN$N;D_TDHWZUu1C>SOv87Q>Ub`#+na8$;YtDGQRBf@F$;mU&~=;i znV01w`-m(+Y_K@034heJg9QMB${JWmpJHe_B&PhK36ZIf=dH~1ZR|phXBnX}W@Kq& zuylS#K)l_%h~!2{Yh-WE>V$YUVDEfRI!Vwgo#B?pc|6x*%l)J`x-LrRHYDeH!xaOs zSyXSddiA>d->5(n@LuH;{{0>hY>%n1kp5%vlJ74ha? zM0Da`OhnKHm7&o&)QUqc0TfUI7z1`*jN9T> z)GpQnD{{@;CIPni7JZs@v_XaiQ+7kEQAKeit4w@C(X@*wbGhF zaJN^AkT#F(>$Ek{13*;&f%uuN0~yOdsTxnN&iH#3$?$RP@#)_|rUI`9WzD29o&hxLFpI^Vc~g+wosFgHuOJyV3pJuo+kh^oQj z0_c0G&d=+ia@@xWx5Wthq%Z&qrnozpD>z=$M`^G8m#g_13e*2ri4H zmjp5d8f+cx4_x=$Yz;CjMI3DrJtYC6?FD|aLb>!Wit~N(>EGP5ye4PlJ?18F)f(LL zw|t9buF)X^hJ)u*A0LX7q<02)BM_jUn480SKm%!p8mx$5I`36l zGt0^%Jz(E%z-7^PpG90fOJ6v22>LWB(*RU271Hxg-+5^yhIhRI79cP8s=vF_r_qfF zOCpM2p+*|n*LIu(u|Ej&z_Uyo_$7K6<$}rK6(Uq%r+pI69Vq?Bi17f| zlw;XJxxqEg0vf@Tud)@s@m*Mv9-NnwDz0!P)aK08x&)0VcoLZu(`p!*DC z#RUq|r%Chsg6bYjV08@73&msPY8%ORFA}Cl`|;xYQzJ^ll`Q8$70;=O3_R^;%+dQMFiZzTV?Yo z)K?zE11B+tOvEE7MY1L$jE697$c?|r`5Yp&HHK3EHSVc6V5ML$m) z?C0B8eOd}T4x^u2AGqZcb>`Uw?8wyDVNIm6IrwbCT8~7z0mL06+DT>H2EscrJkNQ_ zzK4%aq*)i6o;cptjfX5N5BG_q*0{#m0l1o%3td@)pIc%6o(Y-H?GaD=IUsY)196}; zLyZaYa?RCXU;zjd8RH372O?c>ub49QMfH!=*5s~w-d;pK=zYVBus;|M0~8(Ly(PWI&HUgu=8;4KnHjXAU?2k z1f4&7fbPEuKotV@U^cL;LIO?rO@J_&z5s0#!2anaIYFvafk!p{#r?5A0rIiCK#N!} zSn?ki08tJ_ohAUUM6)=l!-lkhP!zD_YYNdE{2+@PxeEeJwqh+LqM}TxykLs*_d7>) zxhGyDcE1w^gz`V-ZJE1kAp#J+CuM|FusFhW5c$7t1@W_#WJLr4qA%tk!Z?t~Wkdsu z>ZcMHK$!W5q|%AtlD#xpTw3C9WCk%@nUVf|yQe5yI}pA$BM$?6gep`YB@rRuYORxt ztRt!sBx`4|IM7K zu2JL=*vF2zob`79_6VaG%bHqyy{m&3fkQh-gl#mzeHokWW{674)O%fWmE4UOE~n!m z^GAl_Y=>!xJeooPQGXNg;XDpl=|&zTlmIsN`}TM9# z6@uNF#6V=>y{ZQczzm3t29M6mvfl?39J2Xd3sT}g;00n8w7%s0z?1pR`_E@fx^BN& z5AtrdjY9@OU8ocY_P5OOr=Lx)fhBNmL>ZC{X@tuR31*=_iCT!}MnX2+zkeTiI2Cfb zTQrSyLrCnKBGxh+ojvd51>Z&~>5CF1h2p6*i$_uyOzWR`LSV^^^A^w}3d*fD};i`Q5dXU)Qn;?Vg z4xH}H%-vpW9o!Ej^JlNb=?SD!q^c`?+RM7RI z4c<#%=L3FbzU!NC4-6<(Ix*6>B0;Q1zX(gZ9XB`2DTIeIHtYRa03IQ3*!nIAF32=j zt82CX8Z2KM;F})sfiMpCryl|qbC~FMznN;WPHcT|ugA{UM&7gQyayMuvR6mD(t@`QassSL0$rM7i1DFWkkesDwG9nc;*mCO`tuK-}1dK zdgspUI0Tp71nvugQk4HKePN1WX_>-0`4e(iX7blpbjRKh2R7#dd1HELZuS74z(DiJ z3T3`=-b{Fz_>WaPt@RY<6zjP4LsT z6E;~JKSMWM+T$ya%3mleMRHWB5`#{~&f^qfcz{=87=O9?4;|-_W>$F+BDot0yaIVr=tpUAL_Nb|#$l zJYcfrK-Qe*s@I2WvVM+WNZ>peGM$18Z7VL`6OR~EInF@&)aYXRNv!8JcLhT6d zN4Cpe5T=iZ(1xQ(1%Wrb5wwHw>I;u_%54b(*rmPcz3Ue{Z@R5{)e5)VIPvVS0ngdK z`%M_4n89QiO8*$yjqq%fGYcT+LVGH&6)aa-YqO~A-`cqva&w!XZ z&vMh%N4-IVOIanES&!Z{ecxQ$zS6R`cVJSf(`%mhszSik*dB$&N8nArO$F zt)lv@h`===LNG5n-bw?0KouP+)wedR@*boTAzVZ?NNo!}8G-hp2(UlktV=@6nKjfFCTh}LkL866Ezg28-ECfZ>EjN5wUGdC%9Han-0<^0Q;DRlLTm%AUh#(zY z$>&H!>ow@LXr7$&?mH0KVr7@ec{}@0c|i&24H8t&%O!%ol+_@2VTfL&TyH7rvNr5> zxF)!!RJn6yujXo1_s@*YzI&@(t!s5HTLEKt$G)BH%gV6%y3KWr?3a%NrXnPwcUBn~ zg7tMn$)af~Nf44XosAZd5qFEX$ef%V&IaD{PhPg$0fH8%SecC!A1&6gY+bqbZYT5V zW=&e4)m#8?XHff;=j)tI?Cx%x^znaRi><9oPeqY&1hXU4QA6}}83^LN``y|%Xlyp{XG2%n&ZF_zz7f~h_MN(_<=Bj+ zlkCeaQ+OoBK+t>_ieYiC34c)b_))NS>%geN$snr5Ul7;#isN-}wwN}RRJLUnkE~w1 zwG%s86<$1m2R(slP#MZ7-v$m|00Mw?mYUm;VRRx^$Ys0)XZBq{U~N) zYjR<=YQpUVuowc_+aeRwL}BnCVaE{}LbC$Yd|HH^NB1Cc%@wAud*JJDfdf0)^uWk0)i1Hpcgdm>xGL{s7kOufjZ?A}qfEfrru^L7Kn8^x82ZXxOjdoGM8+`;N`@58r#4wy!I(^iN`! zK+zZnk~ZLl0YEc!{=IP!Jz?hl)VO|^3K4z+R}D1T3T*a3&&OYo(RZbS@v4&tR}_@6 z-*53UZe1_(Yw6yW`|=Aq(iU`QUS?Gx)?}pBzpJBy13*0JE5J~C#=}}1RE{9@qc~(h zP_j&QiIWP6>gLfrQaVcwFrhC%>mPQZpT>x^*kH-X2W-qe;e{*hx0)k^)u&{p-Ij9Dke(PBode9yRcbgtD^YIJ~02SPS zJp~HH_fkbIh-3#b_Fa)2IMRCpi_jFtu^p~Z?)D;Lib2r_J!ii8bp40nn-hW5tMWlD z%Z)8(Bp61q+T?U(VH#6R>*&_he}i?tF~<|6as6#-{aW-;<~eG`tE` zwg_;gGtn&rR2%fHiF0yeXQvX6C%E(piq8GJxC>SYe-NX73_#@2m#wk%A2LB%KYl?h zJF{Xoi;BE%%@c!r8~xcE*F09fxS7v78uxTh)WbHUza3aUA3#Ob}#4e||9 zBLpflJF%eG+TK?|pH`RPN-P8l&R3Rp6JUtGjMp?2SC z-U^g4;;MbOSBF*lXMwd+myxcNa~@*4;J_#^U4R)6FojIOVnDnLs?WO-=O53$dnCek z7{+<8YJ+Ij&)h3D?{fJfhdG-Dd{iYlLTi~Q{h~og!D=akB zV$nD^n<`c%J#$qq)TYoYC~uipS03y*q2N<#b#GI7Yk0+e^n>I^wfg=x)U+60?=}E7 z>)`CzQ4rUHLnXv7DqinOvHG)N_`|E@Uy$jv&6%~jhuaQ=8NVP8rL-NX&l`{41U+58 zb$oM7ch)8Bc-uL!F|-w;1es4%)^@iE)?}B>LnRCR24y@RI5o0G{%IqBgTuCqc93*B z^NY=MBcFEM78DOW`WSt3tV^b4*=^A2Wss8LyPp>~4eQ=HOk;@ubj4lQxW|H2xXGF4 zZrx*Nj&f!6u3kVpBm?$STiV@~#mq zE~q#40Pxn)DO&kF9yKk$386iA>ab2#B5`oHZJn%JSRAMg4m0816p&yFaMkjl7e&24 zNvh-TqbSNkJOqwFej6X8zgiJk8e~}D?~=l6)vtJFY@@@g1Dp|na|CUWx}}0-e-Ck& z6J%t$UF@?Q(vO(~f$*}?u3h|>PhyW`A(Yy12FA%?Gw7P3bb-T(ck18e@V}ozBu)F= zK=I{exjCBPlI8m^?GRV-@3S(?Dgbr>HU!>6JiN7UR#Uzz$<}fFIB;;)?d|qeMX&E! zDX}U3$00b-uf3OmzG|-;fX>Spb+^p5?LJ@Yce{q*a=UXZtB*>qOb7O77}ZIREMr8b zurLDF4r&mfI8bd49El!8?}h!3{`?6)fri0BrE*nsUZ313EDbCY_aR4QATCErUC27*X@jF?0M9D&et_%7iYSg0_n)H!Jj9{-#%V=@LhqYFB?2QD8z>(o8FX)^3U{Cu>ooHaiN7K8X#%^zOTkN1Wu1OzWzm?t? zSA*(SS(71Q+MH6QI%?m)ay19lKw$up@C=N%LQ(`K+ePJ6}_i>S8%aB8$^ zYfIhGK)Aj^T^2ZfO#O!$lpDzF7|0Pk0E@xayjoeztx}^@_D|!zA2utGo++*LYHU8A zOF@E5l?!dpt0Hj*N{f8n1*+b`&S50X=eRkfVD`Tdm39ZHwh>480bIW)?LLq|g9Rbg z?l1N^xd)|qgk#{;8?HPbNG?2W-oVl?B?eS3DEb6lmx$;wAws>)g4!JvI}BcXzFqJl z_DRS)%UzWvfeO8Ia%YY+k%d{=Gr6e3)d=8v4JSwPk-iR4F0KHlCPV;=;CxKfh~BdX zppo8faK3);4At9|8Ot)l?}!7p8;w@}98ImybGv%RyE<;7QKJVnof!q+PTs_nXsV#D2gb7IXdW(CE( zXQmml3RV<9)lnWUb6(^Ap1t@A!}U>P=o@$1NV=G6)s5X~>=J>7_+?^Y2Acq813X7^ z8)OjzaDjFyHt`J!nkZ?Z>sBVIgBDoOjv%(6j3b;UWR8P*% z{lPgLlo}829L@fxzKV3*C2~y_IcG&8c!Yqb1*ihb-n)te&QN|qHRLkb4#?u&Zfn{c zn)6vb?3!`O)KyNm2WL>tI6%`XUwf~9E=9PwE%;rFU1ibPs+$%MMGS2?WVVzJi<#G$ z=5d0zEWn`ha-YmVy%r<`q3NIy?!6iZ(i!?Ch=vGCI)KoRGLN1E2R~5X_pFee`Pun7 zxr$a95=cn?MeO%?i_zc~IEaDo13gD}P}61vSwBxDTIC}1kdT}IB`$lAF7MKA7LHs4 z#SksTlJ6qQv71Ow)t;YYTa+b&nuld}0uVnv-Hc-O3IPK6judU&bndP?VZbFgktQ8g zcf+Rwkzk5>xF>pUBW||BL1l=91alxK0^($gWceOMBfcQ_7x%2gX9e=xRLGW)m!bYk zddN=@2>#hHToC=20tvY(h6geNlKBtqLLa&6L%t6nPqa=1 zLqj#V+RH^Erz){D!5>i-2p5_{&6-q(we&fOdF)bK&YHd8Z#8}F5PLs&?w7$ z>5p}4!Q!AY`L>nJ4RS!vRs;?VLF|LnD0y{>54{PR*+Ep_Te3irVs|OP)@ppkjCX`v zwpXdj{oW`YzNTlpy9DQ}N}01vPm=T9|W=kK>^ z_k0?MWEnt4y>|&nQz{F4j&msDVxhfH0tlet1ehEM5ElAD)l&I>91K%KKokM)dxHZk z0f{d-*(*&=wBS5P+kL{fT*-9v(vS9)K=iUw<)$_1_3|m=H_Sm9i)GrLusw;B?WD-g5!?7 zbeTH2fD$8+KkmZ2KUgiW!M;oW;l)rYczXf;G+L_TvPbv>fLh@6^KB6ksTu?0y-`Be zGkHA+aU{%5RQUy+nY`6Cy!)!ypV_`l9HQO52HdATeGXZ$7#=|`q|7e@5JA3^20sQw zg2Y8ErC5ey`#*jE=QoHf|0WtHVDpH%EKWVk^CI6y5q68{-!9 zb_o=9mk@LYuahmECIC1oZZbWD6cSAoT!6HFz==aM0 z9Cg)T<`ADj`F_86hYL884s|DB5rq9v@214(ma?vL(-u+Q25$rsiM7QC)u(e_0-wW z0yk0S&;%7dW}H%tt}N%(voG|raEPBY>`nL}rTJmq5Q?+n%Bcz&aTm1dwfvqOogzPz zIL~#{zODMgtH1;A=Jay19fC}Id6RUn+xKx3qQ62jmCeUdEoK%Ac3ltQr7KB{{c-(@ zwCzVVzsiRs$vn4&?ftFN@5+v-`Ri0RFbVAEvePbef;#Y{mNLmy7Pf4O^bh>35~<~8 z3)rsgNQt;9l+i8qox9U)WNA}-)1*IPL(kkffB3FOP!%3mbzZx8Ww_1w$X!D9g=VV`@0?>Dy>!tNcN=(srHAzc?D+w{1`?Xaq)BPNmvGUkfQhCR1dEwT&-A=JUP0 zr8HvU0+RPPF26k_mLu6TEHwA|>Lt4-9>LcFJL8AmLW>9Xd`|j;HENYl;1!I;SUV89 z%UP=)?qP1|Ku=TWR3-E-rR@_weEOA8(J8IZt*Dmke(oiL-RGJL?mN^8oOCA!3cFtT z5MeQ$m$Y_6dTv|c*63r3S4koiZAR=aA5l+MsrC73&fbaAv(sIAE21r;l4H&Jsyl(| zPNOI+I^#u?@1Z%PAEjtZBdpJPYesdLNn81RhH{);M8fq}?g(Fzl}{f@ck1@*&MDi6 z?4_-Y&@YAGXftS{1;)<}X`X(rUXuQHrJgU=KH1Nm$npv`EF(f$`j-T0y+`|n!$lgI z((vi*AZn@6ZE(B?+nzJb zwsmrNXV`40W7lA)=P+dHFIv8rpRY^tY`OA9M(!nxw?iTpU!Jb+6=5EXa?Qg=%{%vzkSr>Y*l8eL*2Ax$k98`*AfZj(P5<9-bGm<{u>pe#*8{FFxmaTGl)g zqA$A}%o8Hnp2aaCoc=hOh|=}KTREM4ZCHg5&^Y+g;7UZ_Y%lCrUM<~D7b5wk`vX>T zdiblz#*;2l-S*l@m)g^EwZT&#!Y=rPB{-OEcGHN6xh986c5&)27W#1##kB=rL^=n< zQ!9f~w+i($S-weY%F4~dt~B(GQIcMt^Y`#SnF&aKxAOS`CQ_DoQjO_eqC>(Pt|yX>>ymY*5rb%hK0PzH}&xrDz}X zI>%eSB!{0mv^Og!@q#K%&xB=4X`Sm`n#ylkJPtl+{m#lyMz}Ilzmr;b`iF9|rc=vH z_<#n-R)cyTmF%G(afa3>m*~}M@3-40&qOIa%iX_n>_xfulcJOxdXXNRc5X>16I;Pw z(9oH8-*4rf;X3MW;rR=yqC4#99HZk9|D4OCQn-s^fh0&>8P+-(#+))zvSPJbvRJBFS~H==ge_kQ<-aOUc>}S*R;H_R{fAnj|Sy7hl-QrDIm7_VL^ci13&!9$cHg zAS^_JwKw%l^7qnL;U#ocM2uO#pntq75_+|R;mSH4ZfC;Ewtdn`qs7>(6NwT(W*c{rTZ&wW!#-6Qq%*>oDZjGf_% zS7^Et_sad)qp8CpJlRdrLoaBXDoIWb*-7^v4jG;mkQG*W+aW3boR(LjOQ3C^iVAD4 z)_mPCry-rc;|(thiod)@r1ewYEfaa1aj6`ya^z-6v-E<2YrPj24Lk>IMDrE9vd!P$riMXS5Ol^ko_uBOh;OqcPrf3 zI85jrL-MxGsIX96*u!;2>%d}{M~%!=>F!;!>U_!`ed|#g?XEV-onMx)92_*GVkrib zj0F4%<;$))tahXo49_gB3WlZZs>51XkFl(W7|n#)X``wRrs3Y(_TO(F=5KDh=d5si zBkRVfXGosrIjuIky^TXFJtzE|o_tFbT4sB_H{RobsGxP-OW*R0%WmaI<5>CNAr)3* z@%v2`7Ee~fO?!nTBy_c%TRCu-x$jc573-UKUAH&dYt^CCX&Nw&4R+Rd%Km|;5;Czk z=U=~1`_$||Mv*UN$|EnbF% zyQnyy*ztDSzch^P8=0<|f~s}w%5rfTS8UujuN`UNG^Gm|`J<)j(E*AG{T zuis{AjARVY(o2&G@eCQ!3>7q+aU(@1Q3-o*5z@uv8_3TJ$JuH1B6SBNUzq)7O3-BI@!8n-W;({A*A zpxJon)@A!9ou^43Z(kPLHVFM5%lcqq{v>sDT@NYTu-%OP1)1mm6&`xvm`?w}a|Lkhvm8PPQofCpQLiC zCPS6!+|ds!e?gv)hgx%u)cSfeqH-4wB(@3Pa?<*~xQDri ze!7w85wjsnWu^YmUFQU|Eb&mMV{NE5Gp(H++aweJJuhQkv}{?^h`IQhDm?N|q2uz( z<5)%+zr4}Qme^rbP8Nw<=T;XkdQ|rz-*-mNMA~NFC+53f=x)B@t(1pYj z7j<~vC}#XlavS9T{;8))L!t+qE*I+YvUGAd|3niLd^kOzUK~|rCc@jxF7@h3xNSy( zF}+WW{`(j{Z>k2q(zQ=ZG{xaDu%Rj2#qM_>8eVzvE}C&37SE1&BiD57qWOWi1hmOI zq!}?_^g%n^sOOV_sZhbWl87FxzKrpYrkgTl4ofvfg<3*~3Yk-d@^rMzo)B^)hhfoa z-~8Mh8l%LR{auIC)F!l_OsPur#=TiM!pJ9;pK|>q;eO)K>Bd`{YoR< z)XE3a*2a@27A_{i`dSR`#g^(PQkU7~K6N|Yr*=8T!+yIe2&KPBzX%_)pko&q78KF^ z>zFPRHgG%&7fHzkwb3TZ*De*AKhH1YFW?n3)F8$SCf?YeQfmCEC~;0#*JOnRcb%88 zU2I71R;aeKUe%>bFrfSpjURfMy`PeiaA#&|iMpImdBR9-|E02xKx>v&n6AkCp5V`( zG^*?s)|u92^a zj_&@PY!4@kYrX}!Lf?jSz8ceif2R8}`lIW-srFil;6uqS)`*u&)N@A_7~hoQbo51V zajV3HJjvjSe z9i2>@VMXjvh0C>uUr>OMh_~|05RZdzQKF)d0o&cf2Mbh~?IredkfM`5vrT_y&Ey!` z%JMb;1<9+nUZzWJkHaM@no}td_FmW2$!BLQ*vBs5&X;8NE-hY-+J}wt`LR$MmD_Q# z^j^tE%(YQz8mLl6Yz>DzF21dSb>`2v&q9xTi49BqbCGxCw=qH_PyX~44m*w zEECsAGBeXvY!Dt;-hH?|gXy{f&DtNn6w@=ys?8`Fgk1^Qf?O=)}giaF*~*jk@e z^`#3xvcoTOQ_4iJXTmZ66u*wAlXAyGX0<`yS(1rKLgIYVk%lXV?Y&Pk(aFxOeAOms znzyOU*GnuGsO{@fEsv#1iPy#yVEGWP1Gkd$-l`;-S&?w6sa|Zcf2rDdzWM9XkyBWu z*B(yLo#cTF*!_%4&tng7e@Z2|n%y1P9~a2qnjR%1a1|ROp?jK7`39r*q0XcP4{K3B z{KTk*86BISviP8MiMFtaUuoj3(b$pJR97K@1xQbIW9v4mWzxI|-I*Da~MI+B;%Pt|@%=T#CxP~3|dWiR=f`#GZbAwq5{9U4O zuZ0Lhi`LOh%h!anvMJJHil;i7yAxh_36~3`CS}LAV}g!L5*v<$$>0^${`o(^2ZD|T>VVg!R4^2zh6zZa@!{f(|enBr@Hv5VSUcEPp zYCW!9{MkQC4lomqMTK;9lAzF~1zKU8mP*1{B(KZ3BG>D*i3pj< z2$Ag*S}T+B0Sk8-QX>2YoDXe`cPToxOBX~bW=6it*Io}TF@p z+Z_8@b3X{DwAD|rX6IhkO!Zek)~B;CPI#x$s5FMp;ETVqWq=|7(9ozNw&ptae&LYk zMebYd`H1{iTqW<=N(o8ooe#*5f#V0_i{z$;)Uynx({N+T*7`nYuR0s+l}GrRyv>t* zg;FQT4M>$)>t{RE2b>o9eE7{BiIF);t#2Y}t4Jg<- z7JSh{O5eto>U+eiLyK%zZYbsZIs8ydTWfS(d==6XMqhI}=B}8?G3}Etn*)l(`rxesNI#-q0x!e{pwSi!QyB0LiymqLeWQ}9jcY}Xgm&G@- zh;ORIpTAd$+7lYlc}Dt0#pT$uA0+mFfHLQ=<&hLc?qc4k9XD})@{sT{jn(*x8~t*o zIZ^I;@0GW5z5Y_muf3SJM$eYi2SzE(pOf~@WsdZlDg_aDFJ^rSLGzP@)H$* zTB9hXs3Ry5OOtLq51;c-mzZd_t4iB(is#SOM;KDZV07qL?*Hs@z3=K@uVd1%`ruov zH`GSINA;cUMu#k$di-jt{_Poxk^H8A<1*NQn&Tz^RU8!C1uJ0mUO{RQT=JExRj$i z&(W#aTSxVco~t@HC@d4NJglTmM~%3@e*Dwnhw`Pg5Xz?M#Zoa`$@j%gQm;D4z*h*I_z~jg=91+f09LM{4`rps!9&?=w4?XEnUK%N(}k1U}zu zFQdMATC~{n&3jMVqXzodg{_<}&K zKaHu4DUTeF_!^CwD-=gBdVW-0F2_L%+^zec*?LBZb@bmopopJDJ;j z>iimM*Jrz0ZgJf48E6eSe-6d-HM_G&kKAC^9=#DbAdcrbE^n;IU? z;bJ`Cn2W*YX^kC>{;DGHOk;mqmHGJVtNhFjF%lkoJ5-i?q{6bKmn7~SYRY|~GVhhI z+ek#s>Yvr-hHymjgz3el{k>}aVSFviHmsxRBGgo9j)TyXJ@VO-Dd@U(;CzJlNHQy6 z9r3E6fr&AxTvS9Hfd&&zqPfi(nJ&V*(ZMDWjMAa@$!An=?30HC>ZwSyUpt97FC7|t z1E!mBoKWrox*ol}{rH4wyJc@eSgm&?tQ)P&muGcBYlF6#sJ&ehUk%}zYZg#UH@-6B zf~_2=TKC_PwAdSbgHl)Coq6v@1w`|-)JZR49l=M`H z1y9d4#)OKyQuL^p{e-YNL`mCO2maZ9M7~Cpu&ZJv?&)>*t-hGFJFVwzk9p`wdIT&V zrr&R=ZqlI@EM1`lUFDFi(USEnzLZWVx7|O&h|8{V+v9Nq8%4X>`Z4{&#}O4ZD)hPW zz7XO@PN6cFSdQzla@7;~uZX}e5?vf*I6mXd(A$S-oyl{J;6kR{(iZz z{Q<6fP=4=MJVN?Q}D-cT)9*RnZ@DW

Qp5Nra{z@;wtlc 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 SChYJ0K0ip6CLsUc%KroFlAX~2 literal 0 HcmV?d00001 diff --git a/src/objects/local-group-structures/inventory.json b/src/objects/local-group-structures/inventory.json index 90a51d0e4c0..3117e511d80 100644 --- a/src/objects/local-group-structures/inventory.json +++ b/src/objects/local-group-structures/inventory.json @@ -4,8 +4,8 @@ { "location": "prepared", "filename": "dots.bin", - "bytes": 33582, - "sha256": "55890fc29d241187597fa66552f85c1e7189dab87b3608977e715b8b23503860" + "bytes": 12588, + "sha256": "73cb414d2ec6e592882fc8a36e3ce4cb40399d64d6eef3b19c1f31338604134e" } ] } diff --git a/src/objects/local-group-structures/source/dots/stack.json b/src/objects/local-group-structures/source/dots/stack.json index f2aa4c5307c..7644c12c363 100644 --- a/src/objects/local-group-structures/source/dots/stack.json +++ b/src/objects/local-group-structures/source/dots/stack.json @@ -2,7 +2,7 @@ "schema": "cssearth-catalogue-points-stack@1", "id": "dots", "published": true, - "meaning": "The Local Group's structures as dots: the globular cluster systems of M31 and the Milky Way, the star clusters of the Magellanic Clouds and the Sagittarius stream, drawn once the camera is outside the Milky Way.", + "meaning": "The Local Group's structures as dots: the globular cluster systems of M31 and the Milky Way and the Sagittarius stream, drawn once the camera is outside the Milky Way.", "levels": [ { "bank": "field", diff --git a/src/objects/local-group-structures/source/field/merge.json b/src/objects/local-group-structures/source/field/merge.json index 3955d88946e..7a936243044 100644 --- a/src/objects/local-group-structures/source/field/merge.json +++ b/src/objects/local-group-structures/source/field/merge.json @@ -1,16 +1,14 @@ { "schema": "cssearth-catalogue-points-merge@1", "id": "field", - "meaning": "The Local Group's structures that are large enough to see from outside the Milky Way: the globular cluster systems of M31 and the Milky Way, the star clusters of the Magellanic Clouds and the Sagittarius stream.", + "meaning": "The Local Group's structures that are large enough to see from outside the Milky Way: the globular cluster systems of M31 and the Milky Way and the Sagittarius stream.", "banks": [ "m31-globular-clusters", "milky-way-globular-clusters", - "lmc-clusters", - "smc-clusters", { "bank": "sagittarius-stream", "keepEvery": 4, - "basis": "Presentation choice: the field holds at most 4,000 dots, so of the 2,553 stream stars it keeps one in 4, in catalogue order (Gaia source ids, which follow the sky), after every cluster." + "basis": "Presentation choice: of the 2,553 stream stars the field keeps one in 4, in catalogue order (Gaia source ids, which follow the sky), after every cluster." } ] } diff --git a/src/objects/local-group-structures/source/lmc-clusters/points.json b/src/objects/local-group-structures/source/lmc-clusters/points.json deleted file mode 100644 index ee04458f09c..00000000000 --- a/src/objects/local-group-structures/source/lmc-clusters/points.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "schema": "cssearth-catalogue-points-source@1", - "id": "lmc-clusters", - "table": { - "path": "table.csv", - "origin": "https://tapvizier.cds.unistra.fr/TAPVizieR/tap/sync?REQUEST=doQuery&LANG=ADQL&FORMAT=csv&MAXREC=100000&QUERY=SELECT+recno%2C+RAJ2000%2C+DEJ2000%2C+49590.6727505+AS+distpc+FROM+%22J%2FMNRAS%2F389%2F678%2Ftable3%22+WHERE+Type+%3D+'C'+AND+RAJ2000+BETWEEN+60+AND+100+ORDER+BY+recno", - "bytes": 123991, - "format": "csv", - "columns": { - "name": 1, - "raDeg": 2, - "decDeg": 3, - "distance": 4 - }, - "distanceUnit": "pc", - "note": "The query keeps the ordinary clusters (type C) the catalogue's own rule gives to the Large Magellanic Cloud (4 h < RA < 6 h 40 min, Bica et al. 2008, Sect. 3) and writes the Cloud's distance, Pietrzyński et al.'s (2019) 49.59 kpc, into each row. No cluster's own distance is measured: every one sits at its Cloud's distance, so the Cloud's depth is not drawn.", - "distanceSource": "publication-pietrzynski2019natur-567-200p" - }, - "filters": [], - "frame": { - "input": "icrs", - "output": "sun-icrf", - "epochJdTt": 2461286.5, - "converter": "Astropy SkyCoord ICRS, heliocentric Cartesian" - }, - "source": "bica-2008-magellanic-extended-objects", - "meaning": "Star clusters of the Large Magellanic Cloud from Bica et al.'s (2008) catalogue of extended objects: one dot per ordinary cluster at its catalogue sky position, at the Cloud's distance.", - "appearance": { - "colorCss": "#9fd4ff", - "radiusPx": 0.75, - "opacity": 1, - "note": "Presentation only: the Milky Way open-cluster layer's blue-white and size." - } -} diff --git a/src/objects/local-group-structures/source/manifest.json b/src/objects/local-group-structures/source/manifest.json index d2e32f0e969..e6abe168202 100644 --- a/src/objects/local-group-structures/source/manifest.json +++ b/src/objects/local-group-structures/source/manifest.json @@ -54,58 +54,6 @@ "dependencies": [], "license": "Original catalogue terms apply; cite Baumgardt & Vasiliev (2021)." }, - { - "id": "lmc-clusters-table", - "path": "src/objects/local-group-structures/source/lmc-clusters/table.csv", - "origin": "https://tapvizier.cds.unistra.fr/TAPVizieR/tap/sync?REQUEST=doQuery&LANG=ADQL&FORMAT=csv&MAXREC=100000&QUERY=SELECT+recno%2C+RAJ2000%2C+DEJ2000%2C+49590.6727505+AS+distpc+FROM+%22J%2FMNRAS%2F389%2F678%2Ftable3%22+WHERE+Type+%3D+'C'+AND+RAJ2000+BETWEEN+60+AND+100+ORDER+BY+recno", - "sourceUrl": "https://cdsarc.cds.unistra.fr/viz-bin/cat/J/MNRAS/389/678", - "title": "A general catalogue of extended objects in the Magellanic System, table3: the Large Magellanic Cloud's ordinary clusters", - "credit": "E. Bica, C. Bonatto, C. M. Dutra, J. F. C. Santos Jr; MNRAS 389, 678; CDS J/MNRAS/389/678", - "acquisition": "Rows selected by the CDS TAP query in the origin, downloaded unchanged; read by packages/bake/cli/prepare-catalogue-points.mts through lmc-clusters/points.json.", - "sourceBinding": { - "kind": "catalogued", - "references": [ - { - "catalogueId": "bica-2008-magellanic-extended-objects", - "role": "material", - "evidence": "https://cdsarc.cds.unistra.fr/ftp/J/MNRAS/389/678/ReadMe" - }, - { - "catalogueId": "publication-pietrzynski2019natur-567-200p", - "role": "reference", - "evidence": "src/objects/local-group-structures/source/lmc-clusters/points.json#/table/note" - } - ] - }, - "dependencies": [], - "license": "Original catalogue terms apply; cite the authors and CDS/VizieR." - }, - { - "id": "smc-clusters-table", - "path": "src/objects/local-group-structures/source/smc-clusters/table.csv", - "origin": "https://tapvizier.cds.unistra.fr/TAPVizieR/tap/sync?REQUEST=doQuery&LANG=ADQL&FORMAT=csv&MAXREC=100000&QUERY=SELECT+recno%2C+RAJ2000%2C+DEJ2000%2C+62440+AS+distpc+FROM+%22J%2FMNRAS%2F389%2F678%2Ftable3%22+WHERE+Type+%3D+'C'+AND+(RAJ2000+%3E+355+OR+RAJ2000+%3C+20)+ORDER+BY+recno", - "sourceUrl": "https://cdsarc.cds.unistra.fr/viz-bin/cat/J/MNRAS/389/678", - "title": "A general catalogue of extended objects in the Magellanic System, table3: the Small Magellanic Cloud's ordinary clusters", - "credit": "E. Bica, C. Bonatto, C. M. Dutra, J. F. C. Santos Jr; MNRAS 389, 678; CDS J/MNRAS/389/678", - "acquisition": "Rows selected by the CDS TAP query in the origin, downloaded unchanged; read by packages/bake/cli/prepare-catalogue-points.mts through smc-clusters/points.json.", - "sourceBinding": { - "kind": "catalogued", - "references": [ - { - "catalogueId": "bica-2008-magellanic-extended-objects", - "role": "material", - "evidence": "https://cdsarc.cds.unistra.fr/ftp/J/MNRAS/389/678/ReadMe" - }, - { - "catalogueId": "publication-graczyk2020apj-904-13g", - "role": "reference", - "evidence": "src/objects/local-group-structures/source/smc-clusters/points.json#/table/note" - } - ] - }, - "dependencies": [], - "license": "Original catalogue terms apply; cite the authors and CDS/VizieR." - }, { "id": "sagittarius-stream-table", "path": "src/objects/local-group-structures/source/sagittarius-stream/table.csv", @@ -143,20 +91,6 @@ "reason": "Project-authored processing configuration." } }, - { - "path": "src/objects/local-group-structures/source/lmc-clusters/points.json", - "sourceBinding": { - "kind": "local", - "reason": "Project-authored processing configuration." - } - }, - { - "path": "src/objects/local-group-structures/source/smc-clusters/points.json", - "sourceBinding": { - "kind": "local", - "reason": "Project-authored processing configuration." - } - }, { "path": "src/objects/local-group-structures/source/sagittarius-stream/points.json", "sourceBinding": { diff --git a/src/objects/local-group-structures/source/presentation.json b/src/objects/local-group-structures/source/presentation.json index 32c5fb2799f..8f22cbb62e5 100644 --- a/src/objects/local-group-structures/source/presentation.json +++ b/src/objects/local-group-structures/source/presentation.json @@ -42,48 +42,6 @@ "The distances carry the errors the table gives, a few per cent for most clusters." ] }, - { - "id": "lmc-clusters", - "label": "Bica et al. (2008) star clusters of the Large Magellanic Cloud, CDS J/MNRAS/389/678", - "process": "Place each ordinary cluster at its sky position, at the Cloud's distance (Pietrzyński et al.'s (2019) 49.59 kpc).", - "recipe": "source/lmc-clusters/points.json", - "selector": "", - "inputs": [ - "lmc-clusters-table" - ], - "outputs": [ - "prepared/dots.bin" - ], - "interpretation": { - "kind": "catalogue-positions", - "sourceKind": "published-catalogue" - }, - "limitations": [ - "No cluster's own distance is used: the Cloud's depth along the sight line is not drawn.", - "The catalogue's 55 ordinary clusters of the Bridge between the Clouds are not drawn." - ] - }, - { - "id": "smc-clusters", - "label": "Bica et al. (2008) star clusters of the Small Magellanic Cloud, CDS J/MNRAS/389/678", - "process": "Place each ordinary cluster at its sky position, at the Cloud's distance (Graczyk et al.'s (2020) 62.44 kpc).", - "recipe": "source/smc-clusters/points.json", - "selector": "", - "inputs": [ - "smc-clusters-table" - ], - "outputs": [ - "prepared/dots.bin" - ], - "interpretation": { - "kind": "catalogue-positions", - "sourceKind": "published-catalogue" - }, - "limitations": [ - "No cluster's own distance is used: the Cloud's depth along the sight line is not drawn.", - "The catalogue's 55 ordinary clusters of the Bridge between the Clouds are not drawn." - ] - }, { "id": "sagittarius-stream", "label": "Ramos et al. (2022) RR Lyrae of the Sagittarius stream, CDS J/A+A/666/A64", @@ -107,15 +65,13 @@ }, { "id": "field", - "label": "The five banks as one field", - "process": "Join the five banks; of the stream stars keep one in four, in catalogue order, so the field stays under 4,000 dots.", + "label": "The three banks as one field", + "process": "Join the three banks; of the stream stars keep one in four, in catalogue order.", "recipe": "source/field/merge.json", "selector": "", "inputs": [ "m31-clusters", "milky-way-clusters", - "lmc-clusters-table", - "smc-clusters-table", "sagittarius-stream-table" ], "outputs": [ @@ -126,7 +82,7 @@ "sourceKind": "published-catalogue" }, "limitations": [ - "The 4,000 dot ceiling is a presentation choice." + "Keeping one stream star in four is a presentation choice." ] }, { @@ -138,8 +94,6 @@ "inputs": [ "m31-clusters", "milky-way-clusters", - "lmc-clusters-table", - "smc-clusters-table", "sagittarius-stream-table" ], "outputs": [ diff --git a/src/objects/local-group-structures/source/smc-clusters/points.json b/src/objects/local-group-structures/source/smc-clusters/points.json deleted file mode 100644 index 96a44e08d43..00000000000 --- a/src/objects/local-group-structures/source/smc-clusters/points.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "schema": "cssearth-catalogue-points-source@1", - "id": "smc-clusters", - "table": { - "path": "table.csv", - "origin": "https://tapvizier.cds.unistra.fr/TAPVizieR/tap/sync?REQUEST=doQuery&LANG=ADQL&FORMAT=csv&MAXREC=100000&QUERY=SELECT+recno%2C+RAJ2000%2C+DEJ2000%2C+62440+AS+distpc+FROM+%22J%2FMNRAS%2F389%2F678%2Ftable3%22+WHERE+Type+%3D+'C'+AND+(RAJ2000+%3E+355+OR+RAJ2000+%3C+20)+ORDER+BY+recno", - "bytes": 20791, - "format": "csv", - "columns": { - "name": 1, - "raDeg": 2, - "decDeg": 3, - "distance": 4 - }, - "distanceUnit": "pc", - "note": "The query keeps the ordinary clusters (type C) the catalogue's own rule gives to the Small Magellanic Cloud (23 h 40 min < RA < 1 h 20 min, Bica et al. 2008, Sect. 3) and writes the Cloud's distance, Graczyk et al.'s (2020) 62.44 kpc, into each row. No cluster's own distance is measured: every one sits at its Cloud's distance, so the Cloud's depth is not drawn.", - "distanceSource": "publication-graczyk2020apj-904-13g" - }, - "filters": [], - "frame": { - "input": "icrs", - "output": "sun-icrf", - "epochJdTt": 2461286.5, - "converter": "Astropy SkyCoord ICRS, heliocentric Cartesian" - }, - "source": "bica-2008-magellanic-extended-objects", - "meaning": "Star clusters of the Small Magellanic Cloud from Bica et al.'s (2008) catalogue of extended objects: one dot per ordinary cluster at its catalogue sky position, at the Cloud's distance.", - "appearance": { - "colorCss": "#9fd4ff", - "radiusPx": 0.75, - "opacity": 1, - "note": "Presentation only: the Milky Way open-cluster layer's blue-white and size." - } -} diff --git a/src/sources/bica-2008-magellanic-extended-objects.json b/src/sources/bica-2008-magellanic-extended-objects.json deleted file mode 100644 index 3f7c344e3bd..00000000000 --- a/src/sources/bica-2008-magellanic-extended-objects.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "id": "bica-2008-magellanic-extended-objects", - "kind": "publication", - "identityLevel": "work", - "title": "A general catalogue of extended objects in the Magellanic System", - "identifiers": [ - { - "type": "ads", - "value": "2008MNRAS.389..678B" - }, - { - "type": "CDS/VizieR", - "value": "J/MNRAS/389/678" - } - ], - "links": [ - { - "role": "landing", - "url": "https://ui.adsabs.harvard.edu/abs/2008MNRAS.389..678B", - "label": "2008MNRAS.389..678B" - }, - { - "role": "archive", - "url": "https://cdsarc.cds.unistra.fr/viz-bin/cat/J/MNRAS/389/678", - "label": "CDS J/MNRAS/389/678" - } - ], - "evidence": [ - { - "url": "https://cdsarc.cds.unistra.fr/ftp/J/MNRAS/389/678/ReadMe", - "checkedOn": "2026-10-04", - "locator": "table3.dat: 3,740 star clusters of the SMC, Bridge and LMC with J2000 positions and a type; 2,770 are ordinary clusters (type C). The paper's Sect. 3 takes as SMC objects those at 23 h 40 min < RA < 1 h 20 min and as LMC objects those at 4 h < RA < 6 h 40 min, the Bridge between: 444 and 2,270 ordinary clusters are drawn; the 55 of the Bridge are not." - } - ], - "creators": [ - "E. Bica", - "C. Bonatto", - "C. M. Dutra", - "J. F. C. Santos Jr" - ], - "publisher": "MNRAS 389, 678", - "publicationDate": "2008", - "relations": [], - "statements": [ - { - "kind": "credit", - "text": "Cite Bica et al. (2008), MNRAS 389, 678.", - "scope": "The Magellanic Clouds' star clusters", - "evidence": "https://cdsarc.cds.unistra.fr/ftp/J/MNRAS/389/678/ReadMe" - } - ] -}