# Bullet

The bullet in the load - its name, size, weight, length, build and tip - and the link that records where a picked bullet's values came from.

## Generated table

**Record:** profile · **Covers:** `ammo.bullet.name`, `ammo.bullet.diameter_in`, `ammo.bullet.weight_gr`, `ammo.bullet.length_in`, `ammo.bullet.construction`, `ammo.bullet.tip_length_in`, `ammo.bullet.catalog`

| Field | Type | Required | Limits in the schema | Solver reads | In a shared log |
|---|---|---|---|---|---|
| `ammo.bullet.catalog` | object | no | - | no | as stored |
| `ammo.bullet.catalog.g1_source` | string | no | - | no | removed for every reader |
| `ammo.bullet.catalog.g7_source` | string | no | - | no | removed for every reader |
| `ammo.bullet.catalog.generated` | string | yes, within | - | no | as stored |
| `ammo.bullet.catalog.id` | string | yes, within | - | no | as stored |
| `ammo.bullet.catalog.length_source` | string | no | - | no | removed for every reader |
| `ammo.bullet.construction` | `'lead-core'` or `'monolithic'` | no | - | yes | as stored |
| `ammo.bullet.diameter_in` | number | yes | min 0.1; max 1 | yes | as stored |
| `ammo.bullet.length_in` | number | yes | min 0.2; max 6 | yes | as stored |
| `ammo.bullet.name` | string | yes | - | no | as stored |
| `ammo.bullet.tip_length_in` | number | no | - | yes | as stored |
| `ammo.bullet.weight_gr` | number | yes | min 10; max 1500 | yes | as stored |

## What it holds

These fields describe the bullet in the load: what it is called, its diameter, weight and overall length, how it is built (lead core or solid copper), the length of any tip, and a small record of where a picked bullet's numbers came from. The size, weight and length are always present, and the name is always present but may be empty. The build, the tip and the catalog record are optional. The bullet's ballistic coefficients and drag are on the [drag](drag.md) page, its outline and caliper readings on the [bullet shape](bullet-shape.md) page, and the coefficient set that can be attached for the Spin model on the [spin](spin.md) page.

## What to know first

**Length is required for every model.** No length, or 0, is refused before any solve, whatever the model. Under Spin a bullet shorter than 2 calibers (0.75 in at 0.375 in) is flown as point mass, and the answer says "bullet shorter than 2 calibers".

**Which model reads what.** Standard and Physics use weight, diameter and length through the stability factor, which sets spin drift and jump. Classic's come-up and windage use none of the three. Only Spin reads the build and the tip. The name is read by no model.

**Size, weight, length, build and tip are a "shape" edit.** On a calibrated profile the profile screen and the connector default to resetting the calibration. The name is not compared, so a name edit asks nothing.

**The catalog link goes when a picked number is changed by hand.** Changing the diameter, weight, length or either BC removes it on save, on the profile screen and in the connector. Changing the name, build or tip keeps it.

**A length may be a placeholder.** A new profile made with the app's button starts at 1.24 in (`create_profile` requires the length), and guided setup swaps in an estimate while the length is flagged "not measured yet". Either looks real in a solve. Check the flag before trusting spin drift.

## The fields

**`ammo.bullet.name`** The bullet's name as the shooter reads it, such as "Example Match 350 gr". Required but may be empty: a new profile starts empty, and no screen refuses an empty name. A catalog pick writes the maker and the product name together. It is shown in the profile list, in shared logs and in Community, which groups shared logs by the catalog link when there is one and otherwise by this name. No solver reads it.

**`ammo.bullet.diameter_in`** Bullet diameter, in inches. Required. Example: 0.375.

**`ammo.bullet.weight_gr`** Bullet weight, in grains, as printed on the box or weighed. Required. The caliper step can record a measured weight, but that goes on the [bullet shape](bullet-shape.md) page and does not replace this one. Example: 350.

**`ammo.bullet.length_in`** Overall length, in inches, tip included. Required. A new profile made with the app's button starts as a 0.308 in, 175 gr bullet with a placeholder length of 1.24 in; `create_profile` has no placeholder, it requires the diameter, weight and length. Guided setup flags that length "not measured yet"; the flag goes when the length changes (typed in Load and bullet, brought by a catalog pick, or averaged in by the Calipers section). While the flag stands, saving the Load and bullet section with a new weight, diameter or build replaces the placeholder with an estimate from them and keeps the flag; since 2026-10-24 a line above Save says so before the save, with the estimate, the saved message repeats it and the box shows the new length. In Load and bullet the estimate, from the weight, diameter, build and tip, is offered when the box is left empty, marked "measure to confirm"; it is never filled in silently. Since 2026-10-24 Load and bullet also warns, under the length box, when the length is under 2.5 times the diameter ("This bullet is only 2.1 calibers long"); the length still saves. Example: 2.07.

