MoreRSS

site iconThe Practical DeveloperModify

A constructive and inclusive social network for software developers.
Please copy the RSS to your reader, or quickly subscribe to:

Inoreader Feedly Follow Feedbin Local Reader

Rss preview of Blog of The Practical Developer

From 10 Millions Monthly Orders to Reality: Architecting a Production-Grade E-commerce Platform on Azure Kubernetes

2025-11-10 03:19:46

How we sized a bulletproof AKS cluster for 10 million monthly orders using real-world battle stories from JD.com, Shopify, and Grab

The Challenge That Started It All

Picture this: You're tasked with architecting an e-commerce platform that needs to handle 10 million orders monthly, serve 4,000 concurrent users, and manage 20-30 microservices. The kicker? It has to survive Black Friday flash sales, scale automatically, and not break the bank.

Sound familiar? This is the exact challenge I tackled, and here's the story of how I designed a production-ready Azure Kubernetes Service (AKS) cluster—backed by real battle-tested architectures from the biggest names in tech.

📊 The Numbers That Matter

Before diving into solutions, let's break down what we're really dealing with:

  • 10,000,000 orders/month = 333,333 orders/day
  • 3.86 orders per second (average) → 13.5 orders/sec at peak (3.5× multiplier)
  • 4,000 concurrent users baseline → 14,000 at peak
  • 25 microservices (mix of frontend, backend, and background jobs)

The big question: How do you size infrastructure that's neither over-provisioned (wasting money) nor under-provisioned (causing outages)?

🔍 Learning from the Giants: Real-World Reference Cases

Instead of guessing, I studied how the world's largest platforms handle similar—and much larger—scales. Here's what I found:

1. American Chase: The E-commerce Success Story

The most relevant case was American Chase's AKS migration for a global e-commerce retailer. Their results were stunning:

  • 99.99% uptime during peak sales (vs. previous crashes)
  • 60% faster checkout speeds
  • 30% cost savings through autoscaling
  • 6-month migration (4 weeks assessment, 3 months implementation)

Key Takeaway: They proved that Azure's managed control plane + pod/node autoscaling is the pattern for e-commerce reliability.

2. JD.com: The World's Largest Kubernetes Cluster

JD.com runs the world's most massive Kubernetes deployment, handling Singles Day 2018:

  • 460,000 pods at peak 🤯
  • 24,188 orders per second (our 13.5 TPS is 0.056% of their scale)
  • 3 million CPU cores
  • 20-30% IT cost efficiency improvement

Key Insight: Even at our "smaller" scale, JD.com's architectural patterns—pod density ratios, autoscaling strategies, resource allocation—apply directly.

3. Shopify: Mastering Flash Sales

Shopify's custom autoscaler handles Black Friday/Cyber Monday like a champ:

  • Flash sale duration: 15-20 minutes with 100-500× traffic spikes
  • Problem: Standard autoscaling too slow (2-20 min scale-up vs. flash sale already over)
  • Solution: Exponentially Weighted Average (EWA) CPU metrics for faster detection

Application: Our conservative 3.5× multiplier works with standard HPA. But if you anticipate 10×+ spikes? Consider Shopify's approach.

4. Grab: The Most Comparable Scale

Grab's superapp infrastructure in Southeast Asia was the closest match:

  • 100 orders per second (vs. our 13.5 TPS peak)
  • 41.9 million monthly users across 8 countries
  • 400+ microservices on AWS EKS with Istio

Validation: Grab proves that our 13.5 TPS peak is easily manageable—we're at 13.5% of their proven baseline capacity.

🏗️ The Architecture: Breaking It Down

Pod Distribution Strategy

I organized workloads into three logical tiers:

Frontend/API Tier (50 pods baseline)
├─ Web interface
├─ API gateway  
├─ Session management
├─ Authentication
└─ Shopping cart
→ Concurrency: 80 users per pod
→ Resources: 0.5 CPU, 1.0 GB RAM per pod

