108 lines
7.6 KiB
Markdown
108 lines
7.6 KiB
Markdown
# Motion and interaction
|
|
|
|
## Motion character
|
|
|
|
Aim for fluid, slightly viscous motion: noticeable, calm, and complete. Avoid bounce, elastic easing, abrupt unmounts, decorative page choreography, or tiny effects too weak to communicate feedback.
|
|
|
|
Motion is functional feedback. If the system is running, refreshing, counting, switching route, or inviting interaction, show that activity with restrained movement. Do not animate every static decoration; animate the part that proves work, state, or affordance.
|
|
|
|
Use exponential ease-out curves such as `cubic-bezier(0.16, 1, 0.3, 1)` for arrivals. Typical timing:
|
|
|
|
- hover and press: 180-300 ms;
|
|
- state color and glow: 600-900 ms;
|
|
- content reveal: 600-850 ms;
|
|
- numeric tween and progress: about 900 ms;
|
|
- copy feedback: about 800 ms;
|
|
- server cascade: 620-760 ms per row with 90-110 ms stagger.
|
|
- tooltip arrival: about 90-140 ms with almost no delay;
|
|
- ambient affordance hint: one small cycle roughly every 10 seconds.
|
|
|
|
## Cycle completion
|
|
|
|
- On pointer leave, do not snap an infinite hover animation or reverse it from the middle. Mark it for stopping, let the current iteration reach its original coordinates, then remove the animation.
|
|
- If the user re-enters before the iteration ends, clear the stop request and continue the same behavior.
|
|
- Separate state transforms from repeating motion when both affect one control. Animate a child for the cycle and its wrapper for durable state, or wait for `animationiteration` before clearing the animated class.
|
|
- Keep reduced-motion behavior immediate and static; never wait for an iteration event that will not fire.
|
|
|
|
## Power state
|
|
|
|
- Transition gray to the current mode accent slowly when connecting and back to gray when disconnecting.
|
|
- Animate icon color, localized light, and SVG shadow together.
|
|
- Let the light expand and brighten on enable, then contract and fade on disable.
|
|
- Keep the hit target and all surrounding geometry fixed.
|
|
- Use a short press compression, followed by a slower release.
|
|
|
|
## Changing text and numbers
|
|
|
|
- Put alternate labels in fixed-size slots.
|
|
- Reveal connection title, timer, and hint with overlapping fixed layers, opacity, and light blur, never vertical layout movement.
|
|
- Crossfade `VPN включён`, `Gateway подключён`, and disconnected copy in the same reserved slot when route state changes.
|
|
- Split changing numeric values into stable digits. On a tick such as `33 → 34`, keep the first `3` mounted and animate only `3 → 4` with a soft color/glow/blur flow; avoid low-opacity blinking or scaling the whole seconds value.
|
|
- Persist user-selected timer presentation locally and restore it on the next visit.
|
|
- Tween numeric traffic values from old to new with `requestAnimationFrame` or an equivalent stable counter.
|
|
- Animate progress width concurrently and add a brief glow that fully fades.
|
|
- Never translate changing numbers if the user asked for a fluid morph; use numerical interpolation, opacity, color, blur, and light.
|
|
|
|
## Mode switch affordance
|
|
|
|
- Treat the Connect/Gateway brand as one state control with a foreground label, a background label, and two independently colored direction arrows.
|
|
- On hover, move both labels continuously: let the foreground drift slightly down while the background rises toward it. Move the right arrow right and the left arrow left, then return; keep amplitudes small.
|
|
- When mode changes, swap the arrows' positions smoothly and bring the new label to the foreground without changing the brand's centered geometry.
|
|
- When hover ends, finish the current cycle at rest before stopping. Outside hover, replay one smaller cycle about every 10 seconds to hint that the control is clickable.
|
|
- Keep explanatory tooltip geometry tied to the mode-label-to-arrows span, not to the entire Harbor wordmark.
|
|
|
|
## Refresh
|
|
|
|
- Use a clean, symmetric SVG refresh icon aligned in the same flex row as its label.
|
|
- Spin for at least one full cycle. If the request finishes mid-cycle, continue to the next cycle boundary before stopping.
|
|
- Update data immediately when it arrives; finishing the icon cycle must not delay the data.
|
|
- Manual refresh may replay meaningful data and server transitions.
|
|
- Background polling should update quietly and must not repeatedly replay the server cascade.
|
|
- On updated traffic, tween the number, advance the bar, and emit a visible but brief mode-accent flare.
|
|
- Keep refresh tooltip outside the rotating button so it remains upright and unfiltered.
|
|
|
|
## Server cascade
|
|
|
|
- On initial display, reveal rows from top to bottom with a small negative Y offset, opacity, and blur.
|
|
- On manual refresh, animate an explicit exit phase first. Fade rows top to bottom, then remount and enter top to bottom.
|
|
- Wait for the last exit delay and duration before starting entry.
|
|
- Disable pointer interaction during exit.
|
|
- Do not replay on ping updates or unrelated renders.
|
|
|
|
## Dynamic editors
|
|
|
|
- Reveal added rows with opacity, blur, and a small transform while keeping surrounding geometry predictable.
|
|
- Give removal its own exit state and keep the row mounted until `animationend`; under reduced motion, remove it immediately.
|
|
- Do not let repeated add actions accumulate unfinished rows. Disable add while any current row lacks its required value and explain the disabled state in a reserved hint slot.
|
|
- Replace browser-native dropdowns when their platform chrome conflicts with the client surface. Use an accessible custom listbox with trigger, selected state, outside-click and Escape closing, arrow-key navigation, and restored trigger focus.
|
|
- Let picker options appear as a short staggered cloud using opacity, blur, and transform. Avoid borders, shadows, raised cards, and layout-property animation.
|
|
|
|
## Subscription input
|
|
|
|
- Show the public domain while retaining the full URL internally.
|
|
- Disable browser autocomplete suggestions and neutralize autofill backgrounds.
|
|
- Hide the blinking caret when the paste-first interaction does not need it, while preserving keyboard input and focus outline.
|
|
- When an existing subscription is being edited and the field is idle, use the mode-accent underline as a five-second timeout indicator: start bright, fade to quiet, then restore display mode.
|
|
- Pause the timeout once the user enters content.
|
|
- Close and clear unfinished input on outside click or Escape.
|
|
- Animate the trash lid independently on hover. Open an inline, non-blocking confirmation surface instead of a browser-native confirm dialog.
|
|
|
|
## First-run initialization
|
|
|
|
- With no subscription, show only the centered subscription input. Hide power, proxy controls, usage, and servers.
|
|
- After a valid subscription loads, keep the subscription and server list centered. Require an explicit server choice instead of silently selecting the first server.
|
|
- On server choice, slide the subscription column to the right while revealing the power column on the viewport's central axis.
|
|
- Preserve the chosen server on later visits, but return to first-run initialization after subscription deletion.
|
|
- Deleting a subscription must stop the VPN, clear its cached/configured state, and return the UI to the centered input without leaving stale controls visible.
|
|
|
|
## Copy feedback
|
|
|
|
- Keep protocol buttons fixed-size and centered.
|
|
- Copy the complete protocol URL while showing a shared address separately.
|
|
- Overlay mode-accent `Copied` feedback in the same fixed box; do not append text or move the label.
|
|
- Make feedback appear immediately, hold briefly, and fade fully before restoring the original label. Keep the whole cycle near 800 ms.
|
|
|
|
## Reduced motion
|
|
|
|
Under `prefers-reduced-motion: reduce`, remove transitions and keyframe animations while preserving final state, focus, color contrast, copy wording, and all functionality.
|