Portfolio
  • 01Home
  • 02Projects
  • 03About
  • 04Skills
  • 05Lab
  • 06Writing
  • 07Contact

© 2026 Hamza Syrage

LabView all
Arrow FieldCursorCursor SpotlightCursorGooey CursorCursorImage CompareMediaInteractive ChartDataMagnetic ButtonInteractionMarquee RevealTypographyMorphing ShapeAnimationsNested ViewsOverlaysOdometer CounterDataParticle ConstellationCanvasRipple ClickButtonsScroll RevealScrollShuffle GridLayoutStep WizardNavigationTabsNavigationTilt CardCards

UI Experiments

All Lab Entries
Cursor

Arrow Field

A cursor-driven field of arrows using atan2 and vector normalization.

Move your cursor over the field. Each arrow calculates the angle to your cursor using atan2 and rotates accordingly.

#Step 1 - atan2

One arrow. Move your cursor and watch Math.atan2(dy, dx) calculate the angle between the arrow's center and your cursor position. The result is in radians, multiply by 180 / Math.PI to get degrees.

Move your cursor
atan2(dy, dx)

0.0°

#Step 2 - Raw distance

Same arrow, but now the length scales with distance from the center. Close to the center means a short arrow. Move to the edges and the arrow stretches. This is the raw, unnormalized version.

Move to edges, arrow stretches
Arrow length

0px

#Step 3 - Normalize

Fix the length. Now the arrow always points at the same distance, only the direction changes. This is what you want for a uniform field. Move to the edges and compare with Step 2.

Fixed length, only direction changes
Normalized

Length is always 80px. Only angle changes.

#Step 4 - Scale to a grid

Put 16 arrows in a 4x4 grid. Each one independently calculates its angle to the cursor. This is the DOM approach, 16 separate elements, each with its own rotation.

16 DOM elements
tsx
Loading...

#Step 5 - Canvas optimization

The same 8x8 grid, but rendered with <canvas>. One requestAnimationFrame loop redraws 64 arrows every frame. No DOM overhead, no layout thrashing.

tsx
Loading...

#Canvas vs DOM

The canvas version handles 64 arrows without breaking a sweat. The DOM version creates 64 separate elements, each one triggers paint and compositing on every frame.

Canvas (imperative)

FPS:

DOM (declarative)

64 individual DOM nodes
FPS:

#Configuration

Tweak the arrow size, grid density, and normalization. The code updates in real-time.

Parameters
Arrow size16px
Normalize
tsx
Loading...