<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.3.4">Jekyll</generator><link href="https://mostuffa.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://mostuffa.com/" rel="alternate" type="text/html" /><updated>2026-06-09T17:42:53+00:00</updated><id>https://mostuffa.com/feed.xml</id><title type="html">Mostafa Louarat</title><subtitle>Software engineer who likes UI/UX.</subtitle><entry xml:lang="en"><title type="html">My work at Jest</title><link href="https://mostuffa.com/en/jest" rel="alternate" type="text/html" title="My work at Jest" /><published>2026-02-26T00:00:00+00:00</published><updated>2026-02-26T00:00:00+00:00</updated><id>https://mostuffa.com/en/jest</id><content type="html" xml:base="https://mostuffa.com/en/jest"><![CDATA[<p><img src="/assets/jest/profiles-3.webp" alt="Jest.com profile screen on phone with fanned-out user profile cards." /></p>

<p><a href="https://about.jest.com/">Jest</a> is the first marketplace for messaging games—a real alternative to the app store model.</p>

<p>As the team’s Product Designer, I help shape how the platform looks, feels, and behaves. My work spans early concepting, product flows, UI design, and product management.</p>

<figure>
  <img src="/assets/jest/jest-techcrunch.webp" alt="Screenshot of TechCrunch article: Jest, a marketplace for messaging games, is challenging the app store status quo." />
  <figcaption><a href="https://techcrunch.com/2026/02/26/jest-a-marketplace-for-messaging-games-is-challenging-the-app-store-status-quo/">TechCrunch coverage</a>, February 2026.</figcaption>
</figure>

<ul>
  <li>We’re live in the US on <a href="https://jest.com/">Jest.com</a></li>
  <li>Learn more on our corporate website, <a href="https://about.jest.com/">about.jest.com</a></li>
  <li>If you’re a game developer or studio, check out the <a href="https://about.jest.com/fund/">Jest Games Fund</a> for up to $1M in support to publish your game on Jest!</li>
</ul>]]></content><author><name></name></author><category term="en" /><category term="case study" /><summary type="html"><![CDATA[]]></summary></entry><entry xml:lang="en"><title type="html">Smart Carousels with CSS</title><link href="https://mostuffa.com/en/carousels" rel="alternate" type="text/html" title="Smart Carousels with CSS" /><published>2026-01-07T00:00:00+00:00</published><updated>2026-01-07T00:00:00+00:00</updated><id>https://mostuffa.com/en/carousels</id><content type="html" xml:base="https://mostuffa.com/en/carousels"><![CDATA[<p>You’ve undoubtedly seen many carousels on the web. You know how usually the content gets cut off?</p>

<p><img src="/assets/carousel-cutoff.webp" alt="" /></p>

<p>The issue arises because, when designing for the web, we need content to have a <strong>maximum width</strong>. Otherwise, if someone has a wide monitor, the layout looks broken or they have to move their head all the way from left to right to read it.</p>

<p>When we give containers a maximum width, anything that doesn’t fit inside them gets cut off and becomes invisible. In a carousel, that means as you scroll, the content disappears abruptly before the end of the window. (Unless the window is narrower than the max width you set. In other words, this isn’t a problem on mobile.)</p>

<p>Everything on a website is a box. The carousel is also a box. When you put something in the box, it appears on the leftmost side. If you want it to show up more to the right, you can add padding on the left. So hypothetically, we could add padding to align the first book with the left edge of the other sections! Alas… the padding would need to be different depending on the window’s width!</p>

<p>So for a long time, I thought this was an unavoidable problem. But then I saw <a href="https://www.apple.com/iphone/">a carousel that worked right on Apple’s website</a>! So… there was a way!</p>

<p>Thankfully, because this is the web, you can right-click → Inspect Source on any website to see exactly how it’s built. I then adapted it for my website, and ta-da!</p>

<figure>
<video autoplay="" loop="" muted="" src="/assets/carousel-demo.mp4" class="w-100 br4"></video>
<figcaption><a href="/reading">See it live</a></figcaption>
</figure>

<p>The code ↴</p>

<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$container</span><span class="p">:</span> <span class="m">1240px</span><span class="p">;</span> <span class="cm">/* Yes, I use Sass. Yes, I know we have CSS variables now, but I like it and the pre-processor is built into Jekyll, which builds my site anyway! */</span>
<span class="nv">$container-padding</span><span class="p">:</span> <span class="m">32px</span><span class="p">;</span>

