or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

application-management.mdattribute-management.mdcontrollers.mdcoordinate-systems.mdeffects-and-lighting.mdindex.mdlayer-system.mdtransitions-and-animation.mdutilities-and-helpers.mdviews-and-viewports.md
tile.json

attribute-management.mddocs/

Attribute Management

Efficient data-to-GPU attribute management system with automatic buffer updates, memory optimization, and seamless integration with WebGL vertex attributes for high-performance data visualization.

Capabilities

AttributeManager Class

Central manager for vertex attributes handling data transformation and GPU buffer management.

/**
 * Manages vertex attributes for layers
 * Handles data-to-attribute transformations and WebGL buffer management
 */
class AttributeManager {
  /** Initialize attribute manager */
  constructor(device: Device, opts?: AttributeManagerOptions);
  
  /** Add vertex attributes */
  add(attributes: Record<string, AttributeOptions>): void;
  
  /** Add instanced vertex attributes */
  addInstanced(attributes: Record<string, AttributeOptions>): void;
  
  /** Remove attributes by name */
  remove(attributeNames: string[]): void;
  
  /** Update attributes from data */
  update(opts: UpdateOptions): void;
  
  /** Mark attributes for update */
  invalidate(triggerName: string, range?: [number, number]): void;
  
  /** Mark all attributes invalid */
  invalidateAll(): void;
  
  /** Get all managed attributes */
  getAttributes(): Record<string, Attribute>;
  
  /** Get attributes that changed since last check */
  getChangedAttributes(opts?: {clearChangedFlags?: boolean}): Record<string, Attribute>;
  
  /** Get shared attribute accessor */
  getSharedAccessor(attributeName: string): any;
  
  /** Set shared attribute accessor */
  setSharedAccessor(attributeName: string, accessor: any): void;
  
  /** Check if any attribute needs update */
  needsUpdate(): boolean;
  
  /** Check if any attribute needs redraw */
  needsRedraw(opts?: {clearRedrawFlags?: boolean}): boolean;
  
  /** Get statistics */
  getStats(): AttributeManagerStats;
  
  /** Unique manager identifier */
  readonly id: string;
  
  /** Managed attributes */
  readonly attributes: Record<string, Attribute>;
  
  /** Whether attributes need redraw */
  readonly needsRedraw: boolean;
}

interface AttributeManagerOptions {
  /** Manager identifier */
  id?: string;
  
  /** Default accessor statistics */
  stats?: any;
  
  /** Data change detection */
  dataComparator?: (newData: any, oldData: any) => boolean;
}

interface AttributeOptions {
  /** Elements per vertex (1, 2, 3, or 4) */
  size: number;
  
  /** Data type */
  type?: 'float32' | 'uint8' | 'int8' | 'uint16' | 'int16' | 'uint32' | 'int32';
  
  /** Accessor function or property name */
  accessor?: string | AccessorFunction<any, any>;
  
  /** Default value when accessor returns undefined */
  defaultValue?: number | number[];
  
  /** Transform function for accessor results */
  transform?: (value: any, objectInfo: any) => any;
  
  /** Whether values should be normalized to [0,1] range */
  normalized?: boolean;
  
  /** Whether attribute is instanced */
  instanced?: boolean | number;
  
  /** Whether attribute should be updated */
  noAlloc?: boolean;
  
  /** Custom update function */
  update?: (attribute: Attribute, opts: any) => void;
  
  /** Buffer update settings */
  bufferLayout?: any;
  
  /** Shader attribute name */
  shaderAttribute?: string;
}

interface UpdateOptions {
  /** Number of data instances */
  numInstances?: number;
  
  /** Data array or source */
  data?: any;
  
  /** Layer properties */
  props?: any;
  
  /** Context information */
  context?: any;
  
  /** Buffer layout information */
  bufferLayout?: any;
  
  /** Partial range to update [start, end] */
  range?: [number, number];
  
  /** Additional parameters */
  [key: string]: any;
}

interface AttributeManagerStats {
  /** Total attributes managed */
  attributeCount: number;
  
