Global flags

Global flags can be placed before or after the subcommand. These are equivalent:

fascat --json inspect input.step
fascat inspect input.step --json
FlagShortDefaultDescription
--help-hShow help for the current command
--version-VShow version and exit
--verbose-vfalsePrint extra diagnostics to stderr; conversion warnings are not truncated
--quiet-qfalseSuppress non-essential output
--jsonfalseOutput results as JSON
--no-colorfalseDisable ANSI color output
--dry-run-nfalsePreview changes without applying them
--no-inputfalseReserved guard for non-interactive runs; commands must not prompt when set

-h / --help and -V / --version are invocation-wide controls. They work before or after subcommands and ignore other arguments.

--verbose expands diagnostic output on stderr. Conversion report warnings are normally capped after 10 messages; with --verbose, Fascat prints the full warning list. --quiet suppresses non-essential diagnostics even when --verbose is also set.

--no-input is reserved for non-interactive automation. Fascat does not prompt today, and future prompts must first check that stdin is a TTY and that --no-input is not set.

A convert --dry-run emits JSON with operation_diagnostics — planned operations each tagged exact, approximate, or metadata_only. With --pipeline it also adds pipeline_advisories warning about ordering issues (decimation before repair, tangents without UV0, AO baking without UV1, LOD generation before LOD0 optimization). In non-JSON mode, add --verbose to print those planned operation diagnostics to stderr; --quiet suppresses them.

Exit codes

CodeMeaning
0Command completed successfully
1Runtime failure, validation failure, missing file, unsupported backend, or failed conversion
2Usage error, invalid option combination, unsupported extension, or invalid argument value
130Interrupted by Ctrl-C / SIGINT

Errors are written to stderr in human mode. With --json, command errors are emitted as a single JSON object on stdout with the same command context plus an error string, while diagnostics remain on stderr.

JSON output schemas

All --json payloads are one JSON object on stdout. Optional sections are omitted when the matching flag or workflow is not used.

version

FieldTypeDescription
commandstringAlways version
versionstringFascat package version

inspect

FieldTypeDescription
commandstringAlways inspect
inputstringInput path, or - for stdin
profilestringInspection profile name
dry_runbooleanWhether execution was skipped
statsobjectAsset counts such as parts, occurrences, materials, vertices, and triangles
optionsobjectResolved profile options
rootobjectRoot node dictionary
partsarrayPart dictionaries
materialsarrayMaterial dictionaries
metadata_summaryobjectCompact metadata counts and keys
pmi_summaryobjectCompact PMI counts and types
reportobjectImport/conversion warnings and report steps
selectionobjectPresent when filters are used
errorstringPresent only on failure

convert

FieldTypeDescription
commandstringAlways convert
inputstring or arrayInput path, stdin marker, or multi-root input list
outputstringOutput path, or - for stdout
profilestringResolved conversion profile
dry_runbooleanWhether execution was skipped
operation_diagnosticsarrayDry-run operation entries with operation, level, and message
pipeline_advisoriesarrayDry-run pipeline-ordering warnings when --pipeline is used
statsobjectOutput asset counts on successful conversion
reportobjectReport warnings and workflow steps on successful conversion
errorstringPresent only on failure

validate

FieldTypeDescription
commandstringAlways validate
outputstringOutput path, or - for stdin
dry_runbooleanWhether execution was skipped
statsobjectValidation stats from the selected exporter validator
analysisobjectPresent with geometry quality checks, reports, or filters
runtime_browserobjectPresent with --runtime-browser
runtime_browser_previewobjectPresent with --runtime-browser-preview
visual_previewobjectPresent with --visual-preview
visual_diffobjectPresent with --visual-baseline
lod_previewobjectPresent with --lod-preview-dir
turntableobjectPresent with --turntable-dir; includes per-view previews and a diff summary with --turntable-baseline-dir
gatesobjectPresent when any gate threshold flag, --strict-geometry, or --profile is set; contains overall, failed, evaluated, and per-gate results entries with gate, status (PASS/FAIL/SKIP), actual, op, and limit
errorstringPresent only on failure

