diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1900fb2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+public/
+resources/
+.hugo_build.lock
+go.sum
+assets/jsconfig.json
\ No newline at end of file
diff --git a/assets/images/logos/logo.svg b/assets/images/logos/logo.svg
new file mode 100644
index 0000000..5def595
--- /dev/null
+++ b/assets/images/logos/logo.svg
@@ -0,0 +1,33 @@
+
\ No newline at end of file
diff --git a/content/docs/_index.md b/content/docs/_index.md
new file mode 100644
index 0000000..0a65ed4
--- /dev/null
+++ b/content/docs/_index.md
@@ -0,0 +1,3 @@
+---
+title: "MoonVeil Docs"
+---
\ No newline at end of file
diff --git a/content/docs/dashboard/img/dashboard-1.png b/content/docs/dashboard/img/dashboard-1.png
new file mode 100644
index 0000000..9fc022a
Binary files /dev/null and b/content/docs/dashboard/img/dashboard-1.png differ
diff --git a/content/docs/dashboard/img/dashboard-options.png b/content/docs/dashboard/img/dashboard-options.png
new file mode 100644
index 0000000..2decf6f
Binary files /dev/null and b/content/docs/dashboard/img/dashboard-options.png differ
diff --git a/content/docs/dashboard/index.md b/content/docs/dashboard/index.md
new file mode 100644
index 0000000..2e928c9
--- /dev/null
+++ b/content/docs/dashboard/index.md
@@ -0,0 +1,20 @@
+---
+weight: 999
+title: "Dashboard"
+description: "Interactive web interface"
+icon: "article"
+date: "2025-05-01T18:47:58-05:00"
+lastmod: "2025-05-01T18:47:58-05:00"
+---
+
+Once you've signed in, you'll be taken to the dashboard. This can also be navigated elsewhere by clicking 'Dashboard' in the top navbar.
+
+{{< figure src="/img/dashboard-1.png" alt="Dashboard" width="auto" >}}
+
+The Dashboard is the main interface for the obfuscator. You simply type the script you'd like to obfuscate into the left-side code editor and your obfuscated script will appear on the right-side as you make changes.
+
+In the bottom right corner you'll see a Plus icon which will open the options menu.
+
+{{< figure src="/img/dashboard-options.png" alt="Dashboard Options" width="auto" >}}
+
+You can use the options menu to toggle different features of the obfuscator and flip through several presets. Additionally, you can use the bottom most buttons to load from a local file, copy the obfuscated script to your clipboard or save to a local file.
\ No newline at end of file
diff --git a/content/docs/macros/MV_ENC_FUNC.md b/content/docs/macros/MV_ENC_FUNC.md
new file mode 100644
index 0000000..c782c9c
--- /dev/null
+++ b/content/docs/macros/MV_ENC_FUNC.md
@@ -0,0 +1,35 @@
+---
+weight: 100
+title: "MV_ENC_FUNC"
+description: "Encrypts functions"
+icon: "article"
+date: "2025-05-01T18:47:58-05:00"
+lastmod: "2025-05-01T18:47:58-05:00"
+---
+
+`declare function MV_ENC_FUNC(vmFunction: (A...) -> R..., encryptKey: string, decryptKey: string): (A...) -> R...`
+
+will virtualize and encrypt the passed function constant with the provided `encryptKey`. Then `decryptKey` is evaluated at runtime to grab the key.
+
+## Valid Usage
+```lua
+local foo = 'ok'
+local total = 0
+
+local getKey = MV_VM(function()
+ -- WARNING: this is just an example! don't do this
+ return "pass" .. "word123"
+end)
+
+for i = 1, 10 do
+ -- referenced upvalues will be captured
+ MV_ENC_FUNC(function()
+ print("in virtualized function # 1", i)
+ total = total + i
+ end, "password123", getKey())()
+end
+
+return total
+```
+{{% alert context="warning" text="**Note**: if your plan doesn't include virtualization support, `MV_ENC_FUNC` is a no-op where the passed function is mangled normally and not virtualized or encrypted!" /%}}
+
diff --git a/content/docs/macros/MV_ENC_STR.md b/content/docs/macros/MV_ENC_STR.md
new file mode 100644
index 0000000..bf51aa6
--- /dev/null
+++ b/content/docs/macros/MV_ENC_STR.md
@@ -0,0 +1,21 @@
+---
+weight: 100
+title: "MV_ENC_STR"
+description: "Encrypts strings"
+icon: "article"
+date: "2025-05-01T18:47:58-05:00"
+lastmod: "2025-05-01T18:47:58-05:00"
+---
+
+`declare function MV_ENC_STR(str: string, encryptKey: string, decryptKey: string): string`
+
+will encrypt the passed string constant with the provided `encryptKey`. Then `decryptKey` is evaluated at runtime to grab the key.
+
+## Valid Usage
+```lua
+local getKey = MV_VM(function()
+ return "pass" .. "word123"
+end)
+
+return MV_ENC_STR("hello world", "password123", getKey())
+```
\ No newline at end of file
diff --git a/content/docs/macros/MV_INDEX_TO_NUM.md b/content/docs/macros/MV_INDEX_TO_NUM.md
new file mode 100644
index 0000000..2cfdc24
--- /dev/null
+++ b/content/docs/macros/MV_INDEX_TO_NUM.md
@@ -0,0 +1,22 @@
+---
+weight: 100
+title: "MV_INDEX_TO_NUM"
+description: "Obfuscates named indexes"
+icon: "article"
+date: "2025-05-01T18:47:58-05:00"
+lastmod: "2025-05-01T18:47:58-05:00"
+---
+
+`declare function MV_INDEX_TO_NUM(tbl: {}): {}`
+
+will replace all instances of named indexes with a unique number constant.
+
+## Valid Usage
+
+```lua
+local foo = MV_INDEX_TO_NUM({total = 0})
+for i = 1, 10 do
+ foo.total = foo.total + i
+end
+return foo.total
+```
diff --git a/content/docs/macros/MV_OMIT_FUNCTION.md b/content/docs/macros/MV_OMIT_FUNCTION.md
new file mode 100644
index 0000000..71d9912
--- /dev/null
+++ b/content/docs/macros/MV_OMIT_FUNCTION.md
@@ -0,0 +1,22 @@
+---
+weight: 100
+title: "MV_OMIT_FUNCTION"
+description: "Omit all mangling steps"
+icon: "article"
+date: "2025-05-01T18:47:58-05:00"
+lastmod: "2025-05-01T18:47:58-05:00"
+---
+
+`declare function MV_OMIT_FUNCTION(omit: (A...) -> R...): (A...) -> R...`
+
+will omit all mangling steps from the passed function, will also disregard any indexes set by `MV_INDEX_TO_NUM`
+
+## Valid Usage
+
+```lua
+local dontMangleMe = MV_OMIT_FUNCTION(function()
+ print("im in plaintext!")
+end)
+
+donMangleMe()
+```
\ No newline at end of file
diff --git a/content/docs/macros/MV_VM.md b/content/docs/macros/MV_VM.md
new file mode 100644
index 0000000..47adf0f
--- /dev/null
+++ b/content/docs/macros/MV_VM.md
@@ -0,0 +1,23 @@
+---
+weight: 100
+title: "MV_VM"
+description: "Virtualize function"
+icon: "article"
+date: "2025-05-01T18:47:58-05:00"
+lastmod: "2025-05-01T18:47:58-05:00"
+---
+
+`declare function MV_VM(vmFunction: (A...) -> R...): (A...) -> R...`
+
+will mark the passed function to be lifted into the VM.
+
+## Valid Usage
+
+```lua
+local virtualizedFunction = MV_VM(function(a, b, c)
+ print(a .. b .. c .. " im in the vm!")
+end)
+
+virtualizedFunction("1", "2", "3")
+```
+{{% alert context="info" text="**Note**: if your plan doesn't include virtualization support, `MV_VM` is a no-op where the passed function is mangled normally and not virtualized." /%}}
\ No newline at end of file
diff --git a/content/docs/macros/_index.md b/content/docs/macros/_index.md
new file mode 100644
index 0000000..8005f13
--- /dev/null
+++ b/content/docs/macros/_index.md
@@ -0,0 +1,8 @@
+---
+weight: 100
+title: "Macros"
+description: "Obfuscator API"
+icon: "article"
+date: "2025-05-01T18:47:58-05:00"
+lastmod: "2025-05-01T18:47:58-05:00"
+---
\ No newline at end of file
diff --git a/content/docs/options/_index.md b/content/docs/options/_index.md
new file mode 100644
index 0000000..f59503c
--- /dev/null
+++ b/content/docs/options/_index.md
@@ -0,0 +1,8 @@
+---
+weight: 200
+title: "Options"
+description: "Options for the obfuscator"
+icon: "article"
+date: "2025-05-01T18:47:58-05:00"
+lastmod: "2025-05-01T18:47:58-05:00"
+---
\ No newline at end of file
diff --git a/content/docs/options/flatten-control-flow.md b/content/docs/options/flatten-control-flow.md
new file mode 100644
index 0000000..8e1e6af
--- /dev/null
+++ b/content/docs/options/flatten-control-flow.md
@@ -0,0 +1,21 @@
+---
+weight: 100
+title: "Flatten control flow"
+description: "Control flow flattener"
+icon: "article"
+date: "2025-05-01T18:47:58-05:00"
+lastmod: "2025-05-01T18:47:58-05:00"
+---
+
+This option will enable the Control Flow Flattener (CFF). This feature is conservative in it's estimates of what can be flattened, if a block can't be flattened without side effects, it will be discarded from the flattening queue. CFF is applied recursively to failed blocks, meaning if a block is discarded from the flattening queue, its children may be flattened individually.
+
+The control flow flattener supports the following branching syntaxes:
+- `if` statements
+- `while` and `repeat` loops
+- numeric `for` loops
+- `for-in` loops and even support for [Luau's generalized iteration](https://luau.org/syntax#generalized-iteration)
+
+The following child options are available:
+
+- `Wrap CFF blocks`: This will move some CFF blocks into their own closure in a lookup table.
+- `Hoist locals`: Will move local storage into a lookup table for CFF blocks. Useful to cut down on the number of used locals.
\ No newline at end of file
diff --git a/content/docs/options/mangle-statements.md b/content/docs/options/mangle-statements.md
new file mode 100644
index 0000000..968fa9b
--- /dev/null
+++ b/content/docs/options/mangle-statements.md
@@ -0,0 +1,18 @@
+---
+weight: 100
+title: "Mangle Statements"
+description: "Constant decomposition and statement patching"
+icon: "article"
+date: "2025-05-01T18:47:58-05:00"
+lastmod: "2025-05-01T18:47:58-05:00"
+---
+
+This option will enable non-destructive constant decomposition and various statement patching.
+
+The following child options are available:
+
+- `Mangle Numbers`: Replaces number constants with a randomized binary expression which evaluates to that number.
+- `Mangle Strings`: Performs light obfuscation of string constants.
+- `Mangle Self-calls`: Replaces `x:foo()` with `x.foo(x)`.
+- `Mangle Named Indexes`: Replaces `x.foo` with `x[]`. This will mangle the string regardless of whether `Mangle Strings` is enabled.
+- `Mangle Globals`: Globals are replaced with a cached global table indexed by an obfuscated string. eg. `print` becomes `_ENV[]`
\ No newline at end of file
diff --git a/content/docs/using-macros.md b/content/docs/using-macros.md
new file mode 100644
index 0000000..bf7793d
--- /dev/null
+++ b/content/docs/using-macros.md
@@ -0,0 +1,12 @@
+---
+weight: 999
+title: "Using Macros"
+description: "Guide to using macros"
+icon: "article"
+date: "2025-05-01T18:47:58-05:00"
+lastmod: "2025-05-01T18:47:58-05:00"
+---
+
+[Macros](./macros/) are a collection of reserved global functions available for use in your scripts. These are only available at obfuscation-time and are not available at runtime, meaning trying to access these functions dynamically will fail.
+
+They can be used in any script in [your dashboard](./dashboard/) and provide many useful tools for obfuscation.
\ No newline at end of file
diff --git a/data/landing.yaml b/data/landing.yaml
new file mode 100644
index 0000000..ffb5bec
--- /dev/null
+++ b/data/landing.yaml
@@ -0,0 +1,202 @@
+# Note: Template blocks require a 'weight' parameter so they're correctly ordered on the landing page
+
+# Hero
+hero:
+ enable: true
+ weight: 10
+ template: hero
+
+ backgroundImage:
+ path: "images/templates/hero"
+ filename:
+ desktop: "gradient-desktop.webp"
+ mobile: "gradient-mobile.webp"
+
+ badge:
+ text: v0.1.0
+ color: primary # primary, secondary, success, danger, warning, info, light, dark
+ pill: false # boolean
+ soft: true # boolean
+
+ # titleLogo:
+ # path: "images/logos"
+ # filename: "title_logo.png"
+ # alt: "Lotus Docs Logo"
+ # height: 80px
+
+ title: "MoonVeil Obfuscator"
+ subtitle: A lightweight, **modern documentation** theme for Hugo. Easily customised for building **fast**, **secure**, and **SEO-friendly** documentation sites.
+
+ ctaButton:
+ icon: rocket_launch
+ btnText: "Get Started"
+ url: "/docs/quickstart/#create-a-new-lotus-docs-site"
+ cta2Button:
+ icon: construction
+ btnText: "In Development"
+ url: "https://github.com/colinwilson/lotusdocs"
+
+ info: "**Open Source** MIT Licensed."
+
+# Feature Grid
+featureGrid:
+ enable: true
+ weight: 20
+ template: feature grid
+
+ title: Why choose Lotus Docs?
+ subtitle: Lotus Docs is a highly configurable Hugo documentation theme. Yet, with the default configuration you can deploy and publish your documentation site in a matter of minutes. Check out some core features below.
+
+ items:
+ - title: Fast
+ icon: speed
+ description: 4 x 100's score on Google Lighthouse by default. Lotus Docs removes unused CSS, prefetches asset links, and lazy loads content images.
+ ctaLink:
+ text: learn more
+ url: /docs/
+
+ - title: SEO Friendly
+ icon: trending_up
+ description: Data is automatically structured to be SEO friendly. Includes Meta tags, Opengraph, and Twitter cards. Choose the settings that best suit you.
+ ctaLink:
+ text: learn more
+ url: /docs/
+
+ - title: Secure by default
+ icon: lock
+ description: Lotus Docs' default configuration scores A+ on Mozilla Observatory. You can update the default Security Headers to suit your requirements.
+ ctaLink:
+ text: learn more
+ url: /docs/
+
+ - title: Optional Features
+ icon: settings
+ description: Many Lotus Docs features are configurable via optional parameters. Require DocSearch for your site? Then enable it via a single setting.
+ ctaLink:
+ text: learn more
+ url: /docs/
+
+ - title: Deploy to Vercel
+ icon: change_history
+ description: Deploy to Vercel in seconds. Vercel Functions, Vercel Redirects/Rewrites, and Vercel Headers are all configurable for an enriched experience.
+ ctaLink:
+ text: learn more
+ url: /docs/
+
+ - title: Dark Mode
+ icon: dark_mode
+ description: Prefer not to be blasted by the sun while reading? Switch to a low-light UI with the click of a button. Modify colour variables to match your branding.
+ ctaLink:
+ text: learn more
+ url: /docs/
+
+ - title: Search by DocSearch
+ icon: search
+ description: Search your docs with DocSearch. A powerful, efficient and accessible search solution built on Algolia Crawler & Autocomplete. TBC.
+ ctaLink:
+ text: learn more
+ url: /docs/
+
+ - title: Multilingual Support
+ icon: translate
+ description: Lotus Docs supports Hugo's Multilingual Mode. Create documentation in multiple languages side by side with i18n support.
+ ctaLink:
+ text: learn more
+ url: /docs/
+
+ - title: Bootstrap v5
+ icon: palette
+ description: Built on Bootstrap 5, Lotus Docs allows for a familiar, flexible, and intuitive developer experience. Easily customise your site via SCSS variables and files.
+ ctaLink:
+ text: learn more
+ url: /docs/
+
+imageText:
+ enable: false
+ weight: 25
+ template: image text
+
+ title: Built with performance and accessability in mind. Top scores on Google's Lighthouse
+ subtitle: A default Lotus Docs deployment is capable of achieving 4 x 100 scores on Google's Lighthouse performance analysis tool.
+
+ list:
+ - text: Blazing fast page loads
+ icon: speed
+
+ - text: Sensible default SEO friendly settings
+ icon: area_chart
+
+ - text: Designed to be accessible
+ icon: accessibility
+
+ image:
+ path: "images/templates/single"
+ filename: "google_lighthouse_circle_v1.0.svg"
+ alt: "Google LightHouse 100% Illustration" # Optional but recommended
+
+ imgOrder:
+ desktop: 2
+ mobile: 1
+
+ ctaButton:
+ text: Learn more
+ url: "/docs/"
+
+# Image compare
+imageCompare:
+ enable: false
+ weight: 30
+ template: image compare
+
+ title: Customise The Lotus Docs Appearance
+ subtitle: Much of Lotus Docs' appearance can be customised. Dark mode is optional (enabled by default) and you can choose a Google font that suites you via the config parameters.
+
+ items:
+ - title: Dark Mode
+ config: {
+ startingPoint: 50,
+ addCircle: true,
+ addCircleBlur: false,
+ showLabels: true,
+ labelOptions: {
+ before: 'Dark',
+ after: 'Light',
+ onHover: false
+ }
+ }
+ imagePath: "images/screenshots"
+ imageBefore: "lotusdocs_dark_v0.8.webp"
+ imageAfter: "lotusdocs_light_v0.8.webp"
+
+ - title: Custom Fonts
+ config: {
+ controlColor: "#3C4257",
+ startingPoint: 25,
+ addCircle: true,
+ addCircleBlur: false,
+ showLabels: true,
+ labelOptions: {
+ before: 'Inter',
+ after: 'Life Saver',
+ onHover: false
+ }
+ }
+ imagePath: "images/screenshots"
+ imageBefore: "lotusdocs_google_font_demo_inter_screenshot.webp"
+ imageAfter: "lotusdocs_google_font_demo_lifesavers_screenshot.webp"
+
+ - title: Accent Color
+ config: {
+ startingPoint: 25,
+ addCircle: true,
+ addCircleBlur: true,
+ showLabels: true,
+ labelOptions: {
+ before: 'Blue',
+ after: 'Cardinal',
+ onHover: false
+ }
+ }
+ imagePath: "images/screenshots"
+ imageBefore: "lotusdocs_blue_theme_colour.webp"
+ imageAfter: "lotusdocs_cardinal_theme_colour.webp"
\ No newline at end of file
diff --git a/go.mod b/go.mod
index 25ddae9..30694c7 100644
--- a/go.mod
+++ b/go.mod
@@ -1,3 +1,8 @@
module my-docs-site
go 1.24.2
+
+require (
+ github.com/colinwilson/lotusdocs v0.2.0 // indirect
+ github.com/gohugoio/hugo-mod-bootstrap-scss/v5 v5.20300.20400 // indirect
+)
diff --git a/hugo.toml b/hugo.toml
index 7e568b8..eee06cb 100644
--- a/hugo.toml
+++ b/hugo.toml
@@ -1,3 +1,21 @@
baseURL = 'https://example.org/'
languageCode = 'en-us'
-title = 'My New Hugo Site'
+title = 'MoonVeil Docs'
+
+[markup]
+ [markup.goldmark.renderer]
+ hardWraps = false
+ unsafe = true
+ xhtml = false
+
+[module]
+ [[module.imports]]
+ path = "github.com/colinwilson/lotusdocs"
+ disable = false
+ [[module.imports]]
+ path = "github.com/gohugoio/hugo-mod-bootstrap-scss/v5"
+ disable = false
+
+[params.docs]
+ darkMode = true
+ themeColor = "red"
\ No newline at end of file
diff --git a/layouts/index.html b/layouts/index.html
new file mode 100644
index 0000000..2c84c56
--- /dev/null
+++ b/layouts/index.html
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/static/android-chrome-192x192.png b/static/android-chrome-192x192.png
new file mode 100644
index 0000000..4a30234
Binary files /dev/null and b/static/android-chrome-192x192.png differ
diff --git a/static/android-chrome-512x512.png b/static/android-chrome-512x512.png
new file mode 100644
index 0000000..d1ae17f
Binary files /dev/null and b/static/android-chrome-512x512.png differ
diff --git a/static/apple-touch-icon.png b/static/apple-touch-icon.png
new file mode 100644
index 0000000..4a30234
Binary files /dev/null and b/static/apple-touch-icon.png differ
diff --git a/static/favicon-16x16.png b/static/favicon-16x16.png
new file mode 100644
index 0000000..b3207a3
Binary files /dev/null and b/static/favicon-16x16.png differ
diff --git a/static/favicon-32x32.png b/static/favicon-32x32.png
new file mode 100644
index 0000000..a7d8c03
Binary files /dev/null and b/static/favicon-32x32.png differ
diff --git a/static/favicon.ico b/static/favicon.ico
new file mode 100644
index 0000000..c4e1643
Binary files /dev/null and b/static/favicon.ico differ
diff --git a/static/favicon.svg b/static/favicon.svg
new file mode 100644
index 0000000..5def595
--- /dev/null
+++ b/static/favicon.svg
@@ -0,0 +1,33 @@
+
\ No newline at end of file