# NightFront

What changed in each release of the NightFront desktop app. The newest release is at the top.
Releases before 2.0.0 predate this list.

## 3.19.1

Configs
- Saving a config, from the app or from the NINA plugin, keeps settings a newer NightFront wrote, except inside list entries with no fixed identity, such as filter preference rules.
- A config that uses features from a newer NightFront opens read-only, with a note under Save saying so; Save and Save As are off until NightFront is updated.
- The plugin's edits to such a config are refused with the same reason.
- Overwrite re-reads the file first: if a newer NightFront wrote it, nothing is saved and the tab turns read-only.
- On a read-only config, moving a target, Complete, Plan again, Accept lights, Apply (overheads) and the Sky tab's Create and Move refuse before changing anything.

## 3.19.0

Mosaics: framed exactly as NINA frames them
- A new mosaic (Add target's Mosaic, or Discovery's mosaic promotion) is laid out exactly as NINA's Framing Assistant lays out the same grid: NINA's field size, its pixel arithmetic and its placement on the sky.
- A new mosaic's rotation is stored as NINA shows it, rounded to 0.01°, and its panels are numbered in NINA's order (Panel 1 at the top-left of NINA's frame).
- Correcting a mirrored mosaic by moving its panels now puts them exactly where NINA draws them, and stores the rotation NINA uses (rounded to 0.01°) on every panel.
- An older mosaic on a very wide field (a camera lens covering more than about 23°) at an odd multiple of 45° can no longer be framed whole from the plugin; frame its panels one at a time.
- Such a mosaic is now named on the Targets page, saying it was laid out by an older NightFront, instead of passing silently.

Field of view
- The field of view and pixel scale (Imaging System page, the mosaic preview, Discovery) are NINA's: pixels × NINA's pixel scale, a little wider than before (about 0.1 % on a 4° field).

Sky map: Frame mode
- A Frame view on the ✦ Sky tab draws an open config's camera field, or a mosaic grid (columns × rows, overlap in % or pixels), exactly as NINA's Framing Assistant lays it out; no Sky gallery is needed.
- Drag the frame to move it, drag its round handle to turn it, or use the arrow keys and [ ]; the rotation shown is NINA's, to 0.01°.
- Double-click empty sky to move the frame there (its rotation and grid kept); a double-click that starts on an object, a result or one of your targets opens it instead.
- The Frame pane shows the center to 0.1 s of RA and 0.1″ of Dec, the precision of NINA's Framing tab.
- Frame for lists every open config; one with no camera, never saved, still loading its targets or changed on disk is listed with the reason and cannot be chosen. Open a config… opens one without leaving the Sky tab.
- The frame's card shows the Year and Tonight charts for that config's site, as its Targets card would, updated a moment after you stop dragging.
- Broadband | Narrowband switches the map between DSS2 color and the narrowband survey.
- Create planned target… adds the frame, or the mosaic, to the config's Planned targets exactly as drawn, and saves the config.
- Move and save moves an existing target to where the frame is; a move that would reset accepted counts asks first, listing each panel.
- Accepted counts are kept while the target stays within 5″, and turned less than 0.1° in all, of where it was when its counts were last reset; small turns can no longer add up to a large one with the counts kept.
- A target card's Frame now sits in its action column under Expand, so you can frame a target without expanding the card (a mosaic card frames the whole mosaic); the Year and Tonight charts on the card are a little taller to match.
- Opening another frame (a card's Frame, a click on a dashed target, Discovery) over one you have moved or turned asks Discard or Keep first.
- A mosaic moves whole and is laid out again on NINA's own grid; one no NINA grid fits (an older mirrored mosaic, say) is moved as it is, can't be turned there, and says so.
- The chosen config's own targets are drawn dashed at their stored footprints (a Completed one fainter); click one to frame it, as its card's Frame does. A click changes nothing in the config.

Stellarium framing removed
- NightFront no longer drives Stellarium: the Stellarium… menu on target cards, Read frame, Discovery's Stellarium… button, the Stellarium panels and their settings are gone. The Sky map's Frame replaces them, and frames exactly as NINA's Framing Assistant does.
- Typing a new RA, Dec or rotation on a target card still asks first when it would reset accepted counts; the dialog now reads Move …?.
- An older preferences file that holds the Stellarium settings still opens, with every other setting kept.

Sky map: Catalogs layer
- A Catalogs layer (under Layers) draws Target Discovery's catalogs on the map: an outline per object at its catalog size and angle, colored by type, labeled more densely as you zoom in. Objects whose size no catalog states are drawn as a cross-hair marked size?.
- Catalog filters uses Discovery's own catalog and type chips, plus magnitude and surface-brightness limits; objects with no stated brightness are kept.
- In Frame mode each outline is tinted against the chosen config's field: fits one frame, needs a mosaic, too small or too large; an optional size filter hides what frames badly, never objects of unknown size (Hide objects of unknown size does that).
- Click an object for its card: every designation, type, size, brightness and AstroBin; in Frame mode also Frame this, Create planned target… (with the rotation you set, never the catalog's) and the Year and Tonight charts. On a Discovery result, both use the grid the search chose.
- If the catalogs were never downloaded, the layer says so and offers the one-time download.

Sky map and Target Discovery, linked
- Show results on Sky map in Discovery opens Frame mode for that config with every ranked result drawn as a numbered outline at its best grid; click near a result's center for its card, which shows its rank, score and hours. Elsewhere inside its grid a click reaches the catalog object or target under it, and a click inside your frame never opens a result. The results stay as searched until you show new ones or press Clear, or another file is opened into that config's tab.
- The Discovery window now stays open, with its chips, while you switch to the Sky tab or another config; each config has its own window, titled with its name.
- Rank in Discovery… in the Catalog filters drawer opens the Frame-for config's Discovery window with the drawer's catalog and type chips; nothing is searched until you press Search.
- Only objects in the current view limits that search to the part of the sky the map shows; Discovery says so above the form and beside the results, and Whole sky removes it.

Sky map: grid labels and pointer readout
- The RA labels of the RA/Dec grid are now on the top edge, out from under the credit line, and the Dec labels are larger; a crowded edge drops every other label instead of shrinking them, and no Dec label sits under the RA labels or the pointer readout.
- A readout at the bottom left, just above the credit line, shows the J2000 RA and Dec under the pointer (RA to 0.1 s, Dec to 1″); it hides when the pointer leaves the map or is off the sky.

Sky map: image labels
- A new Image labels layer in the Layers menu, under Your images (on by default), hides the name and rig written under each posted image; the images and their outlines stay. It is greyed out while Your images is off.

Sky map: double-click an image
- Double-clicking a placed image on the map zooms to it and selects it, the same view as its card's Show on map; a single click still selects at once, and a double-click on overlapping images zooms to the image whose card is open, else to the one the first click picked.

Sky gallery: Edit details
- Edit details… on an image's card now also changes the Object, the Captured from and to dates and the linked imaging system, beside the title, rig and notes. A new object name is looked up once, when you Save, and an unknown one is said in the dialog and saves nothing; a name already stored is never looked up again, and changing only its capitalization saves the new spelling. With no config open, the linked imaging system is shown, read only.

Sky gallery: rig chips
- The rig chips select several rigs at once: click a rig chip to add it or take it out, and the map, the Grid and the Needs placing count follow the rigs chosen. All rigs clears the choice, and so does turning off the last rig. The choice is not remembered between launches.

Sky map: smoother wide-field panning
- Panning and zooming out to a very wide field is several times smoother on a graphics card; what is drawn is unchanged.

Sky map: constellation labels
- A new Constellation labels layer in the Layers menu (on by default) names each constellation in full, such as Orion or Canis Major, at the center of its line figure.
- Where names would overlap, the one nearer the middle of the map stays and the other is left out; names are never shrunk, and they stay clear of the grid labels, the pointer readout and the credit line.
- The Stellarium credit stays on the map while the labels show, even with Constellation lines switched off.

Sky gallery: guided placement
- An image linked to a project now opens at the scale given when it was posted, not the rig's native scale, so a drizzled or binned image no longer opens twice too large or too small; the rig's scale is used only when none was given.
- The How it's placed panel says which scale it opened with, and notes when the posting's scale and the rig's native scale differ by more than 3 %.

Targets and Discovery: Frame
- Every target card, and each panel of a mosaic, has a Frame button that opens the ✦ Sky tab in Frame mode for that config: the camera's field at the target's rotation, or the whole mosaic with the panel highlighted.
- Completed targets get a view-only Frame on their strip.
- The hints on a target card's buttons (Frame, → Planned, AstroBin, Duplicate and the rest) show over the whole button, not only over its label.
- Discovery's Frame opens the Sky tab on the object at the grid the search chose, and the Discovery window stays open.

Targets: rotation
- A rotation you change (on the target card, on the Sky map, or by correcting a mirrored mosaic) is stored as NINA shows it, rounded to 0.01° and between 0° and 360°.
- A rounded rotation now keeps exactly two decimals on the target card and in the config (35.12, never 35.120000000000005), and messages state rotations to 0.01°.

## 3.18.1

Sky gallery
- Images from one rig no longer split into several rig chips with the same name when its config had never been saved with an imaging-system id.

## 3.18.0

Plan chart wording
- The plan chart and guide say Pareto front instead of GA front.

Sky gallery: your images on a map of the sky
- A pinned ✦ Sky tab holds a personal gallery, in a folder you choose, of finished images from any rig, each plate solved or placed by hand on a survey map.
- Post images… takes JPEG, PNG and TIFF (8- or 16-bit, float, BigTIFF), reads scale and position hints from the file or a FITS, XISF or .wcs file (ASTAP's or astrometry.net's) beside it, and links your original without ever changing it.
- Guided placement draws the image over the survey with an opacity slider and Space to blink, locks the scale to the rig for a linked project, and pins stars for an exact fit with a residual.
- Refine snaps a rough placement to exact against Gaia stars or the survey, also trying the image turned 90, 180 and 270 degrees, and never applies a poor match; when survey tiles are missing it says whether you were offline or the survey server refused them, and an outage at the Gaia star service no longer takes the map's survey tiles offline.
- An image linked to a project opens at the target's rotation and now says it may be 180 degrees off, since a rotator can reach the same angle either way round.
- An image's card says when ASTAP is queued, solving, or found no solution, so a Re-solve is never silent; a failure that is not a hard field (timed out, star database or image unreadable) says so, and a Re-solve that fails on an already placed image says so too (the line goes when a placement is saved).
- The Post images window opens no taller than your screen's usable height (nor wider than its width), on the screen the app is on, so Cancel and Post stay in view; the table scrolls.
- ASTAP tries in the background and offers its result; Solve online (slow)… uses astrometry.net only when you ask, uploading a small private copy.
- Zooming past the gallery's copy builds tiles from your original in the background, and the map says "Building tiles from the original" while it runs; a missing or changed original never breaks the gallery.
- Offline, the map says only "Offline: showing cached imagery" (no stuck "Loading imagery…"); the survey picker's NC badge stays on one line; Post again… no longer prints "null" under Object, and names the target's position as the source.
- Opening an image's card from Needs placing no longer moves the map; Show on map is the move.
- Find… takes focus when it opens and Enter runs the search.
- Post images… says when two rows look like the same image (the same name in different formats, such as a TIFF and a PNG) so one is not posted twice; it only warns.
- Needs placing turns itself off, and greys out, when every image is placed, so it can no longer leave the Grid saying "No images match these filters."; when filters hide everything, the Grid names them and how to clear them.
- Post images… opens wide enough to show every column, scrolls sideways with a visible bar when the window is narrower, and Choose files… starts in the folder you last chose from (or the project's folder from a Completed card).
- The map draws DSS2 color (NSNS for narrowband) and other HiPS surveys, with fall-through to the next survey where one has no data, your NINA sky cache, stars, constellation lines and boundaries, all credited; non-commercial layers can be switched off.
- A post the gallery could not make, and an object SIMBAD did not find, are now said on the gallery, with a Dismiss.
- A Completed card can Post to Sky gallery… and shows ✦ in Sky gallery once posted.
- App settings › Paths holds the gallery folder, ASTAP, the astrometry.net key, the NINA cache and the cache sizes.
- Overlapping images show the most recently captured on top (the posted date when no capture date is given).
- Clicking through an overlap draws each image on top in turn.
- The card says "2 of 3 images here".
- On the map, an image's card opens over the map's right edge, so opening or closing it no longer shifts, zooms or turns the map, and a second click at the same spot hits the same place.
- Resizing the window keeps the map's center and scale.
- With a card open, Show on map, Find… and the zoom buttons center on the part of the map the card leaves uncovered.
- The map's +, − and ⤢ buttons stay visible while a card is open in a narrower window: the survey name and the field line shorten instead, and the toolbar keeps its height, so opening a card never moves the map.
- The outline legend in the map's bottom-right corner sits above the credit line however many lines it wraps to (a narrow window, or a card open), so they no longer overlap; the credits stay in full.

Analysis › Overheads
- When Max Slew/Center/Rotate has no suggestion yet, the note now gives how many moves to a new target the chosen nights held, not only how few of them were a wide move with a rotation change.

File and folder dialogs
- Native file and folder dialogs on Windows, macOS and Linux: every Open, Save and folder picker is now your system's own, with its sidebar, search and recent places. If it cannot open, the previous dialog opens instead.
- Analysis: Choose folder… beside Choose files… for the NINA logs and the plan files; both add to the list.

User Guide
- Running with NINA: the recommended sequence now matches the plugin's example night (sunset and sunrise waits, imaging and its safety recovery in one loop until dawn, bounded sky flats, Save Night's Log last), and shows the unpark after each park (after a weather stop, and at the start of each night).
- Save Night's Log placement: the Analysis page and its empty-state hint now say to put the instruction last among the night's end steps, in the End area or at the end of a nightly loop's end-of-night block.

## 3.17.0

Analysis: a new page for what NINA's logs say about your nights
- The rail now reads Site, System, Targets, Schedule, Analysis and Processing; Analysis has four chips: Last night, Overheads, Autofocus and Report.
- Analysis reads the night logs saved by the NINA plugin's new NightFront Save Night's Log instruction (put it last in your sequence's End area; needs plugin 3.17.0.0), which lands each night's whole NINA log, sky flats included, in a nina-logs folder beside your config.
- Until the first night is saved, the page says which instruction to add, and to check that the plugin plans from this config.
- Above the chips, choose Most recent N nights (7 to start) or Picked nights from a Pick nights… checklist; every chip uses the nights you chose.
- Analyze runs only when you press it, and Cancel (or analyzing again) stops it.
- Choose files… analyzes any NINA log or NightFront plan files you pick instead; picks from different folders add up, and Clear empties the list.

Analysis › Last night: the night scorecard
- Each night's card compares the time on sensor the plan counted on with what NINA collected, with a table of what was collected per target and filter and where the night's darkness went.
- Planned adds up every plan of the night, each counted only for the hours it was in charge and never before dusk, and the line above the table names every plan it added up.
- If one of the night's plans cannot be read, or its write time is unknown, the night shows *Actual only* instead of a partial total.
- The Night total stands out under a divider, and the Note column is hidden on a night where no row has a note.
- Flat frames are counted per filter, NINA sky flats included; a flat cut off when the sequence stopped is shown as interrupted.
- The newest chosen night is shown with its NightFront problems; the All nights toggle shows a card for every chosen night.

Analysis › Overheads: settings from what the logs show
- Max Slew/Center/Rotate, Meridian Flip, Dither and Autofocus Run each get a recommended value beside your current one, with how many samples it rests on and its statistics named in plain words.
- The page leads with Setting recommendations and Ways to reduce overhead (each with the minutes it would have saved); everything else sits in one Supporting evidence group.
- Apply changes only the open config: Save highlights and nothing reaches disk until you save; a row with too few samples is greyed and cannot be applied.
- Measurements and copies of NightFront plan files are kept beside your config (<config>.overhead-samples.jsonl), a night once its morning has passed, so they outlast NINA deleting old logs; recommendations count only the nights you chose.
- The evidence compares planned with actual time on sensor over the last 10 imaging nights and shows before and after each change, including Applies, hand edits and NINA settings the logs state.
- Start a new era on… records a change the logs cannot see (a new focuser, say), and Discard samples before… makes older measurements stop counting.
- The overhead fields, the autofocus switches and Min Exposures Before Filter Change moved from Schedule's Setup to a new Overheads tab on the System page, each with what the logs suggest and an Apply.
- A night saved by NightFront Save Night's Log counts as soon as Rescan logs finds it, instead of waiting until noon the next day.

Analysis › Autofocus and filter offsets
- Your autofocus switches sit beside what the logs show, with an Apply where they disagree and the runs per cause and periodic interval underneath.
- When NINA autofocuses on every filter change, the page suggests NINA's filter offsets instead, with the minutes per night it would save and an estimate of each filter's offset from the logs.
- The Filter offsets panel shows what the NINA plugin has measured and committed for each filter whenever its <config-name>.filter-offsets.json sits beside your config.
- The setup note says to keep *Autofocus after filter change* until every filter has an offset, then turn *Use filter offsets* on and remove that trigger at the same time.

Analysis › Report: a report for NightFront support
- Builds a report of NightFront errors and anomalies in the logs, scrubbed of your user name, machine name, equipment serial numbers, site coordinates, keys and email addresses.
- You see it in full before you Save report… or Copy it; NightFront never sends it anywhere.

Targets › Recommender: what to promote to fill open time
- Choose Recommender at the top of the Targets page and press Analyze to see, over the next 30 nights (one lunar cycle), when your enabled Active targets leave the night open: below the horizon, blocked by the Moon, or finished.
- It suggests the Planned target, or set of targets, that fills the most of that open time, says in one sentence what it fills and what stays open, and lists five alternatives by what each would add, with Show all for the rest.
- Targets that fill the same time are marked tied; the tie goes to the one filling more of the gaps, then to your priority order, then to the one needing the most integration.
- → Active moves the target (or the whole mosaic) as an unsaved edit and analyzes again at once; weather is ignored, and nothing moves unless you press it.
- Once you have analyzed your NINA logs, a line under the suggestion says how long before dawn your imaging nights ended, for comparison only.

Schedule: one page for planning
- Season, Roadmap, Setup and Plan are now one Schedule page in two groups: Seasonal (Setup | Plan, formerly Season and Roadmap) and Nightly (Setup | Plan).
- The Editor is a Plan | Editor chip pair on Nightly › Plan, replacing *Edit as new plan*; a GA front point or a generated plan is first copied into a new editable plan, and pressing Editor again reopens that copy.

Schedule: fewer dithers when filters dither at different rates
- A filter set to dither less often (say L every 2 frames, R, G and B every frame) now uses its whole allowance before each dither, so a round runs L, L, R, G, B and then dithers once, instead of dithering after three or four frames.

Schedule: no slew when the plan stays on the same target
- A 0-minute slew back onto the target already being imaged no longer shows in the Nightly Plan chart or sequence list.
- The NINA sequence (from Export or the plugin's Nightly Update) keeps it as one target block with one re-center, and dithers once where the two parts meet.

Schedule › Nightly Plan: sequence list
- The Frames column now sits beside Filter, so a row holding two frames of one filter reads as two.

Targets page
- Every card has a project line: its folder, how many lights it holds and how many await calibration, or a note when there is no folder yet or it needs your answer; it reads "rename pending" or "move pending" until you save.
- Open in Processing › on an Active, Planned or Completed target jumps to its project on Processing › Projects, and the target name on a project card jumps back.
- The enable checkbox belongs to Active targets only and means "eligible for nightly planning"; it stays as you set it, moving a target to Active ticks it, and seasonal planning includes every Active and Planned target that is not completed.
- A rename to a name another target or mosaic already uses, or that cannot be a folder name (such as one containing ":" or "/", or "Completed"), is refused with the reason under the field.
- Renaming a target no longer moves its card, or its place in the Greedy planner's order.
- Plan again on a completed target is now an unsaved edit: Save highlights and nothing is written until you save.
- A card's ⋯ menu gathers its less common actions, the Active and Planned columns start level, and Manual Entry's Single target / Mosaic buttons sit on one line.
- Every target and mosaic card has a Tonight chart under its year chart (now captioned Year), showing the target's altitude from sunset to sunrise, your horizon, the Moon with its phase, and the usable dark time shaded.

Processing: managed project folders
- A rig folder can keep its projects in Active, Planned, Unlinked and Completed subfolders; a rig laid out the old way works as before, and those four names are reserved.
- Adopt managed layout… (Processing › Settings › Rig) shows where every project will go, then moves them; nothing is copied or deleted, and nothing moves while a run, a remote job or frames in an Inbox use the rig.
- On a managed rig, project folders follow your saved targets: created for a new target, moved between Active and Planned, renamed with the target (a mosaic's panel folders too), and moved to Unlinked when the target is deleted.
- Nothing moves until you save, nothing moves if the config changed on disk, completed projects are never moved this way, and what was done (or skipped) is listed in the Folder changes panel; a skipped move is retried on the next open or save.
- Processing now scans your Projects folder when a config is opened, not only when you first visit the Processing page.
- A Rescan that finds a folder renamed, moved or missing by hand puts it right at once.
- Plan again brings the target's folder back out of Completed\, and Restore puts a Planned target's project back in Planned.
- *Create project* in the import dialog puts a new project in the folder matching its target, and a project name can be used only once across Active and Planned.
- An empty leftover copy of a moved project at the rig's root is listed as a leftover and can be removed, never matched to the target.
- When two folders belong to one target, NightFront uses the real project (the one the rig records, then the one holding lights), and the warning names the folder imported frames go to.
- Rename… on a folder named after its target says to rename the target on the Targets page instead.

Processing: renames keep their history
- Rig folders, project folders and imaging systems now carry hidden ids, so renaming any of them (in NightFront or in File Explorer) keeps calibration records, reviews, stacks, blink verdicts, links and per-system Processing settings.
- The first scan moves existing records onto the ids, keeping one-time backups (…pre-project-ids.bak, preferences.json.pre-system-ids.bak); an older NightFront afterwards shows those projects as never reviewed, and nothing is lost.
- The primary rig folder (the one holding the Calibration Library) is now remembered in that folder rather than chosen by name.
- Link… remembers the target itself, takes precedence over the frames' OBJECT keyword, and now offers Planned targets too; Unlink fully removes the link.
- A copied rig or project folder is reported once, naming the hidden id file to delete from the copy.
- Frames calibrated by NightFront 3.9.1 or earlier are offered for calibration once more after a rig folder rename.

Processing › Projects
- Status chips (Active, Planned, Completed, Unlinked), each with a count, replace the "show the other folders" checkbox, the Completed projects section and the folder count beside Rescan.
- A refused action shows its reason under that project's buttons, and a folder move skipped at open or save also shows on the target's card.
- Folder changes and Processing notices panels collect the page's notes.
- The box above the header row is now labeled Active projects, and its Calibrate, Accept lights and Stack all cover only projects whose target is Active; a folder linked to a Planned target is no longer included.

Processing › Blink
- Hover the frame's name in the status line to read its full filename when it is too long to fit.

Processing › Settings and App settings
- Processing › Settings is split into Rig, Import, Calibration and Stacking chips; the ⚙ App settings window holds Paths, Server, Notifications and Appearance.
- Rig starts from one Rig folder picker per imaging system, with Rename… and New rig folder… beside it and other folders serving the config under a collapsed Other rig folders with Make primary.
- New rig folder… creates the Active, Planned, Unlinked and Completed folders and a Calibration Library, linked to this imaging system; Rename… moves only the folder.
- A refused rename, new rig folder, primary pick, claim or adopt says why directly under the Rig folder row (for example while a run or a processing-server job is using the rig).
- Tick Keep flat subs where they are when masters are built (Import, off by default) to archive a verified copy of each flat sub and leave the originals where NINA saved them.

Processing › Library: archiving replaced masters
- After every scan, a line on the Library page counts master flats, darks, biases and dark-flats that a newer master of the same settings has replaced and no project still needs.
- Review… lists each with its reason, and Archive N masters moves the ticked ones into the library's Archive\Masters\ folder; nothing is deleted, and everything is checked again at the click.
- A Kept group lists the replaced masters that must stay, and why.
- The Archived masters section lists what was archived; Restore puts one back exactly where it was.
- When completing a project, the Calibration row says when the library's original of a master is archived or gone, and a missing master flat names an archived one that would fill the gap.

Processing › Stacking: dated master names
- Tick Add stack date and integration time to master names (Processing › Settings › Stacking, Output group; off by default, per imaging system) to name masters like Spaghetti_Nebula_Panel_2_Ha_1x1_2026-10-04_12h30m.xisf, on PixInsight and Siril alike.
- A re-stack on another day, or with an integration time that differs by a minute or more, keeps the earlier master beside the new one.

Processing servers and shared Projects folders
- A job sent to a processing server leaves a hidden .nightfront-remote-job file in its folder until it is collected; another computer sharing the Projects folder then refuses to rename, move, complete, restore, organize or otherwise change that project, naming the job and the computer.
- If the computer that sent a job is gone for good, delete that file by hand.
- With Run processing on: set to a server, Calibrate and Stack in the *All projects* box keep sending projects while a local run goes on, waiting only when the local run is using the same project or rig.
- Siril's FITS copy of an .xisf master is completed before it appears in the library, so another calibration can no longer pick up a half-written master.
- Restore brings back a project's master annotations and hand-chosen masters, and waits for a run in another tab to finish.

Light theme and look
- App settings › Appearance offers Dark or Light; it applies at once to every window, and dark stays the default.
- Charts, the splash screen and scrollbars follow the theme, and the Processing page's scrollbars are visible before you hover.
- Most buttons, chips, tabs and column headings now show a short tip on hover saying what they do.
- Main page section headings are larger.

NINA plugin: filling a night that finishes early
- When the plan runs out with usable darkness left, the plugin replans the rest of the night and keeps imaging; if every enabled Active target is complete, the best-placed one gets extra subs.
- On by default, with a switch on the plugin's Options tab; needs plugin 3.17.0.0.

Export Sequence
- An exported night now carries each target's id, so the NINA plugin credits frames to the right target even after a rename (a config gets its ids on its next Save).

Fixes
- File and folder dialogs no longer freeze on OneDrive-synced folders such as the Desktop; files now show one generic icon.

## 3.15.0

Processing can now message your phone through Telegram or Pushover when a step you choose finishes, fails, is cancelled or needs your input; set it up under Processing > Settings > Notifications.

A saved seasonal plan now lists each target's per-filter allocations in the filter list's order (previously that order was arbitrary and could differ between launches).

The genetic planner runs faster: it no longer writes debug logging nobody reads, which measured as 3–9 % more generations per second on one core and 17–26 % with several.

## 3.14.0

Any NightFront on your LAN can now offer itself as a processing server, so Calibrate, Build masters
and Stack can run on a faster machine while you keep working here. A new Processing server
button in the title bar turns a machine into a server with no config file needed — just its engine
paths, its own path to the Projects folder, and a workspace root. On the machine you dispatch from,
add it as a peer (Processing → Settings → Manage peers…) and pick Run processing on: that peer;
the job runs there and its result is recorded here, exactly as a local run would be. While a job is
away, the project it's working on (or, for a masters build, the whole rig) is held against anything
that would collide with it, and closing NightFront or losing the network mid-job loses nothing — the
next launch or reconnect collects whatever finished. A job away and a local run each report in their
own panel, so their logs and rejected-frame lists never mix. Each panel is only as tall as what it
has to say, and once a run ends its heading reads "… — ended" rather than the running status; a
finished panel folds down to its heading and outcome while another run is still going, and has
*Show details* and *Dismiss* buttons, so the project cards below stay in view. Every button that
can't act right now — Organize, Calibrate, Stack, Build, Review, Complete — now says why in the
status line instead of doing nothing, and Organize says so before its confirmation opens rather than
after. A peer refuses a job it can't run — no
engine set, or its engine moved or deleted — the moment it's sent, rather than failing minutes in.
Sending a large job waits as long as the peer needs to check its files first, and if the peer's
answer is lost anyway, NightFront says the peer may have started it, finds the job there and follows
it — the project stays held meanwhile — rather than reporting it "not started".
Abandon remote job… now tells the peer too, when it can reach it: a job still running there is
stopped and dropped, a finished one is dropped, so the peer no longer lists it as waiting for its
client forever. The confirmation says what happens if the peer can't be reached (it may still finish
the job, and nothing it writes is recorded here), and a processing server now drops any finished job
its client hasn't collected within 7 days — its panel says so.
Manual frame selection is refused for a remote stack rather than silently run automatically (the All
projects Stack excepted, which runs it automatically everywhere, as its confirmation says). Tested
on Windows and Linux, each serving the other; macOS builds and ships this too, but hasn't yet been
tried processing across machines.

A remote masters build's Cancel no longer claims to cancel the peer once the peer is already
done. After a masters build's job came back from a processing peer, this machine still archives the
flat subs and copies the new master(s) into every project — and during that local work the row kept
showing Cancel with *"Cancelling on \<peer\>…"* if pressed, for work the peer was no longer doing. It
now reads *"Finishing on this machine…"* with Cancel disabled for that phase.

A *Calibrate all*/*Stack all* batch that only got a project refused no longer reads "done". When
every project in scope was refused before anything ran — a bad executable path, an unreadable
destination, PixInsight refusing a FITS master, a processing peer refusing the job — the closing line used to read *"Calibrate all — done: 1 project"*, as if it had
succeeded. It now names the outcome, *"Calibrate all — 0 of 1 ran: 1 refused"*, and only says "done"
when every project actually ran.

An ended run on the Processing page now takes one line. When a calibration or stack finishes, its
panel collapses to what ran and how it came out, with *Show details* to open it again and *Dismiss*
beside it, so two finished runs no longer push the project cards off the window. A run that failed
stays open so its error is read, and with two or more ended runs on screen a *Dismiss all* clears them
in one click.

Six small wording and counting fixes on the Processing page, found in a two-machine session:
a background-collect line no longer ends in a double period when the AstroBin CSV has a note of its
own; a local stacking log's Engine row now states its version when known, the same as a remote
one already does; a remote-collected stacking log no longer calls the client's own record folder its
"Working directory" — nothing ran there; the Library's flat-master group count no longer counts a
master held as both .fit and .xisf twice; *Calibrate all*/*Stack all* cancelled while its first
project only waited for a busy peer now says *"cancelled before any project was sent"* instead of
counting that wait as a run; and the PixInsight/Siril executable fields on Settings no longer call
the engine "unavailable" when a processing peer is picked — Calibrate and Stack run there regardless.

A "must wait" note on the Processing page now clears when the remote job it names ends. While a
job ran on another machine, an action on its project was refused with *"… must wait: … is running on
…"* — and that note stayed after the job had finished and been collected, and even after Dismiss,
until a Rescan. It now clears the moment the job ends (collected, failed, cancelled or abandoned), and
Dismiss clears it too. While it stands it has its own line, instead of being run together with the
scan's summary, and a run that fails (a peer refusing the job, for instance) shows its reason once, in
red, in its own panel, rather than twice.

PixInsight now calibrates with an XISF master even when a newer FITS one of the same kind
exists. PixInsight cannot use a FITS (.fit) master, so when the library holds both — typically an
older PixInsight-built .xisf beside a newer Siril-built .fit — PixInsight is handed the .xisf
instead of refusing the run, and the association says which newer master it passed over and why. The
Library page's *calibration uses this one* mark moves with it. Siril is unchanged: it reads both
formats and still takes the newest. A Build masters run with PixInsight whose flats would be
pre-calibrated with a FITS bias or dark-flat is now refused before it starts, naming the masters and
the two ways out.

A PixInsight Calibrate that writes nothing now says why. PixInsight refuses to calibrate with a
FITS (.fit) master — the kind Siril builds — and used to fail every frame in seconds with nothing
but *"PixInsight produced no calibrated output for this frame"*. A PixInsight Calibrate or Stack whose
matched masters are FITS is now refused before it starts, naming the masters and the two ways out:
build the rig's masters with PixInsight, or calibrate the project with Siril. And whenever PixInsight
does calibrate nothing (a missing light takes its whole batch down, for instance), each frame's
failure now carries PixInsight's own error message — in the run's report and in its result.json.

Cancel on a remote job now answers. Pressing Cancel on a job running on another machine used to
change nothing on screen until that machine replied — and if the job was already past its processing
step (copying results into place), it finished anyway and read as though Cancel had never been
pressed. The row now reads *"Cancelling on astroprocess…"* the moment you press it, and a job that
finishes anyway says so: *"… — Cancel arrived after the engine on astroprocess had finished; the result
was kept"*. The finished frames are recorded as usual; a Stack that began with that calibration does
not go on to stack.

You can abandon a remote job while it is still running. *Abandon remote job…* was refused with
*"NightFront is asking the processing machines about their jobs right now — try Abandon again in a
moment"* whenever the background collector was checking on remote jobs — which, after reopening
NightFront, could be the whole time the job ran, so the refusal lasted until the job had finished.
Abandon now goes through at once: the processing machine is asked to stop and drop the job, and
nothing it produces is recorded. The only time it is still refused is the moment NightFront is
recording that same job's finished results; its report then says what was collected.

A remote job whose processing server stops answering now says so. While NightFront follows a job
on another machine and loses contact with it (a pulled cable, a server restarting), the job's status
line now reads *"Windows unreachable since 21:14 — still waiting; the job may be running there"*
instead of carrying on as though nothing had happened — including while the job is still being
handed over, which for a large batch can take a few minutes. When contact returns the line clears, the run
reports *"Back in contact with Windows — the job is still running"*, and NightFront carries on
following the job and records it when it ends. A lost link on its own never marks a job failed or
finished, and NightFront now follows through an outage of a few minutes before leaving the job to the
background collector.

A refusal on the Processing page is no longer erased by a rescan you did not start. A click
refused while a scan was running, or just before a background rescan (a remote job being recorded,
an engine or stacking-setting change), could have its explanation wiped before you could read it, so
the click appeared to do nothing. The explanation now stays until you rescan or do something else.

Processing → Library's *Build masters from calibration subs* section is reachable on any window
size. On a short window (measured live on Linux), the section could be cut off partway through the
plan list with the checkbox, pre-calibration line and Blink link of a later flat group missing, and
the *Show script* / *Build N master(s)* buttons below the list gone entirely — the whole Library page
was a fixed-height column with no way to scroll to what fell past the bottom edge. The Library page is
now a single scrollable list from top to bottom. The *Build* click's *Blink the flat subs first?*
offer also no longer risks clipping its *Build without blinking* button at narrow widths or wider
fonts; its buttons now wrap instead.

A Siril stack of a color (one-shot-color) project no longer warns about channel counts on every
run. With drizzle off, each stack used to report two *"has 3 channels where a frame stating no CFA
pattern implies 1"* warnings per filter — on a perfectly good project, because Siril drops the Bayer
pattern from the color frames it calibrates. The check now asks the original lights what form the
calibrated frames should be in, so a good color project stacks silently — locally and on a
processing server alike — and a calibrated frame that is still one channel when color was asked
for is now refused even when it states no pattern. With drizzle on, a color project's calibrated
frames that were debayered anyway are now refused with a message naming drizzle, rather than only
warned about.

A remote job's leftover intermediate files no longer get reported as a problem when Windows was
just about to let them go anyway. A remote Calibrate or Stack could say *"6 intermediate file(s)
of this job could not be removed"* moments before the folder went empty on its own — the same brief
file hold a finalize move already retries. The server now waits it out the same way; a hold that
clears reports nothing, and one that doesn't is reported once, with why, and says it will be cleared
when the job is acknowledged or at the server's next start.

The Processing server and Processing peers windows now scroll with a visible scrollbar. Both
used to clip their content at the window's bottom edge with no scrollbar shown — the pre-shared
token and Copy button, *Serve at launch*, the firewall note and *Current job* were hidden below the
fold in the server window, and most of a peer's capability report after Check was hidden in the
peers window. Both windows are also a little taller by default.

Blink's status line now shows real numbers for a Calibrated (FLOAT32) frame instead of "median 0 ·
MAD 0 · min 0 · max 0." Calibrated _c data is stored in 0..1, and rounding to the nearest whole
ADU — right for a raw 16-bit light — rounded every one of those values to zero. Float frames now show
enough digits to be meaningful (e.g. median 0.0213); a 16-bit frame's readout is unchanged.

A frame rejected while blinking Originals or Calibrated is now recorded in the ignored folder's
blink record, like an Inbox reject. The record says a person looked at the frame and rejected it,
and when — which the folder alone cannot tell apart from a ledger removal.

A calibration or stack that had to wait out a file another process was briefly holding now says
so. The retry that fixed the intermittent *"being used by another process"* finalize failure used
to succeed silently, leaving no evidence of what was held or for how long. A run's narrative now
gets one line — "Waited out a file hold on 1 file (0.4 s): pp_light_00005.fit" — the first time it
happens, however many retries it took.

A colour-camera project stacked with drizzle off no longer keeps Stack lit after a good stack.
Siril drops the Bayer pattern from the frames it debayers during calibration, so NightFront used to
record such a master as made from undebayered frames and then report it out of date forever — no
re-stack could clear it. The record is now taken from your original lights. A master already
recorded the wrong way clears on its next stack. When a master really is out of date only because of
its colour form, the line under the project now says so (*"made from undebayered frames; the
pipeline now wants them debayered"*) instead of claiming it was made with a drizzle setting it
wasn't.

Blink can now review lights you already organized into Originals\ or Calibrated\, not just a
night's Inbox. The ▾ beside Blink opens a menu — Blink Inbox · Blink originals… ·
Blink calibrated… — and works even with an empty Inbox, where the button itself now reads
Blink ▾ instead of going disabled. Both new choices open a dialog first, with filter and session
checklists (both start fully ticked) to narrow what you look at; Blink calibrated… shows each
light's calibrated copy in place of the original, so you're judging the pixels the stacker actually
uses, and states how many lights it had to leave out and why. Rejecting a light in either scope parks
the original in the rig's ignored folder exactly like an Inbox reject, corrects the target's accepted
time, and lights up Stack for any master that was built from it. Under Siril, blinking a night's
calibrated lights also counts as reviewing them, clearing their Review badge.

Blink has two verdicts now, accepted or rejected; the undecided state and its U and N keys are
gone. Every frame starts accepted, X rejects it, A accepts it again and Space switches
between the two. This holds in every blink — Inbox, originals, calibrated and flats — so committing
an Inbox blink files every frame you saw, and a flat you didn't reject is integrated. The ↺ Clear
button and the tally's third count are gone, and rejected thumbnails in the filmstrip are now the
dimmed ones. Anything you left undecided in an unfinished blink opens as accepted.

Processing → Projects gains an "All projects" box with Calibrate, Accept lights and Stack buttons
that run over every listed project. Calibrate and Stack each run one project at a time
(built on the same engine and lock as the per-project buttons), skipping a project with nothing to
do, continuing past a project that fails or is refused, and reporting a line per project as it
finishes, with its own Cancel. Stack runs unattended — it stops for no question a stack could
normally ask, so a click and a confirmation are enough to start it and walk away: frame selection
runs automatically on each project's stored limits even where it is set to manual review (for this
run only — the setting itself is untouched, and a later single-project stack still asks), a second
OBJECT name found among a project's frames stacks as its own group with no ruling recorded, and a
thin master is left alone rather than replaced. A confirmation pop-up lists the projects, their real
destination folders and these defaults before it starts. Accept lights (all projects) has moved
into this box, relabeled Accept lights N — its own rule is unchanged.

Every Stack now calibrates any uncalibrated lights first, then stacks, as one action — the
per-project button and Stack all alike. This skips the separate Review step in favor of the frame
selection built into the stack itself; the Calibrate and Review buttons are unchanged. If calibration
fails outright nothing is stacked and the report says why; if only some frames fail, the stack still
runs over what calibrated.

A Siril calibration or stack no longer loses a frame because another program had the file open for
a moment. On Windows, moving a just-finished frame out of Siril's working folder could fail with
"being used by another process" (a virus scanner reading the new file is the likely cause), leaving
that light uncalibrated until the next Calibrate. The move now waits briefly and tries again, as does
the move of calibrated frames into the project folder. The "Calibrate: re-stacking … needs its N
older frames calibrated again" note is also corrected: it counted frames that were already
calibrated and would not be touched, so after a partial calibration it named frames Calibrate would
not redo; it now counts only older frames whose calibrated copy is gone.

A stack cancelled before any master was built now reports that it was cancelled, not that "no group
had a stackable filter." That wording is for a genuinely empty run; a cancel is a different reason to
end with nothing, and reporting it as an empty group falsely said the target's frames were never
stackable. A cancel now says so in every case — including a partial or full success cut short — rather
than being mistaken for an ordinary success or failure. Seen in the per-project Stack summary and the
*Stack all* batch line alike, and in a stack run on a processing peer just the same.

A target card's filter table now scrolls sideways in a narrow window instead of crushing its
columns. At 1280-wide or narrower, Gain, Offset, Readout, Dither and Moon Profile used to collapse
into a sliver too thin to read (Moon Profile's header rendered one letter per line). The header,
every filter row and the totals row now scroll together as one unit, with a scrollbar (or shift +
mouse wheel) when the table is wider than the card; at the card's full width nothing changes.

Target cards no longer blow up vertically in a narrow window — the coordinate row (RA, Dec, type and
Rotation Angle) now wraps instead of crushing Rotation Angle's label into a one-letter column. RA and
Dec wrap independently, so Dec drops to its own line rather than clipping its arcseconds field at
1280-wide.

Siril stacking with a keep-best percentage below 100 now produces masters. It used to fail on
every filter, because Siril's registration records no "quality" value for it to rank by. Keep-best
now keeps the best frames of each filter by weighted FWHM (star sharpness, measured during
registration) — each filter ranked on its own, never against the other filters in the stack. If
that measurement is missing, the stack stops with a message saying so instead of quietly using every
frame.

Target and mosaic panel cards now show Plan (h) and Acc (h) alongside Rem (h), plus a totals row.
Every filter row already showed remaining integration in hours; it now also shows planned and
accepted integration in hours, read-only, computed the same way — from the stored seconds, not from
frame count × Exp(s). Below the last filter row, a read-only Total row sums Plan (h), Acc (h) and
Rem (h) across every filter on that card (each mosaic panel gets its own total; the frame-count
columns stay blank, since frames at different exposures don't add meaningfully).

The stacking log gains an Integration section, and the Outcome table a headline Integration line.
Each run's stacking-log_<date-time>.md now states, per filter (and per panel of a mosaic, with a
per-filter subtotal), how many frames the engine actually integrated into that master and their
summed exposure. This is a fact about the run, not the target card: registration and frame selection
can drop frames the card still counts as Accepted, and a re-stack may use a smaller subset than an
earlier one did, so the two numbers can legitimately disagree. A frame whose outcome can't be
confirmed as integrated is reported as "of uncertain outcome" rather than counted or zeroed, and the
total is marked as a lower bound whenever that happens — except where the master file itself says
what went into it: a Siril best-percent stack's master records its frame count and total exposure,
so that master's row reads from it, marked "(from the master)", and counts toward the totals. Frames
whose outcome the engine didn't report are listed in their own section rather than under the frames
that did not reach a master.

In a mosaic, the stack's "other object names" question now knows the panels. The mosaic's own
panels are listed as panels, with their frame counts, and are never asked about, so a mosaic whose
names are all panels stacks without stopping. A name that is no panel — a typo such as Panle 2 — is
offered Merge into ▸ any panel of the mosaic, Keep separate or Skip these frames. Before,
every panel but the most-shot one was asked about, and a typo could be merged only into that panel.

A mosaic's merge ruling now also decides where its frames are counted and filed. Accept
lights counts frames carrying the merged name toward that panel's accepted time (they used to count
toward nothing), and once the old name's folders are tidied, new frames carrying it are organized
into the panel's Originals\ folder and calibrated into its Calibrated\ folder. A project card whose ruling still has folders
under the old name shows a note with Tidy folders…, which lists every move first and then moves
the old name's originals — its rejected\ folder included — and calibrated copies into the panel's
folders. Nothing is re-calibrated, no FITS header is edited and nothing is overwritten; a ruling
whose frames share a file name with the panel's own is refused and named, and the others still move.
A ruling that would merge one panel into another is never acted on in the folders. Stack again
before removing frames from a stack made before the tidy.

The card note, the post-stack note and the Tidy folders… dialog now name a ruling in the spelling
found on the frames, not the lower-cased key used to match it, matching the ruling dialog itself.
The rejected\ folder is only mentioned in the Tidy folders… dialog when the move actually includes one.

A new mosaic frame whose OBJECT differs from a panel's name only in spacing is now filed under
that panel's folder, instead of a folder of its own spelling.

Stack and Calibrate now follow the project's actual folders, not just what has run before. Delete
a stacked master (or the whole Stacked\ folder) and Rescan, and Stack lights up again for the
frames it used — before, a deleted master left Stack dark and Complete lit forever, still
offering to archive a project whose master was gone. Reject a frame after it has
already been stacked and Stack lights up for that master; if a re-stack needs older frames whose
calibrated copies are gone, Calibrate lights up for those too. A line under the row says why, for
example *"Stack: 3 frames in the OIII master have since been rejected"* or *"Calibrate: re-stacking Ha
needs its 108 older frames calibrated again."* Freeing space by deleting Calibrated\ no longer
re-lights Calibrate for frames a still-current master already covers. A filter with too few
frames to stack, or whose stack failed, no longer counts as stacked in its own right — its previous
master (if it has one) is simply left as it is, and the run says so: *"… not stacked this run; its
previous master is kept."*

Re-stacking with fewer calibrated frames than a master already has now asks first, instead of
silently overwriting it. Masters carry no frame count or date in their file name, so a stack run
before recalibrating everything used to replace a full master with a thinner one with every row still
reporting success. Now it stops, per filter: *"Ha 1x1 was stacked from 120 frames; 108 of them are not
calibrated now, so this stack would use 12. Calibrate first, or tick to stack anyway."* Leaving it
unticked keeps the fuller master exactly as it is; a frame you've since rejected doesn't count against
you.

Complete now also waits for the target's collection goal to be met. Before, a project re-stacked
partway through its plan — real, ordinary use now that Stack follows the folders — could offer to
archive it as soon as any master existed. Complete still fills only once nothing upstream has
work, but now also only once the linked target (or mosaic) has nothing left planned, or every panel is
marked complete; a folder mapped to no target is unaffected, and neither is a target nobody ever
stated a plan for. Opening the dialog early states the shortfall instead — *"M 31 still has 4.2 h to
collect (Ha 2.0 h, OIII 2.2 h)"* — and still archives on confirmation.

Blink now groups a night's lights by filter — each filter's frames in the order they were taken,
filters in filter-wheel order — so consecutive frames are directly comparable. Press F (or the
By filter · By time segment in the status line) to switch back to time order, and
PgUp/PgDn (or the status line's ⇤ Group / Group ⇥) to jump to the start of the
previous or next filter group; the choice is remembered on this machine for the next blink. Every
ruling survives the switch. Between the two group buttons a label names the filter you are viewing
and your place within it (Ha · 12 of 40; shown on its own for a night of one filter). The
filmstrip marks each filter's frames, the status line flags when the reference frame is a different
filter, and the sky sparkline and its outlier hint are
now scored per filter instead of across the whole night, so a quiet narrowband filter no longer reads
as flat beside a bright broadband one — or the reverse.

## 3.13.0

Every stack now writes an AstroBin acquisition CSV beside its masters. Uploading the image to
AstroBin becomes *Import CSV* instead of typing one row per night and filter: the file lists each
night, filter and sub length with the number of subs that went into the master, plus binning,
gain, sensor cooling and f-ratio where the frames and rig state them. A mosaic gets one per panel
and one for the whole mosaic. For the filter column, give each filter its AstroBin id once on
Imaging System → Filters → AstroBin filter — paste the filter's AstroBin page address or type
the number; Find on AstroBin opens the filter list. A filter without one is still listed, with
its filter left blank, and the stacking messages say which.

Stacked masters land in a panel folder exactly when the project is a mosaic, on both engines.
A mosaic's masters now go into Stacked\<panel>\ under Siril too (they used to lie flat in
Stacked\), and an ordinary project's PixInsight masters now go straight into Stacked\ (they used
to get a Stacked\<target>\ subfolder). Masters you have already stacked are not moved.

PixInsight stacking logs now name each master's group. The *Masters* table's Group column showed
the step ("Integrating each filter — Ha") instead of the target or panel, so a mosaic's panels could
not be told apart in the log or the run record.

Flat subs can now be blinked before they are built into a master flat. A bad flat — a slipped
dew shield, a flickering panel, a sky flat taken as the sky darkened — can be rejected before it
reaches the master. Every flat group in Library → Build masters from calibration subs has a
Blink button, and pressing Build offers to blink any ticked flat group you have not blinked
yet: Build without blinking, Cancel or Blink first. Building without blinking is always
one click; the offer is on by default and can be turned off with *Don't ask again* or under
Processing → Settings → Offer to blink flat subs before building master flats. Flats open in a
new Window contrast view — a straight ramp held from one frame, so vignetting and dust show
plainly and a brighter or dimmer flat looks brighter or dimmer — and a flat whose level is 3 % or
more off the rest of its group is marked. Rejected flats move into the rig's ignored folder
(rejected\ by default) beside the others; accepted flats never move, and flats left undecided are
integrated. When the master is built, the rejected flats are archived with the rest of their flat
set.

The calibration engine can't be switched while a flat blink is open, since switching re-makes
the master plan and would lose which groups you un-ticked; the Settings page says why. Clicking the
engine that is already selected no longer rescans anything. For the same reason, calibration,
stacking and the other Processing runs wait until a flat blink has finished, and say so.

## 3.12.0

PixInsight calibration can now run the real CosmeticCorrection process, with a defect map.
Processing → Settings has a new Image Calibration section above Stacking — the settings
Calibrate reads, as Stacking's are the ones Stack reads — whose Cosmetic correction group is set
per imaging system: hot and cold
pixels can each be corrected by ImageCalibration's built-in pass (as before) or, under
PixInsight, by CosmeticCorrection's own auto-detect — and you can now point it at a linear defect
map (a LinearDefectDetection output) to correct a sensor's known-bad columns. Leave every new
option off and calibration is unchanged. A map containing a row defect is refused before the run
starts, naming the fix, because PixInsight's own CosmeticCorrection silently corrupts row defects
on some frames.

The app no longer silently overwrites a config that changed on disk. The NINA plugin can now
move a target between Active and Planned, enable or disable one, and export automatically —
alongside CLI edits from other machines. If NightFront's own automatic save (finishing a project,
reframing, accepting subs) would have overwritten one of those changes, it now refuses instead and
tells you to reload first; an interactive Save or Save As offers Reload or Overwrite.

The NINA plugin can now move targets between Active and Planned, enable or disable them, and send
a target — including a whole mosaic — to NINA's Framing Assistant to see it framed, all from the
Targets page at the mount. Reload on this app's Targets page shows the moves and the enable/disable
state the same way it always has.

⚠️ New mosaics now lay out exactly as NINA's own Framing Assistant draws them. Before this
release, a mosaic's panels were laid out as the mirror image of the grid NINA draws at the same
rotation. Each panel was still imaged at its own coordinates, but NINA turned the camera to the
stored rotation while the panels were tiled for its mirror, so at a rotation that is not a multiple
of 90° every frame sat askew of its neighbors: the overlaps shrank and gaps could open between
panels (worst at 45°, 135°, 225° and 315°). Mosaics you already have are untouched; hand-entered mosaics at an angle that
is not a multiple of 90° now lay out differently, and a mosaic generated at 90° or 270° numbers its
panels in reverse. The Rotation field, in Manual Entry and on the target card, now names the
convention: it is the Position Angle NINA's sequencer target carries, the same number the Framing
Assistant's Rotation box shows.

⚠️ New mosaics also place their panels the way NINA itself does (stereographically), not the flat
tangent-plane approximation used before. The two agree closely near the center of a small mosaic
and differ by a few arcseconds toward the edge of a wide one. That is harmless for imaging, but it
is what lets the plugin's whole-mosaic Frame draw wide grids NightFront lays out; a very wide grid
can still occasionally be refused, because NINA works out a camera's field of view slightly
differently. Every newly generated mosaic moves by that small amount, including ones at 0°.

If you have a mosaic laid out before this release at an angle that isn't a multiple of 90°, the
Targets page now tells you about it. A banner above the target lists appears when the open config
has such a mosaic you haven't already decided about. Review… lets you, per mosaic: turn the
camera to the angle NINA needs (resets that mosaic's Accepted counts — you'll need new calibration
flats at the new angle), move the panels to where NINA would put them (keeps the stored rotation;
a panel that doesn't actually move keeps its counts), or leave it and dismiss the flag. A mosaic with
a completed panel is listed but can be neither corrected nor dismissed there until you use Plan
again on it. Dismissing (or undoing a dismissal) is written to the config file straight away, not
at your next Save.

A mosaic at 45°, 135°, 225° or 315° can only be checked once your imaging system states its sensor
size. At those angles an older layout and NINA's fit the same panels, with rows and columns
swapped, and only the camera's shape tells them apart. If the Imaging System page has no Sensor width
(px) and Sensor height (px), the Targets page names such mosaics and asks for them; once they are
entered, a mirrored one appears in the Review… list like any other. A single row or column at those
angles is told apart by how long its step is against the camera's field of view, so it also needs
Focal length and Pixel size. A mosaic within 0.1° of a right angle is never flagged, as before, and
that now holds the same on both sides of the right angle (359.9° and 89.9° alike). A mosaic you have
dismissed, or one with a completed panel, is not named again for want of a sensor size. The check
also recognizes a mosaic NINA laid out with its overlap in pixels, and a wide-field mosaic (a short
lens on a large sensor), where the camera's field of view is not quite the shape of its pixel grid.

AstroPM import has been removed. The Import AstroPM… button, its review dialogs and the
lastAstroPmImportDir preference are gone. Targets and mosaics you already imported are untouched —
nothing about them changes, and an older preferences file carrying the removed directory setting
still loads normally. If you were partway through moving a project from AstroPM to NightFront by
hand, finish that import with the previous NightFront version first; this version has no import
path for it.

Frame on the Targets page no longer says a well-placed target "never rises above the horizon".
Since 3.10.0 that note appeared on every Frame of a target that was comfortably up; it now appears
only when the target really has no usable moment. And a mosaic card whose panels are partly
completed now says so, instead of claiming the completed panel sits in the Planned list.

## 3.11.0

A mosaic now gets a panel folder in all three trees, or none does — and NightFront decides that
from your target, not from the frames. Whether a project is a mosaic used to be guessed at by
counting distinct OBJECT names in it, and that was wrong in both directions: a mosaic whose second
panel you had not shot yet counted as *not* a mosaic, so its lights sat flat in Originals\ until
the night panel 2 arrived and then all moved at once; while a single target whose frames carried two
spellings of its name (say *Eagle Nebula* and *M 16*) counted as a mosaic and grew two panel folders
it should never have had. NightFront now asks whether the target is a mosaic.
⚠️ This can move files in existing projects. The next Organize on an affected project will
put its lights where the rule says they belong — into a panel folder, or back out of one. As always,
Organize lists every move on the card before you press it, and nothing moves until you do.

You can now review and reject a mosaic frame whose file name is shared with another panel. NINA
restarts its numbering each session, so two panels routinely have a LIGHT_0001. Those frames used
to be skipped by the review as ambiguous; now that each panel has its own calibrated folder they are
identified by panel and can be reviewed and rejected like any other.

New: Check layout… tells you what the old flat Calibrated\ folder destroyed. On any project
that predates the change, this reads each calibrated frame's own header, works out which panel it
belongs to, and — crucially — finds the frames that are *missing* because two panels' identically
named frames landed on one file. It reports them per panel and filter (*"Panel 2 lost 9 Ha
frame(s)"*), which is the only place that number exists: every record in NightFront says those frames
calibrated fine. ⚠️ Where frames were lost, re-calibrating is the recommended action, not moving
the files — your original lights were never touched, so re-calibrating restores every lost frame
*and* produces the new layout, while moving only fixes the folders. Projects that lost nothing are
offered a straightforward move, and projects with no mosaic panels are already correct.

Calibrated frames and stacked masters now live under a folder per mosaic panel. The tree mirrors
itself all the way down: Originals\Panel\Session, Calibrated\Panel\Filter, Stacked\Panel.
⚠️ This also fixes silent data loss. Calibrated\ was flat by filter, and NINA restarts its
frame numbering every session — so two panels' LIGHT_0001_c landed on one path and one quietly
overwrote the other, while NightFront went on recording both as calibrated. If you stack mosaics,
re-calibrate to get every frame back. ⚠️ Calibration now runs one job per panel per filter instead of
one per filter, so a multi-panel mosaic reloads its master dark once per panel and calibration takes
longer; that cost was accepted deliberately to keep the frames separate.
⚠️ If you stack mosaics, check your first calibration run of this release wrote frames where you
expect. This change alters which calibration jobs are generated and which folder each engine writes
into. It is covered by tests and was verified end to end on synthetic trees, but it has not been run
against PixInsight or Siril themselves — and PixInsight writes nothing into a folder that does not
exist rather than reporting an error. One look at Calibrated\<panel>\<filter>\ after the run is
enough; if it is empty, say so and stay on 3.10.2 until it is fixed.

Stacked\ is now the default place masters go — <project>\Stacked\<panel>\, derived from the
project rather than typed in. You can still point a run somewhere else on the stacking dialog, and
that is deliberate: choosing a fresh folder is how you avoid a re-stack landing on top of an earlier
one. The folder name is overridable per rig, like Calibrated\.

Importing a new mosaic offered one project folder per panel, instead of one for the mosaic. The
first time you imported a mosaic's frames — before any project folder existed for it — each panel
arrived as its own row in the import dialog, each suggesting a folder named after that panel. Ticking
them gave you Spaghetti Nebula Panel 1 and Spaghetti Nebula Panel 2 as two separate projects for
one mosaic, and afterwards everything imported for either panel silently went to whichever folder
sorted first. The dialog now shows a mosaic as one row that names its panels, suggests the
mosaic's own name for the folder, and creates a single project holding every panel. ⚠️ It also no
longer claims your mosaic's panels look like a NINA typo of each other. If you already have a
split mosaic, the Projects page now warns you about it and offers to merge the two folders (see
below).

New: you can rename a project folder from inside NightFront. *Rename…* on the card. This matters
after a merge: folding a split mosaic back together leaves the survivor still named after one panel,
and now you can call it what it is. ⚠️ Use this rather than Explorer. NightFront keys everything
it stores about a project — which frames you have reviewed and which have been stacked, its stacking
settings, its target link, unsaved blink verdicts — to the folder's name, and renaming outside the
app loses all of it. Renaming inside carries it across. Renaming onto an existing project is refused
and points you at Merge instead.

Two project folders claiming the same target can now be merged. The card offers *Merge this
into…*, which moves every light across — each keeping its panel and session folder — and combines
the two projects' settings, keeping what you have already reviewed and stacked. ⚠️ Nothing is ever
overwritten: if a frame would land on a file that already exists, the whole merge is refused and
names it, so no acquisition is lost to a name clash. Calibrated and stacked output stays in the old
folder for you to delete, because it is rebuilt by calibrating and stacking again.

The Projects page now tells you when two folders map to the same target. This could happen
silently, and it decided where your frames went: imported frames go to whichever of the two folders
sorts first by name, so the other one quietly stopped receiving them. That is how a split mosaic
ends up with one folder holding everything and its sibling holding a single stray night. The card
now says so in red and names the other folder.

Stacking a mosaic in PixInsight overwrote the first panel's masters with the second's. A
mosaic is one project, and its panels are stacked as separate groups — but on the PixInsight path
every group named its masters after the filter alone (master_Ha.xisf), so all of them landed on
one set of files in the destination folder and the last panel won. The run reported every master as
written, because every master *had* been written; only the folder afterwards disagreed. Masters are
now named for the panel and binning as well as the filter (Spaghetti_Nebula_Panel_2_Ha_1x1.xisf),
which is what the Siril path already did — Siril was never affected. The same fault applied to one
target shot at two binnings. If this has bitten you, re-stack: your calibrated lights were never
touched, so nothing needs re-calibrating. ⚠️ Master filenames change for every PixInsight stack,
not only mosaics; existing masters are left alone and a re-stack writes the new names beside them.

Re-pointing a target from NINA's Framing Assistant now defaults to the copy, not the original.
When two of your targets sit at the same pointing — which is exactly what Duplicate makes — the
plugin's *Update an existing target* picker listed them in config order and pre-selected the first.
That was reliably the original: the one holding all the accepted frames a re-point discards. Ties
now put whichever target has the least accepted integration first, so pressing Update without
touching the picker chooses the one with nothing to lose. Targets at different distances are
unaffected, and you can still pick either row.

A balanced mosaic can now hold its window — new slider, and a changed default if you use
panel balancing. *Balance time across a mosaic's panels* had one behaviour: a panel handed
the mount on the moment it stopped being the one furthest behind, which is why a balanced
mosaic could lose its whole night to an ordinary target competing for the same sky. How long a
panel holds on is now yours to set, under the checkbox in Nightly Planning → Setup: *Hold a
panel until a sibling falls N behind*. The number is hours of imaging time, so one hour
means the same thing whether a panel wants ten hours or a hundred.

On a cloudy night a balanced mosaic could still get stuck on one panel. The hold was measured
in *useful data collected* rather than time spent, and NightFront discounts data by the forecast
cloud — so under a thick sky a panel could sit on the mount for nearly five hours while the hour's
worth of credit that would hand it over never accumulated. Measured over three nights on a real
two-panel mosaic: clear skies gave 12 panel turns with the longest at 2.6 h, 85% cloud gave 6 with
the longest at 4.9 h. The hold is now counted in time on the target, so it means the same thing
whatever the sky is doing. Clear-sky plans are unchanged.

It defaults to 1 hour, which is a change if you already had balancing switched on. Measured
over three nights at a threshold of roughly this size: about half the slews, visits roughly
twice as long, panels tracking each other a little less closely, and every panel still served.
On a single night a panel may now
wait until the next night for its turn, so judge a mosaic over the whole run. Drag the slider
to zero for exactly the old behaviour. Nothing changes for a session with no mosaic in it, or
with the checkbox off — which is still the default.

Clicking into a target's RA or Dec box and out again no longer wipes the message above it. The
coordinate boxes show rounded values — a tenth of a time-second for RA, a tenth of an arcsecond for
Dec — and committed those rounded digits back on the way out. For any target whose position came
from Stellarium, SIMBAD or the CLI that was very slightly different from what was stored, so simply
focusing and leaving a box was treated as a move, refused as too small, and the refusal replaced
whatever the last action had reported — including the one line telling you a re-point had just
discarded your accepted frames. An untouched box now commits exactly what it is showing.

Confirming a hand-typed coordinate change no longer discards Stellarium's rotation reference.
Both the *Read frame* button and a hand edit ask before moving a target that has accepted frames,
and confirming either one retired the record of what Oculars was showing when the target was last
framed. Without it, a later *Read frame* could write Oculars' untouched 0° over a real position
angle. Only a move that actually came from a frame read retires it now.

Save now lights up when a tab has unsaved changes. Edit a target, a filter plan, the site,
anything that lives in the config, and the Save button in the top bar fills in and the filename
gains a *• unsaved changes* note. It goes back to normal the moment you save. A tab that has never
been saved counts as unsaved as soon as it holds a target. While a config is still loading —
briefly, while targets resolve — Save stays plain rather than claiming either way, because at that
moment NightFront genuinely cannot tell.

Save and Save As… have moved to a bar across the top of every page. They used to be the last
row of the Site, Imaging System, Targets, Nightly Setup and Seasonal Setup pages, below everything
else those pages hold — so on a long page saving meant scrolling to the bottom to find them, and
they were easy to miss altogether. They are now in one place that never scrolls away, beside the
name of the file this tab is working on, and they are reachable from the Processing page too. They
save exactly what they saved before: the whole config for this tab. The Site page's *Sites Library*
Save/Save As are a different thing and have not moved.

The import window could push its own buttons off the bottom of the screen. When a lot of
the staged files had already been imported, that list grew without limit and squeezed out the
groups below it *and* the Cancel and Import buttons, so the only way out of the window was to
close it. The list now sits in a fixed area of its own with a scrollbar — every line is still
there, and the buttons stay put no matter how long it gets.


A slew now costs what it actually costs, so every plan fits more imaging into the same night.
Until now NightFront charged your Slew/Center/Rotate time in full for every visit, whether the
mount crossed the sky or hopped to the next panel of a mosaic. That number is now treated as the
upper bound it really is: a move of less than 10° costs half, a rotation change of less than 10°
costs half, and a nearby target at a similar rotation — the mosaic case — costs a quarter.
Returning to the target the mount is already on is free. A night's first visit is still charged in
full, because the mount is parked and could be anywhere.

Expect a little more time on sensor everywhere, and noticeably more in a mosaic. Measured on a
six-target winter test night: time on sensor rose from 90.3% to 93.7% of darkness, about 23 extra
minutes of imaging. Plans will differ from those the previous version produced for the same inputs
— this changes the timing of every plan, not just mosaics.

New, and off unless you turn it on: Balance time across a mosaic's panels. The checkbox is in
Nightly Planning → Setup → *Scheduling Criteria*. It makes the optimizer treat a mosaic as one
choice and give each turn to whichever panel is furthest behind, so the whole mosaic advances
evenly instead of panel 1 completing while panel 4 has nothing. On a mosaic that has the night to
itself it works well — in testing it went from serving one panel all night to serving all four,
with the gap between best- and worst-served panel ten times smaller.

⚠️ At a zero hold it can cost your mosaic time overall, and on a busy night all of it. Drag the
slider below to zero and a balanced panel hands the mount on the moment it stops being the one
furthest behind, so the mosaic can never hold a window while an ordinary target competing for that
same patch of sky can. In testing on a real 14-target config that moved a two-panel mosaic's whole
night to a single-pointing target 17° away. The default one-hour hold exists precisely to stop
that, so you will not meet it unless you turn the hold down. Balancing is still off by default
because it constrains the optimizer rather than being a free win: turn it on when a mosaic is
stalling and you would rather its panels advance together. Sessions with no mosaic in them are
unaffected either way.

Reload from disk, without closing and reopening the config. A fifth button on the Targets page
re-reads the file this tab has open — for when the NINA plugin, the Framing Assistant or the CLI
changed it while the app was running. It asks first, says whether it found unsaved changes in the
tab, and lists what goes either way: the GA's Pareto front and the plan selected from it, plan
scoring, undo history, expanded cards and mosaic panel selection are never written to the config
file and do not survive. Plan variants come back from their sidecar, and the forecast is normally
served from cache, so a reload does not usually spend credits.

Duplicate a target, or a whole mosaic. A Duplicate action on every target card and mosaic
card copies the pointing, rotation, template, minimum imaging time and every filter row's planned
time — and none of the progress. The copy is named "Copy of …", with its accepted counts at zero
and its Complete/Reviewed marks cleared. It is the quick way to shoot something again at different
exposures, or to keep a reframe beside the original rather than overwriting it.

The copy lands in Planned, and until you compute a seasonal plan it sits at the end of that
column — the Planned list is ordered by when each target is next due, and a brand-new one is not
due yet.

Planned rather than Active on purpose: two Active targets on the same patch of sky would both go
into tonight's plan and the mount would shoot the same field twice, with nothing looking wrong. Move
the copy to Active when you mean it. Duplicating any panel of a mosaic copies the whole mosaic
as a new one, keeping each panel's own number — so a mosaic missing Panel 3 copies as 1, 2, 4.

Duplicate a moon profile or an exposure template. A ⧉ button sits beside each row's ✕ on the
Imaging System page. The copy lands directly under the original as "Copy of …" and is selected
ready to edit, so building a second profile that differs in one number no longer means retyping all
of them. One thing the copy does *not* inherit: a moon profile's default filters. Those are
first-come-first-served, so a copy claiming the same filters could never actually be used — assign
the copy whichever filters you want it to claim.

Re-point a target from NINA, without leaving the mount. The NINA plugin's Targets page can now
update an existing target or mosaic to whatever you have framed in NINA's Framing Assistant, not
just create a new one. It needs a plugin newer than 3.10.2.0, which brings its own copy of
nightfront-cli.exe; nothing in the desktop app changes.

It follows the same rule as moving a target by hand here: every panel that genuinely moves has its
Accepted counts zeroed and is stamped Reviewed, because frames collected at one pointing do
not belong to a different composition. Panels that did not really move are left alone. It refuses —
and changes nothing — when the panel count does not match, the target is complete, the framing is
more than 5° away, or the name matches two targets. See the plugin guide's *Update an existing
target from the Framing Assistant*.

A project card now says why Review is greyed out under Siril. Review needs PixInsight's star
measurements, so with Siril as the calibration engine the button has always been disabled — with
nothing on screen saying so, which left operators hunting for a setting that would enable it. The
card now carries *"Review needs PixInsight"* under its step row. It appears only on projects that
actually have lights, so a Siril rig does not carry the line on every card forever.

The Processing tab's import count no longer climbs while an import runs. The button counts what
is waiting in your download folder plus anything left staged from a previous run — and those two
overlap during an import, because each frame is copied and verified into the staging folder before
its original is released. A correct 60 could read as high as 114 mid-import before settling back.
The count now holds still while an import or a scan is running, and re-measures the moment it
finishes.

Renaming a target no longer makes its frames get shot again. Every target now carries a
permanent, hidden identity, written into the config and into the exported plan. The NINA plugin
counts what it captures each night and feeds that back to the planner; those counts used to be
tracked by the target's name, so renaming a target orphaned them and the next plan re-shot data
already on disk. They follow the identity now.

Existing configs are untouched: targets already in a file get an identity the first time that file
is saved, and older versions of NightFront and of the plugin ignore the field entirely.

⚠️ It protects frames counted from here on, not ones already counted. Anything the plugin
recorded before this release carries no identity, so a rename still orphans those. It also needs a
plugin new enough to read the identity — an older one ignores it and behaves exactly as it always
did, which is the same place you were before.

What's new now lists every release, not just the latest one. The notes go back to 2.0.0, so the
button shows what changed at each step rather than only the version you just installed.

## 3.10.2

NightFront has a Discord server, and a Community button that opens it. It sits at the foot of
the left-hand rail beside What's new and Guide. It is the place to ask how other people are
using something, report a problem, or suggest what NightFront should do next. The invite is also in
the User Guide, on the first page and under Troubleshooting.

## 3.10.1

Release notes now ship with NightFront. The What's new button at the foot of the left-hand
rail, beside Guide, opens this list of changes. The same notes come with every installer.

The Targets page's cards no longer squeeze a target's name. On macOS, whose system font is
wider, a card's action buttons took nearly the whole width. The Display name field was cut off,
and "0% complete" ran down the card one letter per line. The buttons (Expand, → Planned/→ Active,
AstroBin, Reviewed, ✕) are now stacked at the card's right edge, leaving the name its room. A
completion label no longer wraps. On a mosaic card, the hours across all panels move to their own
line below the bar.

## 3.10.0

NightFront now ships its own User Guide. It is a PDF covering every screen, installed with the
app on Windows, Linux and macOS. The new Guide button at the foot of the left-hand rail opens
it.

Fixes found while writing it:

- Loading a site or opening a config no longer leaves the forecast chart blank until Refresh. A
  forecast still arriving for the previous site can no longer land on the new one.
- Deleting the linked site no longer leaves its name on the Load button.
- A garbled climate source label (such as "2016â€"2025") is repaired when the config loads.
- The Read frame review card closes after a move is applied.
- On-screen text that no longer matched the app is corrected: the reframe dialog, the optics and
  climate captions, the Stellarium Remote Control setup steps, the Discovery framing note, two
  Editor messages and five Processing hints.

## 3.9.3

The first macOS release, and Linux installers built with every release. Both are now produced
automatically alongside the Windows one, so the three platforms stay on the same version. Verified
on Apple Silicon: the macOS build launches and runs the optimizer.

## 3.9.2

Organizing a project no longer throws away its calibration. Calibration remembered a light by
where the file was, and organizing a project moves lights — so an Organize made every frame in the
affected project look uncalibrated, and the ones in complete groups were silently calibrated again
from scratch. Frames are now recognised by the time they were taken, so they survive the move.

A stacking group that cannot be stacked says so on screen instead of only in the log, and a
refused stack is reported rather than passing quietly. Every run is logged.

A project holding frames under more than one object name now asks what to do with them rather
than blocking silently.

The main window remembers its size, position and whether it was maximized.

## 3.9.1

Blink now opens with every frame accepted. A night is mostly keepers, so the work is naming the
exceptions — opening on a screen of undecided frames made the common case pressing A once per
frame. Frames you leave undecided are still left where they were.

The Import button says what is waiting instead of leaving you to guess whether there is
anything to bring in.

## 3.9.0

A new Blink step reviews a night's lights inside NightFront. Point it at a night and it decodes
each frame to a real preview — FITS or XISF, colour or mono — and steps through them at a proper 1:1
crop with a zoom ladder, so the obvious throwaways are named before anything is calibrated. Accepted
and rejected frames are committed together, accepts first, and undecided frames are left alone.

Nights arrive through an Inbox. A night is staged first and only released once the copy is
proven, so a failed import cannot lose frames, and importing the same night twice is caught.
Organize drains the Inbox into the projects tree.

NightFront now asks for 4 GB of memory. Until this release a packaged NightFront took whatever
a quarter of the machine's RAM happened to be — 2 GB on an 8 GB laptop, which the blink previews
can exhaust. This raises the floor on a small machine; on a large one it is a ceiling.

Also: the preview is average-pooled rather than max-pooled, which was destroying the picture; the
stretch is measured from the frame; flats are skipped before they are copied, not after; and a
source frame is never deleted before the copy has somewhere to live.

## 3.8.1

Frame now shows the target at a time it is actually up. It used to push the middle of the
planned night whatever the target was doing, so anything out of season appeared below the horizon
with Stellarium drawing the ground — a correct pointing that looked like a broken button. It now
picks the moment the target is highest during darkness, staying on the planned night whenever the
target is usable there and walking forward only when it is not. If there is no such moment it says
so rather than pushing nothing.

## 3.8.0

A target you already have can be framed in Stellarium and read back. Frame and Read frame are
now on every target card and mosaic panel on the Targets page, not just on discovery results, so an
existing target can be recomposed and its new centre and rotation written back.

⚠️ Moving a target that already has accepted frames clears its accepted counts, because a
different pointing is a different composition. A dialog says so before anything is changed, and it
is only shown when there is something to lose. Editing RA, Dec or rotation by hand goes through the
same rule. A round trip that does not really move anything changes nothing.

## 3.7.2

A reject button that appeared to need several clicks now works on the first. Ticking "Remember
these limits" on a frame review starts a rescan of the projects tree — over a minute on a NAS — and
the confirmation dialog covered the status line that would have said so, while silently swallowing
every click. The dialog now disables its button and says what it is waiting for.

## 3.7.1

A project card shows one filled button: the step that actually has work. It used to fill two,
and neither on the rule it claimed, so the row stopped answering the only question it exists to
answer.

Stack keeps a record again, and Organize adds a new master without removing the old one
beside it.

Packaging: the Windows installer's upgrade identity is now pinned rather than inherited, so a
future version cannot start installing beside the one you have instead of replacing it.

## 3.7.0

A project can be marked complete. Completion sweeps the project and the working drive by a
stated rule rather than a list, offers per-folder compression priced before anything is deleted,
purges rejected frames, keeps a record of what it did, and can be undone.

Frames are reviewed and rejected before they are accepted. A measurement pass with histograms
feeds a manual frame-selection review, frames whose star fit failed can be rejected outright, and
rejected frames leave every chart rather than just the one that flagged them.

A rejected frame says why. The ledger records the reason, where the frame went and which
direction of each measurement is bad, renders as a table in the stacking run report, and lets
frames be removed with the accepted count corrected honestly.

Every stacking run keeps a record, on both engines, with a scrollable report.

Also: WBPP's rigid transformations and all eleven interpolation kernels are exposed; one frame
missing no longer fails a whole group's measurement; and a single unmeasurable value no longer
silently discards an entire run record.

## 3.6.0

Master flat integration and stacking settings now belong to the imaging system, not the config.
Two configs sharing a rig share its settings. Renaming an imaging system carries its processing
link across, or says why it could not.

## 3.5.0

PixInsight stacking could produce nothing at all, silently. PSF Scale SNR weighting needs data
that only the local-normalization reference stage builds, so that stage could never satisfy it —
and PixInsight reported the refusal by doing nothing, with no error and a clean exit. Every filter's
reference failed, so nothing normalized and nothing integrated. Your choice is kept everywhere it
can work; only the stage that cannot substitutes, and it says so.

The stacking charts can be read. A refusal is now reported as its own failure, distinct from
"produced no integrated image".

## 3.4.2

Mixed exposure and gain are judged per filter, not per target. A project shooting Ha at 600 s
and L at 300 s was warned about a mixed pool that does not exist, and there was nothing to do about
it. The warning now names the block that is really mixed, and only for blocks that will integrate.

## 3.4.1

"Auto" is just "Auto". One panel named the same idea two different ways, and the flats picker's
selected value was a sentence rather than a word. What Auto stands for is already in each section's
supporting text.

## 3.4.0

Changing the working root no longer re-calibrates everything you have ever calibrated.
Calibration resume read only the current working root, so the day that setting moved, every
previously calibrated project queued again — hundreds of frames at about ten seconds each, with
nothing on screen connecting it to a setting changed the day before. It now reads every root the
machine has used. A working folder that is present but unreadable is reported instead of being read
as "nothing was ever calibrated".

## 3.3.0

Stacking has a run panel, from the moment the button is pressed, and Siril can plate solve.

Stacking settings are complete and grouped. Local Normalization, WBPP's grouping, drizzle fast
mode, frame weighting (both engines' full lists), and the parameters that were missing, in
collapsible groups. The default is WBPP's Best Quality preset, and the page states what defines it.
Only the settings you actually change are saved.

Intermediates live in the project's own working folder, are swept after a crash, stay put when
you ask to keep them, and the panel says how much room they cost.

## 3.2.0

Siril is a second calibration engine, beside PixInsight. Either can be driven to a master, and
a setting that one engine cannot honour is resolved for display and for the run by the same rules,
so the header, the body and the run record cannot disagree.

Accepting lights saves the config, exactly as pressing Save would.

## 3.1.1

The Discovery filter chips all fit on screen. The chip rows scrolled sideways with no scrollbar
and no cut edge on desktop, so chips past the visible width were simply absent. They wrap now.

Linux packaging is verified: the .deb installs, registers an applications-menu entry and launches
from it, and the AppImage runs across distributions.

## 3.1.0

Reading a frame back from Stellarium takes the frame's centre, not the object you clicked.
Framing is precisely the act of moving the view away from what you clicked — an off-centre
composition, a mosaic panel, a patch of nebulosity with nothing to click at all — so the two agreed
only until the feature was used for what it exists for.

## 3.0.8

Processing settings fields no longer discard what was typed into them. On a maximised window the
Apply button sat most of a screen away from the caret, there was no Enter to commit, and any
refresh reset the field to its stored value. Type, look away, and the edit was gone with nothing
said. Enter now commits, and an uncommitted edit is visible as one.

## 3.0.7

Every rig folder now sees the one calibration library they share. A config can be served by more
than one rig folder with a single library between them, and the folder without it reported "no
master dark in the library or the project" for every light — which reads as a missing master and was
really a library the matcher was never shown.

## 3.0.6

NightFront now records the crashes a released build used to lose. A packaged app has nowhere for
a stack trace to go, so a freeze left nothing on the machine saying what happened. Errors are now
written to a log file in your NightFront settings folder — the first thing to ask for when
reporting a freeze or a vanished window.

Accept lights shows its work, instead of producing a number with no account of it.

## 3.0.5

NightFront is packaged for Linux. A .deb and an AppImage, alongside the Windows installer.

Six ways a master build could go wrong are fixed, and the Library page is no longer buried
under its own list.

Also: file name matching follows the filesystem's own case rules rather than assuming Windows', and
the Processing screen no longer claims to be on Windows when it is not.

## 3.0.4

A readout mode can be given an alias, so a camera's modes can be named the way you know them.

A flat's bias can be chosen by hand when the matching rules refuse to pick one.

## 3.0.3

A duplicate master is found whatever it is named. Removal was gated on the file names matching,
and a master moved into the library is routinely renamed to avoid a collision — so proven duplicates
sat on the page reading plain "Remove", with no bulk button at all. Duplicates are now matched on
their contents, and a master present three times is flagged as such.

## 3.0.2

Calibration reads the .xisf, and the Library says when it holds one master twice.

## 3.0.1

Calibration runs in batches, so a long run is not one all-or-nothing attempt, and a deleted
frame can be redone.

The Calibrate button counts lights, not batches.

Calibrated frames are staged locally and then moved, because PixInsight cannot write to a
network path — which is where most projects trees live.

## 3.0.0

NightFront has a Processing tab. This config's projects, each light group's calibration match or
gap against the rig's master library, master building, session organising, and an unattended
PixInsight run. Sessions are flat nights; lights are organised under numbered session folders with
their matched masters copied in; the master library groups by camera settings, flags duplicates and
can be added to from anywhere on disk.

⚠️ Each exported target now runs once. Without this NINA re-ran Center and Rotate over the tail
of the night that the imaging loop could not fill, re-centering the last target repeatedly until
dawn. This needs NINA plugin 3.0.0.0 or newer.

Correction: Stellarium's Oculars rotation is the mirror of NINA's position angle, not the same
number. A frame read back at a non-zero rotation was previously written the wrong way round.

Target Discovery gains Abell clusters, Arp galaxies, Hickson groups and Harris globulars, plus
type and catalog filter chips.

## 2.7.0

Exposure plans can state a readout mode. It sits beside gain and offset, and is exported to
NINA as a mode switch once per target and again only when it changes. Leaving it unset behaves
exactly as before. Stating one needs NINA plugin 2.7.0.0 or newer.

The groundwork for processing: NightFront can read FITS and XISF headers, classify frames, scan
the projects tree, match a light group to the calibration masters it needs, and drive PixInsight to
build them.

## 2.6.0

Target Discovery. Eight catalogs, merged into one row per object carrying every name it is known
by, ranked for your rig, site and season — availability, framing fit and detectability — and
browsable behind a Search button. A promising object can be promoted straight onto the Targets page,
as a single target or as a mosaic at the grid it was ranked for.

Stellarium framing. Push a candidate to Stellarium to see it in this rig's frame, and read the
frame's centre back as a target.

⚠️ A generated plan whose inputs have changed is now removed from the chart rather than badged.
A Greedy or Dispatch plan costs seconds to reproduce; an edited plan is never removed, and the GA's
Pareto front is never removed. A note says what went and why.

The dwell floor is measured against the whole night, dusk to dawn, rather than whatever is left
of it — so planning part-way through a night no longer shortens every visit.

## 2.5.0

A Proportional planner. Each night's darkness is split equally between the targets that can use
it, with one block per target per night, and a target that sets early gets its share before it goes.

## 2.4.1

The "priority order changed — regenerate" badge can be cleared. Pressing Generate planned from
the previously cached order, stamped the plan with it honestly, and left the badge up — so the only
way out was to change something else first.

## 2.4.0

A Dispatch planner, emulating NINA's Target Scheduler. It scores the same way Target Scheduler
does, weights and all, and plots as another point on the same chart — an honest comparison rather
than a claim. Its rule weights are editable at the foot of Nightly Setup.

⚠️ At Target Scheduler's own default weights one target tends to take the whole night and a mosaic
finishes panel by panel. That is faithful; the lever is the target switch penalty.

## 2.3.0

Broadband targets get more than L. A filter change was charged the whole cost of an autofocus
against the single exposure that pays for it, so nothing could ever out-score the filter already in
the wheel and the first winner kept the sensor all night. The cost is now spread over the run the
change buys.

The GA's knee no longer vanishes off the chart.

## 2.2.0

⚠️ The optimizer now plans fewer, longer visits. A second half of its genome sets a minimum time
to stay on a target once it starts, so a night is no longer fragmented into short visits each
costing a slew and each landing away from transit. This is on by default and changes the plans the
optimizer produces.

The exported night's outer and inner gates no longer share an instant — a first attempt at
stopping the night's last target re-centering itself over and over. It was not enough on its own;
the full fix is in 3.0.0.

## 2.1.3

Every Targets card lines its name field and its year chart up with the others. Each card sized
itself around whatever its own buttons left over, so the charts were drawn at different positions
and could not be compared — which is the only reason they sit in a list.

## 2.1.2

A seasonal grant is bounded by how long the target is actually above the floor. A target up for
under four hours of a five-hour night could be granted the whole night. The floor decided whether a
target could be scheduled and never how much.

## 2.1.1

⚠️ Every exported exposure now asserts its filter. NINA's exposure item carries no filter — it
images through whatever is physically in the wheel — and the exporter suppressed a filter switch
whenever it believed the right one was already there. A meridian flip that changed the filter and
did not restore it meant narrowband exposures shot through L, with no error anywhere and the
collected ledger crediting them to the intended filter.

Filters can be reordered, which is what sets the wheel slot each exported switch names.

## 2.1.0

Custom horizons. NightFront reads NINA's own horizon file, so the trees, the roof and the
neighbour's garage are planned around per azimuth rather than by one flat altitude. A horizon in the
config supersedes the flat minimum outright, so a horizon below it opens that azimuth up.

The altitude floor moves from the site to the imaging system, where it belongs — a rig's spot in
a building is not a property of the site.

## 2.0.2

Filters rotate across the whole wheel. The anti-streak rule tracked only the most recent winner
and wiped its penalty the moment a rival won, so a four- or six-filter wheel ping-ponged its top two
and never reached the rest. Because a dither resets the counters, a two-filter cycle also cost a
dither before every other exposure. Each filter now carries its own debt, which decays rather than
resetting.

A filter stays put when a change would cost a focus run.

## 2.0.1

Five Editor fixes. A block's bars could be drawn outside its own outline and push the next block
into a spurious overlap on a plan nobody had touched; resize handles are drawn on every block rather
than only the selected one; and the right-click menu on a block is now the filter list itself,
staying open across toggles and keeping rejected filters visible with their reason.

## 2.0.0

A night can be planned three ways, and compared on one chart. Beside the optimizer there is now:

- The Editor — build a night by hand, dragging blocks on a Gantt chart.
- The Greedy planner — fill the night chronologically by a priority order you state on the
  Targets page, with mosaic panels balanced against each other automatically.

Every plan is scored on the same two axes as the optimizer's, plots as a point on the same chart,
and exports to NINA identically. A generated plan is already a block list, so it can be adjusted by
hand without converting anything.

Plans are kept as variants. Several plans sit side by side, each with its own undo history,
saved beside the config and restored with it.

An exported plan records who authored it, so an unattended replan can decline to discard a
hand-built night rather than silently replacing it.

The optimizer's first generation is seeded with one greedy plan, automatically, on every solve.

The NINA plugin ships as an MSI, under one licence.
