-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat. Headspace Animation Play Button
- Loading branch information
Showing
15 changed files
with
692 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import type { SkiaValue } from "@shopify/react-native-skia"; | ||
import { | ||
Easing, | ||
mix, | ||
vec, | ||
Path, | ||
Skia, | ||
Fill, | ||
useComputedValue, | ||
} from "@shopify/react-native-skia"; | ||
import React from "react"; | ||
import { Dimensions } from "react-native"; | ||
|
||
const { width, height } = Dimensions.get("window"); | ||
const c = vec(width / 2, height / 2); | ||
|
||
const c1 = "#2ab8aa"; | ||
const c2 = "#3a9dbb"; | ||
const c3 = "#2a7fb8"; | ||
const easing = Easing.bezier(0.37, 0, 0.63, 1); | ||
const getProgress = (t: number, durationInFrames = 4000) => { | ||
const p = (t % durationInFrames) / durationInFrames; | ||
const currentIteration = Math.floor(t / durationInFrames); | ||
const isGoingBack = currentIteration % 2 === 0; | ||
const progress = isGoingBack ? 1 - p : p; | ||
return progress; | ||
}; | ||
|
||
const getCurve = (start: number, h: number) => { | ||
const path = Skia.Path.Make(); | ||
path.moveTo(0, start); | ||
path.quadTo(width / 2, start - h, width, start); | ||
path.lineTo(width, height); | ||
path.lineTo(0, height); | ||
path.close(); | ||
return path; | ||
}; | ||
|
||
interface BackgroundProps { | ||
clock: SkiaValue<number>; | ||
} | ||
|
||
export const Background = ({ clock }: BackgroundProps) => { | ||
// getCurve(200, 50); | ||
const p1 = useComputedValue(() => { | ||
const progress = getProgress(clock.current, 4100); | ||
return getCurve( | ||
mix(easing(progress), c.y - 300, 200), | ||
mix(easing(progress), 50, 60) | ||
); | ||
}, [clock]); | ||
const p2 = useComputedValue(() => { | ||
const progress = getProgress(clock.current); | ||
return getCurve( | ||
mix(easing(progress), c.y - 150, c.y), | ||
mix(easing(progress), 40, 60) | ||
); | ||
}, [clock]); | ||
const p3 = useComputedValue(() => { | ||
const progress = getProgress(clock.current, 3800); | ||
return getCurve( | ||
mix(easing(progress), c.y + 75, c.y + 225), | ||
mix(easing(progress), 30, 50) | ||
); | ||
}, [clock]); | ||
return ( | ||
<> | ||
<Fill color="#60d1b9" /> | ||
<Path path={p1} color={c1} /> | ||
<Path path={p2} color={c2} /> | ||
<Path path={p3} color={c3} /> | ||
</> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
/* eslint-disable prettier/prettier */ | ||
import { | ||
Path, | ||
Skia, | ||
useClockValue, | ||
useComputedValue, | ||
Canvas, | ||
vec, | ||
useTouchHandler, | ||
useTiming, | ||
useValueEffect, | ||
useValue, | ||
runTiming, | ||
Easing, | ||
} from "@shopify/react-native-skia"; | ||
import React, { useEffect, useState } from "react"; | ||
import { Dimensions } from "react-native"; | ||
import { createNoise2D } from "simplex-noise"; | ||
import { SafeAreaInsetsContext } from "react-native-safe-area-context"; | ||
import alea from "alea"; | ||
|
||
import { Play } from "./Play"; | ||
import { Background } from "./Background"; | ||
import { Overlay } from "./Overlay"; | ||
import { useContextBridge } from "./useContextBridge"; | ||
|
||
const C = 0.55228474983079; | ||
const { width, height } = Dimensions.get("window"); | ||
const c = vec(width / 2, height / 2); | ||
const r = 60; | ||
const n1 = createNoise2D(); | ||
const n2 = createNoise2D(); | ||
const n3 = createNoise2D(); | ||
const n4 = createNoise2D(); | ||
|
||
export const Headspace = () => { | ||
const clock = useClockValue(); | ||
|
||
const progress = useValue(0); | ||
const ContextBridge = useContextBridge(SafeAreaInsetsContext); | ||
const [toggled, setToggled] = useState(false); | ||
|
||
const onTouch = useTouchHandler({ | ||
onEnd: () => { | ||
setToggled((toggle) => !toggle); | ||
}, | ||
}); | ||
|
||
useEffect(() => { | ||
runTiming(progress, { to: toggled ? 1 : 0 }, { duration: 450, easing: Easing.inOut(Easing.ease) }); | ||
|
||
if (toggled) { | ||
clock.start(); | ||
} else { | ||
clock.stop(); | ||
} | ||
}, [clock, progress, toggled]); | ||
|
||
const path = useComputedValue(() => { | ||
const A = r * 0.2; | ||
const F = 0.0003; | ||
const d1 = A * n1(clock.current * F, 0); | ||
const d2 = A * n2(clock.current * F, 0); | ||
const d3 = A * n3(clock.current * F, 0); | ||
const d4 = A * n4(clock.current * F, 0); | ||
const p = Skia.Path.Make(); | ||
p.moveTo(c.x, c.y - r); | ||
p.cubicTo(c.x + r * C + d1, c.y - r, c.x + r, c.y - r * C - d1, c.x + r, c.y); | ||
p.cubicTo(c.x + r, c.y + r * C + d2, c.x + r * C + d2, c.y + r, c.x, c.y + r); | ||
p.cubicTo(c.x - r * C - d3, c.y + r, c.x - r, c.y + r * C + d3, c.x - r, c.y); | ||
p.cubicTo(c.x - r, c.y - r * C - d4, c.x - r * C - d4, c.y - r, c.x, c.y - r); | ||
|
||
const m = Skia.Matrix(); | ||
m.translate(c.x, c.y); | ||
m.rotate(clock.current * F); | ||
m.translate(-c.x, -c.y); | ||
p.transform(m); | ||
return p; | ||
}, [clock]); | ||
|
||
return ( | ||
<Canvas style={{ flex: 1 }} onTouch={onTouch}> | ||
<ContextBridge> | ||
<Background clock={clock} /> | ||
<Path path={path} color='#3B3A3A' /> | ||
<Play c={c} r={r} progress={progress} /> | ||
<Overlay /> | ||
</ContextBridge> | ||
</Canvas> | ||
); | ||
}; |
Oops, something went wrong.