Fract and Mod
Creating infinite repetition
The Fract Function
Of all the shader functions, fract might be the most magical. It takes any number and returns just the fractional part: the decimal digits after the point.
fract(2.7) returns 0.7. fract(5.123) returns 0.123. fract(10.0) returns 0.0. No matter how large your input grows, fract keeps bringing it back to the range 0 to 1.
Interactive: See how fract wraps values
fract returns only the decimal part, creating a repeating sawtooth
The definition is simple:
This creates a sawtooth wave. As x increases from 0 to 1, fract(x) increases with it. The moment x hits 1, fract snaps back to 0 and starts again. This pattern repeats forever, no matter how large x becomes.
Tiling with Fract
Here is where fract transforms your understanding of shader programming. If you multiply your UV coordinates before taking the fractional part, you create repetition.
fract(uv * 4.0) divides your coordinate space into a 4x4 grid. Each cell of that grid gets its own copy of the 0-1 UV range. Whatever you draw in that space now tiles perfectly.
Interactive: Tile a gradient
fract(uv * 3.0)
This is not just useful, it is fundamental. Almost every procedural pattern you have ever seen: brick walls, fabric weaves, noise textures, they all start with fract. One line of code gives you infinite repetition.
vec2 tiledUV = fract(uv * tiles);The Mod Function
While fract is specialized for the 0-1 range, mod generalizes repetition to any interval.
mod(x, y) returns the remainder when x is divided by y. It is like fract, but instead of always wrapping at 1, it wraps at whatever value you specify.
Interactive: Modulo with different divisors
mod wraps at 1.0 instead of 1
The formula mirrors fract:
When y is 1.0, mod behaves exactly like fract. But mod can do more: mod(x, 2.0) creates a sawtooth that spans 0 to 2. mod(x, 0.5) creates faster repetition.
Checkerboard Patterns
Combining floor and mod creates one of the most classic patterns: the checkerboard.
The trick is to use floor to get integer cell coordinates, then mod to determine if the sum is even or odd:
vec2 cell = floor(uv * tiles);
float checker = mod(cell.x + cell.y, 2.0);When both coordinates are even, or both are odd, the sum is even and checker equals 0. When one is even and one is odd, the sum is odd and checker equals 1.
Interactive: Build a checkerboard
mod(floor(uv.x * 4) + floor(uv.y * 4), 2.0)
This pattern shows the power of combining simple functions. Floor gives us which cell we are in. Mod gives us alternating values. Together they create structure from coordinates.
Brick Patterns
Bricks take the checkerboard idea further by offsetting alternating rows. This is a beautiful example of how small modifications create dramatically different results.
vec2 coord = uv * vec2(tiles, tiles * 0.5);
float row = floor(coord.y);
coord.x += mod(row, 2.0) * 0.5;
vec2 brick = fract(coord);The key insight is coord.x += mod(row, 2.0) * 0.5. On even rows, we add 0. On odd rows, we add 0.5, shifting the bricks by half a unit.
Interactive: Create a brick pattern
This offset-and-tile technique appears everywhere: in fabric patterns, in circuit board layouts, in countless procedural textures. Master this pattern and you have a powerful tool.
Building Your Own Patterns
Once you understand fract and mod, pattern creation becomes a process of experimentation. Start with tiled coordinates, add offsets, mix in some smooth transitions, and see what emerges.
Interactive: Pattern editor
Each pattern uses fract to create 5x5 repeating tiles
Some ideas to explore:
- Use
sin(fract(uv.x * tiles) * 3.14159)for wavy stripes - Combine multiple tile frequencies for complex textures
- Use distance from cell center for circular patterns within tiles
- Mix fract results with smoothstep for soft-edged repetition
The Art of Repetition
Fract and mod transform the infinite plane of UV coordinates into a manageable, repeating canvas. Instead of thinking about every pixel individually, you design a single tile and let mathematics replicate it endlessly.
This is a profound shift in how you think about graphics. You are not painting pixels. You are defining rules that generate pixels. The same code produces the same pattern whether your canvas is 100 pixels or 10,000 pixels wide.
Key Takeaways
fract(x)returns the fractional part, always in the range [0, 1)fract(uv * n)creates n-by-n tiling of any patternmod(x, y)generalizes fract to wrap at any valuefloorgives integer cell coordinates; combined with mod, creates checkerboards- Offsetting rows with
mod(row, 2.0) * 0.5creates brick-like patterns - These simple functions are the foundation of all procedural textures