or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

animation-generators.mdcore-animation.mdeasing.mdindex.mdinertia.mdutilities.md

utilities.mddocs/

0

# Utility Functions

1

2

Mathematical and interpolation utilities for animation calculations, including value mixing, clamping, geometric operations, and type conversion. These functions provide the building blocks for complex animations and interactions.

3

4

## Capabilities

5

6

### Interpolation Functions

7

8

Core interpolation utilities for mapping values between ranges and creating smooth transitions.

9

10

```typescript { .api }

11

/**

12

* Creates a function that maps input range to output range

13

* @param input - Array of input values (must be ascending)

14

* @param output - Array of output values (same length as input)

15

* @param options - Interpolation configuration

16

* @returns Function that interpolates between the ranges

17

*/

18

function interpolate<T>(

19

input: number[],

20

output: T[],

21

options?: InterpolateOptions<T>

22

): (v: number) => T;

23

24

interface InterpolateOptions<T> {

25

/** Whether to clamp output to range bounds (default: true) */

26

clamp?: boolean;

27

/** Easing function(s) to apply to each segment */

28

ease?: Easing | Easing[];

29

/** Custom mixer function for complex types */

30

mixer?: MixerFactory<T>;

31

}

32

33

type MixerFactory<T> = (from: T, to: T) => (v: number) => T;

34

35

/**

36

* Interpolates between two numbers

37

* @param from - Starting value

38

* @param to - Ending value

39

* @param progress - Interpolation progress (0-1)

40

* @returns Interpolated value

41

*/

42

function mix(from: number, to: number, progress: number): number;

43

```

44

45

**Usage Examples:**

46

47

```typescript

48

import { interpolate, mix } from "popmotion";

49

50

// Basic number interpolation

51

const mixNumbers = interpolate([0, 100], [0, 1]);

52

console.log(mixNumbers(50)); // 0.5

53

54

// Color interpolation

55

const mixColors = interpolate(

56

[0, 50, 100],

57

["#ff0000", "#00ff00", "#0000ff"]

58

);

59

console.log(mixColors(25)); // Blended red-green color

60

61

// Complex string interpolation

62

const mixTransforms = interpolate(

63

[0, 100],

64

["translateX(0px) scale(1)", "translateX(100px) scale(1.5)"]

65

);

66

console.log(mixTransforms(50)); // "translateX(50px) scale(1.25)"

67

68

// With custom easing per segment

69

const easedInterpolate = interpolate(

70

[0, 50, 100],

71

[0, 80, 100],

72

{ ease: ["easeOut", "easeIn"] }

73

);

74

75

// Simple number mixing

76

const currentValue = mix(0, 100, 0.75); // 75

77

```

78

79

### Color Mixing Functions

80

81

Specialized functions for interpolating between colors in different color spaces.

82

83

```typescript { .api }

84

/**

85

* Creates a function to interpolate between two colors

86

* @param from - Starting color (hex, rgb, hsl, or color object)

87

* @param to - Ending color (same format as from)

88

* @returns Function that interpolates between colors

89

*/

90

function mixColor(from: Color | string, to: Color | string): (v: number) => string;

91

92

/**

93

* Interpolates between complex strings containing numbers

94

* @param from - Starting string with numerical values

95

* @param to - Ending string with same structure

96

* @returns Function that interpolates the numerical parts

97

*/

98

function mixComplex(from: string, to: string): (v: number) => string;

99

100

type Color = {

101

red: number;

102

green: number;

103

blue: number;

104

alpha?: number;

105

} | {

106

hue: number;

107

saturation: number;

108

lightness: number;

109

alpha?: number;

110

};

111

```

112

113

**Usage Examples:**

114

115

```typescript

116

import { mixColor, mixComplex } from "popmotion";

117

118

// Color mixing

119

const colorMixer = mixColor("#ff0000", "#0000ff");

120

element.style.backgroundColor = colorMixer(0.5); // Purple blend

121

122

// RGB to HSL mixing

123

const rgbToHsl = mixColor("rgb(255, 0, 0)", "hsl(240, 100%, 50%)");

124

125

// Complex string mixing (CSS transforms, etc.)

126

const transformMixer = mixComplex(

127

"translateX(0px) rotate(0deg) scale(1)",

128

"translateX(100px) rotate(180deg) scale(1.5)"

129

);

130

element.style.transform = transformMixer(0.5);

131

132

// Shadow mixing

133

const shadowMixer = mixComplex(

134

"0px 0px 0px rgba(0,0,0,0)",

135

"10px 10px 20px rgba(0,0,0,0.5)"

136

);

137

element.style.boxShadow = shadowMixer(progress);

138

```

