Stage metadata in Pew Pew Stage Factory PDFs

Every stage PDF carries its own metadata for indexing. The same values are written twice, once as an XMP packet and once as PDF DocInfo keys, so you can read whichever your toolchain handles more comfortably.

Namespace

XMP namespace
urn:ppsf:stage:1
XMP prefix
ppsf
DocInfo keys
PPSF-FieldName

Standard fields

XMP keyDocInfoTypeValue
dc:titleTitletextStage name
dc:creatorAuthortextDesigner name. Falls back to the account display name when the designer has not credited themselves
dc:descriptionSubjecttextOne-line summary, e.g. IDPA, 12 targets, 3 steel, 24 rounds, concealment
dc:identifiernot settextSame value as ppsf:pdfUrl

Stage fields

XMP serializes everything as text. The type column is how to parse it.

XMP keyDocInfoTypeValue
ppsf:stageIdPPSF-StageIdtext128 hex characters, stable for the life of the stage. Use it to recognise a stage you already hold
ppsf:titlePPSF-TitletextStage name. Same value as dc:title, repeated so the full field set sits in one namespace
ppsf:sourceVersionPPSF-SourceVersiontextRelease of Pew Pew Stage Factory that wrote the stage, e.g. 0.9.0
ppsf:rulesetPPSF-RulesettextGPA IDPA USPSA PCSL ICORE IPSC Other
ppsf:scoringPPSF-Scoringtextunlimited limited comstock
ppsf:targetsPPSF-TargetsintegerPaper target count
ppsf:nonThreatsPPSF-NonThreatsintegerNo-shoot target count. A real 0 means the stage puts up none; the field is absent when it could not be determined
ppsf:steelPPSF-SteelintegerSteel target count
ppsf:roundsPPSF-RoundsintegerMinimum round count
ppsf:shotsPerTargetPPSF-ShotsPerTargetintegerRequired shots per paper target
ppsf:stringsPPSF-StringsintegerString count, 0 for a single-string stage
ppsf:concealmentPPSF-Concealmentbooleantrue or false
ppsf:parSecondsPPSF-ParSecondsdecimalPar time in seconds, e.g. 13.59. Absent when the stage has no par time
ppsf:bayWidthYardsPPSF-BayWidthYardsdecimalBay width across the firing line, in yards
ppsf:bayLengthYardsPPSF-BayLengthYardsdecimalBay length downrange, in yards
ppsf:distanceMinYardsPPSF-DistanceMinYardsdecimalNearest engageable target, in yards. Absent when the stage has no shooting positions to measure from
ppsf:distanceMaxYardsPPSF-DistanceMaxYardsdecimalFarthest engageable target, in yards. Absent on the same terms
ppsf:impactAreaPPSF-ImpactAreatextdownrange or side. Read the note below before filtering on it
ppsf:impactAreaSourcePPSF-ImpactAreaSourcetextcomputed declared default
ppsf:designerPPSF-DesignertextSame value as dc:creator, repeated so the full filter set sits in one namespace
ppsf:is3dPPSF-Is3dbooleantrue for stages designed in 3D
ppsf:modifiedPPSF-ModifiedtextISO 8601 UTC, e.g. 2026-09-10T14:22:07Z
ppsf:diagramUrlPPSF-DiagramUrltextLink to the stage diagram on its own, without the sheet around it. Public, no login
ppsf:diagramFormatPPSF-DiagramFormattextjpg png or svg, so you know what ppsf:diagramUrl serves before you fetch it
ppsf:pdfUrlPPSF-PdfUrltextLink to this PDF. Public, no login
ppsf:stageUrlPPSF-StageUrltextLink to the stage page: preview, and an option to copy it into an account for editing. Public, no login to view
ppsf:startPositionPPSF-StartPositiontextWhere the shooter starts, as written by the designer
ppsf:scenarioPPSF-ScenariotextThe scenario description. Absent on stages that do not have one
ppsf:procedurePPSF-ProceduretextThe stage procedure, as written by the designer
ppsf:firearmConditionPPSF-FirearmConditiontextHow the firearm starts, e.g. loaded and holstered
ppsf:targetDesignationsPPSF-TargetDesignationstextHow the targets are labelled on the diagram, e.g. T1-T8 threats. NT1-NT2 no-shoots.
ppsf:specialConditionsPPSF-SpecialConditionstextAnything unusual about the stage: low ports, restricted movement
ppsf:muzzleSafePPSF-MuzzleSafetextMuzzle safe points and direction limits
ppsf:steelMustFallPPSF-SteelMustFallbooleantrue or false
ppsf:mandatoryReloadWaivedPPSF-MandatoryReloadWaivedbooleantrue or false
ppsf:notesPPSF-NotestextThe designer's own notes. Absent on stages that do not have any

