import * as scrawl from '../source/scrawl.js'
import { reportSpeed, initializeDomInputs } from './utilities.js';
import * as scrawl from '../source/scrawl.js'
import { reportSpeed, initializeDomInputs } from './utilities.js';
const canvas = scrawl.findCanvas('mycanvas');
Namespacing boilerplate
const namespace = canvas.name;
const name = (n) => `${namespace}-${n}`;
Get the asset
scrawl.importDomImage('#bunny');
Define some filters
scrawl.makeFilter({
name: name('grayscale'),
method: 'grayscale',
}).clone({
name: name('sepia'),
method: 'sepia',
}).clone({
name: name('invert'),
method: 'invert',
});
scrawl.makeFilter({
name: name('tint'),
method: 'tint',
redInRed: 0.5, redInGreen: 1, redInBlue: 0.9,
greenInRed: 0, greenInGreen: 0.3, greenInBlue: 0.8,
blueInRed: 0.8, blueInGreen: 0.8, blueInBlue: 0.4,
});
scrawl.makeFilter({
name: name('pixelate'),
method: 'pixelate',
tileWidth: 4,
tileHeight: 4,
});
scrawl.makeFilter({
name: name('blur'),
method: 'gaussianBlur',
radius: 5,
});
scrawl.makeFilter({
name: name('matrix'),
method: 'matrix',
weights: [-1, -1, 0, -1, 1, 1, 0, 1, 1],
});
Create a Block entity which covers the entire canvas; this will act as the area in which particles will be generated by the Emitter entity
scrawl.makeBlock({
name: name('field-block'),
width: '100%',
height: '100%',
method: 'none',
});
Create a World object which we can then assign to the particle emitter
const myWorld = scrawl.makeWorld({
name: name('my-world'),
tickMultiplier: 2,
userAttributes: [
{
key: 'brownianIntensity',
defaultValue: 2,
},
],
});
Create some Force objects
scrawl.makeForce({
name: name('brownian-motion'),
/* eslint-disable-next-line */
action: (particle, world, host) => {
const {load} = particle;
/** @ts-expect-error */
const intensity = world.brownianIntensity;
load.vectorAdd({
x: (Math.random() * intensity * 2) - intensity,
y: (Math.random() * intensity * 2) - intensity,
});
},
});
scrawl.makeForce({
name: name('mouse-disruptor'),
/* eslint-disable-next-line */
action: (particle, world, host) => {
const {load, position} = particle;
const {here} = canvas;
if (here.active) {
const v = scrawl.requestVector(here).vectorSubtract(position);
const mag = v.getMagnitude();
if (mag < 100) load.vectorAdd(v);
scrawl.releaseVector(v);
}
},
});
const myEmitter = scrawl.makeEmitter({
name: name('field-emitter'),
world: myWorld,
generationRate: 100,
particleCount: 50,
generateInArea: name('field-block'),
killBeyondCanvas: true,
Add the forces to all Particles that this Emitter entity generates
forces: [name('brownian-motion'), name('mouse-disruptor')],
artefact: scrawl.makePicture({
name: name('particle-image'),
asset: 'bunny',
width: 26,
height: 37,
handle: ['center', 'center'],
copyWidth: '100%',
copyHeight: '100%',
method: 'fill',
visibility: false,
noUserInteraction: true,
noPositionDependencies: true,
noDeltaUpdates: true,
}),
stampAction: function (artefact, particle, host) {
const [ , , ...start] = particle.history[0];
artefact.simpleStamp(host, {start});
},
});
Function to display frames-per-second data, and other information relevant to the demo
const { particlenames, particle } = scrawl.library;
const report = reportSpeed('#reportmessage', function () {
let historyCount = 0;
particlenames.forEach(n => {
const p = particle[n];
if (p) historyCount += p.history.length;
});
return `
Particles: ${particlenames.length}
Stamps per display: ${historyCount}`;
});
Create the Display cycle animation
scrawl.makeRender({
name: name('animation'),
target: canvas,
afterShow: report,
});
scrawl.addNativeListener('touchmove', (e) => {
e.preventDefault();
e.returnValue = false;
}, canvas.domElement);
Setup form observer functionality
const dom = initializeDomInputs([
['input', 'particleCount', '50'],
['input', 'brownianIntensity', '2'],
['select', 'filter', 0],
]);
Handle user interaction with the controls
const updateParticleCount = function (e) {
if (e && e.target) myEmitter.set({ particleCount: parseInt(e.target.value, 10) });
};
scrawl.addNativeListener(['input', 'change'], updateParticleCount, dom.particleCount);
const updateBrownianIntensity = function (e) {
/** @ts-expect-error */
if (e && e.target) myWorld.set({ brownianIntensity: parseFloat(e.target.value) });
};
scrawl.addNativeListener(['input', 'change'], updateBrownianIntensity, dom.brownianIntensity);
const updateFilter = function (e) {
if (e && e.target) {
myEmitter.clearFilters();
const val = e.target.value;
if (val) myEmitter.addFilters(name(val));
}
};
scrawl.addNativeListener(['input', 'change'], updateFilter, dom.filter);
console.log(scrawl.library);