Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import { Group } from 'konva/lib/Group';
- import { Line } from 'konva/lib/shapes/Line';
- import { Rect } from 'konva/lib/shapes/Rect';
- import { Project } from '@motion-canvas/core/lib';
- import { all, delay, sequence, waitFor } from '@motion-canvas/core/lib/flow';
- import type { Scene } from '@motion-canvas/core/lib/Scene';
- import { ThreadGenerator } from '@motion-canvas/core/lib/threading';
- import {
- easeInBackGenerator,
- linear,
- tween,
- } from '@motion-canvas/core/lib/tweening';
- export default function* example(scene: Scene): ThreadGenerator {
- yield* scene.transition();
- let shadowAngle = Math.PI / 2;
- const tweenShadow = (rect: Rect, shadow: Line) => () => {
- const size = rect.size();
- let corners = [
- { x: 0, y: 0 }, // top left
- { x: size.width, y: 0 }, // top right
- { x: size.width, y: size.height }, // bottom right
- { x: 0, y: size.height }, // bottom left
- ];
- const cornerRadius = rect.cornerRadius() as number;
- const innerCorners = corners.map(({ x, y }) => ({
- x: x === 0 ? cornerRadius : x - cornerRadius,
- y: y === 0 ? cornerRadius : y - cornerRadius,
- }));
- for (let i = 0; i < 4; i++) {
- corners[i] = rect.getAbsoluteTransform().point(corners[i]);
- innerCorners[i] = rect.getAbsoluteTransform().point(innerCorners[i]);
- }
- const getScore = ({ x, y }: { x: number; y: number }, topRight: boolean) =>
- (x * Math.cos(shadowAngle + Math.PI / 2) +
- y * Math.sin(shadowAngle + Math.PI / 2)) *
- (topRight ? -1 : 1);
- const bottomLeft = corners.reduce((acc, cur) =>
- getScore(cur, false) > getScore(acc, false) ? cur : acc,
- );
- const topRight = corners.reduce((acc, cur) =>
- getScore(cur, true) > getScore(acc, true) ? cur : acc,
- );
- const bottomLeftInner = innerCorners[corners.indexOf(bottomLeft)];
- const topRightInner = innerCorners[corners.indexOf(topRight)];
- const getRoundPointPos = (
- innerPoint: { x: number; y: number },
- outerPoint: { x: number; y: number },
- dim: 'x' | 'y',
- ) =>
- innerPoint[dim] +
- Math[dim === 'x' ? 'cos' : 'sin'](shadowAngle + Math.PI / 2) *
- (outerPoint === topRight ? -1 : 1) *
- cornerRadius *
- rect.getAbsoluteScale()[dim];
- const absolutePoints = [
- [
- getRoundPointPos(bottomLeftInner, bottomLeft, 'x'),
- getRoundPointPos(bottomLeftInner, bottomLeft, 'y'),
- ],
- [
- getRoundPointPos(topRightInner, topRight, 'x'),
- getRoundPointPos(topRightInner, topRight, 'y'),
- ],
- ];
- const points = absolutePoints
- .map(([x, y]) =>
- shadow.getAbsoluteTransform().copy().invert().point({ x, y }),
- )
- .map(({ x, y }) => [x, y]);
- shadow.points(
- points
- .concat(
- points
- .map(([x, y]) => [
- x + 2500 * Math.cos(shadowAngle),
- y + 2500 * Math.sin(shadowAngle),
- ])
- .reverse(),
- )
- .flat(),
- );
- };
- const COUNT = 5 ** 2;
- const SIZE = 50;
- const HALF_SIZE = SIZE / 2;
- const rects = [...Array(COUNT)].map(
- (_, i) =>
- new Rect({
- fill: '#fff',
- // fill: 'rgba(255,255,255,0.5)',
- width: SIZE,
- height: SIZE,
- x: (i - COUNT / 2 + 0.5) * SIZE,
- y: -600,
- }),
- );
- const rectShadows = [...Array(COUNT)].map((_, i) => {
- const points = [
- [-HALF_SIZE, HALF_SIZE],
- [HALF_SIZE, -HALF_SIZE],
- ];
- const LENGTH = 700;
- return new Line({
- fill: '#b0752e',
- closed: true,
- points: points.flat().concat(
- points
- .map(([x, y]) => [x + LENGTH, y + LENGTH])
- .reverse()
- .flat(),
- ),
- });
- });
- scene.add(...rectShadows);
- scene.add(...rects);
- yield tween(COUNT / 2.5, (value) => {
- shadowAngle = linear(value, (Math.PI * 1) / 4, (Math.PI * 7) / 4);
- for (let i = 0; i < rects.length; i++) {
- tweenShadow(rects[i], rectShadows[i])();
- }
- });
- const moveFromMiddle = (i: number, time: number) =>
- Math.abs(i - rects.length / 2) * time;
- const moveFromEdges = (i: number, time: number) =>
- Math.min(i, rects.length - i - 1) * time;
- yield* sequence(
- 0.01,
- ...rects.map((rect, i) =>
- all(rect.y(0, 0.75), tween(0.75, tweenShadow(rect, rectShadows[i]))),
- ),
- );
- yield* all(
- ...rects.map((rect, i) => {
- const newX = (i - COUNT / 2 + 0.5) * SIZE * 1.5;
- return delay(
- moveFromEdges(i, 0.05),
- all(
- rect.x(newX, 0.75),
- tween(0.75, tweenShadow(rect, rectShadows[i])),
- rect.cornerRadius(SIZE / 10, 0.75),
- ),
- );
- }),
- );
- const COUNT_SQRT = Math.sqrt(COUNT);
- yield* all(
- ...rects.map((rect, i) => {
- const x = i % COUNT_SQRT;
- const y = Math.floor(i / COUNT_SQRT);
- const newX = (x - COUNT_SQRT / 2 + 0.5) * SIZE * 1.5;
- const newY = (y - COUNT_SQRT / 2 + 0.5) * SIZE * 1.5;
- return delay(
- moveFromMiddle(i, 0.1) - 0.3,
- all(
- rect.position({ x: newX, y: newY }, 1),
- tween(1, tweenShadow(rect, rectShadows[i])),
- ),
- );
- }),
- );
- yield* all(
- ...rects.map((rect, i) =>
- delay(
- 0.01 * i,
- all(
- rect.position({ x: 0, y: 0 }, 1),
- tween(1, tweenShadow(rect, rectShadows[i])),
- ),
- ),
- ),
- );
- rects.slice(1).forEach((rect) => rect.destroy());
- rectShadows.slice(1).forEach((rect) => rect.destroy());
- const rect = rects[0];
- const rectShadow = rectShadows[0];
- const group = new Group();
- group.add(rect);
- scene.add(group);
- const TIME = 0.75;
- yield* all(
- group.position({ x: 200, y: 200 }, TIME),
- group.rotation(45, TIME),
- group.scale({ x: 3, y: 3 }, TIME),
- tween(TIME, tweenShadow(rect, rectShadow)),
- );
- yield* all(
- group.position({ x: -200, y: -100 }, TIME),
- group.rotation(-210, TIME),
- group.scale({ x: 5, y: 5 }, TIME),
- tween(TIME, tweenShadow(rect, rectShadow)),
- );
- yield* all(
- group.position({ x: 0, y: 0 }, TIME),
- group.rotation(-90, TIME),
- group.scale({ x: 2.5, y: 2.5 }, TIME),
- tween(TIME, tweenShadow(rect, rectShadow)),
- );
- yield* all(
- group.scale({ x: 0, y: 0 }, 0.75, easeInBackGenerator(5)),
- tween(TIME, tweenShadow(rect, rectShadow)),
- );
- yield* waitFor(1.0);
- scene.canFinish();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement