AOS REVIVALMenuJoin Discord
Creator handbook / Open format

Weapon package
format

The BattleSpades Weapon Package (.bswp) is an open, versioned format for custom weapons and cosmetics. One file carries the voxel parts, hand-grip bones and attachment points, sight or scope, first- and third-person hold, keyframe animations and timed sounds. Anyone may build tools and clients that read or write it.

At a glance

  • Format id battlespades.weapon-package, current version 1.0.0 (semantic versioning), media type application/vnd.battlespades.weapon-package+zip.
  • A ZIP (or an unpacked folder) with manifest.json at the root and files under models/, sounds/, textures/ and previews/. Every file is listed with its SHA-256 and size.
  • Packages are cosmetic. Damage, spread, ammunition, reload time and hitboxes always come from the server.
  • Stock weapons can be exported as packages that reference the original assets instead of copying them, and reproduce stock hold, sight, muzzle flash and sound cues exactly.
  • Nothing in a package runs code. Scripts are not part of the format.

Manifest example

Coordinates of bones and attachment points use the part’s KV6 voxel space: X across, Y toward the muzzle, Z down. Hold transforms use the game’s tool space: the same numbers as the original initial_position, arms_position_offset and view_model_size.

{
  "$schema": "https://www.aosplay.net/schemas/bswp-1.schema.json",
  "format": "battlespades.weapon-package",
  "format_version": "1.0.0",
  "kind": "weapon",
  "id": "yourname.copperhead-rifle",
  "version": "1.0.0",
  "name": "Copperhead Rifle",
  "authors": [
    {
      "name": "Your name"
    }
  ],
  "license": "CC-BY-4.0",
  "target": {
    "tool_id": 60,
    "tool": "ASSAULT_RIFLE",
    "base_template": "assaultrifle"
  },
  "compatibility": {
    "protocol": 168,
    "requires": [
      "sounds.custom",
      "skeleton.points"
    ],
    "fallback": "retail"
  },
  "files": [
    {
      "path": "models/body.kv6",
      "sha256": "…",
      "bytes": 4872,
      "media_type": "model/x-kv6"
    },
    {
      "path": "sounds/bolt-rack.ogg",
      "sha256": "…",
      "bytes": 18211,
      "media_type": "audio/ogg"
    }
  ],
  "models": [
    {
      "id": "body",
      "file": "models/body.kv6",
      "role": "body",
      "views": [
        "first_person",
        "third_person"
      ],
      "authored_offset": {
        "first_person": [
          0,
          0,
          0
        ],
        "third_person": [
          10,
          -26,
          4
        ]
      },
      "team_color": true
    },
    {
      "id": "sight",
      "ref": "retail:kv6/assaultRifle_sight.kv6",
      "role": "sight",
      "views": [
        "sight"
      ]
    }
  ],
  "skeleton": {
    "space": "kv6",
    "points": [
      {
        "id": "grip.right",
        "type": "hand_grip",
        "hand": "right",
        "part": "body",
        "position": [
          2,
          15,
          9.5
        ]
      },
      {
        "id": "muzzle",
        "type": "muzzle",
        "part": "body",
        "position": [
          2,
          51.5,
          5
        ]
      }
    ]
  },
  "sight": {
    "mode": "retail",
    "sight_position": [
      0,
      -0.07,
      0
    ],
    "zoom_factor": 1
  },
  "hold": {
    "first_person": {
      "initial_position": [
        0,
        0.2,
        0
      ],
      "initial_orientation": [
        0,
        0,
        0
      ],
      "arms_position_offset": [
        -0.1,
        -0.08,
        -0.1
      ],
      "view_model_size": 0.035
    },
    "third_person": {
      "model_size": 0.04,
      "initial_position": [
        0,
        0,
        0
      ],
      "initial_orientation": [
        0,
        0,
        0
      ]
    }
  },
  "animations": [
    {
      "id": "reload",
      "event": "reload",
      "duration": 0.9,
      "base": "retail",
      "tracks": [
        {
          "target": "weapon",
          "property": "rotation",
          "keys": [
            {
              "t": 0,
              "value": [
                0,
                0,
                0
              ]
            },
            {
              "t": 0.3,
              "value": [
                -25,
                0,
                10
              ],
              "ease": "ease_out"
            },
            {
              "t": 0.9,
              "value": [
                0,
                0,
                0
              ]
            }
          ]
        }
      ],
      "cues": [
        {
          "t": 0.45,
          "sounds": [
            "bolt-rack"
          ],
          "gain": 0.9,
          "pitch": [
            -0.5,
            0.5
          ]
        }
      ]
    }
  ],
  "sounds": [
    {
      "id": "bolt-rack",
      "file": "sounds/bolt-rack.ogg",
      "duration_ms": 420,
      "channels": 1
    }
  ]
}

