Skip to content

Write an effect ​

Use this procedure to make a new effect. The example effect draws a dot at the pointer.

Procedure ​

  1. Make a schema for the settings of the effect with the field builders:

    ts
    import { createWand, type Effect, field, type Point } from 'magic-cursor-wand';
    
    const schema = {
      radius: field.number({
        label: 'Radius',
        description: 'The radius of the dot in pixels.',
        default: 6,
        min: 1,
        max: 40,
        step: 1,
      }),
      color: field.color({
        label: 'Color',
        description: 'The color of the dot. The value null uses the theme color.',
        default: null,
        nullable: true,
      }),
    };
  2. Write a function that returns an object of the type Effect:

    ts
    export function dotEffect(): Effect<'dot', typeof schema> {
      let radius = schema.radius.default;
      let color = '#ffffff';
      let point: Point | null = null;
    
      return {
        name: 'dot',
        schema,
        layer: 30,
        setup() {},
        configure(config) {
          radius = config.radius;
          color = config.color;
        },
        pointer(event) {
          point =
            event.phase === 'leave' || event.phase === 'cancel' ? null : { x: event.x, y: event.y };
        },
        update() {},
        draw(context) {
          if (!point) return;
          context.fillStyle = color;
          context.beginPath();
          context.arc(point.x, point.y, radius, 0, Math.PI * 2);
          context.fill();
        },
        isIdle: () => point === null,
        clear() {
          point = null;
        },
        destroy() {},
      };
    }
  3. Give the effect to createWand in the effects option:

    ts
    createWand({
      effects: [dotEffect()],
      config: { dot: { radius: 10 } },
    });
  4. Move the pointer on the page. Make sure that the dot follows the pointer.

Result ​

The wand calls configure with the resolved values of the section. A nullable color with the value null arrives as the value of theme.color.

Rules for effects ​

  • Use context.random() for random values, not Math.random.
  • Keep positions in document coordinates. The wand applies the scroll offset before draw.
  • Return true from isIdle when the effect has nothing to draw. Then the frame loop can sleep.
  • Do not allocate objects in update and draw, if possible.
  • Do not change the canvas state that the wand resets, for example the transform, in a different function.
  • Read frame.reducedMotion and decrease the motion when it is true.