<span class="nc">.book-carousel</span> <span class="p">{</span>
    <span class="nl">padding</span><span class="p">:</span> <span class="m">0</span> <span class="nf">calc</span><span class="p">(</span><span class="m">50%</span> <span class="o">-</span> <span class="nf">min</span><span class="p">(</span><span class="nv">$container</span><span class="o">,</span> <span class="m">100%</span><span class="p">)</span> <span class="o">/</span> <span class="m">2</span> <span class="o">+</span> <span class="nv">$container-padding</span><span class="p">);</span> <span class="cm">/* [Half the screen] - [half the container] + [container padding * 2] */</span>
    <span class="nl">overflow-x</span><span class="p">:</span> <span class="nb">auto</span><span class="p">;</span> <span class="cm">/* makes it horizontally scrollable */</span>
    <span class="nl">scroll-snap-type</span><span class="p">:</span> <span class="nb">x</span> <span class="nb">proximity</span><span class="p">;</span> <span class="cm">/* so you can’t stop in between books: it “snaps” to the closest element in the X axis */</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The magic part is:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>calc(50% - min($container, 100%) / 2 + $container-padding);
</code></pre></div></div>

<p>We’re basically saying:</p>
<ul>
  <li>Take half of the screen.</li>
  <li>Subtract half of the max-width container from it OR half the screen (in which case the result is 0), whichever is smaller. This gives us the effective margin on each side.</li>
  <li>Add the container padding. Now we have <strong>the exact distance between the content of the other sections and the edge of the viewport</strong> on each side!</li>
</ul>

<p><img src="/assets/carousel-diagram.webp" alt="" /></p>

<p>And the coolest part is that this is all just CSS! Which means, if scripts don’t load (bad connection, on the train, unknown error, browser that blocks scripts), the carousel still works the same (progressive enhancement 😎).</p>]]></content><author><name></name></author><category term="en" /><category term="product" /><summary type="html"><![CDATA[You’ve undoubtedly seen many carousels on the web. You know how usually the content gets cut off?]]></summary></entry><entry xml:lang="en"><title type="html">Database Design System</title><link href="https://mostuffa.com/en/database" rel="alternate" type="text/html" title="Database Design System" /><published>2025-10-05T00:00:00+00:00</published><updated>2025-10-05T00:00:00+00:00</updated><id>https://mostuffa.com/en/database</id><content type="html" xml:base="https://mostuffa.com/en/database"><![CDATA[<p><a href="https://www.instagram.com/thedatabase.co/">Database™</a> has already established itself as a trusted resource for digital designers. When <a href="https://www.haritos.co/">Constantinos Haritos</a>, the Brand Designer who created it, asked me for some help with the Design System for the upcoming web platform, I was super excited to contribute.</p>

<p>The design of the platform was mostly complete, and I turned the designs into reusable components and responsive styles. I also created some tricky internal pages and flows using the newly established design patterns.</p>

<figure>
  <img src="/assets/database/submission-form.webp" alt="" />
  <figcaption>
  One of the steps of the project submission form that I designed.
  </figcaption>
</figure>

<figure>
  <img src="/assets/database/type-variables.webp" alt="" />
  <figcaption>
  I merged the separate desktop and mobile styles into single styles bound to responsive variables.
  </figcaption>
</figure>

<figure>
  <img src="/assets/database/login-component.webp" alt="" />
  <figcaption>
  Responsive components for modals and forms with desktop and mobile variants.
  </figcaption>
</figure>

<figure>
  <img src="/assets/database/text-input.webp" alt="" />
  <figcaption>
  Input fields with active and error states.
  </figcaption>
</figure>

<figure>
  <img src="/assets/database/media-card.webp" alt="" />
  <figcaption>
  The various states of the media upload card, including hover states.
  </figcaption>
</figure>]]></content><author><name></name></author><category term="en" /><category term="case study" /><summary type="html"><![CDATA[Database™ has already established itself as a trusted resource for digital designers. When Constantinos Haritos, the Brand Designer who created it, asked me for some help with the Design System for the upcoming web platform, I was super excited to contribute.]]></summary></entry><entry xml:lang="en"><title type="html">Done App Development</title><link href="https://mostuffa.com/en/done-app" rel="alternate" type="text/html" title="Done App Development" /><published>2025-06-02T00:00:00+00:00</published><updated>2025-06-02T00:00:00+00:00</updated><id>https://mostuffa.com/en/done-app</id><content type="html" xml:base="https://mostuffa.com/en/done-app"><![CDATA[<p><img src="/assets/work-new/done-app.png" alt="Done App Landing Page" /></p>

<p><a href="https://done.ma/">Done</a> is a modern productivity application designed to help teams manage tasks and workflows efficiently.</p>

<p>As the lead developer, I built the entire application stack from the ground up, utilizing Laravel for the backend, Vue.js for an intuitive frontend interface, and a suite of enterprise-grade technologies for reliability and scalability.</p>

<h2 id="architecture--implementation">Architecture &amp; Implementation</h2>

<ul>
  <li><strong>Backend Framework:</strong> Laravel with PHP</li>
  <li><strong>Frontend Framework:</strong> Vue.js for reactive components</li>
  <li><strong>API Design:</strong> RESTful API for mobile and web clients</li>
  <li><strong>Logging &amp; Monitoring:</strong> ELK Stack for comprehensive system insights</li>
  <li><strong>Caching Layer:</strong> Redis for lightning-fast data retrieval</li>
  <li><strong>Time-Series Data:</strong> InfluxDB for analytics and metrics</li>
  <li><strong>Deployment:</strong> Ansible for automated, consistent deployments</li>
</ul>

<h2 id="key-features">Key Features</h2>

<ul>
  <li>Real-time task synchronization across devices</li>
  <li>Advanced filtering and search capabilities</li>
  <li>Team collaboration tools with role-based access</li>
  <li>Comprehensive analytics dashboard</li>
  <li>Mobile-responsive design</li>
  <li>Enterprise-grade security</li>
</ul>

<p>The application is production-ready and actively used by multiple organizations for improved team productivity.</p>

<ul>
  <li><strong>Live Application:</strong> <a href="https://done.ma/">done.ma</a></li>
  <li><strong>Stack:</strong> Laravel • PHP • Vue.js • ELK • Redis • InfluxDB • Ansible</li>
</ul>]]></content><author><name></name></author><category term="en" /><category term="case study" /><summary type="html"><![CDATA[]]></summary></entry><entry xml:lang="en"><title type="html">ADZ Platform Development</title><link href="https://mostuffa.com/en/adz" rel="alternate" type="text/html" title="ADZ Platform Development" /><published>2025-06-01T00:00:00+00:00</published><updated>2025-06-01T00:00:00+00:00</updated><id>https://mostuffa.com/en/adz</id><content type="html" xml:base="https://mostuffa.com/en/adz"><![CDATA[<p><img src="/assets/work-new/adz.png" alt="ADZ Platform Landing Page" /></p>

<p><a href="https://adz.ma/">ADZ</a> is a comprehensive platform built with modern web technologies to deliver scalable and efficient solutions.</p>

<p>As a full-stack developer, I architected and implemented the entire platform using Laravel, PHP, and Vue.js, ensuring seamless integration with advanced technologies like ELK for logging, Redis for caching, and InfluxDB for time-series data management.</p>

<h2 id="key-technologies">Key Technologies</h2>

<ul>
  <li><strong>Backend:</strong> Laravel, PHP, REST API</li>
  <li><strong>Frontend:</strong> Vue.js</li>
  <li><strong>Infrastructure:</strong> Ansible for deployment automation</li>
  <li><strong>Data Management:</strong> InfluxDB for metrics, ELK Stack for logging</li>
  <li><strong>Caching:</strong> Redis for performance optimization</li>
</ul>

<h2 id="highlights">Highlights</h2>

<ul>
  <li>Built a robust REST API for seamless client communication</li>
  <li>Implemented real-time monitoring with ELK Stack</li>
  <li>Optimized performance using Redis caching strategies</li>
  <li>Automated deployment processes with Ansible</li>
  <li>Designed scalable database architecture with InfluxDB</li>
</ul>

<p>The platform is currently live and serves thousands of users, providing a reliable and performant experience across all devices.</p>

<ul>
  <li><strong>Live Platform:</strong> <a href="https://adz.ma/">adz.ma</a></li>
  <li><strong>Technology Stack:</strong> Laravel • PHP • Vue.js • ELK • Redis • InfluxDB</li>
</ul>]]></content><author><name></name></author><category term="en" /><category term="case study" /><summary type="html"><![CDATA[]]></summary></entry><entry xml:lang="en"><title type="html">My work at Shopflix</title><link href="https://mostuffa.com/en/shopflix" rel="alternate" type="text/html" title="My work at Shopflix" /><published>2025-05-26T00:00:00+00:00</published><updated>2025-05-26T00:00:00+00:00</updated><id>https://mostuffa.com/en/shopflix</id><content type="html" xml:base="https://mostuffa.com/en/shopflix"><![CDATA[<p>From April 2023 until October 2025 I was working as a UI / Product Designer at <a href="https://shopflix.gr/">Shopflix</a>, a major e-commerce marketplace in Greece.</p>

<p>I was initially brought on for UI Design, but over time my role evolved into what we now call Product Design, spanning everything from visual design to component systems and behavior analytics.</p>

<p>I can’t share details due to the NDA, but here’s the gist of my 2.5 years at Shopflix:</p>

<h3 id="year-1">Year 1</h3>
<p>I spent most of my time patching up existing designs as they were being implemented, and rushing to design new features using problematic components in the name of speed and consistency. Alongside that I was creating ad-hoc marketing assets while building a component library in Figma and laying the foundations of a design system on the side.</p>

<p>Due to the replatforming taking place at the same time, rethinking flows was off the table. I hated adapting work I believed was poorly thought-out, but I developed something unique:</p>

<p><strong>I turned complete pages into components</strong> (with variables) <strong>that I could drop into any flow, ensuring all user journeys would always display the latest version</strong>. This solved a major issue: developers would often start working on a feature many months after I’d designed it, and by then there were updates to pages within that flow. Before this approach, they kept accidentally rolling back each other’s work because each person was looking at a different version!</p>

<p>Here’s the component system in action:</p>

<figure>
  <video autoplay="" loop="" muted="" src="/assets/shopflix/shopflix-checkout-cart-components.mp4" class="w-100 br3"></video>
  <figcaption>Screen recording showing real-time interaction with checkout and cart component instances, toggling variants like device type (desktop/mobile) with instant page updates.</figcaption>
</figure>

<h3 id="year-2">Year 2</h3>
<p>With a major deadline gone, I finally had the freedom to explore and pitch improvements. But most of my usability-focused proposals initially got shelved.</p>

<p>That phase taught me as much about organizational dynamics as it did about design at scale. I gradually built stakeholder buy-in by consistently shipping good work, sharing honest opinions, and pushing back when needed. I also got involved with anything I could help improve, even outside my defined role.</p>

<h3 id="year-3">Year 3</h3>
<p>My persistence paid off because on Year 3 an organizational shift allowed me to work on the kind of projects I wanted to from the beginning: remaking core flows from scratch.</p>

<p>As of writing this, the bulk of my design work has not been implemented yet (so I can’t show it here 😮‍💨), but it includes major updates for the:</p>
<ul>
  <li>Checkout Flow</li>
  <li>Product Page</li>
  <li>Homepage</li>
  <li>Orders</li>
  <li>Cart</li>
</ul>

<p>We’d long been aware of the shortcomings, but conflicting priorities did not previously allow the time to address them. I can’t describe the satisfaction I felt seeing the enormous usability improvements and it goes without saying that I can’t wait to see them live!</p>

<p>I left Shopflix knowing it’s on a much better trajectory than when I joined, and I’m confident that the team will continue doing great work to bring the platform to the state we know it can reach!</p>]]></content><author><name></name></author><category term="en" /><category term="case study" /><summary type="html"><![CDATA[From April 2023 until October 2025 I was working as a UI / Product Designer at Shopflix, a major e-commerce marketplace in Greece.]]></summary></entry><entry xml:lang="en"><title type="html">How I generate color scales in CSS with OKLCH</title><link href="https://mostuffa.com/en/css-color-scales" rel="alternate" type="text/html" title="How I generate color scales in CSS with OKLCH" /><published>2025-05-13T00:00:00+00:00</published><updated>2025-05-13T00:00:00+00:00</updated><id>https://mostuffa.com/en/css-color-scales</id><content type="html" xml:base="https://mostuffa.com/en/css-color-scales"><![CDATA[<p><img src="/assets/anna-color-scale-css.webp" alt="" /></p>

