Everything people see and touch.
- HTML and semantic structure
- CSS, branding, and responsive layout
- Rendering and event delegation
- Accessibility and interaction design
Standalone engine · Vanilla JavaScript · Firebase + Firestore
Khaya Engine is the tested layer between a vanilla JavaScript interface and Firebase. It turns user actions into serializable commands, keeps every screen synchronized, and handles confirmation, conflicts, and rollback without owning a single HTML element.
A new frontend should replace its presentation without reimplementing real-time coordination. Khaya gives every vanilla frontend the same small contract: render state, execute commands, observe lifecycle.
The boundary rule: DOM nodes never enter the engine. Firebase objects never enter the engine. Customer identity and project configuration never enter this repository.
The interface depends on the engine; the engine does not know the interface exists. Firebase stays replaceable at the code boundary even though it is Khaya's only supported production backend.
Down Serializable commands
Up State, status, events, errors
This safe documentation demo uses the memory adapter. The engine and binding are identical in production; the Firebase example changes only the adapter.
There are only three integration decisions: create the adapter, provide a render callback, and translate interface events into commands.
Firebase is a peer dependency so the frontend controls its Firebase app, authentication, and project configuration.
npm install khaya-engine firebase
Your application owns its dedicated project configuration.
This is the only production persistence boundary.
Pass state to your own renderer.
No Firebase calls belong in click handlers.
The binding detaches subscriptions and listeners cleanly.
import { initializeApp } from "firebase/app"
import { getFirestore } from "firebase/firestore"
import { createRealtimeEngine } from "khaya-engine"
import { createFirebaseFirestoreAdapter }
from "khaya-engine/firebase"
import { createVanillaBinding }
from "khaya-engine/vanilla"
const app = initializeApp(firebaseConfig)
const adapter = createFirebaseFirestoreAdapter({
firestore: getFirestore(app),
initialState,
})
const engine = createRealtimeEngine({ adapter })
const binding = createVanillaBinding({
engine,
render(state, metadata) {
renderCatalogue(state, metadata)
},
})
await binding.mount()
The same command drives optimistic state, the Firestore transaction, correlation events, and every subscribed frontend.
await binding.execute({
type: "stock.adjust",
categoryId: "catalogue",
itemId: "coffee",
delta: -1,
})
Each implementation gets isolated Firebase infrastructure. The engine code stays unchanged; only application configuration, data shape, rendering, and branding vary.
Register a Web app and enable Cloud Firestore plus Email/Password Authentication.
Replace the public Web configuration and choose the Firestore document path.
Create the Auth user and add its UID to the protected khayaEngineOwners collection.
Use the Firebase emulator to verify public reads, owner writes, revision increments, and denied access.
Replace markup and rendering while keeping the binding, adapter, and command boundary.
Never reuse another customer's Firebase project, owner UID, data, deployment target, or credentials. Firebase Web configuration belongs to the consuming frontend; service-account credentials never belong in browser code.
mount()unmount()dispose()subscribe()getState()getRevision()category.updateitem.updateitem.additem.removestock.adjuststatestatuseventerror