diff --git a/assets/css/custom.css b/assets/css/custom.css
new file mode 100644
index 0000000..7d56c59
--- /dev/null
+++ b/assets/css/custom.css
@@ -0,0 +1,39 @@
+body {
+ background-color: #1e1e1e;
+ color: #d4d4d4;
+}
+
+.editor-container, .output-container {
+ background-color: #252526;
+ border: 1px solid #333333;
+ border-radius: 4px;
+ height: 80vh;
+ display: flex;
+ flex-direction: column;
+}
+
+#editor {
+ flex-grow: 1;
+ background-color: transparent;
+ border: none;
+ color: #d4d4d4;
+ font-family: monospace;
+ resize: none;
+ padding: 1rem;
+}
+
+#output {
+ flex-grow: 1;
+ background-color: transparent;
+ border: none;
+ color: #d4d4d4;
+ font-family: monospace;
+ padding: 1rem;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+}
+
+.btn-primary {
+ background-color: #007acc;
+ border-color: #007acc;
+}
diff --git a/assets/js/main.js b/assets/js/main.js
new file mode 100644
index 0000000..1286376
--- /dev/null
+++ b/assets/js/main.js
@@ -0,0 +1,259 @@
+document.addEventListener('DOMContentLoaded', () => {
+ const editor = ace.edit("editor");
+ editor.session.setMode("ace/mode/lua");
+
+ loadSettings();
+
+ const obfuscateBtn = document.getElementById('obfuscate-btn');
+ const saveBtn = document.getElementById('save-btn');
+ const loadBtn = document.getElementById('load-btn');
+ const clearOutputBtn = document.getElementById('clear-output-btn');
+ const obfuscatedOutput = document.getElementById('obfuscated-output');
+ const loader = document.getElementById('loader');
+ const versionSpan = document.getElementById('luau-version');
+ const examplesMenu = document.getElementById('examples-menu');
+ const saveStatus = document.getElementById('save-status');
+
+ const LS_CODE_KEY = 'luau-saved-code';
+ const LS_SETTINGS_KEY = 'luau-editor-settings';
+
+ const editorThemes = [
+ 'ambiance', 'chaos', 'chrome', 'clouds', 'cobalt',
+ 'crimson_editor', 'dawn', 'dracula', 'dreamweaver', 'eclipse',
+ 'github', 'gob', 'gruvbox', 'idle_fingers', 'iplastic',
+ 'katzenmilch', 'kr_theme', 'kuroir', 'merbivore', 'merbivore_soft',
+ 'mono_industrial', 'monokai', 'nord_dark', 'pastel_on_dark', 'solarized_dark',
+ 'solarized_light', 'sqlserver', 'terminal', 'textmate', 'tomorrow',
+ 'tomorrow_night', 'tomorrow_night_blue', 'tomorrow_night_bright', 'tomorrow_night_eighties',
+ 'twilight', 'vibrant_ink', 'xcode'
+ ];
+
+ let editorSettings = {};
+
+ // --- Editor and Snippet Setup ---
+ const examples = [
+ {
+ title: 'Hello World',
+ code: 'print("Hello, world!")'
+ },
+ {
+ title: 'Variables & Types',
+ code: '-- Luau has types that you can optionally add!\n\n' +
+ 'local message: string = "Hello, Luau!"\n' +
+ 'local version: number = 1.0\n' +
+ 'local isAwesome: boolean = true\n\n' +
+ 'print(message, type(message))\n' +
+ 'print("Version:", version, type(version))\n' +
+ 'print("Is it awesome?", isAwesome, type(isAwesome))'
+ },
+ {
+ title: 'Loops',
+ code: 'print("Counting from 1 to 5:")\n' +
+ 'for i = 1, 5 do\n' +
+ ' print("Number:", i)\n' +
+ 'end\n\n' +
+ 'local t = {"apple", "banana", "cherry"}\n' +
+ 'print("\nIterating through a table:")\n' +
+ 'for _, fruit in ipairs(t) do\n' +
+ ' print("- " .. fruit)\n' +
+ 'end'
+ },
+ {
+ title: 'Functions',
+ code: 'function greet(name: string): string\n' +
+ ' return "Hello, " .. name .. "!"\n' +
+ 'end\n\n' +
+ 'local message = greet("User")\n' +
+ 'print(message)\n\n' +
+ '-- Function with a type alias\n' +
+ 'type Player = { name: string, score: number }\n\n' +
+ 'local function displayPlayer(p: Player)\n' +
+ ' print("Player: " .. p.name .. ", Score: " .. p.score)\n' +
+ 'end\n\n' +
+ 'local player1: Player = { name = "Alice", score = 100 }\n' +
+ 'displayPlayer(player1)'
+ }
+ ];
+
+ examples.forEach((example, index) => {
+ const li = document.createElement('li');
+ const a = document.createElement('a');
+ a.classList.add('dropdown-item');
+ a.href = '#';
+ a.textContent = example.title;
+ a.dataset.index = index;
+ li.appendChild(a);
+ examplesMenu.appendChild(li);
+ });
+
+ examplesMenu.addEventListener('click', (e) => {
+ if (e.target.tagName === 'A') {
+ e.preventDefault();
+ const index = e.target.dataset.index;
+ if (index) {
+ editor.setValue(examples[index].code, 1); // 1 moves cursor to the end
+ }
+ }
+ });
+
+ // --- Settings Modal Logic ---
+ const themeSelect = document.getElementById('theme-select');
+ const fontSizeInput = document.getElementById('font-size-input');
+ const softWrapCheck = document.getElementById('soft-wrap-check');
+
+ function applySettings() {
+ editor.setTheme("ace/theme/" + editorSettings.theme);
+ editor.setFontSize(editorSettings.fontSize);
+ editor.session.setUseWrapMode(editorSettings.softWrap);
+
+ // Update UI controls to reflect current settings
+ themeSelect.value = editorSettings.theme;
+ fontSizeInput.value = editorSettings.fontSize;
+ softWrapCheck.checked = editorSettings.softWrap;
+ }
+
+ function saveSettings() {
+ try {
+ localStorage.setItem(LS_SETTINGS_KEY, JSON.stringify(editorSettings));
+ } catch (e) {
+ console.error("Failed to save settings:", e);
+ }
+ }
+
+ function loadSettings() {
+ const defaults = {
+ theme: 'tomorrow_night',
+ fontSize: 14,
+ softWrap: false
+ };
+
+ try {
+ const saved = localStorage.getItem(LS_SETTINGS_KEY);
+ if (saved) {
+ editorSettings = Object.assign({}, defaults, JSON.parse(saved));
+ } else {
+ editorSettings = defaults;
+ }
+ } catch (e) {
+ console.error("Failed to load settings:", e);
+ editorSettings = defaults;
+ }
+ applySettings();
+ }
+
+ // Populate theme dropdown
+ editorThemes.forEach(theme => {
+ const option = document.createElement('option');
+ option.value = theme;
+ option.textContent = theme.split('_').map(w => w[0].toUpperCase() + w.substr(1)).join(' ');
+ themeSelect.appendChild(option);
+ });
+
+ // Settings event listeners
+ themeSelect.addEventListener('change', () => {
+ editorSettings.theme = themeSelect.value;
+ applySettings();
+ saveSettings();
+ });
+
+ fontSizeInput.addEventListener('input', () => {
+ editorSettings.fontSize = parseInt(fontSizeInput.value, 10);
+ applySettings();
+ saveSettings();
+ });
+
+ softWrapCheck.addEventListener('change', () => {
+ editorSettings.softWrap = softWrapCheck.checked;
+ applySettings();
+ saveSettings();
+ });
+
+
+ // --- Local Storage and UI Logic ---
+
+ function showSaveStatus(message, duration = 2000) {
+ saveStatus.textContent = message;
+ setTimeout(() => {
+ saveStatus.textContent = '';
+ }, duration);
+ }
+
+ saveBtn.addEventListener('click', () => {
+ try {
+ localStorage.setItem(LS_CODE_KEY, editor.getValue());
+ showSaveStatus('Code saved!');
+ } catch (e) {
+ console.error("Failed to save to localStorage:", e);
+ showSaveStatus('Error saving!');
+ }
+ });
+
+ loadBtn.addEventListener('click', () => {
+ const savedCode = localStorage.getItem(LS_CODE_KEY);
+ if (savedCode) {
+ editor.setValue(savedCode, 1);
+ showSaveStatus('Code restored!');
+ } else {
+ showSaveStatus('No code saved yet.');
+ }
+ });
+
+ clearOutputBtn.addEventListener('click', () => {
+ obfuscatedOutput.textContent = '';
+ });
+
+ // --- Load initial code ---
+ const savedCode = localStorage.getItem(LS_CODE_KEY);
+ if (savedCode) {
+ editor.setValue(savedCode, 1);
+ } else {
+ // Load default example if nothing is saved
+ editor.setValue(examples[0].code, 1);
+ }
+
+ versionSpan.textContent = `Luau Obfuscator`;
+
+ obfuscateBtn.addEventListener('click', async () => {
+ const code = editor.getValue();
+ obfuscatedOutput.textContent = '';
+ loader.style.display = 'block';
+ obfuscateBtn.disabled = true;
+
+ // Give the UI a moment to update
+ await new Promise(resolve => setTimeout(resolve, 50));
+
+ try {
+ const formData = new FormData();
+ formData.append('code', code);
+
+ const response = await fetch('obfuscator.php', {
+ method: 'POST',
+ body: formData
+ });
+
+ if (response.ok) {
+ const result = await response.text();
+ obfuscatedOutput.textContent = result;
+ } else {
+ obfuscatedOutput.textContent = `Error: ${response.statusText}`;
+ }
+
+ } catch (err) {
+ obfuscatedOutput.textContent = `Error: ${err.message}`;
+ console.error(err);
+ } finally {
+ loader.style.display = 'none';
+ obfuscateBtn.disabled = false;
+ }
+ });
+
+ // --- Split View ---
+ Split(['#split-0', '#split-1'], {
+ sizes: [50, 50],
+ minSize: 200,
+ gutterSize: 8,
+ onDrag: function() {
+ editor.resize();
+ }
+ });
+});
diff --git a/db/migrations/001_create_snippets_table.sql b/db/migrations/001_create_snippets_table.sql
new file mode 100644
index 0000000..8f356b1
--- /dev/null
+++ b/db/migrations/001_create_snippets_table.sql
@@ -0,0 +1,8 @@
+-- Migration to create the snippets table for storing shared code.
+
+CREATE TABLE IF NOT EXISTS `snippets` (
+ `id` varchar(16) NOT NULL,
+ `code` text NOT NULL,
+ `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
diff --git a/index.php b/index.php
index 7205f3d..6615209 100644
--- a/index.php
+++ b/index.php
@@ -1,150 +1,143 @@
-
-
+
-
-
- New Style
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ Luau Obfuscator
+
+
+
+
-
-
-
Analyzing your requirements and generating your website…
-
- Loading…
-
-
= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.
-
This page will update automatically as the plan is implemented.
-
Runtime: PHP = htmlspecialchars($phpVersion) ?> — UTC = htmlspecialchars($now) ?>
+
+
+
Luau Obfuscator
+
+
Loading Luau...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
print("Hello, from Luau!\n")
+print("Current time: " .. os.date())
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
Anyone with this link can view your code.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+