# Spin

The two stored fields of the Spin model, an optional coefficient set the account has been given and the shooter's own Spin trim, and where to find every other profile field that model reads.

## Generated table

**Record:** profile · **Covers:** `ammo.aero`, `ammo.aero_trim`

| Field | Type | Required | Limits in the schema | Solver reads | In a shared log |
|---|---|---|---|---|---|
| `ammo.aero` | object | no | - | yes | removed for every reader |
| `ammo.aero.set_id` | string | yes, within | - | yes | removed for every reader |
| `ammo.aero_trim` | object | no | - | yes | as stored |
| `ammo.aero_trim.lift` | number | yes, within | min 0.5; max 1.5 | yes | as stored |

## What it holds

The Spin model is a modified point-mass model that needs aerodynamic coefficients for the bullet. This page is about the two fields a profile has for that: `ammo.aero.set_id`, the name of a coefficient set that the account has been given (absent is the usual case, and means the solver estimates the coefficients from the bullet), and `ammo.aero_trim`, the shooter's own factor on the lift those coefficients give (absent means 1). The model's other inputs are ordinary profile fields with pages of their own; the table under "Who reads it" says which. The model itself is described on the [dynamics](../options/dynamics.md) page.

## What to know first

**Absent means an estimate, and that is normal.** Only an account that has been given coefficient sets can pick one. Everyone else's Spin profile has no set and is solved from estimated coefficients for the bullet. Do not suggest that a shooter should have one.

**An id this device cannot use falls back to the estimate.** The id stays stored, and only the Model section says so.

**A named set is used as it is.** Nothing checks it against the bullet's length or build, so editing the bullet does not clear it. Clear it in the Model section when the bullet changes.

**The id is never shared, and the connector can neither set nor clear it.** It is removed from every shared log and copy, and the connector shows it only to an account that has been given sets.

**The trim is the shooter's, and goes with the bullet.** `ammo.aero_trim` is a factor from 0.5 to 1.5 on the lift, from a fit on calm-air groups. A changed bullet drops it, whatever is answered.

## The fields

**`ammo.aero`** An optional object. Present only when the account chose a coefficient set. Absent means the solver estimates one from the bullet. The Model section removes the whole object to clear the choice; it never stores an empty one.

**`ammo.aero.set_id`** The name of the chosen set, as a piece of text with no further limit. The Model section writes it only from its list of sets the account holds, so a value typed by hand cannot get there. There is no unit, no sign and no example here on purpose: the id is private and never printed in documentation.

**`ammo.aero_trim`** An optional object, the shooter's own Spin trim. Present only after a trim was saved; absent means 1. It is not a private coefficient and is not an identifier: it is one number about this bullet in this rifle.

**`ammo.aero_trim.lift`** The factor on the Spin model's lift, a plain number from 0.5 to 1.5 with no unit. Above 1 the model gives the bullet more spin drift, below 1 less. A fit writes it rounded to three decimals (it may land on exactly 1). Absent object, and a value of exactly 1, mean the same: no trim. Example: 1.18.

The id has no limits: the app's save check, the connector and the conversion all accept any text (or none) for it, and the solve ignores one it cannot find. The trim has a range, held by the record schema and by the solver; no writer has a box for it, and the conversion passes any finite number on.

| Field | App | Connector | Conversion | Solve |
|---|---|---|---|---|
| `ammo.aero_trim.lift` | n/a | not settable | none | 0.5 to 1.5 |

The app writes the factor only from a fit, which keeps it inside the range; the connector writes it only through a fit as well, and `calibrate_profile` is the tool for that (it has no input that takes a factor). A profile outside the range, that reaches the solver by sync or a hand-made record, is refused by every solve under every model, with the message "the spin trim must be between 0.5 and 1.5".

## Who writes it

**The app, for the set id.** The profile screen's Model section shows, in its Spin block, a "Coefficient set" list to an account that has been given sets, and only while the profile's model runs the Spin dynamics. Nothing chooses a set for you: opening a profile never writes one. An account without sets sees no list; in the Spin block it sees a note when the profile names a set it cannot reach. Saving from the Model section keeps a stored id for such an account, and keeps it too when the model is later changed away from Spin.

Nothing else in the app writes the field. Guided setup does not know about it. A calibration fit keeps it: the fit's new version carries the profile's `ammo` as it was, and records which coefficients it used inside the calibration (see below).

