From 8efe41bb0cccdac3ac73ded4386e9d7b486a94b4 Mon Sep 17 00:00:00 2001 From: Li Bo Date: Thu, 26 Feb 2026 16:27:58 +0800 Subject: [PATCH 1/5] fix: correct GitHub and website URLs (use dashes instead of underscores) --- README.md | 3 +- docs/index.html | 362 ++++++++++++++++++++++++------ website/index.html | 543 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 835 insertions(+), 73 deletions(-) create mode 100644 website/index.html diff --git a/README.md b/README.md index 0ab5668..c253151 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,9 @@ [![PyPI](https://img.shields.io/pypi/v/esp-batch-flash.svg)](https://pypi.org/project/esp-batch-flash/) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) +[![Website](https://img.shields.io/badge/Website-Live-brightgreen)](https://leeebo.github.io/esp-batch-flash/) -[English](#english) | [中文摘要](#chinese-summary) +[Official Website](https://leeebo.github.io/esp-batch-flash/) | [English](#english) | [中文摘要](#chinese-summary) ## Overview diff --git a/docs/index.html b/docs/index.html index 97ff2c5..bca651d 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,15 +1,19 @@ + ESP Batch Flash | Parallel Flashing, Zero Waiting - - + + - + +
@@ -174,15 +382,16 @@
v1.2.0 Stable Release

Parallel Flashing, Zero Waiting.

- Flash dozens of ESP devices simultaneously. The professional CLI tool for rapid prototyping and mass production. + Flash dozens of ESP devices simultaneously. The professional CLI tool for rapid prototyping and mass + production.

- +
pip install esp-batch-flash
- View on GitHub + View on GitHub
@@ -195,19 +404,22 @@

Parallel Flashing, Zero Waiting.

- $ | + $ |
- + @@ -255,7 +472,7 @@

Visual Progress

const output = document.getElementById('output-content'); const progressArea = document.getElementById('progress-area'); const finalStats = document.getElementById('final-stats'); - + let charIdx = 0; function type() { if (charIdx < cmdTxt.length) { @@ -269,9 +486,9 @@

Visual Progress

function runDemo() { output.classList.remove('hidden'); - + // Generate 8 bars - for(let i=0; i<8; i++) { + for (let i = 0; i < 8; i++) { const row = document.createElement('div'); row.className = 'progress-row'; const duration = 3 + Math.random() * 3; @@ -281,7 +498,7 @@

Visual Progress

0% `; progressArea.appendChild(row); - + // Animate setTimeout(() => { const fill = document.getElementById(`fill-${i}`); @@ -289,7 +506,7 @@

Visual Progress

animateValue(`perc-${i}`, 0, 100, duration * 1000); }, 100 + (i * 120)); } - + setTimeout(() => { finalStats.classList.remove('hidden'); }, 7000); @@ -312,7 +529,7 @@

Visual Progress

} // Copy button logic - document.getElementById('copy-trigger').addEventListener('click', function() { + document.getElementById('copy-trigger').addEventListener('click', function () { navigator.clipboard.writeText("pip install esp-batch-flash"); this.textContent = "Copied!"; setTimeout(() => { this.textContent = "Copy"; }, 2000); @@ -322,4 +539,5 @@

Visual Progress

setTimeout(type, 1200); - + + \ No newline at end of file diff --git a/website/index.html b/website/index.html new file mode 100644 index 0000000..f52a12b --- /dev/null +++ b/website/index.html @@ -0,0 +1,543 @@ + + + + + + + ESP Batch Flash | Parallel Flashing, Zero Waiting + + + + + + + + + + + + +
+
+
v1.2.0 Stable Release
+

Parallel Flashing, Zero Waiting.

+

+ Flash dozens of ESP devices simultaneously. The professional CLI tool for rapid prototyping and mass + production. +

+ +
+
+ pip install esp-batch-flash + +
+ View on GitHub +
+ + +
+
+
+
+
+ esp_batch_flash — 80x24 +
+
+
+ $ | +
+ + +
+
+ +
+
+ +
+
+

Why ESP Batch Flash?

+
+
+

Massive Productivity

+

Stop waiting for serial connections. Flash 10+ devices in the time it takes to do one. Perfect + for batch updates and factory setups.

+
20x Efficiency
+
+
+

Auto-Scan

+

Built-in intelligence to detect all ESP32, ESP32-S2, S3, and C series chips wirelessly or via USB + instantly.

+
+
+

Cross-Platform

+

Native speed on Windows, macOS, and Linux. Built with modern Python and esptool under the hood. +

+
+
+

Visual Progress

+

Beautiful real-time UI bars for every port. Instantly identify which device failed or is lagging + without digging through logs.

+
+
+
+
+ +
+
+

© 2026 ESP Batch Flash Project. Open source under Apache 2.0.

+
+
+ + + + + \ No newline at end of file From 2601f58f8b4b0b12c57d82263c092e04e95fc0c8 Mon Sep 17 00:00:00 2001 From: Li Bo Date: Thu, 26 Feb 2026 16:37:25 +0800 Subject: [PATCH 2/5] feat: add dynamic PyPI version fetching to landing page --- docs/index.html | 376 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 306 insertions(+), 70 deletions(-) diff --git a/docs/index.html b/docs/index.html index bca651d..f39d1dd 100644 --- a/docs/index.html +++ b/docs/index.html @@ -118,16 +118,39 @@ margin: 0 auto 3rem; } - /* CTA */ - .cta-group { + /* Tabs */ + .mode-tabs { display: flex; - gap: 1rem; justify-content: center; - align-items: center; - margin-bottom: 4rem; - flex-wrap: wrap; + gap: 0.5rem; + margin-bottom: 1.5rem; + } + + .tab-btn { + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.1); + color: #9ca3af; + padding: 0.5rem 1rem; + border-radius: 8px; + cursor: pointer; + font-size: 0.85rem; + font-weight: 600; + transition: 0.2s; + } + + .tab-btn:hover { + background: rgba(255, 255, 255, 0.08); + color: #fff; } + .tab-btn.active { + background: rgba(16, 185, 129, 0.1); + border-color: var(--accent-color); + color: var(--accent-color); + } + + /* CTA */ + .copy-cmd { display: flex; align-items: center; @@ -291,6 +314,62 @@ font-weight: bold; } + /* Modes Showcase */ + .modes-showcase { + padding: 4rem 0; + background: linear-gradient(180deg, transparent, rgba(16, 185, 129, 0.02) 50%, transparent); + } + + .modes-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 2rem; + margin-top: 3rem; + } + + .mode-card { + background: #0f172a; + padding: 2rem; + border-radius: 20px; + border: 1px solid rgba(255, 255, 255, 0.05); + transition: 0.3s; + } + + .mode-card:hover { + border-color: var(--accent-color); + transform: translateY(-5px); + } + + .mode-icon { + font-size: 2.5rem; + margin-bottom: 1.5rem; + } + + .mode-card h3 { + margin-bottom: 1rem; + color: #fff; + } + + .mode-card p { + color: #94a3b8; + font-size: 0.95rem; + margin-bottom: 1.5rem; + } + + .mode-card pre { + background: #020617; + padding: 0.75rem; + border-radius: 10px; + font-family: var(--mono-family); + font-size: 0.8rem; + border: 1px solid rgba(255, 255, 255, 0.05); + overflow-x: auto; + } + + .mode-card code { + color: #38bdf8; + } + /* Features */ .features { padding: 8rem 0; @@ -371,6 +450,10 @@ font-size: 12px; min-height: 380px; } + + .modes-grid { + grid-template-columns: 1fr; + } } @@ -379,7 +462,7 @@
-
v1.2.0 Stable Release
+
v0.2.0 Stable Release

Parallel Flashing, Zero Waiting.

Flash dozens of ESP devices simultaneously. The professional CLI tool for rapid prototyping and mass @@ -388,40 +471,31 @@

Parallel Flashing, Zero Waiting.

- pip install esp-batch-flash + pip install esp-batch-flash
View on GitHub
+ +
+ + + +
+
- esp_batch_flash — 80x24 + esp_batch_flash — + 80x24
-
-
- $ | -
- - @@ -429,6 +503,36 @@

Parallel Flashing, Zero Waiting.

+
+
+

Powerful Flashing Modes

+
+
+
🚀
+

IDF Auto-Detect

+

Run esp-batch-flash inside your ESP-IDF project. It automatically finds + flash_args and prepares all binaries for you. +

+
$ esp-batch-flash
+
+
+
📦
+

Standalone Binaries

+

No project needed. Flash raw .bin files directly to specific addresses. Ideal for + production and firmware distribution.

+
$ esp-batch-flash --bin 0x10000:app.bin
+
+
+
🖐️
+

Interactive Selection

+

Too many ports? Use --interactive to pick exactly which devices to target from a + convenient terminal menu.

+
$ esp-batch-flash --interactive
+
+
+
+
+

Why ESP Batch Flash?

@@ -466,53 +570,159 @@

Visual Progress

From 0d542c0f037588d2a4e451843834b4cda8b03b73 Mon Sep 17 00:00:00 2001 From: Li Bo Date: Thu, 26 Feb 2026 16:44:19 +0800 Subject: [PATCH 3/5] fix: responsive layout issues and allow non-blocking tab switching --- docs/index.html | 71 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 22 deletions(-) diff --git a/docs/index.html b/docs/index.html index f39d1dd..203755d 100644 --- a/docs/index.html +++ b/docs/index.html @@ -443,12 +443,41 @@ } .hero { - padding: 4rem 0; + padding: 4rem 0 2rem; + } + + h1 { + font-size: 2.2rem; + } + + .cta-group { + margin-bottom: 2rem; + flex-direction: column; + gap: 0.8rem; + } + + .copy-cmd { + width: 100%; + justify-content: center; + font-size: 0.85rem; + } + + .mode-tabs { + flex-wrap: wrap; + margin-bottom: 2rem; + padding: 0 10px; + } + + .tab-btn { + font-size: 0.75rem; + padding: 0.4rem 0.8rem; + flex: 1 1 auto; } .terminal-body { - font-size: 12px; - min-height: 380px; + font-size: 11px; + padding: 15px; + min-height: 350px; } .modes-grid { @@ -608,17 +637,15 @@

Visual Progress

} }; - let currentScenario = 'idf'; - let isAnimating = false; - let animationTimeout; + let currentTaskId = 0; function clearTerminal() { terminalContent.innerHTML = ''; - if (animationTimeout) clearTimeout(animationTimeout); } - async function typeText(element, text, speed = 40) { + async function typeText(element, text, taskId, speed = 40) { for (let i = 0; i < text.length; i++) { + if (taskId !== currentTaskId) return; element.textContent += text[i]; await new Promise(r => setTimeout(r, speed + Math.random() * 30)); } @@ -632,8 +659,7 @@

Visual Progress

} async function runScenario(id) { - if (isAnimating) return; - isAnimating = true; + const taskId = ++currentTaskId; clearTerminal(); const scenario = scenarios[id]; @@ -653,12 +679,16 @@

Visual Progress

cursor.textContent = '|'; cmdLine.appendChild(cursor); - await typeText(cmdText, scenario.command); + await typeText(cmdText, scenario.command, taskId); + if (taskId !== currentTaskId) return; cursor.remove(); await new Promise(r => setTimeout(r, 500)); + if (taskId !== currentTaskId) return; for (const step of scenario.steps) { + if (taskId !== currentTaskId) return; + if (step.type === 'info') { const line = createLine('output-line info-text'); line.textContent = step.text; @@ -677,7 +707,7 @@

Visual Progress

const input = document.createElement('span'); input.style.color = 'var(--accent-color)'; line.appendChild(input); - await typeText(input, step.input, 100); + await typeText(input, step.input, taskId, 100); } else if (step.type === 'progress') { const grid = document.createElement('div'); grid.className = 'progress-grid'; @@ -698,18 +728,20 @@

Visual Progress

} await new Promise(r => setTimeout(r, 200)); + if (taskId !== currentTaskId) return; const promises = bars.map(bar => { return new Promise(resolve => { const fill = document.getElementById(`fill-${bar.i}`); - // Trigger reflow + if (!fill) { resolve(); return; } fill.offsetHeight; fill.style.width = '100%'; - animateValue(`perc-${bar.i}`, 0, 100, bar.duration * 1000, resolve); + animateValue(`perc-${bar.i}`, 0, 100, bar.duration * 1000, taskId, resolve); }); }); await Promise.all(promises); + if (taskId !== currentTaskId) return; const final = createLine('output-line success-text'); final.style.marginTop = '15px'; @@ -718,14 +750,14 @@

Visual Progress

} await new Promise(r => setTimeout(r, 400)); } - - isAnimating = false; } - function animateValue(id, start, end, duration, onComplete) { + function animateValue(id, start, end, duration, taskId, onComplete) { const obj = document.getElementById(id); + if (!obj) { onComplete(); return; } let startTimestamp = null; const step = (timestamp) => { + if (taskId !== currentTaskId) { onComplete(); return; } if (!startTimestamp) startTimestamp = timestamp; const progress = Math.min((timestamp - startTimestamp) / duration, 1); obj.innerHTML = Math.floor(progress * (end - start) + start) + "%"; @@ -741,24 +773,20 @@

Visual Progress

tabBtns.forEach(btn => { btn.addEventListener('click', () => { - if (isAnimating) return; tabBtns.forEach(b => b.classList.remove('active')); btn.classList.add('active'); runScenario(btn.dataset.mode); }); }); - // Copy button logic document.getElementById('copy-trigger').addEventListener('click', function () { navigator.clipboard.writeText("pip install esp-batch-flash"); this.textContent = "Copied!"; setTimeout(() => { this.textContent = "Copy"; }, 2000); }); - // Start setTimeout(() => runScenario('idf'), 1000); - // Fetch latest version from PyPI async function fetchLatestVersion() { try { const response = await fetch('https://pypi.org/pypi/esp-batch-flash/json'); @@ -766,7 +794,6 @@

Visual Progress

const latestVersion = data.info.version; if (latestVersion) { document.getElementById('version-badge').textContent = `v${latestVersion} Stable Release`; - // Also update install command if needed (though usually stay the same) } } catch (error) { console.error('Error fetching version from PyPI:', error); From 5fef5329ede7b989e146fbada25eac59139980b6 Mon Sep 17 00:00:00 2001 From: Li Bo Date: Thu, 26 Feb 2026 16:49:16 +0800 Subject: [PATCH 4/5] style: final UI polish, add labels, and fix alignment --- docs/index.html | 61 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/docs/index.html b/docs/index.html index 203755d..6aa05b5 100644 --- a/docs/index.html +++ b/docs/index.html @@ -149,18 +149,42 @@ color: var(--accent-color); } - /* CTA */ + /* Hero CTA & Buttons */ + .cta-group { + display: flex; + flex-direction: column; + align-items: center; + gap: 1.5rem; + margin-bottom: 5rem; + } + + .install-wrap { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.75rem; + width: 100%; + } + + .install-label { + font-size: 0.9rem; + color: #94a3b8; + font-weight: 500; + } .copy-cmd { display: flex; align-items: center; - background: #111827; - padding: 0.6rem 1.2rem; + background: rgba(255, 255, 255, 0.03); + border: 1px solid rgba(255, 255, 255, 0.1); + padding: 0.6rem 0.6rem 0.6rem 1.25rem; border-radius: 12px; - border: 1px solid #374151; font-family: var(--mono-family); - font-size: 0.95rem; - box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); + width: 100%; + max-width: 450px; + justify-content: space-between; + transition: 0.3s; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2); } .copy-btn { @@ -180,16 +204,22 @@ } .btn { - padding: 0.75rem 1.5rem; + display: inline-flex; + align-items: center; + padding: 0.8rem 1.8rem; + background: transparent; + color: #fff; + border: 1px solid rgba(255, 255, 255, 0.15); border-radius: 12px; font-weight: 600; - transition: all 0.2s; - border: 1px solid #374151; + text-decoration: none; + transition: 0.3s; } .btn:hover { - background: #1f2937; - border-color: #4b5563; + background: rgba(255, 255, 255, 0.05); + border-color: var(--accent-color); + transform: translateY(-2px); } /* Terminal Animation */ @@ -499,9 +529,12 @@

Parallel Flashing, Zero Waiting.

-
- pip install esp-batch-flash - +
+
Quick Install via pip
+
+ pip install esp-batch-flash + +
View on GitHub
From 2e15cce272ee1e3aa3c4174bd1958615958ae8a6 Mon Sep 17 00:00:00 2001 From: Li Bo Date: Thu, 26 Feb 2026 17:10:41 +0800 Subject: [PATCH 5/5] ux: implement scroll-driven (scrollytelling) mode showcase with mobile stacking --- docs/index.html | 280 +++++++++++++++++++++++++++++------------------- 1 file changed, 171 insertions(+), 109 deletions(-) diff --git a/docs/index.html b/docs/index.html index 6aa05b5..e331f83 100644 --- a/docs/index.html +++ b/docs/index.html @@ -118,35 +118,46 @@ margin: 0 auto 3rem; } - /* Tabs */ - .mode-tabs { + /* Feature Sections */ + .feature-item { display: flex; - justify-content: center; - gap: 0.5rem; - margin-bottom: 1.5rem; + align-items: center; + gap: 4rem; + padding: 8rem 0; + opacity: 0; + transform: translateY(30px); + transition: all 0.8s cubic-bezier(0.22, 1, 0.36, 1); } - .tab-btn { - background: rgba(255, 255, 255, 0.05); - border: 1px solid rgba(255, 255, 255, 0.1); - color: #9ca3af; - padding: 0.5rem 1rem; - border-radius: 8px; - cursor: pointer; - font-size: 0.85rem; - font-weight: 600; - transition: 0.2s; + .feature-item.active { + opacity: 1; + transform: translateY(0); } - .tab-btn:hover { - background: rgba(255, 255, 255, 0.08); - color: #fff; + .feature-content { + flex: 1; + text-align: left; } - .tab-btn.active { - background: rgba(16, 185, 129, 0.1); - border-color: var(--accent-color); - color: var(--accent-color); + .feature-visual { + flex: 1.2; + width: 100%; + } + + .feature-item:nth-child(even) { + flex-direction: row-reverse; + } + + .feature-content h2 { + font-size: 2.5rem; + margin-bottom: 1.5rem; + text-align: left; + } + + .feature-content p { + font-size: 1.1rem; + color: #94a3b8; + margin-bottom: 2rem; } /* Hero CTA & Buttons */ @@ -513,6 +524,26 @@ .modes-grid { grid-template-columns: 1fr; } + + .feature-item { + flex-direction: column !important; + gap: 2rem; + padding: 4rem 0; + text-align: center; + } + + .feature-content h2 { + text-align: center; + font-size: 2rem; + } + + .feature-content p { + text-align: center; + } + + .feature-visual { + width: 100%; + } } @@ -538,58 +569,79 @@

Parallel Flashing, Zero Waiting.

View on GitHub
+
+
- -
- - - +
+
+ +
+
+
Automatic Detection
+

IDF Project Ready

+

Building with ESP-IDF? Just run the tool inside your project directory. It automatically scans + build artifacts and prepares everything for batch flashing.

+
$ esp-batch-flash
+
+
+
+
+
+
+
+
+
+
+
+
+
- -
-
-
-
-
- esp_batch_flash — - 80x24 + +
+
+
Standalone
+

Direct Binary Flash

+

No project? No problem. Flash raw binaries directly to any address. Perfect for factory + production lines where only the final firmware is needed.

+
$ esp-batch-flash --bin 0x10000:app.bin
-
-
- +
+
+
+
+
+
+
+
+
+
- -
-
-
-
-

Powerful Flashing Modes

-
-
-
🚀
-

IDF Auto-Detect

-

Run esp-batch-flash inside your ESP-IDF project. It automatically finds - flash_args and prepares all binaries for you. -

-
$ esp-batch-flash
-
-
-
📦
-

Standalone Binaries

-

No project needed. Flash raw .bin files directly to specific addresses. Ideal for - production and firmware distribution.

-
$ esp-batch-flash --bin 0x10000:app.bin
+ +
+
+
Flexible
+

Interactive Selection

+

Too many ports connected? Use the interactive menu to hand-pick your targets. Efficient, safe, + and prevents accidental flashing of wrong devices.

+
$ esp-batch-flash --interactive
-
-
🖐️
-

Interactive Selection

-

Too many ports? Use --interactive to pick exactly which devices to target from a - convenient terminal menu.

-
$ esp-batch-flash --interactive
+
+
+
+
+
+
+
+
+
+
+
@@ -632,9 +684,6 @@

Visual Progress