selection/hover transition
hover와 selection은 자주 바뀌는 UI state입니다. document state와 섞으면 undo/redo와 충돌합니다.
overlay transition만 보간하는 코드
selection 자체는 즉시 바꾸고, overlay opacity나 handle alpha만 짧게 보간합니다.
function updateOverlayTransition(state, nextSelection, now) {
const changed = state.selectionKey !== nextSelection.join(",");
return {
selectionKey: nextSelection.join(","),
selection: nextSelection,
transitionStartedAt: changed ? now : state.transitionStartedAt
};
}
function selectionOverlayAlpha(state, now) {
const t = Math.min(1, (now - state.transitionStartedAt) / 90);
return t * t * (3 - 2 * t);
}
분리할 상태
document selection
pointer hover
handle visibility
overlay opacity
selection은 즉시 바뀌고, 시각 효과만 짧게 보간합니다.
hover는 history에 넣지 않는다
function updatePointerUiState(uiState, pointer, hitResult, now) {
const hoverId = hitResult?.nodeId ?? null;
const hoverChanged = hoverId !== uiState.hoverId;
return {
...uiState,
pointer,
hoverId,
hoverStartedAt: hoverChanged ? now : uiState.hoverStartedAt
};
}
function hoverAlpha(uiState, nodeId, now) {
if (uiState.hoverId !== nodeId) return 0;
return Math.min(1, (now - uiState.hoverStartedAt) / 80);
}
hover, cursor, overlay opacity는 undo/redo에 들어가면 안 됩니다. command history에는 document change만 남기고, interaction polish는 별도 UI state로 유지합니다.
오늘의 핵심
interactive state와 document state를 분리해야 motion을 넣어도 편집 모델이 깨지지 않습니다.