  /** Total buffer memory used (bytes) */
  totalMemory: number;
  
  /** Number of attributes updated this frame */
  attributesUpdated: number;
  
  /** Time spent updating attributes (ms) */
  updateTime: number;
}

Usage Examples:

import { AttributeManager } from "@deck.gl/core";

// Create attribute manager for a custom layer
class MyLayer extends Layer {
  initializeState(context) {
    const {device} = context;
    
    const attributeManager = new AttributeManager(device, {
      id: 'my-layer-attributes'
    });
    
    // Add vertex attributes
    attributeManager.add({
      positions: {
        size: 3,
        type: 'float32',
        accessor: 'getPosition',
        update: this.calculatePositions
      },
      colors: {
        size: 4,
        type: 'uint8',
        normalized: true,
        accessor: 'getColor',
        defaultValue: [255, 0, 0, 255]
      },
      sizes: {
        size: 1,
        type: 'float32',
        accessor: 'getSize',
        defaultValue: 1,
        transform: (size, {index, data}) => size * data.scaleFactor
      }
    });
    
    // Add instanced attributes  
    attributeManager.addInstanced({
      instancePositions: {
        size: 3,
        accessor: 'getPosition'
      },
      instanceColors: {
        size: 4,
        type: 'uint8',
        normalized: true,
        accessor: 'getColor'
      }
    });
    
    this.setState({attributeManager});
  }
  
  updateState({props, oldProps, changeFlags}) {
    const {attributeManager} = this.state;
    
    if (changeFlags.dataChanged) {
      attributeManager.invalidateAll();
    }
    
    // Update specific attributes based on prop changes
    if (props.getPosition !== oldProps.getPosition) {
      attributeManager.invalidate('getPosition');
    }
    
    if (props.getColor !== oldProps.getColor) {
      attributeManager.invalidate('getColor');
    }
    
    // Update attributes with current data
    attributeManager.update({
      data: props.data,
      numInstances: props.data.length,
      props: props,
      context: this.context
    });
  }
  
  calculatePositions(attribute, {data, numInstances}) {
    const {value} = attribute;
    for (let i = 0; i < numInstances; i++) {
      const position = this.props.getPosition(data[i], {index: i, data, target: []});
      value[i * 3] = position[0];
      value[i * 3 + 1] = position[1]; 
      value[i * 3 + 2] = position[2] || 0;
    }
  }
}

Attribute Class

Represents a single vertex attribute managing data transformation and GPU buffer operations.

/**
 * Represents a single vertex attribute
 * Manages data transformation and GPU buffer operations
 */
class Attribute {
  /** Initialize attribute */
  constructor(device: Device, opts: AttributeCreationOptions);
  
  /** Check if attribute needs update */
  needsUpdate(): boolean;
  
  /** Check if attribute needs redraw */
  needsRedraw(opts?: {clearRedrawFlags?: boolean}): boolean;
  
  /** Allocate GPU buffer for specified number of instances */
  allocate(numInstances: number): void;
  
  /** Update buffer data */
  updateBuffer(opts: UpdateBufferOptions): void;
  
  /** Set constant value for all instances */
  setConstantValue(value: number | number[]): void;
  
  /** Update data using external buffer */
  setExternalBuffer(buffer: Buffer): void;
  
  /** Update partial data range */
  updateSubData(opts: UpdateSubDataOptions): void;
  
  /** Get buffer statistics */
  getBufferStats(): BufferStats;
  
  /** Delete and cleanup attribute */
  delete(): void;
  
  /** Attribute identifier */
  readonly id: string;
  
  /** Elements per vertex */
  readonly size: number;
  
  /** Data type */
  readonly type: string;
  
  /** Whether values are normalized */
  readonly normalized: boolean;
  
  /** Whether attribute is instanced */
  readonly instanced: boolean | number;
  
  /** Current attribute data */
  readonly value: TypedArray;
  
  /** GPU buffer */
  readonly buffer: Buffer;
  
