Supported Arrow Types
This page documents how Apache Arrow columns map to luma.gl GPU upload, vertex attributes, WebGPU storage bindings, and model-specific preparation helpers. For the generic GPU table ownership model, see GPU Table Lifecycle.
Apache Arrow Preliminaries
Apache Arrow has a rich type system that can represent a wide variety of binary data columns. A subset of these column types can be used directly as GPU vertex attribute data, meaning that such arrow columns can be uploaded efficiently to the GPU.
Apache Arrow supports primitive types like Float32, Uint32, and Uint8 that
describe the value stored in each row. It also supports fixed-length vectors of
these types with FixedSizeList. These scalar and fixed-length vector types map
directly to the memory layouts used by GPU vertex attributes.
Arrow also supports variable-length List columns. These are useful for data
such as polygons and paths, but they do not map directly to a single vertex
attribute without an additional conversion step. ArrowPathModel provides the
attribute-backed conversion for prepared Float32 XY, XYZ, and XYZM path coordinate
rows, expanding each logical path into segment instances while keeping row-level
style columns at the path boundary. ArrowStoragePathModel provides the WebGPU
storage-backed form: compute expands GPU-resident path values into compact indexed
segment records from copied list-offset metadata, render shaders fetch coordinates
from the original path-value storage buffer, and per-path style rows remain storage
bindings instead of being repeated for every generated segment. Use
ArrowPathModel.prepareGPUVectors() or prepareArrowPathGPUVectors() to turn raw
Float32 or Float64 Arrow path vectors into prepared attribute-path inputs. Use
ArrowStoragePathModel.prepareGPUVectors() or prepareArrowStoragePathGPUVectors()
when WebGPU storage rendering should convert Float64 path payloads into Float32
deltas on the GPU before rendering.
Arrow Column Support
Support depends on how the column is consumed. A column can be uploadable as a
GPUVector without also being usable as a generic vertex attribute.
Arrow adapters publish GPUVector.format strings from
@luma.gl/tables. Arrow
DataType values are retained only as adapter/readback metadata during
migration.
| Arrow column pattern | GPUVector format | Generic BufferLayout |
|---|---|---|
Float32 | float32 | yes |
FixedSizeList<Float32, 3> | float32x3 | yes |
FixedSizeList<Uint8, 4> as normalized color | unorm8x4 | yes |
List<FixedSizeList<Float32, 3>> path coordinates | vertex-list<float32x3> | no |
List<FixedSizeList<Uint8, 4>> vertex colors | vertex-list<unorm8x4> | no |
vertex-list<...> vectors keep source row boundaries through list-offset
metadata owned by the producing adapter. They are not automatically exposed as
ordinary vertex attributes; path, text, polygon, and geometry adapters must
expand them or bind their flattened values explicitly.
Status: ✅ directly supported, 🟡 conditionally supported, ❌ not supported.
The nullable column refers to columns with actual null rows, not just nullable
schema fields with nullCount: 0.
Scalar-valued Columns
| Arrow data type | GPU upload | nullable | Upload notes | Shader-facing use | Higher-level model support |
|---|---|---|---|---|---|
Int8 | Uint8 | Int16 | Uint16 |Int32 | Uint32 | Float16 | Float32 | ✅ | ❌ | Scalar GPUVector or selected GPUTable columns. | Scalar attributes or storage rows, subject to shader type and vertex format compatibility. | Numeric table workflows and scalar style rows such as text angles, text sizes, and path widths. |
Float64 | 🟡 | ❌ | Raw values can be copied into a GPUVector, but generic render paths should repack them to Float32, origin-relative Float32, or u32 word pairs at preparation boundaries. | No generic f64 vertex attribute or WGSL scalar path; use prepared Float32 values or custom word-pair helpers. | Matrix columns truncate to Float32; Float64 paths become per-row Float32 deltas plus retained origins. |
Uint64 carrying DGGS cell keys | 🟡 | ❌ | DGGS WebGPU helpers retain Uint64 rows as word-pair storage. | Read through DGGS WGSL helpers or expand through prepareDggsCellPathGPUVector(); not a generic vertex attribute. | Global grid cell keys parsed from UTF-8 geohash, quadkey, S2, A5, or H3 IDs. |
Bool | ❌ | ❌ | Arrow Bool values are bit-packed, so they are not a directly uploadable scalar buffer. Repack to Uint8 or Uint32 when shaders need flags. | Use as integer 0/1 flags after repacking; otherwise keep on CPU as row metadata. | closeArrowPaths() accepts Vector<Bool> closed-path flags as CPU input; a future adapter could publish repacked flag columns. |
Vector-valued Columns
| Arrow data type | GPU upload | nullable | Upload notes | Shader-facing use | Higher-level model support |
|---|---|---|---|---|---|
FixedSizeList<numeric,1 | 2 | 3 | 4> | ✅ | ❌ | Fixed-width GPU rows. Planned color adapter support will expand three-component RGB source rows to four-component RGBA rows. FixedSizeList<Float16, 4> is the compact scene-linear/HDR color form. | Vector attributes or storage rows; 3-component 8-bit and 16-bit integer formats are WebGL-only unless padded. | Positions, point rows, normalized colors, scene-linear/HDR colors, pixel offsets, clip rectangles, mesh attributes, and path style rows. |
List<FixedSizeList<Float32,2 | 3 | 4>> | ✅ | ❌ | Flattened GPU path-coordinate values plus copied list-offset metadata. | Not a single generic vertex attribute.ArrowPathModel expands to segment attributes; ArrowStoragePathModel keeps values in storage. | ArrowPathModel.prepareGPUVectors() uploads unchanged unless closed-path normalization is requested.Outputs feed ArrowPathModel and ArrowStoragePathModel. |
List<FixedSizeList<Float64,2 | 3 | 4>> | 🟡 | ❌ | Path preparation emits per-row Float32 deltas plus copied list-offset metadata. CPU Float64 per-row origins are retained separately. | Not a generic vertex attribute. Attribute paths prepare deltas on CPU; WebGPU storage paths can prepare them on GPU before rendering. | ArrowPathModel.prepareGPUVectors() and prepareArrowPathGPUVectors() prepare attribute paths.ArrowStoragePathModel.prepareGPUVectors() prepares storage paths. |
List<numeric |FixedSizeList<numeric, 1 | 2 | 3 | 4>> | ✅ | ❌ | Flattened GPU values plus copied list-offset metadata. | Not a single generic vertex attribute; consume through storage/compute code or model-specific expansion. | Generic variable-length numeric storage/readback. Model support is documented by the model-specific rows above. |
The Points example demonstrates FixedSizeList<Float32, 2 | 3 | 4>
and DenseUnion point rows, including M-coordinate or timestamp animation and hover
identity labels. The Lines example demonstrates
DenseUnion line rows and polygon outlines by normalizing them into prepared line rows
before the path models consume them. The GeoArrow example
routes a mixed DenseUnion geometry column through point, line, and polygon renderers.
Matrix-valued Columns
| Arrow data type | GPU upload | nullable | Upload notes | Shader-facing use | Higher-level model support |
|---|---|---|---|---|---|
FixedSizeList<Float32 | Float64, 4>with visgl: mat2x2 metadata | 🟡 | ❌ | Through prepareArrowMatrixGPUVector().Canonical output is Float32 column-major wgsl-storage; Float64 truncates to Float32. | mat2x2<f32> storage rows or two lowered matrix-column attributes. | Compact 2D linear transforms. |
FixedSizeList<Float32 | Float64, 6>with visgl: mat2x3 metadata | 🟡 | ❌ | Through prepareArrowMatrixGPUVector().Packed 6-value sources normalize to 8-value Float32 WGSL-storage rows. | mat2x3<f32> storage rows or two lowered matrix-column attributes with WGSL three-row padding. | 2-column affine-style transforms with three row components. |
FixedSizeList<Float32 | Float64, 6>with visgl: mat3x2 metadata | 🟡 | ❌ | Through prepareArrowMatrixGPUVector().Canonical output is Float32 column-major wgsl-storage; Float64 truncates to Float32. | mat3x2<f32> storage rows or three lowered matrix-column attributes. | Three-column transforms with two row components. |
FixedSizeList<Float32 | Float64, 9>with visgl: mat3x3 metadata | 🟡 | ❌ | Through prepareArrowMatrixGPUVector().Packed 9-value sources normalize to 12-value Float32 WGSL-storage rows. | mat3x3<f32> storage rows or three lowered matrix-column attributes with WGSL three-row padding. | 2D/3D linear transforms and rotation/scale bases. |
FixedSizeList<Float32 | Float64, 12>with visgl: mat4x3 metadata | 🟡 | ❌ | Through prepareArrowMatrixGPUVector().Packed 12-value sources normalize to 16-value Float32 WGSL-storage rows. | mat4x3<f32> storage rows or four lowered matrix-column attributes with WGSL three-row padding. | deck.gl SimpleMeshLayer and ScenegraphLayer use this affine GPU payload: three model-matrix vec3 columns plus one translation vec3. |
FixedSizeList<Float32 | Float64, 12>with visgl: mat3x4 metadata | 🟡 | ❌ | Through prepareArrowMatrixGPUVector().Canonical output is Float32 column-major wgsl-storage; Float64 truncates to Float32. | mat3x4<f32> storage rows or three lowered matrix-column attributes. | Three-column transforms with four row components. |
FixedSizeList<Float32 | Float64, 16>with visgl: mat4x4 metadata | 🟡 | ❌ | Through prepareArrowMatrixGPUVector().Canonical output is Float32 column-major wgsl-storage; Float64 truncates to Float32. | mat4x4<f32> storage rows or four lowered matrix-column attributes. | Full homogeneous 3D transforms. |
Time-valued Columns
| Arrow data type | GPU upload | nullable | Upload notes | Shader-facing use | Higher-level model support |
|---|---|---|---|---|---|
Date | Time | Timestamp | Duration | 🟡 | ❌ | Through prepareArrowTemporalGPUVector().Emits relative Float32 values plus persisted temporal origin metadata. | Scalar relative-time attributes or storage rows in the source Arrow unit. | Animated or filtered rows; see Time Columns and Blinking Stars. |
List<Date | Time |Timestamp | Duration> | 🟡 | ❌ | Through prepareArrowTemporalGPUVector().Preserves list offsets while emitting relative List<Float32> values. | Not a single generic vertex attribute; consume through storage/compute code or model-specific expansion. | Trips-style per-path timestamp streams aligned with path vertices, including ArrowStorageTripsPathModel. |
Interval | ❌ | ❌ | Interval is compound calendar/time data, not one scalar time value.There is no single preserved unit or origin subtraction rule for prepareArrowTemporalGPUVector(). | Not supported as a generic scalar temporal attribute or storage row. | Deferred; callers should lower intervals into application-defined scalar columns. |
List<Interval> | ❌ | ❌ | The leaf interval has unresolved compound/calendar semantics, and the list form needs a model-specific variable-length consumption path. | Not supported as generic temporal storage or Trips-style timestamps. | Deferred; Trips-style streams require scalar Date, Time, Timestamp, or Duration leaves. |
Text-valued Columns
| Arrow data type | GPU upload | nullable | Upload notes | Shader-facing use | Higher-level model support |
|---|---|---|---|---|---|
Utf8 | 🟡 | 🟡 | UTF-8 value bytes plus readback metadata; null bitmaps are retained for readback, not generic shader use. | Not a generic vertex attribute; consume through text-specific UTF-8 and glyph expansion, or parse DGGS cell keys through prepareDggsCellKeyGPUVector() when the encoding is supplied. | Arrow text conversion helpers, pure text models, and DGGS key parsing. |
Dictionary<Utf8, Int8 | Int16 | Int32 |Uint8 | Uint16 | Uint32> | 🟡 | ❌ | Dictionary index rows. Callers keep CPU source vectors for dictionary values when glyph layout needs them. | Not a generic vertex attribute; consume through dictionary-aware text expansion. | Arrow text conversion helpers and dictionary text models. |
Other Columns
| Arrow data type | GPU upload | nullable | Upload notes | Shader-facing use | Higher-level model support |
|---|---|---|---|---|---|
Binary | ❌ | ❌ | Variable-width byte rows need both offsets and value bytes. Support would mirror UTF-8 with explicit offset and byte-buffer bindings. | Compute shaders could consume offsets and bytes; not a generic vertex attribute. | Adapter-specific payloads such as WKB geometry, compressed attributes, or binary IDs. |
FixedSizeBinary | 🟡 | ❌ | Partially supported for interleaved data columns where each row is a fixed-width byte record. | Not a generic scalar/vector attribute; consume through an explicit interleaved buffer layout or storage decoding path. | Interleaved GPU buffers and packed application-defined row records. |
Struct | 🟡 | ❌ | Supported indirectly when the application selects supported child columns by field path. | Child fields can become separate shader columns after selection or flattening. | Nested style/object columns; GeoArrow separated coordinates can adapt into FixedSizeList values. |
Map | ❌ | ❌ | Map is variable-length key/value Struct data. A future adapter could support maps by reading a specific key from each row. | Not a generic shader column; use application-specific key selection or compute lookup after an adapter lowers the map shape. | Per-row properties or sparse attributes after application-specific lowering. |
Decimal | ❌ | ❌ | Decimal stores scaled fixed-width integers with precision/scale semantics. Support likely requires conversion to Float32/Float64 or packed integer words plus scale metadata. | No generic decimal arithmetic path in shaders. | Financial or exact values should be lowered by the application before upload. |
LargeUtf8 | ❌ | ❌ | Uses 64-bit offsets; current text paths assume regular Utf8 offsets. Support could downcast offsets when value buffers fit Uint32, or add 64-bit offset helpers. | Text shaders could consume after offset normalization; not a generic vertex attribute. | Large text columns once normalized to Utf8-style offset buffers. |
Dictionary non-Utf8 | ❌ | ❌ | Uploading only dictionary indices loses value semantics. Support needs an adapter that uploads indices plus dictionary value buffers, or lowers values to numeric/text columns. | Shader use depends on the decoded value type or explicit lookup tables. | Categorical values, palettes, and enums after dictionary-specific lowering. |
The Time Columns example prepares aligned
DateDay, TimeMillisecond, TimestampMillisecond, and
DurationMillisecond event rows together with prepareArrowTemporalGPUVectors(),
then renders the same relative Float32 columns as instanced attributes or
WebGPU storage rows. The Blinking Stars example
uses aligned TimestampMillisecond and DurationMillisecond rows as per-instance
visibility windows and pulse periods through the same attribute/storage modes.
The path example remains the separate variable-length
List<FixedSizeList<Float32, 4>>, DenseUnion LineString, and List<Timestamp>
Trips-style stream example.
Shader and Buffer Layout Preliminaries
luma.gl provides separate descriptions of shader attributes and the buffers that
provide data for those attributes. The key observation here is that shaders only
work with four vertex attribute scalar types (f32, f16, i32, and u32),
and there is some flexibility in what binary buffer layouts can feed these
declarations.
ShaderLayoutdescribes what the shader can accept, such asvec4<f32>.BufferLayoutdescribes how the current table column is stored in memory, such asfloat32x4,float16x4, orunorm8x4.
This means the shader does not need to be written specifically for every memory representation. A shader attribute is declared using the type used in the shader source code:
const shaderLayout = {
attributes: [{name: 'colors', location: 0, type: 'vec4<f32>'}],
bindings: []
};
Then different Arrow table schemas can use different buffer layouts. For the
vec4<f32> described in the shader layout, the following buffer formats are all
accepted by the GPU.
| Arrow column type | Buffer layout format | Notes |
|---|---|---|
FixedSizeList<Float32, 4> | float32x4 | |
FixedSizeList<Float16, 4> | float16x4 | Shader sees f32; compact scene-linear/HDR color |
FixedSizeList<Int16, 4> | snorm16x4 | Shader sees f32, normalized to [-1.0, 1.0] |
FixedSizeList<Uint16, 4> | unorm16x4 | |
FixedSizeList<Int8, 4> | snorm8x4 | |
FixedSizeList<Uint8, 4> | unorm8x4 |
Semantic RGB color columns use three source components, but most luma.gl color
shader interfaces consume RGBA. Current semantic color adapters treat RGB source
forms as unsupported until expansion is implemented. The intended expansion is
FixedSizeList<Uint8, 3> to RGBA with alpha 255, and
FixedSizeList<Float16 | Float32, 3> to RGBA with alpha 1.0, before buffer
layout generation. Alpha values above 1.0 have no portable meaning unless a
layer explicitly defines application-specific semantics.
Creating a BufferLayout
Use getArrowBufferLayout() with an Arrow table when Arrow column names match
shader attribute names:
import {getArrowBufferLayout} from '@luma.gl/arrow';
const bufferLayout = getArrowBufferLayout(shaderLayout, {
arrowTable: table,
arrowPaths: {
instanceColors: 'properties.color'
}
});
const model = new Model(device, {
vs,
fs,
shaderLayout,
bufferLayout,
vertexCount
});
You can also provide Arrow vectors directly. In this mode, object keys are shader attribute names:
const bufferLayout = getArrowBufferLayout(shaderLayout, {
arrowVectors: {
instanceColors: table.getChild('properties').getChild('color')
}
});
The generated layouts use shader attribute names as buffer names:
[
{name: 'instanceColors', format: 'unorm8x4'}
]
Choosing a Columnar GPU Shape
The main decision is how the shader should read each selected Arrow column.
| GPU-facing shape | Use when | Typical Arrow input |
|---|---|---|
| Vertex attribute | Render or WebGL transform shaders should use fixed scalar/vector inputs | Scalar numeric columns or 2-, 3-, and 4-component fixed-size lists |
| Storage binding | WebGPU render or compute shaders should read/write column arrays directly | Numeric vectors that map cleanly to WGSL storage values |
| Matrix record | One logical matrix should stay one storage binding on WebGPU but split into vector attributes where needed | Arrow matrix vectors created by makeArrowMatrix*Vector() |
| Expanded vector | A compact lookup table must become one row per vertex/instance for attribute paths | expandArrowVector() plus an integer row map |
Use Buffer Schemas and Columnar Records when one logical row needs several attribute views or when you want record-oriented naming that also makes sense next to WGSL storage structs.
The GPU representation does not always stay byte-for-byte identical to the source Arrow representation:
- attribute paths may expand one logical row into several vertex or instance records so draw-time buffers match shader stepping;
- storage paths may need type or layout conversion before data becomes WGSL-compatible storage;
- device buffer-size limits can require preserved or synthetic batching instead of one monolithic GPU upload.
Matrix Columns
@luma.gl/arrow provides explicit matrix vector helpers for the WGSL floating
point matrix shapes used by GPU table workflows:
| Helper | Logical shape |
|---|---|
makeArrowMatrix2x2Vector() | mat2x2<f32> |
makeArrowMatrix2x3Vector() | mat2x3<f32> |
makeArrowMatrix3x2Vector() | mat3x2<f32> |
makeArrowMatrix3x3Vector() | mat3x3<f32> |
makeArrowMatrix4x3Vector() | mat4x3<f32> |
makeArrowMatrix3x4Vector() | mat3x4<f32> |
makeArrowMatrix4x4Vector() | mat4x4<f32> |
The generic makeArrowMatrixVector(shape, values, options) form is available
when the shape is selected dynamically.
import {makeArrowMatrix4x4Vector} from '@luma.gl/arrow';
const instanceModelMatrix = makeArrowMatrix4x4Vector(matrixValues, {
order: 'column-major',
layout: 'wgsl-storage'
});
Matrix options:
| Option | Values | Default | Meaning |
|---|---|---|---|
order | 'column-major' | 'row-major' | 'column-major' | Order of the supplied logical matrix values. GPU-facing vectors are normalized to column-major order. |
layout | 'wgsl-storage' | 'packed' | 'wgsl-storage' | Physical row layout. Three-row matrix columns are padded to four floats for WGSL-compatible storage layout. |
getArrowMatrixVectorInfo(vector) recovers the stored matrix metadata, including
shape, row/column counts, matrix order, physical component count, column stride,
value type, and byte stride. prepareArrowMatrixGPUVector() accepts metadata-tagged
FixedSizeList<Float32> and FixedSizeList<Float64> matrix columns, then emits
canonical Float32 WGSL-storage rows for attribute or storage-buffer use.
deck.gl SimpleMeshLayer and ScenegraphLayer expose getTransformMatrix as a
4x4 accessor, but their attribute updater drops the final row and uploads three
vec3 model-matrix columns plus one vec3 translation. Arrow callers targeting
those layers can store that GPU-facing affine payload directly as mat4x3, or
accept a 4x4 source and explicitly truncate to the affine mat4x3 payload before
binding it.
Public matrix types:
| Type | Meaning |
|---|---|
ArrowMatrixShape | Supported shape identifier such as 'mat4x4'. |
ArrowMatrixOrder | Input value order: 'column-major' or 'row-major'. |
ArrowMatrixLayout | Physical vector layout: 'wgsl-storage' or 'packed'. |
ArrowMatrixVectorOptions | Options accepted by the matrix builders. |
ArrowMatrixVectorInfo | Metadata recovered by getArrowMatrixVectorInfo(). |
ArrowFloat32Matrix2x2 through ArrowFloat32Matrix4x4 | Fixed-size Arrow row types for each supported matrix shape. |
One Matrix Column, Two Consumption Paths
On WebGPU, one matrix Arrow column can remain one storage binding:
const shaderLayout = {
attributes: [],
bindings: [
{
name: 'instanceModelMatrix',
type: 'read-only-storage',
group: 0,
location: 0
}
]
};
@group(0) @binding(auto)
var<storage, read> instanceModelMatrix: array<mat4x4<f32>>;
On attribute-oriented paths, map each vector attribute back to the same matrix column:
const shaderLayout = {
attributes: [
{name: 'instanceModelMatrixCol0', location: 0, type: 'vec4<f32>'},
{name: 'instanceModelMatrixCol1', location: 1, type: 'vec4<f32>'},
{name: 'instanceModelMatrixCol2', location: 2, type: 'vec4<f32>'},
{name: 'instanceModelMatrixCol3', location: 3, type: 'vec4<f32>'}
],
bindings: []
};
const bufferLayout = getArrowBufferLayout(shaderLayout, {
arrowTable,
arrowPaths: {
instanceModelMatrixCol0: 'instanceModelMatrix',
instanceModelMatrixCol1: 'instanceModelMatrix',
instanceModelMatrixCol2: 'instanceModelMatrix',
instanceModelMatrixCol3: 'instanceModelMatrix'
}
});
The Arrow helper recognizes the matrix metadata and lowers the matrix row through
the engine BufferSchema path into
one shared interleaved buffer layout.
Temporal Columns
prepareArrowTemporalGPUVector() and prepareArrowTemporalGPUVectors() normalize
supported Arrow temporal logical columns into relative Float32 GPU vectors while
retaining the original Arrow unit:
const preparedTemporalColumns = await prepareArrowTemporalGPUVectors(device, {
eventStarts,
eventDurations
});
const eventTable = new GPUTable({
vectors: {
eventStarts: preparedTemporalColumns.eventStarts.temporal,
eventDurations: preparedTemporalColumns.eventDurations.temporal
}
});
Absolute Date, Time, and Timestamp columns choose the first valid scalar
or flattened list value as their relative origin when prepared metadata does not
already carry one. Duration columns use origin 0. The chosen kind, unit,
origin, origin policy, and timestamp timezone metadata are persisted on the
prepared field so repeated transforms and append flows can reuse the same
comparison domain.
Prepared scalar temporal rows can be instanced attributes or WebGPU storage rows.
Prepared List<temporal> rows preserve list offsets and are intended for
storage/compute or model-specific expansion, such as
ArrowStorageTripsPathModel. Interval and List<Interval> are intentionally
deferred because Arrow interval leaves have compound calendar semantics rather
than one scalar source unit that can be origin-subtracted without an explicit
application contract.
DGGS Cell Keys
DGGS helpers provide a WebGPU-only path from compact global grid IDs to Uint64 key storage and rendered cell boundaries:
const preparedKeys = prepareDggsCellKeyGPUVector(device, cellIds, {
encoding: 'geohash'
});
const preparedPaths = prepareDggsCellPathGPUVector(device, preparedKeys.keys, {
encoding: 'geohash'
});
prepareDggsCellKeyGPUVector() accepts UTF-8 geohash, quadkey, S2, A5, or H3 IDs
and parses them on the GPU into Uint64 rows. prepareDggsCellPathGPUVector()
accepts those Uint64 rows and emits closed List<FixedSizeList<Float32, 2>>
boundary paths by default. Pass coordinateFormat: 'fp64-split' to emit
List<FixedSizeList<Float32, 4>> paths with components ordered as
[longitudeHigh, latitudeHigh, longitudeLow, latitudeLow]. This is a
compatibility layout only: DGGS boundary math currently remains Float32, so low
components are zero until true higher-precision decode math is added. The dggs
shader module exposes the matching WGSL Uint64 word order and cell-boundary
helpers when a shader should read keys directly. See the Global Grids
example.
Storage-Selected Table Columns
GPURecordBatch and GPUTable also select Arrow columns referenced by shader
bindings of type 'storage' or 'read-only-storage'. Selected storage columns:
- appear in
gpuVectorsby binding name; - appear in
bindingsby binding name; - contribute fields to the GPU-facing Arrow schema;
- are rebound batch-by-batch by
GPUTableModel.drawBatches(renderPass).
This keeps table-backed WebGPU render paths compact. A column such as
instanceModelMatrix can be uploaded once through the table machinery and bound
directly to a WGSL storage array without four separate matrix-column bindings.
Storage-selected columns and attribute-selected columns must use distinct shader
input names. A single name cannot be both an attribute and a storage binding in
one GPURecordBatch.
Expanding Compact Column Values
expandArrowVector(vector, rowMapping, nullValue?) gathers rows from one numeric
Arrow vector into a new contiguous Arrow vector. It accepts either an integer
typed array or an integer Arrow vector as the row mapping.
Use it when a compact table should become vertex- or instance-aligned data for an
attribute path. The Matrices: FixedSizeList<Float32, 16> example uses
this idea for WebGL face colors: a six-row face-color vector is expanded by cube
faceIndex rows into a vertex-aligned color vector.
Supported source vectors:
- scalar numeric Arrow vectors;
FixedSizeListnumeric vectors.
The helper rejects unsupported vector types, non-integer row mappings, negative indices, and out-of-range indices.
ArrowVectorRowMapping is the exported type name for the accepted mapping input.
ArrowVectorNullValue is the exported type name for the optional null-row
fallback. Scalar numeric vectors accept a numeric nullValue.
FixedSizeList numeric vectors accept an array-like nullValue with exactly the
list size number of components. If nullValue is omitted, null source rows keep
the existing values-buffer copy behavior.
For FixedSizeList vectors, the parent row may be nullable and will expand to
the supplied constant fallback. Nullable child values inside valid rows are not
supported by this helper.
Closing Nested Arrow Paths
closeArrowPaths() turns logical closed-path flags into explicit closing
vertices without mutating the input vector. The helper accepts GPU-resident
List<FixedSizeList<Float32>> path rows with one to four components per vertex,
an Arrow Bool vector with one closed flag per row, and a non-negative epsilon.
Those Float32 rows can be absolute path coordinates or origin-relative delta
coordinates produced from Float64 path preparation.
import {closeArrowPaths} from '@luma.gl/arrow';
const normalizedPaths = await closeArrowPaths(device, {
paths,
closed,
epsilon: 1e-5
});
The output preserves Arrow chunk boundaries. Open rows, rows already closed
within epsilon, empty rows, and single-point rows are unchanged. Closed rows
whose first and last vertices differ receive one appended copy of the first
vertex. For Float64 source paths, closure happens after CPU conversion to
delta space; if the original last point equals the first, both deltas are zero,
and injected closing vertices append the first delta, usually [0, 0, ...].
Preparing Arrow Paths for Rendering
Use ArrowPathModel.prepareGPUVectors() when raw Arrow vectors need to become
attribute-renderer inputs. Float32 paths upload unchanged unless closed flags
are supplied. Float64 paths are converted on the CPU into stable per-row Float32
deltas from the first point of each path. The prepared object also owns CPU
Float64 origins and updates view-space origin buffers when the view or model
matrix changes.
const prepared = await ArrowPathModel.prepareGPUVectors(device, {
paths,
colors,
widths,
closed
}, {
closeEpsilon: 1e-5
});
const pathModel = new ArrowPathModel(device, prepared.pathProps);
const storagePathModel = new ArrowStoragePathModel(device, prepared.storagePathProps);
prepared.updateViewOrigins({modelViewMatrix});
pathModel.destroy();
storagePathModel.destroy();
prepared.destroy();
For storage-only WebGPU paths, use the storage preparation entrypoint instead:
const preparedStorage = await ArrowStoragePathModel.prepareGPUVectors(device, {
paths,
colors,
widths,
closed
}, {
closeEpsilon: 1e-5
});
const storagePathModel = new ArrowStoragePathModel(device, preparedStorage.storagePathProps);
That path uploads raw Float64 list payloads temporarily, converts them once into
Float32 per-row deltas with sub_fp64u32_to_f32, then discards the transient
Float64 GPU upload before returning the prepared storage props.
Path constructors stay GPUVector/prepared-state only; raw Arrow path vectors
belong at the preparation boundary. For Float64 paths, shaders should transform
deltas with a zero homogeneous component and add the CPU-updated view origin
before projection.
ArrowStoragePathModel keeps the default storage path record compact: each
generated segment stores three u32 words (segmentStartPointIndex,
segmentFlags, and globalRowIndex) plus a persistent vec4<u32> path range
per source row. The storage shader receives pathRanges automatically and can
derive end, previous, and next point indices from those ranges and flags.
Custom storage shader layouts that request segmentEndPointIndices,
segmentPreviousPointIndices, or segmentNextPointIndices keep the legacy
six-word segment record layout.
GPUTableModel is the generic tables-layer wrapper that combines GPUTable
with Model. It draws preserved GPU batches, syncs table row counts into the
selected draw count, and leaves table ownership with the caller. Convert Arrow
tables explicitly with makeGPUTableFromArrowTable() before constructing the model.
Use model.drawBatches(renderPass) to draw preserved static GPU batches with one
pipeline layout while rebinding only batch-local attribute buffers and storage
bindings. Packed tables naturally reduce that to fewer draw calls.
Mesh Arrow Geometry
GPUTableGeometry exposes one packed static GPUTable as GPUGeometry.
ArrowTableGeometry and makeGPUGeometryFromArrow() convert loaders.gl-
compatible Mesh Arrow tables into that generic geometry surface. These helpers
support mesh and point-cloud tables that use glTF-style column names such as
POSITION, NORMAL, COLOR_0, and TEXCOORD_0.
import {
ArrowTableGeometry,
makeGPUGeometryFromArrow,
type ArrowMeshTable
} from '@luma.gl/arrow';
import {Model} from '@luma.gl/engine';
const geometry = new ArrowTableGeometry(device, {
arrowMesh,
interleaved: true
});
const equivalentGeometry = makeGPUGeometryFromArrow(device, {
arrowMesh,
interleaved: true
});
const model = new Model(device, {
vs,
fs,
shaderLayout,
geometry
});
The local ArrowMeshTable type is structural and does not add a dependency on
loaders.gl. It intentionally mirrors loaders.gl MeshArrowTable: a wrapper with
shape: 'arrow-table', topology, optional top-level indices, and raw
data: arrow.Table.
Mesh Arrow tables use one row per vertex. Vertex attributes are scalar numeric
or FixedSizeList<numeric, 1 | 2 | 3 | 4> columns. ArrowTableGeometry
normalizes common glTF semantics to luma.gl shader attribute names:
| Mesh Arrow column | Shader attribute |
|---|---|
POSITION | positions |
NORMAL | normals |
COLOR_0 | colors |
TEXCOORD_0 | texCoords |
TEXCOORD_1 | texCoords1 |
Unknown column names are preserved unless arrowPaths maps a shader attribute
name to a specific Arrow column name.
Indexed Mesh Arrow tables follow the loaders.gl convention: a lowercase
indices: List<Int32> column stores the full primitive index list in row 0,
and remaining vertex rows are null. ArrowTableGeometry uploads those indices
as a separate GPU index buffer. If the wrapper has a top-level indices
accessor and the Arrow table has no indices column, that accessor is used as a
fallback.
By default, ArrowTableGeometry packs all selected vertex attributes into one
interleaved vertex buffer and keeps indices separate. Pass interleaved: false
to upload one vertex buffer per attribute.
Streaming sources stay application-owned. Convert each yielded Arrow record
batch once, keep the resulting immutable GPURecordBatch, and add it to the
retained GPUTable:
import {makeGPURecordBatchFromArrowRecordBatch, makeGPUTableFromArrowTable} from '@luma.gl/arrow';
const gpuTable = makeGPUTableFromArrowTable(device, new arrow.Table([firstRecordBatch]), {
shaderLayout
});
for await (const recordBatch of remainingRecordBatches) {
gpuTable.addBatch(makeGPURecordBatchFromArrowRecordBatch(device, recordBatch, {shaderLayout}));
model.setInstanceCount(gpuTable.numRows);
}
Text and other generated-geometry paths can then expand each preserved source
GPU batch independently, and may fan one source GPURecordBatch out into
multiple generated render batches when device buffer limits require splitting.
Supported Shader Types
Arrow scalar numeric columns map to scalar shader attributes. Arrow
FixedSizeList<numeric, 2 | 3 | 4> columns map to vector shader attributes.
| Shader attribute type | Portable Arrow columns |
|---|---|
f32 | Float32, Float16, Int8, Uint8, Int16, Uint16 |
vec2<f32> | FixedSizeList<Float32, 2>, FixedSizeList<Float16, 2>, FixedSizeList<Int8, 2>, FixedSizeList<Uint8, 2>, FixedSizeList<Int16, 2>, FixedSizeList<Uint16, 2> |
vec3<f32> | FixedSizeList<Float32, 3> |
vec4<f32> | FixedSizeList<Float32, 4>, FixedSizeList<Float16, 4>, FixedSizeList<Int8, 4>, FixedSizeList<Uint8, 4>, FixedSizeList<Int16, 4>, FixedSizeList<Uint16, 4> |
f16 | Float16, Int8, Uint8, Int16, Uint16 |
vec2<f16> | FixedSizeList<Float16, 2>, FixedSizeList<Int8, 2>, FixedSizeList<Uint8, 2>, FixedSizeList<Int16, 2>, FixedSizeList<Uint16, 2> |
vec3<f16> | None in portable WebGPU layouts |
vec4<f16> | FixedSizeList<Float16, 4>, FixedSizeList<Int8, 4>, FixedSizeList<Uint8, 4>, FixedSizeList<Int16, 4>, FixedSizeList<Uint16, 4> |
i32 | Int8, Int16, Int32 |
vec2<i32> | FixedSizeList<Int8, 2>, FixedSizeList<Int16, 2>, FixedSizeList<Int32, 2> |
vec3<i32> | FixedSizeList<Int32, 3> |
vec4<i32> | FixedSizeList<Int8, 4>, FixedSizeList<Int16, 4>, FixedSizeList<Int32, 4> |
u32 | Uint8, Uint16, Uint32 |
vec2<u32> | FixedSizeList<Uint8, 2>, FixedSizeList<Uint16, 2>, FixedSizeList<Uint32, 2> |
vec3<u32> | FixedSizeList<Uint32, 3> |
vec4<u32> | FixedSizeList<Uint8, 4>, FixedSizeList<Uint16, 4>, FixedSizeList<Uint32, 4> |
Component counts must match. For example, FixedSizeList<Uint8, 4> can feed
vec4<f32>, but not vec3<f32>.
For f32 and f16 shader attributes, integer Arrow columns are read through
normalized vertex formats (snorm* for signed integers and unorm* for unsigned
integers).
WebGPU Portability
WebGPU does not support every vertex format that WebGL can read. In particular,
3-component 8-bit and 16-bit integer-backed columns are not portable. By default,
getArrowBufferLayout() rejects those mappings with an error.
Shaders that declare f16 attributes have an additional capability requirement.
Before creating a WebGPU device, check adapter.features.has('shader-f16'), request
that feature when creating the device, and include enable f16; in WGSL. Without
that feature, WebGPU rejects shader modules that use f16 types.
For WebGL-only use cases, opt in to WebGL-only formats:
const bufferLayout = getArrowBufferLayout(shaderLayout, {
arrowTable: table,
allowWebGLOnlyFormats: true
});
For portable WebGPU layouts, prefer Float32 for vec3<f32> attributes or pad
8-bit and 16-bit vector data to four components.