# Bullet shape

The bullet's outline (nose, boattail, base, meplat) and the raw caliper readings that guided setup keeps behind it.

## Generated table

**Record:** profile · **Covers:** `ammo.bullet.outline`, `ammo.bullet.measured`

| Field | Type | Required | Limits in the schema | Solver reads | In a shared log |
|---|---|---|---|---|---|
| `ammo.bullet.measured` | object | no | - | no | as stored |
| `ammo.bullet.measured.base_diameter_in` | array of number | no | at most 3 items | no | as stored |
| `ammo.bullet.measured.bearing_length_in` | array of number | no | at most 3 items | no | as stored |
| `ammo.bullet.measured.boattail_length_in` | array of number | no | at most 3 items | no | as stored |
| `ammo.bullet.measured.length_in` | array of number | no | at most 3 items | no | as stored |
| `ammo.bullet.measured.meplat_diameter_in` | array of number | no | at most 3 items | no | as stored |
| `ammo.bullet.measured.tip_length_in` | array of number | no | at most 3 items | no | as stored |
| `ammo.bullet.measured.weight_gr` | array of number | no | at most 3 items | no | as stored |
| `ammo.bullet.outline` | object | no | - | yes | as stored |
| `ammo.bullet.outline.band_diameter_in` | number | no | - | no | as stored |
| `ammo.bullet.outline.base_diameter_in` | number | no | - | no | as stored |
| `ammo.bullet.outline.boattail_length_in` | number | no | - | yes | as stored |
| `ammo.bullet.outline.meplat_diameter_in` | number | no | - | no | as stored |
| `ammo.bullet.outline.nose_length_in` | number | no | - | no | as stored |
| `ammo.bullet.outline.ogive_ratio` | number | no | - | no | as stored |

## What it holds

These fields describe the bullet's shape beyond its overall size: an outline (the nose, the tapered base called the boattail, the base and the tip of the nose) and the raw caliper readings that guided setup keeps behind some of those numbers. Both are optional, and a profile without them is complete. The outline is for two uses only: a starting drag shape for one kind of calibration fit, and the boattail length for one Magnus choice of the Spin model. The caliper readings are a record of what was measured and are read by no calculation. The bullet's name, size, weight, length, build and tip are on the [bullet](bullet.md) page.

## What to know first

**Only the boattail length can change a come-up.** It does so only under the Spin model with Magnus set to "From bullet length", on estimated coefficients, by a few thousandths of a mil to 2,000 yd. No other outline member and no caliper reading changes a come-up.

**The rest of the outline is for one drag-fit starting shape.** Calibrate's full fit can start from "Estimated from the bullet's outline". That needs the nose length, ogive ratio, boattail length, base diameter and meplat diameter. Calipers never fill the ogive ratio: type it in Load and bullet.

**The caliper readings are evidence, not inputs.** Nothing reads them but the screens that show them. Editing the outline in Load and bullet does not update them, so the two can disagree. The next caliper save writes the averages back over the outline numbers it derives.

**The connector cannot set or clear either one.** `edit_profile` has no input for them and an edit keeps what is stored. A new bullet length shorter than the nose and the boattail together is refused (since 2026-10-24), as the app refuses it.

**An outline edit almost never asks about the calibration.** Only a boattail change under the Spin model with "From bullet length" counts as a shape edit. Any other change is kept silently, including for a fit that started from the outline.

## The fields

**`ammo.bullet.outline`** The bullet's outline, in inches, as one object. All members are optional. Absent means no outline was entered, and the starting-shape choice above cannot then be chosen. Writers remove a member to clear it; they do not store an empty object.

**`ammo.bullet.outline.nose_length_in`** From the very tip to where the full diameter starts, in inches. Greater than 0. Example: 1.15.

**`ammo.bullet.outline.ogive_ratio`** How round the nose is, from 0 (a straight cone) to 1 (a classic round ogive); most long-range bullets are 0.5 to 0.8. It cannot be measured with calipers, and no guided-setup screen asks for it. Example: 0.7.

**`ammo.bullet.outline.boattail_length_in`** The length of the tapered part at the base, in inches. 0 means a flat base. Absent, 0, a negative number, or a number not shorter than the bullet all count as "no boattail" to the solver. Example: 0.3.

**`ammo.bullet.outline.base_diameter_in`** and **`ammo.bullet.outline.meplat_diameter_in`** The width across the very bottom of the base, and across the flat or open end at the nose (or across the end of the tip), in inches. A meplat of 0 is a point. Examples: 0.3 and 0.05.

