I've decided to publish ecsly - small but highly performant ecs written in dart which I started developing to solve the simulation problem while developing a games in flutter and ended up building game engine xD
currently has no public repository, and in pre-release state - contains no graphics, no flutter, almost no dependencies - so it can be used in flutter, jasper - basically in any dart environment..
I'm not sure that I've got benchmarks correct (added file to library), but hopefully it is true - I've tried to push dart to limits - use SIMD where it is possible, reduce any GC, etc..
I didn’t published entire engine - only most important part of it, which in my opinion has stabilized most.
Tiny example will look like this:
import 'package:ecsly/ecsly.dart';
/// Tiny object component for the pub.dev example entry point.
///
/// `ecsly` also supports packed typed-data columns for hotter loops, but an
/// object component keeps the first example intentionally small.
class CounterComponent extends Component {
CounterComponent(this.value);
int value;
}
void main() {
final world = World();
world.components.registerObjectComponent<CounterComponent>();
final entity = world.reserveEmptyEntity().entity;
world.spawnBundle(entity, ComponentBundle.fromLists([CounterComponent(1)]));
world.flush();
for (final (_, counter) in world.queryMut<CounterComponent>()) {
counter.value += 1;
print('counter=${counter.value}');
}
}
With SIMD the api looks like this:
import 'dart:typed_data';
import 'package:ecsly/ecsly.dart';
class Velocity4Component extends Component {
const Velocity4Component();
}
extension type Velocity4._(int index) {
static late FloatColumn column;
double get x => column.getValueUnsafe(index, 0);
double get y => column.getValueUnsafe(index, 1);
set x(double value) => column.setValue(index, 0, value);
set y(double value) => column.setValue(index, 1, value);
}
final class Velocity4ColumnFactory extends ColumnFactory {
@override
DataColumn createColumn(
ComponentId componentId, {
int initialCapacity = 8,
}) {
return FloatColumn(stride: 4, initialCapacity: initialCapacity);
}
}
final class Velocity4FacadeFactory
extends ComponentFacadeFactory<Velocity4> {
@override
Velocity4 create(int index) => Velocity4._(index);
@override
void initialize(covariant FloatColumn column) {
Velocity4.column = column;
}
}
final world = World();
world.components.registerExtension<Velocity4Component, Velocity4>(
columnFactory: Velocity4ColumnFactory(),
facadeFactory: Velocity4FacadeFactory(),
);
final entity = world.reserveEmptyEntity().entity;
world.spawnBundle(
entity,
ComponentBundle.fromExtensionList(const [
(Velocity4Component, Velocity4),
]),
);
world.flush();
for (final (_, velocity) in world.queryExt<Velocity4Component, Velocity4>()) {
velocity.x = 3;
velocity.y = 4;
}
final simd = Velocity4.column.simdView;
if (simd != null) {
final gravity = Float32x4(0, -9.8, 0, 0);
for (var i = 0; i < Velocity4.column.length; i++) {
simd[i] = simd[i] + gravity;
}
}
I didn't changed the api for almost half a year so decided to try publish:)
More detailed explanation will try to publish as part of architectural series - in short I believe that ECS is best and most scalable architecture for high performance applications and games. I designed it to be used alongside with Flutter, Jaspr and any other dart framework or to be used separately if needed.
I'm sure that it is possible to do more - more convenient DX, more optimizations
will be glad for any feedback:)
https://pub.dev/packages/ecsly
p.s.: heavily inspired by bevy and entt frameworks and many other libraries
p.p.s: made with AI (I'v started from scratch, so every concept was new to me - it would be impossible to write and understand it in such short time for me:)

Top comments (0)