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
"Vecs is AI coded slop, without much oversight. Not closely engineering reviewed. Don't use this library. Please write something better instead."
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.