Installation
npm install basepower
import { EventEmitter, Serializable } from 'basepower';
EventEmitter
A minimal event system.
Constructor
const emitter = new EventEmitter();
on(event, callback)
Register a listener for an event.
emitter.on('data', (value) => {
console.log(value);
});
once(event, callback)
Register a listener that fires only once.
emitter.once('init', () => {
console.log('initialized');
});
off(event, callback?)
Remove a specific listener, or all listeners for an event if no callback is provided.
emitter.off('data', myHandler); // remove specific
emitter.off('data'); // remove all
emit(event, args?)
Emit an event. Arguments are spread to each listener.
emitter.emit('data', [42, 'hello']);
hasEvent(event)
Returns true if there are listeners for the given event.
emitter.hasEvent('data'); // boolean
Interactive Demo
Serializable
A serialization framework that extends EventEmitter. Define fields with getter/setter pairs, then serialize and deserialize them.
Constructor
const obj = new Serializable();
console.log(obj.uuid); // auto-generated UUID
field(path, getter, setter?, opt?)
Register a field. If no setter is provided, the field is read-only. Use { export: false } to exclude from serialize().
let hp = 100;
obj.field('hp', () => hp, (v) => { hp = v; });
// read-only field (still included in serialize)
obj.field('name', () => 'Player1');
// excluded from serialize output
obj.field('debugVal', () => val, (v) => { val = v; }, { export: false });
fieldDir(name, opt?)
Create a group for organizing fields hierarchically.
const stats = obj.fieldDir('stats');
stats.field('hp', () => hp, (v) => { hp = v; });
// accessible as 'stats/hp'
getField(path)
Get the current value of a field.
obj.getField('hp'); // 100
setField(path, value)
Set the value of a field. Emits fields/update and fields/update/<path> events.
obj.setField('hp', 50);
serialize()
Serialize fields to a flat key-value object. Fields with export: false are excluded.
const data = obj.serialize();
// { hp: 100, name: 'Player1' }
deserialize(props)
Restore field values from a serialized object.
obj.deserialize({ hp: 75 });
getSchema()
Get all fields as a nested tree structure based on /-separated paths. Includes all fields regardless of export setting.
const tree = obj.getSchema();
// { type: 'group', childs: { stats: { type: 'group', childs: { hp: { type: 'field', value: 100 } } } } }
Interactive Demo
React Integration
Hooks for binding Serializable fields to React components. Install with basepower and import from basepower/react.
import { useSerializableField, useWatchSerializable } from 'basepower/react';
useSerializableField(serializable, fieldPath)
Returns a [value, setter] tuple that stays in sync with a single field. The component re-renders only when that specific field changes.
function HpEditor({ obj }: { obj: Serializable }) {
const [hp, setHp] = useSerializableField<number>(obj, 'stats/hp');
return <input
type="range" min={0} max={200}
value={hp ?? 0}
onChange={(e) => setHp(Number(e.target.value))}
/>;
}
useWatchSerializable(serializable, deps?)
Returns all serialized fields and re-renders when any (or specified) field changes. Pass a deps array to limit which fields trigger re-renders.
// re-render on ANY field change
const allFields = useWatchSerializable(obj);
// re-render only when 'stats/hp' changes
const fields = useWatchSerializable(obj, ['stats/hp']);
Interactive Demo
Edit the fields below — both serialized views update reactively.
The right panel only watches stats/hp, so it re-renders only when HP changes.
Type Reference
SelectList
type SelectList = ({ value: any; label: string } | string)[]
ValueOpt
type ValueOpt = {
label?: string;
readOnly?: boolean;
step?: number;
disabled?: boolean;
}
FieldOpt
type FieldOpt = {
isFolder?: boolean;
export?: boolean;
hidden?: boolean | ((value: FieldValue) => boolean);
format?: FieldFormat;
} & ValueOpt
FieldFormat
type FieldFormat =
| { type: 'vector' }
| { type: 'select'; list: SelectList | (() => SelectList) }
| { type: 'array'; labels?: (value: FieldValue, index: number) => string }
SerializedFields
interface SerializedFields {
[key: string]: FieldValue
}
SchemaNode
type SchemaNode = SchemaGroup | SchemaField
interface SchemaGroup {
type: 'group';
childs: { [key: string]: SchemaNode };
opt?: FieldOpt;
}
interface SchemaField {
type: 'field';
value: FieldValue;
opt?: FieldOpt;
}