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 🙏

© 2025 – Pkg Stats / Ryan Hefner

xcanvas-ts

v0.9.16

Published

XCanvas is a powerful and flexible TypeScript library for manipulating HTML5 canvases, making every aspect of canvas manipulation extendable and reusable.

Readme

XCanvas brings the full power of the HTML5 canvas API to your projects, making every aspect of canvas manipulation extendable and reusable. Unlike traditional approaches, XCanvas treats each canvas property and method as a modular component. This design enables developers to easily extend functionality, customize behaviors, and integrate seamlessly with other systems.

Why XCanvas

The "X" in XCanvas stands for "Extendable", highlighting its adaptability and extensibility.

Key Advantages:

  • Extensibility: Every canvas feature is accessible as an extendable component.
  • Modularity: Build complex graphics by composing simple, reusable modules.
  • Flexibility: Easily adapt and extend core functionalities to meet your project's needs.
  • Performance: Optimized for high performance and efficiency, leveraging modern JavaScript and TypeScript practices.

With XCanvas, you are not just using the canvas API—you are exploiting a powerful, extendable toolkit for all your graphic needs.

Stack-Based Rendering

One of the key concepts in XCanvas is the Render Stack. Drawing an element involves "stacking" geometries, fills, and/or strokes. You stack the elements in the order you want them to be applied to the context.

Renderable Types

  • PathRenderable: Elements like SolidFill, GradientFill, GradientStroke, PatternFill, PatternStroke, and BitmapFill.
  • TextRenderable: Elements like SolidTextFill, SolidTextStroke, GradientTextFill, GradientTextStroke, PatternTextFill, and PatternTextStroke.
  • RenderStackable: Elements that contain a render stack, including PathRenderable, TextRenderable, Path, TextPath, and Shape.

Nested Render Stacks

A RenderStack can contain other RenderStacks, allowing for complex and layered compositions. This modular approach makes it easy to manage and manipulate the rendering process, providing flexibility and control over the final output.

export type PathRenderable = SolidFill | GradientFill | GradientStroke | PatternFill | PatternStroke | BitmapFill;
export type TextRenderable = SolidTextFill | SolidTextStroke | GradientTextFill | GradientTextStroke | PatternTextFill | PatternTextStroke;
export type RenderStackable = PathRenderable | TextRenderable | Path | TextPath | Shape;

This stack-based approach enables precise control over the rendering order and the application of styles, making XCanvas a powerful tool for creating complex graphics.

Installation

npm install xcanvas-ts

Usage

Start creating amazing graphics with XCanvas:

//Example : 