<h2 id="the-idea">The idea</h2>

<p>I wanted to create a single variable in my CSS, e.g. <code class="language-plaintext highlighter-rouge">--brand: #ff6800;</code>, and have an entire color scale (with variables like <code class="language-plaintext highlighter-rouge">--brand-10: #ffe4d3; --brand-20: #ffd2b2;</code> and so on) automatically “generated” for me. Like this! ⤵︎</p>

<p><img src="/assets/color-scale-example.webp" alt="" /></p>

<p>Similar to what you get from sites like <a href="https://uicolors.app/generate">uicolors.app’s Tailwind CSS Color Generator</a>, but locally, in your CSS file.</p>

<p>Why? When playing around with a new design, not yet sure which colors to go with, being able to tweak a couple of values directly in my CSS and preview my own design in different colors would be super practical.</p>

<p>Now, you <em>might</em> be wondering:</p>

<h2 id="what-is-oklch">What is OKLCH?</h2>

<p>These people have done a much better job explaining than I could at the moment:</p>

<ul>
  <li>
    <p><a href="https://evilmartians.com/chronicles/oklch-a-color-picker-made-to-help-think-perceptively">OK, OKLCH: a color picker made to help think perceptively, by Evil Martians</a></p>

    <p>“OKLCH is <strong>a new way of encoding colors</strong> (like HEX, RGBA, or HSL). It always has predictable lightness after color transformations (compared to HSL), it’s capable of encoding a wider range of colors, it offers native browser support, and unlike LCH and Lab, <strong>it has no hue shift</strong> when chroma is changed.”</p>
  </li>
  <li>
    <p><a href="https://keithjgrant.com/posts/2023/04/its-time-to-learn-oklch-color/">It’s Time to Learn oklch Color, by Keith J. Grant</a></p>

    <p>“In HSL, 100% saturation is simply as saturated as that particular color can be in the sRGB gamut. In OKLCH, the values aren’t based on technical limits or a mathematical definition, but rather on perceived equality. <strong>The amount of lightness indicates exactly how bright the color is</strong>, and the amount of chroma indicates exactly how vivid it is. The human eye perceives some colors like green or yellow to be brighter than others, like blue or purple, and OKLCH takes these details into account.”</p>
  </li>
</ul>

<p>The gist of it is that, similar to HSL, you can keep the Hue constant while adjusting the Lightness and Saturation (Chroma, in this case) independently. What sets OKLCH apart is that, unlike HSL and the others, all colors with the same hue <strong>actually look like they have the same hue</strong>! You know how making a vibrant blue lighter makes it look purple? Well, in OKLCH it still looks blue!</p>

<figure>
  <img src="/assets/blue-hue-difference-atmos.webp" alt="Difference between a blue color scale in LCH vs OKLCH" />
  <figcaption>Image from <a href="https://atmos.style/blog/lch-vs-oklch">atmos.style</a></figcaption>
</figure>

<p>You can also use <code class="language-plaintext highlighter-rouge">oklch(from…)</code> to convert HEX, RGB, etc. colors into OKLCH and <em>then</em> mess with their Lightness, Chroma, and Hue.</p>

<h2 id="what-i-did">What I did</h2>

<p>Firstly, I used the numbering format from the Tailwind color scales for familiarity.
Then I tried using <code class="language-plaintext highlighter-rouge">oklch(from…)</code> and adjusting the Alpha value to create a scale. But then colors on the scale could not be darker than the original. And if they ever overlap (think, text color with 80% opacity + background at 30%) then the color on top will be a mix of the two!</p>

<p>So I switched to using <code class="language-plaintext highlighter-rouge">calc()</code> instead of L and C values within <code class="language-plaintext highlighter-rouge">oklch()</code> and keeping the hue value the same.
I first created a color scale using an online generator, then converted to OKLCH and used a spreadsheet to calculate the difference between the Lightness and Chroma values of each color. I rounded those up and created variables in my CSS to represent the Lightness increment and the Chroma increment separately.</p>

<p><img src="/assets/color-scale-excel.webp" alt="" /></p>

