diff --git a/sandbox/embed_selfhost_errors.html b/sandbox/embed_selfhost_errors.html
index a445dde..85acc1f 100644
--- a/sandbox/embed_selfhost_errors.html
+++ b/sandbox/embed_selfhost_errors.html
@@ -33,6 +33,7 @@
+
diff --git a/sandbox/embed_selfhost_externallibs.html b/sandbox/embed_selfhost_externallibs.html
index 2f298a1..2f2af70 100644
--- a/sandbox/embed_selfhost_externallibs.html
+++ b/sandbox/embed_selfhost_externallibs.html
@@ -33,6 +33,7 @@
+
diff --git a/sandbox/embed_selfhost_fullscreen.html b/sandbox/embed_selfhost_fullscreen.html
index 1a8fb0d..b02b445 100644
--- a/sandbox/embed_selfhost_fullscreen.html
+++ b/sandbox/embed_selfhost_fullscreen.html
@@ -32,6 +32,7 @@
+
diff --git a/sandbox/embed_selfhost_manual.html b/sandbox/embed_selfhost_manual.html
index 161915c..9a5cd75 100644
--- a/sandbox/embed_selfhost_manual.html
+++ b/sandbox/embed_selfhost_manual.html
@@ -33,6 +33,7 @@
+
diff --git a/sandbox/embed_selfhost_multiple.html b/sandbox/embed_selfhost_multiple.html
index f3638b3..0b90d10 100644
--- a/sandbox/embed_selfhost_multiple.html
+++ b/sandbox/embed_selfhost_multiple.html
@@ -33,6 +33,7 @@
+
diff --git a/sandbox/embed_selfhost_single.html b/sandbox/embed_selfhost_single.html
index 7c203e9..f981cec 100644
--- a/sandbox/embed_selfhost_single.html
+++ b/sandbox/embed_selfhost_single.html
@@ -32,6 +32,7 @@
+
diff --git a/sandbox/embed_selfhost_single_scroll.html b/sandbox/embed_selfhost_single_scroll.html
index cf400e9..02aad68 100644
--- a/sandbox/embed_selfhost_single_scroll.html
+++ b/sandbox/embed_selfhost_single_scroll.html
@@ -32,6 +32,7 @@
+
diff --git a/source/model/node.js b/source/model/node.js
new file mode 100644
index 0000000..c1ffe89
--- /dev/null
+++ b/source/model/node.js
@@ -0,0 +1,56 @@
+OV.Node = class
+{
+ constructor ()
+ {
+ this.parent = null;
+ this.name = '';
+ this.childNodes = [];
+ this.meshIndices = [];
+ }
+
+ GetParent ()
+ {
+ return this.parent;
+ }
+
+ GetName ()
+ {
+ return this.name;
+ }
+
+ SetName (name)
+ {
+ this.name = name;
+ }
+
+ AddChildNode (node)
+ {
+ node.parent = this;
+ this.childNodes.push (node);
+ return this.childNodes.length - 1;
+ }
+
+ GetChildNodes ()
+ {
+ return this.childNodes;
+ }
+
+ AddMeshIndex (index)
+ {
+ this.meshIndices.push (index);
+ return this.meshIndices.length - 1;
+ }
+
+ GetMeshIndices ()
+ {
+ return this.meshIndices;
+ }
+
+ Enumerate (processor)
+ {
+ processor (this);
+ for (const childNode of this.childNodes) {
+ childNode.Enumerate (processor);
+ }
+ }
+};
diff --git a/test/tests/node_test.js b/test/tests/node_test.js
new file mode 100644
index 0000000..24e3250
--- /dev/null
+++ b/test/tests/node_test.js
@@ -0,0 +1,60 @@
+var assert = require ('assert');
+
+describe ('Node', function() {
+ it ('Default Initialization', function () {
+ let node = new OV.Node ();
+ assert.strictEqual (node.GetName (), '');
+ assert.deepStrictEqual (node.GetChildNodes (), []);
+ assert.deepStrictEqual (node.GetMeshIndices (), []);
+ });
+
+ it ('Set Name', function () {
+ let node = new OV.Node ();
+ node.SetName ('New Name');
+ assert.strictEqual (node.GetName (), 'New Name');
+ });
+
+ it ('Add Mesh Indices', function () {
+ let node = new OV.Node ();
+ node.AddMeshIndex (0);
+ node.AddMeshIndex (4);
+ node.AddMeshIndex (8);
+ assert.deepStrictEqual (node.GetMeshIndices (), [0, 4, 8]);
+ });
+
+ it ('Add Child Node', function () {
+ let node = new OV.Node ();
+ let child1 = new OV.Node ();
+ let child2 = new OV.Node ();
+ child1.SetName ('Child 1');
+ child2.SetName ('Child 2');
+ node.AddChildNode (child1);
+ node.AddChildNode (child2);
+ assert.strictEqual (node.GetChildNodes ().length, 2);
+ assert.strictEqual (node.GetChildNodes ()[0].GetName (), 'Child 1');
+ assert.strictEqual (node.GetChildNodes ()[1].GetName (), 'Child 2');
+ assert.strictEqual (node.GetChildNodes ()[0].GetParent (), node);
+ assert.strictEqual (node.GetChildNodes ()[1].GetParent (), node);
+ });
+
+ it ('Recursive Enumeration', function () {
+ let node = new OV.Node ();
+ let child1 = new OV.Node ();
+ let child2 = new OV.Node ();
+ let child11 = new OV.Node ();
+ let child12 = new OV.Node ();
+
+ node.AddChildNode (child1);
+ node.AddChildNode (child2);
+
+ child1.AddChildNode (child11);
+ child1.AddChildNode (child12);
+
+ let enumerated = [];
+ node.Enumerate ((child) => {
+ enumerated.push (child);
+ });
+
+ assert.deepStrictEqual (enumerated, [node, child1, child11, child12, child2]);
+ });
+});
diff --git a/tools/config.json b/tools/config.json
index 2e27703..6162121 100644
--- a/tools/config.json
+++ b/tools/config.json
@@ -29,6 +29,7 @@
"source/model/element.js",
"source/model/mesh.js",
"source/model/meshbuffer.js",
+ "source/model/node.js",
"source/model/model.js",
"source/model/topology.js",
"source/model/modelutils.js",
diff --git a/website/embed.html b/website/embed.html
index 5643112..c74252e 100644
--- a/website/embed.html
+++ b/website/embed.html
@@ -42,6 +42,7 @@
+
diff --git a/website/index.html b/website/index.html
index a81ec30..291ab02 100644
--- a/website/index.html
+++ b/website/index.html
@@ -42,6 +42,7 @@
+