Version 2.13 Release Notes

Version 2.13.0b0

  • Added scenarioMovingCamera, demonstrating two message-driven instrument camera platforms on a spacecraft in a circular Earth orbit with fixed prescribed attitude, visible Vizard camera frustums, and offline pose and visualization-wiring tests. This documents the moving-platform alternative for issue 1309 without adding a camera pose-input port.

  • Added ommHandling to read CCSDS Orbit Mean-Elements Message (OMM) general perturbations data in all four CelesTrak encodings (XML, JSON, CSV and KVN) and convert it to osculating orbital elements, lifting the five-digit catalog number limit of the TLE format. Includes scenarioOrbitFromOmm, a tutorial with bundled synthetic OMM data, spacecraft initialization, and orbit, altitude and speed figures.

  • Added scenarioThrusterArm, scenarioRoboticGrappling, and scenarioAerobrake, which demonstrate effector branching across the supported parent and child effector pairings.

  • Added scenarioBranchingVerification, which verifies the branched equations of motion against the integrator’s formal order and the impulse-momentum theorems.

  • Fixed C++ Module: constraintDynamicEffector applying its constraint force and torque while the device status message commanded it off, which previously suppressed only the output message.

  • Added Accuracy Comparison with GMAT and Orekit, a rough comparison of Basilisk orbit propagation against GMAT and Orekit for zonal and tesseral gravity up to degree and order 70, Sun and Moon third-body forces, solar radiation pressure, and exponential-atmosphere drag, in LEO, sun-synchronous, Molniya, GTO, and GEO orbits at several epochs, all in the ICRF axes. The exponential-atmosphere drag is compared with both tools, and the faceted drag and solar radiation pressure of a box spacecraft with a fixed and with a spinning attitude are compared with Orekit. The scripts that generate the GMAT and Orekit reference ephemerides, which also write a manifest with the case configuration, frame, tool versions and data checksums that is validated before the comparison, and that run the comparison, which also compare the altitude and density of the three exponential atmospheres at a set of probe points before any propagation, are in benchmarks/accuracyComparison, and the page explains how to reproduce the results.

  • Fixed the gravity effector extrapolating the planet orientation with a first-order update of the matrix elements, which is not orthonormal. The orientation is now advanced as a rotation about the planet angular velocity. Before, a SPICE-driven planet distorted even a point-mass field by a relative error of order \((\omega\,\Delta t)^2\) of the time since the planet message was written. The J20002Pfix and J20002Pfix_dot state properties of the gravity bodies were also stored transposed after each gravity evaluation, as \([NP]\) instead of the documented \([PN]\). They now hold \([PN]\) and \([\dot{PN}]\) as documented, which matters to code that reads these properties.

  • Added setExtrapolateScStateToStepMidpoint() and getExtrapolateScStateToStepMidpoint() to C++ Module: atmosphereBase (including C++ Module: msisAtmosphere, C++ Module: exponentialAtmosphere, and C++ Module: tabularAtmosphere), C++ Module: windBase, C++ Module: magneticFieldBase, C++ Module: eclipse, and C++ Module: solarFlux. These modules evaluate the spacecraft state of the previous step because they run before the spacecraft. When the extrapolation is enabled, the spacecraft position is advanced to the middle of the interval the next spacecraft update integrates. This removes a step-size dependent error. The planet (or sun) position and orientation are moved to the same epoch, so a translating planet does not bias the relative position. Stale messages are not extrapolated. The extrapolation is disabled by default and requires that the module is updated with the same task period as the spacecraft. The extrapolation starts once two spacecraft write times show an interval equal to the module update interval, so the first updates are not extrapolated, and during them the planet is moved back to the epoch of the spacecraft state to keep the relative geometry consistent. If the spacecraft is faster or slower than the module, nothing is extrapolated, and a warning is logged when a spacecraft message is found not to have been written at the previous module update. A mismatch is not always detectable, since a message written at the current module update is used as written, but a message that is not the output of the previous module update is never extrapolated. With several spacecraft the extrapolation is applied to all of them and to the planets, or to none.

  • Added setPlanetPolarRadius() and getPlanetPolarRadius() to C++ Module: atmosphereBase to compute the altitude, and the latitude in C++ Module: msisAtmosphere, above an oblate ellipsoid. The default remains a sphere.

  • Added setUseApparentSolarTime() and getUseApparentSolarTime() to C++ Module: msisAtmosphere to add the equation of time to the local solar time input of NRLMSISE-00. The default remains the mean solar time.

  • Added setUseApHistory() and getUseApHistory() to C++ Module: msisAtmosphere to make NRLMSISE-00 use the 3-hour Ap history of the space weather messages (switch 9 set to -1) instead of the daily Ap, which follows a geomagnetic storm more closely. The default remains the daily Ap.

  • Fixed PCPF2LLA() returning an altitude that was wrong for a position exactly at a pole of an oblate planet, where the equatorial component is zero.

  • Fixed C++ Module: msisAtmosphere, C++ Module: windBase, C++ Module: magneticFieldBase, and C++ Module: magneticFieldWMM converting the UTC epoch with mktime, which uses the time zone of the computer. On a computer in a time zone with daylight saving time, the local solar time of C++ Module: msisAtmosphere was one hour wrong after a simulation crossed a daylight saving transition. The epoch is now converted as UTC with the new architecture/utilities/utcTime.h.

  • Changed C++ Module: facetSRPDynamicEffector to use the solar flux SOLAR_FLUX_EARTH of 1361 W/m2 at 1 AU, as C++ Module: radiationPressure does, instead of 1368 W/m2. The facet SRP force is 0.5% smaller than before.

  • Normalized GaussMarkov secondary seeds to 32 bits so the same base seed produces identical raw engine sequences across standard libraries. This changes existing secondary sensor sequences on builds with a 64-bit std::minstd_rand::result_type (such as typical Linux/libstdc++ builds). Sensor noise samples and fault events are still not guaranteed to match across standard libraries because std::normal_distribution and std::uniform_real_distribution use implementation-defined algorithms.

  • Added prescribed rotation and translation solar array deployment sequence scenarioRotTransArrayDeployment to examples, with unequal deployment rates and heavier panel elements to show the spacecraft hub’s response.

  • Fixed GaussMarkov::deriveSecondarySeed() collisions for 64-bit input seeds by checking both 32-bit and 64-bit primary engine states while preserving existing primary seeding.

  • Fixed BSpline.approximate() ignoring final-acceleration components because of incorrect constraint-vector indexing (GitHub issue 1563).

  • Added scenarioHingedRigidBodyMuJoCo to demonstrate hinged solar-panel dynamics and an orbital burn using MuJoCo.

  • Added scenarioFlexiblePanelMuJoCo to demonstrate attitude control with a flexible, multi-segment solar panel using MuJoCo.

  • Added scenarioMomentumDumpingMuJoCo to demonstrate reaction-wheel momentum dumping with thrusters using MuJoCo.

  • Added Python Module: cmdTorqueBodyToTorqueAtSite, a Python module that converts a CmdTorqueBodyMsg into a TorqueAtSiteMsg with an optional constant body-to-site rotation.

  • GitHub issue 1573: Rust MsgReader ports now expose is_written, time_written (nanoseconds), and module_id for the subscribed source message.

  • Fixed out-of-bounds table reads in the C debyeLength() utility for altitudes from 2,000 km through 30,000 km (GitHub issue 1581).

  • Fixed out-of-bounds table reads for NaN altitude inputs to the C debyeLength() utility; these inputs now produce an error diagnostic and return NaN.

  • Fixed the vscmg case in benchmarks/dynamics/benchmark_state_effectors.py defining two of its four VSCMG gimbal frames with a left-handed gsHat0_B/gtHat0_B/ggHat_B axis set, which made InitializeSimulation() raise a BSK_ERROR.

  • Fixed C++ Module: groundLocation, C++ Module: stripLocation and C++ Module: groundMapping crossing the planet angular velocity, which was expressed in planet-fixed components, with inertial vectors. This affected v_BL_L, range_dot, az_dot and el_dot of the access messages when the planet spin axis was not aligned with the inertial 3-axis.

  • Fixed C++ Module: groundLocation and C++ Module: groundMapping ignoring the planet translational velocity from planetInMsg when computing v_BL_L, range_dot, az_dot and el_dot of the access messages.

  • Fixed C++ Module: groundMapping using an uninitialized planet-fixed to SEZ rotation matrix; it is now computed for each mapping point from its latitude and longitude.

  • Fixed C++ Module: stripLocation not populating the v_BL_L field of its access messages.

  • Fixed C++ Module: stripLocation omitting the rotation of the moving target’s local SEZ frame from v_BL_L, az_dot and el_dot; these outputs now agree with derivatives of the published geometry while the target moves along the strip.

  • Fixed C++ Module: stripLocation retaining its acquisition velocity after reaching the endpoint; the target now stops in the planet-fixed frame, keeping its strip state and access rate outputs consistent with the completed trajectory.

  • Fixed C++ Module: groundMapping not populating the rHat_LP_N field of its ground state messages.

  • Added a guard to C++ Module: groundLocation and C++ Module: groundMapping so that azimuth, az_dot and el_dot are set to zero, as in C++ Module: stripLocation, instead of being undefined when the horizontal distance to a spacecraft directly overhead of the location vanishes. All three modules account separately for distant-origin position quantization and local frame-transformation round-off, preserving resolvable near-overhead offsets.

  • Updated scenarioThrArmControl to use configuration-driven MuJoCo dynamics and flight software for thruster-arm regulation control.

  • Added scenarioThrArmTracking to demonstrate spacecraft position and attitude tracking with articulated thruster arms in MuJoCo.

  • Added the Python Module: arcLineHoldRef guidance module to generate inertial position, velocity, and acceleration references for an arc-to-line-to-hold maneuver.

  • Fixed keplerianOrbit eccentric and mean anomalies, signed flight-path angles, and rates after construction and set_a(); set_mu() now refreshes derived outputs and oe().rmag returns the current radius. Anomalies follow the orbitalMotion.f2E() and E2M() conventions without additional angle normalization.

  • Fixed rigid-body kinematics issues #1610 and #1611 across C, Python, Numba, and the corresponding Rust C bindings: conversions and composition preserve identity, small rotations, half-turns, and Euler singularities; PRV rate maps handle zero attitude and angle wrapping handles multiple revolutions. See Numerical scope and representation limits for representation limits.

  • Preserved Python and Numba list/tuple support and non-contiguous PRV array inputs. RigidBodyKinematicsNumba now exposes Python wrappers with Numba overloads instead of public dispatcher objects, avoiding deprecated list reflection; see RigidBodyKinematicsNumba for compiled-call requirements. Added Python/Numba MRPshadow() and extended the Rust attitude bindings.

  • Fixed C++ Module: spiceInterface GPS week and seconds of spiceTimeOutMsg, which were computed from TDB instead of atomic time, and its UTC Julian date, which was quantized to 1e-7 day, while preserving the SPICE convention of holding the Julian date at midnight during an inserted leap second.

  • Fixed C++ Module: spiceInterface GPSSeconds integer overflow after GPS week 3550, and held the GPS time outputs at zero with a warning when the simulation starts before the GPS epoch.

  • Fixed C++ Module: eclipse returning the occulted instead of the visible fraction of the solar disk during annular eclipses, where the disk of the occulting body lies inside the solar disk.

  • Fixed the same annular-eclipse formula in PlanetRadiationBase, used by C++ Module: albedo and C++ Module: earthRadiationModel, to return the visible fraction of the solar disk.

  • Fixed C++ Module: imuSensor DVFramePlatform, which turned the delta v accumulated since the start of the simulation into a spurious delta v whenever the spacecraft attitude changed between IMU calls. The delta v is now computed from TotalAccumDV_CN_N and the change of the sensor velocity relative to the center of mass.

  • Fixed C++ Module: imuSensor Reset(), which kept the state of the previous IMU call, so the first call after a reset in the middle of a simulation differenced the new state against the state from before the reset. This call now outputs a zero message.

  • Fixed MJSite stateOutMsg fields that a site does not provide, such as the center of mass states and the accumulated delta v, which were uninitialized and are now zero.

  • Fixed C++ Module: spacecraft nonConservativeAccelpntB_B and omegaDot_BN_B, which were uninitialized before the first integration step and, with pointMassTranslationalOnly, for the whole simulation.

  • Fixed the GCRS to J2000 frame bias in tleHandling.frame_bias().

  • Fixed makeDraftModule path handling and generated test imports, preserved the caller’s working directory, and protected existing module files from validation and generation failures by staging replacements.

  • makeDraftModule now generates smoke tests that check module execution and output message publication, including recording and write timestamps. Removed unused placeholder test parameters; add numerical payload assertions when implementing the module algorithm.

  • Documented the actual C and C++ template behavior with runnable Python examples, moved general RST instruction to Module RST Documentation, and added the standard documentation outline to generated module drafts.

  • Renamed dummy to updateCounter and dumVector to sampleConfigVector in C Module: cModuleTemplate and C++ Module: cppModuleTemplate to clarify runtime state versus configuration. Update assignments, logger field names, and C++ calls to setUpdateCounter(), getUpdateCounter(), setSampleConfigVector(), and getSampleConfigVector(); the old names are no longer available. Reset behavior and sample calculations are unchanged.

  • Simplified C Module: cModuleTemplate and C++ Module: cppModuleTemplate updates by removing a redundant temporary vector while retaining the linear-algebra examples, configuration interfaces, and simulation behavior.

  • C++ Module: fuelTank now retains Python thruster effectors and fuel-slosh particles supplied to addThrusterSet() and pushFuelSloshParticle(), preventing dangling connections when local Python references disappear. Null connections and dynamic-thruster connections without a tank model raise BasiliskError. Existing valid Python calls and C++ borrowed ownership are unchanged.

  • Fixed standalone Python input-message lifetimes in the spacecraft-input configuration methods of atmosphere, magnetic-field, wind, eclipse, location, charging, MSM, and formation-barycenter models, plus Eclipse.addPlanetToModel() and EphemerisConverter.addSpiceInputMsg(). Native readers now retain their sources until unsubscribe, replacement, or destruction, preserving existing Python call signatures. See Retaining Sources in Configuration Methods for the SWIG pattern and remaining borrowed-source requirements.

  • DynamicObject now owns its integrator through std::unique_ptr. Python setIntegrator() calls and integrator attribute access remain available, including scripts that explicitly disown a new integrator before installation; attribute assignment transfers ownership, and reinstalling the active integrator is safe. Custom C++ dynamics classes that assign raw pointers directly to integrator must use setIntegrator() instead. The changed C++ ownership contract increments the SDK extension ABI to version 3; compiled extensions must be rebuilt.

  • C++ callers can pass std::make_unique results or move an existing std::unique_ptr<StateVecIntegrator> into DynamicObject::setIntegrator(). The raw-pointer overload and Python ownership-transfer interface remain supported; rejected replacements are consumed without replacing the active integrator.

  • Dynamically allocated output messages in environment models, dynamics effectors, controllers, and device/visualization modules now use private std::unique_ptr storage. Public output-message vectors, Python indexing, subscriptions, and recorders remain available. This fixes missing cleanup in several modules and releases partially constructed output collections after allocation failures. See Vector of Output Messages for lifetime requirements; compiled extensions using the changed module layouts must be rebuilt for SDK extension ABI version 3.

  • Added the C++ addOwnedMessage() helper in architecture/messaging/ownedMessage.h to create an owned output message and its borrowed view together, rolling back that insertion on failure. See Vector of Input/Output Messages for usage and the limits of this guarantee during module configuration.

  • Extended standalone Python input-message retention to power and data storage, transmitters, downlink handling, mapping instruments, simple-antenna and albedo planet inputs, articulated facets, thruster attached-body inputs, small-body navigation thruster inputs, and Vizard camera configuration. Existing Python calls are unchanged; native readers and their copies retain each source until their subscriptions end. See Retaining Sources in Configuration Methods.

  • SPICE scratch buffers now clean up automatically, including when spacecraft-name validation or allocation fails. SpiceInterface.spiceBuffer and charBufferSize are now private; remove direct access to these internal fields from custom code. Standard simulation configuration is unchanged.

  • SpiceInterface.getCurrentTimeString() now raises BasiliskError when the output format would produce a buffer too short for SPICE, including five- and six-character format strings.

  • syncDynamicsIntegration() now retains Python secondary objects and removes native synchronization links when either object is destroyed. Surviving secondaries can integrate independently again, repeated connections are a no-op, and invalid null, self, nested, or competing-primary connections raise BasiliskError. Python calls must use the owning primary object; borrowed primary proxies are rejected before changing connections. See Lifetime of Synchronized Objects. Compiled extensions using DynamicObject must be rebuilt against the updated SDK extension ABI version 3 layouts.

  • Simulation worker records now use std::unique_ptr and own their std::thread by value. Shutdown joins workers before releasing their state or changing process assignments, including exception cleanup. Normal Python thread configuration and simulation APIs are unchanged; the internal threadList and threadContext ownership fields are no longer exposed in Python. C++ code accessing these fields must use the new owning types, and compiled extensions must be rebuilt against extension ABI version 3.

  • Added Advanced: Multithreaded Simulations, a tutorial on configuring independent processes for multiple worker threads, with a runnable example and guidance on assignment, reinitialization, and shutdown.

  • SimThreadExecution::requestStop() requests shutdown and wakes an idle worker once. killThread() remains a compatibility alias, and repeated stop requests no longer add semaphore releases. Pool shutdown continues to signal every worker before joining any of them.

  • Added Advanced: Naming Effector States and a runnable example explaining constructor-generated effector state names, object and Python-process lifetimes, and custom names for repeatable lookups across simulation builds.

  • Documented the existing hub and wheel mass-property accounting for all three C++ Module: reactionWheelStateEffector models, including center-of-mass and parallel-axis contributions and guidance for switching models without double-counting (issue 600).

  • Added the opt-in includeWheelMassProperties setting to C++ Module: reactionWheelStateEffector for automatic mass, center-of-mass, inertia, energy, and momentum accounting of balanced and simple-jitter wheels with axisymmetric inertia. The default preserves existing hub accounting (issue 600).

  • Added initialization checks for finite, positive spin inertia in every wheel model and for valid mass, transverse inertia, and imbalance inputs in fully coupled wheels, independently of the mass-accounting option.

  • Fixed the error message of atmosphericDrag() in orbitalMotion, which printed the position components with an index shifted by one and read past the end of the position vector.

  • Updated BSK-SDK Release Guide with beta and release workflows, the single-command --refresh-example version update, and nightly source verification.

  • Reduced native binding startup overhead, especially after macOS rebuilds, by grouping message, core FSW, core simulation, MuJoCo, and OpenCV bindings into separate libraries. Python imports, message recorders, optional build features, and per-module compilation are preserved.

  • Conan builds using Ninja or Makefile generators now export compile_commands.json by default for clangd and other language servers. Xcode and Visual Studio do not support export. Setting exportCompileCommands=False disables export and removes an existing database from the selected build directory.

  • constraintDynamicEffector now rejects unsupported parent types before computing forces and torques.

  • Incremental native builds now refresh Basilisk.getBuildInfo() when docs/source/bskVersion.txt changes, including in existing build trees with an old Conan-cached version.

  • Added a common native segment/view API for state, derivative, and diffusion buffers, preserving existing typed accessors and state/local-source diffusion ordering.

  • Added stable contiguous state, derivative, and diffusion storage allocated once after registration. DynParamManager retains the module-facing API; StateRegistry owns registration and native buffer access behind getStateRegistry().

  • Reworked fixed and adaptive Runge-Kutta bookkeeping to use preallocated flat buffers with a fixed synchronized dynamics group.

  • Euclidean drift candidates and adaptive truncation errors use single Eigen expressions, eliminating redundant buffer-copy passes.

  • State and derivative views bind directly to storage without repeated registry lookups; resets update finalized values in place.

  • State, derivative, and diffusion setters copy contiguous input directly while retaining support for strided matrix blocks.

  • Fixed Runge-Kutta can use a Euclidean buffer as its candidate buffer. Euler-Maruyama avoids diffusion packing and fuses one- and two-source Euclidean updates while preserving captured drift and local noise order.

  • Reaction wheels reuse derivative buffers sized during state registration.

  • Empty wheel and thruster effectors remain runnable without registering zero-sized state records.

  • Two-axis spinning-body default state and property names separate the axis and instance numbers with _ to prevent collisions with single-axis effectors. Use each effector’s public name fields when accessing these records.

  • Release builds use the toolchain’s default optimization flags without appending an -O2 override.

  • Fixed and adaptive Runge-Kutta permit compiler-dependent rounding differences, including fused multiply-add. Numerical compatibility is evaluated with accuracy tolerances.

  • Migrated all stochastic integrators to finalized indexed noise topology and preallocated workspaces. Noise counts can be declared through StateSpec or the deprecated registration-time StateData.setNumNoiseSources() compatibility API.

  • Shared stochastic sources preserve each state’s local increment order, including noncommutative update policies and Euclidean rounding.

  • Native StateBuffers, StateBufferKind, and StateBufferSegment types describe contiguous storage and borrowed scalar ranges.

  • Simplified stochastic buffer views and validation, and reduced RKMil’s packed arithmetic passes while retaining its inline Euclidean update path.

  • Borrowed VSCMG configuration elements retain their owning Python effector through both indexed collection access and getVSCMGAt().

  • Stochastic methods that only use Wiener increments no longer draw unused auxiliary Gaussian values. Seeded trajectories from these methods therefore differ from earlier releases.

  • Replaced MuJoCo’s specialized scene-wide qpos state with buffer-backed, manager-owned records associated with each joint, quaternion update policies, and fixed-layout validation during model recompilation.

  • Removed StateVector, ExtendedStateVector, standalone or subclassed StateData construction and arithmetic, and mutable error-control flags. Deprecated getStateReference() and getStateDerivReference() names remain as borrowed const-view aliases and will be removed after September 30, 2027. Use stateView() and derivativeView(), respectively.

  • Standalone DynParamManager users call finalizeStates() after state declarations and before integration. Later declarations reuse existing states by name; shapes and noise connections remain fixed. Setup errors propagate without Reset rollback.

  • Python keeps registerState(nRow, nCol, stateName) and exposes complete specifications through registerStateSpec(stateName, spec). Embedded managers and callback-created states retain their borrowed-lifetime contracts; callers keep the owning dynamics object or scene alive.

  • SWIG uses declaration-local ownership hooks and canonical imports. Both setIntegrator(method) and integrator = method transfer newly supplied integrators, including rejected replacements. Synchronized secondaries remain retained by Python, and native destruction detaches connections before later propagation.

  • Adaptive Runge-Kutta tolerances can be configured with the compatibility relTol and absTol properties or with setRelativeTolerance() and setAbsoluteTolerance().

  • C++ callers should replace direct DynamicObject::integrator reads with getIntegrator(), isDynamicsSynced reads with getIntegrationOwner() != nullptr, and mutable StateVecIntegrator::dynPtrs access with the read-only getDynamics() view.

  • C++ callers should configure MuJoCo attitude integration with setHighOrderAttitudeIntegration() before reset; Python retains the highOrderAttitudeIntegration property.

  • Allocation-regression tests intercept C++ and C allocation APIs on macOS and ELF platforms. MSVC validation is explicitly partial because it covers C++ operators and Eigen’s runtime allocation guard but cannot robustly interpose every CRT allocator.

  • Added an architecture guide and subsystem/API documentation covering state ownership, initialization, binding, RK workspaces, shared noise, MuJoCo policies, and Python compatibility. Matching resets initialize existing state buffers in place. Replacing an integrator destroys the old object, invalidating its borrowed pointers.

  • Fixed a buffer overflow in headingSuKF covariance updates.

  • Corrected horizonOpNav planet selection and added errors for unsupported planet IDs.

  • Fixed zero-noise operation in hingedRigidBodyMotorSensor.

  • Corrected the initial state dimension in scenarioSmallBodyNav. Invalid state and covariance or noise matrix dimensions in smallBodyNavEKF now raise BasiliskError in Python.

  • Fixed Ninja Multi-Config builds failing on C message interface dependencies and preserved configured C message sources across native clean operations.

  • Split release notes into version-series pages and a single archive for versions before 2.0.0, preserving historical release bookmarks and the manual release workflow.

  • Removed the obsolete StateEffector.receiveMotherSpacecraftData() method and its r_BP_P and dcm_BP fields following the removal of SpacecraftSystem. Hub and hinged-body calculations now use their configured body-frame geometry directly; prescribed-motion transformations remain supported.

  • Removed the unused prependSpacecraftNameToStates() hooks from state and gravity effectors and the obsolete GravityEffector.nameOfSpacecraftAttachedTo, StateEffector.nameOfSpacecraftAttachedTo, and StateEffector.parentSpacecraftName fields. These supported the retired SpacecraftSystem shared state manager; remove calls, overrides, and field assignments in custom effectors, and use the configured state and property names directly without adding a spacecraft prefix. Prescribed-motion attachments continue to use explicit property names assigned by addStateEffector() and no longer request an unused hub-attitude state. Vizard’s separate parentSpacecraftName field is unchanged.

  • Removed the deprecated spacecraftSystem module, including SpacecraftSystem, SpacecraftUnit, and DockingData, after its one-year deprecation period. Use C++ Module: spacecraft with C++ Module: constraintDynamicEffector to connect spacecraft; see scenarioConstrainedDynamics.

  • Group the example-script sidebar by its existing topic headings, with collapsible categories and automatic expansion for the current scenario.

  • Added optional viewing-angle and geometric specular-glare access limits to C++ Module: spacecraftLocation for optical observation planning (issue #864).

  • Corrected C++ Module: spacecraftLocation Sun and viewing directions to originate at the configured body-fixed location; the viewing angle is now reported without a Sun input (issue #864).

  • Reject NaN glare thresholds in C++ Module: spacecraftLocation during initialization so invalid settings cannot silently bypass glare rejection (issue #864).

  • Updated Usage Metrics with a daily updated total and trend plot of recorded requests for known BSK .whl files from all clients except identified mirrors, including coverage dates and counting limitations.

  • Fixed Visual Studio 2026 clean failures caused by an absolute path in the C-message target’s solution folder.

  • Wheel workflows now resolve stable Rust once per run and share the exact toolchain across core and opNav builds, preventing packaging failures caused by runner toolchain drift.