Skip to content

Add method to update a specific index in p5.StorageBuffer #8749

@aashu2006

Description

@aashu2006

Increasing access

Unsure

Most appropriate sub-area of p5.js?

  • Accessibility
  • Color
  • Core/Environment/Rendering
  • Data
  • DOM
  • Events
  • Image
  • IO
  • Math
  • Typography
  • Utilities
  • WebGL
  • Build process
  • Unit testing
  • Internationalization
  • Friendly errors
  • Other (specify if possible)

Feature request details

Current behavior

p5.StorageBuffer.update() always rewrites the entire buffer from index 0. If a user wants to change a single element for example, one particle out of 10,000, they currently have to:

  1. await buf.read() - full GPU→CPU sync
  2. modify the element in the JS array
  3. buf.update(data) - rewrite the whole buffer

This is slow and awkward for simple updates.

Proposed feature

Add a set(index, value) method to p5.StorageBuffer that updates a single element at a given index without affecting the rest of the buffer.

// Float buffer
let buf = createStorage(new Float32Array([1, 2, 3, 4]));
buf.set(2, 9.5); // only updates index 2

// Struct buffer
let particles = createStorage(makeParticles());
particles.set(42, { position: createVector(0, 0), velocity: createVector(1, 0) });

Why this helps

WebGPU's GPUQueue.writeBuffer() natively supports a byte offset, so a partial write doesn’t need a readback, staging buffer, or GPU sync. The cost is proportional to one element instead of the whole buffer.

Implementation notes

The byte offset for index i in a struct buffer is i * schema.stride. For a float buffer it's i * 4. The existing _packField logic already handles all field types, so packing a single element just reuses it with baseOffset = 0, then calls:

device.queue.writeBuffer(this.buffer, byteOffset, packedElement);

Scope for v1:

  • Full element replacement only (no partial field updates)
  • Works for both float and struct buffers
  • Bounds check with a friendly error

This complements the .read() method added recently.

Related to #8722
This idea came up in discussion with @davepagurek after the .read() implementation.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions