diff --git a/doc/html-helpers.md b/doc/html-helpers.md
deleted file mode 100644
index e69de29..0000000
diff --git a/doc/html-proxy.md b/doc/render.md
similarity index 65%
rename from doc/html-proxy.md
rename to doc/render.md
index 716a815..0397174 100644
--- a/doc/html-proxy.md
+++ b/doc/render.md
@@ -1,7 +1,7 @@
-# Skooma.js
+# Rendering DOM nodes using `render.js`
```js
-import {html} from "skooma.js"
+import {html} from "skooma/render.js"
```
A functional-friendly helper library for procedural DOM generation and templating, with support for reactive state objects.
@@ -110,7 +110,8 @@ html.div({
})
```
-The `dataset` property will add its key/value pairs to the new node's `dataset`, as a more convenient alternative to setting individual `data-` attributes.
+The `dataset` property will add its key/value pairs to the new node's `dataset`,
+as a more convenient alternative to setting individual `data-` attributes.
```js
const dataset = { foo: "bar" }
@@ -123,12 +124,51 @@ console.log(div.getAttribute("data-foo") === "bar")
Skooma supports reactivity through a simple protocol:
-Observable objects identify themselves with the `observable` attribute, which
-must return a truthy value.
+Observable objects identify themselves with the `observable` attribute,
+which must return a truthy value.
-Observables are expected to expose a `value` attribute that is both readable and
-writeable, and to emit a "change" event whenever its vale has changed.
+Observables are expected to expose a `value` attribute that is both readable and writeable,
+and to emit a "change" event whenever its vale has changed.
-Observables can be used both as attribute values as well as for child elements.
+Observables can be passed to skooma's node functions as both
+attribute values (values in an object) or
+child elements (direct arguments or in an array).
-TODO: Explain what actually happens
+#### Reactive Children
+
+Passing an observable as a child element will attempt to insert its current
+value into the new node as if it was passed in directly, but will also hook into
+the observable to replace the value when the state changes.
+
+```js
+const state = new Observable.value(0)
+
+const button = html.button(state, {
+ click(event) { state.value++ }
+})
+```
+
+Note that to keep the replacement logic simple, it is not currently possible to
+insert use document fragments, as these could insert several top-level children
+into a component that would then all have to be replaced. When an observable
+contains or changes to a document fragment, skooma will raise an error.
+
+Before replacing an element, a `"replace"` event is emitted from the old
+element. This event bubbles and is cancelable, and can thus be used both to
+completely prevent the replacement according to custom logic, to alter or
+initialise the new element before it is inserted, or even to modify the old
+object instead of replacing it.
+
+#### Reactive Attributes
+
+Passing an observable as an object value will, likewise, treat its value as the
+attribute value, and update it whenever the state's value changes.
+
+```js
+const state = new Observable.value(0)
+
+const input_1 = html.input({ type: "number", value: state })
+const input_2 = html.input({ type: "number", value: state })
+```
+
+TODO: events as for reactive children