or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

animated-components.mdanimation-functions.mdconfiguration-utilities.mdcore-reactive-system.mdcss-integration.mdevent-handling.mdindex.mdinterpolation-easing.mdlayout-animations.mdplatform-functions.mdscreen-transitions.mdtesting-utilities.mdworklet-functions.md

interpolation-easing.mddocs/

0

# Interpolation and Easing

1

2

Mathematical functions for smooth value transitions, custom animation curves, and color interpolation that enable sophisticated animation effects.

3

4

## Capabilities

5

6

### Numeric Interpolation

7

8

Maps values from one range to another using linear interpolation.

9

10

```typescript { .api }

11

/**

12

* Maps a value from an input range to an output range using linear interpolation

13

* @param value - The input value to interpolate

14

* @param inputRange - Array of input values (must be monotonically increasing)

15

* @param outputRange - Array of corresponding output values

16

* @param extrapolate - How to handle values outside the input range

17

* @returns Interpolated output value

18

*/

19

function interpolate(

20

value: number,

21

inputRange: readonly number[],

22

outputRange: readonly number[],

23

extrapolate?: ExtrapolationType

24

): number;

25

26

/**

27

* Clamps a value between minimum and maximum bounds

28

* @param value - Value to clamp

29

* @param min - Minimum allowed value

30

* @param max - Maximum allowed value

31

* @returns Clamped value

32

*/

33

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

34

35

enum Extrapolation {

36

/** Extend the interpolation beyond the ranges */

37

EXTEND = "extend",

38

/** Clamp to the edge values of the ranges */

39

CLAMP = "clamp",

40

/** Return the input value as-is when outside ranges */

41

IDENTITY = "identity"

42

}

43

44

type ExtrapolationType = Extrapolation;

45

46

/** @deprecated Use Extrapolation instead */

47

const Extrapolate = Extrapolation;

48

```

49

50

**Usage Examples:**

51

52

```typescript

53

import React from "react";

54

import Animated, {

55

useSharedValue,

56

useAnimatedStyle,

57

interpolate,

58

Extrapolation,

59

clamp,

60

withTiming,

61

useDerivedValue

62

} from "react-native-reanimated";

63

import { Button } from "react-native";

64

65

const InterpolationExample = () => {

66

const progress = useSharedValue(0);

67

68

// Basic interpolation

69

const animatedStyle = useAnimatedStyle(() => ({

70

opacity: interpolate(progress.value, [0, 1], [0.2, 1]),

71

transform: [

72

{

73

scale: interpolate(progress.value, [0, 0.5, 1], [1, 1.5, 1]),

74

},

75

{

76

rotate: `${interpolate(progress.value, [0, 1], [0, 360])}deg`,

77

},

78

],

79

}));

80

81

// Interpolation with different extrapolation modes

82

const extendedStyle = useAnimatedStyle(() => ({

83

// Extends beyond range

84

translateX: interpolate(

85

progress.value,

86

[0, 1],

87

[0, 100],

88

Extrapolation.EXTEND

89

),

90

// Clamps to range bounds

91

translateY: interpolate(

92

progress.value,

93

[0, 1],

94

[0, 100],

95

Extrapolation.CLAMP

96

),

97

}));

98

99

// Complex multi-point interpolation

100

const complexStyle = useAnimatedStyle(() => ({

101

backgroundColor: progress.value < 0.33 ? "red" :

102

progress.value < 0.66 ? "green" : "blue",

103

borderRadius: interpolate(

104

progress.value,

105

[0, 0.25, 0.5, 0.75, 1],

106

[0, 10, 25, 10, 0]

107

),

108

}));

109

110

// Using clamp utility

111

const clampedValue = useDerivedValue(() =>

112

clamp(progress.value * 150, 50, 100)

113

);

114

115

const clampedStyle = useAnimatedStyle(() => ({

116

width: clampedValue.value,

117

height: clampedValue.value,

118

}));

119

120

const animate = () => {

121

progress.value = withTiming(progress.value === 0 ? 1 : 0, {

122

duration: 2000

123

});

124

};

125

126

return (

127

<>

128

<Button title="Animate" onPress={animate} />

129

130

{/* Basic interpolation */}

131

<Animated.View

132

style={[

133

{ width: 100, height: 100, backgroundColor: "lightblue", margin: 10 },

134

animatedStyle,

135

]}

136

/>

137

138

{/* Extended interpolation */}

139

<Animated.View

140

style={[

141

{ width: 50, height: 50, backgroundColor: "lightgreen", margin: 10 },

142

extendedStyle,

143

]}

144

/>

145

146

{/* Complex interpolation */}

147

<Animated.View

148

style={[

149

{ width: 80, height: 80, margin: 10 },

150

complexStyle,

151

]}

152

/>

153

154

{/* Clamped size */}

155

<Animated.View

156

style={[

157

{ backgroundColor: "lightcoral", margin: 10 },

158

clampedStyle,

159

]}

160

/>

161

</>

162

);

163

};

164

```