Conversion reports wrap the run in four steps: preflight (before expensive work — flags missing patch cleanup, orientation prep, UV/tangent ordering, AO-bake UV1 prerequisites, LOD0 optimization, and glTF compression notes), then near the end workflow_recipe (the profile's target recipe with honored/disabled/metadata-only/unsupported counts), conversion_manifest (resolved profile, import, operation, and export settings), and workflow_summary (preparation stages mapped to run/skipped status).

Commands

CommandDescription
fascat inspect input.stepInspect CAD assembly metadata and planned conversion inputs
fascat convert input.step [output.usdc]Convert STEP, IGES, BREP, or JT CAD into OpenUSD, glTF, OBJ, STL, or FBX
fascat validate output.usdcValidate generated USD, glTF, OBJ, STL, or FBX output
fascat validate output.glb --runtime-browserMeasure optional headless browser/WebGL load and FPS for glTF/GLB output
fascat validate output.glb --runtime-browser-preview preview.pngWrite a browser/WebGL-rendered glTF/GLB PNG preview
fascat validate output.glb --visual-preview preview.pngWrite a stable software-rendered PNG preview for visual review
fascat validate output.glb --turntable-dir views/Write multi-angle turntable preview PNGs and a contact sheet for visual review
fascat help [command]Show top-level or command-specific help
fascat versionPrint version and exit

Format support matrix

This matrix is scoped to Fascat's current importer/exporter surface. It is meant to make Unity Asset Transformer-style format parity explicit, not to imply that all listed formats are implemented.

Format familyInput supportOutput supportCurrent decision
STEP .step, .stpSupportedNot emitted as CADPrimary neutral CAD input path
IGES .igs, .igesSupportedNot emitted as CADLegacy CAD geometry import through OCP/XDE
OpenCASCADE BREP .brepSupportedNot emitted as CADNative-kernel shape import as a single source-shape part
OpenUSD .usd, .usda, .usdc, .usdzNot importedSupportedRuntime and scene-composition delivery
glTF .gltf, .glbNot importedSupportedPreferred web/mobile runtime delivery
OBJ .objNot importedSupportedMesh-only interchange output
STL .stlNot importedSupportedMesh-only manufacturing or inspection output
FBX .fbxNot importedSupportedASCII FBX DCC and engine handoff output
Parasolid .x_t, .x_bNot supportedNot supportedNative-kernel CAD import candidate, not in scope yet
JT .jtSupported (JT 8.x/9.x/10.x tessellation)Not emitted as CADPure-Python import of pre-tessellated JT 8/9/10 LOD meshes, assembly structure, and materials
CATIA, NX, SolidWorks, InventorNot supportedNot supportedNative CAD coverage is deferred
IFC, 3MF, QIFNot supportedNot supportedAdjacent workflow formats, deferred unless a user need changes priority

STEP import reports record two diagnostic steps:

  • import_decisions — each import toggle (PMI, variants, existing meshes, construction cleanup, coordinate normalization) as requested vs. effective, with a status of honored, approximated, unsupported, disabled, not_present, or backend_default.
  • loaded_representations — a per-part summary of BREP/construction-shape inputs, deleted construction-only nodes, and source topology counts. Free construction edges split from mixed face+curve shapes appear as separate construction-line parts or cleanup counts, per the construction-curve policy.

PMI (--pmi) runs a textual AP242 scan, writes typed PmiAnnotation metadata, and reports a pmi_semantic_graph. Design variants (--design-variants) scan configuration, effectivity, and condition records; --design-variant then prunes geometry by variant label, record id, effectivity value/range, or label=value assignment. The full list of supported STEP entity families and selection-resolution rules is documented once on the Python API page — the CLI flags drive exactly the same importer. metadata_and_visuals export adds deterministic glTF/USD marker meshes with simple vector text glyphs.

Full AP242 conditional/effectivity geometry evaluation and graphical PMI

presentation reconstruction remain planned backend work.

IGES import uses the same OCP/XDE shape-tree traversal for hierarchy, transforms, colors, and materials. BREP import creates one root occurrence and one part, keeping the native source shape for tessellation and healing.

JT import is a pure-Python reader (no OCP dependency) for JT 8.x, 9.x, and 10.x files. It decodes pre-tessellated LOD meshes (plain tri-strips in JT 8, topologically compressed tri-strip sets in JT 9/10), assembly hierarchy, instances, transforms, materials, and properties; parts are mesh-only (source_shape is None) and reuse the imported tessellation. Only the finest LOD is imported by default (--lod-selection all also fills Part.lod_meshes). Units come from the JT_PROP_MEASUREMENT_UNITS property (millimetres assumed when absent); JT declares no up axis, so the NX/Teamcenter Z-up right-handed convention is assumed — override with the standard --source-*/--target-* flags. Embedded precise B-rep (Parasolid XT), PMI, textures, JT 7 and older input, JT via stdin, and external (shattered) partition references are not supported; unsupported versions and B-rep-only files fail with explicit errors, and external references import as placeholder nodes with warnings.

Convert flags

FlagDefaultDescription
--profilerealtime-desktopConversion profile: inspect-only, realtime-desktop, realtime-web, realtime-mobile, virtual-reality, augmented-reality, or mixed-reality
--target-device-profileunsetTOML or JSON target-device budget overlay for the selected profile
--pipelineunsetTOML pipeline file with named filters and ordered conversion steps
--inputunsetAdditional STEP root input for explicit multi-root conversion; may be passed more than once
--lod-selectionfinestImport only the finest stored LOD or all stored LODs (finest, all); currently supported by JT
--jt-lod-selectionunsetDeprecated compatibility alias for --lod-selection; conflicting values are rejected
--stdout-formatusdaOutput format used only when the output path is -: usda, usdc, usdz, gltf, glb, obj, stl, or fbx
--sagprofile valueAbsolute CAD tessellation sag tolerance; overrides the profile's relative sag ratio when set
--sag-ratioprofile valueRelative CAD tessellation sag ratio; realtime profiles default to 0.0002
--angleprofile valueCAD tessellation angle tolerance in degrees
--target-trianglesprofile valueTarget triangle count for optimized LOD0
--ratiounsetSimplification ratio when no triangle target is set
--min-edge-lengthunsetCollapse tessellated edges shorter than this length
--max-edge-lengthprofile valueSplit tessellated triangles longer than this length
--max-polygon-lengthunsetReport tessellated polygon edges longer than this length without subdividing geometry
--max-triangles-per-partunsetFail when any tessellated part exceeds this triangle count
--preserve-boundaries / --no-preserve-boundariestruePreserve sharp/boundary edges during tessellation cleanup
--curvature-adaptivefalseUse tighter interior meshing on curved CAD faces
--detail-adaptivefalseAuto-tighten tessellation for shiny or high-detail material/metadata parts
--avoid-skinny-trianglesfalseRefine long skinny triangles after tessellation
--quality-reportunsetWrite per-part tessellation quality metrics and quality advisories as JSON
--free-edge-reportfalseRecord free/boundary edge diagnostics and warn when tessellated parts have open boundaries
--reuse-existing-meshes / --retessellate-existing-meshestrueReuse imported mesh data or force retessellation from source BREP where available
--heal-brepfalseRun BREP healing before tessellation
--heal-tolerance0.05BREP healing tolerance
--group-open-shells / --no-group-open-shellstrueGroup disconnected open BREP shells before healing
--cleanup-overlapping-faces / --keep-overlapping-facestrueRemove redundant coplanar BREP faces that overlap enough to z-fight
--overlap-area-ratio0.995Minimum smaller-face area ratio for BREP overlap cleanup
--remove-sliver-facesfalseRequest tiny sliver-face removal during BREP healing; current backend support is limited and reports warnings when unavailable
--max-sliver-area1e-4Area threshold for sliver-face reporting
--fail-on-open-shellsfalseFail if healed BREP still contains open shells
--lodsprofile valueComma-separated LOD ratios, for example 0.5,0.25,0.1
--lod-sourceauto for profilesChoose imported, generated, or auto; explicit --lods implies generated unless set
--lod-modevariantsLOD output mode: variants, extras, or separate
--lod-engine-profilegenericEngine-specific LOD export profile: generic, unity, or unreal
--lod-screen-coverageunsetScreen coverage values for generated LODs
--lod-per-part-budgetfalseApply LOD budgets independently per part
--lod-drop-tiny-partsfalseOmit tiny parts from lower LOD meshes
--lod-tiny-part-screen-size2.0Screen-size threshold for tiny-part LOD omission
--validate-lodsfalseValidate generated LOD monotonicity
--jobs1Worker count for independent per-part repair, staging, optimization, decimation, and LOD mesh work
--normalssmoothNormal generation mode: none, smooth, hard-edges, or flat
--normal-weightingareaNormal averaging weights for smooth or hard-edge normals: angle or area
--preserve-face-boundariesfalseTreat CAD face-group boundaries as hard normal edges
--override-normals / --preserve-normalstrueRegenerate existing normals, or preserve existing normals and only generate missing normals
--tangentsfalseEnsure glTF-compatible vertex tangents exist; existing tangents are preserved unless invalidated or overridden
--tangent-uv-channel0UV channel used when tangent generation or regeneration is needed
--override-tangents / --preserve-tangentsfalseRegenerate existing tangents instead of preserving them when --tangents is used
--validate-normalsfalseValidate staged normals and tangents
--uv0boxUV0 generation mode: none, box, unwrap, or lightmap
--uv1noneUV1 generation mode: none, box, unwrap, lightmap, or copy-uv0
--uv-aabb-scopelocalAABB projection scope for box UVs: local per part or shared across selected parts
--uv3d-sizeunsetWorld-space size per UV tile for box/AABB projection; unset normalizes to the AABB
--uv-override-existing / --uv-preserve-existingtrueOverride or preserve existing destination-channel UVs when box projection is requested
--normalize-uvsunsetComma-separated UV channels to rescale into 0..1 after UV generation or copy
--materialscadMaterial staging mode: cad, display, or none
--material-modecadMaterial normalization mode: cad or pbr
--merge-equivalent-materialsfalseMerge CAD materials with matching PBR values
--merge-verticesfalseMerge exact or tolerance-close vertices after staging
--merge-vertex-tolerance0.0Position tolerance used by --merge-vertices
--preserve-merge-vertex-attributes / --drop-merge-vertex-attributestrueKeep normals, tangents, and UV seams as merge constraints
--preserve-merge-vertex-material-boundaries / --ignore-merge-vertex-material-boundariestrueKeep material-boundary signatures as merge constraints
--delete-merge-vertex-degenerate / --keep-merge-vertex-degeneratetrueDelete degenerate polygons created by vertex merging
--merge-vertex-area-epsilonbbox-derivedArea threshold for degenerate polygons after vertex merging (default: 1e-12 × squared bbox diagonal)
--delete-degenerate-polygonsfalseRun standalone degenerate polygon cleanup after vertex merging
--degenerate-area-epsilonbbox-derivedArea threshold for standalone degenerate polygon cleanup (default: 1e-12 × squared bbox diagonal)
--delete-duplicate-polygons / --keep-duplicate-polygonstrueRemove exact duplicate polygons during standalone degenerate polygon cleanup
--texel-densityunsetUV texel density metadata for unwrap and atlas workflows
--uv-padding2UV island padding metadata in pixels; bake-domain packing clamps values below 2 px to 2 px
--max-stretchunsetMaximum UV stretch metadata for unwrap workflows
--unwrap-methoddefaultUnwrap solver intent: default, conformal, or isometric
--unwrap-iterationsunsetRequested unwrap solver iteration budget metadata
--unwrap-toleranceunsetRequested unwrap solver tolerance metadata
--uv-sharp-to-seam / --uv-no-sharp-to-seamfalseRequest sharp edges as UV seams for unwrap and lightmap channels
--uv-forbid-overlapping / --uv-allow-overlappingfalseRequest non-overlapping UV islands and report overlaps as policy violations
--atlasfalseTag materials and UVs for a generated atlas
--atlas-size4096Maximum atlas texture size
--metadatafullMetadata import/export mode: none, summary, or full
--pmimetadataPMI import/export mode: none, metadata, or metadata-and-visuals
--design-variants / --no-design-variantsfalseScan STEP design variant records into metadata and import reports
--design-variantunsetSelect a STEP design variant label, effectivity value, numeric/string assignment, record id, or referenced label and filter imported geometry; may be passed more than once
--import-existing-meshes / --no-import-existing-meshestruePrefer existing STEP tessellation payloads when the importer exposes them
--multi-file-import / --single-file-importfalseResolve quoted external STEP references from a master STEP file
--material-libraryunsetVendor material-library JSON/MTL/ZIP file or folder to apply during import; may be passed more than once
--material-library-color-spaceautoNumeric material-library color interpretation: auto, linear, or srgb255
--delete-free-vertices / --keep-free-verticesfalseDrop construction-only point shapes during STEP import
--delete-lines / --keep-linesfalseDrop construction-only line shapes during STEP import
--construction-curve-policypreserve-metadataConstruction-only line policy: preserve-metadata, delete, or tessellate-tubes
--construction-curve-tube-radius0.01Tube radius in source units when construction curves are tessellated as tubes
--source-unitsSTEP headerOverride source units for normalization
--source-meters-per-unitSTEP headerOverride source meters per unit for normalization
--source-up-axisZDeclared source up axis: Y or Z
--source-handednessrightDeclared source handedness: right or left
--target-unitssource unitsNormalize imported asset units, for example metre
--target-meters-per-unitsource factorNormalize imported asset meters per unit with a custom factor
--target-up-axissource axisNormalize imported asset up axis to Y or Z
--target-handednesssource handednessNormalize imported asset handedness to right or left
--filterunsetScope optimization and LOD work with a selector such as path=*/Fasteners/*
--exclude-filterunsetExclude selector matches from --filter results
--mergefalseMerge selected geometry before optimization
--merge-modeallMerge mode: all, by-material, by-node-name, by-part-name, hierarchy-level, parent-children, final-level, or regions
--keep-parent / --no-keep-parenttrueAttach merged nodes to a shared selected parent when possible
--merge-metadatapreserveMetadata policy: preserve, combine, summarize, or drop
--max-vertices-per-mesh65535Split merged output above this vertex count
--region-sizeunsetSpatial region size for --merge-mode regions
--merge-strategyallRegion merge strategy: all or by-material
--hierarchy-level1Hierarchy level used by --merge-mode hierarchy-level
--explodeunsetExplode selected geometry by by-material or connected-components
--replaceunsetReplace selected geometry with bounding-box or external-asset proxies
--external-assetunsetExternal asset path recorded by --replace external-asset
--batch-by-materialfalseBatch compatible scene geometry by material
--merge-compatible-meshesfalseMerge compatible scene meshes to reduce draw calls
--split-large-meshesfalseSplit scene-optimized meshes above the vertex limit
--index-bufferautoIndex buffer mode: auto, uint16, or uint32
--flattensafeHierarchy flattening mode: none, safe, or all
--instance-policyautoInstance policy: auto and preserve reconstruct exact matching mesh instances; expand duplicates per occurrence
--instance-similarity-tolerance0.0Position tolerance for reconstructing near-identical mesh instances with matching topology, attributes, materials, and metadata
--bake-materialsfalseCreate a shared baked material with raster atlas textures
--maps-resolution2048Bake texture resolution in pixels for generated raster maps
--lightmap-resolution1024Resolution used for generated bake/lightmap UV packing
--force-uv-generationfalseGenerate UVs before material bake metadata and textures are recorded
--bakebase-colorMaps to bake into raster atlas textures, such as base-color,opacity
--ambient-occlusion-strategyconservativeAO sampling direction set for baked AO maps and decimation AO protection: conservative, exterior, or advanced
--decimatefalseRun explicit decimation before profile optimization
--decimate-criteriontargetDecimation criterion: target or quality
--surface-toleranceunsetSurface deviation tolerance metadata for decimation
--line-toleranceunsetHard-edge deviation tolerance metadata for decimation
--normal-tolerance15Normal angle tolerance for decimation preservation
--uv-toleranceunsetUV deviation tolerance metadata for decimation
--decimate-iterative-threshold1000000Source triangle threshold above which explicit decimation runs intermediate passes
--protect-topology / --no-protect-topologytruePreserve topology-sensitive faces during decimation
--preserve-painted-areasfalsePreserve painted/protected/weighted face groups or metadata-marked face indices during decimation
--preserve-ambient-occlusionfalsePreserve low-AO faces from the sampled AO estimator during decimation
--budget-scopeselectionDecimation budget scope: part or selection
--uv-importancepreserve-islandsDecimation UV handling: preserve islands, preserve seams, or ignore UVs
--decimate-cleanup-attributesunsetComma-separated pre-decimation cleanup attributes: unused-uvs,tangents
--remove-holesfalseRemove small open hole loops with mesh boundary classification
--hole-typesthrough,blind,surfaceBoundary hole types to remove
--max-hole-diameter3.0Maximum planar-span hole diameter to remove
--prefer-brep / --no-prefer-breptruePrefer BREP feature removal when available
--remove-occludedfalseRemove geometry hidden from sampled exterior visibility rays
--occlusion-strategyadvancedOcclusion strategy: conservative, exterior, or advanced
--occlusion-leveltrianglesOcclusion removal level: parts, submeshes, or triangles
--occlusion-precision2048Occlusion precision preset or sample resolution
--hemi-evaluationfalseRestrict occlusion visibility rays to upper-hemisphere and side views
--neighbors-preservation1Visible-neighbor preservation rings for triangle occlusion removal
--consider-transparency-opaquefalseTreat transparent materials as occluders
--preserve-cavities / --no-preserve-cavitiestruePreserve large interior cavities
--minimum-cavity-volume-m30.5Minimum cavity volume to preserve
--run-lod-generatorsfalseRun preset-driven LOD generation after optimization actions
--lod-presetdesktopLOD preset: desktop, web, mobile, or vr
--preserve-instances / --no-preserve-instancestruePreserve repeated parts as shared instances, or duplicate per occurrence
--preserve-hard-edgesfalseProtect faces adjacent to hard edges during simplification
--hard-edge-angle45Angle threshold for hard-edge preservation
--preserve-holesfalseProtect open boundary faces during simplification
--preserve-material-boundariesfalseProtect faces along material boundaries
--preserve-uv-seamsfalseProtect faces touching duplicated-position UV seams
--preserve-small-partsfalseSkip simplification for small parts
--small-part-triangle-threshold64Triangle threshold for --preserve-small-parts
--preserve-silhouettefalseProtect faces on bounding-box silhouette extremes
--export-presetunsetglTF export preset: desktop, web, mobile, vr, or ar; presets request compression plus texture resize/dedupe cleanup during conversion
--quantizefalseWrite glTF KHR_mesh_quantization accessors and node dequantization transforms
--meshoptfalseWrite glTF EXT_meshopt_compression bufferView payloads with fallback data
--dracofalseCompress glTF geometry with KHR_draco_mesh_compression
--draco-compression-level5Draco compression level, 0 (fastest) to 10 (smallest)
--draco-quantize-position14Draco position quantization bits (1-30)
--draco-quantize-normal10Draco normal quantization bits (1-30)
--draco-quantize-texcoord12Draco texcoord quantization bits (1-30)
--draco-quantize-color8Draco color quantization bits (1-30)
--texture-compressionunsetCompress glTF textures with KTX2/Basis: ktx2 or basisu
--ktx2-quality128KTX2/Basis encoder quality level (0-255)
--ktx2-effort2KTX2/Basis encoder compression effort (0-6)
--ktx2-uastc/--ktx2-etc1sderivedForce UASTC or ETC1S encoding (default derives from --texture-compression)
--texture-fallback-formatautoPNG/JPEG fallback policy when KTX2/Basis compression is not requested: auto, png, or jpeg
--png-compression6PNG fallback compression level, 0 through 9
--jpeg-quality85JPEG fallback quality, 0 through 100
--packagedefaultUSD package mode: default or packaged .usdz
--usd-layoutautoUSD scene layout: auto (flat for the realtime-web profile, instanced otherwise), instanced (prototypes, internal references, LOD variants, instancing), or flat (inline meshes per occurrence for viewers without USD composition support)
--file-size-budget-mbunsetWarn in reports when output exceeds this size
--size-ladderfalseMeasure baseline, optimized, compressed, and requested temporary GLB sizes in a gltf_size_ladder report
--obj-materials / --no-obj-materialstrueWrite OBJ material assignments
--write-mtl / --no-write-mtltrueWrite an OBJ MTL sidecar
--preserve-groups / --no-preserve-groupstruePreserve OBJ groups per occurrence
--stl-binary / --stl-asciitrueWrite binary STL instead of ASCII STL
--stl-merge / --no-stl-mergetrueMerge STL output into one triangle stream
--fbx-materials / --no-fbx-materialstrueWrite FBX material nodes and connections
--fbx-normals / --no-fbx-normalstrueWrite FBX normal layers
--fbx-tangents / --no-fbx-tangentstrueWrite FBX tangent layers when available
--fbx-uvs / --no-fbx-uvstrueWrite FBX UV layers when available
--debugfalseRequire text .usd or .usda output for debugging
--reportunsetWrite a JSON conversion report sidecar
--forcefalseOverwrite an existing output file

Units

  • Linear tolerances and sizes (--sag, --min-edge-length, --max-edge-length, --max-polygon-length, --heal-tolerance, --max-sliver-area, --region-size, --max-hole-diameter) use the source asset's working units unless stated otherwise.
  • Angles (--angle, --normal-tolerance, --hard-edge-angle) are degrees.
  • Ratios (--ratio, --lods, decimation ratios) and screen-coverage values are fractions between 0 and 1; LOD ratios must be sorted highest-to-lowest detail. File-size budgets are megabytes; atlas/bake sizes are pixels.
  • Import space normalization uses a root transform: source coordinates stay in source units while the asset declares the target units, up-axis, and handedness, and the import report records the transform.
  • tessellate, heal_brep, and repair report a tolerance_policy with effective source/target units, meter conversions, the active deflection kind, converted absolute lengths, and which cleanup backends are implemented.
  • --sag and --sag-ratio are mutually exclusive in the effective tessellation options: passing --sag switches from the realtime profiles' relative sag_ratio=0.0002 default to an absolute tolerance.
  • Migration note: current staging defaults use --normal-weighting area and --hard-edge-angle 45 instead of the older angle weighting and 30 degree threshold, so re-converted assets can shade or split vertices differently unless the older values are passed explicitly.

Repair

  • face_orientation="exterior" is the implemented closed-component winding path; source-trusted, preserve, viewer-standpoint, open-shell, and unstitched-group policies are explicit in metadata rather than hidden behind fix_winding.
  • fix_winding flips coherent closed shells with inward signed volume and records before/after flipped-component counts; it detects non-orientable shared-edge cycles first and warns on Möbius-like topology it cannot fix.
  • T-junctions and boundary gaps are reported by default and fixed only with the opt-in fix_t_junctions / stitch_boundary_gaps flags; stitched vertices keep the surviving representative vertex's normals, tangents, and UVs, and UV-conflicting merges are counted in metadata.
  • --delete-degenerate-polygons removes repeated-vertex, collapsed-edge, near-flat, and exact-duplicate polygons (separate report counts per reason); use --keep-duplicate-polygons to only report duplicates.

Decimation

  • Keeping under 20% of source triangles emits an LOD0 distortion warning — prefer aggressive ratios for distant LODs.
  • --decimate without --target-triangles/--ratio seeds its target from the profile or --target-device-profile triangle budget.
  • --decimate-criterion quality passes tolerance-derived error bounds to the backend and records bound/result metadata.
  • Reports include target_strategy (target count / ratio / quality), estimated RAM (Unity's ~5 GB per million source triangles), iterative pass counts, and per-part target allocation; plus protected hard-edge, hole-boundary, material-boundary, UV-seam, and silhouette face counts.
  • --uv-importance: ignore strips UV/tangents first, preserve-seams uses then strips them, preserve-islands keeps them. --preserve-painted-areas and --preserve-ambient-occlusion add painted/protected and low-AO faces as constraints; --ambient-occlusion-strategy controls the AO direction set. --decimate-cleanup-attributes unused-uvs,tangents removes unused UV channels/tangents first.

Materials

  • --merge-equivalent-materials compares PBR material factors with fixed six-decimal rounding for base color, metallic, roughness, and opacity, so importer floating-point noise does not prevent deduplication.

UVs

  • --uv1 unwrap/lightmap bake channels are packed by xatlas with configured padding/resolution and report pack dimensions, utilization, and padding status. Bake-domain packing warns and clamps requested padding below 2 px to 2 px.
  • box UV generation is reported as AABB projection; --uv-aabb-scope, --uv3d-size, and --uv-preserve-existing record local/shared bounds, scale, destination, override policy, and units.
  • --uv-sharp-to-seam and --uv-forbid-overlapping are recorded as intent (the xatlas backend doesn't expose them directly) and validated after generation.

Material Baking

  • --bake-materials collapses source material factors into the baked output with a simple arithmetic mean for base color, metallic, roughness, and opacity; atlas images carry the per-face raster detail.

LODs

  • LOD reports separate source, newly added, retained imported, and full-chain vertex/triangle counts and payload bytes, so the memory/size cost and origin of extra levels are visible. Ratio LODs simplify progressively from the previous level while preserving each ratio against the source count.
  • Chain advisories warn on more than four levels, over-aggressive LOD1/LOD2, and geometry-only far LODs that should bake to one mesh/material. Per-level metadata records simplification source, instance reuse, material merge, texture bake, culling-granularity changes, and resolved export representation.
  • --lod-engine-profile unity emits MSFT_lod variant nodes; unreal emits separate _LOD# scene nodes for tools that ignore MSFT_lod.

Holes, occlusion, and compression

  • --remove-holes uses mesh boundary classification and filling when BREP hole removal is unavailable; --hole-types filters inferred through/blind/surface loops.
  • --remove-occluded uses deterministic sampled visibility — --occlusion-strategy sets the direction set, --hemi-evaluation restricts to upper-hemisphere/side views, and --occlusion-level picks parts/submeshes/triangles. Metadata records sample/direction coverage and a confidence score.
  • --draco runs the Draco encoder for glTF/GLB. --texture-fallback-format auto keeps alpha-bearing sets PNG and color-only sets JPEG when KTX2/Basis isn't requested; explicit jpeg warns when it would discard transparency.

Validation previews

fascat validate can write review artifacts (full detail on the Python API page):

  • --visual-preview / --lod-preview-dir — software-rendered PNGs of the output mesh and per-LOD contact sheet.
  • --turntable-dir — software-rendered turntable PNGs from --turntable-views azimuths at each --turntable-elevations elevation, plus a turntable.png contact sheet grid. --turntable-baseline-dir diffs each view against a same-named baseline PNG using the --visual-diff-* thresholds and fails validation when any view drifts. Framing auto-fits each view, so diffs catch silhouette and shading changes rather than absolute size changes.
  • --runtime-browser / --runtime-browser-preview — headless Chromium WebGL load/FPS measurement and screenshots for supported glTF/GLB primitives.

Inspect flags

FlagDefaultDescription
--profileinspect-onlyInspection profile to show in output
--metadatasummaryMetadata output mode: none, summary, or full
--pmisummaryPMI output mode: none, summary, full, metadata, or metadata-and-visuals
--design-variants / --no-design-variantsfalseScan STEP design variant records into metadata and import reports
--design-variantunsetSelect a STEP design variant label, effectivity value, numeric/string assignment, record id, or referenced label and filter imported geometry; may be passed more than once
--import-existing-meshes / --no-import-existing-meshestruePrefer existing STEP tessellation payloads when the importer exposes them
--multi-file-import / --single-file-importfalseResolve quoted external STEP references from a master STEP file
--material-libraryunsetVendor material-library JSON/MTL/ZIP file or folder to apply during import; may be passed more than once
--material-library-color-spaceautoNumeric material-library color interpretation: auto, linear, or srgb255
--delete-free-vertices / --keep-free-verticesfalseDrop construction-only point shapes during STEP import
--delete-lines / --keep-linesfalseDrop construction-only line shapes during STEP import
--construction-curve-policypreserve-metadataConstruction-only line policy: preserve-metadata, delete, or tessellate-tubes
--construction-curve-tube-radius0.01Tube radius in source units when construction curves are tessellated as tubes
--source-unitsSTEP headerOverride source units for normalization
--source-meters-per-unitSTEP headerOverride source meters per unit for normalization
--source-up-axisZDeclared source up axis: Y or Z
--source-handednessrightDeclared source handedness: right or left
--target-unitssource unitsNormalize imported asset units, for example metre
--target-meters-per-unitsource factorNormalize imported asset meters per unit with a custom factor
--target-up-axissource axisNormalize imported asset up axis to Y or Z
--target-handednesssource handednessNormalize imported asset handedness to right or left
--heal-brepfalseRun BREP healing before inspection output
--heal-tolerance0.05BREP healing tolerance
--cleanup-overlapping-faces / --keep-overlapping-facestrueRemove redundant coplanar BREP faces that overlap enough to z-fight
--overlap-area-ratio0.995Minimum smaller-face area ratio for BREP overlap cleanup
--remove-sliver-facesfalseRequest tiny sliver-face removal during BREP healing; current backend support is limited and reports warnings when unavailable
--max-sliver-area1e-4Area threshold for sliver-face reporting
--filterunsetReport matched assembly nodes and parts
--exclude-filterunsetExclude selector matches from --filter results

Supported filter expressions use case-sensitive shell-style fnmatchcase patterns for string fields (*, ?, and character classes), not regular expressions:

ExpressionMeaning
path=*/Fasteners/*Match node paths
name=Bolt*Match node names
part=part_123Match part ids
part-name=Housing*Match part names
material=*Steel*Match material ids or names
metadata.step_label=0:1:*Match metadata values
triangles<=1200Match triangle counts
vertices>=300Match vertex counts
size>=50Match bounding-box diagonal

Repeated --filter flags are combined with logical AND. Use --exclude-filter for negative selectors.

Pipeline files

Use --pipeline when different assembly branches need different ordered steps.

[import]
metadata = "full"
pmi = true
design_variants = false
design_variant_selection = []
existing_meshes = true
multi_file = false
material_library_paths = ["vendor-materials.json"]
material_library_color_space = "auto"
delete_free_vertices = false
delete_lines = false
construction_curve_policy = "preserve_metadata"
construction_curve_tube_radius = 0.01
target_units = "metre"
target_up_axis = "Y"
target_handedness = "right"

[export]
metadata = "summary"
pmi = "metadata"

[[filters]]
name = "fasteners"
path = "*/Fasteners/*"
names = ["Bolt*", "Nut*", "Washer*"]

[[filters]]
name = "large_castings"
path = "*/Housing/*"
min_diagonal = 50.0

[[steps]]
op = "tessellate"
where = "large_castings"
sag = 0.03
sag-ratio = 0.005
max-polygon-length = 5.0
free-edge-report = true
reuse-existing-meshes = false
angle = 10.0

[[steps]]
op = "tessellate"
where_not = "large_castings"
sag = 0.2
angle = 20.0

[[steps]]
op = "merge_vertices"
tolerance = 0.001
preserve_uvs = true
preserve_material_boundaries = true
quality_report = true

[[steps]]
op = "delete_degenerate_polygons"
area_epsilon = 1e-12

[[steps]]
op = "merge"
where = "fasteners"
mode = "by_material"
metadata = "combine"
fascat convert motor.step motor.glb --pipeline realtime.toml

Pipeline files are validated before conversion starts. Unknown top-level, filter, import/export, or operation keys are rejected, and option constraints such as invalid numeric ranges, missing external_path, conflicting where / where_not, or unsupported operation names fail during parse. CLI errors include line N when the source file location can be identified.

Unity-inspired capability matrix

This matrix maps Unity Asset Transformer-style CAD-to-runtime capabilities to the current Fascat behavior. Use dry-run operation_diagnostics, report workflow_summary, and report step warnings to distinguish exact work from fallbacks.

The Report step column names where to look for the detail; the linked sections above and on the Python API page document each field.

CapabilityStatusReport stepNext step
CAD import (hierarchy, names, transforms, colors, metadata, PMI, variants)Implemented for STEP/IGES; BREP as a single part; JT 8.x/9.x/10.x as pre-tessellated mesh parts; multi-root and master-file external references supportedimport (decisions, loaded representations, PMI semantic graph, design-variant records, external_reference_graph)Full AP242 conditional/effectivity geometry evaluation; full PMI semantic + graphical coverage; richer external-reference transforms
BREP healingPartialheal_brep (open shells, edges, slivers, same-domain/overlap cleanup status)Sliver-face removal and deeper face/wire repair
TessellationImplementedtessellate (tolerance policy, detail-adaptive criteria, quality metrics and advisories)Conformal CAD UV solving; deeper curvature-targeted profiles
Mesh repairImplemented for core cleanuprepair, plus standalone merge_vertices / delete_degenerate_polygons reportsT-junction sewing, boundary-gap stitching, non-manifold cracking, viewer/open-shell orientation backends
Staging (normals, tangents, UV metadata)Partialstage (normal/tangent provenance, per-channel UV domain/seam/distortion/pack metadata)Backend-enforced unwrap controls, island merge, tileable UV alignment
Material bakingImplemented for factor/face atlas, sidecar textures, JSON/MTL/ZIP librariesbake_materials; emissive material/fallback provenance; import material-library match countsHigh-poly normal transfer; closed vendor library containers
Hole removalApproximateremove_holes (warns on mesh-fill fallback)BREP feature-level removal for closed holes
Occlusion removalApproximateremove_occluded (sample/direction coverage, confidence)Acceleration structures and raster/GPU backends
DecimationPartialdecimate (target strategy, RAM/pass estimates, protected/importance counts)Continuous weighted decimation and retopology
LOD generationPartiallods with ratio or generator options; run_lod_generators compatibility alias (per-level counts, chain advisories, engine export mode)Measured engine runtime validation of LOD profiles
Instance reconstructionPartialoptimize_scene (reconstructed counts, savings, draw-call breakdown)Transform-aware matching; compressed size estimates
Runtime compressionImplementedwrite runtime_dependencies / runtime_decision_matrix (quantize, meshopt, Draco, KTX2/Basis)Full renderer/material validation
Export and budgetsImplemented for USD, USDZ, glTF/GLB, OBJ, STLwrite, gltf_size_ladder, texture_export_policy, profile_budget; validate runtime/preview reportsFallback-free KTX2/Basis decode
PMI metadata exportPartialPmiAnnotation metadata + pmi_semantic_graph; glTF extras.fascat / USD customData; markers when metadata_and_visualsFull AP242 semantic + graphical presentation

Validate flags

FlagDefaultDescription
--geometry-qualityfalseEnable all geometry quality checks in the validation report
--non-manifold-edgesfalseReport non-manifold edge counts
--open-boundariesfalseReport open boundary counts
--self-intersectionsfalseReport detected self-intersections with bounded triangle-triangle checks and lower-bound fields when the pair limit is hit
--sliver-trianglesfalseReport degenerate and sliver triangle stats
--tiny-partsfalseReport tiny part stats
--draw-call-estimatefalseReport material count, draw-call estimate, mesh/submesh slots, instances, and merged batch counts
--visual-riskfalseReport before/after visual risk warnings
--visual-previewunsetWrite a stable software-rendered PNG preview of the validated output mesh
--runtime-browser-previewunsetWrite a browser/WebGL-rendered PNG preview for supported glTF/GLB primitives
--visual-baselineunsetCompare --visual-preview against a baseline PNG and fail validation when thresholds are exceeded
--visual-diff-pixel-tolerance0Per-channel byte tolerance ignored when counting changed visual diff pixels
--visual-diff-mean-threshold0.0Maximum allowed mean absolute error for the visual baseline diff
--visual-diff-changed-pixel-ratio0.0Maximum allowed ratio of changed visual diff pixels
--lod-preview-dirunsetWrite LOD switching preview PNGs and lod-switching.png into a directory
--turntable-dirunsetWrite multi-angle turntable preview PNGs and turntable.png into a directory
--turntable-views8Number of turntable azimuth views per elevation
--turntable-elevations-30,30Comma-separated turntable camera elevations in degrees (each between -90 and 90)
--turntable-baseline-dirunsetCompare each turntable view against same-named PNGs in this directory with the --visual-diff-* thresholds and fail validation on drift
--turntable-width512Turntable preview image width in pixels
--turntable-height512Turntable preview image height in pixels
--turntable-supersample2Turntable preview supersampling factor
--runtime-browserfalseFor glTF/GLB, run optional headless browser/WebGL load and FPS measurement
--runtime-browser-commandunsetBrowser executable for --runtime-browser or --runtime-browser-preview; otherwise FASCAT_BROWSER or common Chromium/Chrome names are used
--runtime-duration2.0Browser FPS measurement duration in seconds
--runtime-timeout15.0Browser runtime validation timeout in seconds
--filterunsetScope validation-time geometry analysis with an assembly selector
--exclude-filterunsetExclude selector matches from validation-time analysis
--reportunsetWrite validation and geometry quality report as JSON
--max-non-manifoldunsetFail validation when non-manifold edges exceed this limit; implies --non-manifold-edges
--max-self-intersectionsunsetFail validation when self-intersections exceed this limit; implies --self-intersections
--max-sliversunsetFail validation when sliver triangles exceed this limit; implies --sliver-triangles
--max-open-boundariesunsetFail validation when open boundaries exceed this limit; implies --open-boundaries
--max-trianglesunsetFail validation when the triangle count exceeds this limit
--max-file-size-mbunsetFail validation when the on-disk output size exceeds this limit in MiB
--profileunsetResolve triangle and file-size gate budgets from a conversion profile; explicit --max-* flags take precedence
--strict-geometryfalseShorthand for setting all four geometry gate limits to 0

When any gate threshold flag, --strict-geometry, or --profile is set, validate evaluates the requested gates, prints one PASS|FAIL|SKIP <gate> <actual> <op> <limit> line per gate plus an OVERALL line on stdout, and exits 1 when any gate fails. Gates whose input is unavailable or inapplicable are reported as SKIP and never fail validation. Structural validity, visual diff, turntable diff, and LOD monotonicity are reported through the same gate mechanism.

Gated example:

fascat --json validate motor.glb \
  --strict-geometry \
  --profile realtime-web \
  --max-file-size-mb 25 \
  --turntable-dir views/ \
  --turntable-baseline-dir reference-views/

Example:

fascat validate motor.glb \
  --filter 'path=*/Fasteners/*' \
  --geometry-quality \
  --non-manifold-edges \
  --open-boundaries \
  --self-intersections \
  --sliver-triangles \
  --tiny-parts \
  --draw-call-estimate \
  --visual-risk \
  --visual-preview preview.png \
  --visual-baseline baseline.png \
  --lod-preview-dir preview-lods/ \
  --turntable-dir preview-views/ \
  --runtime-browser \
  --report report.json

File arguments

Use - for standard streams:

cat input.step | fascat inspect -
cat input.step | fascat convert - - --stdout-format glb --profile realtime-web
cat output.usdc | fascat validate -

When the convert output argument is omitted for a file input, Fascat writes beside the input with a .usdc suffix. Stdin input requires an explicit output path or -.

When output is -, --stdout-format selects the emitted format and defaults to usda. Progress/errors stay on stderr.

Supported input suffixes are .step, .stp, .igs, .iges, and .brep. Supported output suffixes are .usd, .usda, .usdc, .usdz, .gltf, .glb, .obj, .stl, and .fbx.

--debug is only valid with .usd or .usda output. Binary .usdc, .gltf, and .glb output is rejected when debug mode is enabled.

convert validates the generated asset before reporting success. If validation fails, the command exits non-zero.

convert prints up to 10 report warnings (budget violations, tessellation and UV advisories, export policy notes) on stderr after a successful run; --quiet suppresses them and --json keeps them in the JSON payload instead. Pass --report report.json for the full list.

All exporters write transactionally: content is produced at a hidden temp file in the destination directory, validated there, and atomically renamed into place only on success. A failed or interrupted export never leaves a partial or corrupt file at the output path (sidecar files from a previous differently-named export are not garbage-collected).

Benchmarking

Use the benchmark harness before performance-sensitive changes:

make benchmark
# or
uv run python scripts/benchmark.py tests/fixtures/vertical-screw.step --output-dir dist/benchmarks --output-suffix .glb

The harness writes JSON with total wall time, process peak RSS where the platform exposes it, per-report-step durations, output paths, and final mesh statistics. Pass --repeat N for repeated runs and --validate-output when the validation round trip should be included in the measured path.

Output streams

StreamContents
stdoutPrimary command output and --json payloads
stderrErrors, source counts, per-stage progress, warnings, and diagnostics

When --json is active, expected runtime errors are reported as JSON payloads on stdout and still exit non-zero.

Environment variables

VariableDescription
NO_COLORSet to any non-empty value to disable color output

Color is also disabled when --no-color is passed, TERM=dumb, or the relevant stream is not a TTY.

Exit codes

Fascat keeps exit codes stable for scripts: 0 means the command completed, 1 means the command was valid but failed at runtime or validation, and 2 means the invocation or option values were invalid before the requested work could run.

CodeMeaning
0Success
1Runtime failure
2Invalid usage
130Interrupted (Ctrl-C) — no partial output file is left behind

Shell completions

Typer provides built-in shell completion support:

# Install completion for your shell (auto-detects)
fascat --install-completion

# Show the completion script without installing
fascat --show-completion