or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

animations.mdcolors.mdcomponents.mdcoordinates.mdindex.mdmath.mdmatrices.mdpaths.mdtransforms.mdtransitions.mdutilities.mdvectors.md

transforms.mddocs/

0

# Transform Utilities

1

2

Transform utilities for applying transformations with custom origins and creating animated styles with translation effects.

3

4

```typescript

5

import type { TransformsStyle } from "react-native";

6

```

7

8

## Capabilities

9

10

### Transform Types

11

12

```typescript { .api }

13

/**

14

* React Native transform array type

15

*/

16

type RNTransform = Exclude<TransformsStyle["transform"], undefined>;

17

```

18

19

### Transform Origin

20

21

Apply transformations around a custom pivot point instead of the default center.

22

23

```typescript { .api }

24

/**

25

* Apply transformations with custom origin point

26

* @param origin - Origin point for transformations

27

* @param transformations - Array of React Native transform objects

28

* @returns Transform array with origin translations

29

*/

30

function transformOrigin(

31

origin: Vector,

32

transformations: RNTransform

33

): RNTransform;

34

35

/**

36

* Apply 2D transformations with custom origin point

37

* @param origin - Origin point for transformations

38

* @param transformations - Array of 2D transform objects

39

* @returns Transform array with origin translations

40

*/

41

function transformOrigin2d(

42

origin: Vector,

43

transformations: Transforms2d

44

): Transforms2d;

45

```

46

47

**Usage Example:**

48

49

```typescript

50

import { transformOrigin, vec2 } from "react-native-redash";

51

import { useAnimatedStyle, useSharedValue } from "react-native-reanimated";

52

53

export const CustomOriginRotation = () => {

54

const rotation = useSharedValue(0);

55

56

const animatedStyle = useAnimatedStyle(() => {

57

// Rotate around top-left corner instead of center

58

const topLeft = vec2(0, 0);

59

60

const transform = transformOrigin(topLeft, [

61

{ rotate: `${rotation.value}deg` },

62

{ scale: 1.2 }

63

]);

64

65

return { transform };

66

});

67

68

return (

69

<Animated.View

70

style={[

71

{ width: 100, height: 100, backgroundColor: 'blue' },

72

animatedStyle

73

]}

74

/>

75

);

76

};

77

```

78

79

### Translation Hook

80

81

Convenient hook for creating translation-based animated styles.

82

83

```typescript { .api }

84

/**

85

* Hook for translation animations using vector of SharedValues

86

* @param vector - Vector with SharedValue components for x and y translation

87

* @returns Animated style object with translation transform

88

*/

89

function useTranslation(vector: Vector<Animated.SharedValue<number>>): {

90

transform: { translateX: number; translateY: number }[];

91

};

92

```

93

94

**Usage Example:**

95

96

```typescript

97

import { useTranslation, useVector } from "react-native-redash";

98

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

99

import { PanGestureHandler } from "react-native-gesture-handler";

100

101

export const DraggableElement = () => {

102

const position = useVector(0, 0);

103

const offset = useVector(0, 0);

104

105

// Use the translation hook for convenient styling

106

const translationStyle = useTranslation(position);

107

108

const gestureHandler = useAnimatedGestureHandler({

109

onStart: () => {

110

offset.x.value = position.x.value;

111

offset.y.value = position.y.value;

112

},

113

onActive: (event) => {

114

position.x.value = offset.x.value + event.translationX;

115

position.y.value = offset.y.value + event.translationY;

116

}

117

});

118

119

return (

120

<PanGestureHandler onGestureEvent={gestureHandler}>

121

<Animated.View

122

style={[

123

{ width: 100, height: 100, backgroundColor: 'red' },

124

translationStyle

125

]}

126

/>

127

</PanGestureHandler>

128

);

129

};

130

```

131

132

### Advanced Transform Origin Examples

133

134

```typescript

135

import { transformOrigin, transformOrigin2d, vec2 } from "react-native-redash";

136

import { useAnimatedStyle, useSharedValue } from "react-native-reanimated";

137

138

export const AdvancedTransforms = () => {

139

const rotation = useSharedValue(0);

140

const scale = useSharedValue(1);

141

142

// Rotate around bottom-right corner

143

const bottomRightRotation = useAnimatedStyle(() => {

144

const bottomRight = vec2(100, 100); // Assuming 100x100 element

145

146

return {

147

transform: transformOrigin(bottomRight, [

148

{ rotate: `${rotation.value}deg` }

149

])

150

};

151

});

152

153

// Scale from top-center

154

const topCenterScale = useAnimatedStyle(() => {

155

const topCenter = vec2(50, 0); // Center horizontally, top vertically

156

157

return {

158

transform: transformOrigin(topCenter, [

159

{ scale: scale.value }

160

])

161

};

162

});

163

164

// Combined transformations with custom origin

165

const combinedTransform = useAnimatedStyle(() => {

166

const customOrigin = vec2(75, 25); // 3/4 right, 1/4 down

167

168

return {

169

transform: transformOrigin(customOrigin, [

170

{ rotate: `${rotation.value}deg` },

171

{ scale: scale.value },

172

{ skewX: `${rotation.value * 0.1}deg` }

173

])

174

};

175

});

176

177

// Using 2D transform types

178

const matrix2dTransform = useAnimatedStyle(() => {

179

const origin = vec2(50, 50);

180

181

const transforms = transformOrigin2d(origin, [

182

{ rotateZ: `${rotation.value}deg` },

183

{ scaleX: scale.value },

184

{ scaleY: scale.value * 0.8 }

185

]);

186

187

return { transform: transforms };

188

});

189

190

return (

191

<View style={{ padding: 20 }}>

192

<Animated.View style={[styles.box, bottomRightRotation]} />

193

<Animated.View style={[styles.box, topCenterScale]} />

194

<Animated.View style={[styles.box, combinedTransform]} />

195

<Animated.View style={[styles.box, matrix2dTransform]} />

196

</View>

197

);

198

};

199

```

200

201

### Interactive Transform Origin

202

203

```typescript

204

import React from "react";

205

import { View, StyleSheet } from "react-native";

206

import { transformOrigin, useVector, vec2 } from "react-native-redash";

207

import {

208

useAnimatedGestureHandler,

209

useAnimatedStyle,

210

useSharedValue

211

} from "react-native-reanimated";

212

import { PanGestureHandler, RotationGestureHandler } from "react-native-gesture-handler";

213

214

export const InteractiveTransformOrigin = () => {

215

const rotation = useSharedValue(0);

216

const originPosition = useVector(50, 50); // Center of 100x100 element

217

const elementPosition = useVector(100, 100);

218

219

// Drag to change transform origin

220

const originGestureHandler = useAnimatedGestureHandler({

221

onActive: (event) => {

222

originPosition.x.value = event.x;

223

originPosition.y.value = event.y;

224

}

225

});

226

227

// Rotate the element

228

const rotationGestureHandler = useAnimatedGestureHandler({

229

onActive: (event) => {

230

rotation.value = event.rotation;

231

}

232

});

233

234

// Element style with custom origin

235

const elementStyle = useAnimatedStyle(() => {

236

const origin = vec2(originPosition.x.value, originPosition.y.value);

237

238

return {

239

transform: transformOrigin(origin, [

240

{ rotate: `${rotation.value}rad` }

241

])

242

};

243

});

244

245

// Origin indicator style

246

const originStyle = useAnimatedStyle(() => ({

247

transform: [

248

{ translateX: originPosition.x.value - 5 },

249

{ translateY: originPosition.y.value - 5 }

250

]

251

}));

252

253

return (

254

<View style={styles.container}>

255

{/* Transform origin indicator */}

256

<PanGestureHandler onGestureEvent={originGestureHandler}>

257

<Animated.View style={[styles.origin, originStyle]} />

258

</PanGestureHandler>

259

260

{/* Rotatable element */}

261

<RotationGestureHandler onGestureEvent={rotationGestureHandler}>

262

<Animated.View style={[styles.element, elementStyle]} />

263

</RotationGestureHandler>

264

</View>

265

);

266

};

267

268

const styles = StyleSheet.create({

269

container: {

270

flex: 1,

271

backgroundColor: '#f0f0f0'

272

},

273

element: {

274

position: 'absolute',

275

left: 100,

276

top: 100,

277

width: 100,

278

height: 100,

279

backgroundColor: 'blue',

280

borderRadius: 10

281

},

282

origin: {

283

position: 'absolute',

284

width: 10,

285

height: 10,

286

borderRadius: 5,

287

backgroundColor: 'red',

288

borderWidth: 1,

289

borderColor: 'white'

290

}

291

});

292

```

293

294

### Practical Use Cases

295

296

```typescript

297

import { transformOrigin, vec2 } from "react-native-redash";

298

299

// 1. Clock hands rotating from center-bottom

300

const clockHandStyle = useAnimatedStyle(() => {

301

const handOrigin = vec2(2, 100); // 2px from left (hand width/2), 100px from top (hand length)

302

303

return {

304

transform: transformOrigin(handOrigin, [

305

{ rotate: `${hourAngle.value}deg` }

306

])

307

};

308

});

309

310

// 2. Card flipping from left edge

311

const cardFlipStyle = useAnimatedStyle(() => {

312

const leftEdge = vec2(0, cardHeight / 2);

313

314

return {

315

transform: transformOrigin(leftEdge, [

316

{ rotateY: `${flipAngle.value}deg` }

317

])

318

};

319

});

320

321

// 3. Door opening from hinges

322

const doorStyle = useAnimatedStyle(() => {

323

const hingePoint = vec2(0, doorHeight / 2);

324

325

return {

326

transform: transformOrigin(hingePoint, [

327

{ rotateZ: `${doorAngle.value}deg` }

328

])

329

};

330

});

331

332

// 4. Scaling from bottom (like growing plants)

333

const growthStyle = useAnimatedStyle(() => {

334

const bottomCenter = vec2(elementWidth / 2, elementHeight);

335

336

return {

337

transform: transformOrigin(bottomCenter, [

338

{ scaleY: growthScale.value }

339

])

340

};

341

});

342

```

343

344

**Important Notes:**

345

346

- Transform origin calculations are done by adding translation transforms before and after the main transforms

347

- The pattern is: translate to origin → apply transforms → translate back

348

- Works with both React Native transforms and custom 2D transform types

349

- `useTranslation` is a convenience hook that's equivalent to manually creating translation transforms

350

- All transform origins are relative to the element's coordinate system (0,0 = top-left)