165

166

### Color Interpolation

167

168

Interpolates between color values in different color spaces.

169

170

```typescript { .api }

171

/**

172

* Interpolates between color values

173

* @param value - The input value to interpolate

174

* @param inputRange - Array of input values (must be monotonically increasing)

175

* @param outputRange - Array of color strings to interpolate between

176

* @param colorSpace - Color space for interpolation (RGB or HSV)

177

* @param options - Additional interpolation options

178

* @returns Interpolated color string

179

*/

180

function interpolateColor(

181

value: number,

182

inputRange: readonly number[],

183

outputRange: readonly string[],

184

colorSpace?: ColorSpace,

185

options?: InterpolationOptions

186

): string;

187

188

enum ColorSpace {

189

RGB = "rgb",

190

HSV = "hsv"

191

}

192

193

interface InterpolationOptions {

194

/** Gamma correction for RGB interpolation */

195

gamma?: number;

196

/** Whether to use shorter or longer path in HSV */

197

useCorrectedHSVInterpolation?: boolean;

198

}

199

200

/**

201

* Hook for creating reusable color interpolation configurations

202

* @param inputRange - Input range for interpolation

203

* @param outputRange - Output color range

204

* @param colorSpace - Color space to use

205

* @returns Interpolation configuration function

206

*/

207

function useInterpolateConfig(

208

inputRange: readonly number[],

209

outputRange: readonly string[],

210

colorSpace?: ColorSpace

211

): (value: number) => string;

212

```

213

214

**Usage Examples:**

215

216