Backend Tier (30 pods baseline)
├─ Payment processing
├─ Order orchestration
├─ Inventory management
├─ Notification service
└─ Analytics pipeline
→ Throughput: 30-40 orders/sec per pod
→ Resources: 1.0 CPU, 2.0 GB RAM per pod

Background Jobs (10 pods baseline)
├─ Email notifications
├─ Report generation
├─ Data synchronization
└─ Webhook processing
→ Resources: 0.5 CPU, 1.5 GB RAM per pod

System Services (30 pods fixed)
├─ Prometheus + Grafana
├─ Fluentd logging
├─ NGINX Ingress
└─ CoreDNS
→ Resources: 0.25 CPU, 0.5 GB RAM per pod

Total Baseline: 120 pods consuming 67.5 CPU cores and 140 GB RAM

At Peak (3.5× scale): 420 pods consuming ~236 CPU cores and ~490 GB RAM

Node Pool Architecture: The Secret Sauce

Instead of a homogeneous cluster, I used 4 dedicated node pools (inspired by Uber's massive Kubernetes clusters):

Pool Nodes VM Type vCPU RAM Purpose
System 3 D16ds_v5 48 192 GB K8s services, monitoring, ingress
Frontend 4 D8ds_v5 32 128 GB User-facing APIs, web tier
Backend 3 E16ds_v5 (memory-opt) 48 192 GB Databases, caches, data processing
Jobs 2 D8ds_v5 16 64 GB Async processing, batch jobs
TOTAL 12 - 144 576 GB -

Why memory-optimized for backend? Redis caches, MySQL buffer pools, Kafka queues—all memory-hungry. The E16ds_v5 series gives us 1:4 CPU:RAM ratio (vs. 1:2 for D-series).

💡 The Rationale: Why These Numbers?

1. Headroom Philosophy

CPU Headroom: 51.9%
Memory Headroom: 68.8%

"Isn't that wasteful?" you might ask. Here's why it's critical:

  • Flash Sale Scaling (3.5×): 120 → 420 pods in 2-5 minutes
  • Zero-Downtime Deployments: Rolling updates duplicate pods temporarily
  • Node Failures: Single node down = 10% capacity loss, absorbed gracefully
  • Organic Growth: 20-40% YoY order growth typical
  • Unknown Unknowns: Real-world traffic always exceeds predictions

Pinterest's 80% capacity reclamation during off-peak validates this approach—autoscaling makes headroom cost-effective.

2. The Master Nodes Mystery

Short answer: You don't provision them.

Azure AKS uses a managed control plane—Azure runs the masters (API server, etcd, scheduler, controllers) for you:

  • 99.95% SLA backed by Azure
  • Auto-scales as your cluster grows
  • Multi-zone failover built-in
  • Cost: $0 (included in AKS)

This is a massive operational win vs. self-managed Kubernetes.

3. Autoscaling: The Double Layer

Layer 1: Horizontal Pod Autoscaler (HPA)

Frontend Services:
  Target CPU: 70%
  Min Replicas: 3
  Max Replicas: 20 per service
  Scale-up: 1 minute
  Scale-down: 3 minutes

Layer 2: Cluster Autoscaler

Settings:
  Scale-down delay: 10 minutes (prevent thrashing)
  New pod scale-up: 0 seconds (immediate)
  Max unready %: 45% (graceful degradation)

This two-layer approach is exactly what American Chase used to achieve 99.99% uptime during traffic surges.

💰 Cost Reality Check

Scenario Monthly Cost Annual Cost Savings
Baseline (Pay-as-you-go) $12,600 $151,200 0%
1-Year Reserved Instances $8,100 $97,200 35.6%
Reserved + Spot VMs $8,220 $98,640 34.8%

Pro tip: Start pay-as-you-go, collect 4 weeks of real metrics, then purchase Reserved Instances based on actual baseline usage. Save an additional 15-25% with Vertical Pod Autoscaler (VPA) right-sizing.

📈 Performance Expectations

Load Scenario Pods Nodes Avg Response P99 Response Success Rate
Baseline (3.86 TPS) 120 12 <200ms <300ms 99.99%
Peak (13.5 TPS, 3.5×) 420 18-20 <300ms <500ms 99.99%
Flash Sale (50 TPS, 13×) N/A N/A Degraded >2s 99.5-99.8%

Note: The 50 TPS flash sale scenario exceeds our 3.5× design. For those events, consider load shedding (graceful degradation) or a secondary burst cluster.

🚀 Key Takeaways

Conservative sizing prevents outages: 51.9% CPU + 68.8% memory headroom isn't waste—it's insurance

Learn from battle-tested architectures: JD.com, Shopify, Grab, and American Chase all validate this approach

Autoscaling is non-negotiable: Both pod-level (HPA) and node-level (Cluster Autoscaler) required

Cost optimization is iterative: Start pay-as-you-go, measure for 4 weeks, then optimize with Reserved Instances

Validation matters: Our 13.5 TPS peak is 13.5% of Grab's proven 100 TPS baseline—plenty of validation

🔗 Resources

Enhancing ChatGPT Results by Removing the 'Nice' Filter

2025-11-10 03:19:06

Deep Dive into AI Prompt Engineering: Enhancing ChatGPT Outputs by Disabling the 'Nice' Filter

Users are experimenting with advanced techniques to get more out of AI models. One notable approach involves modifying ChatGPT's behavior by disabling its default 'nice' filter. This seemingly simple change can lead to significantly improved results, offering more direct, concise, and potentially more insightful responses.

Why this works:
By default, AI models like ChatGPT are trained with safety and politeness guidelines. While crucial for general use, these constraints can sometimes hinder performance when specific, unfiltered information or direct problem-solving is required. Removing the 'nice' filter allows the model to bypass these politeness checks, leading to responses that are less concerned with social niceties and more focused on delivering the requested information accurately and efficiently.

Use Cases:
This technique can be particularly beneficial for:

  • Technical troubleshooting and debugging
  • Complex data analysis requests
  • Generating concise code snippets or explanations
  • Exploring nuanced theoretical concepts

It’s a powerful reminder that understanding and manipulating AI parameters can unlock new levels of utility. This isn't about making the AI 'rude', but about optimizing its output for specific, often technical, objectives.

Stelixx #StelixxInsights #IdeaToImpact #AI #BuilderCommunity #ChatGPT

Mastering the Options Pattern in .NET — Strongly Typed Configuration Made Simple

2025-11-10 03:13:12

When building modern applications with .NET, configuration management is one of the most critical design aspects.

Instead of spreading configuration keys like API URLs or SMTP credentials across your codebase, .NET provides a clean, strongly typed, and dependency-injection-friendly solution: the Options Pattern.

Let’s explore this pattern in detail and see how to use it properly in real-world applications.

What Is the Options Pattern?

The Options Pattern allows you to represent configuration settings as strongly typed classes that can be easily injected and validated.

Instead of calling Configuration["SomeKey"], you can map a JSON configuration section directly to a C# class.

Example Scenario — SMTP Settings

Here’s an example appsettings.json configuration:

{
  "SmtpSettings": {
    "Server": "smtp.gmail.com",
    "Port": 587,
    "Username": "[email protected]",
    "Password": "mypassword"
  }
}

Step 1 — Define a Strongly Typed Configuration Class

public class SmtpSettings
{
    public string Server { get; set; } = string.Empty;
    public int Port { get; set; }
    public string Username { get; set; } = string.Empty;
    public string Password { get; set; } = string.Empty;
}

Step 2 — Register Configuration in Program.cs

In .NET 6+:

var builder = WebApplication.CreateBuilder(args);

builder.Services.Configure<SmtpSettings>(
    builder.Configuration.GetSection("SmtpSettings")
);

var app = builder.Build();

Now your configuration is available through the DI system.

Step 3 — Access Configuration via Dependency Injection

There are three interfaces to access Options in .NET:

  • IOptions<T> — static, read once at startup
  • IOptionsSnapshot<T> — reloads per request (scoped)
  • IOptionsMonitor<T> — observes live changes (singleton)

Let’s break them down

IOptions<T> — Static Configuration

using Microsoft.Extensions.Options;

public class EmailService
{
    private readonly SmtpSettings _settings;

    public EmailService(IOptions<SmtpSettings> options)
    {
        _settings = options.Value;
    }

    public void SendEmail()
    {
        Console.WriteLine($"Using SMTP server: {_settings.Server}:{_settings.Port}");
    }
}

Best for static configuration that never changes during the app’s lifetime.

IOptionsSnapshot<T> — Per Request Reload

IOptionsSnapshot reloads values automatically for each web request, making it ideal for ASP.NET Core applications.

public class EmailController : ControllerBase
{
    private readonly SmtpSettings _settings;

    public EmailController(IOptionsSnapshot<SmtpSettings> options)
    {
        _settings = options.Value;
    }

    [HttpGet("send")]
    public IActionResult SendEmail()
    {
        return Ok($"SMTP Server: {_settings.Server}");
    }
}

Use this in web apps where configuration might change between requests.

IOptionsMonitor<T> — Real-time Change Notifications

IOptionsMonitor provides live reload and change notification support.

public class EmailBackgroundService
{
    private readonly IOptionsMonitor<SmtpSettings> _monitor;

    public EmailBackgroundService(IOptionsMonitor<SmtpSettings> monitor)
    {
        _monitor = monitor;

        _monitor.OnChange(settings =>
        {
            Console.WriteLine($"SMTP settings changed! New server: {settings.Server}");
        });
    }

    public void SendEmail()
    {
        var settings = _monitor.CurrentValue;
        Console.WriteLine($"Sending email via {settings.Server}");
    }
}

Best for background services or long-running processes that must react immediately to configuration updates.

Options Interface Comparison

Interface Lifetime Auto Reload Ideal Use Case
IOptions<T> Singleton ❌ No Static configuration
IOptionsSnapshot<T> Scoped ✅ Per Request ASP.NET Core apps
IOptionsMonitor<T> Singleton ✅ Real-time Background jobs, daemons

Named Options — Multiple Configurations

You can manage multiple sets of configurations (for example, Gmail and Outlook) using named options:

builder.Services.Configure<SmtpSettings>("Gmail", builder.Configuration.GetSection("SmtpGmail"));
builder.Services.Configure<SmtpSettings>("Outlook", builder.Configuration.GetSection("SmtpOutlook"));

Then:

public class EmailService
{
    private readonly IOptionsSnapshot<SmtpSettings> _options;

    public EmailService(IOptionsSnapshot<SmtpSettings> options)
    {
        _options = options;
    }

    public void SendViaGmail()
    {
        var gmail = _options.Get("Gmail");
        Console.WriteLine($"Sending via Gmail: {gmail.Server}");
    }
}

Validating Options

It’s good practice to validate configuration values during startup.

builder.Services
    .AddOptions<SmtpSettings>()
    .Bind(builder.Configuration.GetSection("SmtpSettings"))
    .Validate(settings => settings.Port > 0, "Port must be greater than 0")
    .ValidateDataAnnotations()
    .ValidateOnStart();

This ensures invalid configuration will throw an exception at startup, not at runtime.

Benefits of Using the Options Pattern

Benefit Description
Strongly Typed Compile-time safety for configuration keys
DI Integration Works naturally with .NET’s dependency injection
Supports Reload IOptionsMonitor and IOptionsSnapshot can refresh automatically
Separation of Concerns Keeps configuration separate from business logic
Testable Easy to mock in unit tests

Best Practices

  1. Prefer strongly typed options classes over raw Configuration access.
  2. Use IOptionsSnapshot for web requests and IOptionsMonitor for background services.
  3. Add validation using ValidateOnStart() and data annotations.
  4. Don’t store secrets in appsettings.json — use User Secrets, Azure Key Vault, or environment variables.
  5. Organize your configuration sections logically (one class per section).

Final Thoughts

The Options Pattern in .NET provides a robust, clean, and scalable approach to configuration management.
It simplifies how you handle settings, supports automatic reloads, and integrates perfectly with .NET’s dependency injection system.

Once you adopt it, configuration management becomes safer, more maintainable, and more professional.

download sample code from github

I’m Morteza Jangjoo and “Explaining things I wish someone had explained to me”

Smart Template Revolution in WebForms Core 2

2025-11-10 03:12:46

So far, we have presented some of the features and capabilities of WebForms Core version 2. What you have seen so far is just the tip of the iceberg; WebForms Core 2 will revolutionize the web industry.
Given its depth and breadth, this technology has the following capabilities:

  1. Redefining web application development standards
  2. Reducing dependency on heavy front-end frameworks
  3. Returning to server-centric architectures with modern capabilities
  4. Democratizing complex application development

Our team at Elanat is introducing a complete transformation in the web development paradigm, not just another framework.

Get ready to see:

  • Architectures we thought were “impossible”

  • Simplifications that seemed “fantasy”

  • Performances that were thought to be “unattainable”

This is just the beginning!

Continuing with the features of version 2, in this article we want to expose the new feature of extracting HTML tags from a source (URL).

Extract HTML tags

One of the new features in version 2 of the WebForms Core technology is extracting HTML tags from sources (URLs). This feature allows you to create entire HTML Templates in a single large file and extract the desired templates.

WebForms Core Template

This new feature is accessible by using the "LoadHtml" method in the WebForms class on the server.

Fetch.LoadHtml(Url, FetchInputPlace, FetchScript = false)

Url: Path to the external HTML template file.
FetchInputPlace: Specifies which template(s) to extract from the file. It has the same structure as InputPlace but is used for external templates.
FetchScript: Optional boolean to include or exclude scripts.

Example

HTML template ("/template/content.html")

<template id="Article">
  <section>
    <h2>@ArticleTitle</h2>
    <p>@ArticleText</p>
  </section>
</template>

<template id="Video">
  <section>
    <h2>@VideoTitle</h2>
    <video controls>
      <source src="@VideoPath" type="video/mp4">
      @VideoFallbackText
    </video>
  </section>
</template>

<template id="Link">
  <section>
    <h2>@LinksTitle</h2>
    <a href="@Link1Url">@Link1Text</a></li>
  </section>
</template>

The above example shows a quality template for all types of content. Here, each section is placed inside a section tag and each section is added inside a template tag with a unique id. This template is structured and created for professional work; you are free to create the template however you like, however, we at Elanat recommend following this structured pattern.

Server code

form.AddText("<main>", Fetch.LoadHtml("/template/content.html", "Video|<section>"));
form.Replace("<main>|<section>-1", "@VideoTitle", "My video", false, true);
form.Replace("-", "@VideoPath", "/video/video1.mp4", false, true);
form.Replace("-", "@VideoFallbackText", "Your browser doesn't support HTML5 video.", false, true);

Explanation:

  1. Fetch.LoadHtml loads the <section> from the "Video" template.
  2. form.Replace replaces the placeholders (@VideoTitle, @VideoPath, etc.) with real values.
  3. The resulting HTML is dynamically rendered on the page.

Result

<!DOCTYPE html>
<html>
<head>
  <title>Page Title</title>
  <script type="text/javascript" src="/script/web-forms.js"></script>
</head>
<body>
  <h1>This is a Heading</h1>
  <p>This is a paragraph.</p>
  <main>
    <section>
      <h2>My video</h2>
      <video controls>
        <source src="/video/video1.mp4" type="video/mp4">
        Your browser doesn't support HTML5 video.
      </video>
    </section>
  </main>
</body>
</html>
  • This produces ready-to-display HTML with dynamic content.
  • You can repeat the process for multiple templates (Article, Link, etc.) in the same page.

Note: If you have enabled client caching on the server side, templates are requested from the server only once. Of course, you can also create dynamic templates on the server.

Comparison to Modern Tools

Feature WebForms Core 2 React / Vue Blazor Server
HTML Templates External, server-extracted Component-based JSX / Vue templates Server-rendered
Server Interaction Built-in API calls / Fetch Server HTML updates
Learning Curve Low (HTML + server logic) High Moderate
Performance High (minimal client JS) Depends on build & hydration Moderate to Low
Real-Time Built-in (WebSocket & SSE) WebSocket / manual setup Optional

What’s Innovative Here

1. External HTML Templating

Instead of embedding HTML directly in your server-side logic, LoadHtml allows you to fetch and extract specific templates from remote or local HTML files.
This makes your UI layer:

  • Modular and maintainable — ensuring a clear separation between structure and logic
  • Easily editable by designers without requiring any server-side code changes
  • Cacheable — templates are fetched once and efficiently reused

It’s reminiscent of modern component-based architectures such as React or Vue — but executed entirely on the server side.

2. Server SPA — Without Frontend SPA Complexity

By introducing the concept of “Server Command / Client Execution”, WebForms Core 2 enables the delivery of even the most advanced front-end capabilities through purely server-side control.
This modern templating model redefines full-stack development by restoring simplicity and coherence:

  • No heavy JavaScript frameworks required
  • Real-time capabilities (via SSE or WebSocket) cover the same ground as reactive SPAs
  • Extends the traditional server-side model to a new level — powerful enough to replace many front-end frameworks in practice

In essence, it achieves SPA-like interactivity without SPA-level complexity.

3. Dynamic Placeholder Replacement

The syntax:

form.Replace("-", "@VideoPath", "/video/video1.mp4", false, true);

illustrates data binding within pure HTML templates, using placeholder constructs such as @Placeholder, {{Placeholder}}, or <%Placeholder%>, which are replaced dynamically at render time — clean, explicit, and framework-agnostic.

This allows for flexible, server-driven rendering while maintaining clear and readable markup.

Comparison: React Component vs WebForms Core 2 Template

Feature React Component WebForms Core 2 Template Explanation / Analysis
🧭 Execution Environment Browser (Client-side) On the client after receiving the server command React renders the UI in the browser, WebForms Core is also the responsible client.
🧩 Core Nature A function of data to produce UI (UI = f(state)) HTML template with placeholders replaced at render time Both produce UI output based on input data (state or placeholders). Placeholders in WebForms Core are more flexible.
🧱 Purpose Build interactive, reusable UI on the client Build modular, reusable HTML templates on the server Both focus on modularity and reusability.
⚙️ Dependency on JavaScript High — fully JS-based Without writing JavaScript WebForms Core delivers similar flexibility without heavy client-side JS.
🧠 Data Mechanism props, state, hooks @Placeholders or methods like Replace() Both inject data into the template/component to produce dynamic output.
🔁 Re-rendering Happens in the browser when state changes Happens on the server per request or via SSE updates React is reactive on the client; WebForms Core is reactive on the server.
🧩 Composition Components can be nested (<Button /> inside <Form />) Templates can be loaded and combined (LoadHtml) The concept of composition is central in both architectures.
🧰 Development Tools JSX, Virtual DOM, React Hooks Template Loader, Fetch/Replace, Server Command Different toolsets, same goal: controlling and regenerating UI efficiently.
Performance Fast on the client, requires hydration Fast on the server, automatic hydration in client React has heavier initial load; WebForms Core is lighter but server-driven.
🔌 Real-Time / Interaction Via WebSocket or React state Via SSE & WebSocket Both support real-time updates, but via different mechanisms.
🔒 SEO / Indexing Requires SSR for SEO optimization Fully SEO-friendly In WebForms Core, you can first present the data on the page and then use the Template.
🧠 Design Philosophy “UI is a function of state” “Template is a function of data” Philosophically very similar; the difference is primarily the execution environment.
🧱 Structure Type Component Tree on the client Template Hierarchy on the server Both use a hierarchical structure to manage UI effectively.

Conclusion

The LoadHtml feature represents a forward-thinking leap that fuses the simplicity of server-centric architectures with the flexibility of modular HTML templating.

This Smart Template Revolution is not just a new feature — it’s a thoughtful reimagining of how server-side rendering can meet modern web demands:

✅ Clean, external HTML templates
✅ Server-driven rendering
✅ Cacheable, composable UI elements
✅ Minimal JavaScript dependency

Ultimately, WebForms Core 2 bridges the gap between traditional simplicity and modern flexibility — something that no web framework has achieved so far.

Becoming a Full Stack Developer Day 2

2025-11-10 03:10:53

Made 4 mini projects using html, css and js

  1. Guessing number game generated my math random module
  2. color match background changer on click
  3. Simple clock
  4. BMI Calculator




learnt about anaconda and mini conda

  1. Anaconda - Full distribution with hundreds of packages for data science and machine learning
  2. Mini Conda - Lightweight version of anaconda

ArtistAssistApp New Features and Improvements – November 2025

2025-11-10 03:09:45

ArtistAssistApp, also known as Artist Assist App, is a web app for artists to accurately mix any color from a photo, analyze tonal values, turn a photo into an outline, draw with the grid method, paint with a limited palette, simplify a photo, remove the background from an image, compare photos pairwise, and more.

Hello, artists! I am pleased to announce the latest update to the ArtistAssistApp, released in November 2025. This time, there are some major new features in addition to the usual stability and performance improvements.

Let's take a look at what's new since the last major update in August 2025!

  • Adjusting White Balance Using the Percentile and Reference Methods
  • Add Margins for the Tape When Printing the Outline on Multiple Pages
  • Color Temperature Estimation: Warm and Cool Colors
  • Automatic Backup of Color Sets

Adjusting White Balance Using the Percentile and Reference Methods

We've improved how you adjust white balance in your photos!

Choose from two White balance method:

  • Percentile: Auto white balance from brightest areas, good for most photos.
  • Reference: Manual white balance using selected white area.

If you select the Percentile white balance method, the white balance will be adjusted automatically. If needed, move the Percentile slider to further adjust the white balance of the photo. Smaller Percentile values correspond to stronger whitening.

If you select the Reference white balance method, click or tap anywhere in the photo to choose a white point. For best results, instead of a single pixel, a small area is sampled, and the average color of that area is used as the white point.

This update gives you more control and better results when color-correcting your artwork or reference photos!

White Balance Adjustment in ArtistAssistApp

White Balance Adjustment in ArtistAssistApp

Add Margins for the Tape When Printing the Outline on Multiple Pages

If you tape the paper to the base, take the tape width (e.g., 1 cm) into account when printing the outline. You can control the tape's size with the Margin setting. The default value is 0, meaning no margin.

ArtistAssistApp Printing Image Outline With Margins

Color Temperature Estimation: Warm and Cool Colors

ArtistAssistApp algorithmically estimates the color temperature, whether it is warm, cool, or neutral, and shows the corresponding symbol next to the color name. You can choose a color mixing recipe based on color temperature, or create your own color set by selecting colors with the desired temperature.

ArtistAssistApp Color Temperature Estimation: Warm and Cool Colors

Automatic Backup of Color Sets

To protect your work, ArtistAssistApp automatically exports a backup file (Color-Sets-[date_time].clrs) whenever you modify your color sets. This file is downloaded to your device's default Downloads folder, independent of browser storage.
Thanks to the auto-backup feature, you can restore all color sets with a single click of the Load color sets file button, even after unintentionally clearing the web browser storage, which results in the loss of all application data, including all your color sets.

ArtistAssistApp Automatic Backup of Color Sets

To enable or disable automatic backup of color sets, go to the Help tab and enable or disable the Automatic backup of color sets feature.

ArtistAssistApp Automatic Backup of Color Sets