**`ammo.bullet.construction`** How the bullet is built: `'lead-core'` (a jacket around a lead core, the default) or `'monolithic'` (solid copper or copper alloy, a longer bullet for its weight). Absent and `'lead-core'` mean the same to every reader, and a value the app does not know (from a newer app) is also read as lead core. The editor stores the key only when it is `'monolithic'` or already stored; `create_profile` leaves it out for lead core; `edit_profile` stores the value when it differs from what the profile reads as, so `'lead-core'` is written only over a stored `'monolithic'`.

**`ammo.bullet.tip_length_in`** Length of a plastic or aluminium tip, in inches, from the end of the tip to where the metal starts. Absent or 0 means no tip, and it must be shorter than the bullet. Blank in Load and bullet and 0 in the connector remove the key; a 0 typed in Load and bullet is stored as 0. Example: 0.2.

**`ammo.bullet.catalog`** Present only on a bullet picked from the catalog, and only while its numbers are the picked ones. It holds `ammo.bullet.catalog.id` (the catalog's id for the bullet, which Community groups by), `ammo.bullet.catalog.generated` (the date of the catalog build it was picked from, for example 2026-09-29) and up to three short codes naming where a value came from: `ammo.bullet.catalog.g1_source`, `ammo.bullet.catalog.g7_source` and `ammo.bullet.catalog.length_source`. A code is written only for a value the pick actually filled in. A pick does not fill every value: for some the picker shows a link to where the value is published, and the number is typed. A bullet with no value to fill gets its name, diameter and weight only, and no catalog record at all. A catalog record is never typed by hand.

**Limits, by writer.** App: the save check the profile screen's sections share. Connector: the input of `edit_profile` and `create_profile`. Conversion: the step every solve goes through first; a profile that fails it cannot be solved, and the connector refuses to save it. Solve: what the solver itself refuses.

| Field | App | Connector | Conversion | Solve |
|---|---|---|---|---|
| `ammo.bullet.diameter_in` | 0.1 to 1 | 0.1 to 1 | > 0 | > 0 |
| `ammo.bullet.weight_gr` | 10 to 1500 | 10 to 1500 | > 0 | > 0 |
| `ammo.bullet.length_in` | 0.2 to 6 | 0.2 to 6 | > 0 | > 0 |

Units are inches, grains and inches. The tip has no row because its upper bound is the bullet's own length: the app, the conversion and the solver refuse a tip that is negative or not shorter than the bullet, and the connector input is 0 to 5 in. The connector's `bullet_name` is at most 80 characters; the app has no limit on the name. Since 2026-10-15 the record schema holds the size, weight and length to the same ranges as the app and the connector (one table of bounds), so the server refuses a pushed profile outside them; a profile stored before that still loads and solves, and its next saved version must come back inside them. The schema refuses a build other than the two above, but the conversion does not: it reads an unknown build as lead core. In the Solve column a finite number above 0 is all that is asked.

## Who writes it

**The app.** The profile screen's Load and bullet section has the name, weight, diameter and construction as rows with the catalog pick above them, and the Length and Tip length boxes below; the Calipers section can fill the length and the tip from the average of up to three readings. The Model section's Spin block shows the saved bullet, with a link to Load and bullet. The Workbench's bullet panel edits a draft for its Spin charts and can save it as the profile's next version. Every section, and that panel, saves through one check and one edit function, which also removes the catalog record when a picked number was changed.

**The connector.** `edit_profile` takes `bullet_name`, `bullet_diameter_in`, `bullet_weight_gr`, `bullet_length_in`, `construction` and `tip_length_in`; `create_profile` takes the same, and needs the diameter, weight and length. Give only what changes. Setting the diameter, weight or length (or a BC) removes the catalog record. A tip of 0 removes the tip. A profile the solver would refuse is not saved, and the reply gives the solver's own words. Since 2026-10-24 `edit_profile` also refuses a length shorter than the stored outline's nose and boattail together, and says which field to change.

**Copies and restores.** Copying a shared profile writes the bullet as the shared view held it, which has only the catalog id and date; restoring a deleted profile writes it as the deleted version held it. Neither applies the limits above. The [origin](origin.md) and [versions](versions.md) pages describe the two.

**Never fitted.** No calibration writes these fields. The server does not set them.

## Who reads it

**The solver.** The conversion passes the diameter, weight and length always, the build when it is one of the two known values, and the tip when it is above 0. The stability factor comes from the weight, diameter, length, twist and velocity by Miller's rule, corrected for the air of the shot. Which options use it:

- [spinDrift](../options/spinDrift.md): with the Litz formula (Standard and Physics) the drift is a function of that stability factor, so weight, diameter and length move it. With the Classic formula the drift is a fraction of the come-up and the bullet does not enter. Under Spin the drift is flown instead.
- [aeroJump](../options/aeroJump.md): the same split. The Litz jump uses the stability factor and the length in calibers; the Classic jump is a fixed amount per mph.
- [dynamics](../options/dynamics.md): under the Spin model the build, the tip, the weight, diameter and length decide the bullet's inertia and its estimated coefficients, and one of the two ways the Spin model works out the crosswind jump ([aeroJumpSpin](../options/aeroJumpSpin.md)) uses the length in calibers. With a coefficient set attached, only the weight and diameter are still read there, and the length only by the second way of working out the crosswind jump; the build and the tip are not. A bullet under 2 calibers long has no estimate, and the solve runs as point mass with the reason in the answer. The tip is counted in the length but its mass is taken as nothing.
- [estimatorRules](../options/estimatorRules.md): the choice of typical values the estimate uses; it is handed the same bullet fields, and does nothing when a coefficient set is attached to the profile.
- [magnus](../options/magnus.md): under the Spin model, its "From bullet length" choice works the Magnus value out from the length and diameter (with the boattail length from the [bullet shape](bullet-shape.md) page) when the coefficients are estimated, and its diameter choice reads the diameter. The other choices do not read the bullet.

On a 1,500 yd shot with a 10 mph crosswind, an invented 0.375 in, 350 gr bullet at 3,000 fps from a 1:9 twist in standard air, a 2.0 in to 2.2 in length moved the Standard windage from 1.713 to 1.762 mil and left the Classic answer unchanged; the build moved the Spin windage by 0.025 mil and the Standard answer by none. The energy figure in an answer uses the weight under every model.

**The fitter.** A calibration solves each group through the same conversion, so these fields enter a fit only as above, and it first leaves out the groups shot with a different diameter, weight or length (see "Changing it"). It never changes them.

**The app.** The Calculator, range cards, the range log and the Workbench all go through the conversion. The profile list and shared logs show the name. The editor shows "From the bullet catalog" with the build date while the link stands, and "Edited by hand since it was picked: the catalog link is dropped when you save" once a picked number has been changed. The editor compares the boxes as typed, so the same number in another spelling counts as a change.

**The connector.** `check_profile` checks the stability the length gives with the twist (a stability below 1.0 is a problem, below 1.3 a check) and, when exactly one catalog bullet matches the profile's name at its diameter and weight, or exactly one has that diameter and weight at all, compares the BC and the length with the catalog's, where the catalog gives them. It finds that bullet by searching, not through the stored catalog record. `edit_profile` reports the bullet fields it changed.

**The server.** Community and the admins' pool group shared logs by bullet: the catalog id when the profile has one, else a key made from the typed name. The pool lists the name, diameter, weight and both BCs of each profile.

## Why it is stored

**Diameter, weight and length** give the stability that spin drift and jump need, and the Spin model's whole estimate. **Construction and tip** exist only for the Spin estimate: a solid copper bullet is longer for its weight and its mass sits differently, and a tip adds length without adding mass. **The name** is for people, and for Community's grouping when there is no catalog record. **The catalog record** says which catalog build a profile's numbers came from, so a later look-up, and the grouping by bullet, have something to go on. It is dropped on a hand edit because after one it no longer describes the profile's numbers.

## Changing it

An edit saves a new version; the [versions](versions.md) page explains that once for every field.

**The edit category is "shape", except the name.** A change to the diameter, weight, length, build or tip is a "shape" edit, which defaults to resetting the calibration. In the app a profile with anything a reset could remove gets the keep-or-reset question with "reset" already chosen. The connector refuses a shape edit on a calibrated profile until it is called with `calibration` set to keep or reset. An unset build and `'lead-core'` count as the same, and so do an unset tip and 0. A name edit is not compared and never asks. What a reset removes is on the [calibration](calibration.md) page. A changed diameter, weight, length, build, tip or outline value also drops a saved Spin trim, whatever is answered (see [spin](spin.md)).

**Older groups.** A fit uses a group only if the version it was shot with has the same diameter, weight and length as the profile's newest version (and the same twist, twist direction, sight height, zero range, zero air and zero slope). A group that fails is listed as left out, with the reason; it is not deleted, and a later version that restores the old value makes it usable again. So after a length edit with the calibration kept, the profile still carries its fitted curve, but a new fit finds none of the earlier groups usable. The name, the build, the tip and the catalog record are not compared, so groups shot before and after such a change are fitted together, all solved with the newest version's bullet. How a group records its version is on the [observation](../log/observation.md) page.

## Sharing and privacy

The name, diameter, weight, length, build and tip read as stored for every reader, on a share with one person, the public or the admins, and whether or not location and notes are hidden: hiding notes empties the notes, not the bullet's name. A reader of a shared log sees the catalog record's `ammo.bullet.catalog.id` and `ammo.bullet.catalog.generated`. The source codes `ammo.bullet.catalog.g1_source`, `ammo.bullet.catalog.g7_source` and `ammo.bullet.catalog.length_source` are removed for every reader. The name and the numbers let a reader tell which bullet it is and, with the twist on the [rifle](rifle.md) page, work out its stability. A copy of a shared profile arrives with the stripped record.

---

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