```typescript

217

import React from "react";

218

import Animated, {

219

useSharedValue,

220

useAnimatedStyle,

221

interpolateColor,

222

ColorSpace,

223

withTiming,

224

useInterpolateConfig,

225

useDerivedValue

226

} from "react-native-reanimated";

227

import { Button } from "react-native";

228

229

const ColorInterpolationExample = () => {

230

const progress = useSharedValue(0);

231

232

// RGB color interpolation

233

const rgbStyle = useAnimatedStyle(() => ({

234

backgroundColor: interpolateColor(

235

progress.value,

236

[0, 0.5, 1],

237

["#FF0000", "#00FF00", "#0000FF"], // Red -> Green -> Blue

238

ColorSpace.RGB

239

),

240

}));

241

242

// HSV color interpolation (smoother transitions)

243

const hsvStyle = useAnimatedStyle(() => ({

244

backgroundColor: interpolateColor(

245

progress.value,

246

[0, 1],

247

["#FF0000", "#0000FF"], // Red -> Blue via HSV

248

ColorSpace.HSV

249

),

250

}));

251

252

// Complex color progression

253

const rainbowStyle = useAnimatedStyle(() => ({

254

backgroundColor: interpolateColor(

255

progress.value,

256

[0, 0.16, 0.33, 0.5, 0.66, 0.83, 1],

257

[

258

"#FF0000", // Red

259

"#FF8000", // Orange

260

"#FFFF00", // Yellow

261

"#00FF00", // Green

262

"#0000FF", // Blue

263

"#8000FF", // Indigo

264

"#FF00FF", // Violet

265

],

266

ColorSpace.HSV

267

),

268

}));

269

270

// Using interpolation config hook

271

const colorConfig = useInterpolateConfig(

272

[0, 0.3, 0.7, 1],

273

["#1a1a1a", "#ff6b6b", "#4ecdc4", "#45b7d1"],

274

ColorSpace.RGB

275

);

276

277

const configStyle = useAnimatedStyle(() => ({

278

backgroundColor: colorConfig(progress.value),

279

}));

280

281

// Color with alpha interpolation

282

const alphaStyle = useAnimatedStyle(() => ({

283

backgroundColor: interpolateColor(

284

progress.value,

285

[0, 1],

286

["rgba(255, 0, 0, 0.2)", "rgba(255, 0, 0, 1.0)"]

287

),

288

}));

289

290

// Border color animation

291

const borderStyle = useAnimatedStyle(() => ({

292

borderColor: interpolateColor(

293

progress.value,

294

[0, 1],

295

["#cccccc", "#ff0000"],

296

ColorSpace.RGB

297

),

298

borderWidth: 3,

299

}));

300

301

const animate = () => {

302

progress.value = withTiming(progress.value === 0 ? 1 : 0, {

303

duration: 3000

304

});

305

};

306

307

return (

308

<>

309

<Button title="Animate Colors" onPress={animate} />

310

311

{/* RGB interpolation */}

312

<Animated.View

313

style={[

314

{ width: 100, height: 50, margin: 5, borderRadius: 5 },

315

rgbStyle,

316

]}

317

/>

318

319

{/* HSV interpolation */}

320

<Animated.View

321

style={[

322

{ width: 100, height: 50, margin: 5, borderRadius: 5 },

323

hsvStyle,

324

]}

325

/>

326

327

{/* Rainbow progression */}

328

<Animated.View

329

style={[

330

{ width: 100, height: 50, margin: 5, borderRadius: 5 },

331

rainbowStyle,

332

]}

333

/>

334

335

{/* Config-based interpolation */}

336

<Animated.View

337

style={[

338

{ width: 100, height: 50, margin: 5, borderRadius: 5 },

339

configStyle,

340

]}

341

/>

342

343

{/* Alpha interpolation */}

344

<Animated.View

345

style={[

346

{ width: 100, height: 50, margin: 5, borderRadius: 5 },

347

alphaStyle,

348

]}

349

/>

350

351

{/* Border color */}

352

<Animated.View

353

style={[

354

{

355

width: 100,

356

height: 50,

357

margin: 5,

358

borderRadius: 5,

359

backgroundColor: "white"

360

},

361

borderStyle,

362

]}

363

/>

364

</>

365

);

366

};

367

```

368

369

### Color Processing Functions

370

371

Utility functions for color validation, conversion, and processing for animations.

372

373

```typescript { .api }

374

/**

375

* Checks if a value is a valid color string or number

376

* @param value - Value to test for color validity

377

* @returns True if value is a valid color

378

*/

379

function isColor(value: unknown): boolean;

380

381

/**

382

* Converts a color value to RGBA array format

383

* @param color - Color value (string, number, or hex)

384

* @returns RGBA array with values from 0-1

385

*/

386

function convertToRGBA(color: unknown): ParsedColorArray;

387

388

/**

389

* Processes color values for platform-specific rendering

390

* @param color - Raw color value to process

391

* @returns Processed color number, null, or undefined

392

*/

393

function processColor(color: unknown): number | null | undefined;

394

395

type ParsedColorArray = [number, number, number, number]; // [r, g, b, a]

396

```

397

398

**Usage Examples:**

399

400

