47 lines
4.1 KiB
Markdown
47 lines
4.1 KiB
Markdown
# Джойстик: редизайн під референс + два реальні баги (2026-08-13)
|
||
|
||
Референс: прозора середина, градієнтний бордер, помаранчева точка пальця
|
||
з підсвіткою навколо. `JoystickC.init()` (SDK-обгортка nipplejs) приймає
|
||
будь-які опції nipplejs напряму, включно з `color: {back, front}` —
|
||
кожен рядок йде прямо в `background` відповідного div, підтримує
|
||
градієнти й навіть `var()`/`calc()` (живі CSS-змінні всередині inline
|
||
style реально оновлюються).
|
||
|
||
**Фінальна реалізація** (`beforeResourcesLoadedCb.ts` + `main.css`):
|
||
- `back` (кільце) — `conic-gradient(from var(--joy-angle), ...)`, базовий
|
||
колір однотонний темний, підсвітка (тон точки пальця) лише у широкій
|
||
дузі навпроти пальця, з `calc()`-інтерполяцією RGB-каналів (не альфи!)
|
||
за `--joy-force`.
|
||
- `front` (точка) — суцільний плоский колір, без градієнта/тіні.
|
||
- Форма кільця (прозора середина) — `mask-image: radial-gradient(...)`
|
||
з **абсолютними px**, не відсотками — щоб зміна `size` (радіус зони) не
|
||
розтягувала товщину бордера пропорційно.
|
||
- Розмір точки пальця (`.front`) — фіксований px-оверрайд, повністю
|
||
відв'язаний від `size` (nipplejs хардкодить точку як `size/2`, тож
|
||
збільшення радіуса зони інакше тягнуло за собою і точку).
|
||
- `JoystickC.onJoysticMove` — окрема підписка (SDK підтримує кілька
|
||
делегатів на подію, `PlayerC` підписаний окремо на той самий івент для
|
||
руху) ставить `--joy-angle`/`--joy-force` на `instance.ui.el` щокадру.
|
||
|
||
**⚠️ Знайдений і виправлений баг: підсвітка на 90° проти стрілки від
|
||
реального положення пальця.** `Math.atan2(y, x)` на скрін-координатах (y
|
||
вниз) і CSS `conic-gradient(from Xdeg, ...)` обидва рахують по
|
||
годинниковій, але з різною точкою нуля: atan2 — схід (3 година),
|
||
conic-gradient — північ (12 година). Фікс — плюс 90° один раз, не свап
|
||
знаку і не переписування напрямку градієнта.
|
||
|
||
**⚠️ Знайдений і виправлений баг: підсвітка не зупинялась на межі
|
||
зони, а продовжувала змінюватись, коли палець вели далі за край.**
|
||
Трасування в самому nipplejs (`Collection.ts`): `force` рахується з
|
||
СИРОЇ, необмеженої дистанції дотику (`dist / size`), тоді як
|
||
`frontPosition` (сама видима точка й кут вище) — з ОБМЕЖЕНОЇ. За краєм
|
||
кільця `force` продовжує необмежено зростати, хоча точка вже візуально
|
||
запінена на місці — усі `calc()` розраховані на `force` в межах `0..1`.
|
||
Це ж переповнення й давало жовтуватий відтінок (RGB-канали переїжджали
|
||
за цільовий колір). Фікс — один `Math.min(Math.max(force, 0), 1)` перед
|
||
записом у CSS-змінну, а не clamp у кожному calc() окремо.
|
||
|
||
Розмір: `size` (радіус зони) підняли на +50%, потім усі елементи
|
||
(зона+точка+товщина кільця) зменшені на -30% від того — фінальні числа:
|
||
`size: 105`, точка `35px`/`-17.5px` margin, кільце `43.4/44.8/46.9/48.3px`.
|