docs: note the two web looks that still have to reach Android
The web studio grew a CLASSIC VIVIDIPES sim (Classic Chrome's blue row spliced to Velvia's red and green) and an FX MONOCHROME switch; both are written up here with the exact matrices, anchors and the checks they have to pass before they count as ported.
This commit is contained in:
@@ -0,0 +1,123 @@
|
|||||||
|
# Ghi chú port web → Android: sim `CLASSIC VIVIDIPES` + chip FX `MONOCHROME`
|
||||||
|
|
||||||
|
Nguồn: web studio `docker/frontend` (nhánh `recipes-web`), commit `d7d7be2` (sim mới) và
|
||||||
|
`4d0d441` (chip FX). Việc dưới đây là **port sang app Android** (`src/`, nhánh này).
|
||||||
|
|
||||||
|
Đối chiếu: `src/` giữa `recipes-web` và `feat/vision-camera-v5` **chỉ khác**
|
||||||
|
`src/components/RecipeCreateModal.tsx` (+9 dòng) — nên port gần như là chép y nguyên.
|
||||||
|
Số dòng dưới đây tính theo nhánh này.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Sim mới `CLASSIC VIVIDIPES`
|
||||||
|
|
||||||
|
Ghép tại dòng blue: **giữ nguyên dòng blue của `classic-chrome`**, lấy **dòng R/G của `velvia`**.
|
||||||
|
|
||||||
|
Sửa 4 file:
|
||||||
|
|
||||||
|
1. `src/types/index.ts:65` — `BaseFilter`: thêm `'classic-vivid'`.
|
||||||
|
2. `src/utils/colorUtils.ts` — thêm nhánh **ngay sau** nhánh `classic-chrome` (dòng 111):
|
||||||
|
```ts
|
||||||
|
} else if (baseFilter === 'classic-vivid') {
|
||||||
|
// Classic Vivid: the Classic Chrome blue row kept verbatim — skies stay the
|
||||||
|
// same muted teal/cyan — with the red and green rows taken from Velvia, so
|
||||||
|
// everything that is not blue reads loud.
|
||||||
|
matrix = [
|
||||||
|
1.3895, -0.2540, -0.0256, 0, -0.0550, // R — velvia
|
||||||
|
-0.0772, 1.2355, -0.0261, 0, -0.0661, // G — velvia
|
||||||
|
0.0652, 0.3973, 0.5575, 0, -0.0100, // B — classic-chrome (nguyên bản)
|
||||||
|
0, 0, 0, 1, 0,
|
||||||
|
];
|
||||||
|
```
|
||||||
|
3. `src/utils/defaultRecipes.ts:43` — `FILM_SIMS`, thêm ngay sau `sim-classic-chrome`:
|
||||||
|
```ts
|
||||||
|
{ id: 'sim-classic-vivid', name: 'CLASSIC VIVIDIPES', baseFilter: 'classic-vivid', adjustments: { ...DEFAULT_ADJUSTMENTS } },
|
||||||
|
```
|
||||||
|
4. `src/utils/toneShader.ts:190` — `FILM_TONE`, cạnh `'classic-chrome'`:
|
||||||
|
```ts
|
||||||
|
'classic-vivid': { sh: -0.28 },
|
||||||
|
```
|
||||||
|
(Dìm shadow thuộc về stock chứ không thuộc dòng ma trận → đi kèm. Bỏ dòng này nếu muốn
|
||||||
|
VIVIDIPES không dìm shadow.)
|
||||||
|
|
||||||
|
**Không phải sửa gì thêm**: chip `PHOTO STYLE` (`AdjustmentPanel.tsx` `groupDefs.style`), TopBar
|
||||||
|
(`activeRecipe.name`) và picker trong `RecipeCreateModal.tsx` đều map từ `FILM_SIMS`.
|
||||||
|
|
||||||
|
**Kiểm chứng**: strip PHOTO STYLE có **10** sim; chọn `CLASSIC VIVIDIPES` → look khác **cả**
|
||||||
|
`CLASSIC CHRIPES` lẫn `VELVIPES`; `CLASSIC CHRIPES` vẫn nguyên vẹn cạnh nó.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Chip `MONOCHROME` ở tab FX (`filters`)
|
||||||
|
|
||||||
|
Đây là **công tắc**, không phải một look: bật thì đổi `baseFilter` sang `monochrome`, tắt thì
|
||||||
|
trả lại đúng cái ảnh đang mặc (kể cả tên sim). **Không được đụng `adjustments`** — knob chỉnh
|
||||||
|
trong lúc đang bật phải sống sót.
|
||||||
|
|
||||||
|
Web: `docker/frontend/src/App.tsx` — `monoPrev` ref + `toggleMono`, chip `mono` đứng đầu
|
||||||
|
`case 'fx'`, `active: monoOn` với `monoOn = recipe.baseFilter === 'monochrome'`.
|
||||||
|
|
||||||
|
Android cần 2 chỗ:
|
||||||
|
|
||||||
|
**a. `src/components/AdjustmentPanel.tsx`** — `case 'filters'` (dòng 888):
|
||||||
|
```ts
|
||||||
|
case 'filters':
|
||||||
|
return chipRow([
|
||||||
|
{ key: 'mono', label: 'MONOCHROME', active: monoOn, amberValue: monoOn, onPress: onToggleMono },
|
||||||
|
...paramChips(paramDefs.filters),
|
||||||
|
]);
|
||||||
|
```
|
||||||
|
+ thêm 2 prop vào `interface AdjustmentPanelProps`: `monoOn: boolean;` và `onToggleMono: () => void;`
|
||||||
|
+ truyền từ `App.tsx` chỗ render `<AdjustmentPanel … />` (`App.tsx:1929` có `currentBaseFilter`,
|
||||||
|
`onSelectRecipe` — đặt cạnh đó).
|
||||||
|
|
||||||
|
**b. `App.tsx`** — Android giữ `adjustments` là state **riêng** (không nằm trong `selectedRecipe`),
|
||||||
|
nên công tắc chỉ chạm `selectedRecipe`:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// FX's MONOCHROME switch: not a look of its own — it swaps the base filter for
|
||||||
|
// the mono stock and swaps right back. Adjustments are never touched.
|
||||||
|
const monoOn = selectedRecipe?.baseFilter === 'monochrome';
|
||||||
|
const monoPrevRef = useRef<Recipe | null>(null);
|
||||||
|
|
||||||
|
const handleToggleMono = () => {
|
||||||
|
commit(true, () => {
|
||||||
|
if (selectedRecipe?.baseFilter === 'monochrome') {
|
||||||
|
const back = monoPrevRef.current ?? filmSimToRecipe(FILM_SIMS.find((f) => f.id === 'sim-provia')!);
|
||||||
|
setSelectedRecipe(back);
|
||||||
|
} else {
|
||||||
|
monoPrevRef.current = selectedRecipe;
|
||||||
|
setSelectedRecipe({
|
||||||
|
...(selectedRecipe ?? filmSimToRecipe(FILM_SIMS[0])),
|
||||||
|
id: 'mono',
|
||||||
|
name: 'MONOCHROME',
|
||||||
|
baseFilter: 'monochrome',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Lưu ý:
|
||||||
|
- `commit(true, …)` (dòng 739) để công tắc vào **undo stack** như mọi edit khác — `handleResetAll`
|
||||||
|
dùng đúng cách này.
|
||||||
|
- `Look` đã có `recipe` → UNDO tự trả lại đúng `baseFilter` cũ, không cần state phụ nào khác.
|
||||||
|
- `id: 'mono'` không trùng sim nào nên khi bật, chip PHOTO STYLE **không** còn sáng tên sim cũ
|
||||||
|
(`groupDefs.style.value` tính từ `currentRecipeId` so với `FILM_SIMS`).
|
||||||
|
- Tắt khi `monoPrevRef` rỗng (ví dụ vào monochrome bằng cách chọn sim ACRIPES, không qua công tắc)
|
||||||
|
→ rơi về PROVIA, tức là "tắt là có màu", không phải về đen trắng.
|
||||||
|
|
||||||
|
**Kiểm chứng**: bật → ảnh xám (mọi pixel `R=G=B`; chỉ lệch khi WB khác 5500K hoặc tint khác 0);
|
||||||
|
tắt → ảnh trở lại **y hệt** trước khi bật (so hash pixel); đổi `CONTRAST` trong lúc bật/tắt →
|
||||||
|
giá trị vẫn giữ; UNDO một nhịp → về màu, chip trở lại trạng thái tắt.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Test web đã chạy (tham chiếu — nằm trong scratchpad của agent, không nằm trong repo)
|
||||||
|
|
||||||
|
- `sim-vivid-test.cjs` — **9/0**: chip có mặt, strip đủ 10 sim, chọn được, render khác cả
|
||||||
|
CHRIPES lẫn VELVIPES.
|
||||||
|
- `fx-mono-test.cjs` — **15/0**: đo trực tiếp kênh màu trên pixel preview (spread `>25` khi màu,
|
||||||
|
`<=6` khi mono), hash quay lại y hệt khi tắt, CONTRAST sống sót, UNDO gỡ mono.
|
||||||
|
- Regression web quanh 2 thay đổi: `panel`, `layout`, `fonts 27/0`, `create 52/0`, `share 22/0`,
|
||||||
|
`photo-save 19/0`, `redo 30/0`, `accent-brand` — tất cả xanh.
|
||||||
Reference in New Issue
Block a user