**The app, for the trim.** A fit on calm-air groups writes it: the Workbench's Spin trim panel (a Save trim button once a fit exists, and a Remove trim button beside a saved one) and the Calibration section's Spin trim method on a Spin profile both save the next version with the factor and a calibration record of method `'spin_trim'` on top of the present one (see [calibration](calibration.md)). A fit never reports a factor outside 0.5 to 1.5: it holds it at the bound and gives the verdict `clamped`, and such a result can still be saved at the bound after "Save it anyway". The Workbench offers Save trim only while the profile is on the Spin model. Removing a trim saves a version without the field, and also drops its record from the head of the calibration. Nothing else in the app writes the field, and no box takes a typed factor.

**The connector, for the set id.** No tool has an input for it. `edit_profile` and `create_profile` do not use an input they do not know, and the reply names it ("I ignored: ..."), so an agent that sends an `aero_set_id` gets success for the rest of the edit and the stored id is unchanged. Sent alone, nothing is saved and the reply says "Nothing to change: I ignored" and the name. `create_profile` makes a profile without one.

**The connector, for the trim.** `calibrate_profile` with the method `spin_trim` runs the same fit as the app on the same groups (those marked as shot in calm air, and with `light_wind` those typed with 2 mph or less) and previews it for any link. A save needs the `profiles` scope and the preview's fingerprint, and a result that is not a clear fit needs `confirm`. With `remove` and `save` it removes a saved trim. It is refused on a profile that is not on the Spin model. `edit_profile` has no input for the factor, and it drops the trim when it changes the bullet, saying `spin trim dropped` in its line and `trim_dropped` in its details.

**Copies and restores.** A copy of a shared profile never carries the id, because the shared view it is made from has none. A copy keeps the sharer's fit record, which may say a set was used, while the copy itself is solved from the estimate (since 2026-10-24 the Calibrate history says the set is not held here and the estimate is used); restoring a deleted profile writes it back as the deleted version held it, trim included. A copy of a shared profile carries the sharer's trim, since a share shows it. The [origin](origin.md) and [versions](versions.md) pages describe the two.

**Never fitted, for the set.** No calibration chooses or changes a set. The server does not set either field.

## Who reads it

**The solver.** The conversion from the stored profile attaches the set named by `ammo.aero.set_id` when the caller holds it, and attaches nothing otherwise. The solve then uses the attached set or, when none is attached, the coefficients estimated from the bullet. Under the point-mass models the set is not flown.

| What | Result |
|---|---|
| Spin model, set attached | The set is flown. |
| Spin model, no id, or an id that is not held | The estimate is flown. |
| Spin model, estimate impossible (bullet under 2 calibers) | Point mass, with a reason in the answer. |
| Spin model, a trim other than 1 | The lift of the coefficients in use, attached or estimated, is multiplied by the factor, and that is flown. |
| Standard, Physics, Classic | The set and the trim are not used. |

A missing or zero bullet length is refused before any of this, under every model, with a message that the length must be greater than 0.

How the choice reaches the options, each linked from the page that has the math:

- [dynamics](../options/dynamics.md): decides whether the field is flown at all (only the Spin flight uses it), and holds the math of the trim.
- [estimatorRules](../options/estimatorRules.md): the choice of typical values the estimate uses. It does nothing when a set named by `ammo.aero.set_id` is in use.
- [magnus](../options/magnus.md): its "From bullet length" choice is applied only when no set is in use (`ammo.aero.set_id` absent or not held).
- [subsonicLift](../options/subsonicLift.md): its reduced choice is applied only when no set is in use (`ammo.aero.set_id` absent or not held).
- [yawRepose](../options/yawRepose.md): its automatic choice follows the coefficients in use, so it can differ between a profile with `ammo.aero.set_id` and one without.
- [dragTable](../options/dragTable.md): a set named by `ammo.aero.set_id` may bring its own drag, which then replaces the profile's drag model, BC and this choice.
- [aeroJumpSpin](../options/aeroJumpSpin.md): the Spin model's crosswind jump is computed from the coefficients in use, so `ammo.aero.set_id` changes it.

**The other profile fields the Spin model reads.** Each has its own page; this table only points.

| Field | Page | What the Spin model uses it for |
|---|---|---|
| Bullet diameter, weight, length, build and tip | [bullet](bullet.md) | The estimate's inertia and shape. With a set in use the flight reads only the weight and diameter; the length is read only by one choice of the crosswind jump option. A bullet under 2 calibers has no estimate. |
| Boattail length | [bullet shape](bullet-shape.md) | Only for the Magnus choice "From bullet length", on estimated coefficients. |
| Twist and twist direction | [rifle](rifle.md) | The spin rate and the direction of spin drift and jump. |
| Muzzle velocity | [velocity](velocity.md) | The start of the flight and the estimate. |
| The preset and six stored options | [model](model.md) | Which model runs, and the Magnus, estimator-rule, yaw and lift choices a Spin profile may store. |
| Ballistic coefficient and fitted drag | [drag](drag.md) | The drag the spin flight is flown through. A set in use may bring its own drag; the fitted correction still multiplies on top. |

