Skip to content

Commit

Permalink
pi digits anim
Browse files Browse the repository at this point in the history
  • Loading branch information
Matt Henderson committed Oct 27, 2023
1 parent ea17535 commit fa12d7f
Show file tree
Hide file tree
Showing 5 changed files with 285 additions and 12 deletions.
18 changes: 9 additions & 9 deletions src/animations/ballspin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ const Ballspin = () => {
angle: 0,
angularVelocity: 0.0,
};
const ballSpin = Matter.Bodies.circle(ballInitParams.x, ballInitParams.y, 20, {
const ball1 = Matter.Bodies.circle(ballInitParams.x, ballInitParams.y, 20, {
restitution: 0.99,
collisionFilter: { mask: 2, category: 1 },
});
const ballNoSpin = Matter.Bodies.circle(ballInitParams.x, ballInitParams.y, 20, {
const ball2 = Matter.Bodies.circle(ballInitParams.x, ballInitParams.y, 20, {
restitution: 0.99,
collisionFilter: { mask: 2, category: 1 },
});
Expand All @@ -52,7 +52,7 @@ const Ballspin = () => {
),
);

Matter.World.add(engine.world, [ballSpin, ballNoSpin, ...groundPieces]);
Matter.World.add(engine.world, [ball1, ball2, ...groundPieces]);
let lastT = 0.0;

const ballGraphics = (ball: Matter.Body) => [
Expand Down Expand Up @@ -84,8 +84,8 @@ const Ballspin = () => {

const drawFn: DrawFn = ({ t, ground }: DrawArgs) => {
if (t == 0.0) {
initBall(ballSpin, 0);
initBall(ballNoSpin, 0.1);
initBall(ball1, 0);
initBall(ball2, 0.1);
trace1 = [];
trace2 = [];
}
Expand All @@ -96,8 +96,8 @@ const Ballspin = () => {
for (let i = 0; i < 12; i++) {
Matter.Engine.update(engine, deltaT2);
if (i % 4 == 0) {
trace1.push([ballNoSpin.position.x, ballNoSpin.position.y]);
trace2.push([ballSpin.position.x, ballSpin.position.y]);
trace1.push([ball2.position.x, ball2.position.y]);
trace2.push([ball1.position.x, ball1.position.y]);
}
}
}
Expand All @@ -111,8 +111,8 @@ const Ballspin = () => {
Graphics.AbsoluteLineWidth(4),
[Graphics.Set({ strokeStyle: '#985e00ff' }), Graphics.Line({ pts: trace1 })],
[Graphics.Set({ strokeStyle: '#5290a5ff' }), Graphics.Line({ pts: trace2 })],
[Graphics.Set({ fillStyle: '#7dddfca0', strokeStyle: bgColor }), ballGraphics(ballSpin)],
[Graphics.Set({ fillStyle: '#ff9d00b5', strokeStyle: bgColor }), ballGraphics(ballNoSpin)],
[Graphics.Set({ fillStyle: '#7dddfca0', strokeStyle: bgColor }), ballGraphics(ball1)],
[Graphics.Set({ fillStyle: '#ff9d00b5', strokeStyle: bgColor }), ballGraphics(ball2)],
// ground
Graphics.Set({ fillStyle: '#ff000062', strokeStyle: '#ffffffff', lineWidth: 6 }),
Graphics.Disk({ center: [plotRange / 2, plotRange / 2], radius, fill: false, edge: true }),
Expand Down
247 changes: 247 additions & 0 deletions src/animations/piArcs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
import chroma from 'chroma-js';

import { Animation, DrawArgs, DrawFn, MakeDrawFn, Parameter } from 'lib/Animation';
import Graphics from 'lib/graphics';
import Utils from 'lib/utils';

const PiArcs = () => {
const duration = 56;
const canvasWidth = 1024;
const canvasHeight = 1024;
const bgColor = '#020115';

const tt = (t: number) =>
0.25 * t +
0.25 * Utils.smoothstepI(t, 2, 3) +
Utils.smoothstepI(t, 10, 15) +
1.5 * Utils.smoothstepI(t, 15, 20) +
10 * Utils.smoothstepI(t, 20, 40) -
13 * Utils.smoothstepI(t, duration - 3.5, duration - 0.5);

const parameters: Parameter[] = [
{
name: 'arc',
minValue: 0,
maxValue: 1,
step: 0.01,
compute: (t) => Utils.smoothstep(Utils.frac(tt(t)), 0, 0.5),
},
{
name: 'next',
minValue: 0,
maxValue: 1,
step: 0.01,
compute: (t) => Utils.smoothstep(Utils.frac(tt(t)), 0.5, 1.0),
},
{ name: 'index', minValue: 0, maxValue: Utils.piDigits.length - 1, step: 1, compute: (t) => Math.floor(tt(t)) },

{
name: 'zoom',
minValue: 1,
maxValue: 100,
step: 0.01,
compute: (t) => 2.4 + 8 * Utils.smoothstep(tt(t), 1, 14) + tt(t) * 0.1,
},

{ name: 'centreX', minValue: -20, maxValue: 20, compute: (t) => 0.7 + 4 * Utils.smoothstep(tt(t), 1, 14) },
{
name: 'centreY',
minValue: -20,
maxValue: 20,
compute: (t) => -0.8 + 7 * Utils.smoothstep(tt(t), 1, 14) + 0.015 * Utils.smoothstepI(tt(t), 14, 30),
},
];
const pyByFive = Math.PI / 5;

const makeDrawFn: MakeDrawFn = (canvas) => {
const ctx = canvas.getContext('2d')!;

const drawFn: DrawFn = ({ t, arc, next, index, zoom, centreX, centreY }: DrawArgs) => {
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
ctx.fillStyle = bgColor;
ctx.fillRect(0, 0, canvasWidth, canvasHeight);

const digit = Number(Utils.piDigits[index]);
const even = index % 2 == 0;
const angle = pyByFive * (digit > 0 ? digit : 10);
let oddOpacity = 0.0;
let evenOpacity = 0.0;
oddOpacity = Math.max(0, 1.0 - 2 * next);
evenOpacity = Math.max(0, Math.min(1, -1 + 2 * next));
if (!even) {
[oddOpacity, evenOpacity] = [evenOpacity, oddOpacity];
}

let arcStyles = [Graphics.Set({ strokeStyle: '#ff36e8af', lineWidth: 0.07 })];
let transformsAndPreviousArcs: Graphics.DrawCommand[] = [];
for (let i = 0; i < index; i++) {
const digitI = Number(Utils.piDigits[i]);
const angleI = pyByFive * (digitI > 0 ? digitI : 9.999);
transformsAndPreviousArcs.push(
Graphics.Disk({
center: [0, 0],
radius: 1,
fill: false,
edge: true,
startAngle: i % 2 == 0 ? -0.5 * Math.PI : -0.5 * Math.PI - angleI,
endAngle: i % 2 == 0 ? -0.5 * Math.PI + angleI : -0.5 * Math.PI,
sector: false,
}),
);
if (i % 2 == 0) {
transformsAndPreviousArcs.push(
Graphics.Translate({ offset: [2 * Math.sin(angleI), 2 * Math.cos(angleI)] }),
);
transformsAndPreviousArcs.push(Graphics.Rotate({ center: [0, 0], angle: angleI - Math.PI }));
} else {
transformsAndPreviousArcs.push(
Graphics.Translate({ offset: [2 * Math.sin(-angleI), 2 * Math.cos(-angleI)] }),
);
transformsAndPreviousArcs.push(Graphics.Rotate({ center: [0, 0], angle: Math.PI - angleI }));
}
}

let piStrings = ['3.'];
for (let i = 1; i <= index; i++) {
piStrings[piStrings.length - 1] += Utils.piDigits[i];
if (i % 54 == 0) {
piStrings.push(' ');
}
}

Graphics.draw(
[
Graphics.Set({
font: '28px Courier',
fillStyle: '#a3a3ae',
textAlign: 'left',
textBaseline: 'top',
}),
piStrings.map((str, i) => Graphics.Text({ at: [24, 230 - i * 28], text: str })),
],
{ xmin: 0, ymin: 0, xmax: canvasWidth, ymax: canvasHeight },
ctx,
);

Graphics.draw(
[
[
// Move it using translates and rotates.
...arcStyles,
...transformsAndPreviousArcs,
Graphics.Set({ lineWidth: 0.02 }),

[
// Filled in arc
Graphics.Set({
fillStyle: chroma('#178585')
.alpha(1 - next)
.css(),
}),
Graphics.Disk({
center: [0, 0],
radius: 1,
fill: true,
edge: false,
startAngle: even ? -0.5 * Math.PI : -0.5 * Math.PI - angle * arc,
endAngle: even ? -0.5 * Math.PI + angle * arc : -0.5 * Math.PI,
}),
],
[
// The 'clock'
even
? Graphics.Translate({
offset: [next * 2 * Math.sin(angle), next * 2 * Math.cos(angle)],
})
: Graphics.Translate({
offset: [next * 2 * Math.sin(-angle), next * 2 * Math.cos(-angle)],
}),
even
? Graphics.Rotate({
center: [0, 0],
angle: next > 0.5 ? angle - Math.PI : 0,
})
: Graphics.Rotate({
center: [0, 0],
angle: next > 0.5 ? Math.PI - angle : 0,
}),
Graphics.Set({
strokeStyle: 'white',
fillStyle: 'white',
font: '0.2px serif',
textAlign: 'center',
textBaseline: 'middle',
}),

Utils.range(-0.5 * Math.PI, 1.5 * Math.PI, pyByFive).map((th, i) => [
Graphics.Disk({
center: [0, 0],
radius: 1,
fill: false,
edge: true,
startAngle: th,
endAngle: th + pyByFive,
}),
[
[
Graphics.Set({
fillStyle: chroma('white').alpha(oddOpacity).css(),
}),
Graphics.Text({
at: [0.7 * Math.cos(th + pyByFive / 2), -0.7 * Math.sin(th + pyByFive / 2)],
text: `${(i + 1) % 10}`,
}),
],
[
Graphics.Set({
fillStyle: chroma('white').alpha(evenOpacity).css(),
}),
Graphics.Text({
at: [0.7 * Math.cos(th + pyByFive / 2), -0.7 * Math.sin(th + pyByFive / 2)],
text: `${(10 - i) % 10}`,
}),
],
],
]),
],
[
// New arc
...arcStyles,
Graphics.Disk({
center: [0, 0],
radius: 1,
fill: false,
edge: true,
startAngle: even ? -0.5 * Math.PI : -0.5 * Math.PI - angle * arc,
endAngle: even ? -0.5 * Math.PI + angle * arc : -0.5 * Math.PI,
sector: false,
}),
],
],
],
{
xmin: centreX - zoom,
xmax: centreX + zoom,
ymin: centreY - zoom,
ymax: centreY + zoom,
},
ctx,
);
};

return drawFn;
};

return (
<Animation
duration={duration}
canvasWidth={canvasWidth}
canvasHeight={canvasHeight}
makeDrawFn={makeDrawFn}
parameters={parameters}
enableTimeControl={true}
/>
);
};

export default PiArcs;
5 changes: 5 additions & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Ballspin from 'animations/ballspin';
import PiArcs from 'animations/piArcs';
import React, { ReactNode } from 'react';
import ReactDOM from 'react-dom/client';
import { FaArrowLeft } from 'react-icons/fa';
Expand All @@ -17,6 +18,10 @@ const animations = [
name: 'ballspin',
component: Ballspin,
},
{
name: 'piArcs',
component: PiArcs,
},
];

const AnimationList = () => {
Expand Down
17 changes: 16 additions & 1 deletion src/lib/graphics.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
namespace Graphics {
type DrawCommand = (ctx: CanvasRenderingContext2D) => void;
export type DrawCommand = (ctx: CanvasRenderingContext2D) => void;

type CanvasState = {
strokeStyle: string;
Expand Down Expand Up @@ -49,13 +49,15 @@ namespace Graphics {
edge,
startAngle = 0,
endAngle = 2 * Math.PI,
sector = true,
}: {
center: number[];
radius: number;
fill: boolean;
edge: boolean;
startAngle?: number;
endAngle?: number;
sector?: boolean;
}): DrawCommand => {
return (ctx) => {
if (!fill && !edge) {
Expand All @@ -66,7 +68,13 @@ namespace Graphics {
ctx.fillStyle = 'rgba(0, 0, 0, 0)';
}
ctx.beginPath();
if (sector) {
ctx.moveTo(center[0], center[1]);
}
ctx.arc(center[0], -center[1], radius, startAngle, endAngle);
if (sector) {
ctx.moveTo(center[0], center[1]);
}
ctx.fill();
if (edge) {
ctx.stroke();
Expand Down Expand Up @@ -110,6 +118,13 @@ namespace Graphics {
};
};

export const Text = ({ at, text }: { at: number[]; text: string }): DrawCommand => {
return (ctx) => {
const [x, y] = at;
ctx.fillText(text, x, -y);
};
};

export const Rotate = ({ angle, center }: { angle: number; center: number[] }): DrawCommand => {
// Rotate clockwise by angle radians around center.
return (ctx) => {
Expand Down
10 changes: 8 additions & 2 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { start } from 'repl';

namespace Utils {
export const range = (start: number, end: number, step: number = 1) => {
const result: number[] = [];
Expand Down Expand Up @@ -63,6 +61,14 @@ namespace Utils {
(2 * Math.pow(startT - endT, 5))
);
};

export const frac = (t: number): number => {
// Fractional part of t.
return t - Math.floor(t);
};

export const piDigits =
'3141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420198938095257201065485863278865936153381827968230301952035301852968995773622599413891249721775283479131515574857242454150695950829533116861727855889075098381754637464939319255060400927701671139009848824012858361603563707660104710181942955596198946767837449448255379774726847104047534646208046684259069491293313677028989152104752162056966024058038150193511253382430035587640247496473263914199272604269922796782354781636009341721641219924586315030286182974555706749838505494588586926995690927210797509302955321165344987202755960236480665499119881834797753566369807426542527862551818417574672890977772793800081647060016145249192173217214772350141441973568548161361157352552133475741849468438523323907394143334547762416862518983569485562099219222184272550254256887671790494601653466804988627232791786085784383827967976681454100953883786360950680064225125205117392984896084128488626945604241965285022210661186306744278622039194945047123713786960956364371917287467764657573962413890865832645995813390478027590099465764078951269468398352595709825822620522489407726719478268482601476990902640136394437455305068203496252451749399651431429809190659250937221696461515709858387410597885959772975498930161753928468138268683868942774155991855925245953959431049972524680845987273644695848653836736222626099124608051243884390451244136549762780797715691435997700129616089441694868555848406353422072225828488648158456028506016842739452267467678895252138522549954666727823986456596116354886230577456498035593634568174324112515076069479451096596094025228879710893145669136867228748940560101503308617928680920874760917824938589009714909675985261365549781893129784821682998948722658804857564014270477555132379641451523746234364542858444795265867821051141354735739523113427166102135969536231442952484937187110145765403590279934403742007310578539062198387447808478489683321445713868751943506430218453191048481005370614680674919278191197939952061419663428754440643745123718192179998391015919561814675142691239748940907186494231961567945208095146550225231603881930142093762137855956638937787083039069792077346722182562599661501421503068038447734549202605414665925201497442850732518666002132434088190710486331734649651453905796268561005508106658796998163574736384052571459102897064140110971206280439039759515677157700420337869936007230558763176359421873125147120532928191826186125867321579198414848829164470609575270695722091756711672291098169091528017350671274858322287183520935396572512108357915136988209144421006751033467110314126711136990865851639831501970165151168517143765761835155650884909989859982387345528331635507647918535893226185489632132933089857064204675259070915481416549859461637180270981994309924488957571282890592323326097299712084433573265489382391193259746366730583604142813883032038249037589852437441702913276561809377344403070746921120191302033038019762110110044929321516084244485963766983895228684783123552658213144957685726243344189303968642624341077322697802807318';
}

export default Utils;

0 comments on commit fa12d7f

Please sign in to comment.