**`ammo.bullet.outline.band_diameter_in`** For a bullet with a raised driving band only: the band's diameter, in inches, at least the bullet's diameter. Absent means no band. It is not part of what the starting shape requires.

**`ammo.bullet.measured`** The raw readings of guided setup's Calipers step: one list per measurement, up to three numbers each (three bullets), in the order typed. An absent list was not measured. Guided setup removes the whole object when every row is emptied.

**`ammo.bullet.measured.length_in`**, **`ammo.bullet.measured.tip_length_in`**, **`ammo.bullet.measured.boattail_length_in`** and **`ammo.bullet.measured.bearing_length_in`** Lengths, in inches: overall (tip to base), tip, boattail, and the straight full-diameter section (the bearing surface). The bearing length has no field of its own: it is kept only so that the nose length can be worked out. Example: `[1.9, 1.902, 1.898]`.

**`ammo.bullet.measured.base_diameter_in`** and **`ammo.bullet.measured.meplat_diameter_in`** Diameters, in inches, of the base and of the open tip.

**`ammo.bullet.measured.weight_gr`** Bullet weight on a scale, in grains. It is kept as a reading and never replaces the weight on the [bullet](bullet.md) page.

**Limits, by writer.** App: the save check the profile screen's sections share. Connector: the input of `edit_profile` and `create_profile`, which has none for these fields. Conversion: the step every solve goes through first. Solve: what the solver itself refuses.

| Field | App | Connector | Conversion | Solve |
|---|---|---|---|---|
| `ammo.bullet.outline.ogive_ratio` | 0 to 1 | not settable | n/a | n/a |

The other outline members are limited by how they fit the bullet, so no single bound is theirs. The app refuses a nose length of 0 or less, a negative boattail length, a base diameter of 0 or less or wider than the bullet, a meplat diameter that is negative or not narrower than the bullet, a band diameter narrower than the bullet, and a nose plus boattail longer than the bullet (equal passes, unless rounding in the sum puts it just over). The caliper readings must be numbers, at most three per measurement, none negative; the Calipers screen itself refuses a reading of 0 and says so. The conversion never refuses an outline or a reading: it passes the boattail length when it is above 0 and shorter than the bullet, and ignores everything else. Handed a boattail length that is negative or not shorter than the bullet, the solver itself refuses with an invalid-profile error; the conversion keeps that from happening. A fit's starting shape (see "Who reads it") is stricter than the app: it also needs the ogive ratio, and refuses a nose plus boattail equal to the bullet's length.

## Who writes it

**The app, in two places.** Load and bullet's "Bullet outline (optional)" block has the six outline boxes: nose length, ogive ratio, boattail length, base diameter, meplat diameter and band diameter ("blank = none"); blank removes the member. It has no box for the caliper readings and never touches them. The Calipers section has three boxes for each of seven measurements: overall length, tip length, boattail length, base diameter, bearing length, meplat diameter and weight. On a save it stores the readings, and from them fills the bullet's length and tip (the averages), the outline's boattail, base and meplat (the averages), and the outline's nose length (overall length minus bearing length minus boattail length, where the boattail is the average, or else the stored one, or else 0). The nose length is written only when both an overall length and a bearing length are read and the result is above 0; otherwise a nose already stored stays as it was. A boattail, base or meplat that was not read keeps its stored value. Emptying every row removes the readings but leaves the outline numbers they filled in. Since 2026-10-24 a Calipers save fills in only from the rows that changed (the nose follows any of its three rows), so a bullet length typed later in Load and bullet stays when another reading is touched.

The Workbench's bullet panel has boxes for the nose, boattail, base and meplat; they redraw the charts as a draft, and the panel's Save writes the draft as the profile's next version through the same check every section uses.

**The connector.** No tool writes either field. An edit that changes anything else saves the outline and the readings exactly as they were; a new bullet length is not checked against them.

**Copies and restores.** Copying a shared profile writes both fields as the sharer's record held them, and restoring a deleted profile writes them as the deleted version held them; neither applies the limits above. The [origin](origin.md) and [versions](versions.md) pages describe the two.

**Never fitted.** No calibration writes either field, and the server does not set them.

## Who reads it

**The solver.** The conversion from the stored profile passes on one number, the boattail length, when it is above 0 and shorter than the bullet. No other outline member and no reading is read. The boattail length is used by one choice only, and only under the Spin model ([dynamics](../options/dynamics.md) set to the modified point-mass flight): with [magnus](../options/magnus.md) set to "From bullet length" and the coefficients estimated, the Magnus value is worked out from the bullet's length and boattail length in calibers, and a bullet without a usable boattail length is treated as having none. A longer boattail raises the Magnus value slightly. In a run for this page, a 0.375 in, 350 gr bullet 1.9 in long at 3,048 fps from a 1:10 twist, 2,000 yd, standard air, calm, came up 0.004 mil lower with a 0.6 in boattail than with none. Under every other Magnus choice, with a coefficient set attached to the profile, and under the other models, the boattail length is ignored.

**The fitter.** The full calibration fit can start from a drag shape estimated from the outline, instead of the standard shape. It needs a nose length above 0, an ogive ratio from 0 to 1, a boattail length of 0 or more, a base diameter above 0 and no wider than the bullet, a meplat diameter of 0 or more and narrower than the bullet, and a nose plus boattail shorter than the bullet. A band diameter is used when given (at least the bullet's diameter) and otherwise the body diameter. If any is missing the Calibrate screen lists the choice greyed out with a note naming the first missing item, and the connector's `calibrate_profile` with `prior: 'outline'` answers that the estimated shape needs the bullet outline, naming the first missing item. A saved fit records that the outline was its starting shape; later, the guide for reviewing groups and the Workbench's fits rebuild that shape from the outline as it is now, and if the outline is no longer complete they use no shape. The readings are not read by the fitter.

**The app.** Load and bullet shows the outline boxes. The Calibrate screen lets you choose "Estimated from the bullet's outline" when the outline is complete. The Workbench draws the bullet to scale from the nose, boattail, base and meplat and, when no nose length is given, draws the nose as a guess and says so. The Calipers section lists each measurement with its readings, average and spread; a reader of a shared log sees the same section, read-only, under its Profile tab. The printable worksheet has the blank three-column table and does not print stored readings.

**The connector.** Only `calibrate_profile`, as above, and every tool that returns a whole profile, which shows both fields. `check_profile` and `explain_dope` have no finding about them. Every tool that solves reads the boattail length through the conversion.

**The server.** Nothing reads them beyond storing and sharing them.

## Why it is stored

**The outline** exists because a drag curve for a new bullet has to start from some shape, and the standard one is a guess for a bullet that is not like the standard. An outline lets the fit start nearer the bullet's real shape in the speeds no group reached. It is optional so a shooter without calipers loses nothing. The boattail length is read by the solver for the one Magnus choice that depends on it.

**The caliper readings** are kept so that the averages written into the bullet and the outline have their evidence next to them: the spread shows whether three bullets agreed, and a later reader can see how a number was measured. The bearing length and the weight have no field of their own and exist only as readings.

## Changing it

An edit saves a new version and each logged group keeps the version it was shot with; the [versions](versions.md) page explains that once for every field.

**The edit category is "shape" for one case, and nothing otherwise.** The profile screen's sections pass the boattail length to the keep-or-reset check only when the model is Spin (or Custom with the Spin dynamics) and Magnus is "From bullet length". A change of the boattail length then counts as a shape edit (0 and blank are the same here), and the default is to reset the calibration. Any other outline change, a change of the readings themselves and a boattail change under another model count as nothing: no question is asked and the calibration is kept. A Calipers save can still ask, because it also writes the bullet's length and tip from the readings, and those are shape edits described on the [bullet](bullet.md) page. The connector never passes the boattail length, and has no input for it anyway. What a reset removes is on the [calibration](calibration.md) page. A changed outline value (nose, boattail, base or meplat) asks nothing, but it drops a saved Spin trim, and the save says so (see [spin](spin.md)).

**Older groups.** A fit is always of the profile's newest version, and which groups it may use is decided from the bullet's size, weight and length, the twist, the sight height and the zero. The outline and the readings are not compared, so changing them never leaves a logged group out of a fit. A Calipers save that changes the bullet's length does: an average that differs from the stored length, even in the fourth decimal, makes every earlier group unusable, by the rule on the [bullet](bullet.md) page. How a group records its version is on the [observation](../log/observation.md) page.

## Sharing and privacy

Every field on this page reads "as stored": a reader of a shared log sees the outline and the readings exactly as the owner does, on a share with one person, with the public or with the admins, and whether or not location and notes are hidden. They are numbers of the bullet, with no place, date or name. The readings can show how many bullets were measured and how closely they agreed, and the outline reveals the shape of a bullet that may not be in any catalog.

---

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