Bones and attachment points

hand_grip

grip.right

Right hand grip (trigger hand).

hand_grip

grip.left

Left hand grip (support hand).

muzzle

muzzle

Muzzle (flash, tracer origin).

sight

sight.rear

Rear sight / eye line.

sight

sight.front

Front sight post.

ejection

eject

Ejection port (casings).

socket

socket.scope

Scope rail. Accepts scope.

socket

socket.barrel

Barrel attachment. Accepts barrel.

socket

socket.grip

Underbarrel grip. Accepts grip, underbarrel.

socket

socket.magazine

Magazine well. Accepts magazine.

Any other id is allowed. Points record where they came from (authored, retail or estimated). Model parts can attach to a socket; scopes, suppressors and grips become their own KV6 parts.

Animation and sound timeline

Each clip is tied to a game event. Keyframe tracks add to the hold pose, and the original recoil or swing can be kept underneath. Cues play sound variants and emit effects at exact times after the event. Clip timing only changes how the weapon looks and sounds; the server still decides fire rate and reload time.

event

pullout

Tool raised (retail: 0.5 s, switch sound)

event

fire

Each accepted primary shot

event

fire_loop

Sustained automatic fire loop (loop: true)

event

fire_tail

Played once when the fire loop stops

event

dry_fire

Trigger pulled on an empty magazine

event

reload

One reload cycle (per shell for clip_reload weapons)

event

reload_end

The final reload cycle completed

event

zoom_in

Aim / scope in

event

zoom_out

Aim / scope out

event

melee

Melee swing (hit or miss)

event

melee_hit_block

Melee hit a block

event

melee_hit_player

Melee hit a player

event

throw_pin

Throwable: hold started

event

throw_release

Throwable: released

event

spin_loop

Barrel spin loop (minigun)

event

tool_loop_start

Sustained tool started

event

tool_loop

Sustained tool loop

event

tool_loop_stop

Sustained tool stopped

event

tool_extra

Tool-specific extra cue

event

inspect

Inspect / idle flourish (optional)

Cue options: sounds (variants), pick (cycle or random), gain 0–2 relative to the stock level, pitch as a random range in semitones, positional, and emit (muzzle_flash, eject_casing, tracer, camera_kick or custom.*). Custom events use the custom. prefix.

Sounds

  • Ogg Vorbis/Opus or WAV, 8–96 kHz, mono or stereo. Use mono for weapon sounds: the game can only position mono sounds in the world.
  • Up to 10 s per sound (20 s for loops) and 1024 KB. Community submissions allow 24 custom sounds of up to 512 KB each and 2 MB in total.
  • Skin Studio measures peak and RMS level and suggests a gain toward about −18 dBFS RMS with peaks below −1 dBFS.
  • Reviewers listen to every submitted sound before approval. Hate speech, copyrighted music and deafening or clipped audio are rejected.

