2026-02-13--teilchen.gif

the last days i have started something i wanted to do since a long time: Teilchen, a VERY basic particle system1

if you are interested you can have a first glance at a very rough and early version of it in the library repository:

https://codeberg.org/Umfeld/umfeld-libraries/src/branch/main/teilchen

⚠️ WARNING ⚠️ this is a very early, raw, and volatile project so do not count on TOO MUCH stability ATM neither in terms of API and naming nor in terms of behavior or performance.

some key points:

  • use only verlet integration ( position-based, no velocity )
  • refer to people using the library as operators instead of users
  • make it light weight and compact ( e.g header-only )
  • use a audio-DSP inspired central update method for updating physics ( in contrast to hiding that part in the system ). in Teilchen this means that the operator has to handle applying forces, integrating particle positions, and solving constraints. this concept is actually a bit of a longer topic, that i havn t really developed yet but find quite interesting in terms of programming style2
  • make it user-unfriendly in a friendly way i.e rather keep it raw and accessible than super-easy to use but obfuscating core (physics) concepts ( i.e operators need to understand a bit of how particle simulation, vectors and physics work )
  • make it either 2D or 3D but still use more or less the same code base ( use C++ templates and glm vector library )
  • develop it on a by demand basis i.e it is not really complete but grows and matures arbitrarily in places where is needed and used
  • use it as a tool to stress-test Umfeld

PS one thing i also want to try, but am shying away from a bit ATM is implementing a Structure of Arrays (SoA) approach for maximum performance.

this is a basic application with a single particle operator with the mouse:

#include "Umfeld.h"  
#include "Physics.h"  
#include "Particle.h"  
#include "constraint/Box.h"  
  
using namespace umfeld;  
using namespace teilchen;  
  
Physics physics;  
Box     boxed({0, 0}, {1024, 768});  
  
void update_physics(const float dt) {  
    if (physics.get_particles().empty()) {  
        return;  
    }  
  
    Particle& particle = physics.get_particles().front();  
    particle.add_force({0, 1000.0f}); // apply force from raw vector  
    particle.integrate(dt);  
    boxed.contrain(particle);  
}  
  
void settings() {  
    size(1024, 768);  
    Particle::clamp_velocity_default = false;  
}  
  
void setup() {  
    physics.set_update_callback(update_physics);  
  
    Particle& particle = physics.make_particle();  
    particle.set_position({width / 2.0f, height / 2.0f});  
    particle.radius = 20;  
    particle.set_mass(1.0f);  
    particle.set_velocity({1, 0.2f});  
  
    noStroke();  
    fill(0);  
}  
  
void draw() {  
    // control  
    if (isMousePressed) {  
        if (!physics.get_particles().empty()) {  
            Particle& particle = physics.get_particles().front();  
            particle.set_position({mouseX, mouseY});  
            glm::vec2 mouse_velocity;  
            mouse_velocity.x = mouseX - pmouseX;  
            mouse_velocity.y = mouseY - pmouseY;  
            mouse_velocity *= 0.1f;  
            particle.set_velocity(mouse_velocity);  
        }  
    }  
  
    // simulate  
    physics.integrate_fixed_timestep(0.001); // fixed time step, framerate independent  
  
    // draw    background(216);  
    for (const Particle& particle: physics.get_particles()) {  
        circle(particle.position.x, particle.position.y, particle.radius * 2);  
    }  
}
  1. as an Umfeld library but not (really) tied to it ). also, i have been developing a processing library of the same name with a similar goal. but designed differently. confusing yes, but i am not going to come with another name regardless ;) 

  2. the gist is that Object Oriented Programming when done properly often leads to bloated and slow(!) code ( <- yes, i have been using a profiler recently and it s just true! ). therefore, i started to develop this approach ( especially for libraries ) of a more loose and more intention-based or contract-based OOP. rather than implementing strict OOP concepts i often just have these unwritten rules or intentions that all classes from a library comply to. as example, instead of implementing an interface base class with virtual methods, i use the same method name for all related classes for a common behavior e.g in Teilchen every force class implements a void apply_force(Particle p) method, but not because they inherit it from a abstract base class but because that just an unwritten rule ;) i know from an engineering point of view it sound ridiculous, but it is actually quite operator-friendly and keeps things nicely simple hashtag opinion.