```typescript

401

import { isColor, convertToRGBA, processColor } from "react-native-reanimated";

402

403

// Color validation

404

const validateColors = () => {

405

console.log(isColor("red")); // true

406

console.log(isColor("#FF0000")); // true

407

console.log(isColor("rgb(255,0,0)")); // true

408

console.log(isColor("invalid")); // false

409

console.log(isColor(123)); // false

410

};

411

412

// Color conversion for animations

413

const useColorAnimation = () => {

414

const colorValue = useSharedValue("red");

415

416

const animatedStyle = useAnimatedStyle(() => {

417

// Convert color to RGBA for processing

418

const [r, g, b, a] = convertToRGBA(colorValue.value);

419

420

return {

421

backgroundColor: `rgba(${r * 255}, ${g * 255}, ${b * 255}, ${a})`,

422

};

423

});

424

425

return animatedStyle;

426

};

427

428

// Color processing for platform compatibility

429

const processColors = () => {

430

const colors = ["red", "#FF0000", "rgb(255,0,0)", null, undefined];

431

432

colors.forEach(color => {

433

const processed = processColor(color);

434

console.log(`${color} -> ${processed}`);

435

});

436

};

437

438

// Advanced color interpolation with conversion

439

const ColorTransition = () => {

440

const progress = useSharedValue(0);

441

442

const animatedStyle = useAnimatedStyle(() => {

443

// Convert start and end colors to RGBA

444

const startColor = convertToRGBA("red"); // [1, 0, 0, 1]

445

const endColor = convertToRGBA("blue"); // [0, 0, 1, 1]

446

447

// Manually interpolate each component

448

const r = interpolate(progress.value, [0, 1], [startColor[0], endColor[0]]);

449

const g = interpolate(progress.value, [0, 1], [startColor[1], endColor[1]]);

450

const b = interpolate(progress.value, [0, 1], [startColor[2], endColor[2]]);

451

const a = interpolate(progress.value, [0, 1], [startColor[3], endColor[3]]);

452

453

return {

454

backgroundColor: `rgba(${r * 255}, ${g * 255}, ${b * 255}, ${a})`,

455

};

456

});

457

458

return <Animated.View style={animatedStyle} />;

459

};

460

```

461

462

### Easing Functions

463

464

Predefined and custom easing functions for natural animation curves.

465

466

```typescript { .api }

467

const Easing: {

468

/** Linear easing function (f(t) = t) */

469

linear: EasingFunction;

470

/** Default ease function with gentle acceleration and deceleration */

471

ease: EasingFunction;

472

/** Quadratic easing (f(t) = t²) */

473

quad: EasingFunction;

474

/** Cubic easing (f(t) = t³) */

475

cubic: EasingFunction;

476

/** Polynomial easing with custom exponent */

477

poly(n: number): EasingFunction;

478

/** Sinusoidal easing */

479

sin: EasingFunction;

480

/** Circular easing */

481

circle: EasingFunction;

482

/** Exponential easing */

483

exp: EasingFunction;

484

/** Elastic spring easing with bounce effect */

485

elastic(bounciness?: number): EasingFunction;

486

/** Back easing with overshoot effect */

487

back(s?: number): EasingFunction;

488

/** Bouncing easing with multiple bounces */

489

bounce: EasingFunction;

490

/** Cubic bezier curve easing */

491

bezier(x1: number, y1: number, x2: number, y2: number): EasingFunction;

492

493

/** Apply easing in forward direction */

494

in(easing: EasingFunction): EasingFunction;

495

/** Apply easing in reverse direction */

496

out(easing: EasingFunction): EasingFunction;

497

/** Apply easing in both directions (symmetric) */

498

inOut(easing: EasingFunction): EasingFunction;

499

};

500

501

type EasingFunction = (value: number) => number;

502

503

interface EasingFunctionFactory {

504

factory(): EasingFunction;

505

}

506

```

507

508

**Usage Examples:**

509

510

```typescript

511

import React from "react";

512

import Animated, {

513

useSharedValue,

514

useAnimatedStyle,

515

withTiming,

516

Easing

517

} from "react-native-reanimated";

518

import { Button } from "react-native";

519

520

const EasingExample = () => {

521

const progress1 = useSharedValue(0);

522

const progress2 = useSharedValue(0);

523

const progress3 = useSharedValue(0);

524

const progress4 = useSharedValue(0);

525

526

// Linear easing

527

const linearStyle = useAnimatedStyle(() => ({

528

transform: [{ translateX: progress1.value * 200 }],

529

}));

530

531

// Ease out quadratic

532

const easeOutStyle = useAnimatedStyle(() => ({

533

transform: [{ translateX: progress2.value * 200 }],

534

}));

535

536

// Bounce easing

537

const bounceStyle = useAnimatedStyle(() => ({

538

transform: [{ translateX: progress3.value * 200 }],

539

}));

540

541

// Custom bezier easing

542

const bezierStyle = useAnimatedStyle(() => ({

543

transform: [{ translateX: progress4.value * 200 }],

544

}));

545

546

const animateLinear = () => {

547

progress1.value = withTiming(progress1.value === 0 ? 1 : 0, {

548

duration: 1000,

549

easing: Easing.linear,

550

});

551

};

552

553

const animateEaseOut = () => {

554

progress2.value = withTiming(progress2.value === 0 ? 1 : 0, {

555

duration: 1000,

556

easing: Easing.out(Easing.quad),

557

});

558

};

559

560

const animateBounce = () => {

561

progress3.value = withTiming(progress3.value === 0 ? 1 : 0, {

562

duration: 1500,

563

easing: Easing.bounce,

564

});

565

};

566

567

const animateBezier = () => {

568

progress4.value = withTiming(progress4.value === 0 ? 1 : 0, {

569

duration: 1000,

570

easing: Easing.bezier(0.25, 0.1, 0.25, 1), // CSS ease

571

});

572

};

573

574

return (

575

<>

576

<Button title="Linear" onPress={animateLinear} />

577

<Animated.View

578

style={[

579

{ width: 50, height: 50, backgroundColor: "red", margin: 5 },

580

linearStyle,

581

]}

582

/>

583

584

<Button title="Ease Out Quad" onPress={animateEaseOut} />

585

<Animated.View

586

style={[

587

{ width: 50, height: 50, backgroundColor: "green", margin: 5 },

588

easeOutStyle,

589

]}

590

/>

591

592

<Button title="Bounce" onPress={animateBounce} />

593

<Animated.View

594

style={[

595

{ width: 50, height: 50, backgroundColor: "blue", margin: 5 },

596

bounceStyle,

597

]}

598

/>

599

600

<Button title="Bezier" onPress={animateBezier} />

601

<Animated.View

602

style={[

603

{ width: 50, height: 50, backgroundColor: "purple", margin: 5 },

604

bezierStyle,

605

]}

606

/>

607

</>

608

);

609

};

610

```

611

612

### Advanced Easing Patterns

613

614

Complex easing combinations and custom curves.

615

616

**Custom Easing Functions:**

617

618

```typescript

619

import { Easing } from "react-native-reanimated";

620

621

// Create custom easing functions

622

const customEasings = {

623

// Elastic with custom bounciness

624

elasticOut: Easing.out(Easing.elastic(2)),

625

626

// Back with overshoot

627

backInOut: Easing.inOut(Easing.back(1.7)),

628

629

// Custom polynomial

630

fastSlowFast: Easing.inOut(Easing.poly(3)),

631

632

// Complex bezier curves

633

cssEase: Easing.bezier(0.25, 0.1, 0.25, 1),

634

cssEaseIn: Easing.bezier(0.42, 0, 1, 1),

635

cssEaseOut: Easing.bezier(0, 0, 0.58, 1),

636

cssEaseInOut: Easing.bezier(0.42, 0, 0.58, 1),

637

638

// Material Design curves

639

materialStandard: Easing.bezier(0.4, 0.0, 0.2, 1),

640

materialDecelerate: Easing.bezier(0.0, 0.0, 0.2, 1),

641

materialAccelerate: Easing.bezier(0.4, 0.0, 1, 1),

642

643

// Custom stepped function

644

stepped: (steps: number) => (t: number) => Math.floor(t * steps) / steps,

645

};

646

```