const stage = new Stage2D(window.innerWidth, window.innerHeight);
    //Stage2D represent the canvas. It's the top-level abstraction in XCanvas. 

    const contener = new Group2D();
    //a Group2D is a Display2D that can contains multiple Display2D 

    contener.x = 300;
    contener.y = 0;
    contener.rotation = 25
    stage.appendChild(contener);

    const solidColor = new SolidColor(0xcc0000);
    const gradient = new GradientColor([solidColor, new SolidColor(0xff0000)], null, true);

    const image = new Img("assets/mire.jpg");
    const video = new Video(1920 * 0.5, 1080 * 0.5, "assets/video.webm")
    const gradientStroke = new GradientStroke(gradient);

    const treeLineStyle: LineStyle = new LineStyle(15)
    const alphaBd = new Img("assets/alpha.png");
    alphaBd.addEventListener(BitmapData.IMAGE_LOADED, function () {

        //we convert a png with alpha background showing a tree into a Path2D   
        const bitmapPath = new BitmapPath(alphaBd);

        //we create a Display2D containing the renderStack  
        const tree = new Display2D(400, 500);
        tree.x = -200

        const isLinearGradient: boolean = false;
        const treeGradient = new GradientColor([new SolidColor(0x0000ff), solidColor, new SolidColor(0xff0000)], null, isLinearGradient);

        //we stack some RenderStackable items in it 
        tree.stack(bitmapPath);
        tree.stack(new SolidStroke(solidColor, treeLineStyle));
        tree.stack(new GradientStroke(treeGradient, isLinearGradient, treeLineStyle))
        tree.stack(new PatternFill(video));
        contener.appendChild(tree);
    })


    const textStyle = new TextStyle("Arial", 100, "px");
    textStyle.lineStyle = new LineStyle(3);
    const solidTextStroke = new SolidTextStroke(textStyle, solidColor);

    const glowFilter = new GlowFilter(25, "#ff0000");
    const filters = new FilterStack().add(glowFilter);

    const fill = new PatternFill(image, true, false);
    fill.filters = filters;


    const circleLinestyle = gradientStroke.lineStyle = new LineStyle();
    circleLinestyle.lineWidth = 10;
    circleLinestyle.dashLineDist = 30;
    circleLinestyle.dashHoleDist = 30;
    circleLinestyle.cap = "round";
    circleLinestyle.join = "round"

    const rectangle = new RenderStack();
    rectangle.push(SquarePath.instance);
    rectangle.push(new SolidFill(solidColor));

    const shape = new Shape(50, 450, 50, 100, rectangle);
    //a shape is a cheap Display2D. Shape doesn't extends Matrix2D 
    //and only contains the properties "x","y","width","height" and "renderStack".
    //a renderStack can contains multiple paths/fill/stroke and even multiple sub-renderStack

    const compositeObject = new Display2D(400, 400);
    compositeObject.stack(CirclePath.instance);
    compositeObject.stack(fill);
    compositeObject.stack(gradientStroke);
    const textElement: RenderStackElement = compositeObject.stack(new TextPath("Hello Canvas !"));
    compositeObject.stack(solidTextStroke);
    compositeObject.stack(shape);
    compositeObject.align(Align.CENTER);
    compositeObject.x = 200;
    compositeObject.y = 200;
    compositeObject.rotation = 50;
    contener.appendChild(compositeObject);


    compositeObject.addEventListener(Display2D.MOUSE_OVER, function (e) {
        e.alpha = 0.5;

    })
    compositeObject.addEventListener(Display2D.MOUSE_OUT, function (e) {
        e.alpha = 1
    })


    document.body.onclick = function () {
        //in order to inprove performance, you can store the result of a renderPass in a bitmapCache
        //(if you do it, the property cannot be updated anymore )
        //(you must set "cacheAsBitmap" to false if you want to update the stack)
        compositeObject.cacheAsBitmap = !compositeObject.cacheAsBitmap;

    }

    let a = 0
    const text = "Hello Canvas !";
    function animate() {
        a += 0.01;
        const pct = Math.sin(a * 2.5);

        //we animate the text
        (textElement as any).value.text = "Hello Canvas ! ".slice(0, Math.round(text.length * Math.abs(pct)));

        //we animate the stroke of the tree
        treeLineStyle.lineWidth = Math.abs(Math.cos(a)) * 15;

        //we update "solidColor" 
        //it will update every object that use "solidColor" in its renderStack
        solidColor.g = 127 + Math.abs(pct * 100);
        solidColor.b = 255 - Math.abs(pct * 255);

        //we update the radius of the glowFilter
        glowFilter.radius = 25 + 50 * Math.sin(pct * Math.PI * 0.2);

        //we update the dash configuration of the linestyle used with the circle path
        circleLinestyle.dashLineDist = 25 + pct * 15;
        circleLinestyle.dashHoleDist = 20 + (1 - pct) * 5;

        //we move our compositeObject along the x-axis
        compositeObject.x = 400 + Math.sin(a) * 150

        //we rotate the gradient used in the stroke
        gradientStroke.rotation += 0.01;

        //we rotate the picture used in the fill
        fill.rotation -= 0.0025;
        //we scale the picture used in the fill
        fill.scaleX = fill.scaleY = 1 + Math.abs(Math.sin(a) * .5);
        //we translate the picture used in the fill
        fill.x = Math.sin(a * Math.PI) * 100;

        //we draw everything on the stage
        stage.drawElements();

        requestAnimationFrame(animate);
    }

    animate()

You can show the result HERE

Look at index.ts to see every classes available as component

It's possible to save a renderStack as text file when everything is build (it can be usefull if you want to build an editor at the top of what you build)

you can add this code at the end of the example :

setTimeout(() => {
    ObjectLibrary.instance.save();
    //it will generate and download a text file containing all the infos required to rebuild everything
}, 3000)

if you want to load the file and display its content, you can do it like that :

import { ObjectLibrary } from "./utils/ObjectLibrary";
import * as classes from "./index";
ObjectLibrary.classes = classes;

var stage;
ObjectLibrary.instance.load("test.txt", function () {
    ObjectLibrary.print()
    //ObjectLibrary.printElements("RenderStackElement")
    stage = ObjectLibrary.instance.getElementsByName("Stage2D")[0];
    stage.setStage(stage);
    animate()
})

function animate() {
    stage.drawElements();
    requestAnimationFrame(animate);
}

Contributing

Contributions are welcome! Please submit pull requests and report issues on GitHub.

License

This project is licensed under the MIT License. See the LICENSE file for details.