skills/vvvv-spreads/SKILL.md
Helps write code using vvvv gamma's Spread<T> immutable collection type and SpreadBuilder<T>. Use when working with Spreads, SpreadBuilder, collections, arrays, iteration, mapping, filtering, zipping, accumulating, or converting between Span and Spread. Trigger whenever the user writes collection-processing C# code in vvvv — even if they say 'list', 'array', or 'IEnumerable' instead of Spread, this skill likely applies.
npx skillsauth add tebjan/vvvv-skills vvvv-spreadsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Spread<T> is vvvv's immutable collection type, conceptually similar to ImmutableArray<T>. It is the primary way to pass collections between nodes.
Key properties:
Spread<T>.Empty instead of nullvar builder = new SpreadBuilder<float>(expectedCount);
for (int i = 0; i < count; i++)
builder.Add(ComputeValue(i));
Spread<float> result = builder.ToSpread();
// From array (extension method)
Spread<int> fromArray = new int[] { 1, 2, 3 }.ToSpread();
// From array (static factory)
Spread<Waypoint> fromResult = Spread.Create(resultArray);
// Empty spread (NEVER use null)
Spread<float> empty = Spread<float>.Empty;
// Single element
var single = new SpreadBuilder<float>(1);
single.Add(42f);
Spread<float> one = single.ToSpread();
// Always check Count before indexing
if (spread.Count > 0)
{
float first = spread[0];
float last = spread[spread.Count - 1];
}
// Iterate (preferred — no allocation)
foreach (var item in spread)
Process(item);
// Index access in loop
for (int i = 0; i < spread.Count; i++)
Process(spread[i]);
public static Spread<float> Scale(Spread<float> input, float factor = 1f)
{
var builder = new SpreadBuilder<float>(input.Count);
foreach (var value in input)
builder.Add(value * factor);
return builder.ToSpread();
}
public static Spread<float> FilterAbove(Spread<float> input, float threshold = 0.5f)
{
var builder = new SpreadBuilder<float>();
foreach (var value in input)
{
if (value > threshold)
builder.Add(value);
}
return builder.ToSpread();
}
public static Spread<float> Add(Spread<float> a, Spread<float> b)
{
int count = Math.Max(a.Count, b.Count);
var builder = new SpreadBuilder<float>(count);
for (int i = 0; i < count; i++)
{
float va = a.Count > 0 ? a[i % a.Count] : 0f;
float vb = b.Count > 0 ? b[i % b.Count] : 0f;
builder.Add(va + vb);
}
return builder.ToSpread();
}
public static Spread<float> RunningSum(Spread<float> input)
{
var builder = new SpreadBuilder<float>(input.Count);
float sum = 0f;
foreach (var value in input)
{
sum += value;
builder.Add(sum);
}
return builder.ToSpread();
}
For hot-path output (e.g., per-frame simulation data), ReadOnlySpan<T> avoids allocation entirely:
[ProcessNode]
public class ParticleSimulator
{
private ParticleState[] _states;
public ReadOnlySpan<ParticleState> Update(SimulationConfig config, float deltaTime)
{
// Simulate into pre-allocated array — zero allocation
Simulate(_states, config, deltaTime);
return _states.AsSpan();
}
}
Use Spread<T> for infrequent config inputs; use ReadOnlySpan<T> for high-frequency frame data.
new SpreadBuilder<T>(expectedCount) when count is known.Where(), .Select(), .ToList() create hidden allocations.ToSpread(): Build once, output the resultSpan<T> internally, convert to Spread at the API boundary!= or ReferenceEquals) is sufficient — if the reference changed, the content changed[ProcessNode]
public class SpreadProcessor
{
private Spread<float> _lastInput = Spread<float>.Empty;
private Spread<float> _cachedOutput = Spread<float>.Empty;
public void Update(
out Spread<float> output,
Spread<float> input = default)
{
input ??= Spread<float>.Empty;
if (!ReferenceEquals(input, _lastInput))
{
var builder = new SpreadBuilder<float>(input.Count);
foreach (var v in input)
builder.Add(v * 2f);
_cachedOutput = builder.ToSpread();
_lastInput = input;
}
output = _cachedOutput;
}
}
For more code examples, see examples.md.
data-ai
Diagnoses and fixes common vvvv gamma errors in C# nodes, SDSL shaders, and runtime behavior. Use when encountering errors, exceptions, crashes, red nodes, shader compilation failures, missing nodes in the browser, performance issues, or unexpected behavior.
development
Set up and run automated tests for vvvv gamma packages and C# nodes -- VL.TestFramework with NUnit for library/package authors (CI-ready), test .vl patches with assertion nodes, and lightweight agent-driven test workflows. Use when writing tests for vvvv packages, setting up test infrastructure, creating test patches, running automated compilation checks, or integrating vvvv tests into CI/CD.
testing
Covers launching vvvv gamma from the command line or programmatically -- normal startup, opening specific .vl patches, command-line arguments, package repositories, and key filesystem paths (install directory, user data, sketches, exports, packages). Use when starting vvvv, configuring launch arguments, setting up package repositories, or finding vvvv's data directories.
development
Helps write SDSL shaders for Stride and vvvv gamma — TextureFX, shader mixins, compute shaders, and ShaderFX composition. SDSL is a superset of HLSL, so use this skill when writing or debugging .sdsl shader files, GPU shaders, visual effects, HLSL code for vvvv, working with the Stride rendering pipeline, composing shader mixins, or any GPU/compute work. Trigger even if the user says 'HLSL', 'shader', 'GPU effect', 'render pass', or 'compute' in a vvvv context.