139

140

### Mathematical Utilities

141

142

Core mathematical functions for value manipulation and calculations.

143

144

```typescript { .api }

145

/**

146

* Constrains a value between minimum and maximum bounds

147

* @param min - Minimum value

148

* @param max - Maximum value

149

* @param v - Value to constrain

150

* @returns Clamped value

151

*/

152

function clamp(min: number, max: number, v: number): number;

153

154

/**

155

* Wraps a value around a range (circular behavior)

156

* @param min - Minimum value of range

157

* @param max - Maximum value of range

158

* @param v - Value to wrap

159

* @returns Wrapped value

160

*/

161

function wrap(min: number, max: number, v: number): number;

162

163

/**

164

* Calculates progress of a value within a range

165

* @param from - Start of range

166

* @param to - End of range

167

* @param value - Current value

168

* @returns Progress as 0-1 (can exceed bounds)

169

*/

170

function progress(from: number, to: number, value: number): number;

171

172

/**

173

* Creates a function that snaps values to specific points

174

* @param points - Snap points (number for interval, array for specific points)

175

* @returns Function that snaps input to nearest point

176

*/

177

function snap(points: number | number[]): (v: number) => number;

178

```

179

180

**Usage Examples:**

181

182

```typescript

183

import { clamp, wrap, progress, snap } from "popmotion";

184

185

// Clamp values to valid range

186

const opacity = clamp(0, 1, userInput); // Ensures 0-1 range

187

const angle = clamp(-180, 180, rotation);

188

189

// Wrap for circular behavior

190

const wrappedAngle = wrap(0, 360, 450); // Returns 90

191

const scrollPosition = wrap(0, maxScroll, currentScroll);

192

193

// Calculate progress

194

const scrollProgress = progress(0, 1000, scrollY); // 0.5 at 500px

195

const animationProgress = progress(startTime, endTime, currentTime);

196

197

// Snap to grid or specific values

198

const gridSnap = snap(25); // Snaps to multiples of 25

199

const specificSnap = snap([0, 50, 100, 150]); // Snaps to specific values

200

201

console.log(gridSnap(37)); // 25

202

console.log(gridSnap(63)); // 50

203

console.log(specificSnap(75)); // 50

204

```

205

206

### Geometric Utilities

207

208

Functions for geometric calculations including angles, distances, and coordinate transformations.

209

210

```typescript { .api }

211

/**

212

* Calculates angle between two points in degrees

213

* @param a - First point or origin if b not provided

214

* @param b - Second point (optional)

215

* @returns Angle in degrees

216

*/

217

function angle(a: Point, b?: Point): number;

218

219

/**

220

* Calculates distance between two points or values

221

* @param a - First point or number

222

* @param b - Second point or number

223

* @returns Distance between points

224

*/

225

function distance<P extends Point | number>(a: P, b: P): number;

226

227

/**

228

* Converts angle and distance to x,y coordinates

229

* @param angle - Angle in degrees

230

* @param distance - Distance from origin

231

* @returns Point with x,y coordinates

232

*/

233

function pointFromVector(angle: number, distance: number): Point2D;

234

235

type Point2D = {

236

x: number;

237

y: number;

238

};

239

240

type Point3D = Point2D & {

241

z: number;

242

};

243

244

type Point = Point2D | Point3D;

245

```

246

247

**Usage Examples:**

248

249

```typescript

250

import { angle, distance, pointFromVector } from "popmotion";

251

252

// Calculate angle between mouse and element

253

const mouseAngle = angle(

254

{ x: mouseX, y: mouseY },

255

{ x: elementX, y: elementY }

256

);

257

258

// Distance calculations

259

const dist2D = distance({ x: 0, y: 0 }, { x: 3, y: 4 }); // 5

260

const dist1D = distance(10, 50); // 40

261

const dist3D = distance(

262

{ x: 0, y: 0, z: 0 },

263

{ x: 1, y: 1, z: 1 }

264

); // ~1.73

265

266

// Convert polar to cartesian coordinates

267

const point = pointFromVector(45, 100); // { x: 70.7, y: 70.7 }

268

269

// Rotate point around origin

270

const rotatedPoint = pointFromVector(

271

angle({ x: pointX, y: pointY }) + rotationDelta,

272

distance({ x: 0, y: 0 }, { x: pointX, y: pointY })

273

);

274

```

