---
title: secondmouseau/swiftpmx
framework: Swift Package Catalog
role: article
path: packages/secondmouseau/swiftpmx
---

# secondmouseau/swiftpmx

📖 **Documentation:** <https://secondmouseau.github.io/SwiftPMX/> · **Changelog:** [docs/CHANGELOG.md](docs/CHANGELOG.md)

## Install

```swift // Package.swift dependencies: [     .package(url: "https://github.com/SecondMouseAU/SwiftPMX.git", from: "1.0.0"), ], // target: .target(name: "YourTarget", dependencies: [.product(name: "SwiftPMX", package: "SwiftPMX")]), ```

## Use

```swift import SwiftPMX

let mesh = try PMX.read(contentsOf: url)   // right-handed, welded, degenerate faces dropped print(mesh.vertexCount, mesh.triangleCount) for t in 0..<mesh.triangleCount {     let i = t * 3     let (a, b, c) = (mesh.indices[i], mesh.indices[i + 1], mesh.indices[i + 2])     // mesh.positions[Int(a)] ... } ```

### Options

Everything is configurable via `PMX.Options`:

```swift var opts = PMX.Options() opts.convertToRightHanded = true   // negate Z + reverse winding (MMD is LH/Y-up). Default true. opts.weldEpsilon = 1e-4            // merge seam-duplicated vertices; nil keeps PMX indexing. Default 1e-4. opts.dropDegenerate = true         // drop zero-area edge/point-draw faces. Default true. opts.scale = 1.0                   // MMD models are ~8 units ≈ 1 m; scale for real-world units. let raw = try PMX.read(contentsOf: url, options: opts) ```

`PMX.looksLikePMX(data)` sniffs the `"PMX "` signature if you need to detect the format.

### Submeshes

`mesh.submeshes` gives one `PMX.Submesh` per material — a contiguous `(indexOffset, indexCount)` run into `mesh.indices`, in file order, plus that material's `materialIndex`. This is the material section's own segmentation of the face buffer, recovered without decoding a single name: useful for isolating one part (say, the carbody skin) out of a whole-model PMX.

```swift for sub in mesh.submeshes {     let partIndices = mesh.indices[sub.indexOffset ..< sub.indexOffset + sub.indexCount]     // build a standalone Mesh from partIndices + mesh.positions ... } ```

It's empty if the material section can't be read (e.g. a truncated buffer) — the geometry above is unaffected either way.

## Scope

SwiftPMX is a **geometry reader**. It reads material *index ranges* for submeshing but not material properties (colours, textures, names), and it does not load rig/animation data or write any format. It is intended as the front-end that turns a PMX model into a plain indexed mesh you can feed into your own pipeline (rendering, CAD reconstruction, conversion, …).

## License

MIT. The reference byte layout (oguna/MMDFormats) is CC0.

## Package Metadata

Repository: secondmouseau/swiftpmx

Default branch: main

README: README.md