Impact area

downrange means every shot in the stage is taken into the downrange backstop.

side means the stage may put rounds into a side boundary. Read it as may, not does: the field is deliberately conservative, and any stage we cannot positively confirm as downrange-only reports side.

So downrange is a claim, and side is the absence of one. Filtering for downrange-only stages will be accurate. Filtering for stages that definitely involve side impacts will not.

ppsf:impactAreaSource tells you where the value came from, if you want to weight it:

Description text

ppsf:startPosition, ppsf:scenario and ppsf:procedure carry the designer's own wording, exactly as it appears on the page.

One difference worth knowing if you display them: they arrive as a single line. Line breaks are collapsed to spaces, because a metadata value is single-line by nature. No words are lost, but the designer's paragraph breaks are not in there, so do not expect them to lay out the way they do on the PDF page itself.

ppsf:scenario is absent on stages that do not have one.

Notes

Par time is not universal

Par is specific to certain rulesets. Where it does not apply the field is absent rather than zero.

Bay dimensions mean slightly different things

For a stage designed in 3D they describe the bay the designer selected. For a 2D stage they describe the drawing area. Both are in yards; ppsf:is3d tells you which you are holding.

The diagram is a separate asset

ppsf:diagramUrl serves the stage drawing on its own, not a page of the PDF. A stage designed in 3D serves a raster of its printed diagram; a 2D stage serves SVG. Check ppsf:diagramFormat before fetching.

Six fields are ruleset specific

ppsf:firearmCondition, targetDesignations, specialConditions, muzzleSafe, steelMustFall and mandatoryReloadWaived are authored only on stages whose ruleset uses them, which today means GPA. They are absent everywhere else, so treat a missing one as "not applicable to this stage" rather than "the designer left it blank".

Distances are measured, not declared

Each target is measured to the nearest shooting position, and the two fields are the spread across the stage. They cover paper and steel alike. Both are absent, rather than zero, on a stage whose designer placed no shooting positions.

Both links are live

Neither is a snapshot. A stage edited after you index it will serve different content at the same URL, so compare ppsf:modified against what you stored to spot a revision.

Sample

Trimmed to a few fields. The full packet is a standard XMP wrapper.

<rdf:Description rdf:about=""
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:ppsf="urn:ppsf:stage:1">
  <dc:title><rdf:Alt><rdf:li xml:lang="x-default">Cold Open</rdf:li></rdf:Alt></dc:title>
  <dc:creator><rdf:Seq><rdf:li>R. Staph</rdf:li></rdf:Seq></dc:creator>
  <ppsf:stageId>3f9c1a...</ppsf:stageId>
  <ppsf:ruleset>GPA</ppsf:ruleset>
  <ppsf:rounds>18</ppsf:rounds>
  <ppsf:nonThreats>3</ppsf:nonThreats>
  <ppsf:distanceMinYards>3.8</ppsf:distanceMinYards>
  <ppsf:distanceMaxYards>16.7</ppsf:distanceMaxYards>
  <ppsf:diagramUrl>https://www.pewpewstagefactory.com/stagefiles/...</ppsf:diagramUrl>
  <ppsf:diagramFormat>jpg</ppsf:diagramFormat>
  <ppsf:bayWidthYards>9.3</ppsf:bayWidthYards>
  <ppsf:bayLengthYards>16.7</ppsf:bayLengthYards>
  <ppsf:impactArea>side</ppsf:impactArea>
  <ppsf:impactAreaSource>computed</ppsf:impactAreaSource>
  <ppsf:modified>2026-09-10T14:22:07Z</ppsf:modified>
</rdf:Description>

Changes

The version is carried at the end of the namespace so you can pin against it.

New fields are additive and stay in urn:ppsf:stage:1. Read the keys you know and ignore the rest, as you would with any other metadata namespace, and an addition cannot break you. urn:ppsf:stage:2 is reserved for a change that would: renaming a key, repurposing one, or changing the units or value set of a key you already read.

Fields that could not be determined for a stage are absent rather than empty or zero, so a key you find always carries a real value.

2026-09-22Added title, sourceVersion, nonThreats, shotsPerTarget, distanceMinYards, distanceMaxYards, diagramUrl, diagramFormat, notes, and the six ruleset-specific fields firearmCondition, targetDesignations, specialConditions, muzzleSafe, steelMustFall, mandatoryReloadWaived.
2026-09-10First published set.