web: a film sim is colour and tone only

The ten PHOTO STYLE sims now carry nothing but their stock's own grade, and
each is named for the stock it stands for: PROVIA, VELVIA, CLASSIC CHROME,
CLASSIC VIVID (Velvia spliced with Classic Chrome at the blue row), CLASSIC
NEGATIVE, ASTIA, ETERNA, ACROS, LC STREETLIFE CLASSIC, LC STREETLIFE VIVID.
Grain, clarity, saturation and light moves were dropped from their
`adjustments`, so a sim is a clean starting point and the general knobs read
their defaults while the look still lands on the pixels.

LC STREETLIFE VIVID keeps the one brightness step its stock needs, but as
SIM_EXPOSURE_BIAS in colorUtils rather than as an adjustment: it is folded in
where the Exposure slider applies, so the picture gets the lift and the
parameter stays at 0.

Also in this checkpoint: the watermark/GPS boxes and their colour pickers, the
WATERMARK chip column, the real admin stats, and the fix that stopped presets
from doubling and a frame from refusing to come off when a photo was reopened
(/file is the finished render, /base the editable pixels).
This commit is contained in:
2026-09-22 08:32:28 +07:00
parent 52b672deec
commit 428e7fa682
18 changed files with 1831 additions and 148 deletions
+12 -1
View File
@@ -26,6 +26,8 @@ export const en: Dict = {
'drop.peeking': 'SHOWING THE ORIGINAL',
'drop.peekHint': 'Hold right-click or the \\ key to compare with the original',
'drop.compare': 'Compare with original picture',
'drop.keep': 'SAVE ORIGINAL',
'drop.keepHint': 'Save the untouched photo to the device photo library. A browser that cannot share files downloads it instead.',
'drop.demoLimit': 'Demo build: exports are capped at {px}px and carry a watermark.',
'hist.title': 'HISTOGRAM',
@@ -97,7 +99,12 @@ export const en: Dict = {
'wm.lat': 'Latitude',
'wm.lng': 'Longitude',
'wm.hasExif': 'GPS read from the photo.',
'wm.noExif': 'This photo has no GPS — type it in if you want the stamp.',
'wm.noExif': 'This photo has no GPS — type it in, or use where you are now.',
'wm.useLocation': 'USE MY LOCATION',
'wm.locating': 'GETTING LOCATION…',
'wm.hasDevice': "GPS taken from the device's current position.",
'wm.hasManual': 'GPS typed in by you.',
'wm.locFail': 'Could not get a location — type the coordinates in.',
'auth.loginTitle': 'Log in',
'auth.signupTitle': 'Create an account',
@@ -143,6 +150,7 @@ export const en: Dict = {
'save.photoNeedLogin': 'Log in to save a photo.',
'save.photoSaved': 'Photo saved {n}/{max}.',
'save.photoFull': 'That is all {max} — remove one in My photos.',
'save.photoNoMax': 'SAVE PHOTO {n}',
'save.photoNoSource': 'Load a photo first.',
'save.photoFailed': 'Could not save the photo: {msg}',
'myp.empty': 'NO SAVED PHOTOS YET.',
@@ -161,6 +169,9 @@ export const en: Dict = {
'photos.title': 'My photos',
'photos.hint': 'Each account keeps up to {max} photos. What the studio saves lives here and shows up on the community reel.',
'photos.count': '{n}/{max} photos',
'photos.countNoMax': '{n} photos',
'photos.hintNoMax':
'Admin accounts keep no photo limit. What the studio saves lives here and shows up on the community reel.',
'photos.add': 'ADD A PHOTO',
'photos.empty': 'No photos yet. Open the studio and hit SAVE PHOTO, or add one right here.',
'photos.full': 'That is all {max}. Remove one before saving again.',
+12 -1
View File
@@ -33,6 +33,8 @@ export const vi = {
'drop.peeking': 'ĐANG XEM ẢNH GỐC',
'drop.peekHint': 'Giữ chuột phải hoặc phím \\ để so ảnh gốc',
'drop.compare': 'So với ảnh gốc',
'drop.keep': 'LƯU ẢNH GỐC',
'drop.keepHint': 'Lưu nguyên ảnh gốc chưa chỉnh vào thư viện ảnh của máy. Trình duyệt không chia sẻ được tệp thì ảnh sẽ được tải về.',
'drop.demoLimit': 'Bản demo: ảnh xuất ra tối đa {px}px và có watermark.',
// The histogram overlay. 'HISTOGRAM' is the word Vietnamese photographers use.
@@ -105,7 +107,12 @@ export const vi = {
'wm.lat': 'Vĩ độ',
'wm.lng': 'Kinh độ',
'wm.hasExif': 'Đã đọc GPS từ ảnh.',
'wm.noExif': 'Ảnh không có GPS — nhập tay nếu muốn đóng dấu.',
'wm.noExif': 'Ảnh không có GPS — nhập tay hoặc lấy vị trí hiện tại.',
'wm.useLocation': 'DÙNG VỊ TRÍ CỦA TÔI',
'wm.locating': 'ĐANG LẤY VỊ TRÍ…',
'wm.hasDevice': 'GPS lấy từ vị trí hiện tại của thiết bị.',
'wm.hasManual': 'GPS do bạn nhập tay.',
'wm.locFail': 'Không lấy được vị trí — hãy nhập tay.',
'auth.loginTitle': 'Đăng nhập',
'auth.signupTitle': 'Tạo tài khoản',
@@ -151,6 +158,7 @@ export const vi = {
'save.photoNeedLogin': 'Đăng nhập để lưu ảnh.',
'save.photoSaved': 'Đã lưu ảnh {n}/{max}.',
'save.photoFull': 'Đã đủ {max} ảnh — xoá bớt trong Ảnh của tôi.',
'save.photoNoMax': 'LƯU ẢNH {n}',
'save.photoNoSource': 'Chưa có ảnh nào để lưu.',
'save.photoFailed': 'Không lưu được ảnh: {msg}',
'myp.empty': 'CHƯA LƯU ẢNH NÀO.',
@@ -169,6 +177,9 @@ export const vi = {
'photos.title': 'Ảnh của tôi',
'photos.hint': 'Mỗi tài khoản giữ tối đa {max} ảnh. Ảnh lưu từ studio nằm ở đây và xuất hiện trên dải phim cộng đồng.',
'photos.count': '{n}/{max} ảnh',
'photos.countNoMax': '{n} ảnh',
'photos.hintNoMax':
'Tài khoản admin không giới hạn số ảnh. Ảnh lưu từ studio nằm ở đây và xuất hiện trên dải phim cộng đồng.',
'photos.add': 'THÊM ẢNH',
'photos.empty': 'Chưa có ảnh nào. Mở studio rồi bấm LƯU ẢNH, hoặc thêm ảnh ngay ở đây.',
'photos.full': 'Đã đủ {max} ảnh. Xoá bớt trước khi lưu tiếp.',