**The trim, the conversion and the fitter.** The conversion passes a finite `ammo.aero_trim.lift` to the solver as it is, whatever the model, and the solver refuses a value outside 0.5 to 1.5 under every model (the trim itself is read only by the Spin dynamics). The drag, velocity and scope fits solve under the profile's model, so under Spin they fly the trim already saved. The trim's own fit always works against the untrimmed model, so a re-fit on a trimmed profile finds the absolute factor and not a change to it.

**The fitter.** The calibration solves under the profile's model, so under Spin it uses the set when it is attached and the estimate when not. A saved fit records which it was in the calibration's coefficient source: a set or an estimate. The record is described on the [calibration](calibration.md) page. The sets the fit used are the ones the device (or the connector) holds at that moment.

**The app.** The Model section's Spin block shows which coefficients a calm 1,000 yd solve used, in plain words. The Calculator's Spin note says only that the model ran as point mass when it did. The Calculator, the session screen and Calibrate re-solve whenever the held sets change. A profile named by a stored id with no set held gets the estimate everywhere, with no message outside the Model section.

**The connector.** Every connector tool that solves under a Spin model reads the sets of the acting account (through the same function), so the same profile gives the same answer on the phone and in the connector for an account that holds the set. For an account that does not, they estimate. Only `solve` reports which coefficients it used. On a Spin profile `check_profile` notes a set the account cannot use, and asks to check the length when a held set's bullet length differs from the profile's (since 2026-10-24); neither finding names the set.

## Why it is stored

A profile names a coefficient set and does not copy its numbers, because the set is not the shooter's data to hand on. Absent is the default so a shooter loses nothing without one.

## Changing it

Choosing, changing or clearing the set is a shape edit in the Model section: it is listed with the bullet, twist and sight height, and the default for a calibrated profile is to reset the calibration, because the fit was made under other coefficients. The question is asked only when the profile holds a calibration. The check works for any model, also when the set is not being used. What a reset removes is on the [calibration](calibration.md) page. The connector never changes the field, so it never asks.

**The trim goes with the bullet.** An edit that changes the bullet's weight, diameter, length, build, tip or any outline value drops `ammo.aero_trim` from the new version, in the app and (for weight, diameter, length, build and tip, the only bullet inputs it has) through `edit_profile`, whatever is answered to keep or reset: the factor was found for the old bullet. A profile whose only calibration is the trim is not asked at all, because there would be nothing left to keep; it is told in a plain line before the save, and the connector's line says `spin trim dropped`. Other edits ask as for any calibration (the trim counts as one): a changed twist, sight height, velocity or ballistic coefficient asks keep or reset, and a reset removes the trim with the rest. A changed model and a changed zero keep it; a changed set asks keep or reset with reset chosen first, and a reset removes the trim. A restored version brings back its own trim, and "Use this one again" on an older record carries that version's trim only when the bullet has not changed since.

**Older groups.** The rule that decides which logged groups a fit may use compares bullet size, weight and length, twist and its direction, sight height and the zero. It does not compare the coefficients, so changing the set never leaves a group out of a fit, and groups shot while another set was in use stay eligible. Each saved fit records the coefficients it used, so a mix is visible in the history. How a group records its profile version is on the [observation](../log/observation.md) page.

## Sharing and privacy

`ammo.aero` and `ammo.aero.set_id` read "removed for every reader": a shared log's reader never sees a set id, on a share with one person, with the public or with the admins, whether or not location and notes are hidden. The same is done to the id a calibration records for its coefficients; the kind (a set or an estimate) stays. A copy of a shared profile therefore starts with no set, and a suggestion sent back from a shared log carries no id either. The connector shows the stored id, and the ids in saved fits, only to an account that holds sets; to any other account the reply has them removed while the stored profile is unchanged. A reader of a shared log can still see that the profile uses the Spin model and, from a fit's record, whether it used a set or an estimate.

`ammo.aero_trim` and `ammo.aero_trim.lift` read "as stored": every reader of a shared log sees the factor, on every audience, as they see the rest of the calibration, and a copy of the profile starts with it. It is not location and not a coefficient. A reader learns that the owner trimmed the model's spin drift and by how much.

---

[All reference pages](../index.md)