<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">:root</span> <span class="p">{</span>

    <span class="cm">/* Base color */</span>
   <span class="na">--brand</span><span class="p">:</span> <span class="mh">#0d1bbd</span><span class="p">;</span>

    <span class="cm">/* Lightness and Chroma increments */</span>
    <span class="na">--l-increment</span><span class="p">:</span> <span class="m">0</span><span class="mi">.075</span><span class="p">;</span> <span class="cm">/* UP: Lighter*/</span>
    <span class="na">--c-increment</span><span class="p">:</span> <span class="m">0</span><span class="mi">.028</span><span class="p">;</span> <span class="cm">/* UP: LESS saturated*/</span>

    <span class="cm">/* Some of the resulting color tokens */</span>
    <span class="na">--bg-brand-50</span><span class="p">:</span> <span class="nf">oklch</span><span class="p">(</span><span class="n">from</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">brand</span><span class="p">)</span> <span class="nf">calc</span><span class="p">(</span><span class="n">l</span> <span class="o">+</span> <span class="nf">calc</span><span class="p">(</span><span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">l-increment</span><span class="p">)</span> <span class="o">*</span> <span class="m">8</span><span class="p">))</span> <span class="nf">calc</span><span class="p">(</span><span class="n">c</span> <span class="o">-</span> <span class="nf">calc</span><span class="p">(</span><span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">c-increment</span><span class="p">)</span> <span class="o">*</span> <span class="m">8</span><span class="p">))</span> <span class="n">h</span> <span class="o">/</span> <span class="m">1</span><span class="p">);</span>
    <span class="cm">/* … */</span>
    <span class="na">--bg-brand-800</span><span class="p">:</span> <span class="nf">oklch</span><span class="p">(</span><span class="n">from</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">brand</span><span class="p">)</span> <span class="n">l</span> <span class="n">c</span> <span class="n">h</span> <span class="o">/</span> <span class="m">1</span><span class="p">);</span> <span class="cm">/* This is the base color */</span>
    <span class="cm">/* … */</span>
    <span class="na">--bg-brand-950</span><span class="p">:</span> <span class="nf">oklch</span><span class="p">(</span><span class="n">from</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">brand</span><span class="p">)</span> <span class="nf">calc</span><span class="p">(</span><span class="n">l</span> <span class="o">-</span> <span class="nf">calc</span><span class="p">(</span><span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">l-increment</span><span class="p">)</span> <span class="o">*</span> <span class="m">2</span><span class="p">))</span> <span class="nf">calc</span><span class="p">(</span><span class="n">c</span> <span class="o">-</span> <span class="nf">calc</span><span class="p">(</span><span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">c-increment</span><span class="p">)</span> <span class="o">*</span> <span class="m">2</span><span class="p">))</span> <span class="n">h</span> <span class="o">/</span> <span class="m">1</span><span class="p">);</span>

<span class="p">}</span>
</code></pre></div></div>

<p>That seemed to work exactly how I imagined!</p>

<p>For that specific color…</p>

<h2 id="obstacles">Obstacles</h2>

<p>Obvious in hindsight: that method only works if the base colors all have similar Lightness and Chroma. There’s no way to create conditional statements (“if this, then that”) in CSS, so a base color would always have to occupy the same step on the color scale.</p>

<p>That can be sorted by spending a bit of extra time choosing base colors. Problem solved? Not so fast! Because of the way OKLCH works, some HEX/RGB/HSL colors do not have an OKLCH equivalent!</p>

<figure> 
    <img src="/assets/hsl-vs-oklch.webp" alt="Difference between a blue color scale in LCH vs OKLCH" /> 
    <figcaption>
        Image from <a href="https://evilmartians.com/chronicles/oklch-a-color-picker-made-to-help-think-perceptively">evilmartians.com</a>
    </figcaption> 
</figure>

<p><code class="language-plaintext highlighter-rouge">oklch(from…)</code> works by converting, say, a HEX value into OKLCH. But that means if you’re using HEX for your base variables, some colors are bound to look less saturated than the rest even if you max out their saturation in the HEX color space.</p>

<p><img src="/assets/color-scale-saturation.webp" alt="" /></p>

<h2 id="solution">Solution</h2>

<p>Switch to OKLCH for the base color variables. Then you can make sure the lightness and chroma of each color are the same, or close enough. Now, you do miss out on a couple of things when you do that…</p>

<ul>
  <li>You can’t just enter any color you like and get a color scale. You need to find its OKLCH Hue and input that instead. The original color might not even be part of the resulting color scale.</li>
  <li>Design tools like Figma do not support OKLCH, so you have to figure out the hue by other means.</li>
  <li>Code editors like VS Code don’t natively preview OKLCH colors like they do HEX, RGB, etc. You need to install an extension if you want that, but it can really slow down the app.</li>
</ul>

<p>But hey—it works! :D And changing a single number to get an entirely new color scale is kinda fun, like a design nerd’s slot machine. I figured this technique might be useful (and/or fun) to someone, so why not share.</p>

<p>Here’s the CSS you can use:</p>

<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">:root</span> <span class="p">{</span>

    <span class="c">/* Base colors */</span>
    <span class="c">/* Change the HUE (last number) for different colors. */</span>
    <span class="c">/* You might wanna change the Lightness and Chroma slightly too in some cases. */</span>
    <span class="py">--brand</span><span class="p">:</span> <span class="nf">oklch</span><span class="p">(</span><span class="m">0.40</span> <span class="m">0.30</span> <span class="m">265.71</span><span class="p">);</span>

    <span class="c">/* add more variables here */</span>

    <span class="c">/* Adjuts scales */</span>
    <span class="py">--l-increment</span><span class="p">:</span> <span class="m">0.075</span><span class="p">;</span> <span class="c">/* UP: Lighter*/</span>
    <span class="py">--c-increment</span><span class="p">:</span> <span class="m">0.028</span><span class="p">;</span> <span class="c">/* UP: LESS saturated*/</span>

    <span class="c">/* Color tokens */</span>
    <span class="c">/* Use them in classes like this: var(----bg-brand-600) */</span>
    <span class="py">--bg-brand-50</span><span class="p">:</span> <span class="nf">oklch</span><span class="p">(</span><span class="n">from</span> <span class="nf">var</span><span class="p">(</span><span class="l">--brand</span><span class="p">)</span> <span class="nf">calc</span><span class="p">(</span><span class="n">l</span> <span class="o">+</span> <span class="nf">calc</span><span class="p">(</span><span class="nf">var</span><span class="p">(</span><span class="l">--l-increment</span><span class="p">)</span> <span class="o">*</span> <span class="m">8</span><span class="p">))</span> <span class="nf">calc</span><span class="p">(</span><span class="n">c</span> <span class="o">-</span> <span class="nf">calc</span><span class="p">(</span><span class="nf">var</span><span class="p">(</span><span class="l">--c-increment</span><span class="p">)</span> <span class="o">*</span> <span class="m">8</span><span class="p">))</span> <span class="n">h</span> <span class="o">/</span> <span class="m">1</span><span class="p">);</span>
    <span class="py">--bg-brand-100</span><span class="p">:</span> <span class="nf">oklch</span><span class="p">(</span><span class="n">from</span> <span class="nf">var</span><span class="p">(</span><span class="l">--brand</span><span class="p">)</span> <span class="nf">calc</span><span class="p">(</span><span class="n">l</span> <span class="o">+</span> <span class="nf">calc</span><span class="p">(</span><span class="nf">var</span><span class="p">(</span><span class="l">--l-increment</span><span class="p">)</span> <span class="o">*</span> <span class="m">7</span><span class="p">))</span> <span class="nf">calc</span><span class="p">(</span><span class="n">c</span> <span class="o">-</span> <span class="nf">calc</span><span class="p">(</span><span class="nf">var</span><span class="p">(</span><span class="l">--c-increment</span><span class="p">)</span> <span class="o">*</span> <span class="m">7</span><span class="p">))</span> <span class="n">h</span> <span class="o">/</span> <span class="m">1</span><span class="p">);</span>
    <span class="py">--bg-brand-200</span><span class="p">:</span> <span class="nf">oklch</span><span class="p">(</span><span class="n">from</span> <span class="nf">var</span><span class="p">(</span><span class="l">--brand</span><span class="p">)</span> <span class="nf">calc</span><span class="p">(</span><span class="n">l</span> <span class="o">+</span> <span class="nf">calc</span><span class="p">(</span><span class="nf">var</span><span class="p">(</span><span class="l">--l-increment</span><span class="p">)</span> <span class="o">*</span> <span class="m">6</span><span class="p">))</span> <span class="nf">calc</span><span class="p">(</span><span class="n">c</span> <span class="o">-</span> <span class="nf">calc</span><span class="p">(</span><span class="nf">var</span><span class="p">(</span><span class="l">--c-increment</span><span class="p">)</span> <span class="o">*</span> <span class="m">6</span><span class="p">))</span> <span class="n">h</span> <span class="o">/</span> <span class="m">1</span><span class="p">);</span>
    <span class="py">--bg-brand-300</span><span class="p">:</span> <span class="nf">oklch</span><span class="p">(</span><span class="n">from</span> <span class="nf">var</span><span class="p">(</span><span class="l">--brand</span><span class="p">)</span> <span class="nf">calc</span><span class="p">(</span><span class="n">l</span> <span class="o">+</span> <span class="nf">calc</span><span class="p">(</span><span class="nf">var</span><span class="p">(</span><span class="l">--l-increment</span><span class="p">)</span> <span class="o">*</span> <span class="m">5</span><span class="p">))</span> <span class="nf">calc</span><span class="p">(</span><span class="n">c</span> <span class="o">-</span> <span class="nf">calc</span><span class="p">(</span><span class="nf">var</span><span class="p">(</span><span class="l">--c-increment</span><span class="p">)</span> <span class="o">*</span> <span class="m">5</span><span class="p">))</span> <span class="n">h</span> <span class="o">/</span> <span class="m">1</span><span class="p">);</span>
    <span class="py">--bg-brand-400</span><span class="p">:</span> <span class="nf">oklch</span><span class="p">(</span><span class="n">from</span> <span class="nf">var</span><span class="p">(</span><span class="l">--brand</span><span class="p">)</span> <span class="nf">calc</span><span class="p">(</span><span class="n">l</span> <span class="o">+</span> <span class="nf">calc</span><span class="p">(</span><span class="nf">var</span><span class="p">(</span><span class="l">--l-increment</span><span class="p">)</span> <span class="o">*</span> <span class="m">4</span><span class="p">))</span> <span class="nf">calc</span><span class="p">(</span><span class="n">c</span> <span class="o">-</span> <span class="nf">calc</span><span class="p">(</span><span class="nf">var</span><span class="p">(</span><span class="l">--c-increment</span><span class="p">)</span> <span class="o">*</span> <span class="m">4</span><span class="p">))</span> <span class="n">h</span> <span class="o">/</span> <span class="m">1</span><span class="p">);</span>
    <span class="py">--bg-brand-500</span><span class="p">:</span> <span class="nf">oklch</span><span class="p">(</span><span class="n">from</span> <span class="nf">var</span><span class="p">(</span><span class="l">--brand</span><span class="p">)</span> <span class="nf">calc</span><span class="p">(</span><span class="n">l</span> <span class="o">+</span> <span class="nf">calc</span><span class="p">(</span><span class="nf">var</span><span class="p">(</span><span class="l">--l-increment</span><span class="p">)</span> <span class="o">*</span> <span class="m">3</span><span class="p">))</span> <span class="nf">calc</span><span class="p">(</span><span class="n">c</span> <span class="o">-</span> <span class="nf">calc</span><span class="p">(</span><span class="nf">var</span><span class="p">(</span><span class="l">--c-increment</span><span class="p">)</span> <span class="o">*</span> <span class="m">3</span><span class="p">))</span> <span class="n">h</span> <span class="o">/</span> <span class="m">1</span><span class="p">);</span>
    <span class="py">--bg-brand-600</span><span class="p">:</span> <span class="nf">oklch</span><span class="p">(</span><span class="n">from</span> <span class="nf">var</span><span class="p">(</span><span class="l">--brand</span><span class="p">)</span> <span class="nf">calc</span><span class="p">(</span><span class="n">l</span> <span class="o">+</span> <span class="nf">calc</span><span class="p">(</span><span class="nf">var</span><span class="p">(</span><span class="l">--l-increment</span><span class="p">)</span> <span class="o">*</span> <span class="m">2</span><span class="p">))</span> <span class="nf">calc</span><span class="p">(</span><span class="n">c</span> <span class="o">-</span> <span class="nf">calc</span><span class="p">(</span><span class="nf">var</span><span class="p">(</span><span class="l">--c-increment</span><span class="p">)</span> <span class="o">*</span> <span class="m">2</span><span class="p">))</span> <span class="n">h</span> <span class="o">/</span> <span class="m">1</span><span class="p">);</span>
    <span class="py">--bg-brand-700</span><span class="p">:</span> <span class="nf">oklch</span><span class="p">(</span><span class="n">from</span> <span class="nf">var</span><span class="p">(</span><span class="l">--brand</span><span class="p">)</span> <span class="nf">calc</span><span class="p">(</span><span class="n">l</span> <span class="o">+</span> <span class="nf">calc</span><span class="p">(</span><span class="nf">var</span><span class="p">(</span><span class="l">--l-increment</span><span class="p">)</span> <span class="o">*</span> <span class="m">1</span><span class="p">))</span> <span class="nf">calc</span><span class="p">(</span><span class="n">c</span> <span class="o">-</span> <span class="nf">calc</span><span class="p">(</span><span class="nf">var</span><span class="p">(</span><span class="l">--c-increment</span><span class="p">)</span> <span class="o">*</span> <span class="m">1</span><span class="p">))</span> <span class="n">h</span> <span class="o">/</span> <span class="m">1</span><span class="p">);</span>
    <span class="py">--bg-brand-800</span><span class="p">:</span> <span class="nf">oklch</span><span class="p">(</span><span class="n">from</span> <span class="nf">var</span><span class="p">(</span><span class="l">--brand</span><span class="p">)</span> <span class="n">l</span> <span class="n">c</span> <span class="n">h</span> <span class="o">/</span> <span class="m">1</span><span class="p">);</span>
    <span class="py">--bg-brand-900</span><span class="p">:</span> <span class="nf">oklch</span><span class="p">(</span><span class="n">from</span> <span class="nf">var</span><span class="p">(</span><span class="l">--brand</span><span class="p">)</span> <span class="nf">calc</span><span class="p">(</span><span class="n">l</span> <span class="o">-</span> <span class="nf">calc</span><span class="p">(</span><span class="nf">var</span><span class="p">(</span><span class="l">--l-increment</span><span class="p">)</span> <span class="o">*</span> <span class="m">1</span><span class="p">))</span> <span class="nf">calc</span><span class="p">(</span><span class="n">c</span> <span class="o">-</span> <span class="nf">calc</span><span class="p">(</span><span class="nf">var</span><span class="p">(</span><span class="l">--c-increment</span><span class="p">)</span> <span class="o">*</span> <span class="m">1</span><span class="p">))</span> <span class="n">h</span> <span class="o">/</span> <span class="m">1</span><span class="p">);</span>
    <span class="py">--bg-brand-950</span><span class="p">:</span> <span class="nf">oklch</span><span class="p">(</span><span class="n">from</span> <span class="nf">var</span><span class="p">(</span><span class="l">--brand</span><span class="p">)</span> <span class="nf">calc</span><span class="p">(</span><span class="n">l</span> <span class="o">-</span> <span class="nf">calc</span><span class="p">(</span><span class="nf">var</span><span class="p">(</span><span class="l">--l-increment</span><span class="p">)</span> <span class="o">*</span> <span class="m">2</span><span class="p">))</span> <span class="nf">calc</span><span class="p">(</span><span class="n">c</span> <span class="o">-</span> <span class="nf">calc</span><span class="p">(</span><span class="nf">var</span><span class="p">(</span><span class="l">--c-increment</span><span class="p">)</span> <span class="o">*</span> <span class="m">2</span><span class="p">))</span> <span class="n">h</span> <span class="o">/</span> <span class="m">1</span><span class="p">);</span>

<span class="p">}</span>
</code></pre></div></div>

<hr />

<h2 id="disclosure">Disclosure</h2>
<p>I originally planned to name this post “What I learned making an OKLCH color scale generator in CSS” and it was gonna have a section titled “Why it failed”. While writing that I realized… I had not failed. I just needed to tweak some Chroma values (and mention some caveats)! ;)</p>]]></content><author><name></name></author><category term="en" /><category term="code" /><summary type="html"><![CDATA[]]></summary></entry><entry xml:lang="el"><title type="html">Γιατί δεν φτιάχνω φθηνά site</title><link href="https://mostuffa.com/el/mle" rel="alternate" type="text/html" title="Γιατί δεν φτιάχνω φθηνά site" /><published>2025-05-13T00:00:00+00:00</published><updated>2025-05-13T00:00:00+00:00</updated><id>https://mostuffa.com/el/el-mle</id><content type="html" xml:base="https://mostuffa.com/el/mle"><![CDATA[<p>Πελάτης μου στον χώρο μεταφορών είχε ήδη site. Αρχική σελίδα με καρουζέλ γεμάτο stock φωτογραφίες (συμπεριλαμβανομένης μίας που έδειχνε ζευγάρι να κοιτάει χάρτη, πρόσωπα εκτώς πλάνου).</p>

