Degrees to Radians for Developers: CSS Transforms, Canvas, and Game Engines
Degrees to radians conversion hits you the moment you call ctx.rotate() on an HTML Canvas and your 90° rotation does something insane. The Canvas API, WebGL, and every trig function in JavaScript expect radians — but designers, config files, and user inputs speak degrees. Multiply by π/180 and the mismatch vanishes. This guide focuses on the practical developer side: where radians show up in web APIs, how game engines handle angles, and the edge cases that ship bugs to production.

The Degrees-to-Radians Formula
One line:
radians = degrees × (π / 180)
A full circle is 360° and 2π radians. Divide: 2π / 360 = π/180 ≈ 0.017453 radians per degree. Multiply any degree value by this constant. For the reverse operation — radians back to degrees — flip the fraction to 180/π. Our radians to degrees converter covers that direction with physics examples.
CSS Transforms: deg vs rad vs turn
CSS supports four angle units out of the box: deg, rad, grad, and turn. You can write any of these:
transform: rotate(90deg)transform: rotate(1.5708rad)transform: rotate(0.25turn)
All three produce identical results. In practice, hardcoded CSS uses degfor readability. But when you generate styles from JavaScript — say, pointing an arrow toward the user's cursor — the math produces radians via Math.atan2(). Instead of converting back to degrees, you can inject the radian value directly:
element.style.transform = `rotate(${radians}rad)`;
One fewer conversion, one fewer place for bugs. The turn unit is useful for loading spinners: rotate(1turn) is a full revolution — cleaner than typing 360deg or 6.2832rad.
Canvas 2D API: Why arc() and rotate() Need Radians
The Canvas 2D specification inherited its angle convention from PostScript and OpenGL — both radian-native. Two methods trip developers up most often:
ctx.arc(x, y, r, startAngle, endAngle)— draws a circular arc. To draw a semicircle, you pass 0 and Math.PI (not 0 and 180). A full circle: 0 to 2 * Math.PI. Passing 360 instead of 2π draws an arc spanning 360 radians — roughly 57 full circles — which the browser clips to one revolution, but it's technically wrong and can cause rendering glitches in some engines.
ctx.rotate(angle) — rotates the entire canvas coordinate system by angleradians. If an artist says "rotate the sprite 45°," your code needs ctx.rotate(45 * Math.PI / 180). Forgetting the conversion rotates by 45 radians instead — about 7.16 full spins — leaving the sprite in a seemingly random orientation.
WebGL Rotation Matrices in Practice
WebGL has no built-in rotation function. You build rotation matrices yourself (or use a library like gl-matrix). A 2D rotation matrix looks like this:
[cos(θ), -sin(θ), 0, 0,
sin(θ), cos(θ), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1]
θ must be in radians because Math.cos() and Math.sin() expect radians. The gl-matrix library's mat4.rotateZ(out, a, rad)takes radians explicitly. Three.js's object.rotation.z also stores radians, though its MathUtils.degToRad() helper exists specifically because so many developers pass degrees by mistake.
Angle Conventions Across Game Engines
Not every engine agrees. Here's the landscape:
| Engine / Library | Input Unit | Notes |
|---|---|---|
| Canvas 2D | Radians | arc(), rotate(), all angles |
| WebGL / gl-matrix | Radians | Rotation matrices, shader uniforms |
| Three.js | Radians | Has MathUtils.degToRad() helper |
| PixiJS | Radians | sprite.rotation in rad |
| Unity (C#) | Degrees | Transform.Rotate() uses degrees; Mathf.Deg2Rad for conversion |
| Unreal (C++) | Degrees | FRotator uses degrees; FMath::DegreesToRadians() when needed |
| Godot | Radians | deg_to_rad() built-in; inspector shows degrees |
| CSS | Any | Accepts deg, rad, grad, turn |
The pattern: low-level APIs (Canvas, WebGL, OpenGL) use radians. High-level engines (Unity, Unreal) use degrees for the inspector and convert internally. If you're porting code between engines, the angle convention is the first thing to check.
Building a Reusable Conversion Helper
Rather than typing * Math.PI / 180 everywhere, wrap it once:
- JavaScript / TypeScript:
const toRad = (deg: number) => deg * (Math.PI / 180); - Python:
from math import radians— Python already ships one - C#:
float rad = deg * Mathf.Deg2Rad;(Unity) ordeg * MathF.PI / 180f(vanilla .NET) - Rust:
let rad = deg.to_radians();— built into f64
The helper isn't just about saving keystrokes. It makes code self-documenting: toRad(heading) is immediately clear; heading * 0.017453isn't. And if you ever need to swap to a lookup table for performance (unlikely but it happens in shader-adjacent code), you change one function.
Edge Cases in Animation Loops
Animations that accumulate rotation over time hit two gotchas.
Overflow past 2π.A spinning loader adding 2° per frame reaches 360° after 180 frames (3 seconds at 60 fps). In radians, that's 2π ≈ 6.2832. After 10 minutes, the accumulated value is ~37,700 rad. JavaScript handles this fine numerically, but some physics engines or collision systems behave erratically with large angles. Normalize periodically: angle = angle % (2 * Math.PI).
Interpolating between 350° and 10°. A naive lerp goes the long way around (350 → 180 → 10). The fix: convert both to radians, compute the shortest angular difference using atan2(sin(b-a), cos(b-a)), then interpolate. This trick — sometimes called "angular lerp" — is essential for smooth turret tracking, compass needles, and camera follow systems.
Unit Circle Quick Reference
The eight angles you'll convert most often in code, with their exact radian values and trig outputs:
| Degrees | Radians | sin | cos | Common use case |
|---|---|---|---|---|
| 0° | 0 | 0 | 1 | Default / east-facing |
| 30° | π/6 | 0.5 | 0.866 | Isometric projection angle |
| 45° | π/4 | 0.707 | 0.707 | Diagonal movement / miter cut |
| 90° | π/2 | 1 | 0 | Right angle / north-facing |
| 180° | π | 0 | −1 | Flip / U-turn |
| 270° | 3π/2 | −1 | 0 | South-facing / dropdown arrow |
| 360° | 2π | 0 | 1 | Full revolution / spinner |
For angles between these landmarks, the conversion helper is faster than memorization. But knowing that π/2 ≈ 1.5708 and π ≈ 3.1416 lets you sanity-check results instantly — if your rotation function returns 47.12 for a 270° input, something's wrong.
Working with GPS coordinates in DMS format? That's a two-step pipeline: DMS → decimal degrees → radians. Common in geolocation code where the Haversine formula needs radian inputs to calculate distances between points on Earth.
