• Jump To … +
    ./demo/canvas-001.js ./demo/canvas-002.js ./demo/canvas-003.js ./demo/canvas-004.js ./demo/canvas-005.js ./demo/canvas-006.js ./demo/canvas-007.js ./demo/canvas-008.js ./demo/canvas-009.js ./demo/canvas-010.js ./demo/canvas-011.js ./demo/canvas-012.js ./demo/canvas-013.js ./demo/canvas-014.js ./demo/canvas-015.js ./demo/canvas-016.js ./demo/canvas-017.js ./demo/canvas-018.js ./demo/canvas-019.js ./demo/canvas-020.js ./demo/canvas-021.js ./demo/canvas-022.js ./demo/canvas-023.js ./demo/canvas-024.js ./demo/canvas-025.js ./demo/canvas-026.js ./demo/canvas-027.js ./demo/canvas-028.js ./demo/canvas-029.js ./demo/canvas-030.js ./demo/canvas-031.js ./demo/canvas-032.js ./demo/canvas-033.js ./demo/canvas-034.js ./demo/canvas-035.js ./demo/canvas-036.js ./demo/canvas-037.js ./demo/canvas-038.js ./demo/canvas-039.js ./demo/canvas-040.js ./demo/canvas-041.js ./demo/canvas-042.js ./demo/canvas-043.js ./demo/canvas-044.js ./demo/canvas-045.js ./demo/canvas-046.js ./demo/canvas-047.js ./demo/canvas-048.js ./demo/canvas-049.js ./demo/canvas-050.js ./demo/canvas-051.js ./demo/canvas-052.js ./demo/canvas-053.js ./demo/canvas-054.js ./demo/canvas-055.js ./demo/canvas-056.js ./demo/canvas-057.js ./demo/canvas-058.js ./demo/canvas-059.js ./demo/canvas-060.js ./demo/canvas-061.js ./demo/canvas-062.js ./demo/canvas-063.js ./demo/canvas-064.js ./demo/canvas-065.js ./demo/canvas-066.js ./demo/canvas-067.js ./demo/canvas-068.js ./demo/canvas-069.js ./demo/canvas-070.js ./demo/canvas-071.js ./demo/canvas-072.js ./demo/canvas-073.js ./demo/canvas-074.js ./demo/canvas-201.js ./demo/canvas-202.js ./demo/canvas-203.js ./demo/canvas-204.js ./demo/canvas-205.js ./demo/canvas-206.js ./demo/canvas-207.js ./demo/canvas-208.js ./demo/canvas-209.js ./demo/canvas-210.js ./demo/delaunator-001.js ./demo/delaunator-002.js ./demo/dom-001.js ./demo/dom-002.js ./demo/dom-003.js ./demo/dom-004.js ./demo/dom-005.js ./demo/dom-006.js ./demo/dom-007.js ./demo/dom-008.js ./demo/dom-009.js ./demo/dom-010.js ./demo/dom-011.js ./demo/dom-012.js ./demo/dom-013.js ./demo/dom-015.js ./demo/dom-016.js ./demo/dom-017.js ./demo/dom-018.js ./demo/dom-019.js ./demo/dom-020.js ./demo/dom-021.js ./demo/filters-001.js ./demo/filters-002.js ./demo/filters-003.js ./demo/filters-004.js ./demo/filters-005.js ./demo/filters-006.js ./demo/filters-007.js ./demo/filters-008.js ./demo/filters-009.js ./demo/filters-010.js ./demo/filters-011.js ./demo/filters-012.js ./demo/filters-013.js ./demo/filters-014.js ./demo/filters-015.js ./demo/filters-016.js ./demo/filters-017.js ./demo/filters-018.js ./demo/filters-019.js ./demo/filters-020.js ./demo/filters-021.js ./demo/filters-022.js ./demo/filters-023.js ./demo/filters-024.js ./demo/filters-025.js ./demo/filters-026.js ./demo/filters-027.js ./demo/filters-028.js ./demo/filters-029.js ./demo/filters-030.js ./demo/filters-031.js ./demo/filters-032.js ./demo/filters-033.js ./demo/filters-034.js ./demo/filters-035.js ./demo/filters-036.js ./demo/filters-037.js ./demo/filters-038.js ./demo/filters-039.js ./demo/filters-040.js ./demo/filters-041.js ./demo/filters-101.js ./demo/filters-102.js ./demo/filters-103.js ./demo/filters-104.js ./demo/filters-105.js ./demo/filters-501.js ./demo/filters-502.js ./demo/filters-503.js ./demo/filters-504.js ./demo/filters-505.js ./demo/mediapipe-001.js ./demo/mediapipe-002.js ./demo/mediapipe-003.js ./demo/modules-001.js ./demo/modules-002.js ./demo/modules-003.js ./demo/modules-004.js ./demo/modules-005.js ./demo/modules-006.js ./demo/packets-001.js ./demo/packets-002.js ./demo/particles-001.js ./demo/particles-002.js ./demo/particles-003.js ./demo/particles-004.js ./demo/particles-005.js ./demo/particles-006.js ./demo/particles-007.js ./demo/particles-008.js ./demo/particles-009.js ./demo/particles-010.js ./demo/particles-011.js ./demo/particles-012.js ./demo/particles-013.js ./demo/particles-014.js ./demo/particles-015.js ./demo/particles-016.js ./demo/particles-017.js ./demo/snippets-001.js ./demo/snippets-002.js ./demo/snippets-003.js ./demo/snippets-004.js ./demo/snippets-005.js ./demo/snippets-006.js ./demo/temp-001.js ./demo/temp-shape-scale-investigation.js ./demo/tensorflow-001.js ./demo/tensorflow-002.js ./demo/utilities.js
  • §

    Demo Filters 028

    Stencil (background) filter functionality

  • §

    Run code

    import * as scrawl from '../source/scrawl.js';
    
    import { reportSpeed, addImageDragAndDrop } from './utilities.js';
  • §

    Scene setup

    Get a handle to the Canvas wrapper

    const canvas = scrawl.findCanvas('mycanvas');
  • §

    Namespacing boilerplate

    const namespace = canvas.name;
    const name = (n) => `${namespace}-${n}`;
  • §

    Import the initial image used by the Picture entity

    scrawl.importDomImage('.flowers');
  • §

    Define filters

    Displace filter

    scrawl.makeNoiseAsset({
    
        name: name('my-noise-generator'),
        width: 400,
        height: 400,
        scale: 60,
    
        sumFunction: 'modular',
        sumAmplitude: 4,
    
        noiseEngine: 'worley-manhattan',
    });
  • §

    TODO: this is required to make the noise asset work … but there must be a better way?

    scrawl.makePicture({
        name: name('temp-1'),
        asset: name('my-noise-generator'),
        dimensions: [100, 100],
        copyDimensions: ['100%', '100%'],
        method: 'none',
    });
    
    scrawl.makeFilter({
        name: name('displace'),
        actions: [
            {
                action: 'process-image',
                asset: name('my-noise-generator'),
                width: 400,
                height: 400,
                copyWidth: 400,
                copyHeight: 400,
                lineOut: 'noise-map',
            },
            {
                action: 'displace',
                lineMix: 'noise-map',
                scaleX: 3,
                scaleY: 3,
                transparentEdges: true,
            }
        ],
    });
  • §

    Blue filter

    scrawl.makeFilter({
    
        name: name('blue'),
        method: 'blue',
    });
  • §

    Emboss filter

    scrawl.makeFilter({
    
        name: name('emboss'),
        method: 'emboss',
        angle: 225,
        strength: 10,
        tolerance: 50,
    });
  • §

    Threshhold filter

    scrawl.makeFilter({
        name: name('threshold'),
        method: 'threshold',
        level: 127,
        lowRed: 100,
        lowGreen: 0,
        lowBlue: 0,
        highRed: 220,
        highGreen: 60,
        highBlue: 60,
    });
  • §

    Swirl filter

    scrawl.makeFilter({
        name: name('swirl'),
        method: 'swirl',
        startX: '50%',
        startY: '50%',
        innerRadius: 0,
        outerRadius: '50%',
        angle: 240,
        easing: 'easeOutSine',
    });
  • §

    Pixellate filter

    scrawl.makeFilter({
        name: name('pixelate'),
        method: 'pixelate',
        tileWidth: 20,
        tileHeight: 20,
        offsetX: 8,
        offsetY: 8,
    });
  • §

    Gaussian Blur filter

    scrawl.makeFilter({
        name: name('gaussianBlur'),
        method: 'gaussianBlur',
        radius: 4,
    });
  • §

    ChannelLevels filter

    scrawl.makeFilter({
        name: name('channelLevels'),
        method: 'channelLevels',
        red: [50, 200],
        green: [60, 220, 150],
        blue: [40, 180],
        alpha: [],
    });
  • §

    Scene entitys

    const piccy = scrawl.makePicture({
    
        name: name('background'),
        asset: 'iris',
        copyDimensions: ['100%', '100%'],
        dimensions: ['95%', '95%'],
        handle: ['center', 'center'],
        start: ['center', 'center'],
    });
    
    const group = scrawl.makeGroup({
        name: name('mouse-group'),
        host: canvas.get('baseName'),
    });
    
    const outlineGroup = scrawl.makeGroup({
        name: name('outline-group'),
        host: canvas.get('baseName'),
    });
  • §

    Gradient

    scrawl.makeGradient({
    
        name: name('gradient'),
        endX: '100%',
    
        colors: [
            [0, 'blue'],
            [350, 'red'],
            [500, 'transparent'],
            [649, 'red'],
            [999, 'green']
        ],
        colorSpace: 'OKLAB',
        precision: 5,
    });
  • §

    Note: stencil filters cannot be memoized, which makes them slow

    • We can’t memoize what we don’t know, and we have no way of knowing what the canvas behind the entity will look like, or if it has changed since the last Display cycle
    const cog = scrawl.makeCog({
    
        name: name('cog'),
        group,
        start: ['center', 'center'],
        handle: ['center', 'center'],
        outerRadius: 120,
        innerRadius: 80,
        outerControlsDistance: 20,
        innerControlsDistance: 16,
        points: 12,
        fillStyle: name('gradient'),
        lockFillStyleToEntity: true,
        delta: {
            roll: 0.5,
        },
        isStencil: true,
        visibility: false,
    });
    
    cog.clone({
    
        name: name('cog-outline'),
        group: outlineGroup,
        strokeStyle: 'white',
        lineWidth: 2,
        method: 'draw',
        pivot: name('cog'),
        lockTo: 'pivot',
        isStencil: false,
    });
    
    const block = scrawl.makeBlock({
    
        name: name('block'),
        group,
        start: ['center', 'center'],
        handle: ['center', 'center'],
        dimensions: [200, 120],
        fillStyle: 'red',
        isStencil: true,
    });
    
    block.clone({
    
        name: name('block-outline'),
        group: outlineGroup,
        strokeStyle: 'white',
        lineWidth: 2,
        method: 'draw',
        pivot: name('block'),
        lockTo: 'pivot',
        isStencil: false,
    });
  • §

    Cat spritesheet image file taken from https://www.kisspng.com/png-walk-cycle-css-animations-drawing-sprite-sprite-1064760/

    scrawl.importSprite('img/cat-sprite.png');
    
    const cat = scrawl.makePicture({
    
        name: name('cat'),
        group,
        start: ['center', 'center'],
        handle: ['center', 'center'],
        dimensions: [300, 150],
        roll: 20,
        asset: 'cat-sprite',
        spriteTrack: 'walk',
        spriteFrameDuration: 100,
        isStencil: true,
        visibility: false,
    });
    
    cat.clone({
    
        name: name('cat-outline'),
        group: outlineGroup,
        strokeStyle: 'white',
        lineWidth: 2,
        method: 'draw',
        pivot: name('cat'),
        lockTo: 'pivot',
        isStencil: false,
    });
    
    let stencil = block;
  • §

    Scene animation

    Function to check whether mouse cursor is over canvas, and lock the reference entity accordingly

    const mouseCheck = function () {
    
        let active = false;
    
        return function () {
    
            if (canvas.here.active !== active) {
    
                active = canvas.here.active;
    
                stencil.set({
                    lockTo: (active) ? 'mouse' : 'start'
                });
            }
        };
    }();
  • §

    For this demo we will suppress touchmove functionality over the canvas

    scrawl.addNativeListener('touchmove', (e) => {
    
        e.preventDefault();
        e.returnValue = false;
    
    }, canvas.domElement);
  • §

    Function to display frames-per-second data, and other information relevant to the demo

    const report = reportSpeed('#reportmessage', function () {
    
        return `
        globalAlpha - ${dom.globalAlpha.value}`;
    });
  • §

    Create the Display cycle animation

    scrawl.makeRender({
    
        name: name('animation'),
        target: canvas,
        commence: mouseCheck,
        afterShow: report,
    });
  • §

    User interaction

    Setup form

    const dom = scrawl.initializeDomInputs([
        ['input', 'globalAlpha', '1'],
        ['select', 'filter', 0],
        ['select', 'entity', 0],
        ['select', 'globalCompositeOperation', 0],
    ]);
  • §

    Handle the filter selector

    scrawl.addNativeListener(['input', 'change'], (e) => {
    
        if (e && e.target) {
    
            e.preventDefault();
            e.returnValue = false;
    
            const val = e.target.value;
    
            if (val) {
    
                group.setArtefacts({
                    filters: [name(val)],
                });
            }
            else {
    
                group.setArtefacts({
                    filters: [],
                });
            }
        }
    }, dom.filter);
  • §

    Handle the entity selector

    scrawl.addNativeListener(['input', 'change'], (e) => {
    
        if (e && e.target) {
    
            e.preventDefault();
            e.returnValue = false;
    
            const val = e.target.value;
    
            if (val) {
    
                group.setArtefacts({
                    visibility: false,
                });
    
                outlineGroup.setArtefacts({
                    visibility: false,
                });
    
                cat.haltSprite();
    
                /** @ts-expect-error */
                stencil = group.getArtefact(name(val));
    
                stencil.set({
                    visibility: true,
                });
    
                if (val === 'cat') cat.playSprite();
    
                outlineGroup.getArtefact(name(`${val}-outline`)).set({
                    visibility: true,
                });
            }
        }
    }, dom.entity);
  • §

    Handle the composite and alpha inputs

    scrawl.makeUpdater({
    
        event: ['input', 'change'],
        origin: '.controlItem',
    
        target: group,
    
        useNativeListener: true,
        preventDefault: true,
    
        updates: {
    
            globalAlpha: ['globalAlpha', 'float'],
            globalCompositeOperation: ['globalCompositeOperation', 'raw'],
        },
    });
  • §

    Drag-and-Drop image loading functionality

    addImageDragAndDrop(scrawl, canvas, `#${namespace} .assets`, piccy);
  • §

    Development and testing

    console.log(scrawl.library);