<p>Καμία φόρμα επικοινωνίας. Αντί αυτού, γραπτές οδηγίες για το τι να γράψεις στο email που θα στείλεις για να ζητήσεις μεταφορά.</p>

<p>Χωρίς analytics, χωρίς φόρμα, χωρίς τρόπο να μετρήσει αν το site δουλεύει.</p>

<h2 id="η-διαφορά">Η διαφορά</h2>

<h3 id="τυπικό-template-site-300500-">Τυπικό template site (300–500 €)</h3>
<ul>
  <li>Γενικό template με αλλαγμένα χρώματα</li>
  <li>Stock εικόνες που δεν σχετίζονται με την επιχείρηση</li>
  <li>“Εντυπωσιακά” εφέ που κάνουν το site αργό και δύσχρηστο</li>
</ul>

<p><a href="https://www.google.com/search?q=free+bootstrap+marketing+templates&amp;udm=2&amp;sclient=img">Κάνε μια αναζήτηση για “free bootstrap marketing templates”</a> και θα σου φανούν πολύ γνώριμα.</p>

<h3 id="στρατηγικό-site-1000--">Στρατηγικό site (1000 € +)</h3>
<ul>
  <li>Κάθε στοιχείο υπάρχει για συγκεκριμένο λόγο</li>
  <li>Εξυπηρετεί τους επισκέπτες ώστε να γίνουν πελάτες</li>
  <li>Ευανάγνωστο, λειτουργικό, και χτισμένο για τις δικές σου ανάγκες</li>
