splat-transform

playcanvasMIT活跃维护

处理与转换 3D Gaussian Splatting 模型的命令行工具和库,支持格式互转和批量处理,方便把 3DGS 资产接入 PlayCanvas 等渲染管线。

CLI tool and library for 3D Gaussian splat processing and conversion

v3.10.3发布于 2026-10-21 19:09 UTC1,436star +20 / 7 天184fork同步于 2026-11-10 11:48 UTC

怎么上手

由 README 提炼,执行前请确认
npm install -g @playcanvas/splat-transform
硬件要求按 README 说明

README 未说明显存要求;SOG 压缩和 GPU 体素化需要 GPU,可用 --list-gpus 查看适配器,也可用 -g cpu 禁用 GPU(但 --filter-cluster 等 GPU 专属功能不可用)。

下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

PlayCanvas 出品的 3D Gaussian Splat 转换与编辑 CLI 工具,支持多种格式互转

处理与转换 3D Gaussian Splatting 模型的命令行工具和库,支持格式互转和批量处理,方便把 3DGS 资产接入 PlayCanvas 等渲染管线。

核心能力

  • 读取 PLY、SOG、SPZ、SPLAT、KSPLAT、LCC 等格式
  • 写出 PLY、SOG、SPZ、GLB、CSV、HTML Viewer、LOD、Voxel、WebP
  • 按平移、旋转、缩放对 splat 应用变换
  • 按包围盒、球体、数值或 NaN 过滤高斯点
  • 用 Morton 排序重排 splat 以改善空间局部性

容易踩的坑

抽稀(--decimate)必须是最后一个动作且输出必须为 .ply,需分两次调用完成转换;大规模场景深度抽稀需显式指定 --scratch-dir,否则不写中间文件;-g cpu 与 --filter-cluster 等 GPU 专属功能不兼容;SPZ 无法表示 2DGS,输出时会告警。

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

