Ivan’s creative space
mediacrumbs

A collection of projects, experiments and ideas by Ivan.
Small crumbs. Big things.

See the work
SimpleSnip
SimpleSnip
LuluBoard
LuluBoard
Tabletop
Tabletop
TextureFox
TextureFox
MediaCrumbs
MediaCrumbs
PHOTO
About Me
Your Project
Your Project
Let's build something
What I’ve built

Projects

02
A photo editor that lives in your browser

SimpleSnip

A layer-based image editor that runs entirely in the browser — brushes, smart selections, free transform, filters and text — with nothing ever uploaded. Built from scratch, no image-editing libraries.

React 19TypeScriptViteZustandCanvas 2D
Deep dive
Why I built it

I wanted a quick image editor that just opened and worked — no download, no account, no upload. But the real motivation was to learn what actually sits behind a tool like Photoshop: layer compositing, flood fill, perceptual colour matching, snapshot history. So I set the rule that I'd build every piece by hand, with no image-editing libraries.

How I built it

State lives in two Zustand stores — one for the canvas (layers, selection model, transforms, 30-step snapshot history) and one for the workspace (active tool and settings). Each pixel layer is backed by its own off-DOM canvas in a small registry, and the visible canvas re-composites them every frame. Editing follows a buffer-and-composite pattern: a stroke is drawn into a scratch buffer, then composited over a base snapshot at the layer's opacity and clipped to the active selection mask. The magic wand and bucket fill share a flood-fill that compares colours with a perceptual 'redmean' distance for natural-looking edges. Everything is local — nothing leaves the device.

Feature highlights
Layers & tools
Layers & tools
A locked background plus unlimited paintable layers, with move, brush, eraser, shapes, crop and text — every tool masked to the active selection.
Smart selections
Smart selections
Rectangle, ellipse and lasso marquees plus a magic wand that uses perceptual colour distance with anti-aliased edges. Selections move, copy and transform.
Transform, filters & export
Transform, filters & export
Free transform with handles, non-destructive filters and a hue/saturation tool that preview live, then export to PNG, JPEG or WebP at 0.5×–2×.
Core snippet
// Perceptual "redmean" colour distance (squared) — powers the magic wand and
// bucket fill. Far closer to human vision than raw RGB, and skips the sqrt.
function redmeanDistanceSq(
  r1: number, g1: number, b1: number, a1: number,
  r2: number, g2: number, b2: number, a2: number,
): number {
  const rm = (r1 + r2) >> 1
  const dr = r1 - r2, dg = g1 - g2, db = b1 - b2, da = a1 - a2
  return (((512 + rm) * dr * dr) >> 8) + 4 * dg * dg
       + (((767 - rm) * db * db) >> 8) + 8 * da * da
}
Warhammer 40K combat calculator

Tabletop Calculator

Pit any two Warhammer 40,000 (10th ed.) units against each other and see the expected outcome instantly — every weapon keyword, save and army rule modelled, with the whole unit database derived straight from the community BSData catalogues.

Next.js 15TypeScriptTailwind CSSBSData
Deep dive
Why I built it

Doing combat math mid-game kills the pace, and online calculators tend to drift out of date because someone has to hand-enter every datasheet. I wanted two things: instant, accurate matchup math without rolling a calculator by hand, and a unit database that stays faithful to the rules by being derived from the open BSData catalogues rather than retyped.

How I built it

A single parse script treats the raw BSData .cat catalogues as the lossless source of truth and turns them into a typed factions.json with fast-xml-parser — stats, weapons, abilities and keywords, never hand-edited. The calculator runs in expected values (average dice, no RNG), auto-applying each weapon's own keywords — Lethal and Sustained Hits, Devastating Wounds, Anti-X, Blast, Rapid Fire, Melta — and modelling armour vs AP, cover, invulnerable saves and Feel No Pain. Toggleable detachment/army rules and a game-state conditions bar (½ range, stationary, charged) merge their modifiers into the result live, and legal-loadout rules (the pistol rule, pick-one weapon profiles) are enforced so no illegal combination is ever counted.

Feature highlights
Faithful unit database
Faithful unit database
Stats, weapons, abilities and keywords parsed straight from the BSData catalogues by one script — never hand-edited, so it stays accurate and easy to update.
Full damage sequence
Full damage sequence
Hits, wounds, armour/invuln saves and Feel No Pain as expected values, with every weapon keyword auto-applied from the weapon’s own profile.
Rules, buffs & conditions
Rules, buffs & conditions
Toggle detachment rules, army rules like Oath of Moment, faction mechanics and game-state conditions (½ range, stationary, charged) and watch the result update live.
Core snippet
// Everything is expected-value math — no dice are rolled.
function avgDice(expr: string | number): number {
  if (typeof expr === 'number') return expr
  const m = String(expr).match(/^(\d*)\s*[dD](\d+)\s*([+-]\s*\d+)?$/)
  if (!m) return parseInt(expr, 10) || 1
  const count = parseInt(m[1] || '1', 10)
  const die   = parseInt(m[2], 10)
  const bonus = m[3] ? parseInt(m[3].replace(/\s/g, ''), 10) : 0
  return count * ((die + 1) / 2) + bonus      // e.g. D6 → 3.5
}

// 10th-edition wound chart — Strength vs Toughness
function woundTarget(S: number, T: number): number {
  if (S >= T * 2) return 2
  if (S > T)      return 3
  if (S === T)    return 4
  if (S * 2 <= T) return 6
  return 5
}
The person behind it

About

Hey, I’m Ivan, a developer based in Breda, the Netherlands. I like building things that are simple, useful and nicely made.

I started out in game art and 3D modelling, with internships as a game artist at studios like Gamious and Engine Software, before moving into the web. Right now I’m studying a Bachelor’s in Computer Science at Avans Hogeschool, and that visual background still shapes how I build.

mediacrumbs is my home on the web, where all my projects live under one roof. Each one is a small experiment that grows into something people actually use.

I care about the details. Good typography, fast interfaces, tools that get out of your way. Off the clock you’ll find me riding and wrenching on my motorcycle, or painting Warhammer 40k minis.

Ivan van Dijk
What I work with
Languages I speak
DutchNative
EnglishFluent
GermanLearning
Programming
JavaScriptExperienced
TypeScriptExperienced
HTML & CSSExperienced
C#Some experience
C++Some experience
JavaExperienced
PythonLearning
Frameworks & tools
ReactExperienced
Next.jsExperienced
Node.jsSome experience
Tailwind CSSExperienced
GitSome experience
Design & creative
3ds MaxExperienced
MayaExperienced
UI / UXSome experience
PhotoshopExperienced
FigmaLearning
Contact

Let’s build something together.

Got a project in mind, a question, or just want to say hi? My inbox is always open and I try to reply within a day or two.

Email meivanvandijk27@gmail.comFind me onGitHubConnect onLinkedIn
What’s cooking

Upcoming

???
TextureFox
TextureFox

A marketplace for hand-crafted PBR game textures — browsable, licensed and instantly downloadable.

Coming soon
LuluBoard
LuluBoard

Browser-first planning and note-keeping — organise tasks and ideas in one clean space, always saved, no account needed.

Coming soon
💡
Your project
is next

Got an idea for a web tool, app or side project? I’m open to building things for people. Let’s make something useful together.

Get in touch →