</ul>

<p><a href="/en/snippets">Δες παραδείγματα από το portfolio μου</a></p>

<h2 id="τι-σημαίνει-custom-design">Τι σημαίνει custom design</h2>
<ul>
  <li><strong>Λογική Δομή</strong>: Αν είσαι εστιατόριο, το μενού είναι άμεσα προσβάσιμο (και όχι PDF). Αν είσαι δικηγόρος, οι υπηρεσίες σου να είναι κατανοητές.</li>
  <li><strong>Λύσεις που δουλεύουν</strong>: Οι επισκέπτες βρίσκουν αυτό που ψάχνουν γρήγορα, παίρνουν δράση, και γίνονται πελάτες.</li>
  <li><strong>Χωρίς περιττά στοιχεία</strong>: Κάθε σελίδα και πληροφορία εξυπηρετεί έναν σκοπό. Αυτό δεν σημαίνει ότι το site είναι απαραίτητα απλό ή minimal—τα ωραία γραφικά εξυπηρετούν και αυτά σκοπό.</li>
</ul>

<h2 id="δεν-ξεκίνησα-ως-designer">Δεν ξεκίνησα ως designer</h2>

<p>Πριν το web development δούλευα σε supply chain και operations. Έχω δει πρώτο χέρι πώς κακοσχεδιασμένα συστήματα σπαταλούν χρόνο και χρήμα. Το ίδιο ισχύει και για website — αν δεν δουλεύει, κοστίζει.</p>