647

648

### Interpolation Configuration

649

650

Advanced interpolation patterns and utilities.

651

652

```typescript { .api }

653

interface InterpolateConfig {

654

inputRange: readonly number[];

655

outputRange: readonly (string | number)[];

656

extrapolate?: ExtrapolationType;

657

extrapolateLeft?: ExtrapolationType;

658

extrapolateRight?: ExtrapolationType;

659

}

660

661

interface InterpolateHSV {

662

h: number;

663

s: number;

664

v: number;

665

}

666

667

interface InterpolateRGB {

668

r: number;

669

g: number;

670

b: number;

671

}

672

```

673

674

**Advanced Interpolation Example:**

675

676

```typescript

677

import React from "react";

678

import Animated, {

679

useSharedValue,

680

useAnimatedStyle,

681

interpolate,

682

Extrapolation,

683

withTiming

684

} from "react-native-reanimated";

685

686

const AdvancedInterpolationExample = () => {

687

const scrollY = useSharedValue(0);

688

689

// Complex header transformation

690

const headerStyle = useAnimatedStyle(() => {

691

const headerHeight = 200;

692

const minHeight = 80;

693

694

return {

695

height: interpolate(

696

scrollY.value,

697

[0, headerHeight - minHeight],

698

[headerHeight, minHeight],

699

Extrapolation.CLAMP

700

),

701

opacity: interpolate(

702

scrollY.value,

703

[0, headerHeight / 2, headerHeight],

704

[1, 0.8, 0.3],

705

Extrapolation.CLAMP

706

),

707

transform: [

708

{

709

scale: interpolate(

710

scrollY.value,

711

[0, headerHeight],

712

[1, 0.9],

713

Extrapolation.CLAMP

714

),

715

},

716

],

717

};

718

});

719

720

// Parallax background

721

const backgroundStyle = useAnimatedStyle(() => ({

722

transform: [

723

{

724

translateY: interpolate(

725

scrollY.value,

726

[0, 300],

727

[0, -100],

728

Extrapolation.EXTEND // Allow over-scroll effect

729

),

730

},

731

{

732

scale: interpolate(

733

scrollY.value,

734

[-100, 0, 300],

735

[1.2, 1, 0.8],

736

{

737

extrapolateLeft: Extrapolation.CLAMP,

738

extrapolateRight: Extrapolation.EXTEND,

739

}

740

),

741

},

742

],

743

}));

744

745

return (

746

<>

747

<Animated.View style={[{ position: "absolute", top: 0 }, backgroundStyle]}>

748

{/* Background content */}

749

</Animated.View>

750

751

<Animated.View style={headerStyle}>

752

{/* Header content */}

753

</Animated.View>

754

755

<Animated.ScrollView

756

onScroll={(event) => {

757

scrollY.value = event.nativeEvent.contentOffset.y;

758

}}

759

scrollEventThrottle={16}

760

>

761

{/* Scroll content */}

762

</Animated.ScrollView>

763

</>

764

);

765

};

766

```

767

768

## Type Definitions

769

770

```typescript { .api }

771

type ExtrapolationType = Extrapolation | {

772

extrapolateLeft?: Extrapolation;

773

extrapolateRight?: Extrapolation;

774

};

775

776

interface ExtrapolationConfig {

777

extrapolateLeft?: ExtrapolationType;

778

extrapolateRight?: ExtrapolationType;

779

}

780

781

type ParsedColorArray = readonly [number, number, number, number]; // RGBA

782

783

interface InterpolationOptions {

784

gamma?: number;

785

useCorrectedHSVInterpolation?: boolean;

786

}

787

```