cloud-compiler

A real-time, low-latency code ...
Log | Files | Refs | README | LICENSE

commit b3493bb2946933665405d4eacebef3881d10c5b3
parent 25989dde2e1a5495a75c670d85736fedd76316ae
Author: Amit Dutta <amitdutta4255@gmail.com>
Date:   Mon, 12 Jan 2026 11:21:34 +0530

[2025-01-12]

Diffstat:
A.firebaserc | 5+++++
A.gitignore | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abackend.py | 226+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Afirebase.json | 11+++++++++++
Apublic/404.html | 149+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apublic/c.html | 529+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apublic/cpp.html | 527+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apublic/docs.html | 348+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apublic/index.html | 424+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apublic/logo.png | 0
Apublic/python.html | 499+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apublic/sitemap.xml | 28++++++++++++++++++++++++++++
Arequirements.txt | 3+++
13 files changed, 2818 insertions(+), 0 deletions(-)

diff --git a/.firebaserc b/.firebaserc @@ -0,0 +1,5 @@ +{ + "projects": { + "default": "compiler-aranag-site" + } +} diff --git a/.gitignore b/.gitignore @@ -0,0 +1,69 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +firebase-debug.log* +firebase-debug.*.log* + +# Firebase cache +.firebase/ + +# Firebase config + +# Uncomment this if you'd like others to create their own Firebase project. +# For a team working on the same Firebase project(s), it is recommended to leave +# it commented so all members can deploy to the same project(s) in .firebaserc. +# .firebaserc + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +# dataconnect generated files +.dataconnect diff --git a/backend.py b/backend.py @@ -0,0 +1,225 @@ +import asyncio +from aiohttp import web +import json +import subprocess +import os +import sys +import threading +import re +import importlib.util +import platform # <--- FIXED: Added missing import + +# ================================================================================== +# CLOUD COMPILER SERVER (AIOHTTP) - RENDER COMPATIBLE +# ================================================================================== + +def install_package(package_name, ws=None, loop=None): + """Attempt to install a python package via pip.""" + try: + if importlib.util.find_spec(package_name) is not None: + return + + msg = f"Installing missing package: {package_name}..." + print(msg) + if ws and loop: + asyncio.run_coroutine_threadsafe( + ws.send_json({'type': 'status', 'msg': msg}), + loop + ) + + subprocess.check_call([sys.executable, "-m", "pip", "install", package_name]) + except Exception as e: + error_msg = f"Failed to install {package_name}: {e}" + print(error_msg) + if ws and loop: + asyncio.run_coroutine_threadsafe( + ws.send_json({'type': 'stdout', 'data': f"\n[Error] {error_msg}\n"}), + loop + ) + +def check_and_install_packages(code, ws=None, loop=None): + """Scan Python code for imports and install them if missing.""" + imports = re.findall(r'^\s*import\s+(\w+)', code, re.MULTILINE) + from_imports = re.findall(r'^\s*from\s+(\w+)', code, re.MULTILINE) + unique_packages = set(imports + from_imports) + for pkg in unique_packages: + if pkg in ['os', 'sys', 'time', 'random', 'math', 'json', 'asyncio', 'threading', 'platform', 'subprocess', 're']: + continue + install_package(pkg, ws, loop) + +async def handle_client(request): + # --- HEALTH CHECK HANDLING --- + # Render sends HEAD/GET to root. If not a websocket upgrade, return OK. + if request.headers.get("Upgrade", "").lower() != "websocket": + return web.Response(text="OK") + + # --- WEBSOCKET HANDLING --- + ws = web.WebSocketResponse() + await ws.prepare(request) + + print(f"Client connected: {request.remote}") + process = None + + # Helper to read output stream in a separate thread + def read_stream(stream, loop): + try: + while True: + # Read 1 byte/char at a time + char = stream.read(1) + if not char: + break + # aiohttp's send_json is a coroutine + asyncio.run_coroutine_threadsafe( + ws.send_json({'type': 'stdout', 'data': char}), + loop + ) + + # --- SIGNAL FINISH --- + # When stream ends (process exits), tell frontend + asyncio.run_coroutine_threadsafe( + ws.send_json({'type': 'status', 'msg': 'Program finished'}), + loop + ) + + except Exception: + pass + + try: + async for msg in ws: + if msg.type == web.WSMsgType.TEXT: + data = json.loads(msg.data) + + if data.get('type') == 'run': + code = data.get('code') + language = data.get('language', 'python') + + # --- PYTHON HANDLING --- + if language == 'python': + await ws.send_json({'type': 'status', 'msg': 'Checking dependencies...'}) + loop = asyncio.get_running_loop() + await loop.run_in_executor(None, check_and_install_packages, code, ws, loop) + + filename = "temp_script.py" + with open(filename, "w", encoding="utf-8") as f: + f.write(code) + + env = os.environ.copy() + env["PYTHONIOENCODING"] = "utf-8" + + process = subprocess.Popen( + [sys.executable, "-u", filename], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + bufsize=0, + encoding='utf-8', + env=env + ) + await ws.send_json({'type': 'status', 'msg': 'Running Python...'}) + + # --- C HANDLING --- + elif language == 'c': + filename = "temp_code.c" + executable = "./a.out" if platform.system() != "Windows" else "a.exe" + + with open(filename, "w", encoding="utf-8") as f: + f.write(code) + + await ws.send_json({'type': 'status', 'msg': 'Compiling C...'}) + + compile_process = subprocess.run( + ["gcc", filename, "-o", executable], + capture_output=True, + text=True + ) + + if compile_process.returncode != 0: + await ws.send_json({'type': 'stdout', 'data': f"Compilation Error:\n{compile_process.stderr}"}) + continue + + await ws.send_json({'type': 'status', 'msg': 'Running C Binary...'}) + + process = subprocess.Popen( + [executable], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + bufsize=0, + encoding='utf-8' + ) + + # --- C++ HANDLING --- + elif language == 'cpp': + filename = "temp_code.cpp" + executable = "./a.out" if platform.system() != "Windows" else "a.exe" + + with open(filename, "w", encoding="utf-8") as f: + f.write(code) + + await ws.send_json({'type': 'status', 'msg': 'Compiling C++...'}) + + compile_process = subprocess.run( + ["g++", filename, "-o", executable], + capture_output=True, + text=True + ) + + if compile_process.returncode != 0: + await ws.send_json({'type': 'stdout', 'data': f"Compilation Error:\n{compile_process.stderr}"}) + continue + + await ws.send_json({'type': 'status', 'msg': 'Running C++ Binary...'}) + + process = subprocess.Popen( + [executable], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + bufsize=0, + encoding='utf-8' + ) + + if process: + loop = asyncio.get_running_loop() + thread = threading.Thread(target=read_stream, args=(process.stdout, loop)) + thread.daemon = True + thread.start() + + elif data.get('type') == 'input': + if process and process.poll() is None: + user_input = data.get('data') + try: + process.stdin.write(user_input) + process.stdin.flush() + except Exception: + pass + + elif msg.type == web.WSMsgType.ERROR: + print(f'ws connection closed with exception {ws.exception()}') + + finally: + if process: process.kill() + print("Client disconnected") + + return ws + +async def main(): + port = int(os.environ.get("PORT", 8765)) + app = web.Application() + # Route root path to the unified handler (handles both HTTP checks and WS upgrades) + app.add_routes([web.get('/', handle_client)]) + + runner = web.AppRunner(app) + await runner.setup() + site = web.TCPSite(runner, '0.0.0.0', port) + print(f"AIOHTTP Server started on port {port}...") + await site.start() + + # Keep the server running + await asyncio.Event().wait() + +if __name__ == "__main__": + asyncio.run(main())+ \ No newline at end of file diff --git a/firebase.json b/firebase.json @@ -0,0 +1,11 @@ +{ + "hosting": { + "public": "public", + "ignore": [ + "firebase.json", + "**/.*", + "**/node_modules/**" + ], + "cleanUrls": true + } +} diff --git a/public/404.html b/public/404.html @@ -0,0 +1,149 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css'> +<link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Arvo'> + <!-- The font was updated to 'Inter' as requested. --> +<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet"> +</head> + +<style> + body{ + margin:0; + padding:0; + font-family: 'Inter', sans-serif; + height:100vh; +background-image: linear-gradient(to top, #2e1753, #1f1746, #131537, #0d1028, #050819); + display:flex; + justify-content:center; + align-items:center; + overflow:hidden; +} +.text{ + position:absolute; + top:10%; + color:#fff; + text-align:center; +} +h1{ + font-size:50px; +} +.star{ + position:absolute; + width:2px; + height:2px; + background:#fff; + right:0; + animation:starTwinkle 3s infinite linear; +} +.astronaut img{ + width:100px; + position:absolute; + top:55%; + animation:astronautFly 6s infinite linear; +} +@keyframes astronautFly{ + 0%{ + left:-100px; + } + 25%{ + top:50%; + transform:rotate(30deg); + } + 50%{ + transform:rotate(45deg); + top:55%; + } + 75%{ + top:60%; + transform:rotate(30deg); + } + 100%{ + left:110%; + transform:rotate(45deg); + } +} +@keyframes starTwinkle{ + 0%{ + background:rgba(255,255,255,0.4); + } + 25%{ + background:rgba(255,255,255,0.8); + } + 50%{ + background:rgba(255,255,255,1); + } + 75%{ + background:rgba(255,255,255,0.8); + } + 100%{ + background:rgba(255,255,255,0.4); + } +} + + + +@media (max-width: 768px) { + .four_zero_four_bg { + height: 200px; + } + .four_zero_four_bg h1 { + font-size: 40px; + } + .four_zero_four_bg h3 { + font-size: 40px; + } + .button a { + font-size: 16px; + padding: 15px 30px; + } +} +</style> + +<body> + + <div class="text"> + <div>ERROR</div> + <h1>404</h1> + <hr> + <div>Page Not Found</div><br> + <div><a href="https://compiler.aranag.site" style="color: #fff; text-decoration: none;"><u>Go to Homepage</u></a></div> +</div> + +<div class="astronaut"> + <img src="https://images.vexels.com/media/users/3/152639/isolated/preview/506b575739e90613428cdb399175e2c8-space-astronaut-cartoon-by-vexels.png" alt="" class="src"> +</div> + + </div> + </div> + </div> + </div> + </div> +</section> +</body> +<script> + document.addEventListener("DOMContentLoaded",function(){ + + var body=document.body; + setInterval(createStar,100); + function createStar(){ + var right=Math.random()*500; + var top=Math.random()*screen.height; + var star=document.createElement("div"); + star.classList.add("star") + body.appendChild(star); + setInterval(runStar,10); + star.style.top=top+"px"; + function runStar(){ + if(right>=screen.width){ + star.remove(); + } + right+=3; + star.style.right=right+"px"; + } + } +}) +</script> +</html> diff --git a/public/c.html b/public/c.html @@ -0,0 +1,528 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> + <title>Amit Dutta // C Compiler</title> + <link rel="icon" type="image/x-icon" href="https://compiler.aranag.site/logo.png"> + + <!-- Fonts & Icons --> + <link rel="preconnect" href="https://fonts.googleapis.com"> + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> + <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=Inter:wght@300;400;500&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet"> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css"> + + <!-- Tailwind CSS --> + <script src="https://cdn.tailwindcss.com"></script> + + <!-- Xterm.js --> + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.3.0/css/xterm.css" /> + <script src="https://cdn.jsdelivr.net/npm/xterm@5.3.0/lib/xterm.js"></script> + <script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.8.0/lib/xterm-addon-fit.js"></script> + + <style> + :root { + --bg-main: #050505; + --accent: #bef264; /* Lime 300 */ + --text-muted: #737373; + --border-color: rgba(255, 255, 255, 0.1); + } + + body { + font-family: 'Inter', sans-serif; + background-color: var(--bg-main); + color: #f5f5f5; + height: 100vh; + height: 100dvh; + overflow: hidden; + display: flex; + flex-direction: column; + } + + /* Portfolio Aesthetic */ + .font-mono { font-family: 'JetBrains Mono', monospace; } + .font-heading { font-family: 'Space Grotesk', sans-serif; } + + /* Noise Overlay */ + .bg-noise { + position: fixed; top: 0; left: 0; width: 100%; height: 100%; + pointer-events: none; z-index: 0; opacity: 0.03; + background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E"); + } + + /* CRT Scanline */ + .crt-scanline { + position: fixed; top: 0; left: 0; width: 100%; height: 2px; + background: rgba(190, 242, 100, 0.1); opacity: 0.5; + pointer-events: none; z-index: 50; + animation: scanline 8s linear infinite; + } + @keyframes scanline { 0% { top: -10vh; } 100% { top: 110vh; } } + + /* Custom Editor Styles */ + .editor-container { + position: relative; + width: 100%; + height: 100%; + overflow: hidden; + font-family: 'JetBrains Mono', monospace; + font-size: 13px; + line-height: 1.5; + } + + /* The actual textarea for typing */ + #code-input { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + padding: 1rem; + border: none; + outline: none; + background: transparent; + color: #e2e8f0; /* Visible Text */ + caret-color: #fff; /* Cursor visible */ + z-index: 1; + resize: none; + white-space: pre; + overflow: auto; + } + + .xterm-viewport { overflow-y: auto !important; } + + ::selection { background: var(--accent); color: black; } + + .custom-scrollbar::-webkit-scrollbar { width: 6px; height: 6px; } + .custom-scrollbar::-webkit-scrollbar-track { background: #050505; } + .custom-scrollbar::-webkit-scrollbar-thumb { background: #333; border-radius: 3px; } + + /* Toast Notification */ + .toast { + position: fixed; + bottom: 2rem; + left: 50%; + transform: translateX(-50%) translateY(100px); + background: #1a1a1a; + border: 1px solid var(--accent); + color: var(--accent); + padding: 0.5rem 1.5rem; + border-radius: 9999px; + font-family: 'JetBrains Mono', monospace; + font-size: 0.8rem; + transition: transform 0.3s ease; + z-index: 100; + } + .toast.show { transform: translateX(-50%) translateY(0); } + + /* Connection Dot Pulse */ + .pulse-dot { + width: 8px; + height: 8px; + border-radius: 50%; + display: inline-block; + box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.7); + animation: pulse-white 2s infinite; + } + .pulse-dot.connected { + background-color: #bef264; /* Lime */ + box-shadow: 0 0 0 0 rgba(190, 242, 100, 0.7); + animation: pulse-lime 2s infinite; + } + .pulse-dot.disconnected { + background-color: #ef4444; /* Red */ + box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7); + animation: pulse-red 2s infinite; + } + + @keyframes pulse-lime { + 0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(190, 242, 100, 0.7); } + 70% { transform: scale(1); box-shadow: 0 0 0 6px rgba(190, 242, 100, 0); } + 100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(190, 242, 100, 0); } + } + @keyframes pulse-red { + 0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7); } + 70% { transform: scale(1); box-shadow: 0 0 0 6px rgba(239, 68, 68, 0); } + 100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); } + } + </style> +</head> +<body class="antialiased selection:bg-lime-300 selection:text-black"> + + <div class="bg-noise"></div> + <div class="crt-scanline"></div> + <div id="toast" class="toast">Link Copied to Clipboard!</div> + + <!-- Header (Responsive) --> + <header class="h-auto md:h-16 flex flex-col md:flex-row items-center justify-between px-4 py-3 md:px-6 shrink-0 border-b border-white/10 z-20 bg-neutral-900/50 backdrop-blur-md gap-3 md:gap-4"> + + <!-- Top Row: Title & Status --> + <div class="flex items-center justify-between w-full md:w-auto"> + <h1 class="text-lg md:text-xl font-heading font-bold text-white tracking-tight flex items-center"> + <span class="text-lime-300 mr-2">//</span>C.COMPILER + <span id="conn-dot" class="pulse-dot disconnected ml-3" title="Disconnected"></span> + </h1> + + <!-- Mobile Only: Exit Link --> + <a href="./index.html" class="md:hidden font-mono text-[10px] text-neutral-500 hover:text-white uppercase tracking-wider transition-colors">[ EXIT ]</a> + </div> + + <!-- Middle: Connection Text --> + <div class="hidden md:flex items-center gap-2 font-mono text-xs text-neutral-500"> + <span id="connection-status">Connecting to server...</span> + </div> + + <!-- Bottom/Right: Buttons --> + <div class="flex items-center gap-2 w-full md:w-auto justify-end"> + <a href="./index.html" class="hidden md:inline font-mono text-[10px] text-neutral-500 hover:text-white uppercase tracking-wider transition-colors mr-2">[ EXIT ]</a> + + <button id="reset-btn" class="bg-white/5 hover:bg-neutral-800 text-white border border-white/10 px-3 py-2 rounded font-mono text-[10px] font-bold uppercase tracking-wider flex items-center justify-center transition-all" title="Reset Terminal"> + <i class="fas fa-rotate-left"></i> + </button> + + <button id="share-btn" class="bg-white/5 hover:bg-neutral-800 text-white border border-white/10 px-3 py-2 rounded font-mono text-[10px] font-bold uppercase tracking-wider flex items-center justify-center transition-all" title="Share Code"> + <i class="fas fa-share-alt"></i> + </button> + + <button id="copy-btn" class="bg-white/5 hover:bg-neutral-800 text-white border border-white/10 px-3 py-2 rounded font-mono text-[10px] font-bold uppercase tracking-wider flex items-center justify-center transition-all" title="Copy Output"> + <i class="fas fa-copy"></i> + </button> + + <button id="run-btn" disabled class="bg-white/5 hover:bg-lime-300 hover:text-black disabled:opacity-50 disabled:cursor-not-allowed text-white border border-white/10 px-4 py-2 rounded font-mono text-xs font-bold uppercase tracking-wider flex items-center gap-2 transition-all flex-1 md:flex-none justify-center shadow-lg shadow-black/50"> + <i class="fas fa-play text-[10px]"></i> <span class="md:hidden lg:inline">EXECUTE</span><span class="hidden md:inline lg:hidden">RUN</span> + </button> + </div> + </header> + + <!-- Main Workspace --> + <div class="flex-1 flex flex-col md:flex-row min-h-0 z-10 relative"> + + <!-- Code Editor --> + <div class="flex-1 flex flex-col h-[60%] md:h-auto min-h-0 border-b md:border-b-0 md:border-r border-white/10 relative group"> + <div class="bg-black/20 px-4 py-2 text-[10px] font-mono text-lime-300 uppercase border-b border-white/10 flex justify-between items-center shrink-0"> + <span>SRC // main.c</span> + <span class="text-neutral-600">GCC 11.2</span> + </div> + + <!-- Custom Editor Area --> + <div class="editor-container relative bg-[#0c0f16]"> + <textarea id="code-input" spellcheck="false" autocapitalize="off" autocomplete="off" autocorrect="off" class="custom-scrollbar">#include <stdio.h> + +int main() { + int n, i; + printf("Enter count: "); + // Manual flush required for buffered environments + fflush(stdout); + + if (scanf("%d", &n)) { + printf("Counting to %d:\n", n); + for(i=1; i<=n; i++) { + printf("%d ", i); + } + printf("\nDone."); + } + return 0; +}</textarea> + </div> + + <!-- AI Fix Button --> + <button id="ai-fix-btn" class="hidden absolute bottom-4 right-4 bg-red-500/10 border border-red-500/50 text-red-400 hover:bg-red-500 hover:text-white px-3 py-1.5 rounded-lg text-xs font-mono transition-all items-center gap-2 backdrop-blur-md z-20"> + <i class="fas fa-magic"></i> Fix with AI + </button> + </div> + + <!-- Terminal --> + <div class="flex-1 flex flex-col h-[40%] md:h-auto min-h-0 bg-[#050505]"> + <div class="bg-black/20 px-4 py-2 text-[10px] font-mono text-lime-300 uppercase border-b border-white/10 flex justify-between items-center shrink-0"> + <span>OUT // TERMINAL</span> + <span class="text-neutral-600">XTERM.JS</span> + </div> + <div class="flex-1 relative"> + <div id="terminal-container" class="absolute inset-0 w-full h-full p-2 overflow-hidden"></div> + </div> + </div> + </div> + + <script> + // --- DOM Elements --- + const runBtn = document.getElementById('run-btn'); + const resetBtn = document.getElementById('reset-btn'); + const shareBtn = document.getElementById('share-btn'); + const copyBtn = document.getElementById('copy-btn'); + const aiFixBtn = document.getElementById('ai-fix-btn'); + const connDot = document.getElementById('conn-dot'); + const connectionStatus = document.getElementById('connection-status'); + const codeInput = document.getElementById('code-input'); + const toast = document.getElementById('toast'); + + // --- State --- + let socket = null; + let currentLine = ""; + let startTime = 0; + + // --- EDITOR LOGIC --- + codeInput.addEventListener('keydown', function(e) { + if (e.key === 'Tab') { + e.preventDefault(); + const start = this.selectionStart; + const end = this.selectionEnd; + this.setRangeText(' ', start, end, 'end'); + } else if (e.key === 'Enter') { + e.preventDefault(); + const start = this.selectionStart; + const end = this.selectionEnd; + const value = this.value; + const lineStart = value.lastIndexOf('\n', start - 1) + 1; + const currentLineText = value.substring(lineStart, start); + let match = currentLineText.match(/^(\s*)/); + let indent = match ? match[1] : ""; + if (currentLineText.trim().endsWith('{')) indent += " "; + this.setRangeText('\n' + indent, start, end, 'end'); + this.blur(); this.focus(); + } else if (e.key === '}') { + const start = this.selectionStart; + const end = this.selectionEnd; + const value = this.value; + const lineStart = value.lastIndexOf('\n', start - 1) + 1; + const currentLineText = value.substring(lineStart, start); + if (/^\s+$/.test(currentLineText) && currentLineText.length >= 4) { + const newIndent = currentLineText.substring(0, currentLineText.length - 4); + this.setSelectionRange(lineStart, start); + this.setRangeText(newIndent, this.selectionStart, this.selectionEnd, 'end'); + } + } + }); + + window.addEventListener('load', () => { + const params = new URLSearchParams(window.location.search); + const sharedCode = params.get('code'); + if (sharedCode) { + try { codeInput.value = atob(sharedCode); } + catch(e) {} + } + setTimeout(connect, 500); + }); + + // --- Terminal Setup --- + const term = new Terminal({ + theme: { + background: '#050505', + foreground: '#f5f5f5', + cursor: '#bef264', + selectionBackground: 'rgba(190, 242, 100, 0.3)', + black: '#050505', + green: '#bef264', + yellow: '#facc15', + red: '#ef4444', + }, + fontFamily: "'JetBrains Mono', monospace", + fontSize: 12, + cursorBlink: true, + convertEol: true + }); + const fitAddon = new FitAddon.FitAddon(); + term.loadAddon(fitAddon); + term.open(document.getElementById('terminal-container')); + fitAddon.fit(); + window.addEventListener('resize', () => fitAddon.fit()); + + // Custom Key Handler for Ctrl+C Copy + term.attachCustomKeyEventHandler((arg) => { + if (arg.ctrlKey && arg.code === "KeyC" && arg.type === "keydown") { + const selection = term.getSelection(); + if (selection) { + fallbackCopyTextToClipboard(selection); + return false; + } + } + return true; + }); + + term.write('\x1b[38;2;115;115;115m> SYSTEM READY.\r\n> ATTEMPTING CONNECTION...\x1b[0m\r\n'); + + // --- WebSocket Logic --- + function connect() { + const url = "wss://compiler-z4x4.onrender.com"; + try { socket = new WebSocket(url); } catch (e) { + term.write(`\r\n\x1b[31m> INVALID URL.\x1b[0m\r\n`); + return; + } + + socket.onopen = () => { + connDot.className = "pulse-dot connected ml-3"; + if(connectionStatus) connectionStatus.textContent = "Connected to Server"; + if(connectionStatus) connectionStatus.className = "hidden md:flex items-center gap-2 font-mono text-xs text-lime-300"; + + term.write(`\x1b[38;2;190;242;100m> CONNECTION ESTABLISHED.\x1b[0m\r\n> ./a.out\r\n`); + runBtn.disabled = false; + }; + + socket.onclose = () => { + connDot.className = "pulse-dot disconnected ml-3"; + if(connectionStatus) connectionStatus.textContent = "Disconnected"; + if(connectionStatus) connectionStatus.className = "hidden md:flex items-center gap-2 font-mono text-xs text-red-500"; + + term.write(`\r\n\x1b[31m> CONNECTION LOST. RECONNECTING...\x1b[0m\r\n`); + runBtn.disabled = true; + setTimeout(connect, 3000); + socket = null; + }; + + socket.onmessage = (event) => { + const msg = JSON.parse(event.data); + if (msg.type === 'stdout') { + let text = msg.data; + + if (text.toLowerCase().includes("error:") || text.toLowerCase().includes("warning:")) { + aiFixBtn.classList.remove('hidden'); + } + + if (!text.includes('\r')) { + text = text.replace(/\n/g, '\r\n'); + } + term.write(text); + } else if (msg.type === 'status') { + // Detect "Program finished" signal from backend + if (msg.msg.includes("Program finished")) { + const duration = (Date.now() - startTime) / 1000; + term.write(`\r\n\x1b[38;2;115;115;115m[Finished in ${duration.toFixed(3)}s]\x1b[0m\r\n`); + } + } + }; + } + + // --- Run Logic --- + runBtn.addEventListener('click', () => { + if (!socket || socket.readyState !== WebSocket.OPEN) return; + + document.activeElement.blur(); + term.reset(); + currentLine = ""; + aiFixBtn.classList.add('hidden'); + + let code = codeInput.value; + code = code.replace(/\u00A0/g, " ").replace(/[\u2018\u2019]/g, "'").replace(/[\u201C\u201D]/g, '"'); + + function injectAutoFlush(source) { + const mainRegex = /(int|void)\s+main\s*\([^)]*\)\s*\{/; + const match = source.match(mainRegex); + if (match) { + const insertionPoint = match.index + match[0].length; + return source.slice(0, insertionPoint) + "\n setbuf(stdout, NULL);" + source.slice(insertionPoint); + } + return source; + } + code = injectAutoFlush(code); + + startTime = Date.now(); + term.write('\x1b[32m> ./a.out\x1b[0m\r\n'); + + socket.send(JSON.stringify({ + type: 'run', + code: code, + language: 'c' + })); + + term.focus(); + }); + + // --- Reset Logic --- + resetBtn.addEventListener('click', () => { + term.reset(); + currentLine = ""; + term.write(`\x1b[38;2;190;242;100m> CONNECTION ESTABLISHED.\x1b[0m\r\n> ./a.out\r\n`); + }); + + // --- Share Functionality with Native Share API --- + shareBtn.addEventListener('click', async () => { + const code = codeInput.value; + const encoded = btoa(code); + const url = new URL(window.location.href); + url.searchParams.set('code', encoded); + const shareUrl = url.toString(); + + // Try native sharing first (Mobile/Supported Browsers) + if (navigator.share) { + try { + await navigator.share({ + title: document.title, + text: 'Check out my C code!', + url: shareUrl + }); + } catch (err) { + // Ignore cancellation or errors, no fallback needed if cancelled + } + } else { + // Fallback to clipboard copy + fallbackCopyTextToClipboard(shareUrl); + } + }); + + function showToast(msg) { + toast.textContent = msg; + toast.classList.add('show'); + setTimeout(() => toast.classList.remove('show'), 3000); + } + + // --- Smart Copy Function --- + copyBtn.addEventListener('click', () => { + const buffer = term.buffer.active; + let text = ""; + for (let i = 0; i < buffer.length; i++) { + const line = buffer.getLine(i); + if (line) { + let lineText = line.translateToString(true); + if(lineText.trim().startsWith("> [") || lineText.trim().startsWith("> ./a.out") || lineText.includes("SYSTEM READY") || lineText.includes("ATTEMPTING") || lineText.includes("CONNECTION")) { + continue; + } + text += lineText + "\n"; + } + } + text = text.trim(); + fallbackCopyTextToClipboard(text); + }); + + function fallbackCopyTextToClipboard(text) { + const textArea = document.createElement("textarea"); + textArea.value = text; + textArea.style.position = "fixed"; + textArea.style.top = "0"; + textArea.style.left = "0"; + textArea.style.opacity = "0"; + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + try { + document.execCommand('copy'); + showToast("Copied to Clipboard!"); + } catch (err) { + showToast("Copy Failed"); + } + document.body.removeChild(textArea); + } + + aiFixBtn.addEventListener('click', () => { + alert("AI Feature: Coming Soon via Backend Update"); + }); + + // Terminal Input + term.onData((data) => { + if (!socket || socket.readyState !== WebSocket.OPEN) return; + + if (data === '\r') { + term.write('\r\n'); + socket.send(JSON.stringify({ type: 'input', data: currentLine + '\n' })); + currentLine = ""; + } else if (data === '\x7f' || data === '\b') { + if (currentLine.length > 0) { + currentLine = currentLine.slice(0, -1); + term.write('\b \b'); + } + } else { + currentLine += data; + term.write(data); + } + }); + </script> +</body> +</html>+ \ No newline at end of file diff --git a/public/cpp.html b/public/cpp.html @@ -0,0 +1,526 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> + <title>Amit Dutta // C++ Compiler</title> + <link rel="icon" type="image/x-icon" href="https://compiler.aranag.site/logo.png"> + + <!-- Fonts & Icons --> + <link rel="preconnect" href="https://fonts.googleapis.com"> + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> + <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=Inter:wght@300;400;500&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet"> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css"> + + <!-- Tailwind CSS --> + <script src="https://cdn.tailwindcss.com"></script> + + <!-- Xterm.js --> + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.3.0/css/xterm.css" /> + <script src="https://cdn.jsdelivr.net/npm/xterm@5.3.0/lib/xterm.js"></script> + <script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.8.0/lib/xterm-addon-fit.js"></script> + + <style> + :root { + --bg-main: #050505; + --accent: #bef264; /* Lime 300 */ + --text-muted: #737373; + --border-color: rgba(255, 255, 255, 0.1); + } + + body { + font-family: 'Inter', sans-serif; + background-color: var(--bg-main); + color: #f5f5f5; + height: 100vh; + height: 100dvh; + overflow: hidden; + display: flex; + flex-direction: column; + } + + /* Portfolio Aesthetic */ + .font-mono { font-family: 'JetBrains Mono', monospace; } + .font-heading { font-family: 'Space Grotesk', sans-serif; } + + /* Noise Overlay */ + .bg-noise { + position: fixed; top: 0; left: 0; width: 100%; height: 100%; + pointer-events: none; z-index: 0; opacity: 0.03; + background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E"); + } + + /* CRT Scanline */ + .crt-scanline { + position: fixed; top: 0; left: 0; width: 100%; height: 2px; + background: rgba(190, 242, 100, 0.1); opacity: 0.5; + pointer-events: none; z-index: 50; + animation: scanline 8s linear infinite; + } + @keyframes scanline { 0% { top: -10vh; } 100% { top: 110vh; } } + + /* Custom Editor Styles */ + .editor-container { + position: relative; + width: 100%; + height: 100%; + overflow: hidden; + font-family: 'JetBrains Mono', monospace; + font-size: 13px; + line-height: 1.5; + } + + /* The actual textarea for typing */ + #code-input { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + padding: 1rem; + border: none; + outline: none; + background: transparent; + color: #e2e8f0; /* Visible Text */ + caret-color: #fff; /* Cursor visible */ + z-index: 1; + resize: none; + white-space: pre; + overflow: auto; + } + + .xterm-viewport { overflow-y: auto !important; } + + ::selection { background: var(--accent); color: black; } + + .custom-scrollbar::-webkit-scrollbar { width: 6px; height: 6px; } + .custom-scrollbar::-webkit-scrollbar-track { background: #050505; } + .custom-scrollbar::-webkit-scrollbar-thumb { background: #333; border-radius: 3px; } + + /* Toast Notification */ + .toast { + position: fixed; + bottom: 2rem; + left: 50%; + transform: translateX(-50%) translateY(100px); + background: #1a1a1a; + border: 1px solid var(--accent); + color: var(--accent); + padding: 0.5rem 1.5rem; + border-radius: 9999px; + font-family: 'JetBrains Mono', monospace; + font-size: 0.8rem; + transition: transform 0.3s ease; + z-index: 100; + } + .toast.show { transform: translateX(-50%) translateY(0); } + + /* Connection Dot Pulse */ + .pulse-dot { + width: 8px; + height: 8px; + border-radius: 50%; + display: inline-block; + box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.7); + animation: pulse-white 2s infinite; + } + .pulse-dot.connected { + background-color: #bef264; /* Lime */ + box-shadow: 0 0 0 0 rgba(190, 242, 100, 0.7); + animation: pulse-lime 2s infinite; + } + .pulse-dot.disconnected { + background-color: #ef4444; /* Red */ + box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7); + animation: pulse-red 2s infinite; + } + + @keyframes pulse-lime { + 0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(190, 242, 100, 0.7); } + 70% { transform: scale(1); box-shadow: 0 0 0 6px rgba(190, 242, 100, 0); } + 100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(190, 242, 100, 0); } + } + @keyframes pulse-red { + 0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7); } + 70% { transform: scale(1); box-shadow: 0 0 0 6px rgba(239, 68, 68, 0); } + 100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); } + } + </style> +</head> +<body class="antialiased selection:bg-lime-300 selection:text-black"> + + <div class="bg-noise"></div> + <div class="crt-scanline"></div> + <div id="toast" class="toast">Link Copied to Clipboard!</div> + + <!-- Header (Responsive) --> + <header class="h-auto md:h-16 flex flex-col md:flex-row items-center justify-between px-4 py-3 md:px-6 shrink-0 border-b border-white/10 z-20 bg-neutral-900/50 backdrop-blur-md gap-3 md:gap-4"> + + <!-- Top Row: Title & Status --> + <div class="flex items-center justify-between w-full md:w-auto"> + <h1 class="text-lg md:text-xl font-heading font-bold text-white tracking-tight flex items-center"> + <span class="text-lime-300 mr-2">//</span>CPP.COMPILER + <span id="conn-dot" class="pulse-dot disconnected ml-3" title="Disconnected"></span> + </h1> + + <!-- Mobile Only: Exit Link --> + <a href="./index.html" class="md:hidden font-mono text-[10px] text-neutral-500 hover:text-white uppercase tracking-wider transition-colors">[ EXIT ]</a> + </div> + + <!-- Middle: Connection Text --> + <div class="hidden md:flex items-center gap-2 font-mono text-xs text-neutral-500"> + <span id="connection-status">Connecting to server...</span> + </div> + + <!-- Bottom/Right: Buttons --> + <div class="flex items-center gap-2 w-full md:w-auto justify-end"> + <a href="./index.html" class="hidden md:inline font-mono text-[10px] text-neutral-500 hover:text-white uppercase tracking-wider transition-colors mr-2">[ EXIT ]</a> + + <button id="reset-btn" class="bg-white/5 hover:bg-neutral-800 text-white border border-white/10 px-3 py-2 rounded font-mono text-[10px] font-bold uppercase tracking-wider flex items-center justify-center transition-all" title="Reset Terminal"> + <i class="fas fa-rotate-left"></i> + </button> + + <button id="share-btn" class="bg-white/5 hover:bg-neutral-800 text-white border border-white/10 px-3 py-2 rounded font-mono text-[10px] font-bold uppercase tracking-wider flex items-center justify-center transition-all" title="Share Code"> + <i class="fas fa-share-alt"></i> + </button> + + <button id="copy-btn" class="bg-white/5 hover:bg-neutral-800 text-white border border-white/10 px-3 py-2 rounded font-mono text-[10px] font-bold uppercase tracking-wider flex items-center justify-center transition-all" title="Copy Output"> + <i class="fas fa-copy"></i> + </button> + + <button id="run-btn" disabled class="bg-white/5 hover:bg-lime-300 hover:text-black disabled:opacity-50 disabled:cursor-not-allowed text-white border border-white/10 px-4 py-2 rounded font-mono text-xs font-bold uppercase tracking-wider flex items-center gap-2 transition-all flex-1 md:flex-none justify-center shadow-lg shadow-black/50"> + <i class="fas fa-play text-[10px]"></i> <span class="md:hidden lg:inline">EXECUTE</span><span class="hidden md:inline lg:hidden">RUN</span> + </button> + </div> + </header> + + <!-- Main Workspace --> + <div class="flex-1 flex flex-col md:flex-row min-h-0 z-10 relative"> + + <!-- Code Editor --> + <div class="flex-1 flex flex-col h-[60%] md:h-auto min-h-0 border-b md:border-b-0 md:border-r border-white/10 relative group"> + <div class="bg-black/20 px-4 py-2 text-[10px] font-mono text-lime-300 uppercase border-b border-white/10 flex justify-between items-center shrink-0"> + <span>SRC // main.cpp</span> + <span class="text-neutral-600">G++ 11.2</span> + </div> + + <!-- Custom Editor Area --> + <div class="editor-container relative bg-[#0c0f16]"> + <textarea id="code-input" spellcheck="false" autocapitalize="off" autocomplete="off" autocorrect="off" class="custom-scrollbar">#include <iostream> +#include <string> + +int main() { + std::string name; + + std::cout << "Enter your name: "; + // Force flush ensures prompt appears immediately in buffered environments + std::cout.flush(); + + std::cin >> name; + std::cout << "Hello, " << name << "!" << std::endl; + + return 0; +}</textarea> + </div> + + <!-- AI Fix Button --> + <button id="ai-fix-btn" class="hidden absolute bottom-4 right-4 bg-red-500/10 border border-red-500/50 text-red-400 hover:bg-red-500 hover:text-white px-3 py-1.5 rounded-lg text-xs font-mono transition-all items-center gap-2 backdrop-blur-md z-20"> + <i class="fas fa-magic"></i> Fix with AI + </button> + </div> + + <!-- Terminal --> + <div class="flex-1 flex flex-col h-[40%] md:h-auto min-h-0 bg-[#050505]"> + <div class="bg-black/20 px-4 py-2 text-[10px] font-mono text-lime-300 uppercase border-b border-white/10 flex justify-between items-center shrink-0"> + <span>OUT // TERMINAL</span> + <span class="text-neutral-600">XTERM.JS</span> + </div> + <div class="flex-1 relative"> + <div id="terminal-container" class="absolute inset-0 w-full h-full p-2 overflow-hidden"></div> + </div> + </div> + </div> + + <script> + // --- DOM Elements --- + const runBtn = document.getElementById('run-btn'); + const resetBtn = document.getElementById('reset-btn'); + const shareBtn = document.getElementById('share-btn'); + const copyBtn = document.getElementById('copy-btn'); + const aiFixBtn = document.getElementById('ai-fix-btn'); + const connDot = document.getElementById('conn-dot'); + const connectionStatus = document.getElementById('connection-status'); + const codeInput = document.getElementById('code-input'); + const toast = document.getElementById('toast'); + + // --- State --- + let socket = null; + let currentLine = ""; + let startTime = 0; + + // --- EDITOR LOGIC (Indentation) --- + codeInput.addEventListener('keydown', function(e) { + if (e.key === 'Tab') { + e.preventDefault(); + const start = this.selectionStart; + const end = this.selectionEnd; + this.setRangeText(' ', start, end, 'end'); + } else if (e.key === 'Enter') { + e.preventDefault(); + const start = this.selectionStart; + const end = this.selectionEnd; + const value = this.value; + const lineStart = value.lastIndexOf('\n', start - 1) + 1; + const currentLineText = value.substring(lineStart, start); + let match = currentLineText.match(/^(\s*)/); + let indent = match ? match[1] : ""; + if (currentLineText.trim().endsWith('{')) indent += " "; + this.setRangeText('\n' + indent, start, end, 'end'); + this.blur(); this.focus(); + } else if (e.key === '}') { + const start = this.selectionStart; + const end = this.selectionEnd; + const value = this.value; + const lineStart = value.lastIndexOf('\n', start - 1) + 1; + const currentLineText = value.substring(lineStart, start); + if (/^\s+$/.test(currentLineText) && currentLineText.length >= 4) { + const newIndent = currentLineText.substring(0, currentLineText.length - 4); + this.setSelectionRange(lineStart, start); + this.setRangeText(newIndent, this.selectionStart, this.selectionEnd, 'end'); + } + } + }); + + window.addEventListener('load', () => { + const params = new URLSearchParams(window.location.search); + const sharedCode = params.get('code'); + if (sharedCode) { + try { codeInput.value = atob(sharedCode); } + catch(e) {} + } + setTimeout(connect, 500); + }); + + // --- Terminal Setup --- + const term = new Terminal({ + theme: { + background: '#050505', + foreground: '#f5f5f5', + cursor: '#bef264', + selectionBackground: 'rgba(190, 242, 100, 0.3)', + black: '#050505', + green: '#bef264', + yellow: '#facc15', + red: '#ef4444', + }, + fontFamily: "'JetBrains Mono', monospace", + fontSize: 12, + cursorBlink: true, + convertEol: true + }); + const fitAddon = new FitAddon.FitAddon(); + term.loadAddon(fitAddon); + term.open(document.getElementById('terminal-container')); + fitAddon.fit(); + window.addEventListener('resize', () => fitAddon.fit()); + + // Custom Key Handler for Ctrl+C Copy + term.attachCustomKeyEventHandler((arg) => { + if (arg.ctrlKey && arg.code === "KeyC" && arg.type === "keydown") { + const selection = term.getSelection(); + if (selection) { + fallbackCopyTextToClipboard(selection); + return false; + } + } + return true; + }); + + term.write('\x1b[38;2;115;115;115m> SYSTEM READY.\r\n> ATTEMPTING CONNECTION...\x1b[0m\r\n'); + + // --- WebSocket Logic --- + function connect() { + const url = "wss://compiler-z4x4.onrender.com"; + try { socket = new WebSocket(url); } catch (e) { + term.write(`\r\n\x1b[31m> INVALID URL.\x1b[0m\r\n`); + return; + } + + socket.onopen = () => { + connDot.className = "pulse-dot connected ml-3"; + if(connectionStatus) connectionStatus.textContent = "Connected to Server"; + if(connectionStatus) connectionStatus.className = "hidden md:flex items-center gap-2 font-mono text-xs text-lime-300"; + + term.write(`\x1b[38;2;190;242;100m> CONNECTION ESTABLISHED.\x1b[0m\r\n> ./a.out\r\n`); + runBtn.disabled = false; + }; + + socket.onclose = () => { + connDot.className = "pulse-dot disconnected ml-3"; + if(connectionStatus) connectionStatus.textContent = "Disconnected"; + if(connectionStatus) connectionStatus.className = "hidden md:flex items-center gap-2 font-mono text-xs text-red-500"; + + term.write(`\r\n\x1b[31m> CONNECTION LOST. RECONNECTING...\x1b[0m\r\n`); + runBtn.disabled = true; + setTimeout(connect, 3000); + socket = null; + }; + + socket.onmessage = (event) => { + const msg = JSON.parse(event.data); + if (msg.type === 'stdout') { + let text = msg.data; + + if (text.toLowerCase().includes("error:") || text.toLowerCase().includes("warning:")) { + aiFixBtn.classList.remove('hidden'); + } + + if (!text.includes('\r')) { + text = text.replace(/\n/g, '\r\n'); + } + term.write(text); + } else if (msg.type === 'status') { + if (msg.msg.includes("Program finished")) { + const duration = (Date.now() - startTime) / 1000; + term.write(`\r\n\x1b[38;2;115;115;115m[Finished in ${duration.toFixed(3)}s]\x1b[0m\r\n`); + } + } + }; + } + + // --- Run Logic --- + runBtn.addEventListener('click', () => { + if (!socket || socket.readyState !== WebSocket.OPEN) return; + + document.activeElement.blur(); + term.reset(); + currentLine = ""; + aiFixBtn.classList.add('hidden'); + + let code = codeInput.value; + code = code.replace(/\u00A0/g, " ").replace(/[\u2018\u2019]/g, "'").replace(/[\u201C\u201D]/g, '"'); + + // Auto-inject std::cout.setf(std::ios::unitbuf); for C++ + function injectAutoFlush(source) { + const mainRegex = /(int|void)\s+main\s*\([^)]*\)\s*\{/; + const match = source.match(mainRegex); + if (match) { + const insertionPoint = match.index + match[0].length; + return source.slice(0, insertionPoint) + "\n std::cout.setf(std::ios::unitbuf); // Auto-injected" + source.slice(insertionPoint); + } + return source; + } + code = injectAutoFlush(code); + + startTime = Date.now(); + term.write('\x1b[32m> ./a.out\x1b[0m\r\n'); + + socket.send(JSON.stringify({ + type: 'run', + code: code, + language: 'cpp' + })); + + term.focus(); + }); + + // --- Reset Logic --- + resetBtn.addEventListener('click', () => { + term.reset(); + currentLine = ""; + term.write(`\x1b[38;2;190;242;100m> CONNECTION ESTABLISHED.\x1b[0m\r\n> ./a.out\r\n`); + }); + + // --- Share Functionality with Native Share API --- + shareBtn.addEventListener('click', async () => { + const code = codeInput.value; + const encoded = btoa(code); + const url = new URL(window.location.href); + url.searchParams.set('code', encoded); + const shareUrl = url.toString(); + + // Try native sharing first (Mobile/Supported Browsers) + if (navigator.share) { + try { + await navigator.share({ + title: document.title, + text: 'Check out my C++ code!', + url: shareUrl + }); + } catch (err) { + // Ignore cancellation or errors + } + } else { + // Fallback to clipboard copy + fallbackCopyTextToClipboard(shareUrl); + } + }); + + function showToast(msg) { + toast.textContent = msg; + toast.classList.add('show'); + setTimeout(() => toast.classList.remove('show'), 3000); + } + + // --- Smart Copy Function --- + copyBtn.addEventListener('click', () => { + const buffer = term.buffer.active; + let text = ""; + for (let i = 0; i < buffer.length; i++) { + const line = buffer.getLine(i); + if (line) { + let lineText = line.translateToString(true); + if(lineText.trim().startsWith("> [") || lineText.trim().startsWith("> ./a.out") || lineText.includes("SYSTEM READY") || lineText.includes("ATTEMPTING") || lineText.includes("CONNECTION")) { + continue; + } + text += lineText + "\n"; + } + } + text = text.trim(); + fallbackCopyTextToClipboard(text); + }); + + function fallbackCopyTextToClipboard(text) { + const textArea = document.createElement("textarea"); + textArea.value = text; + textArea.style.position = "fixed"; + textArea.style.top = "0"; + textArea.style.left = "0"; + textArea.style.opacity = "0"; + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + try { + document.execCommand('copy'); + showToast("Copied to Clipboard!"); + } catch (err) { + showToast("Copy Failed"); + } + document.body.removeChild(textArea); + } + + aiFixBtn.addEventListener('click', () => { + showToast("AI Feature: Coming Soon via Backend Update"); + }); + + // Terminal Input + term.onData((data) => { + if (!socket || socket.readyState !== WebSocket.OPEN) return; + + if (data === '\r') { + term.write('\r\n'); + socket.send(JSON.stringify({ type: 'input', data: currentLine + '\n' })); + currentLine = ""; + } else if (data === '\x7f' || data === '\b') { + if (currentLine.length > 0) { + currentLine = currentLine.slice(0, -1); + term.write('\b \b'); + } + } else { + currentLine += data; + term.write(data); + } + }); + </script> +</body> +</html>+ \ No newline at end of file diff --git a/public/docs.html b/public/docs.html @@ -0,0 +1,347 @@ +<!DOCTYPE html> +<html lang="en" class="scroll-smooth"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Documentation // Cloud Code Compiler</title> + <link rel="icon" type="image/x-icon" href="https://compiler.amit.is-a.dev/logo.png"> + + <!-- Fonts --> + <link rel="preconnect" href="https://fonts.googleapis.com"> + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> + <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=Inter:wght@300;400;500&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet"> + + <!-- Libraries --> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css"> + <script src="https://cdn.tailwindcss.com"></script> + <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css"> + + <style> + :root { + --bg-main: #050505; + --accent: #bef264; /* Lime 300 */ + --text-muted: #737373; + --border-color: rgba(255, 255, 255, 0.1); + } + + body { + font-family: 'Inter', sans-serif; + background-color: var(--bg-main); + color: #f5f5f5; + line-height: 1.6; + } + + .font-mono { font-family: 'JetBrains Mono', monospace; } + .font-heading { font-family: 'Space Grotesk', sans-serif; } + + /* Custom Scrollbar */ + ::-webkit-scrollbar { width: 8px; } + ::-webkit-scrollbar-track { background: #050505; } + ::-webkit-scrollbar-thumb { background: #333; border-radius: 4px; } + ::-webkit-scrollbar-thumb:hover { background: #555; } + + /* Doc Sections */ + .doc-section { + margin-bottom: 4rem; + scroll-margin-top: 6rem; + } + + .code-block { + background: #0f1115; + border: 1px solid var(--border-color); + border-radius: 0.75rem; + padding: 1rem; + margin: 1.5rem 0; + font-size: 0.9rem; + } + + .nav-link { + display: block; + padding: 0.5rem 1rem; + color: var(--text-muted); + border-left: 2px solid transparent; + transition: all 0.2s; + } + .nav-link:hover, .nav-link.active { + color: var(--accent); + border-left-color: var(--accent); + background: rgba(190, 242, 100, 0.05); + } + + /* Noise Overlay */ + .bg-noise { + position: fixed; top: 0; left: 0; width: 100%; height: 100%; + pointer-events: none; z-index: 0; opacity: 0.03; + background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E"); + } + </style> +</head> +<body class="antialiased selection:bg-lime-300 selection:text-black"> + + <div class="bg-noise"></div> + + <!-- Layout Grid --> + <div class="max-w-7xl mx-auto px-6 py-12 grid grid-cols-1 lg:grid-cols-4 gap-12 relative z-10"> + + <!-- Sidebar Navigation --> + <aside class="hidden lg:block col-span-1 sticky top-12 h-[calc(100vh-6rem)] overflow-y-auto pr-4"> + <div class="mb-8"> + <a href="./index.html" class="flex items-center gap-2 group"> + <i class="fas fa-arrow-left text-neutral-500 group-hover:text-white transition-colors"></i> + <span class="font-heading font-bold text-xl text-white">Back to Home</span> + </a> + </div> + + <nav class="space-y-1"> + <p class="px-4 text-xs font-mono text-neutral-500 uppercase tracking-widest mb-2">Contents</p> + <a href="#architecture" class="nav-link font-mono text-sm">Architecture</a> + <a href="#communication" class="nav-link font-mono text-sm">WebSocket Protocol</a> + <a href="#python-engine" class="nav-link font-mono text-sm">Python Engine</a> + <a href="#cpp-engine" class="nav-link font-mono text-sm">C / C++ Engine</a> + <a href="#security" class="nav-link font-mono text-sm">Security & Sandbox</a> + <a href="#privacy" class="nav-link font-mono text-sm">Privacy & Data</a> + <a href="#disclaimer" class="nav-link font-mono text-sm">Legal & Disclaimer</a> + </nav> + + <div class="mt-12 p-4 rounded-xl bg-white/5 border border-white/10"> + <p class="text-xs text-neutral-400 mb-2">Powered by</p> + <div class="flex flex-wrap gap-2"> + <span class="text-xs px-2 py-1 rounded bg-black border border-white/10 text-lime-300 font-mono">aiohttp</span> + <span class="text-xs px-2 py-1 rounded bg-black border border-white/10 text-lime-300 font-mono">Python 3.10</span> + <span class="text-xs px-2 py-1 rounded bg-black border border-white/10 text-lime-300 font-mono">GCC 11</span> + </div> + </div> + </aside> + + <!-- Main Content --> + <main class="col-span-1 lg:col-span-3"> + + <!-- Mobile Header --> + <div class="lg:hidden mb-12"> + <a href="./index.html" class="flex items-center gap-2 text-neutral-400 hover:text-white mb-6"> + <i class="fas fa-arrow-left"></i> Return Home + </a> + <h1 class="text-4xl font-heading font-bold text-white">System Documentation</h1> + </div> + + <!-- Intro --> + <div class="mb-16 border-b border-white/10 pb-12"> + <h1 class="hidden lg:block text-5xl font-heading font-bold text-white mb-6">System Documentation</h1> + <p class="text-xl text-neutral-400 leading-relaxed max-w-3xl"> + A technical deep-dive into the Cloud Code Compiler. Learn how we achieve low-latency remote execution, handle real-time I/O streams, and manage dynamic dependency resolution. + </p> + </div> + + <!-- Architecture --> + <section id="architecture" class="doc-section"> + <h2 class="text-2xl font-heading font-bold text-lime-300 mb-6 flex items-center"> + <span class="mr-3">01.</span> Architecture + </h2> + <p class="text-neutral-300 mb-4"> + The compiler uses a client-server model optimized for persistent connections. Unlike traditional stateless REST APIs which require polling for output, we utilize <strong>WebSockets</strong> to maintain a full-duplex communication channel between the browser's xterm.js terminal and the backend process. + </p> + <div class="grid grid-cols-1 md:grid-cols-2 gap-6 my-8"> + <div class="p-6 rounded-xl bg-white/5 border border-white/10"> + <h3 class="text-white font-bold mb-2"><i class="fas fa-desktop text-lime-300 mr-2"></i> Frontend</h3> + <p class="text-sm text-neutral-400">Xterm.js renders a TTY-like interface. User keystrokes are captured and sent as binary/text frames.</p> + </div> + <div class="p-6 rounded-xl bg-white/5 border border-white/10"> + <h3 class="text-white font-bold mb-2"><i class="fas fa-server text-lime-300 mr-2"></i> Backend</h3> + <p class="text-sm text-neutral-400">Python <code>aiohttp</code> server running on Linux. Spawns <code>subprocess</code> threads for isolation.</p> + </div> + </div> + </section> + + <!-- WebSocket Protocol --> + <section id="communication" class="doc-section"> + <h2 class="text-2xl font-heading font-bold text-lime-300 mb-6 flex items-center"> + <span class="mr-3">02.</span> WebSocket Protocol + </h2> + <p class="text-neutral-300 mb-4"> + Communication occurs via JSON payloads. The server handles two main event types: <strong>execution</strong> and <strong>input streaming</strong>. + </p> + + <h3 class="text-lg font-bold text-white mt-6 mb-2">Client -> Server</h3> + <div class="code-block"> + <pre><code class="language-json">// 1. Initiate Execution +{ + "type": "run", + "language": "python", // or "c", "cpp" + "code": "print('Hello World')" +} + +// 2. Send User Input (stdin) +{ + "type": "input", + "data": "user_input_string\n" +}</code></pre> + </div> + + <h3 class="text-lg font-bold text-white mt-6 mb-2">Server -> Client</h3> + <div class="code-block"> + <pre><code class="language-json">// 1. Standard Output/Error Stream (sent character-by-character or chunked) +{ + "type": "stdout", + "data": "H" +} + +// 2. Status Updates +{ + "type": "status", + "msg": "Compiling..." +}</code></pre> + </div> + </section> + + <!-- Python Engine --> + <section id="python-engine" class="doc-section"> + <h2 class="text-2xl font-heading font-bold text-lime-300 mb-6 flex items-center"> + <span class="mr-3">03.</span> Python Engine & Auto-Pip + </h2> + <p class="text-neutral-300 mb-4"> + The Python runner is equipped with a dynamic dependency resolver. Before execution, the backend statically analyzes the code imports using RegEx. + </p> + + <div class="p-6 rounded-xl border border-lime-300/20 bg-lime-300/5 mb-6"> + <h4 class="font-bold text-white mb-2">Feature: Dynamic Installation</h4> + <p class="text-sm text-neutral-300"> + If a user imports a non-standard library (e.g., <code>import numpy</code>), the server automatically runs <code>pip install numpy</code> before executing the script. This allows for rich script execution without pre-configuration. + </p> + </div> + + <div class="code-block"> + <pre><code class="language-python"># Backend Logic Snippet +def check_and_install_packages(code): + imports = re.findall(r'^\s*import\s+(\w+)', code, re.MULTILINE) + for pkg in imports: + if pkg not in standard_libs: + subprocess.check_call([sys.executable, "-m", "pip", "install", pkg])</code></pre> + </div> + </section> + + <!-- C / C++ Engine --> + <section id="cpp-engine" class="doc-section"> + <h2 class="text-2xl font-heading font-bold text-lime-300 mb-6 flex items-center"> + <span class="mr-3">04.</span> C / C++ Compilation + </h2> + <p class="text-neutral-300 mb-4"> + For compiled languages, the server performs a two-step process. Source code is written to a temporary file, compiled via GCC/G++, and then executed. + </p> + <ul class="list-disc list-inside text-neutral-400 space-y-2 mb-6 ml-4"> + <li><strong>C:</strong> <code>gcc temp.c -o a.out</code></li> + <li><strong>C++:</strong> <code>g++ temp.cpp -o a.out</code></li> + </ul> + <p class="text-neutral-300"> + Standard Input buffer flushing is handled automatically to ensure prompts (like <code>cin >> var</code>) appear immediately in the terminal before blocking for input. + </p> + </section> + + <!-- Security --> + <section id="security" class="doc-section"> + <h2 class="text-2xl font-heading font-bold text-lime-300 mb-6 flex items-center"> + <span class="mr-3">05.</span> Security & Limitations + </h2> + <p class="text-neutral-300 mb-4"> + The current implementation runs code directly on the host instance. While effective for a portfolio demonstration or trusted environment, this setup is <strong>not sandboxed</strong>. + </p> + <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> + <div class="p-4 border border-red-500/30 bg-red-500/5 rounded-lg"> + <h4 class="text-red-400 font-bold mb-2">Current Limitations</h4> + <ul class="text-xs text-neutral-400 space-y-1"> + <li>• No containerization (Docker)</li> + <li>• No CPU/RAM usage quotas</li> + <li>• File system access is unrestricted within user scope</li> + </ul> + </div> + <div class="p-4 border border-lime-300/30 bg-lime-300/5 rounded-lg"> + <h4 class="text-lime-300 font-bold mb-2">Future Roadmap</h4> + <ul class="text-xs text-neutral-400 space-y-1"> + <li>• Docker container per session</li> + <li>• Timeouts for infinite loops</li> + <li>• Network access restrictions</li> + </ul> + </div> + </div> + </section> + + <!-- Privacy & Data Handling --> + <section id="privacy" class="doc-section"> + <h2 class="text-2xl font-heading font-bold text-lime-300 mb-6 flex items-center"> + <span class="mr-3">06.</span> Privacy & Data Handling + </h2> + <p class="text-neutral-300 mb-4"> + We believe in complete transparency regarding how your data is handled. As a demonstration platform, we prioritize privacy and ephemeral execution. + </p> + <div class="grid grid-cols-1 md:grid-cols-3 gap-6 my-8"> + <div class="p-6 rounded-xl bg-white/5 border border-white/10"> + <h3 class="text-white font-bold mb-2"><i class="fas fa-trash-alt text-lime-300 mr-2"></i> No Storage</h3> + <p class="text-sm text-neutral-400"> + Your code is processed in volatile memory or temporary files that are <strong>immediately deleted</strong> after execution. We do not maintain a database of user code. + </p> + </div> + <div class="p-6 rounded-xl bg-white/5 border border-white/10"> + <h3 class="text-white font-bold mb-2"><i class="fas fa-user-secret text-lime-300 mr-2"></i> Anonymous</h3> + <p class="text-sm text-neutral-400"> + No user accounts, cookies, or personal identifiers are required to use the compiler. Usage is completely anonymous. + </p> + </div> + <div class="p-6 rounded-xl bg-white/5 border border-white/10"> + <h3 class="text-white font-bold mb-2"><i class="fab fa-github text-lime-300 mr-2"></i> Open Source</h3> + <p class="text-sm text-neutral-400"> + The entire backend infrastructure is open source. You can audit the code yourself on <a href="https://github.com/notamitgamer" target="_blank" class="text-lime-300 hover:underline">GitHub</a>. + </p> + </div> + </div> + </section> + + <!-- Legal & Disclaimer --> + <section id="disclaimer" class="doc-section"> + <h2 class="text-2xl font-heading font-bold text-lime-300 mb-6 flex items-center"> + <span class="mr-3">07.</span> Legal & Disclaimer + </h2> + <div class="p-6 rounded-xl border border-red-500/20 bg-red-500/5"> + <p class="text-neutral-300 mb-4"> + This compiler infrastructure has been extensively refactored by <strong>Gemini 3 Pro</strong>. For bug reports or inquiries, please contact us via: + </p> + <ul class="text-lime-300 font-mono text-sm mb-6 space-y-1"> + <li><i class="fas fa-envelope mr-2"></i> <a href="mailto:amitdutta4255@gmail.com" class="hover:underline">amitdutta4255@gmail.com</a></li> + <li><i class="fas fa-envelope mr-2"></i> <a href="mailto:mail@amit.is-a.dev" class="hover:underline">mail@amit.is-a.dev</a></li> + <li><i class="fab fa-github mr-2"></i> <a href="https://github.com/notamitgamer" target="_blank" class="hover:underline">@notamitgamer</a></li> + </ul> + <div class="text-neutral-400 text-sm border-t border-white/10 pt-4 leading-relaxed"> + <p class="mb-2"><strong class="text-red-400">Disclaimer of Liability:</strong> Amit Dutta assumes no responsibility or liability for any consequences, errors, or data loss arising from the use of this compiler. This project is provided for demonstration purposes only.</p> + <p class="italic opacity-80">"I explicitly disclaim any affiliation with or responsibility for the ongoing operation of this project. I reserve the absolute right to modify, suspend, or permanently delete this compiler and its associated services at any time, for any reason, without prior notice."</p> + </div> + </div> + </section> + + </main> + </div> + + <script> + hljs.highlightAll(); + + // Simple scroll spy for nav + window.addEventListener('scroll', () => { + const sections = document.querySelectorAll('.doc-section'); + const navLinks = document.querySelectorAll('.nav-link'); + + let current = ''; + sections.forEach(section => { + const sectionTop = section.offsetTop; + if (pageYOffset >= sectionTop - 150) { + current = section.getAttribute('id'); + } + }); + + navLinks.forEach(link => { + link.classList.remove('active'); + if (link.getAttribute('href').includes(current)) { + link.classList.add('active'); + } + }); + }); + </script> +</body> +</html>+ \ No newline at end of file diff --git a/public/index.html b/public/index.html @@ -0,0 +1,423 @@ +<!DOCTYPE html> +<html lang="en" class="scroll-smooth"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="google-site-verification" content="pwteHw44Ax3N2B1zkFzVJB7NIK0-xgQGRihK_vtZTF4" /> + <title>Cloud Code Compiler // Amit Dutta</title> + <link rel="canonical" href="https://compiler.amit.is-a.dev/" /> + <link rel="icon" type="image/x-icon" href="https://compiler.amit.is-a.dev/logo.png"> + + <!-- Fonts --> + <link rel="preconnect" href="https://fonts.googleapis.com"> + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> + <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=Inter:wght@300;400;500&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet"> + + <!-- Libraries --> + <link href="https://unpkg.com/aos@2.3.1/dist/aos.css" rel="stylesheet"> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css"> + <script src="https://cdn.tailwindcss.com"></script> + + <style> + :root { + --bg-main: #050505; + --accent: #bef264; /* Lime 300 */ + --text-muted: #737373; + --border-color: rgba(255, 255, 255, 0.1); + } + + body { + font-family: 'Inter', sans-serif; + background-color: var(--bg-main); + color: #f5f5f5; + overflow-x: hidden; + } + + /* Portfolio Aesthetic */ + .font-mono { font-family: 'JetBrains Mono', monospace; } + .font-heading { font-family: 'Space Grotesk', sans-serif; } + + /* Noise Overlay */ + .bg-noise { + position: fixed; top: 0; left: 0; width: 100%; height: 100%; + pointer-events: none; z-index: 0; opacity: 0.03; + background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E"); + } + + /* CRT Scanline */ + .crt-scanline { + position: fixed; top: 0; left: 0; width: 100%; height: 2px; + background: rgba(190, 242, 100, 0.1); opacity: 0.5; + pointer-events: none; z-index: 50; + animation: scanline 8s linear infinite; + } + @keyframes scanline { 0% { top: -10vh; } 100% { top: 110vh; } } + + /* Compiler Card Styling */ + .compiler-card { + background: rgba(255, 255, 255, 0.02); + border: 1px solid var(--border-color); + border-radius: 1.5rem; + position: relative; + overflow: hidden; + transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); + z-index: 10; + } + + .compiler-card:hover { + transform: translateY(-5px); + border-color: var(--accent); + box-shadow: 0 0 20px rgba(190, 242, 100, 0.1); + } + + .compiler-card::before { + content: ''; + position: absolute; + inset: 0; + background: radial-gradient(800px circle at var(--mouse-x) var(--mouse-y), rgba(255, 255, 255, 0.06), transparent 40%); + opacity: 0; + transition: opacity 0.5s; + pointer-events: none; + } + + .compiler-card:hover::before { + opacity: 1; + } + + .icon-container { + background: rgba(255, 255, 255, 0.03); + border: 1px solid var(--border-color); + transition: all 0.3s ease; + } + + .compiler-card:hover .icon-container { + border-color: var(--accent); + background: rgba(190, 242, 100, 0.1); + } + + /* Buttons */ + .btn-primary { + background-color: var(--accent); + color: #000; + font-family: 'Space Grotesk', sans-serif; + font-weight: 700; + transition: all 0.3s ease; + } + .btn-primary:hover { + background-color: #d9f99d; /* Lime 200 */ + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(190, 242, 100, 0.3); + } + + /* Animations */ + .floating-code { + position: absolute; + font-family: 'JetBrains Mono', monospace; + font-size: 0.8rem; + color: var(--text-muted); + opacity: 0.2; + pointer-events: none; + animation: float 10s infinite ease-in-out; + } + @keyframes float { + 0%, 100% { transform: translateY(0); } + 50% { transform: translateY(-20px); } + } + + /* Social Links */ + .social-link { + background: rgba(255, 255, 255, 0.03); + border: 1px solid var(--border-color); + color: #a3a3a3; + transition: all 0.3s ease; + } + .social-link:hover { + color: var(--accent); + border-color: var(--accent); + transform: translateY(-3px); + } + + ::selection { background: var(--accent); color: black; } + + .typewriter h1 { + border-right: none; + } + + /* Fade in animation for "Create." */ + .fade-in-create { + animation: fadeIn 1s ease-in forwards; + opacity: 0; + } + @keyframes fadeIn { + to { opacity: 1; } + } + </style> +</head> +<body class="antialiased selection:bg-lime-300 selection:text-black"> + + <div class="bg-noise"></div> + <div class="crt-scanline"></div> + + <!-- Background Elements --> + <div class="fixed inset-0 z-0 overflow-hidden pointer-events-none"> + <div class="floating-code" style="top: 15%; left: 10%; animation-delay: 0s;">print("Hello World")</div> + <div class="floating-code" style="top: 25%; right: 15%; animation-delay: 2s;">#include &lt;stdio.h&gt;</div> + <div class="floating-code" style="bottom: 20%; left: 20%; animation-delay: 4s;">std::cout << "Code";</div> + <div class="floating-code" style="bottom: 30%; right: 10%; animation-delay: 1s;">const int MAX = 100;</div> + </div> + + <!-- Hero Section --> + <div class="relative min-h-screen flex flex-col items-center justify-center p-6 z-10"> + + <header class="text-center mb-16" data-aos="fade-up"> + <div class="inline-block mb-4 px-4 py-1 rounded-full border border-white/10 bg-white/5 backdrop-blur-sm"> + <span class="text-xs font-mono text-lime-300 tracking-wider">/// REAL-TIME CLOUD COMPILER</span> + </div> + <div class="typewriter max-w-4xl mx-auto"> + <h1 class="text-4xl sm:text-6xl md:text-7xl font-heading font-bold text-white mb-6 tracking-tight leading-tight"> + <span id="type-text"></span><br /> + <span id="create-text" class="text-lime-300 fade-in-create hidden">Create.</span> + </h1> + </div> + <p class="sub-text-fade opacity-0 text-base sm:text-lg md:text-xl text-gray-400 max-w-3xl mx-auto leading-relaxed mt-4 font-light"> + Experience powerful, server-side code execution with low-latency WebSocket connections. No simulations, just pure performance. + </p> + </header> + + <!-- Compiler Cards --> + <main class="w-full max-w-6xl mx-auto px-4" data-aos="fade-up" data-aos-delay="200"> + <div class="grid grid-cols-1 md:grid-cols-3 gap-6" id="compiler-grid"> + + <!-- C Compiler --> + <a href="./c.html" class="compiler-card p-8 group block"> + <div class="icon-container w-14 h-14 rounded-xl flex items-center justify-center mb-6"> + <span class="font-heading font-bold text-2xl text-white">C</span> + </div> + <h2 class="text-2xl font-heading font-bold text-white mb-2 group-hover:text-lime-300 transition-colors">Standard C</h2> + <p class="text-sm text-neutral-500 mb-6 leading-relaxed"> + Compile standard C programs on a remote server using GCC. Supports pointers and memory logic. + </p> + <div class="flex items-center text-xs font-mono text-lime-300 uppercase tracking-widest"> + Launch <i class="fas fa-arrow-right ml-2 group-hover:translate-x-1 transition-transform"></i> + </div> + </a> + + <!-- C++ Compiler --> + <a href="./cpp.html" class="compiler-card p-8 group block"> + <div class="icon-container w-14 h-14 rounded-xl flex items-center justify-center mb-6"> + <span class="font-heading font-bold text-2xl text-white">C++</span> + </div> + <h2 class="text-2xl font-heading font-bold text-white mb-2 group-hover:text-lime-300 transition-colors">Modern C++</h2> + <p class="text-sm text-neutral-500 mb-6 leading-relaxed"> + Execute C++ code via G++. Features standard input/output streaming and STL support. + </p> + <div class="flex items-center text-xs font-mono text-lime-300 uppercase tracking-widest"> + Launch <i class="fas fa-arrow-right ml-2 group-hover:translate-x-1 transition-transform"></i> + </div> + </a> + + <!-- Python Compiler --> + <a href="./python.html" class="compiler-card p-8 group block"> + <div class="icon-container w-14 h-14 rounded-xl flex items-center justify-center mb-6"> + <i class="fab fa-python text-2xl text-white"></i> + </div> + <h2 class="text-2xl font-heading font-bold text-white mb-2 group-hover:text-lime-300 transition-colors">Python 3</h2> + <p class="text-sm text-neutral-500 mb-6 leading-relaxed"> + Full Python 3 environment with automatic package installation (pip) and interactive shell. + </p> + <div class="flex items-center text-xs font-mono text-lime-300 uppercase tracking-widest"> + Launch <i class="fas fa-arrow-right ml-2 group-hover:translate-x-1 transition-transform"></i> + </div> + </a> + + </div> + + <div class="text-center mt-8"> + <p class="text-[10px] font-mono text-neutral-600 uppercase tracking-widest">More languages loading...</p> + </div> + </main> + + <a href="#features" class="absolute bottom-10 animate-bounce text-neutral-600 hover:text-white transition-colors"> + <i class="fas fa-chevron-down text-xl"></i> + </a> + </div> + + <!-- Features Section --> + <section id="features" class="py-32 px-6 border-t border-white/5 bg-black/20 z-10"> + <div class="max-w-6xl mx-auto"> + <div class="text-center mb-20" data-aos="fade-up"> + <h2 class="text-3xl sm:text-4xl font-heading font-bold text-white mb-4">Engineered for <span class="text-lime-300">Performance</span></h2> + <p class="text-neutral-400 max-w-xl mx-auto">A robust platform designed for real development tasks.</p> + </div> + + <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"> + <!-- Feature 1 --> + <div class="compiler-card p-8" data-aos="fade-up" data-aos-delay="100"> + <i class="fas fa-server text-2xl text-lime-300 mb-6"></i> + <h3 class="text-xl font-bold text-white mb-3">Real Backend</h3> + <p class="text-sm text-neutral-500 leading-relaxed">Code is executed on a live Linux server instance, ensuring accurate runtime behavior.</p> + </div> + <!-- Feature 2 --> + <div class="compiler-card p-8" data-aos="fade-up" data-aos-delay="200"> + <i class="fas fa-bolt text-2xl text-lime-300 mb-6"></i> + <h3 class="text-xl font-bold text-white mb-3">Low Latency</h3> + <p class="text-sm text-neutral-500 leading-relaxed">WebSockets provide a persistent connection for instant input/output streaming.</p> + </div> + <!-- Feature 3 --> + <div class="compiler-card p-8" data-aos="fade-up" data-aos-delay="300"> + <i class="fas fa-box-open text-2xl text-lime-300 mb-6"></i> + <h3 class="text-xl font-bold text-white mb-3">Auto-Pip Install</h3> + <p class="text-sm text-neutral-500 leading-relaxed">The server detects missing Python libraries and installs them on the fly.</p> + </div> + </div> + </div> + </section> + + <!-- AI Generator Section --> + <section class="py-32 px-6 border-t border-white/5 z-10"> + <div class="max-w-4xl mx-auto text-center" data-aos="fade-up"> + <h2 class="text-3xl font-heading font-bold text-white mb-8">Generate Code Instantly</h2> + + <div class="compiler-card p-1 rounded-2xl bg-gradient-to-br from-white/10 to-transparent p-[1px]"> + <div class="bg-[#0a0a0a] rounded-2xl p-8"> + <textarea id="ai-prompt-input" class="w-full h-32 bg-transparent text-white font-mono text-sm placeholder-neutral-600 focus:outline-none resize-none" placeholder="// Describe the function you need...&#10;e.g. Write a Python script to scrape a website using BeautifulSoup"></textarea> + <div class="flex justify-between items-center mt-6 border-t border-white/10 pt-6"> + <span class="text-xs text-neutral-500 font-mono">POWERED BY GEMINI</span> + <button id="ai-generate-btn" class="btn-primary py-2 px-6 rounded-lg text-sm uppercase tracking-wide"> + Generate <i class="fas fa-sparkles ml-2"></i> + </button> + </div> + </div> + </div> + + <div id="ai-response-container" class="mt-8 hidden text-left"> + <div class="compiler-card p-6 bg-[#0a0a0a]"> + <pre id="ai-response-text" class="text-sm font-mono text-neutral-300 whitespace-pre-wrap"></pre> + </div> + </div> + </div> + </section> + + <!-- Footer --> + <footer class="py-12 border-t border-white/5 z-10 bg-black/40"> + <div class="max-w-6xl mx-auto px-6 text-center"> + + <!-- Documentation Link Added Here --> + <div class="mb-8"> + <a href="./docs.html" class="inline-flex items-center gap-2 text-sm font-mono text-neutral-500 hover:text-lime-300 transition-colors uppercase tracking-widest border border-white/10 px-4 py-2 rounded-full bg-white/5 hover:bg-white/10"> + <i class="fas fa-book"></i> Read Documentation + </a> + </div> + + <h3 class="text-xl font-heading font-bold text-white mb-8">Connect with Me</h3> + + <div class="flex flex-wrap justify-center gap-4 mb-12"> + <a href="https://github.com/notamitgamer" target="_blank" class="social-link w-12 h-12 rounded-full flex items-center justify-center text-lg"> + <i class="fab fa-github"></i> + </a> + <a href="https://linkedin.com/in/notamitgamer" target="_blank" class="social-link w-12 h-12 rounded-full flex items-center justify-center text-lg"> + <i class="fab fa-linkedin-in"></i> + </a> + <a href="https://twitter.com/notamitgamer" target="_blank" class="social-link w-12 h-12 rounded-full flex items-center justify-center text-lg"> + <i class="fab fa-twitter"></i> + </a> + <a href="https://instagram.com/notamitgamer" target="_blank" class="social-link w-12 h-12 rounded-full flex items-center justify-center text-lg"> + <i class="fab fa-instagram"></i> + </a> + </div> + + <div class="text-neutral-600 text-sm font-mono space-y-2"> + <p>&copy; 2025 Amit Dutta. All rights reserved.</p> + <p><a href="https://amit.is-a.dev" class="hover:text-lime-300 transition-colors">amit.is-a.dev</a></p> + </div> + </div> + </footer> + + <script src="https://unpkg.com/aos@2.3.1/dist/aos.js"></script> + <script> + document.addEventListener('DOMContentLoaded', () => { + AOS.init({ + duration: 800, + once: true, + offset: 50 + }); + + // Card Hover Effect (Mouse tracking) + const cards = document.querySelectorAll('.compiler-card'); + document.getElementById('compiler-grid').onmousemove = e => { + for(const card of cards) { + const rect = card.getBoundingClientRect(); + const x = e.clientX - rect.left; + const y = e.clientY - rect.top; + card.style.setProperty('--mouse-x', `${x}px`); + card.style.setProperty('--mouse-y', `${y}px`); + } + }; + + // Typewriter logic + const typeTextElement = document.getElementById('type-text'); + const createTextElement = document.getElementById('create-text'); + const textToType = "Code. Compile."; + let i = 0; + const speed = 75; // ms per char + + function typeWriter() { + if (i < textToType.length) { + typeTextElement.textContent += textToType.charAt(i); + i++; + setTimeout(typeWriter, speed); + } else { + // Typing done, show "Create." with fade-in + createTextElement.classList.remove('hidden'); + + // Trigger subtext fade + document.querySelector('.sub-text-fade').style.animation = 'fadeInDown 2s ease-in-out forwards 0.5s'; + } + } + + // Start typing after a short delay + setTimeout(typeWriter, 500); + + // AI Generator Logic + const generateBtn = document.getElementById('ai-generate-btn'); + const promptInput = document.getElementById('ai-prompt-input'); + const responseContainer = document.getElementById('ai-response-container'); + const responseText = document.getElementById('ai-response-text'); + + generateBtn.addEventListener('click', async () => { + const userPrompt = promptInput.value.trim(); + if (!userPrompt) return; + + generateBtn.innerHTML = '<i class="fas fa-circle-notch fa-spin"></i>'; + generateBtn.disabled = true; + responseContainer.classList.remove('hidden'); + responseText.textContent = '// Thinking...'; + + const systemPrompt = "You are an expert code assistant. Provide concise, clean, and well-commented code based on the user request. Use markdown format."; + const apiKey = "AIzaSyAi1FdeIJ4PzihkCrOGztdVHIyJ7xIoVQ0"; + const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-05-20:generateContent?key=${apiKey}`; + + try { + const response = await fetch(apiUrl, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + contents: [{ parts: [{ text: userPrompt }] }], + systemInstruction: { parts: [{ text: systemPrompt }] } + }) + }); + + const data = await response.json(); + const text = data.candidates?.[0]?.content?.parts?.[0]?.text || "// Error: No response generated."; + responseText.textContent = text; + } catch (error) { + responseText.textContent = `// Error: ${error.message}`; + } finally { + generateBtn.innerHTML = 'Generate <i class="fas fa-sparkles ml-2"></i>'; + generateBtn.disabled = false; + } + }); + }); + </script> +</body> +</html>+ \ No newline at end of file diff --git a/public/logo.png b/public/logo.png Binary files differ. diff --git a/public/python.html b/public/python.html @@ -0,0 +1,498 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> + <title>Amit Dutta // Python Compiler</title> + <link rel="icon" type="image/x-icon" href="https://compiler.aranag.site/logo.png"> + + <!-- Fonts & Icons --> + <link rel="preconnect" href="https://fonts.googleapis.com"> + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> + <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=Inter:wght@300;400;500&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet"> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css"> + + <!-- Tailwind CSS --> + <script src="https://cdn.tailwindcss.com"></script> + + <!-- Xterm.js --> + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.3.0/css/xterm.css" /> + <script src="https://cdn.jsdelivr.net/npm/xterm@5.3.0/lib/xterm.js"></script> + <script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.8.0/lib/xterm-addon-fit.js"></script> + + <style> + :root { + --bg-main: #050505; + --accent: #bef264; /* Lime 300 */ + --text-muted: #737373; + --border-color: rgba(255, 255, 255, 0.1); + } + + body { + font-family: 'Inter', sans-serif; + background-color: var(--bg-main); + color: #f5f5f5; + height: 100vh; + height: 100dvh; + overflow: hidden; + display: flex; + flex-direction: column; + } + + /* Portfolio Aesthetic */ + .font-mono { font-family: 'JetBrains Mono', monospace; } + .font-heading { font-family: 'Space Grotesk', sans-serif; } + + /* Noise Overlay */ + .bg-noise { + position: fixed; top: 0; left: 0; width: 100%; height: 100%; + pointer-events: none; z-index: 0; opacity: 0.03; + background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E"); + } + + /* CRT Scanline */ + .crt-scanline { + position: fixed; top: 0; left: 0; width: 100%; height: 2px; + background: rgba(190, 242, 100, 0.1); opacity: 0.5; + pointer-events: none; z-index: 50; + animation: scanline 8s linear infinite; + } + @keyframes scanline { 0% { top: -10vh; } 100% { top: 110vh; } } + + /* Custom Editor Styles */ + .editor-container { + position: relative; + width: 100%; + height: 100%; + overflow: hidden; + font-family: 'JetBrains Mono', monospace; + font-size: 13px; + line-height: 1.5; + } + + /* The actual textarea for typing */ + #code-input { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + padding: 1rem; + border: none; + outline: none; + background: transparent; + color: #e2e8f0; /* Visible Text */ + caret-color: #fff; /* Cursor visible */ + z-index: 1; + resize: none; + white-space: pre; + overflow: auto; + } + + .xterm-viewport { overflow-y: auto !important; } + + ::selection { background: var(--accent); color: black; } + + .custom-scrollbar::-webkit-scrollbar { width: 6px; height: 6px; } + .custom-scrollbar::-webkit-scrollbar-track { background: #050505; } + .custom-scrollbar::-webkit-scrollbar-thumb { background: #333; border-radius: 3px; } + + /* Toast Notification */ + .toast { + position: fixed; + bottom: 2rem; + left: 50%; + transform: translateX(-50%) translateY(100px); + background: #1a1a1a; + border: 1px solid var(--accent); + color: var(--accent); + padding: 0.5rem 1.5rem; + border-radius: 9999px; + font-family: 'JetBrains Mono', monospace; + font-size: 0.8rem; + transition: transform 0.3s ease; + z-index: 100; + } + .toast.show { transform: translateX(-50%) translateY(0); } + + /* Connection Dot Pulse */ + .pulse-dot { + width: 8px; + height: 8px; + border-radius: 50%; + display: inline-block; + box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.7); + animation: pulse-white 2s infinite; + } + .pulse-dot.connected { + background-color: #bef264; /* Lime */ + box-shadow: 0 0 0 0 rgba(190, 242, 100, 0.7); + animation: pulse-lime 2s infinite; + } + .pulse-dot.disconnected { + background-color: #ef4444; /* Red */ + box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7); + animation: pulse-red 2s infinite; + } + + @keyframes pulse-lime { + 0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(190, 242, 100, 0.7); } + 70% { transform: scale(1); box-shadow: 0 0 0 6px rgba(190, 242, 100, 0); } + 100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(190, 242, 100, 0); } + } + @keyframes pulse-red { + 0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7); } + 70% { transform: scale(1); box-shadow: 0 0 0 6px rgba(239, 68, 68, 0); } + 100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); } + } + </style> +</head> +<body class="antialiased selection:bg-lime-300 selection:text-black"> + + <div class="bg-noise"></div> + <div class="crt-scanline"></div> + <div id="toast" class="toast">Link Copied to Clipboard!</div> + + <!-- Header (Responsive) --> + <header class="h-auto md:h-16 flex flex-col md:flex-row items-center justify-between px-4 py-3 md:px-6 shrink-0 border-b border-white/10 z-20 bg-neutral-900/50 backdrop-blur-md gap-3 md:gap-4"> + + <!-- Top Row: Title & Status --> + <div class="flex items-center justify-between w-full md:w-auto"> + <h1 class="text-lg md:text-xl font-heading font-bold text-white tracking-tight flex items-center"> + <span class="text-lime-300 mr-2">//</span>PY.COMPILER + <span id="conn-dot" class="pulse-dot disconnected ml-3" title="Disconnected"></span> + </h1> + + <!-- Mobile Only: Exit Link --> + <a href="./index.html" class="md:hidden font-mono text-[10px] text-neutral-500 hover:text-white uppercase tracking-wider transition-colors">[ EXIT ]</a> + </div> + + <!-- Middle: Connection Text --> + <div class="hidden md:flex items-center gap-2 font-mono text-xs text-neutral-500"> + <span id="connection-status">Connecting to server...</span> + </div> + + <!-- Bottom/Right: Buttons --> + <div class="flex items-center gap-2 w-full md:w-auto justify-end"> + <a href="./index.html" class="hidden md:inline font-mono text-[10px] text-neutral-500 hover:text-white uppercase tracking-wider transition-colors mr-2">[ EXIT ]</a> + + <button id="reset-btn" class="bg-white/5 hover:bg-neutral-800 text-white border border-white/10 px-3 py-2 rounded font-mono text-[10px] font-bold uppercase tracking-wider flex items-center justify-center transition-all" title="Reset Terminal"> + <i class="fas fa-rotate-left"></i> + </button> + + <button id="share-btn" class="bg-white/5 hover:bg-neutral-800 text-white border border-white/10 px-3 py-2 rounded font-mono text-[10px] font-bold uppercase tracking-wider flex items-center justify-center transition-all" title="Share Code"> + <i class="fas fa-share-alt"></i> + </button> + + <button id="copy-btn" class="bg-white/5 hover:bg-neutral-800 text-white border border-white/10 px-3 py-2 rounded font-mono text-[10px] font-bold uppercase tracking-wider flex items-center justify-center transition-all" title="Copy Output"> + <i class="fas fa-copy"></i> + </button> + + <button id="run-btn" disabled class="bg-white/5 hover:bg-lime-300 hover:text-black disabled:opacity-50 disabled:cursor-not-allowed text-white border border-white/10 px-4 py-2 rounded font-mono text-xs font-bold uppercase tracking-wider flex items-center gap-2 transition-all flex-1 md:flex-none justify-center shadow-lg shadow-black/50"> + <i class="fas fa-play text-[10px]"></i> <span class="md:hidden lg:inline">EXECUTE</span><span class="hidden md:inline lg:hidden">RUN</span> + </button> + </div> + </header> + + <!-- Main Workspace --> + <div class="flex-1 flex flex-col md:flex-row min-h-0 z-10 relative"> + + <!-- Code Editor --> + <div class="flex-1 flex flex-col h-[60%] md:h-auto min-h-0 border-b md:border-b-0 md:border-r border-white/10 relative group"> + <div class="bg-black/20 px-4 py-2 text-[10px] font-mono text-lime-300 uppercase border-b border-white/10 flex justify-between items-center shrink-0"> + <span>SRC // main.py</span> + <span class="text-neutral-600">PYTHON 3</span> + </div> + + <!-- Custom Editor Area --> + <div class="editor-container relative bg-[#0c0f16]"> + <textarea id="code-input" spellcheck="false" autocapitalize="off" autocomplete="off" autocorrect="off" class="custom-scrollbar">import time + +# Simple Clock Preview +print("Current Time:") +print(time.strftime("%H:%M:%S")) +print("Done.")</textarea> + </div> + + <!-- AI Fix Button --> + <button id="ai-fix-btn" class="hidden absolute bottom-4 right-4 bg-red-500/10 border border-red-500/50 text-red-400 hover:bg-red-500 hover:text-white px-3 py-1.5 rounded-lg text-xs font-mono transition-all items-center gap-2 backdrop-blur-md z-20"> + <i class="fas fa-magic"></i> Fix with AI + </button> + </div> + + <!-- Terminal --> + <div class="flex-1 flex flex-col h-[40%] md:h-auto min-h-0 bg-[#050505]"> + <div class="bg-black/20 px-4 py-2 text-[10px] font-mono text-lime-300 uppercase border-b border-white/10 flex justify-between items-center shrink-0"> + <span>OUT // TERMINAL</span> + <span class="text-neutral-600">XTERM.JS</span> + </div> + <div class="flex-1 relative"> + <div id="terminal-container" class="absolute inset-0 w-full h-full p-2 overflow-hidden"></div> + </div> + </div> + </div> + + <script> + // --- DOM Elements --- + const runBtn = document.getElementById('run-btn'); + const resetBtn = document.getElementById('reset-btn'); + const shareBtn = document.getElementById('share-btn'); + const copyBtn = document.getElementById('copy-btn'); + const aiFixBtn = document.getElementById('ai-fix-btn'); + const connDot = document.getElementById('conn-dot'); + const connectionStatus = document.getElementById('connection-status'); + const codeInput = document.getElementById('code-input'); + const toast = document.getElementById('toast'); + + // --- State --- + let socket = null; + let currentLine = ""; + let startTime = 0; + + // --- EDITOR LOGIC (Indentation for Python) --- + codeInput.addEventListener('keydown', function(e) { + if (e.key === 'Tab') { + e.preventDefault(); + const start = this.selectionStart; + const end = this.selectionEnd; + this.setRangeText(' ', start, end, 'end'); + } else if (e.key === 'Enter') { + e.preventDefault(); + const start = this.selectionStart; + const end = this.selectionEnd; + const value = this.value; + const lineStart = value.lastIndexOf('\n', start - 1) + 1; + const currentLineText = value.substring(lineStart, start); + let match = currentLineText.match(/^(\s*)/); + let indent = match ? match[1] : ""; + + // Python specific: indent if line ends with colon + if (currentLineText.trim().endsWith(':')) indent += " "; + + this.setRangeText('\n' + indent, start, end, 'end'); + this.blur(); this.focus(); + } + }); + + window.addEventListener('load', () => { + const params = new URLSearchParams(window.location.search); + const sharedCode = params.get('code'); + if (sharedCode) { + try { codeInput.value = atob(sharedCode); } + catch(e) {} + } + setTimeout(connect, 500); + }); + + // --- Terminal Setup --- + const term = new Terminal({ + theme: { + background: '#050505', + foreground: '#f5f5f5', + cursor: '#bef264', + selectionBackground: 'rgba(190, 242, 100, 0.3)', + black: '#050505', + green: '#bef264', + yellow: '#facc15', + red: '#ef4444', + }, + fontFamily: "'JetBrains Mono', monospace", + fontSize: 12, + cursorBlink: true, + convertEol: true + }); + const fitAddon = new FitAddon.FitAddon(); + term.loadAddon(fitAddon); + term.open(document.getElementById('terminal-container')); + fitAddon.fit(); + window.addEventListener('resize', () => fitAddon.fit()); + + // Custom Key Handler for Ctrl+C Copy + term.attachCustomKeyEventHandler((arg) => { + if (arg.ctrlKey && arg.code === "KeyC" && arg.type === "keydown") { + const selection = term.getSelection(); + if (selection) { + fallbackCopyTextToClipboard(selection); + return false; + } + } + return true; + }); + + term.write('\x1b[38;2;115;115;115m> SYSTEM READY.\r\n> ATTEMPTING CONNECTION...\x1b[0m\r\n'); + + // --- WebSocket Logic --- + function connect() { + const url = "wss://compiler-z4x4.onrender.com"; + try { socket = new WebSocket(url); } catch (e) { + term.write(`\r\n\x1b[31m> INVALID URL.\x1b[0m\r\n`); + return; + } + + socket.onopen = () => { + connDot.className = "pulse-dot connected ml-3"; + if(connectionStatus) connectionStatus.textContent = "Connected to Server"; + if(connectionStatus) connectionStatus.className = "hidden md:flex items-center gap-2 font-mono text-xs text-lime-300"; + + term.write(`\x1b[38;2;190;242;100m> CONNECTION ESTABLISHED.\x1b[0m\r\n> python3 main.py\r\n`); + runBtn.disabled = false; + }; + + socket.onclose = () => { + connDot.className = "pulse-dot disconnected ml-3"; + if(connectionStatus) connectionStatus.textContent = "Disconnected"; + if(connectionStatus) connectionStatus.className = "hidden md:flex items-center gap-2 font-mono text-xs text-red-500"; + + term.write(`\r\n\x1b[31m> CONNECTION LOST. RECONNECTING...\x1b[0m\r\n`); + runBtn.disabled = true; + setTimeout(connect, 3000); + socket = null; + }; + + socket.onmessage = (event) => { + const msg = JSON.parse(event.data); + if (msg.type === 'stdout') { + let text = msg.data; + + if (text.toLowerCase().includes("error") || text.toLowerCase().includes("traceback")) { + aiFixBtn.classList.remove('hidden'); + } + + if (!text.includes('\r')) { + text = text.replace(/\n/g, '\r\n'); + } + term.write(text); + } else if (msg.type === 'status') { + if (msg.msg.includes("Program finished")) { + const duration = (Date.now() - startTime) / 1000; + term.write(`\r\n\x1b[38;2;115;115;115m[Finished in ${duration.toFixed(3)}s]\x1b[0m\r\n`); + } + } + }; + } + + // --- Run Logic --- + runBtn.addEventListener('click', () => { + if (!socket || socket.readyState !== WebSocket.OPEN) return; + + document.activeElement.blur(); + term.reset(); + currentLine = ""; + aiFixBtn.classList.add('hidden'); + + let code = codeInput.value; + // Basic sanitization + code = code.replace(/\u00A0/g, " ").replace(/[\u2018\u2019]/g, "'").replace(/[\u201C\u201D]/g, '"'); + + startTime = Date.now(); + term.write('\x1b[32m> python3 main.py\x1b[0m\r\n'); + + socket.send(JSON.stringify({ + type: 'run', + code: code, + language: 'python' + })); + + term.focus(); + }); + + // --- Reset Logic --- + resetBtn.addEventListener('click', () => { + term.reset(); + currentLine = ""; + term.write(`\x1b[38;2;190;242;100m> CONNECTION ESTABLISHED.\x1b[0m\r\n> python3 main.py\r\n`); + }); + + // --- Share Functionality with Native Share API --- + shareBtn.addEventListener('click', async () => { + const code = codeInput.value; + const encoded = btoa(code); + const url = new URL(window.location.href); + url.searchParams.set('code', encoded); + const shareUrl = url.toString(); + + // Try native sharing first (Mobile/Supported Browsers) + if (navigator.share) { + try { + await navigator.share({ + title: document.title, + text: 'Check out my Python code!', + url: shareUrl + }); + } catch (err) { + // Ignore cancellation or errors + } + } else { + // Fallback to clipboard copy + fallbackCopyTextToClipboard(shareUrl); + } + }); + + function showToast(msg) { + toast.textContent = msg; + toast.classList.add('show'); + setTimeout(() => toast.classList.remove('show'), 3000); + } + + // --- Smart Copy Function --- + copyBtn.addEventListener('click', () => { + const buffer = term.buffer.active; + let text = ""; + for (let i = 0; i < buffer.length; i++) { + const line = buffer.getLine(i); + if (line) { + let lineText = line.translateToString(true); + if(lineText.trim().startsWith("> [") || lineText.trim().startsWith("> python") || lineText.includes("SYSTEM READY") || lineText.includes("ATTEMPTING") || lineText.includes("CONNECTION")) { + continue; + } + text += lineText + "\n"; + } + } + text = text.trim(); + fallbackCopyTextToClipboard(text); + }); + + function fallbackCopyTextToClipboard(text) { + const textArea = document.createElement("textarea"); + textArea.value = text; + textArea.style.position = "fixed"; + textArea.style.top = "0"; + textArea.style.left = "0"; + textArea.style.opacity = "0"; + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + try { + document.execCommand('copy'); + showToast("Copied to Clipboard!"); + } catch (err) { + showToast("Copy Failed"); + } + document.body.removeChild(textArea); + } + + aiFixBtn.addEventListener('click', () => { + showToast("AI Feature: Coming Soon via Backend Update"); + }); + + // Terminal Input + term.onData((data) => { + if (!socket || socket.readyState !== WebSocket.OPEN) return; + + if (data === '\r') { + term.write('\r\n'); + socket.send(JSON.stringify({ type: 'input', data: currentLine + '\n' })); + currentLine = ""; + } else if (data === '\x7f' || data === '\b') { + if (currentLine.length > 0) { + currentLine = currentLine.slice(0, -1); + term.write('\b \b'); + } + } else { + currentLine += data; + term.write(data); + } + }); + </script> +</body> +</html>+ \ No newline at end of file diff --git a/public/sitemap.xml b/public/sitemap.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<urlset + xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 + http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"> + + +<url> + <loc>https://compiler.amit.is-a.dev/</loc> + <lastmod>2026-01-05T13:27:42+00:00</lastmod> +</url> +<url> + <loc>https://compiler.amit.is-a.dev/c/</loc> + <lastmod>2026-01-05T13:27:42+00:00</lastmod> +</url> +<url> + <loc>https://compiler.amit.is-a.dev/cpp/</loc> + <lastmod>2026-01-05T13:27:42+00:00</lastmod> +</url> +<url> + <loc>https://compiler.amit.is-a.dev/python/</loc> + <lastmod>2026-01-05T13:27:42+00:00</lastmod> +</url> + + +</urlset>+ \ No newline at end of file diff --git a/requirements.txt b/requirements.txt @@ -0,0 +1,2 @@ +aiohttp +websockets+ \ No newline at end of file
© notamitgamer • Site Built: 2026-07-21 13:58:23 UTC • git-mirror commit: 1037f62 [view raw info]
Originally created with stagit • modified by notamitgamer
Forked from github.com/notamitgamer/git-mirror