Spaces:
Running
Running
| <html lang="cs"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>ECU Tuning Studio Pro</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;600;700;800;900&family=JetBrains+Mono:wght@300;400;500;600&display=swap" rel="stylesheet"> | |
| <style> | |
| :root { | |
| --bg-primary: #0a0a0f; | |
| --bg-secondary: #12121a; | |
| --bg-card: #1a1a25; | |
| --accent-cyan: #00f0ff; | |
| --accent-orange: #ff6b00; | |
| --accent-red: #ff2d55; | |
| --accent-green: #00ff88; | |
| --text-primary: #ffffff; | |
| --text-muted: #6b7280; | |
| --border-color: #2a2a3a; | |
| } | |
| * { box-sizing: border-box; } | |
| body { | |
| font-family: 'JetBrains Mono', monospace; | |
| background: var(--bg-primary); | |
| color: var(--text-primary); | |
| min-height: 100vh; | |
| overflow-x: hidden; | |
| } | |
| .font-display { font-family: 'Orbitron', sans-serif; } | |
| .bg-grid { | |
| position: fixed; | |
| inset: 0; | |
| background-image: | |
| linear-gradient(rgba(0, 240, 255, 0.03) 1px, transparent 1px), | |
| linear-gradient(90deg, rgba(0, 240, 255, 0.03) 1px, transparent 1px); | |
| background-size: 50px 50px; | |
| pointer-events: none; | |
| z-index: 0; | |
| } | |
| .bg-glow { | |
| position: fixed; | |
| width: 600px; | |
| height: 600px; | |
| border-radius: 50%; | |
| filter: blur(150px); | |
| opacity: 0.15; | |
| pointer-events: none; | |
| z-index: 0; | |
| } | |
| .glow-1 { | |
| top: -200px; | |
| left: -200px; | |
| background: var(--accent-cyan); | |
| animation: floatGlow 15s ease-in-out infinite; | |
| } | |
| .glow-2 { | |
| bottom: -200px; | |
| right: -200px; | |
| background: var(--accent-orange); | |
| animation: floatGlow 18s ease-in-out infinite reverse; | |
| } | |
| @keyframes floatGlow { | |
| 0%, 100% { transform: translate(0, 0); } | |
| 50% { transform: translate(100px, 50px); } | |
| } | |
| .header { | |
| background: linear-gradient(180deg, rgba(26, 26, 37, 0.95) 0%, rgba(10, 10, 15, 0.9) 100%); | |
| backdrop-filter: blur(20px); | |
| border-bottom: 1px solid var(--border-color); | |
| position: sticky; | |
| top: 0; | |
| z-index: 100; | |
| } | |
| .card { | |
| background: linear-gradient(145deg, rgba(26, 26, 37, 0.9) 0%, rgba(18, 18, 26, 0.95) 100%); | |
| border: 1px solid var(--border-color); | |
| border-radius: 16px; | |
| backdrop-filter: blur(10px); | |
| transition: all 0.3s ease; | |
| } | |
| .card:hover { | |
| border-color: rgba(0, 240, 255, 0.3); | |
| box-shadow: 0 0 30px rgba(0, 240, 255, 0.1); | |
| } | |
| .upload-zone { | |
| border: 2px dashed var(--border-color); | |
| border-radius: 16px; | |
| transition: all 0.3s ease; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .upload-zone::before { | |
| content: ''; | |
| position: absolute; | |
| inset: 0; | |
| background: linear-gradient(45deg, transparent 40%, rgba(0, 240, 255, 0.05) 50%, transparent 60%); | |
| background-size: 300% 300%; | |
| animation: shimmer 3s ease-in-out infinite; | |
| opacity: 0; | |
| transition: opacity 0.3s ease; | |
| } | |
| .upload-zone:hover::before, | |
| .upload-zone.dragover::before { opacity: 1; } | |
| .upload-zone:hover, | |
| .upload-zone.dragover { | |
| border-color: var(--accent-cyan); | |
| box-shadow: 0 0 40px rgba(0, 240, 255, 0.15); | |
| } | |
| @keyframes shimmer { | |
| 0% { background-position: 100% 100%; } | |
| 100% { background-position: 0% 0%; } | |
| } | |
| .btn-primary { | |
| background: linear-gradient(135deg, var(--accent-cyan) 0%, #00a8b3 100%); | |
| color: var(--bg-primary); | |
| font-weight: 600; | |
| padding: 12px 24px; | |
| border-radius: 10px; | |
| border: none; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .btn-primary::before { | |
| content: ''; | |
| position: absolute; | |
| inset: 0; | |
| background: linear-gradient(135deg, transparent 0%, rgba(255, 255, 255, 0.2) 50%, transparent 100%); | |
| transform: translateX(-100%); | |
| transition: transform 0.5s ease; | |
| } | |
| .btn-primary:hover::before { transform: translateX(100%); } | |
| .btn-primary:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 10px 30px rgba(0, 240, 255, 0.3); | |
| } | |
| .btn-secondary { | |
| background: transparent; | |
| color: var(--text-primary); | |
| font-weight: 500; | |
| padding: 12px 24px; | |
| border-radius: 10px; | |
| border: 1px solid var(--border-color); | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| } | |
| .btn-secondary:hover { | |
| border-color: var(--accent-cyan); | |
| background: rgba(0, 240, 255, 0.1); | |
| } | |
| .toggle-switch { | |
| position: relative; | |
| width: 60px; | |
| height: 30px; | |
| background: var(--bg-secondary); | |
| border-radius: 15px; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| border: 1px solid var(--border-color); | |
| } | |
| .toggle-switch::after { | |
| content: ''; | |
| position: absolute; | |
| width: 24px; | |
| height: 24px; | |
| background: var(--text-muted); | |
| border-radius: 50%; | |
| top: 2px; | |
| left: 2px; | |
| transition: all 0.3s ease; | |
| } | |
| .toggle-switch.active { | |
| background: linear-gradient(135deg, var(--accent-cyan) 0%, #00a8b3 100%); | |
| border-color: var(--accent-cyan); | |
| } | |
| .toggle-switch.active::after { | |
| left: 32px; | |
| background: var(--bg-primary); | |
| } | |
| .hex-viewer { | |
| font-family: 'JetBrains Mono', monospace; | |
| font-size: 12px; | |
| line-height: 1.6; | |
| background: var(--bg-primary); | |
| border-radius: 8px; | |
| overflow: auto; | |
| max-height: 400px; | |
| } | |
| .hex-line { | |
| display: flex; | |
| padding: 2px 8px; | |
| transition: background 0.2s ease; | |
| } | |
| .hex-line:hover { background: rgba(0, 240, 255, 0.1); } | |
| .hex-offset { | |
| color: var(--accent-cyan); | |
| min-width: 80px; | |
| opacity: 0.7; | |
| } | |
| .hex-bytes { | |
| color: var(--text-primary); | |
| min-width: 380px; | |
| } | |
| .hex-ascii { | |
| color: var(--accent-green); | |
| opacity: 0.8; | |
| } | |
| .info-row { | |
| display: flex; | |
| justify-content: space-between; | |
| padding: 10px 0; | |
| border-bottom: 1px solid var(--border-color); | |
| } | |
| .info-row:last-child { border-bottom: none; } | |
| .info-label { color: var(--text-muted); } | |
| .info-value { | |
| color: var(--text-primary); | |
| font-weight: 500; | |
| } | |
| .info-value.highlight { color: var(--accent-cyan); } | |
| .mod-card { | |
| background: linear-gradient(145deg, rgba(26, 26, 37, 0.8) 0%, rgba(18, 18, 26, 0.9) 100%); | |
| border: 1px solid var(--border-color); | |
| border-radius: 12px; | |
| padding: 20px; | |
| transition: all 0.3s ease; | |
| } | |
| .mod-card:hover { | |
| transform: translateY(-4px); | |
| box-shadow: 0 15px 40px rgba(0, 0, 0, 0.3); | |
| } | |
| .mod-card.active { | |
| border-color: var(--accent-cyan); | |
| box-shadow: 0 0 30px rgba(0, 240, 255, 0.15); | |
| } | |
| .progress-bar { | |
| height: 4px; | |
| background: var(--bg-secondary); | |
| border-radius: 2px; | |
| overflow: hidden; | |
| } | |
| .progress-fill { | |
| height: 100%; | |
| background: linear-gradient(90deg, var(--accent-cyan) 0%, var(--accent-green) 100%); | |
| border-radius: 2px; | |
| transition: width 0.5s ease; | |
| } | |
| .status-dot { | |
| width: 8px; | |
| height: 8px; | |
| border-radius: 50%; | |
| background: var(--accent-green); | |
| animation: pulse 2s ease-in-out infinite; | |
| } | |
| @keyframes pulse { | |
| 0%, 100% { opacity: 1; box-shadow: 0 0 10px var(--accent-green); } | |
| 50% { opacity: 0.5; box-shadow: 0 0 5px var(--accent-green); } | |
| } | |
| ::-webkit-scrollbar { width: 8px; height: 8px; } | |
| ::-webkit-scrollbar-track { background: var(--bg-secondary); } | |
| ::-webkit-scrollbar-thumb { background: var(--border-color); border-radius: 4px; } | |
| ::-webkit-scrollbar-thumb:hover { background: var(--accent-cyan); } | |
| .fade-in { animation: fadeIn 0.5s ease forwards; } | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(20px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| .slide-in { animation: slideIn 0.6s ease forwards; } | |
| @keyframes slideIn { | |
| from { opacity: 0; transform: translateX(-30px); } | |
| to { opacity: 1; transform: translateX(0); } | |
| } | |
| @media (prefers-reduced-motion: reduce) { | |
| *, *::before, *::after { | |
| animation-duration: 0.01ms ; | |
| transition-duration: 0.01ms ; | |
| } | |
| } | |
| @media (max-width: 768px) { | |
| .hex-viewer { font-size: 10px; } | |
| .hex-bytes { min-width: 280px; } | |
| } | |
| .flame-icon { animation: flicker 0.5s ease-in-out infinite alternate; } | |
| @keyframes flicker { | |
| 0% { opacity: 0.8; transform: scale(1); } | |
| 100% { opacity: 1; transform: scale(1.1); } | |
| } | |
| .badge-warning { | |
| background: linear-gradient(135deg, var(--accent-orange) 0%, #cc5500 100%); | |
| color: white; | |
| font-size: 10px; | |
| padding: 2px 8px; | |
| border-radius: 4px; | |
| text-transform: uppercase; | |
| font-weight: 600; | |
| } | |
| .badge-success { | |
| background: linear-gradient(135deg, var(--accent-green) 0%, #00cc6a 100%); | |
| color: var(--bg-primary); | |
| font-size: 10px; | |
| padding: 2px 8px; | |
| border-radius: 4px; | |
| text-transform: uppercase; | |
| font-weight: 600; | |
| } | |
| .slider { | |
| -webkit-appearance: none; | |
| width: 100%; | |
| height: 6px; | |
| background: var(--bg-secondary); | |
| border-radius: 3px; | |
| outline: none; | |
| } | |
| .slider::-webkit-slider-thumb { | |
| -webkit-appearance: none; | |
| width: 18px; | |
| height: 18px; | |
| background: var(--accent-cyan); | |
| border-radius: 50%; | |
| cursor: pointer; | |
| transition: all 0.2s ease; | |
| } | |
| .slider::-webkit-slider-thumb:hover { | |
| transform: scale(1.2); | |
| box-shadow: 0 0 15px var(--accent-cyan); | |
| } | |
| .map-item { | |
| padding: 8px 12px; | |
| background: rgba(0, 240, 255, 0.05); | |
| border-radius: 6px; | |
| cursor: pointer; | |
| transition: all 0.2s ease; | |
| border: 1px solid transparent; | |
| } | |
| .map-item:hover { | |
| background: rgba(0, 240, 255, 0.1); | |
| border-color: rgba(0, 240, 255, 0.3); | |
| } | |
| .dtc-item { | |
| padding: 10px; | |
| background: rgba(255, 45, 85, 0.1); | |
| border-radius: 6px; | |
| border-left: 3px solid var(--accent-red); | |
| } | |
| .dtc-item.pending { | |
| background: rgba(255, 107, 0, 0.1); | |
| border-left-color: var(--accent-orange); | |
| } | |
| .file-loaded .upload-zone { | |
| border-color: var(--accent-green); | |
| background: rgba(0, 255, 136, 0.05); | |
| } | |
| .toast { | |
| position: fixed; | |
| bottom: 20px; | |
| right: 20px; | |
| background: var(--bg-card); | |
| border: 1px solid var(--border-color); | |
| border-radius: 12px; | |
| padding: 16px 24px; | |
| z-index: 1000; | |
| animation: slideInToast 0.3s ease; | |
| } | |
| @keyframes slideInToast { | |
| from { transform: translateX(100%); opacity: 0; } | |
| to { transform: translateX(0); opacity: 1; } | |
| } | |
| .toast.success { border-color: var(--accent-green); } | |
| .toast.error { border-color: var(--accent-red); } | |
| .toast.warning { border-color: var(--accent-orange); } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="bg-grid"></div> | |
| <div class="bg-glow glow-1"></div> | |
| <div class="bg-glow glow-2"></div> | |
| <header class="header relative z-10"> | |
| <div class="max-w-7xl mx-auto px-4 py-4"> | |
| <div class="flex items-center justify-between flex-wrap gap-4"> | |
| <div class="flex items-center gap-4"> | |
| <div class="flex items-center gap-3"> | |
| <svg class="w-10 h-10 text-cyan-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
| <path d="M12 2L2 7l10 5 10-5-10-5z"/> | |
| <path d="M2 17l10 5 10-5"/> | |
| <path d="M2 12l10 5 10-5"/> | |
| </svg> | |
| <div> | |
| <h1 class="font-display text-xl font-bold tracking-wider">ECU TUNING STUDIO</h1> | |
| <p class="text-xs text-gray-500">Professional Binary Analysis</p> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="flex items-center gap-4"> | |
| <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="text-xs text-gray-400 hover:text-cyan-400 transition-colors"> | |
| Built with anycoder | |
| </a> | |
| <div class="flex items-center gap-2"> | |
| <div class="status-dot" id="statusDot"></div> | |
| <span class="text-xs text-gray-400" id="statusText">Ready</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </header> | |
| <main class="relative z-10 max-w-7xl mx-auto px-4 py-8"> | |
| <!-- Upload section --> | |
| <section id="uploadSection" class="mb-8 fade-in"> | |
| <div class="upload-zone p-8 text-center cursor-pointer" id="dropZone"> | |
| <input type="file" id="fileInput" accept=".bin,.BIN,.hex,.HEX" class="hidden"> | |
| <div class="relative z-10"> | |
| <svg class="w-16 h-16 mx-auto mb-4 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"/> | |
| </svg> | |
| <h3 class="font-display text-lg font-semibold mb-2">Nahrajte ECU soubor</h3> | |
| <p class="text-gray-500 text-sm mb-4">Pretáhněte .bin soubor nebo klikněte pro výběr</p> | |
| <p class="text-xs text-gray-600">Podporované formáty: .bin, .BIN, .hex | Max velikost: 2MB</p> | |
| </div> | |
| </div> | |
| <div id="fileInfo" class="hidden mt-4 card p-4"> | |
| <div class="flex items-center justify-between"> | |
| <div class="flex items-center gap-3"> | |
| <svg class="w-8 h-8 text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/> | |
| </svg> | |
| <div> | |
| <p class="font-semibold" id="loadedFileName">-</p> | |
| <p class="text-xs text-gray-500" id="loadedFileSize">-</p> | |
| </div> | |
| </div> | |
| <button class="btn-secondary text-xs py-2 px-4" onclick="resetFile()">Odstranit</button> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- File info & analysis --> | |
| <section id="analysisSection" class="hidden mb-8"> | |
| <div class="grid grid-cols-1 lg:grid-cols-3 gap-6"> | |
| <div class="card p-6 slide-in"> | |
| <div class="flex items-center justify-between mb-4"> | |
| <h2 class="font-display text-sm font-semibold tracking-wider text-gray-400">RIDICI JEDNOTKA</h2> | |
| <span class="badge-success">DETEKOVANO</span> | |
| </div> | |
| <div id="ecuInfo"> | |
| <div class="info-row"> | |
| <span class="info-label">ECU Typ</span> | |
| <span class="info-value highlight" id="ecuType">-</span> | |
| </div> | |
| <div class="info-row"> | |
| <span class="info-label">Vyrobce</span> | |
| <span class="info-value" id="ecuManufacturer">-</span> | |
| </div> | |
| <div class="info-row"> | |
| <span class="info-label">Verze SW</span> | |
| <span class="info-value" id="swVersion">-</span> | |
| </div> | |
| <div class="info-row"> | |
| <span class="info-label">Verze HW</span> | |
| <span class="info-value" id="hwVersion">-</span> | |
| </div> | |
| <div class="info-row"> | |
| <span class="info-label">Velikost</span> | |
| <span class="info-value" id="fileSizeDisplay">-</span> | |
| </div> | |
| <div class="info-row"> | |
| <span class="info-label">Checksum</span> | |
| <span class="info-value font-mono text-xs" id="checksum">-</span> | |
| </div> | |
| <div class="info-row"> | |
| <span class="info-label">Vozidlo</span> | |
| <span class="info-value" id="vehicle">-</span> | |
| </div> | |
| <div class="info-row"> | |
| <span class="info-label">Motor</span> | |
| <span class="info-value" id="engine">-</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="card p-6 slide-in" style="animation-delay: 0.1s"> | |
| <div class="flex items-center justify-between mb-4"> | |
| <h2 class="font-display text-sm font-semibold tracking-wider text-gray-400">DETEKCE MAP</h2> | |
| <span class="text-xs text-gray-500" id="mapCount">0 nalezeno</span> | |
| </div> | |
| <div id="mapList" class="space-y-2 max-h-64 overflow-y-auto"></div> | |
| </div> | |
| <div class="card p-6 slide-in" style="animation-delay: 0.2s"> | |
| <div class="flex items-center justify-between mb-4"> | |
| <h2 class="font-display text-sm font-semibold tracking-wider text-gray-400">DTC KODY</h2> | |
| <span class="badge-warning" id="dtcCount">0 aktivnich</span> | |
| </div> | |
| <div id="dtcList" class="space-y-2"></div> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- Hex Viewer & Modifications --> | |
| <section id="mainSection" class="hidden"> | |
| <div class="grid grid-cols-1 xl:grid-cols-2 gap-6 mb-8"> | |
| <div class="card p-6"> | |
| <div class="flex items-center justify-between mb-4 flex-wrap gap-2"> | |
| <h2 class="font-display text-sm font-semibold tracking-wider text-gray-400">HEX VIEWER</h2> | |
| <div class="flex gap-2"> | |
| <button class="btn-secondary text-xs py-2 px-3" onclick="jumpToOffset()">Skocit na offset</button> | |
| <button class="btn-secondary text-xs py-2 px-3" onclick="searchHex()">Hledat</button> | |
| </div> | |
| </div> | |
| <div class="hex-viewer p-4" id="hexViewer"></div> | |
| <div class="mt-4 flex items-center justify-between text-xs text-gray-500"> | |
| <span id="hexOffset">Offset: 0x00000000</span> | |
| <span id="hexSelection">Vyber: zadny</span> | |
| </div> | |
| </div> | |
| <div class="card p-6"> | |
| <div class="flex items-center justify-between mb-4"> | |
| <h2 class="font-display text-sm font-semibold tracking-wider text-gray-400">MODIFIKACE</h2> | |
| <span class="text-xs text-gray-500" id="activeModCount">0 aktivnich</span> | |
| </div> | |
| <div class="space-y-4" id="modificationsList"> | |
| <!-- Pop & Bangs --> | |
| <div class="mod-card" id="mod-popbang"> | |
| <div class="flex items-center justify-between mb-3"> | |
| <div class="flex items-center gap-3"> | |
| <svg class="w-6 h-6 text-orange-500 flame-icon" fill="currentColor" viewBox="0 0 24 24"> | |
| <path d="M12 23c-3.9 0-7-3.1-7-7 0-2.8 1.6-5.2 4-6.4V8c0-2.2 1.8-4 4-4s4 1.8 4 4v1.6c2.4 1.2 4 3.6 4 6.4 0 3.9-3.1 7-7 7zm0-18c-1.1 0-2 .9-2 2v2.3l-.7.4C7.8 10.7 7 12.3 7 14c0 2.8 2.2 5 5 5s5-2.2 5-5c0-1.7-.8-3.3-2.3-4.3l-.7-.4V7c0-1.1-.9-2-2-2z"/> | |
| </svg> | |
| <div> | |
| <h3 class="font-semibold">POP AND BANGS</h3> | |
| <p class="text-xs text-gray-500">Agresivni vyfukove efekty</p> | |
| </div> | |
| </div> | |
| <div class="toggle-switch" data-mod="popbang" onclick="toggleMod('popbang', this)"></div> | |
| </div> | |
| <div class="mod-settings hidden mt-4 pt-4 border-t border-gray-700" id="settings-popbang"> | |
| <div class="space-y-4"> | |
| <div> | |
| <label class="text-xs text-gray-400 mb-2 block">Intenzita</label> | |
| <input type="range" class="slider" min="1" max="10" value="5" id="popbang-intensity" oninput="updateSliderValue(this, 'popbang-intensity-val')"> | |
| <div class="flex justify-between text-xs text-gray-500 mt-1"> | |
| <span>Mirna</span> | |
| <span id="popbang-intensity-val">5</span> | |
| <span>Extremni</span> | |
| </div> | |
| </div> | |
| <div> | |
| <label class="text-xs text-gray-400 mb-2 block">RPM rozsah</label> | |
| <div class="flex gap-2"> | |
| <input type="number" class="bg-gray-800 border border-gray-700 rounded px-3 py-2 text-sm w-24" value="2500" placeholder="Min"> | |
| <span class="text-gray-500 self-center">-</span> | |
| <input type="number" class="bg-gray-800 border border-gray-700 rounded px-3 py-2 text-sm w-24" value="6500" placeholder="Max"> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Hardcut --> | |
| <div class="mod-card" id="mod-hardcut"> | |
| <div class="flex items-center justify-between mb-3"> | |
| <div class="flex items-center gap-3"> | |
| <svg class="w-6 h-6 text-red-500 flame-icon" fill="currentColor" viewBox="0 0 24 24"> | |
| <path d="M13.5.67s.74 2.65.74 4.8c0 2.06-1.35 3.73-3.41 3.73-2.07 0-3.63-1.67-3.63-3.73l.03-.36C5.21 7.51 4 10.62 4 14c0 4.42 3.58 8 8 8s8-3.58 8-8C20 8.61 17.41 3.8 13.5.67zM11.71 19c-1.78 0-3.22-1.4-3.22-3.14 0-1.62 1.05-2.76 2.81-3.12 1.77-.36 3.6-1.21 4.62-2.58.39 1.29.59 2.65.59 4.04 0 2.65-2.15 4.8-4.8 4.8z"/> | |
| </svg> | |
| <div> | |
| <h3 class="font-semibold">HARDCUT WITH FLAMES</h3> | |
| <p class="text-xs text-gray-500">Tvrde strihani s plameny</p> | |
| </div> | |
| </div> | |
| <div class="toggle-switch" data-mod="hardcut" onclick="toggleMod('hardcut', this)"></div> | |
| </div> | |
| <div class="mod-settings hidden mt-4 pt-4 border-t border-gray-700" id="settings-hardcut"> | |
| <div class="space-y-4"> | |
| <div> | |
| <label class="text-xs text-gray-400 mb-2 block">Hardcut RPM</label> | |
| <input type="range" class="slider" min="6000" max="8000" value="7200" id="hardcut-rpm" oninput="updateSliderValue(this, 'hardcut-rpm-val')"> | |
| <div class="flex justify-between text-xs text-gray-500 mt-1"> | |
| <span>6000</span> | |
| <span id="hardcut-rpm-val">7200</span> | |
| <span>8000</span> | |
| </div> | |
| </div> | |
| <div> | |
| <label class="text-xs text-gray-400 mb-2 block">Delka plamene (ms)</label> | |
| <input type="range" class="slider" min="50" max="300" value="150" id="flame-duration" oninput="updateSliderValue(this, 'flame-duration-val')"> | |
| <div class="flex justify-between text-xs text-gray-500 mt-1"> | |
| <span>50</span> | |
| <span id="flame-duration-val">150</span> | |
| <span>300</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Stage 1 --> | |
| <div class="mod-card" id="mod-stage1"> | |
| <div class="flex items-center justify-between mb-3"> | |
| <div class="flex items-center gap-3"> | |
| <svg class="w-6 h-6 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"/> | |
| </svg> | |
| <div> | |
| <h3 class="font-semibold">STAGE 1 TUNE</h3> | |
| <p class="text-xs text-gray-500">Zakladni optimalizace vykonu</p> | |
| </div> | |
| </div> | |
| <div class="toggle-switch" data-mod="stage1" onclick="toggleMod('stage1', this)"></div> | |
| </div> | |
| <div class="mod-settings hidden mt-4 pt-4 border-t border-gray-700" id="settings-stage1"> | |
| <div class="grid grid-cols-2 gap-4 text-sm"> | |
| <div class="bg-gray-800/50 rounded-lg p-3"> | |
| <span class="text-gray-500 text-xs">Puvodni vykon</span> | |
| <p class="font-display text-lg" id="originalHP">150 HP</p> | |
| </div> | |
| <div class="bg-gray-800/50 rounded-lg p-3"> | |
| <span class="text-gray-500 text-xs">Po uprave</span> | |
| <p class="font-display text-lg text-green-400" id="tunedHP">195 HP</p> | |
| </div> | |
| <div class="bg-gray-800/50 rounded-lg p-3"> | |
| <span class="text-gray-500 text-xs">Puvodni moment</span> | |
| <p class="font-display text-lg" id="originalNM">210 Nm</p> | |
| </div> | |
| <div class="bg-gray-800/50 rounded-lg p-3"> | |
| <span class="text-gray-500 text-xs">Po uprave</span> | |
| <p class="font-display text-lg text-green-400" id="tunedNM">280 Nm</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- DPF/EGR --> | |
| <div class="mod-card" id="mod-dpf"> | |
| <div class="flex items-center justify-between"> | |
| <div class="flex items-center gap-3"> | |
| <svg class="w-6 h-6 text-yellow-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636"/> | |
| </svg> | |
| <div> | |
| <h3 class="font-semibold">DPF/EGR OFF</h3> | |
| <p class="text-xs text-gray-500">Odstraneni emisnich systemu</p> | |
| </div> | |
| </div> | |
| <div class="toggle-switch" data-mod="dpf" onclick="toggleMod('dpf', this)"></div> | |
| </div> | |
| <div class="mt-2"> | |
| <span class="badge-warning">Pouze pro zavodni pouziti</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Action buttons --> | |
| <div class="flex flex-wrap gap-4 justify-center mb-8"> | |
| <button class="btn-primary flex items-center gap-2" onclick="applyMods()"> | |
| <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/> | |
| </svg> | |
| Aplikovat zmeny | |
| </button> | |
| <button class="btn-secondary flex items-center gap-2" onclick="compareFiles()"> | |
| <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"/> | |
| </svg> | |
| Porovnat s originalom | |
| </button> | |
| <button class="btn-secondary flex items-center gap-2" onclick="exportFile()"> | |
| <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/> | |
| </svg> | |
| Exportovat .bin | |
| </button> | |
| </div> | |
| <!-- Progress section --> | |
| <div id="progressSection" class="hidden card p-6 mb-8"> | |
| <div class="flex items-center justify-between mb-4"> | |
| <h2 class="font-display text-sm font-semibold tracking-wider text-gray-400">PRUBEH APLIKACE</h2> | |
| <span class="text-xs text-cyan-400" id="progressPercent">0%</span> | |
| </div> | |
| <div class="progress-bar mb-4"> | |
| <div class="progress-fill" id="progressFill" style="width: 0%"></div> | |
| </div> | |
| <div id="progressLog" class="text-xs text-gray-500 space-y-1 max-h-32 overflow-y-auto"></div> | |
| </div> | |
| </section> | |
| </main> | |
| <!-- Search Modal --> | |
| <div id="searchModal" class="fixed inset-0 bg-black/80 backdrop-blur-sm z-50 hidden flex items-center justify-center p-4"> | |
| <div class="card p-6 max-w-md w-full"> | |
| <div class="flex items-center justify-between mb-4"> | |
| <h2 class="font-display text-lg font-semibold">Hledat v HEX</h2> | |
| <button onclick="closeSearchModal()" class="text-gray-500 hover:text-white"> | |
| <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/> | |
| </svg> | |
| </button> | |
| </div> | |
| <input type="text" id="searchInput" class="w-full bg-gray-800 border border-gray-700 rounded-lg px-4 py-3 mb-4" placeholder="Zadejte HEX hodnotu (napr. FF00A1)"> | |
| <button class="btn-primary w-full" onclick="performSearch()">Hledat</button> | |
| </div> | |
| </div> | |
| <!-- Offset Modal --> | |
| <div id="offsetModal" class="fixed inset-0 bg-black/80 backdrop-blur-sm z-50 hidden flex items-center justify-center p-4"> | |
| <div class="card p-6 max-w-md w-full"> | |
| <div class="flex items-center justify-between mb-4"> | |
| <h2 class="font-display text-lg font-semibold">Skocit na offset</h2> | |
| <button onclick="closeOffsetModal()" class="text-gray-500 hover:text-white"> | |
| <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/> | |
| </svg> | |
| </button> | |
| </div> | |
| <input type="text" id="offsetInput" class="w-full bg-gray-800 border border-gray-700 rounded-lg px-4 py-3 mb-4" placeholder="Zadejte offset (napr. 0x1000 nebo 4096)"> | |
| <button class="btn-primary w-full" onclick="performJump()">Skocit</button> | |
| </div> | |
| </div> | |
| <script> | |
| // State | |
| let fileData = null; | |
| let originalFileData = null; | |
| let fileName = ''; | |
| let activeMods = new Set(); | |
| let currentECU = null; | |
| // ECU Database | |
| const ecuDatabase = { | |
| 'Bosch ME7.5': { | |
| manufacturer: 'Bosch', | |
| vehicle: 'VW Golf IV 1.8T', | |
| engine: 'AGU 150HP', | |
| originalHP: 150, | |
| originalNM: 210, | |
| maps: [ | |
| { name: 'Ignition Advance', offset: '0x00012A00', size: '24x20', type: '2D' }, | |
| { name: 'Fuel Injection', offset: '0x00015C00', size: '16x16', type: '2D' }, | |
| { name: 'Boost Pressure', offset: '0x00018400', size: '12x12', type: '2D' }, | |
| { name: 'Torque Limit', offset: '0x0001A200', size: '8x8', type: '2D' }, | |
| { name: 'Rev Limiter', offset: '0x0001B800', size: '1D', type: '1D' }, | |
| { name: 'Speed Limiter', offset: '0x0001B900', size: '1D', type: '1D' }, | |
| { name: 'Lambda Target', offset: '0x0001C000', size: '16x16', type: '2D' }, | |
| { name: 'Throttle Response', offset: '0x0001E400', size: '10x10', type: '2D' } | |
| ], | |
| dtcs: [ | |
| { code: 'P0171', desc: 'System Too Lean (Bank 1)', status: 'active' }, | |
| { code: 'P0300', desc: 'Random Misfire Detected', status: 'pending' }, | |
| { code: 'P0420', desc: 'Catalyst Efficiency Below Threshold', status: 'active' } | |
| ] | |
| }, | |
| 'Bosch ME9.1': { | |
| manufacturer: 'Bosch', | |
| vehicle: 'Audi A4 2.0TFSI', | |
| engine: 'BWA 200HP', | |
| originalHP: 200, | |
| originalNM: 280, | |
| maps: [ | |
| { name: 'Ignition Advance', offset: '0x00014000', size: '32x24', type: '2D' }, | |
| { name: 'Fuel Injection', offset: '0x00018000', size: '20x20', type: '2D' }, | |
| { name: 'Boost Pressure', offset: '0x0001C000', size: '16x16', type: '2D' }, | |
| { name: 'Torque Limit', offset: '0x0001E000', size: '10x10', type: '2D' }, | |
| { name: 'Rev Limiter', offset: '0x0001F000', size: '1D', type: '1D' } | |
| ], | |
| dtcs: [ | |
| { |