diff --git a/3x5.js b/3x5.js
index 355aa05..940da9a 100644
--- a/3x5.js
+++ b/3x5.js
@@ -24,7 +24,7 @@
  * @returns {string} Markup to render / output
  */
 function renderCard(state, code) {
-  const script = parseNotcl(code);
+  const script = Notcl.parse(code);
   state.output = JSON.stringify(script, null, 2);
   return state.output;
 }
diff --git a/notcl.js b/notcl.js
index 180d15c..187e36a 100644
--- a/notcl.js
+++ b/notcl.js
@@ -1,84 +1,88 @@
 /**
- * @typedef {Command[]} Script
- * @typedef {Word[]} Command
- * @typedef {object} Word
+ * @typedef {Notcl.Command[]} Notcl.Script
+ * @typedef {Notcl.Word[]} Notcl.Command
+ * @typedef {object} Notcl.Word
  * @property {string} text
  */
 
-const InterCommandWhitespace = Peg.Regex(/[^\S\n;]*/y);
+var Notcl = (() => {
+  const InterCommandWhitespace = Peg.Regex(/[^\S\n;]*/y);
 
-const CommentPattern = Peg.Regex(/#.*\n/y);
+  const Comment = Peg.Regex(/#.*\n/y);
 
-const PreWordWhitespace = Peg.Regex(/[^\S\n;]*/y);
+  const PreWordWhitespace = Peg.Regex(/[^\S\n;]*/y);
 
-const BasicWord = Peg.Map(Peg.Regex(/[^\s;]+/y), ([word]) => ({
-  text: word,
-}));
+  const BasicWord = Peg.Map(Peg.Regex(/[^\s;]+/y), ([word]) => ({
+    text: word,
+  }));
 
-const WordPattern = Peg.Map(
-  Peg.Sequence(PreWordWhitespace, BasicWord),
-  ([_, word]) => word
-);
+  const Word = Peg.Map(
+    Peg.Sequence(PreWordWhitespace, BasicWord),
+    ([_, word]) => word
+  );
 
-/**
- * Parse out a Notcl script into an easier-to-interpret representation.
- * No script is actually executed yet.
- *
- * @param {string} code
- * @returns Script
- */
-function parseNotcl(code) {
-  /* Preprocess */
-  // fold line endings
-  code = code.replace(/(?<!\\)((\\\\)*)\\\n/g, "$1");
+  return {
+    /**
+     * Parse out a Notcl script into an easier-to-interpret representation.
+     * No script is actually executed yet.
+     *
+     * @param {string} code
+     * @returns Script
+     */
+    parse(code) {
+      /* Preprocess */
+      // fold line endings
+      code = code.replace(/(?<!\\)((\\\\)*)\\\n/g, "$1");
 
-  /* Parse */
-  function nextWord(/* TODO: null/]/" terminator */) {
-    // TODO: handle all kinds of brace/substitution stuff
-    const [word, nextIndex] = WordPattern(code, 0) ?? [null, 0];
-    if (word) {
-      code = code.substring(nextIndex);
-      return word;
-    } else {
-      return null;
-    }
-  }
-
-  function nextCommand(/* TODO: null/]/" terminator */) {
-    const command = /** @type {Word[]} */ ([]);
-    while (true) {
-      // Strip whitespace
-      code = code.replace(/^\s*/, "");
-      // Strip comments
-      if (code[0] == "#") {
-        code = code.replace(/^.*\n/, "");
-        continue;
+      /* Parse */
+      function nextWord(/* TODO: null/]/" terminator */) {
+        // TODO: handle all kinds of brace/substitution stuff
+        const [word, nextIndex] = Word(code, 0) ?? [null, 0];
+        if (word) {
+          code = code.substring(nextIndex);
+          return word;
+        } else {
+          return null;
+        }
       }
-      // Strip semicolons
-      if (code[0] == ";") {
-        code = code.substring(1);
-        continue;
+
+      function nextCommand(/* TODO: null/]/" terminator */) {
+        const command = /** @type {Notcl.Word[]} */ ([]);
+        while (true) {
+          // Strip whitespace
+          code = code.replace(/^\s*/, "");
+          // Strip comments
+          if (code[0] == "#") {
+            code = code.replace(/^.*\n/, "");
+            continue;
+          }
+          // Strip semicolons
+          if (code[0] == ";") {
+            code = code.substring(1);
+            continue;
+          }
+          break;
+        }
+
+        while (true) {
+          const word = nextWord();
+          if (word) {
+            command.push(word);
+            continue;
+          }
+          break;
+        }
+
+        return command;
       }
-      break;
-    }
 
-    while (true) {
-      const word = nextWord();
-      if (word) {
-        command.push(word);
-        continue;
+      /* Loop through commands, with safety check */
+      const script = /** @type {Notcl.Command[]} */ ([]);
+      for (let i = 0; i < 1000 && code != ""; i++) {
+        script.push(nextCommand());
       }
-      break;
-    }
 
-    return command;
-  }
-
-  /* Loop through commands, with safety check */
-  const script = /** @type {Command[]} */ ([]);
-  for (let i = 0; i < 1000 && code != ""; i++) {
-    script.push(nextCommand());
-  }
-
-  return script;
-}
+      return script;
+    },
+  };
+})();