physics
This commit is contained in:
@@ -90,6 +90,7 @@ interface InertiaSimulationState {
|
||||
dragScale?: number;
|
||||
lastTimestamp: number;
|
||||
frameId?: number;
|
||||
massGrams?: number;
|
||||
}
|
||||
|
||||
interface WorkspaceSnapshot {
|
||||
@@ -133,15 +134,25 @@ export const DESK_DEFAULT_CANVAS_WIDTH = 1024;
|
||||
export const DESK_DEFAULT_CANVAS_HEIGHT = 680;
|
||||
export const DESK_CARD_MIN = 240;
|
||||
export const DESK_CARD_MAX = 340;
|
||||
export const CARD_PAGE_WEIGHT_GRAMS = 5;
|
||||
export const CARD_BASE_WEIGHT_GRAMS = 30;
|
||||
|
||||
const DEFAULT_Z_START = 10;
|
||||
export const MIN_TIMESTEP = 1 / 120;
|
||||
export const MAX_TIMESTEP = 1 / 20;
|
||||
export const MAX_DYNAMIC_ROTATION = 4;
|
||||
export const MAX_ANGULAR_VELOCITY = 180;
|
||||
export const ANGULAR_DAMPING = 11;
|
||||
export const TORQUE_TO_ACCELERATION = 0.006;
|
||||
export const SETTLE_ANGULAR_VELOCITY = 1.2;
|
||||
export const MAX_DYNAMIC_ROTATION = 7;
|
||||
export const MAX_ANGULAR_VELOCITY = 210;
|
||||
export const ANGULAR_DAMPING = 10;
|
||||
export const TORQUE_TO_ACCELERATION = 0.007;
|
||||
export const SETTLE_ANGULAR_VELOCITY = 0.45;
|
||||
|
||||
const getMassScale = (massGrams?: number): number => {
|
||||
if (!Number.isFinite(massGrams) || Number(massGrams) <= 0) {
|
||||
return 1;
|
||||
}
|
||||
const normalized = Math.max(Number(massGrams), CARD_BASE_WEIGHT_GRAMS) / CARD_BASE_WEIGHT_GRAMS;
|
||||
return Math.max(normalized, 1);
|
||||
};
|
||||
|
||||
export const applyDomTransform = (
|
||||
node: HTMLElement | null,
|
||||
@@ -927,9 +938,11 @@ export class WorkspaceEngine {
|
||||
return true;
|
||||
}
|
||||
|
||||
const massScale = getMassScale(simulationState.massGrams);
|
||||
const torqueAcceleration = torque * TORQUE_TO_ACCELERATION;
|
||||
let angularVelocity = simulationState.angularVelocity + torqueAcceleration * dt;
|
||||
angularVelocity = clamp(angularVelocity, -MAX_ANGULAR_VELOCITY, MAX_ANGULAR_VELOCITY);
|
||||
const maxAngularVelocity = MAX_ANGULAR_VELOCITY / massScale;
|
||||
angularVelocity = clamp(angularVelocity, -maxAngularVelocity, maxAngularVelocity);
|
||||
|
||||
const dampingConstant = Number.isFinite(dampingOverride)
|
||||
? Number(dampingOverride)
|
||||
@@ -938,17 +951,30 @@ export class WorkspaceEngine {
|
||||
angularVelocity *= dampingFactor;
|
||||
|
||||
let dynamicRotation = simulationState.dynamicRotation + angularVelocity * dt;
|
||||
if (dynamicRotation > MAX_DYNAMIC_ROTATION) {
|
||||
dynamicRotation = MAX_DYNAMIC_ROTATION;
|
||||
const dynamicLimit = MAX_DYNAMIC_ROTATION / Math.sqrt(massScale);
|
||||
if (dynamicRotation > dynamicLimit) {
|
||||
dynamicRotation = dynamicLimit;
|
||||
angularVelocity = Math.min(angularVelocity, 0);
|
||||
} else if (dynamicRotation < -MAX_DYNAMIC_ROTATION) {
|
||||
dynamicRotation = -MAX_DYNAMIC_ROTATION;
|
||||
} else if (dynamicRotation < -dynamicLimit) {
|
||||
dynamicRotation = -dynamicLimit;
|
||||
angularVelocity = Math.max(angularVelocity, 0);
|
||||
}
|
||||
|
||||
simulationState.angularVelocity = angularVelocity;
|
||||
simulationState.dynamicRotation = dynamicRotation;
|
||||
simulationState.rotation = simulationState.restRotation + dynamicRotation;
|
||||
const isSettled = Math.abs(angularVelocity) < (SETTLE_ANGULAR_VELOCITY * 0.6)
|
||||
|| Math.abs(dynamicRotation) < (MAX_DYNAMIC_ROTATION * 0.05);
|
||||
|
||||
if (isSettled) {
|
||||
simulationState.angularVelocity = 0;
|
||||
simulationState.dynamicRotation = 0;
|
||||
simulationState.rotation = simulationState.restRotation;
|
||||
} else {
|
||||
simulationState.angularVelocity = angularVelocity;
|
||||
simulationState.dynamicRotation = dynamicRotation;
|
||||
simulationState.rotation = simulationState.restRotation + dynamicRotation;
|
||||
if (Math.sign(simulationState.angularVelocity) !== Math.sign(angularVelocity)) {
|
||||
simulationState.angularVelocity = angularVelocity;
|
||||
}
|
||||
}
|
||||
|
||||
const rotation = simulationState.rotation;
|
||||
const nextEntry = { ...entry, rotation };
|
||||
@@ -966,7 +992,6 @@ export class WorkspaceEngine {
|
||||
nextEntry.z,
|
||||
);
|
||||
|
||||
const isSettled = Math.abs(angularVelocity) < SETTLE_ANGULAR_VELOCITY;
|
||||
return isSettled;
|
||||
}
|
||||
|
||||
@@ -989,6 +1014,9 @@ export class WorkspaceEngine {
|
||||
docId: key,
|
||||
dragScale: baseState.dragScale || 1,
|
||||
lastTimestamp: now,
|
||||
massGrams: Number.isFinite(baseState.massGrams)
|
||||
? Math.max(Number(baseState.massGrams), CARD_BASE_WEIGHT_GRAMS)
|
||||
: CARD_BASE_WEIGHT_GRAMS,
|
||||
};
|
||||
|
||||
const step = (timestamp: number) => {
|
||||
|
||||
Reference in New Issue
Block a user