5 个版本v3.10.3
  1. v3.10.3最新正式版2026-10-21 · 2026-10-21 19:09 UTC

    What's Changed

    Full Changelog: https://github.com/playcanvas/splat-transform/compare/v3.10.2...v3.10.3

  2. v3.10.22026-10-21 · 2026-10-21 14:01 UTC
    查看更新说明
  3. v3.10.12026-10-09 · 2026-10-09 09:13 UTC
    查看更新说明

    What's Changed

    Full Changelog: https://github.com/playcanvas/splat-transform/compare/v3.10.0...v3.10.1

  4. v3.10.02026-10-06 · 2026-10-06 13:21 UTC
    查看更新说明
  5. v3.9.22026-10-05 · 2026-10-05 17:41 UTC
    查看更新说明

    What's Changed

    Full Changelog: https://github.com/playcanvas/splat-transform/compare/v3.9.1...v3.9.2

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    SplatTransform - 3D Gaussian Splat Converter

    NPM Version NPM Downloads License Discord Reddit X

    | User Guide | API Reference | Blog | Forum |

    SplatTransform is an open source library and CLI tool for converting and editing Gaussian splats. It can:

    📥 Read PLY, Compressed PLY, SOG, Streamed SOG, SPZ, SPLAT, KSPLAT, LCC and LCC2 formats
    📤 Write PLY, Compressed PLY, SOG, Streamed SOG, SPZ, GLB, CSV, HTML Viewer, LOD, Voxel and WebP image formats
    📊 Generate statistical summaries for data analysis
    🔗 Merge multiple splats
    🔄 Apply transformations to input splats
    🎛️ Filter out Gaussians or spherical harmonic bands
    🔀 Reorder splats for improved spatial locality
    ⚙️ Procedurally generate splats using JavaScript generators

    The library is platform-agnostic and can be used in both Node.js and browser environments.

    Installation

    Install or update to the latest version:

    npm install -g @playcanvas/splat-transform
    

    For library usage, install as a dependency:

    npm install @playcanvas/splat-transform
    

    For running on a backend with Docker (including GPU/Vulkan setup), see the Docker Backend guide.

    [!TIP] For one-off conversions without installing anything, try SuperSplat Convert — a browser-based frontend to splat-transform. See the Convert page docs for details.

    Guides

    Format Specifications

    FormatDescription
    PLYIndustry-standard uncompressed format for source, editing and interchange
    SOGSuper-compressed format for web delivery (meta.json + WebP textures, bundled or unbundled)
    Streamed SOGMulti-LOD chunked SOG for streaming very large scenes (lod-meta.json)
    VoxelSparse voxel octree for collision detection (.voxel.json / .voxel.bin)

    CLI Usage

    splat-transform [GLOBAL] input [ACTIONS]  ...  output [ACTIONS]
    

    Key points:

    • Input files become the working set; ACTIONS are applied in order
    • The last file is the output; actions after it modify the final result
    • Use null as output to discard file output

    Supported Formats

    FormatInputOutputDescription
    .ply✅✅Standard PLY format
    .sog✅✅Bundled super-compressed format (recommended)
    meta.json✅✅Unbundled super-compressed format (accompanied by .webp textures)
    lod-meta.json✅✅Streamed LOD data stored in SOG chunks
    .compressed.ply✅✅Compressed PLY format (auto-detected and decompressed on read)
    .spz✅✅Compressed splat format (Niantic format, v2–4)
    .lcc✅❌LCC file format (XGRIDS)
    .lcc2✅❌LCC2 file format (XGRIDS, octree)
    .ksplat✅❌Compressed splat format (mkkellogg format)
    .splat✅❌Compressed splat format (antimatter15 format)
    .mjs✅❌Generate a scene using an mjs script (Beta)
    .glb❌✅Binary glTF with KHR_gaussian_splatting extension
    .csv❌✅Comma-separated values spreadsheet
    .html❌✅HTML viewer app (single-page or unbundled) based on SOG
    .voxel.json❌✅Sparse voxel octree for collision detection
    .webp❌✅Lossless WebP image rendered from a camera view via GPU rasterizer
    null❌✅Discard output (useful with --stats for analysis-only runs)

    Antialiased and 2DGS scenes

    Scenes trained with antialiasing or as 2DGS are tagged, and the tag is preserved where the output format can hold it. --info reports it as model.

    On read: a PLY header comment — Brush's comment SplatRenderMode: default | mip | 2dgs or Postshot's comment antialiased 0 | 1 (last one wins); SPZ's antialiased header bit; a SOG meta.json "model" entry, or the one in lod-meta.json, which applies to all its files. A PLY with scale_0/scale_1 but no scale_2 is read as 2DGS regardless of comments, and the missing column is materialized as a zero-thickness scale so the rest of the pipeline is unaffected.

    On write: .ply and .compressed.ply carry comment SplatRenderMode: mip | 2dgs (Brush's spelling, whichever form was read); .sog, meta.json and lod-meta.json carry "model": "antialiased" | "2dgs"; .spz sets its antialiased bit, and warns that it cannot represent 2DGS. A 2DGS PLY output drops the scale_2 column again. Other output formats have nowhere to record it and drop the tag silently. Combining inputs whose models disagree warns and writes the result untagged.

    Actions

    Actions execute in the order specified and can be repeated. Any action may appear after any input or output file:

    -t, --translate        <x,y,z>          Translate Gaussians by (x, y, z)
    -r, --rotate           <x,y,z>          Rotate Gaussians by Euler angles (x, y, z), in degrees
    -s, --scale            <factor>         Uniformly scale Gaussians by factor
    -H, --filter-harmonics <0|1|2|3>        Remove spherical harmonic bands > n
    -N, --filter-nan                        Remove Gaussians with NaN values, most Inf values, or a
                                              zero-norm (unrenderable) rotation quaternion;
                                              retains +Infinity in opacity and -Infinity in scale_*
    -B, --filter-box       <x,y,z,X,Y,Z>    Remove Gaussians outside box (min, max corners)
    -S, --filter-sphere    <x,y,z,radius>   Remove Gaussians outside sphere (center, radius)
    -V, --filter-value     <name,cmp,value> Keep Gaussians where <name> <cmp> <value>
                                              cmp ∈ {lt,lte,gt,gte,eq,neq}
                                              opacity, scale_*, f_dc_* use transformed values
                                              (linear opacity 0-1, linear scale, linear color 0-1).
                                              Append _raw for raw PLY values (e.g. opacity_raw).
    -d, --decimate         <n|n%>           Simplify at a uniform rate everywhere
                                              Use n% for a percentage. --decimate-adaptive allocates removal
                                              by local error instead: much better on mixed-scale content such
                                              as skies, at higher memory cost.
                                              Memory-bounded and streaming: scales to scenes of 100M+
                                              Gaussians. Must be the final action, and the output must
                                              be .ply (write a decimated PLY first, then convert in a
                                              second invocation). A deep target on a huge scene needs
                                              --scratch-dir for its intermediate levels; nothing is
                                              written to disk without it.
        --scratch-dir      <path>           Directory for decimation intermediates (explicit only)
    -F, --filter-floaters  [size,op,min]    Remove Gaussians not contributing to any solid voxel.
                                              Evaluates each Gaussian at occupied voxel centers.
                                              Default: size=0.05, opacity=0.1, min=0.004 (1/255).
                                              Bare flag (no value) uses all defaults.
    -C, --filter-cluster   [res,op,min]     Keep only the connected cluster at --seed-pos.
                                              GPU-voxelizes at coarse resolution (res world units/voxel).
                                              Default: res=1.0, opacity=0.999, min=0.1.
                                              Bare flag (no value) uses all defaults.
    -p, --params           <key=val,...>    Pass parameters to .mjs generator script
    -l, --tag-lod          <n>              Tag the Gaussians with LOD level n (n >= 0, or -1 for environment)
        --stats            [text|json]      Print file info, per-column statistics and the fill/overdraw ratio to stdout. Default: text
        --info             [text|json]      Print structural metadata (format, per-LOD counts, extra columns) to stdout. Default: text
    -m, --morton-order                      Reorder Gaussians by Morton code (Z-order curve)
    

    CLI Options

    These options configure a run as a whole rather than operating on splat data — most groups apply only when reading or writing a specific format.

    General Options

    -h, --help                              Show this help and exit
    -v, --version                           Show version and exit
    -q, --quiet                             Suppress non-error output
        --verbose                           Show debug-level diagnostics
        --memory                            Show peak memory in progress output
        --tty                               Interactive bar rendering (default on a TTY; --no-tty to disable)
    -w, --overwrite                         Overwrite output file if it exists
        --webp-effort      <0-9>            Lossless WebP compression effort for image, SOG, HTML and LOD output.
                                            Higher tries harder to reduce size. Default: libwebp’s default lossless settings.
    

    GPU Options

    Used by SOG compression and GPU voxelization (--filter-cluster, --filter-floaters, .voxel.json output).

        --list-gpus                         List available GPU adapters and exit
    -g, --gpu              <n|cpu>          Device for GPU operations: GPU adapter index | 'cpu'
                                              ('cpu' disables GPU and is incompatible with
                                              GPU-only features like --filter-cluster)
    

    SOG Compression Options

    Apply when writing .sog, meta.json, lod-meta.json, or .html outputs.

    -i, --sh-iterations    <n>              Iterations for SH compression (more=better). Default: 10
        --max-workers      <n>              Worker threads for SOG encoding (0 = inline/serial). Default: 4
    

    SPZ Output Options

    Apply when writing .spz outputs.

        --spz-version      <3|4>            The SPZ format version to write. Default: 4
    

    HTML Viewer Output Options

    Apply when writing .html outputs.

        --viewer-settings  <settings.json>  HTML viewer settings JSON file
        --unbundled                         Generate unbundled HTML viewer with separate files
    

    [!NOTE] See the SuperSplat Viewer Settings Schema for details on how to pass data to the --viewer-settings option.

    LOD Input Options

    Apply when reading lod-meta.json, .lcc, and .lcc2 files.

    -L, --select-lod       <n,n,...>        Comma-separated LOD levels to read from streamed SOG / LCC / LCC2 input
    

    LOD Output Options

    Apply when writing lod-meta.json (multi-LOD streaming SOG bundle).

        --lod-chunk-count  <n>              Approximate number of Gaussians per LOD chunk in K. Default: 512
        --lod-chunk-extent <n>              Approximate size of an LOD chunk in world units (m). Default: 16
        --lod-chunk-min    <n>              Gaussians in K below which a chunk is not split for extent. Default: 8
    

    A chunk is split when it holds more than --lod-chunk-count Gaussians, or when it is wider than --lod-chunk-extent and holds more than --lod-chunk-min. The minimum keeps sparse regions such as sky or distant background from being cut into thousands of near-empty chunks: below it a region stays one chunk however wide it is. Dense regions are unaffected.

    See Generating Streamed SOG for an end-to-end walkthrough.

    Voxel Output Options

    Apply when writing .voxel.json (sparse voxel octree for collision detection). See the Collision Mesh guide for a deep dive on each step and tuning.

        --voxel-size       <n>              Voxel size for .voxel.json. Default: 0.05
        --voxel-opacity    <n>              Voxel opacity threshold for .voxel.json. Default: 0.1
        --voxel-external-fill [size]        Seal exterior voxels via boundary flood fill (interior scenes).
                                              [size] (world units) is the dilation distance applied
                                              before the flood fill to bridge small wall gaps.
                                              --seed-pos is used to verify the volume is enclosed at
                                              the seed; the fill is skipped if the seed is reachable
                                              from outside.
                                              Default size: 1.6
        --voxel-floor-fill [size]           Fill each column upward from bottom until hitting solid (exterior scenes).
                                              Optional size (world units): only patch XZ areas surrounded by floor
                                              within 2*size; large empty exterior areas are left alone.
                                              Default size: 1.6
        --voxel-carve      [h,r]            Carve navigable space using capsule flood fill from seed.
                                              Default: height=1.6, radius=0.2
        --seed-pos         <x,y,z>          Seed position for voxel fill/carve and --filter-cluster.
                                              Default: 0,0,0
        --collision-mesh   [smooth|faces]   Generate collision mesh (.collision.glb). Default: smooth
    

    Image Output Options

    Apply when writing .webp (lossless WebP rendered via GPU rasterizer).

        --projection       <pinhole|equirect>  Camera projection. Default: pinhole.
                                            equirect = 360°×180° panorama from --camera-pos; --camera-fov must be
                                            omitted; --resolution must be 2:1 (default 2048x1024).
        --camera-pos       <x,y,z>          Camera position in world space. Default: 2,1,-2
        --camera-target    <x,y,z>          Camera target point. Default: 0,0,0
        --camera-up        <x,y,z>          World up vector. Default: 0,1,0
        --camera-fov       <degrees>        Vertical field of view in degrees. Default: 60. Rejected with --projection equirect.
        --resolution       <WxH>            Output resolution, e.g. 1920x1080. Default: 1280x720 (pinhole) or 2048x1024 (equirect)
        --camera-near      <n>              Near clip distance. Default: 0.2 (matches reference 3DGS)
        --background       <r,g,b[,a]>      Background color in [0,1]. Default: 0,0,0,1
        --f-stop           <N>              Aperture as a photographic f-stop (e.g. 2.8, 5.6, 11). Enables defocus blur;
                                            smaller = more blur. Pinhole only. Default: disabled (no defocus).
        --focus-distance   <n>              Camera-space Z of the focus plane (world units). Default: distance to --camera-target.
                                            Pinhole only; only meaningful with --f-stop.
        --dof-samples      <n>              Aperture samples per instant with --f-stop. Default: 32. More samples reduce
                                            sampling artifacts at greater cost; multiplies --motion-samples when combined.
        --sensor-size      <n>              Vertical sensor height in world units. Gives --f-stop a physical meaning.
                                            Default: 0.024 (35mm full-frame, world units = meters). Scale to your world:
                                            world unit = decimeter → 0.24, world unit = millimeter → 24.
        --camera-pos-end   <x,y,z>          End camera position. When set, enables camera motion blur: the camera moves
                                            from --camera-pos (shutter open) to --camera-pos-end (shutter close) and the
                                            frame averages renders at instants across the shutter. Default: disabled.
        --camera-target-end <x,y,z>         End camera target. Default: same as --camera-target. Only with --camera-pos-end.
        --camera-up-end    <x,y,z>          End up vector. Default: same as --camera-up. Only with --camera-pos-end.
        --shutter          <0..1>           Fraction of the start→end segment averaged, centered on its midpoint. Default: 0.5.
                                            With --camera-track, fraction of the frame interval averaged around each frame.
                                            Default for tracks: off. 1.0 = full interval; 0.5 = 180° shutter.
        --motion-samples   <n>              Renders averaged per motion-blurred frame, at evenly spaced instants across
                                            the shutter. Cost is N× a single render; too few show as discrete copies
                                            where the motion between instants exceeds a couple of pixels. Default: 16.
        --camera-track     <path>           Render a camera animation as a frame sequence: a supersplat editor project
                                            (.ssproj directory or its document.json), a viewer settings.json with
                                            animTracks, or a JSON { frameRate, frames: [{ position, target, fov, up }] }.
                                            Frames are written as <name>.NNNN.webp. Replaces --camera-pos/--camera-target;
                                            the track's target is the defocus focus point. A frame's up vector tilts the
                                            camera; frames without one use --camera-up. With --shutter, each frame is
                                            motion-blurred over that fraction of the frame interval.
        --frames           <a[-b]>          Inclusive frame range of the track to render. Default: all frames.
    

    Examples

    Basic Operations

    # Simple format conversion
    splat-transform input.ply output.csv
    
    # Convert from .splat format
    splat-transform input.splat output.ply
    
    # Convert from .ksplat format
    splat-transform input.ksplat output.ply
    
    # Convert to compressed PLY
    splat-transform input.ply output.compressed.ply
    
    # Uncompress a compressed PLY back to standard PLY
    # (compressed .ply is detected automatically on read)
    splat-transform input.compressed.ply output.ply
    
    # Convert to SOG bundled format
    splat-transform input.ply output.sog
    
    # Convert to SOG unbundled format
    splat-transform input.ply output/meta.json
    
    # Convert from SOG (bundled) back to PLY
    splat-transform scene.sog restored.ply
    
    # Convert from SOG (unbundled folder) back to PLY
    splat-transform output/meta.json restored.ply
    
    # Convert to standalone HTML viewer (bundled, single file)
    splat-transform input.ply output.html
    
    # Convert to unbundled HTML viewer (separate CSS, JS, and SOG files)
    splat-transform --unbundled input.ply output.html
    
    # Convert to HTML viewer with custom settings
    splat-transform --viewer-settings settings.json input.ply output.html
    

    Transformations

    # Scale and translate
    splat-transform bunny.ply -s 0.5 -t 0,0,10 bunny_scaled.ply
    
    # Rotate by 90 degrees around Y axis
    splat-transform input.ply -r 0,90,0 output.ply
    
    # Chain multiple transformations
    splat-transform input.ply -s 2 -t 1,0,0 -r 0,0,45 output.ply
    

    Filtering

    # Remove entries containing NaN and Inf
    splat-transform input.ply --filter-nan output.ply
    
    # Filter by opacity values (keep only splats with opacity > 0.5)
    splat-transform input.ply -V opacity,gt,0.5 output.ply
    
    # Strip spherical harmonic bands higher than 2
    splat-transform input.ply --filter-harmonics 2 output.ply
    
    # Simplify to 50000 splats via progressive pairwise merging
    splat-transform input.ply --decimate 50000 output.ply
    
    # Simplify to 25% of original splat count
    splat-transform input.ply -d 25% output.ply
    

    Advanced Usage

    # Combine multiple files with different transforms
    splat-transform -w cloudA.ply -r 0,90,0 cloudB.ply -s 2 merged.compressed.ply
    
    # Apply final transformations to combined result
    splat-transform input1.ply input2.ply output.ply -t 0,0,10 -s 0.5
    

    Statistics

    Generate per-column statistics for data analysis or test validation:

    # Print stats, then write output
    splat-transform input.ply --stats output.ply
    
    # Print stats without writing a file (discard output)
    splat-transform input.ply --stats null
    
    # Print stats as JSON for scripting
    splat-transform input.ply --stats json null
    
    # Print stats before and after a transform
    splat-transform input.ply --stats -s 0.5 --stats output.ply
    

    The output starts with the file info block (including the gaussian verdict — false for a readable container that isn't splat data, such as a plain point-cloud PLY), followed by min, max, median, mean, stdDev, nanCount, infCount and a histogram for each column, one table per LOD. Each LOD also reports a fillRatio — total splat footprint area over the scene's robust (p1–p99) cross-section, approximately the average overdraw layer count: healthy scenes score in the ones-to-hundreds, while degenerate or adversarial scenes that would overwhelm a GPU with fill score orders of magnitude higher, making the value suitable for automated publish gating. A +Infinity scale propagates to an infinite ratio, which serializes as null in JSON — treat that as a reject. The JSON form is the same info fields plus a columnar per-LOD stats array. The stats are computed in a single streaming pass; the median is approximated from a 1024-bin histogram (error within ~1/1000 of the column's range), all other fields are exact.

    Generators (Beta)

    Generator scripts can be used to synthesize gaussian splat data. See gen-grid.mjs for an example.

    splat-transform gen-grid.mjs -p width=10,height=10,scale=10,color=0.1 scenes/grid.ply -w
    

    Voxel Format

    The voxel format stores sparse voxel octree data for collision detection. It consists of two files: .voxel.json (metadata) and .voxel.bin (binary octree data). Pass --collision-mesh to also emit a .collision.glb mesh derived from the voxel grid.

    For a step-by-step walkthrough of each option (with illustrations), see the Collision Mesh guide.

    Recommended pipeline
    splat-transform input.ply \
        --filter-cluster --seed-pos x,y,z \
        [--voxel-external-fill | --voxel-floor-fill] [--voxel-carve] \
        [--collision-mesh [smooth|faces]] \
        output.voxel.json
    

    --filter-cluster isolates the central scene and discards stray floaters before voxelization. --seed-pos is shared by --filter-cluster and the voxel fill/carve passes — set it once to a known-walkable point inside the scene.

    Interior scenes (rooms, indoor scans)

    Use --voxel-external-fill to seal the void around the room interior, then --voxel-carve to hollow out the navigable space:

    splat-transform room.ply \
        --filter-cluster --seed-pos 0,1,0 \
        --voxel-external-fill --voxel-carve \
        --collision-mesh room.voxel.json
    
    Exterior scenes (outdoor objects, terrain)

    Use --voxel-floor-fill to fill the ground beneath surfaces, optionally followed by --voxel-carve:

    splat-transform terrain.ply \
        --filter-cluster --seed-pos 0,0,0 \
        --voxel-floor-fill \
        --collision-mesh terrain.voxel.json
    
    Other examples
    # Voxelize with custom resolution and opacity threshold
    splat-transform --voxel-size 0.1 --voxel-opacity 0.3 input.ply output.voxel.json
    
    # Custom carve capsule (height, radius)
    splat-transform --seed-pos 1,0,0 --voxel-carve 2.0,0.3 input.ply output.voxel.json
    
    # Watertight voxel-face collision mesh
    splat-transform --collision-mesh faces input.ply output.voxel.json
    

    Image Rendering

    Render a splat scene to a lossless WebP image from a given camera view. Rendering runs on the GPU.

    # Default 1280x720 render
    splat-transform input.ply view.webp
    
    # Custom camera and resolution
    splat-transform input.ply view.webp \
        --camera-pos 2,1,-2 --camera-target 0,0,0 \
        --camera-fov 50 --resolution 1920x1080
    
    # Transparent background
    splat-transform input.ply view.webp --background 0,0,0,0
    
    # Defocus blur (focus on camera-target, f/2.8 aperture)
    splat-transform input.ply view.webp --f-stop 2.8
    
    # Smoother aperture sampling for strongly defocused edges
    splat-transform input.ply view.webp --f-stop 1 --dof-samples 64
    
    # Defocus with explicit focus distance and a smaller world scale
    splat-transform input.ply view.webp \
        --f-stop 2.8 --focus-distance 3 --sensor-size 0.1
    
    # 360° equirectangular panorama from camera position
    splat-transform input.ply pano.webp \
        --projection equirect --camera-pos 0,1,0 --camera-target 0,1,1
    
    # Camera motion blur (dolly from start to end pose over a 180° shutter, 16 instants averaged)
    splat-transform input.ply view.webp \
        --camera-pos 2,1,-2 --camera-pos-end 3,1,-2 \
        --shutter 0.5 --motion-samples 16
    

    Depth of field and motion blur resolve visibility separately for each sample, then average in linear light before encoding the final image. Reconstructed splat colours are treated as sRGB; transparent outputs use premultiplied linear colour during averaging. When both effects are enabled, each shutter instant uses --dof-samples aperture views.

    Device Selection for SOG Compression

    When compressing to SOG format, you can control which device (GPU or CPU) performs the compression:

    # List available GPU adapters
    splat-transform --list-gpus
    
    # Let WebGPU automatically choose the best GPU (default behavior)
    splat-transform input.ply output.sog
    
    # Explicitly select a GPU adapter by index
    splat-transform -g 0 input.ply output.sog  # Use first listed adapter
    splat-transform -g 1 input.ply output.sog  # Use second listed adapter
    
    # Use CPU for compression instead (much slower but always available)
    splat-transform -g cpu input.ply output.sog
    

    [!NOTE] When -g is not specified, WebGPU automatically selects the best available GPU. Use --list-gpus to list available adapters with their indices and names. The order and availability of adapters depends on your system and GPU drivers. Use -g <index> to select a specific adapter, or -g cpu to force CPU computation.

    [!WARNING] CPU compression can be significantly slower than GPU compression (often 5-10x slower). Use CPU mode only if GPU drivers are unavailable or problematic.

    Getting Help

    # Show version
    splat-transform --version
    
    # Show help
    splat-transform --help
    

    Library Usage

    SplatTransform exposes a programmatic API for reading, processing, and writing Gaussian splat data. Scenes flow through lazy, chunked ChunkSources, so resident memory is bounded by chunk size rather than scene size — the same pipeline the CLI uses to process scenes of hundreds of millions of Gaussians.

    import { Vec3 } from 'playcanvas';
    import {
        readFile,
        writeSource,
        getInputFormat,
        getOutputFormat,
        createChunkDataPool,
        processSourceBridged,
        UrlReadFileSystem,
        MemoryFileSystem
    } from '@playcanvas/splat-transform';
    
    // Read a PLY file from a URL as a lazy, chunked source
    const fileSystem = new UrlReadFileSystem('https://example.com/');
    const [source] = await readFile({
        filename: 'scene.ply',
        inputFormat: getInputFormat('scene.ply'),
        fileSystem
    });
    
    // Apply actions: transforms compose lazily, filters stream chunk-by-chunk
    const pool = createChunkDataPool();
    const processed = await processSourceBridged(source, [
        { kind: 'scale', value: 0.5 },
        { kind: 'translate', value: new Vec3(0, 1, 0) },
        { kind: 'filterNaN' }
    ], pool);
    
    // Stream the result to an in-memory PLY
    const memFs = new MemoryFileSystem();
    await writeSource({
        filename: 'output.ply',
        outputFormat: getOutputFormat('output.ply', {}),
        source: processed,
        pool,
        options: {}
    }, memFs);
    await processed.close();
    
    // Get the output data
    const outputBuffer = memFs.results.get('output.ply');
    

    [!NOTE] For the full walkthrough — key exports, file system abstractions, processing actions, custom logging — see the Library Usage guide. The TypeDoc reference for every export lives at api.playcanvas.com/splat-transform.