Versioning and compatibility

  1. Readers accept every 1.x manifest. A newer minor version loads with a warning, and features the reader does not know are ignored.
  2. Unknown fields are always kept when a package is opened and saved again. Vendor data goes under extensions with a namespaced key.
  3. New roles, events or capabilities are warnings, so only the unknown entry is skipped. A different major version is refused.
  4. compatibility.requires lists capabilities (models.multipart, models.custom_geometry, skeleton.points, sight.iron, sight.overlay, animation.keyframes, sounds.custom, sounds.timeline, muzzle_flash.custom, colors.team). A client missing one uses fallback: stock visuals, or not equipping the item.
  5. Older data upgrades through ordered migrations. The client’s previous weapon-presentation.json sight and sound tuning already converts to packages.

Stock firearm defaults

Generated from the native client’s recovered retail tables (retail_tool_hold, muzzle flash tables and weapon catalogue sound slots). A new package for a weapon starts from these values.

Toolidinitial_positionarms offsetview sizemodel sizeflash (view)reloadfire sound
Smg7(0, 0, 0)(0, 0, 0)0.050.065(0, 0.12, 0.5) ×0.51.25 ssmg_fire_loop
Minigun8(0, 0, 0)(0, 0, 0)0.050.065(0, -0.18, 2) ×0.752 sminigun_fire_single
Shotgun9(0, 0, 0)(0, 0, 0)0.050.065(-0.05, 0.12, 0.8) ×10.5 s / shellshotgunshoot
Shotgun210(0, 0.1, 0)(0, -0.1, 0)0.050.065(-0.05, 0.12, 0.8) ×11 s / shellshotgun_double_fire01
Pistol17(0, 0, 0)(0, 0, 0)0.050.065(-0.05, 0.12, 0.35) ×0.50.6 spistolshoot
Sniper18(0, 0.1, 0)(0, -0.1, 0)0.050.065(0, 0.12, 0.9) ×0.52 ssemishoot
Sniper219(0, 0.2, 0.1)(0, -0.2, -0.1)0.050.065(0, 0.12, 0.9) ×0.53 ssemi_weak_shoot
Tommygun35(0, 0.12, 0)(0, -0.12, 0)0.050.04329(0, 0.35, 1.2) ×0.52 stommygun_fire_loop
Snub Pistol36(0, 0.12, 0)(0, -0.12, 0)0.050.04329(0, 0.34, 0.5) ×0.50.75 s / shellsnub_fire
Classic Shotgun37(0, 0, 0)(0, 0, 0)0.050.065(-0.05, 0.12, 0.8) ×10.5 s / shellclassic_shotgunshoot
Classic Smg38(0, 0, 0)(0, 0, 0)0.050.065(0, 0.12, 0.5) ×0.51.25 sclassic_smg_fire_loop
Automatic Pistol53(-0.15, -0.05, 0.2)(0, 0.05, -0.05)0.0350.04(0, 0.12, 0.5) ×0.51 sAoS_soundfx_PLAYER_marksman_wpn_AUTOPISTOL_fire_loop_001
Assault Rifle60(0, 0.2, 0)(-0.1, -0.08, -0.1)0.0350.04(0, 0.12, 0.5) ×0.50.9 sAoS_soundfx_PLAYER_commando_wpn_ASSAULT_RIFLE_burst_fire_001-005
Light Machine Gun61(0, 0, 0.25)(0, 0, 0)0.0550.055(0, 0.12, 0.5) ×0.52 sAoS_soundfx_PLAYER_medic_wpn_LMG_loop_fire_001-002
Auto Shotgun62(0, 0.125, 0.13)(0, -0.1, -0.2)0.050.05(-0.05, 0.12, 0.8) ×0.62.5 sAoS_soundfx_PLAYER_specalist_wpn_AUTO_SHOTGUN_fire_001-005

Build with it

  • Skin Studio Advanced edits multi-part KV6 models, places bones with a 3D gizmo, previews the first- and third-person hold, and records keyframes and sound cues on a timeline. It imports and exports .bswp.
  • Validate your own tools against the JSON Schema. The reference TypeScript implementation (types, validator, migrations, reader and writer) is in src/lib/creator/package of the site repository, and the full specification is docs/WEAPON_PACKAGE_FORMAT.md.
  • The native BattleSpades client does not load packages yet. The specification includes a loader checklist for client developers.