<p>Δεν έχω στόχο να φτιάχνω «ωραία» site που δεν κάνουν τίποτα, αλλά όμορφα και χρηστικά εργαλεία που δουλεύουν.</p>

<h2 id="site-που-φέρνει-πελάτες">Site που φέρνει πελάτες</h2>

<ul>
  <li>Τιμή για site 1-3 σελίδων: <strong>1.000 €</strong></li>
  <li>Για πολυσέλιδα projects: <strong>2.000-3.000 €</strong> ή παραπάνω ανάλογα την πολυπλοκότητα</li>
</ul>

<p>Αυτό περιλαμβάνει:</p>

<ul>
  <li>Ανάλυση του χώρου σου και του ανταγωνισμού</li>
  <li>Στρατηγικό σχεδιασμό και προγραμματισμό από το μηδέν</li>
  <li>Βελτιστοποίηση για όλες τις συσκευές</li>
  <li>Συγγραφή ή βελτίωση κειμένων, δημιουργία εικόνων κατάλληλων για web</li>
  <li>Μπόλικο testing για να μην υπάρχουν εκπλήξεις</li>
</ul>

<p>Θα μπορούσα να φτιάχνω copy-paste sites με template, να τελειώνω γρήγορα και να πληρώνομαι το ίδιο. Αλλά δεν μπορώ να το κάνω με ήσυχη συνείδηση.</p>

<h2 id="εν-κατακλείδι">Εν κατακλείδι</h2>

<p>Αν θες ένα site απλά για να υπάρχει, δεν είμαι η σωστή επιλογή. Αν θες ένα site που να δουλεύει για σένα, θα χαρώ να μιλήσουμε.</p>

<hr />

<p><a href="/en/contact/">Στοιχεία επικοινωνίας →</a></p>

<p><a href="/en">Αρχική σελίδα (Αγγλικά) →</a></p>

<!-- [English version →](/en/mle) -->]]></content><author><name></name></author><category term="el" /><category term="business" /><summary type="html"><![CDATA[Πελάτης μου στον χώρο μεταφορών είχε ήδη site. Αρχική σελίδα με καρουζέλ γεμάτο stock φωτογραφίες (συμπεριλαμβανομένης μίας που έδειχνε ζευγάρι να κοιτάει χάρτη, πρόσωπα εκτώς πλάνου).]]></summary></entry><entry xml:lang="en"><title type="html">A case study on The Newsroom: Reducing bias in news reporting</title><link href="https://mostuffa.com/en/newsroom" rel="alternate" type="text/html" title="A case study on The Newsroom: Reducing bias in news reporting" /><published>2023-03-23T00:00:00+00:00</published><updated>2023-03-23T00:00:00+00:00</updated><id>https://mostuffa.com/en/newsroom</id><content type="html" xml:base="https://mostuffa.com/en/newsroom"><![CDATA[]]></content><author><name></name></author><category term="en" /><category term="case study" /><summary type="html"><![CDATA[]]></summary></entry><entry xml:lang="en"><title type="html">Time Tracker Concept</title><link href="https://mostuffa.com/en/time-tracker-concept" rel="alternate" type="text/html" title="Time Tracker Concept" /><published>2023-01-10T00:00:00+00:00</published><updated>2023-01-10T00:00:00+00:00</updated><id>https://mostuffa.com/en/time-tracker-concept</id><content type="html" xml:base="https://mostuffa.com/en/time-tracker-concept"><![CDATA[]]></content><author><name></name></author><category term="en" /><category term="case study" /><summary type="html"><![CDATA[]]></summary></entry></feed>