275

276

### Physics and Animation Helpers

277

278

Utilities for physics calculations and animation smoothing.

279

280

```typescript { .api }

281

/**

282

* Converts per-frame velocity to per-second velocity

283

* @param velocity - Velocity per frame

284

* @param frameDuration - Duration of one frame in milliseconds

285

* @returns Velocity per second

286

*/

287

function velocityPerSecond(velocity: number, frameDuration: number): number;

288

289

/**

290

* Creates function to convert per-second velocity to per-frame

291

* @param fps - Frames per second

292

* @returns Function that converts velocity

293

*/

294

function velocityPerFrame(fps: number): (velocity: number) => number;

295

296

/**

297

* Creates smoothing function for reducing jitter

298

* @param strength - Smoothing strength (0-1, higher = more smoothing)

299

* @returns Function that smooths input values

300

*/

301

function smooth(strength?: number): (v: number) => number;

302

303

/**

304

* Single-frame smoothing calculation

305

* @param previousValue - Previous smoothed value

306

* @param targetValue - New target value

307

* @param delta - Time delta in milliseconds

308

* @param strength - Smoothing strength

309

* @returns New smoothed value

310

*/

311

function smoothFrame(

312

previousValue: number,

313

targetValue: number,

314

delta: number,

315

strength: number

316

): number;

317

```

318

319

**Usage Examples:**

320

321

```typescript

322

import { velocityPerSecond, velocityPerFrame, smooth, smoothFrame } from "popmotion";

323

324

// Velocity conversions

325

const frameVel = 5; // pixels per frame

326

const secVel = velocityPerSecond(frameVel, 16.67); // ~300 pixels/second

327

328

const perFrameConverter = velocityPerFrame(60);

329

const frameVelocity = perFrameConverter(300); // 5 pixels/frame

330

331

// Smooth jittery input (like mouse movement)

332

const smoother = smooth(0.1);

333

let smoothedX = 0;

334

335

document.addEventListener('mousemove', (e) => {

336

smoothedX = smoother(e.clientX);

337

element.style.left = smoothedX + 'px';

338

});

339

340

// Manual smoothing with time delta

341

let lastValue = 0;

342

let lastTime = Date.now();

343

344

function updateSmoothed(newValue) {

345

const now = Date.now();

346

const delta = now - lastTime;

347

348

lastValue = smoothFrame(lastValue, newValue, delta, 0.1);

349

lastTime = now;

350

351

return lastValue;

352

}

353

```

354

355

### Type Checking Utilities

356

357

Type guard functions for runtime type checking of geometric objects.

358

359

```typescript { .api }

360

/**

361

* Type guard to check if object is a Point

362

* @param point - Object to check

363

* @returns True if object has x and y properties

364

*/

365

function isPoint(point: unknown): point is Point;

366

367

/**

368

* Type guard to check if Point is 3D

369

* @param point - Point to check

370

* @returns True if point has z property

371

*/

372

function isPoint3D(point: Point): point is Point3D;

373

```

374

375

**Usage Examples:**

376

377

```typescript

378

import { isPoint, isPoint3D } from "popmotion";

379

380

function handleInput(input: unknown) {

381

if (isPoint(input)) {

382

console.log(`2D point: ${input.x}, ${input.y}`);

383

384

if (isPoint3D(input)) {

385

console.log(`3D point: ${input.x}, ${input.y}, ${input.z}`);

386

}

387

}

388

}

389

390

// Safe point operations

391

function safeDistance(a: unknown, b: unknown) {

392

if (isPoint(a) && isPoint(b)) {

393

return distance(a, b);

394

}

395

return 0;

396

}

397

```

398

399

### Conversion Utilities

400

401

Functions for converting between different units and formats.

402

403

```typescript { .api }

404

/**

405

* Converts degrees to radians

406

* @param degrees - Angle in degrees

407

* @returns Angle in radians

408

*/

409

function degreesToRadians(degrees: number): number;

410

411

/**

412

* Converts radians to degrees

413

* @param radians - Angle in radians

414

* @returns Angle in degrees

415

*/

416

function radiansToDegrees(radians: number): number;

417

418

/**

419

* Converts percentage string to decimal

420

* @param num - Percentage as number (e.g., 50 for "50%")

421

* @returns Decimal value (e.g., 0.5)

422

*/

423

function toDecimal(num: number): number;

424

425

/**

426

* Creates function that applies offset transformation

427

* @param from - Starting offset value

428

* @param to - Ending offset value (optional)

429

* @returns Function that applies offset

430

*/

431

function applyOffset(from: number, to?: number): (v: number) => number;

432

```

433

434

**Usage Examples:**

435

436

```typescript

437

import { degreesToRadians, radiansToDegrees, toDecimal, applyOffset } from "popmotion";

438

439

// Angle conversions

440

const radians = degreesToRadians(90); // π/2

441

const degrees = radiansToDegrees(Math.PI); // 180

442

443

// Percentage conversion

444

const decimal = toDecimal(75); // 0.75

445

446

// Offset transformations

447

const offsetter = applyOffset(10, 110); // Maps 0-1 to 10-110

448

const mappedValue = offsetter(0.5); // 60

449

```

450

451

### Attract Functions

452

453

Specialized utilities for creating attraction effects that pull values towards target points with customizable curves.

454

455

```typescript { .api }

456

/**

457

* Creates a customizable attractor function with displacement modification

458

* @param alterDisplacement - Function to modify displacement calculation (default: identity)

459

* @returns Attractor function that applies the modified displacement

460

*/

461

function createAttractor(alterDisplacement?: (displacement: number) => number):

462

(constant: number, origin: number, v: number) => number;

463

464

/**

465

* Linear attractor function that pulls values towards an origin point

466

* @param constant - Attraction strength (0-1, where 0 = no attraction, 1 = full)

467

* @param origin - Target point to attract towards

468

* @param v - Current value being attracted

469

* @returns New attracted value

470

*/

471

function attract(constant: number, origin: number, v: number): number;

472

473

/**

474

* Exponential attractor function with softer attraction curve

475

* @param constant - Attraction strength (0-1)

476

* @param origin - Target point to attract towards

477

* @param v - Current value being attracted

478

* @returns New attracted value with exponential curve

479

*/

480

function attractExpo(constant: number, origin: number, v: number): number;

481

```

482

483

**Usage Examples:**

484

485

```typescript

486

import { attract, attractExpo, createAttractor } from "popmotion";

487

488

// Linear attraction - pulls value towards origin

489

const result1 = attract(0.5, 10, 5); // Returns 7.5 (halfway to origin)

490

const result2 = attract(1.0, 10, 5); // Returns 10 (full attraction)

491

const result3 = attract(0.0, 10, 5); // Returns 5 (no attraction)

492

493

// Exponential attraction - softer curve

494

const softer1 = attractExpo(0.5, 10, 5); // Returns ~8.9 (softer than linear)

495

const softer2 = attractExpo(0.5, 10, 15); // Returns ~11.1

496

497

// Custom attractor with square root displacement

498

const customAttractor = createAttractor(Math.sqrt);

499

const custom = customAttractor(0.5, 10, 5); // Returns ~8.9

500

501

// Use in animations for magnetic effects

502

animate({

503

from: currentValue,

504

to: targetValue,

505

onUpdate: (value) => {

506

const attracted = attract(0.1, magnetPoint, value);

507

element.style.left = attracted + 'px';

508

}

509

});

510

```

511

512

### Functional Utilities

513

514

Higher-order functions for composing and chaining operations.

515

516

```typescript { .api }

517

/**

518

* Composes functions to run left to right

519

* @param transformers - Functions to compose

520

* @returns Single function that applies all transformers in sequence

521

*/

522

function pipe(...transformers: Array<(v: any) => any>): (v: any) => any;

523

```

524

525

**Usage Examples:**

526

527

```typescript

528

import { pipe, clamp, snap, mix } from "popmotion";

529

530

// Compose multiple transformations

531

const processValue = pipe(

532

(v: number) => clamp(0, 100, v), // First clamp to 0-100

533

snap(10), // Then snap to multiples of 10

534

(v: number) => mix(0, 1, v / 100) // Finally convert to 0-1 range

535

);

536

537

const result = processValue(87.3); // Clamps to 87.3, snaps to 90, converts to 0.9

538

539

// Create reusable transformation chains

540

const normalizeAndSmooth = pipe(

541

(v: number) => clamp(-1, 1, v),

542

(v: number) => (v + 1) / 2, // Convert -1,1 to 0,1

543

smooth(0.1)

544

);

545

```