npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

tw-engine-498tokio

v0.1.33

Published

web game animation example

Downloads

38

Readme

tw-engine-498tokio

license: MIT version

implementation of a keyframe animation for web game.

about

  • keyframe animation with audio sync
  • use typescript for web
  • this implementation can be used anywhere (not dependent on the game engine)

build

preview All animations in this project are rendered in CSS (do not use WebGL) reference: 498 Tokio

usage

for install,

npm i tw-engine-498tokio

first, you need requestAnimationFrame based player

import { IAnimationInstance } from "tw-engine-498tokio";

//simple animation player that use requestAnimationFrame
class AnimationPlayer {
    public frameRate = 60;
    private _startTime = 0;
    private _time = 0;
    private _animationInstance: IAnimationInstance;

    public constructor(animationInstance: IAnimationInstance) {
        this._animationInstance = animationInstance;
    }

    public start() {
        this._time = performance.now();
        this._currentTime = 0;
        this.animate();
    }

    private animate = () => {
        const now = performance.now();
        const delta = now - this._time;
        this._time = now;
        this._currentTime += delta;
        const frameTime = this._currentTime * this.frameRate;
        this._animationInstance.process(frameTime);
        
        if (track1.endFrame < frameTime) {
            requestAnimationFrame(this.animate);
        }
    }
}

Animation Track

AnimationTrack is the smallest unit of container that can store animation. You can create an animation with the code below and bind it to the object you want.

//define track that has scalar key
export const track1 = AnimationTrack.createScalarTrack([
    AnimationKey.createValueType(0, 0, InterpolationKind.Linear), //frame 0, value 0
    AnimationKey.createValueType(60, 1, InterpolationKind.Linear)  //frame 60, value 1
])

const div = document.getElementById("animated-div")!;

//create animation instance with bind info
const divAnimInstance = track1.createInstance(value => div.style.opacity = value.toString());

new AnimationPlayer(divAnimInstance).start();

Animation Clip

AnimationClip is an animation container that contains several animation tracks. It's perfect for creating a little bit of a complicated animation.

//animation clip can contain multiple tracks
const clip1 = new AnimationClip([
    {
        name: "track1" as const,
        // you can create AnimationTrack to use constructor, in this case, AnimationTrack need interpolator
        track: new AnimationTrack<number>([
            AnimationKey.createValueType(0, 0, InterpolationKind.Linear), //frame 0, value 0
            AnimationKey.createValueType(60, 1, InterpolationKind.Linear)  //frame 60, value 1
        ], ScalarInterpolator)
    },
    {
        name: "track2" as const,
        // this track use cubic hermite interpolation
        track: AnimationTrack.createScalarTrack([
            AnimationKey.createValueType(0, 0, InterpolationKind.Cubic, 0, 0), //frame 0, value 0
            AnimationKey.createValueType(60, 1, InterpolationKind.Cubic, 0, 0)  //frame 120, value 1
        ])
    }
])

const div1 = document.getElementById("animated-div1")!;
const div2 = document.getElementById("animated-div2")!;

const divAnimInstance = clip1.createInstance(new AnimationClipBindInfo([
    {
        trackName: "track1" as const,
        target: (value: number) => div1.style.opacity = value.toString()
    },
    {
        trackName: "track2" as const,
        target: (value: number) => div2.style.opacity = value.toString()
    }
]));

new AnimationPlayer(divAnimInstance).start();

Animation Sequence

AnimationSequence can contain animation tracks, animation clips, and themselves recursively. This container is optimized for use with very long animations over 3 minutes.

//animation sequence can contain multiple animation clips, tracks and even them self
const sequence1 = new AnimationSequence([
    new RangedAnimation(track1),
    new RangedAnimation(clip1, 20, 1, 50), // RangedAnimation that offset 20, start frame 1, end frame 50
    new RangedAnimation(AnimationTrack.createVector2Track([
        //Vector2 is class so you must create key by createRefType
        AnimationKey.createRefType(0, new Vector2(0, 0), InterpolationKind.Linear), //frame 0, value 0, 0
        AnimationKey.createRefType(60, new Vector2(1, 1), InterpolationKind.Linear)  //frame 60, value 1, 1
    ]))
]);

const div1 = document.getElementById("animated-div1")!;
const div2 = document.getElementById("animated-div2")!;

const divAnimInstance = sequence1.createInstance([
    (value: number) => div1.style.opacity = value.toString(),
    new AnimationClipBindInfo([
        {
            trackName: "track1" as const,
            target: (value: number) => div2.style.opacity = value.toString()
        },
        {
            trackName: "track2" as const,
            target: (value: number) => div2.style.opacity = value.toString()
        }
    ]),
    (value: Vector2) => {
        div1.style.left = value.x.toString();
        div1.style.top = value.y.toString();
    }
]);

new AnimationPlayer(divAnimInstance).start();

Credits