  /** Whether attribute has constant value */
  readonly constant: boolean;
  
  /** Settings for buffer updates */
  readonly settings: AttributeSettings;
}

interface AttributeCreationOptions {
  /** Attribute identifier */
  id: string;
  
  /** Elements per vertex */
  size: number;
  
  /** Data type */
  type?: string;
  
  /** Whether values are normalized */
  normalized?: boolean;
  
  /** Whether attribute is instanced */
  instanced?: boolean | number;
  
  /** Initial buffer size */
  bufferSize?: number;
  
  /** Default value */
  defaultValue?: number | number[];
  
  /** Update function */
  update?: (attribute: Attribute, opts: any) => void;
  
  /** Additional settings */
  settings?: Partial<AttributeSettings>;
}

interface AttributeSettings {
  /** Whether to allocate buffer automatically */
  noAlloc: boolean;
  
  /** Buffer update frequency */
  updateFrequency: 'once' | 'dynamic' | 'stream';
  
  /** Whether attribute is per-instance */
  isIndexed: boolean;
  
  /** Shader attribute location */
  shaderLocation: number;
}

interface UpdateBufferOptions {
  /** Data to upload */
  data?: TypedArray;
  
  /** Number of instances */
  numInstances?: number;
  
  /** Byte offset in buffer */
  offset?: number;
  
  /** Number of bytes to update */
  size?: number;
  
  /** Partial range [start, end] */
  range?: [number, number];
}

interface UpdateSubDataOptions {
  /** Start index */
  startOffset: number;
  
  /** End index */
  endOffset: number;
  
  /** Data to upload */
  data: TypedArray;
}

interface BufferStats {
  /** Buffer size in bytes */
  byteSize: number;
  
  /** Number of elements */
  elementCount: number;
  
  /** Memory usage per element */
  bytesPerElement: number;
  
  /** Whether buffer is allocated */
  allocated: boolean;
}

Usage Examples:

import { Attribute } from "@deck.gl/core";

// Create custom attribute with manual management
class CustomLayer extends Layer {
  initializeState({device}) {
    // Manual attribute creation
    const positionAttribute = new Attribute(device, {
      id: 'positions',
      size: 3,
      type: 'float32',
      update: this.updatePositions.bind(this)
    });
    
    const colorAttribute = new Attribute(device, {
      id: 'colors', 
      size: 4,
      type: 'uint8',
      normalized: true,
      defaultValue: [255, 255, 255, 255]
    });
    
    this.setState({
      positionAttribute,
      colorAttribute
    });
  }
  
  updateState({props, changeFlags}) {
    const {positionAttribute, colorAttribute} = this.state;
    
    if (changeFlags.dataChanged) {
      const numInstances = props.data.length;
      
      // Allocate buffers
      positionAttribute.allocate(numInstances);
      colorAttribute.allocate(numInstances);
      
      // Update data
      positionAttribute.updateBuffer({
        numInstances,
        data: this.extractPositions(props.data)
      });
      
      colorAttribute.updateBuffer({
        numInstances,
        data: this.extractColors(props.data)
      });
    }
  }
  
  updatePositions(attribute, {data, numInstances}) {
    const positions = new Float32Array(numInstances * 3);
    
    for (let i = 0; i < numInstances; i++) {
      const pos = this.props.getPosition(data[i]);
      positions[i * 3] = pos[0];
      positions[i * 3 + 1] = pos[1];
      positions[i * 3 + 2] = pos[2] || 0;
    }
    
    return positions;
  }
  
  draw({uniforms}) {
    const {positionAttribute, colorAttribute} = this.state;
    
    // Use attributes in WebGL draw call
    this.state.model.draw(this.context.renderPass, {
      uniforms,
      attributes: {
        positions: positionAttribute,
        colors: colorAttribute
      }
    });
  }
}

Binary Attribute Support

Support for binary attribute data for high-performance applications.

/**
 * Binary attribute interface for direct GPU buffer management
 * Enables zero-copy data transfer for optimal performance
 */
interface BinaryAttribute {
  /** Buffer containing attribute data */
  buffer: ArrayBuffer;
  
  /** Byte offset within buffer */
  offset?: number;
  
  /** Byte stride between elements */
  stride?: number;
  
  /** Number of instances */
  size: number;
  
  /** Attribute value accessor */
  value?: TypedArray;
}

Transition and Animation Support

Built-in support for attribute transitions and animations.

interface AttributeTransitionSettings {
  /** Transition type */  
  type: 'interpolation' | 'spring' | 'gpu';
  
  /** Transition duration in milliseconds */
  duration?: number;
  
  /** Easing function */
  easing?: (t: number) => number;
  
  /** Called when transition starts */
  onStart?: () => void;
  
  /** Called during transition */
  onUpdate?: (t: number) => void;
  
  /** Called when transition ends */
  onEnd?: () => void;
  
  /** Whether to use GPU-based transitions */
  useGPU?: boolean;
}

interface TransitionManager {
  /** Start attribute transition */
  startTransition(
    attributeName: string, 
    fromValue: any, 
    toValue: any, 
    settings: AttributeTransitionSettings
  ): void;
  
  /** Update all active transitions */
  update(deltaTime: number): void;
  
  /** Cancel transition */
  cancelTransition(attributeName: string): void;
  
  /** Get transition progress */
  getTransitionProgress(attributeName: string): number;
}

Usage Examples:

// Attribute transitions
const layer = new ScatterplotLayer({
  id: 'animated-points',
  data: data,
  getPosition: d => d.coordinates,
  getRadius: d => d.radius,
  getColor: d => d.color,
  
  // Animate radius changes
  transitions: {
    getRadius: {
      type: 'interpolation',
      duration: 1000,
      easing: t => t * t, // quadratic easing
      onStart: () => console.log('Radius animation started'),
      onEnd: () => console.log('Radius animation completed')
    },
    
    // Spring animation for color changes
    getColor: {
      type: 'spring',
      stiffness: 0.1,
      damping: 0.8
    }
  }
});

// Update data with smooth transitions
layer.setProps({
  data: newData,
  updateTriggers: {
    getRadius: Math.random(), // Force radius recalculation
    getColor: Math.random()   // Force color recalculation
  }
});

Performance Optimization

Advanced features for optimizing attribute performance.

interface AttributePerformanceSettings {
  /** Whether to use typed array managers for memory pooling */
  useTypedArrayManager?: boolean;
  
  /** Buffer reuse strategy */
  bufferReuseStrategy?: 'never' | 'same-size' | 'larger';
  
  /** Whether to pack attributes in interleaved arrays */
  interleaved?: boolean;
  
  /** Target GPU memory usage limit */
  memoryLimit?: number;
  
  /** Batch size for partial updates */
  batchSize?: number;
}

Usage Examples:

// Optimized attribute manager for large datasets
const optimizedAttributeManager = new AttributeManager(device, {
  id: 'large-dataset-attributes',
  stats: new Stats({id: 'attributes'}),
  performanceSettings: {
    useTypedArrayManager: true,
    bufferReuseStrategy: 'larger',
    interleaved: true,
    memoryLimit: 1024 * 1024 * 100, // 100MB limit
    batchSize: 10000
  }
});

// Add optimized attributes
optimizedAttributeManager.add({
  positions: {
    size: 3,
    accessor: 'getPosition',
    settings: {
      updateFrequency: 'dynamic',
      noAlloc: false
    }
  },
  colors: {
    size: 4,
    type: 'uint8',
    normalized: true,
    accessor: 'getColor',
    settings: {
      updateFrequency: 'once'
    }
  }
});

// Batch updates for performance
const updateAttributes = (dataChunks) => {
  dataChunks.forEach((chunk, index) => {
    const startIndex = index * optimizedAttributeManager.batchSize;
    const endIndex = Math.min(startIndex + chunk.length, totalDataSize);
    
    optimizedAttributeManager.update({
      data: chunk,
      range: [startIndex, endIndex],
      numInstances: chunk.length
    });
  });
};