Skip to content

Instantly share code, notes, and snippets.

@pragdave
Created February 20, 2023 18:54
Show Gist options
  • Save pragdave/b07540972910e09b1fc959ab953305a7 to your computer and use it in GitHub Desktop.
Save pragdave/b07540972910e09b1fc959ab953305a7 to your computer and use it in GitHub Desktop.
Looking for feedback on my first Motion Canvas attempt
import {makeScene2D} from '@motion-canvas/2d/lib/scenes';
import {Rect, View2D} from '@motion-canvas/2d/lib/components';
import {createRef, Reference} from '@motion-canvas/core/lib/utils';
import { Color, Vector2 } from '@motion-canvas/core/lib/types';
const PoleLong = 201
const PoleShort = 25
const PoleBase = 150
const DiskCount = 5
const MinDiskWidth = 50
const MaxDiskWidth = PoleLong - 20
const DeltaWidth = (MaxDiskWidth - MinDiskWidth)/(DiskCount - 1)
const DiskHeight = 30
const DiskGap = 4
const BaseDiskColor = new Color("#c3e")
const EndDiskColor = new Color("#baf")
const VMoveTime = 0.5
const HMoveTime = 1
// ╭──────────────────────────────────────────────────────────╮
// │ Each disk │
// ╰──────────────────────────────────────────────────────────╯
class Disk {
me: Reference<Rect>;
constructor(view: View2D, i: number) {
const width = MaxDiskWidth - i*DeltaWidth
const color = BaseDiskColor.lerp(EndDiskColor, i/(DiskCount-1)).name()
this.me = createRef<Rect>()
view.add(<Rect ref={this.me} width={width} height={DiskHeight} fill={color} x={0} y={0} />)
}
position(pos: Vector2) {
this.me().position(pos)
}
*moveUpDownTo(absY: number) {
return yield * this.me().position.y(absY, VMoveTime)
}
*moveAcrossTo(absX: number) {
return yield * this.me().position.x(absX, HMoveTime)
}
static heightOfStack(n: number) {
return (DiskHeight + DiskGap) * n
}
}
// ╭──────────────────────────────────────────────────────────╮
// │ A Pole │
// ╰──────────────────────────────────────────────────────────╯
class Pole {
_base: Vector2
disks: Disk[] = []
constructor(view: View2D, public xpos: number) {
view.add([
<Rect width={PoleLong} height={PoleShort} x={xpos} y={PoleBase+PoleShort/2} fill="brown" />,
<Rect width={PoleShort} height={PoleLong} x={xpos} y={PoleBase-PoleLong/2} fill="green" />,
])
this._base = new Vector2(xpos, PoleBase)
}
push(disk: Disk) {
this.disks.push(disk)
// return the position of the newly pushed disk
return Disk.heightOfStack(this.disks.length) - DiskHeight/2
}
pop() {
return this.disks.pop()
}
pushAndPosition(disk: Disk) {
const offset = this.push(disk)
disk.position(new Vector2([this.xpos, PoleBase - offset]))
}
}
// ╭──────────────────────────────────────────────────────────╮
// │ Animate moving a disk from `from` to `to` │
// ╰──────────────────────────────────────────────────────────╯
function *moveFromTo(from: Pole, to: Pole) {
const disk = from.pop()
yield * disk.moveUpDownTo(-200)
yield * disk.moveAcrossTo(to.xpos)
const pos = to.push(disk)
yield * disk.moveUpDownTo(PoleBase - pos)
}
// ╭──────────────────────────────────────────────────────────╮
// │ Keep dem monks busy │
// ╰──────────────────────────────────────────────────────────╯
function *hanoi(n: number, from: Pole, to: Pole, using: Pole): Generator<any> {
if (n > 0) {
yield * hanoi(n-1, from, using, to)
yield * moveFromTo(from, to)
yield * hanoi(n-1, using, to, from)
}
}
export default makeScene2D(function* (view) {
// drawGrid(view)
const Poles = [
new Pole(view, -300),
new Pole(view, 0),
new Pole(view, +300)
]
for (let i = 0; i < DiskCount; i++) {
const d = new Disk(view, i)
Poles[0].pushAndPosition(d)
}
yield * hanoi(DiskCount, Poles[0], Poles[1], Poles[2])
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment