v1.0 is critically flawed

72.8x faster than EnTT.

A high-performance, single-header C++ ECS utilising a two-level bitfield sparse index. Performance by default. Reliability by coincidence.

Trusted by absolutely no one in production

NULLPTR
SEGFAULT
UNDEFINED_BEHAVIOR
STD::BAD_ALLOC

"Vecs is AI coded slop, without much oversight. Not closely engineering reviewed. Don't use this library. Please write something better instead."

CSO
Chief Slop Officer
Unapologetic Slop. Unapologetic Performance.

AI Coded Slop

Generated with zero human oversight. Pure latent space hallucination packaged as an enterprise solution.

O(1) Lookups

Two-level bitfield sparse index. It is terrifyingly fast. Fast enough to melt your motherboard.

SIMD Joins

Automatic SSE2, AVX2, and NEON vectorised joins. We honestly aren't entirely sure how it works.

Zero Dependencies

One single, massive, terrifying C++ header file. Just drop it in your project and pray.

Dubious Benchmarks

We would make dubious comparisons just to make this library look cooler. Here are the dubious comparisons vs EnTT (v3.13.0), Ryzen 9 5950X:

Operation Vecs EnTT Ratio
Entity Create 1.75 B ops/s 66.8 M ops/s 26.2x
Component Insert 159.9 M ops/s 42.6 M ops/s 3.7x
Query Iterate 72.3 B ops/s 0.99 B ops/s 72.8x
Full Destroy 38.0 M ops/s 14.5 M ops/s 2.6x
Shotgun Deletion 38.2 M ops/s 14.1 M ops/s 2.7x

Documentation

If you must use it, here is how. Require C++17.

Quick Start

main.cpp
#include "vecs.h"

struct Position { float x, y; };
struct Velocity { float vx, vy; };
struct IsEnemy {};  // Zero-byte tag

int main()
{
    vecsWorld* w = vecsCreateWorld();
    vecsEntity e = vecsCreate( w );

    vecsSet<Position>( w, e, { 0.0f, 0.0f } );
    vecsSet<Velocity>( w, e, { 1.0f, 0.5f } );

    vecsEach<Position, Velocity>( w, []( vecsEntity, Position& p, Velocity& v )
    {
        p.x += v.vx;
        p.y += v.vy;
    } );

    vecsDestroyWorld( w );
    return 0;
}

Component Operations

// Set component (copy-based)
vecsSet<Position>( w, e, { x, y } );

// Emplace component (in-place, no copy)
vecsEmplace<Position>( w, e, x, y );

// Get component pointer
Position* p = vecsGet<Position>( w, e );

// Check if entity has component
bool has = vecsHas<Position>( w, e );

// Remove component
vecsUnset<Position>( w, e );

Entity Handle Wrapper

// Create entity with wrapper
vecsHandle player = vecsCreateHandle( w );
player.emplace<Position>( 10.0f, 20.0f );
player.addTag<IsEnemy>();

// Access components
Position* p = player.get<Position>();
if ( player.hasAll<Position, Velocity>() ) { ... }

// Parent/child relationships
player.setParent( parentEntity );

// Cleanup
player.destroy();

Command Buffers

vecsCommandBuffer* cb = vecsCreateCommandBuffer( w );

uint32_t idx = vecsCmdCreate( cb );
vecsCmdSetCreated<Position>( cb, idx, { 1, 2 } );
vecsCmdDestroy( cb, someEntity );
vecsCmdSetParent( cb, child, parent );

// Execute all deferred commands
vecsFlush( cb );  
vecsEntity e = vecsCmdGetCreated( cb, idx );

vecsDestroyCommandBuffer( cb );

Cached Queries

vecsQuery* q = vecsBuildQuery<Position, Velocity>( w );

// Exclude entities with Dead tag
vecsQueryAddWithout( q, vecsTypeId<Dead>() );  

vecsQueryEach<Position, Velocity>( w, q, 
[]( vecsEntity, Position& p, Velocity& v )
{
    p.x += v.vx;
} );

vecsDestroyQuery( q );

Header Reference

Interactive breakdown of vecs.h.