<!-- savepoint: 2026-05-12 / 4x4 CropAlpha 純前端化並移除單張流程 -->

# Savepoint：4×4 CropAlpha 純前端化並移除單張 370×320

> 日期：2026-05-12
> 專案：`d:\www\docker\www\line_cut_tools`（Laravel）
> 主題：把 `/line-sticker/sheet-4x4` 改寫成 CropAlpha 風格的純前端工具，並完整移除「單張 370×320」流程，使整站只剩唯一一個工具頁。

---

## 1. 一開始是如何提出需求與問題的

1. 第一輪請求：把舊計畫檔 `c:\Users\HSU\.cursor\plans\4x4_去背與_zip_d9e2133e.plan.md` **重新設計**，要求「用 [https://cidercoder.github.io/Crop-tool-rmbg/](https://cidercoder.github.io/Crop-tool-rmbg/) 一樣的版型程式碼去做」。
   - 舊計畫：Laravel 後端流程（上傳 → rembg → 後端切 16 格 → ZipArchive 打包）。
   - 參考站 CropAlpha：純前端工具（拖曳 → 客戶端 flood-fill 去背 → JSZip 客戶端打包，最多 32 張、可累積多張原圖）。
   - 兩者在「去背放哪邊」「ZIP 打包放哪邊」「上限張數」皆有重大歧異。
2. 第二輪請求（plan mode 確認後）：依重新設計的計畫實作。
3. 第三輪請求：**「請移除單張 370×320」**——把保留給單張流程的 controller / rembg service / blade 全部清掉，整站只剩 4×4 頁。
4. 第四輪請求：`savepoint`——存檔本次對話。

---

## 2. 過程中是如何一步步引導、修正與優化的

1. **比對差異**：先讀完 CropAlpha 完整 1080 行 HTML/CSS/JS（host 機 `Invoke-WebRequest` 抓檔）、舊計畫、現有 [`resources/views/line-sticker/sheet-4x4.blade.php`](../../resources/views/line-sticker/sheet-4x4.blade.php)、[`app/Services/Sheet4x4Service.php`](../../app/Services/Sheet4x4Service.php)，列出八項客製決策。
2. **用 AskQuestion 釐清關鍵歧異**（避免單方面假設）：
   - 去背策略 → 選 **純前端 flood-fill**（不再呼叫 rembg）。
   - ZIP 與上限張數 → 選 **前端 JSZip + 嚴格 16 張**（不開放「上傳下一張」累積到 32）。
3. **產出新計畫**：建立 `c:\Users\HSU\.cursor\plans\4x4_cropalpha_純前端化_a9932e07.plan.md`，含 mermaid 流程圖、改寫 / 簡化 / 刪除 / 不動四類清單、6 點驗收項。
4. **實作（5 個 to-do）**：
   - 把 Blade 整檔替換為 CropAlpha 版型，並客製：`MAX=16`、移除「上傳下一張」按鈕與 `nextFileInput`、`pad2()` 檔名 `01.png~16.png`、下載檔名 `4x4_sticker_<n>張.zip`、自動偵測按鈕文案「✦ 自動偵測 16 格」、刪除原作者個人宣傳 banner 改成 topbar 說明 + 回單張連結。
   - 簡化 `Sheet4x4Controller` 只剩 `form()`，移除所有 rembg / service / request import。
   - 移除 `POST /line-sticker/sheet-4x4/process` 路由與 throttle。
   - 刪除 `app/Services/Sheet4x4Service.php`、Blade 編譯快取。
5. **驗證**：lint 全清、grep 無殘留、`Invoke-WebRequest` 拿到 200、用 Cursor browser MCP 看 DOM/Console/Network——除 JSZip CDN + Google Fonts 之外**完全無後端請求**。
6. **追加需求：移除單張 370×320**——重新 grep 影響範圍，建立 8 個新 to-do：
   - 刪 9 個 PHP（controller / request / 4 個 service / cutout gray spill / exception / Utf8 support）。
   - 刪 view `upload.blade.php`、2 個測試、`config/line_sticker.php`。
   - 改寫 `routes/web.php`：`/`、`/line-sticker`、`/line-sticker/sheet-4x4` 三條全部指向 `Sheet4x4Controller::form`（同一頁，URL 別名）。
   - Blade topbar 移除「回單張 370×320」連結。
   - `.env`、`.env.example` 移除 `REMBG_*` / `LINE_CUTOUT_*` / `LINE_STICKER_*` 共 16 行。
   - 清空 Blade view cache、跑 `composer dump-autoload --optimize`（6862 classes 重生）、`php artisan route:clear / config:clear / view:clear`。
7. **最終驗證**：三個 URL 全部 HTTP 200、回傳同一份 4×4 頁面（41457 bytes）、Cursor browser MCP DOM 11 個元素正確、console 無錯誤。

---

## 3. 最後是如何產出目前這個結果的（現況）

### View 層

- [`resources/views/line-sticker/sheet-4x4.blade.php`](../../resources/views/line-sticker/sheet-4x4.blade.php)（1035 行，完整重寫）：CropAlpha 暗色雙欄版型 + 內嵌 CSS + 內嵌 JS + JSZip CDN，全部 client-side。
  - `MAX=16` 常數
  - 自動偵測：4×4 等分 + valley snap 演算法
  - 手動框選：滑鼠/觸控 overlay
  - 去背：flood-fill + connected-component clean + autotrim
  - ZIP：前端 JSZip 打包 `01.png~16.png`
  - topbar 文案：「限 4×4（16 格）合圖專用，背景需為近似純色才能正確去背」
- 已刪除：`resources/views/line-sticker/upload.blade.php`、所有 Blade 編譯快取。

### Controller 層

- [`app/Http/Controllers/Sheet4x4Controller.php`](../../app/Http/Controllers/Sheet4x4Controller.php)（14 行）：

```1:14:app\Http\Controllers\Sheet4x4Controller.php
<?php

namespace App\Http\Controllers;

use Illuminate\View\View;

class Sheet4x4Controller extends Controller
{
    public function form(): View
    {
        return view('line-sticker.sheet-4x4');
    }
}
```

- 已刪除：`LineStickerController`、`LineStickerUploadRequest`、`RembgFailedException`。

### Service / Support 層

- 已刪除（共 7 檔）：`RembgService`、`CutoutPostCleanupService`、`CornerBgCutoutCleanupService`、`CutoutGraySpillService`、`StickerCanvasService`、`Sheet4x4Service`、`App\Support\Utf8`。
- 已刪除的測試（2）：`tests/Feature/LineStickerUploadTest.php`、`tests/Unit/Utf8JsonSafeTest.php`。

### 路由層

- [`routes/web.php`](../../routes/web.php)（12 行）：三條 GET 都指向同一個 `Sheet4x4Controller::form`，整站不再有任何 POST 路由。

```1:12:routes\web.php
<?php

use App\Http\Controllers\Sheet4x4Controller;
use Illuminate\Support\Facades\Route;

Route::get('/', [Sheet4x4Controller::class, 'form'])
    ->name('home');

Route::get('/line-sticker', [Sheet4x4Controller::class, 'form'])
    ->name('line-sticker.form');

Route::get('/line-sticker/sheet-4x4', [Sheet4x4Controller::class, 'form'])
    ->name('line-sticker.sheet-4x4.form');
```

### Config / Env 層

- 已刪除：`config/line_sticker.php`（rembg / 370×320 / corner-bg cleanup 全部不再使用）。
- [`.env`](../../.env)、[`.env.example`](../../.env.example)：移除 `REMBG_BINARY`、`REMBG_PYTHON`、`REMBG_TIMEOUT`、`LINE_CUTOUT_CORNER_BG_CLEANUP`、`LINE_CUTOUT_CORNER_BG_DISTANCE`、`LINE_CUTOUT_SPILL_*`、`LINE_STICKER_WIDTH/HEIGHT/MARGIN` 共 16 行。

### 影響

- 整站只剩唯一一個工具頁：`/`（或 `/line-sticker`、`/line-sticker/sheet-4x4`）→ CropAlpha 風格 4×4 純前端工具。
- 任何流程都不上傳伺服器；`storage/app/public/uploads`、`outputs`、`sheet_cells`、`sheet_zips` 永不會再被寫入。
- 已不再依賴 rembg / Python 環境，純 HTML/CSS/JS + JSZip CDN 即可運作。

---

## 可直接複製使用、能夠重現相同結果的提示詞

```text
我有一個 Laravel 11 專案，目前以後端 rembg + Intervention Image + ZipArchive 處理「單張 370×320 貼圖」與「4×4 合圖（16 格）」兩種流程。
請依以下需求重新設計：

1. 用 https://cidercoder.github.io/Crop-tool-rmbg/ （CropAlpha）的整套 HTML/CSS/JS 版型作為新 4×4 頁面的基底（雙欄暗色介面、Syne + DM Mono 字型、棋盤底預覽 grid、右上角去背 toggle、Toast、Lightbox），改寫成單一 Blade 模板。
2. 去背改為「純前端 flood-fill」（沿用 CropAlpha 的 detectBgColor + removeBackground + autotrimCanvas + connected-component clean），完全不再呼叫 rembg、圖片不上傳伺服器。
3. ZIP 改為「前端 JSZip」客戶端打包，產出 `4x4_sticker_<n>張.zip`，內含檔名 `01.png ~ 16.png`（用 pad2 兩位數編號；刪除某張後重新排序）。
4. 嚴格 4×4 = 16 張上限（移除 CropAlpha 「上傳下一張」累積到 32 張的行為：MAX = 16、移除 btnNext / nextFileInput / nextFile()、自動偵測按鈕文案改成「✦ 自動偵測 16 格」）。
5. 完全移除「單張 370×320」流程：刪除 LineStickerController、LineStickerUploadRequest、RembgService、StickerCanvasService、CutoutPostCleanupService、CornerBgCutoutCleanupService、CutoutGraySpillService、RembgFailedException、App\Support\Utf8、Sheet4x4Service、resources/views/line-sticker/upload.blade.php、tests/Feature/LineStickerUploadTest.php、tests/Unit/Utf8JsonSafeTest.php、config/line_sticker.php、.env / .env.example 中 REMBG_* / LINE_CUTOUT_* / LINE_STICKER_* 全部設定。
6. routes/web.php 只留三條 GET，都指向 Sheet4x4Controller::form：`/`（home）、`/line-sticker`（line-sticker.form）、`/line-sticker/sheet-4x4`（line-sticker.sheet-4x4.form）；不再有任何 POST。
7. Sheet4x4Controller 精簡到只有 form() 方法，不再 inject 任何 service。
8. topbar 文案：「限 4×4（16 格）合圖專用，背景需為近似純色才能正確去背」，不要原作者的個人宣傳 banner、不要外連回單張流程。
9. 完成後：清空 storage/framework/views/*.php、跑 composer dump-autoload --optimize、php artisan route:clear / config:clear / view:clear。
10. 驗證：
    - lint 全部乾淨
    - grep 全專案無 LineStickerController / RembgService / StickerCanvasService / Cutout*Service / Utf8 / line_sticker config 殘留
    - `/`、`/line-sticker`、`/line-sticker/sheet-4x4` 三個 URL 都 HTTP 200 且回傳同一份頁面
    - 用 Cursor browser MCP 打開頁面 → console 無錯誤、Network 除了 JSZip CDN + Google Fonts 沒有任何後端請求

請逐步：先讀計畫範圍、用 AskQuestion 釐清「去背策略 / ZIP 策略 / 張數上限」三個關鍵歧異後再動手；實作時建立 to-do 清單追蹤進度，每完成一項標記 completed；最後做 smoke test。
```
