For the complete documentation index, see llms.txt. This page is also available as Markdown.

With Ferp

If you don't want to roll your own state management

Ferp effects are perfect for running the declarativas render method.

<!doctype html>
<html>
<body>
<canvas></canvas>
<script type="module">
import { app, effects } from 'https://unpkg.com/ferp@^2.0.0-beta?module=1';
import { render, c } from 'https://unpkg.com/declarativas@^0.0.1-beta?module=1';

const getDelta = (state, timestamp) => state.lastRender > 0
  ? ((timestamp - state.lastRender) / 1000)
  : 0;
  
const move = (value, change, multiplier) => value + (change * multiplier);

const scheduleFx = (action) => effects.defer((resolve) => {
  requestAnimationFrame((timestamp) => {
    resolve(effects.act(action(timestamp)));
  });
});

const drawFx = (state, nextFx) => effects.thunk(() => {
  render(state.context2d, state.sceneFn(state));
  return nextFx
});

const drawAction = timestamp => state => {
  const nextState = {
    ...state,
    angle: move(state.angle, 30, getDelta(state, timestamp)),
    lastRender: timestamp
  };
  return [
    nextState,
    drawFx(
      nextState,
      scheduleFx(drawAction),
    ),
  ];
};

const sceneFn = state => [
  c('save'),
  c('clearRect', {
    x: 0,
    y: 0,
    width: state.context2d.canvas.width,
    height: state.context2d.canvas.height,
  }),
  c('translate', { x: state.context2d.canvas.width / 2, y: state.context2d.canvas.height / 2 }),
  c('rotate', { value: state.angle * Math.PI / 180 }),
  c('fillStyle', { value: '#f0f' }),
  c('fillRect', {
    x: -50,
    y: -50,
    width: 100,
    height: 100,
  }),
  c('restore'),
];

app({
  init: [
    {
      sceneFn: sceneFn,
      angle: 0,
      lastRender: 0,
      context2d: document.querySelector('canvas').getContext('2d'),
    },
    scheduleFx(drawAction),
  ]
})

</script>
</body>
</html>

Last updated