/* global React, ReactDOM */ const { useState, useEffect, useRef, useCallback } = React; /* ============================================================ DATA ============================================================ */ const WORKS = [ { id: "work-1", title: "Spring Explosion", year: "2026", medium: "Acrylic on canvas", size: "50 × 70 cm", link: "https://www.saatchiart.com/en-de/art/Painting-Spring-Explosion/1481511/13665937/view" }, { id: "work-2", title: "Chromatic Burst", year: "2026", medium: "Acrylic on canvas", size: "50 × 50 cm", link: "https://www.saatchiart.com/en-de/art/Painting-Chromatic-Burst/1481511/13655763/view" }, { id: "work-3", title: "Vibrant Energy", year: "2026", medium: "Acrylic on canvas", size: "50 × 50 cm", link: "https://www.saatchiart.com/en-de/art/Painting-Vibrant-Energy/1481511/13655735/view" }, { id: "work-4", title: "Dynamic Pulse", year: "2026", medium: "Acrylic on canvas", size: "50 × 70 cm", link: "https://www.saatchiart.com/en-de/art/Painting-Dynamic-Pulse/1481511/13745687/view" }, { id: "work-5", title: "Ethereal Bloom", year: "2026", medium: "Acrylic on canvas", size: "50 × 70 cm", link: "https://www.saatchiart.com/en-de/art/Painting-Ethereal-Bloom/1481511/13684545/view" }, { id: "work-6", title: "Vibrant Pulse", year: "2026", medium: "Acrylic on canvas", size: "100 × 80 cm" }, { id: "work-7", title: "First Light", year: "2025", medium: "Oil & acrylic on canvas", size: "80 × 60 cm" }, { id: "work-8", title: "The sky in dream colors", year: "2024", medium: "Oil on canvas", size: "100 × 70 cm" }, { id: "work-9", title: "Golden Hour", year: "2025", medium: "Oil on canvas", size: "40 × 30 cm" }]; const CV = [ { cat: "Solo Exhibitions", rows: [ { yr: "2013", ttl: "Solo Exhibition", loc: "Kherson Cultural Centre, Kherson, Ukraine" }] }, { cat: "Group Exhibitions", rows: [ { yr: "2024", ttl: "Art Alt Stadt MH Reloaded", loc: "Petrikirche, Mülheim an der Ruhr, Germany" }] }, { cat: "Memberships", rows: [ { yr: "2015", ttl: "“Dnieper Palette”", loc: "Member, Kherson Regional Union of Fine & Decorative Arts, Ukraine" }] }, { cat: "Education", rows: [ { yr: "2010–15", ttl: "Kherson National Technical University", loc: "Faculty of Design, Ukraine" }, { yr: "2006–10", ttl: "Kherson College of Culture", loc: "Department of Fine & Decorative Arts, Ukraine" }] }, { cat: "Collections", rows: [ { yr: "—", ttl: "Private collections", loc: "United States, France, Italy & Germany" }] }]; const SAATCHI = "https://www.saatchiart.com/en-de/zavadskayaart"; const EMAIL = "e.zavadskaya91@gmail.com"; /* ============================================================ NAV ============================================================ */ function Nav({ onJump }) { const [scrolled, setScrolled] = useState(false); useEffect(() => { const on = () => setScrolled(window.scrollY > 40); on(); window.addEventListener("scroll", on, { passive: true }); return () => window.removeEventListener("scroll", on); }, []); const link = (id, label) => {e.preventDefault();onJump(id);}}>{label}; return ( ); } /* ============================================================ HERO ============================================================ */ function Hero({ onJump }) { return (

Gestural Abstraction · Painting

Painting the
weather of feeling

MÜLHEIM AN DER RUHR — WORKING IN OIL, ACRYLIC & MIXED MEDIA

Large-scale abstract paintings built from gesture, memory and atmosphere — where colour is allowed to behave like light moving through a room.

{e.preventDefault();onJump("commission");}}> Commission a piece
Featured Dynamic Pulse, 2025
); } /* ============================================================ GALLERY ============================================================ */ function Gallery({ onOpen }) { return (
01 / Selected Works

Paintings

A selection of recent canvases and works on paper. Click any piece to view it larger.

{WORKS.map((w, i) =>
onOpen(i)}>
View
{w.title} {w.year}
{w.medium} · {w.size}
)}

Original works & prints are available through

Saatchi Art ↗
); } /* ============================================================ LIGHTBOX ============================================================ */ function Lightbox({ index, onClose, onPrev, onNext, onInquire }) { const open = index !== null; useEffect(() => { if (!open) return; const onKey = (e) => { if (e.key === "Escape") onClose();else if (e.key === "ArrowLeft") onPrev();else if (e.key === "ArrowRight") onNext(); }; window.addEventListener("keydown", onKey); document.body.style.overflow = "hidden"; return () => { window.removeEventListener("keydown", onKey); document.body.style.overflow = ""; }; }, [open, onClose, onPrev, onNext]); const w = open ? WORKS[index] : null; return (
{open && }
{open &&
{String(index + 1).padStart(2, "0")} — {String(WORKS.length).padStart(2, "0")}

{w.title}

Year
{w.year}
Medium
{w.medium}
Size
{w.size}
{w.link ? "Acquire on Saatchi Art ↗" : "View on Saatchi Art ↗"} {e.preventDefault();onInquire();}}>Or enquire about this piece
}
); } /* ============================================================ ABOUT ============================================================ */ function About() { return (
02 / Studio

About

KATERYNA ZAVADSKA, STUDIO — MÜLHEIM AN DER RUHR

Kateryna Zavadska is a painter based in Mülheim an der Ruhr. Her canvases begin without a plan — a single gesture, a remembered colour, the residue of a particular light — and grow through layering, erasure and return.

“I am not painting a landscape. I am painting the moment the landscape became a feeling.”

The result is abstraction that stays close to the body: weather, water and breath as organising forces rather than subjects. Each surface holds its own history of decisions, the visible record of being made slowly.

Her work is held in private collections in the United States, France, Italy and Germany, and is shown internationally through the Saatchi Art platform and private collections across Europe and North America.

— Kateryna
); } /* ============================================================ EXHIBITIONS / CV ============================================================ */ function Exhibitions() { return (
03 / Curriculum

Exhibitions & Recognition

{CV.map((block) =>
{block.cat}
{block.rows.map((r, i) =>
{r.yr} {r.ttl} {r.loc && , {r.loc}}
)}
)}
); } /* ============================================================ COMMISSION FORM ============================================================ */ const BUDGETS = ["Under €1,500", "€1,500 – €3,500", "€3,500 – €7,000", "€7,000 +", "Not sure yet"]; const KINDS = ["Original painting", "Commissioned piece", "Print enquiry", "Exhibition / press", "Other"]; function Commission({ formRef, prefill }) { const [values, setValues] = useState({ name: "", email: "", kind: "", size: "", budget: "", timeline: "", message: "" }); const [errors, setErrors] = useState({}); const [sent, setSent] = useState(false); useEffect(() => { if (prefill) { setValues((v) => ({ ...v, kind: v.kind || "Original painting", message: v.message || `I'm interested in "${prefill}". Could you tell me more about availability?` })); } }, [prefill]); const set = (k) => (e) => { setValues((v) => ({ ...v, [k]: e.target.value })); setErrors((er) => er[k] ? { ...er, [k]: false } : er); }; const validate = () => { const er = {}; if (!values.name.trim()) er.name = true; if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(values.email.trim())) er.email = true; if (!values.message.trim()) er.message = true; setErrors(er); return Object.keys(er).length === 0; }; const submit = (e) => { e.preventDefault(); if (validate()) setSent(true); }; const reset = () => { setSent(false); setValues({ name: "", email: "", kind: "", size: "", budget: "", timeline: "", message: "" }); setErrors({}); }; return (
04 / Enquiries

Commission a Work

For acquisitions of available paintings, please use Saatchi Art. For commissions and all other enquiries, write below.

Let's make
something for
your space.

I take on a small number of commissions each year — paintings made in dialogue with your space, light and intention.

1
Conversation
We discuss scale, palette, and the feeling you want the work to hold.
2
Sketches
I share studies and a proposal, with timeline and pricing.
3
The painting
The work is made over 4–10 weeks, with progress shared along the way.
{!sent ?
Please enter your name.
Please enter a valid email.
Please add a short message.

I reply personally, usually within 2–3 working days.

:

Thank you, {values.name.split(" ")[0] || "friend"}.

Your enquiry has been noted. I read every message personally and will reply to {values.email} within a few days.

In the meantime, you're welcome to browse available originals on Saatchi Art.

}
); } /* ============================================================ FOOTER ============================================================ */ function Footer({ onJump }) { return ( ); } /* ============================================================ APP ============================================================ */ function App() { const [lbIndex, setLbIndex] = useState(null); const [prefill, setPrefill] = useState(null); const commissionRef = useRef(null); const jump = useCallback((id) => { const el = id === "top" ? document.body : document.getElementById(id); if (el) { const y = id === "top" ? 0 : el.getBoundingClientRect().top + window.scrollY - 12; window.scrollTo({ top: y, behavior: "smooth" }); } }, []); const open = useCallback((i) => setLbIndex(i), []); const close = useCallback(() => setLbIndex(null), []); const prev = useCallback(() => setLbIndex((i) => (i + WORKS.length - 1) % WORKS.length), []); const next = useCallback(() => setLbIndex((i) => (i + 1) % WORKS.length), []); const inquire = useCallback(() => { if (lbIndex !== null) setPrefill(WORKS[lbIndex].title); setLbIndex(null); setTimeout(() => jump("commission"), 120); }, [lbIndex, jump]); // Scroll reveal — opt-in via .anim so content is never hidden if JS lags useEffect(() => { const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches; if (reduce) return; document.documentElement.classList.add("anim"); const els = document.querySelectorAll(".reveal"); const io = new IntersectionObserver((entries) => { entries.forEach((e) => { if (e.isIntersecting) {e.target.classList.add("in");io.unobserve(e.target);} }); }, { threshold: 0.12, rootMargin: "0px 0px -8% 0px" }); els.forEach((el) => io.observe(el)); return () => {io.disconnect();document.documentElement.classList.remove("anim");}; }, []); return (