<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: GeekyAnts</title>
    <description>The latest articles on DEV Community by GeekyAnts (geekyants).</description>
    <link>https://dev.to/geekyants</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F12611%2F12ba258b-c1e8-4802-9a86-9447eacb706a.png</url>
      <title>DEV Community: GeekyAnts</title>
      <link>https://dev.to/geekyants</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/geekyants"/>
    <language>en</language>
    <item>
      <title>Building a Production-Ready Canva-like Editor with Konva.js, React 19 and Next.js 15</title>
      <dc:creator>GeekyAnts India Pvt Ltd</dc:creator>
      <pubDate>Thu, 10 Sep 2026 10:31:18 +0000</pubDate>
      <link>https://dev.to/geekyants/building-a-production-ready-canva-like-editor-with-konvajs-react-19-and-nextjs-15-3imd</link>
      <guid>https://dev.to/geekyants/building-a-production-ready-canva-like-editor-with-konvajs-react-19-and-nextjs-15-3imd</guid>
      <description>&lt;p&gt;This blog explains how to build a production-ready canvas editor with&lt;br&gt;
Konva.js, React, and Next.js, covering architecture, performance, and&lt;br&gt;
key engineering decisions.&lt;/p&gt;

&lt;p&gt;Author: Priyanka Rokhade, Software Engineer III&lt;br&gt;
Subject Matter Expert: Deepanshu Goyal, Senior Software Engineer -&lt;br&gt;
III&lt;/p&gt;

&lt;p&gt;Executive Summary: Why Build an In-App Canvas Editor?&lt;/p&gt;

&lt;p&gt;Modern SaaS&lt;br&gt;
applications&lt;br&gt;
increasingly require users to create visually rich documents directly&lt;br&gt;
inside the browser. Whether it is travel itineraries, reports,&lt;br&gt;
certificates, brochures, or marketing collateral, users expect the same&lt;br&gt;
drag-and-drop experience offered by tools like Canva---but without&lt;br&gt;
leaving the application.&lt;/p&gt;

&lt;p&gt;Our challenge was straightforward:&lt;/p&gt;

&lt;p&gt;"How do we build a Canva-like editor that feels native, performs&lt;br&gt;
smoothly, and integrates seamlessly with our product?"&lt;/p&gt;

&lt;p&gt;After evaluating multiple approaches---including embedded design&lt;br&gt;
tools,&lt;br&gt;
HTML-based editors, and a fully custom canvas engine---we built our&lt;br&gt;
editor on Konva.js + React-Konva.&lt;/p&gt;

&lt;p&gt;The result was a production-ready editor capable of:&lt;/p&gt;

&lt;p&gt;60 FPS interaction&lt;/p&gt;

&lt;p&gt;250+ canvas objects&lt;/p&gt;

&lt;p&gt;Rich text editing&lt;/p&gt;

&lt;p&gt;Autosave&lt;/p&gt;

&lt;p&gt;Multi-page documents&lt;/p&gt;

&lt;p&gt;Responsive previews&lt;/p&gt;

&lt;p&gt;Pixel-perfect rendering between editor and viewer&lt;/p&gt;

&lt;p&gt;This article presents the architecture, design&lt;br&gt;
decisions,&lt;br&gt;
production challenges, and engineering lessons behind building a&lt;br&gt;
production-ready canvas editor.&lt;/p&gt;

&lt;p&gt;Business Objectives&lt;/p&gt;

&lt;p&gt;Beyond replicating Canva-like functionality, the primary objective was&lt;br&gt;
to eliminate dependence on external design tools and bring document&lt;br&gt;
creation directly into our platform. By integrating editing, previewing,&lt;br&gt;
and publishing into a single workflow, the editor reduces operational&lt;br&gt;
overhead, shortens content turnaround time, and enables teams to create&lt;br&gt;
production-ready documents without switching between multiple&lt;br&gt;
applications. This also gives the product team complete control over the&lt;br&gt;
editing experience, data ownership, and future feature development.&lt;/p&gt;

&lt;p&gt;Why We Chose Konva.js Over Other Alternatives&lt;/p&gt;

&lt;p&gt;When we started designing the editor, we evaluated three possible&lt;br&gt;
approaches.&lt;/p&gt;

&lt;p&gt;At first glance, embedding a tool such as Canva or Figma looked&lt;br&gt;
attractive because this approach reduced implementation effort. However,&lt;br&gt;
licensing costs, limited customization, and data ownership concerns&lt;br&gt;
quickly ruled it out.&lt;/p&gt;

&lt;p&gt;Next, we experimented with HTML-based editors built using absolutely&lt;br&gt;
positioned &lt;/p&gt; elements. Although this worked for simple layouts,&lt;br&gt;
performance degraded significantly as documents became more complex.

&lt;p&gt;Ultimately, we chose Konva.js because it provided a scene graph&lt;br&gt;
architecture, high-performance rendering, and complete control over the&lt;br&gt;
editing experience.&lt;/p&gt;

&lt;p&gt;When evaluating how to build this visual editor, we assessed three&lt;br&gt;
architectural paths:&lt;/p&gt;

&lt;p&gt;Architectural Approach  How It Works            Why It Succeeded or&lt;br&gt;
Failed in Production&lt;/p&gt;

&lt;p&gt;Third-Party Embeds      Embeds an external      Failed: High recurring&lt;br&gt;
(e.g.&amp;nbsp;Canva / Figma SDK design tool inside our  per-user licensing&lt;br&gt;
via iFrame)             web page using an       fees; user data lives&lt;br&gt;
iFrame.                 on external servers;&lt;br&gt;
inability to build&lt;br&gt;
custom domain features&lt;br&gt;
such as custom torn&lt;br&gt;
image frames, Unsplash&lt;br&gt;
search panel, and&lt;br&gt;
specific Google Font&lt;br&gt;
pickers.&lt;/p&gt;

&lt;p&gt;HTML/DOM-Based Editors  Renders elements as     Failed: When a document&lt;br&gt;
(e.g.&amp;nbsp;GrapesJS /        standard HTML &lt;/p&gt;   contains 50+ elements&lt;br&gt;
Absolute CSS Divs)      tags positioned with    with rotations, drop&lt;br&gt;
CSS.                    shadows, and masks, DOM&lt;br&gt;
repaints cause&lt;br&gt;
noticeable lag during&lt;br&gt;
dragging. Rotation and&lt;br&gt;
corner resize handle&lt;br&gt;
math also glitch across&lt;br&gt;
different web browsers.

&lt;p&gt;Practical Benefits of Our Konva.js Architecture&lt;/p&gt;

&lt;p&gt;100% Visual Fidelity (Zero Rendering Drift): Both the admin&lt;br&gt;
design editor and the public viewer application use the exact same&lt;br&gt;
Konva shape primitives (Konva.Text, Konva.Image, Konva.Rect). What&lt;br&gt;
the creator designs on their screen is 100% identical to what&lt;br&gt;
end-users see---no displaced text, shifting margins, or&lt;br&gt;
browser-specific rendering bugs.&lt;/p&gt;

&lt;p&gt;Lightweight Universal Canvas Format (UCF JSON): Instead of&lt;br&gt;
saving heavy image files or fragile HTML, our editor serializes&lt;br&gt;
document pages into clean, portable JSON, including item&lt;br&gt;
coordinates, font size, and fill colors. A complete 10-page document&lt;br&gt;
is under 15 KB, loads instantly, and is stored securely in our cloud&lt;br&gt;
database and object storage.&lt;/p&gt;

&lt;p&gt;Production Impact: Beyond the technical architecture, the editor&lt;br&gt;
delivered measurable improvements to our internal workflow: reduced&lt;br&gt;
document creation time from 1--2 days to under 15 minutes by&lt;br&gt;
eliminating external design tools; supports 250+ canvas objects&lt;br&gt;
while maintaining smooth 60 FPS interactions; replaced fragmented&lt;br&gt;
designer-to-operations workflows with a fully integrated in-app&lt;br&gt;
editing experience; and enabled creators to design, preview, and&lt;br&gt;
publish documents without leaving the platform.&lt;/p&gt;

&lt;p&gt;Customer Value: Enables operations teams to publish customer&lt;br&gt;
documents 95% faster. Eliminates dependence on external design&lt;br&gt;
tools. Keeps customer data inside the platform. Reduces onboarding&lt;br&gt;
time for non-design users.&lt;/p&gt;

&lt;p&gt;What the Editor Does&lt;/p&gt;

&lt;p&gt;The editor operates inside the web&lt;br&gt;
application&lt;br&gt;
workspace and enables users to:&lt;/p&gt;

&lt;p&gt;Compose multi-page visual documents featuring text, vector shapes,&lt;br&gt;
high-resolution photography, video clips, buttons, and hyperlinks.&lt;/p&gt;

&lt;p&gt;Drag, resize, rotate, and layer elements with pixel-level precision&lt;br&gt;
on an interactive 2D canvas.&lt;/p&gt;

&lt;p&gt;Apply custom Google Fonts, decorative frames (torn edge, square&lt;br&gt;
borders), mask clippings (circle, star, heart, diamond), image&lt;br&gt;
cropping, and character-level rich text formatting.&lt;/p&gt;

&lt;p&gt;Preview responsive layouts in real-time across web and mobile&lt;br&gt;
device&lt;br&gt;
viewports.&lt;/p&gt;

&lt;p&gt;Autosave design state with debouncing and publish completed&lt;br&gt;
documents directly to the client viewing application.&lt;/p&gt;

&lt;p&gt;Primary users: The editor is designed for internal operations teams,&lt;br&gt;
content creators, and administrators responsible for producing&lt;br&gt;
customer-facing documents. Instead of relying on external design&lt;br&gt;
software, users can create, review, and publish visual content directly&lt;br&gt;
within the application, reducing context switching and simplifying&lt;br&gt;
day-to-day workflows.&lt;/p&gt;

&lt;p&gt;Application scope: Integrated visual design module within the Admin&lt;br&gt;
Web Workspace.&lt;/p&gt;

&lt;p&gt;Why Konva?&lt;/p&gt;

&lt;p&gt;Konva provides decisive technical advantages for our production&lt;br&gt;
requirements:&lt;/p&gt;

&lt;p&gt;Scene Graph Hierarchy: A clean Stage → Layer → Group → Shape&lt;br&gt;
tree that maps 1:1 to document pages and layered canvas items.&lt;/p&gt;

&lt;p&gt;Built-in Drag, Transform &amp;amp; Hit Detection: Accelerated&lt;br&gt;
mathematical routines for drag-and-drop, multi-node rotation, corner&lt;br&gt;
scaling, and pointer hit detection.&lt;/p&gt;

&lt;p&gt;Interactive Transformer: Customizable bounding box with 8 anchor&lt;br&gt;
handles, rotation anchor, and aspect-ratio constraints out of the&lt;br&gt;
box.&lt;/p&gt;

&lt;p&gt;Declarative React Bindings: Allows canvas elements to be&lt;br&gt;
composed declaratively with standard React props, state hooks, and&lt;br&gt;
component lifecycles.&lt;/p&gt;

&lt;p&gt;Universal Canvas Format Serialization: Rather than storing the&lt;br&gt;
document as an image, we store every object as JSON. Each element&lt;br&gt;
records information such as position, size, color, font, rotation,&lt;br&gt;
and opacity. This lightweight format allows us to recreate the exact&lt;br&gt;
same document anywhere using Konva.&lt;/p&gt;

&lt;p&gt;Konva Fundamentals&lt;/p&gt;

&lt;p&gt;For developers exploring Konva, four foundational primitives form the&lt;br&gt;
foundation of our canvas architecture:&lt;/p&gt;

&lt;p&gt;Konva Concept           Core Responsibility     Implementation in Our&lt;br&gt;
Editor&lt;/p&gt;

&lt;p&gt;Stage                   The root canvas         One Konva Stage per&lt;br&gt;
container managing      document page inside&lt;br&gt;
global dimensions,      our canvas container.&lt;br&gt;
viewport scaling, and&lt;br&gt;
top-level mouse/touch&lt;br&gt;
events.&lt;/p&gt;

&lt;p&gt;Layer                   An independent HTML5 2D Three discrete layers:&lt;br&gt;
canvas drawing surface  Background layer,&lt;br&gt;
with isolated redraw    elements layer, and&lt;br&gt;
loops.                  transformer/UI overlay&lt;br&gt;
layer.&lt;/p&gt;

&lt;p&gt;Shape                   Drawable nodes on the   One Konva shape per&lt;br&gt;
canvas (Text, Rect,     document element&lt;br&gt;
Circle, Line, Arrow,    dispatched dynamically&lt;br&gt;
Image, Star, etc.).     via our shape rendering&lt;br&gt;
engine.&lt;/p&gt;

&lt;p&gt;Shape Registration: All required Konva shapes are registered at app&lt;br&gt;
initialization---including Rect, Circle, Ellipse, Text, Image, Line,&lt;br&gt;
Arrow, RegularPolygon, Star, Wedge, and Arc---ensuring tree-shaking&lt;br&gt;
keeps bundle size minimal while guaranteeing all element types render&lt;br&gt;
without runtime errors.&lt;/p&gt;

&lt;p&gt;Editor Architecture at a Glance&lt;/p&gt;

&lt;p&gt;The editor is engineered as a hybrid Next.js/React application wrapped&lt;br&gt;
around a high-performance Konva canvas. React governs the outer UI&lt;br&gt;
chrome, toolbar actions, sidebar panels, and state management, while&lt;br&gt;
Konva drives the 2D visual layout surface.&lt;/p&gt;

&lt;p&gt;Figure: High-Level Architecture: React UI Chrome, State Layer, Canvas&lt;br&gt;
Engine, and Output Pipeline&lt;/p&gt;

&lt;p&gt;The Hybrid Canvas Model&lt;/p&gt;

&lt;p&gt;One of the biggest engineering decisions was not using the canvas for&lt;br&gt;
everything. At first, we tried rendering every interaction directly&lt;br&gt;
inside Konva. It quickly became obvious that some browser features&lt;br&gt;
simply work better in the DOM.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;p&gt;Blinking text cursor&lt;/p&gt;

&lt;p&gt;Spell check&lt;/p&gt;

&lt;p&gt;Video controls&lt;/p&gt;

&lt;p&gt;Copy/paste&lt;/p&gt;

&lt;p&gt;Text selection&lt;/p&gt;

&lt;p&gt;Instead of fighting the browser, we built a Hybrid Canvas Architecture&lt;br&gt;
where Konva renders graphics while temporary HTML overlays handle&lt;br&gt;
editing.&lt;/p&gt;

&lt;p&gt;To combine the performance of canvas with the rich UX of the DOM, our&lt;br&gt;
editor implements a Hybrid Canvas Architecture:&lt;/p&gt;

&lt;p&gt;Figure: The Hybrid Canvas Architecture: Synchronized Konva Canvas and&lt;br&gt;
HTML DOM Overlays&lt;/p&gt;

&lt;p&gt;Why the Hybrid Model Matters&lt;/p&gt;

&lt;p&gt;Inline Text Editing: When a user double-clicks a text item, an&lt;br&gt;
invisible HTML  is mounted at the exact bounding box and&amp;lt;br&amp;gt;
rotation of the Konva text node---providing native cursor blinking,&amp;lt;br&amp;gt;
typing, and keyboard shortcuts.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Rich Text Formatting: Multi-range formatted text (bold, italic,&amp;lt;br&amp;gt;
underline per character slice) is painted directly onto the canvas&amp;lt;br&amp;gt;
via a custom sceneFunc (drawFormattedTextOnCanvas)---ensuring&amp;lt;br&amp;gt;
correct z-ordering without persistent DOM elements.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Video Playback: Video items display a poster thumbnail on&amp;lt;br&amp;gt;
canvas, while interactive playback, trimming, and audio controls&amp;lt;br&amp;gt;
appear in a synchronized DOM overlay.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Real-Time Overlay Synchronization: Floating toolbars and editing&amp;lt;br&amp;gt;
inputs continuously recalculate their CSS transforms during canvas&amp;lt;br&amp;gt;
panning, zooming, and item dragging.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Architectural Takeaway: By keeping DOM overlays transient (active&amp;lt;br&amp;gt;
only during direct editing) and painting all normal elements inside&amp;lt;br&amp;gt;
Konva, we preserve 60 FPS canvas performance while giving users full&amp;lt;br&amp;gt;
browser editing ergonomics.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;How a User Action Becomes Canvas State&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Every user interaction follows a strict unidirectional loop:&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;UI event → Global Editor State → Konva re-render → history push →&amp;lt;br&amp;gt;
debounced autosave&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Interaction Loop Steps&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;User Triggers Action: User clicks "Add heading" in the sidebar&amp;lt;br&amp;gt;
or drags an element on canvas.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Context Mutation: The action invokes addItem() or&amp;lt;br&amp;gt;
updateItem() in the global editor state.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;History Recording: The history manager pushes the previous&amp;lt;br&amp;gt;
snapshot onto the 50-state undo stack.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Canvas Re-draw: React-Konva receives updated props and&amp;lt;br&amp;gt;
re-renders the modified shapes on the elements layer.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Debounced Serialization: The autosave pipeline serializes canvas&amp;lt;br&amp;gt;
items to JSON and dispatches a debounced (2-second) PATCH request to&amp;lt;br&amp;gt;
the backend API.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Key User Flows&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Flow 1 --- Adding and Editing Text&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Figure: Flow 1: Adding, Rendering, and Inline-Editing Text Elements&amp;lt;br&amp;gt;
(Vertical Workflow)&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Konva Touchpoints: Konva.Text node, custom sceneFunc for formatted&amp;lt;br&amp;gt;
character ranges, and Transformer with scale-to-fontSize baking (scaling&amp;lt;br&amp;gt;
corner anchors adjusts fontSize directly to avoid pixelated text).&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Flow 2 --- Adding an Image from Unsplash&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Figure: Flow 2: Searching, Loading, and Rendering Unsplash Images&amp;lt;br&amp;gt;
(Vertical Workflow)&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Konva Touchpoints: Konva.Image node with HTMLImageElement source;&amp;lt;br&amp;gt;
mask clipping via custom clipFunc; aspect ratio preservation during&amp;lt;br&amp;gt;
transform handles.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Flow 3 --- Selection, Transform, and Snap&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Figure: Flow 3: Single/Multi-Selection, Transformer Attachment, and&amp;lt;br&amp;gt;
Snap Grid Guides&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Konva Touchpoints: Canvas Transformer with 8 anchor handles,&amp;lt;br&amp;gt;
real-time snap grid logic calculating alignment guidelines against&amp;lt;br&amp;gt;
canvas edges and sibling elements; arrows bypass Transformer and use&amp;lt;br&amp;gt;
2-point anchor handles.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Flow 4 --- Save, Preview, and Publish&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Figure: Flow 4: Autosave, UCF Serialization, Live Preview, and&amp;lt;br&amp;gt;
Production Publish&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Konva Touchpoints: Serialization transforms page scenes into&amp;lt;br&amp;gt;
Universal Canvas Format (UCF) JSON. The same Konva shape vocabulary is&amp;lt;br&amp;gt;
reused in the client viewer for 100% visual fidelity between editor&amp;lt;br&amp;gt;
preview and production viewer.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Supported Element Types&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;The editor supports 12 distinct element types, each mapped to a Konva&amp;lt;br&amp;gt;
primitive or custom renderer:&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Element Type            Konva / Custom Renderer Technical Implementation&amp;lt;br&amp;gt;
Notes&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Text                    Konva.Text + custom     Inline HTML textarea&amp;lt;br&amp;gt;
sceneFunc               editing; rich formatted&amp;lt;br&amp;gt;
character ranges&amp;lt;br&amp;gt;
(bold/italic/underline)&amp;lt;br&amp;gt;
painted on canvas.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Rectangle               Konva.Rect              Solid and gradient fills,&amp;lt;br&amp;gt;
border strokes,&amp;lt;br&amp;gt;
customizable corner&amp;lt;br&amp;gt;
radius, opacity.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Circle / Ellipse        Konva.Circle /          Uniform and non-uniform&amp;lt;br&amp;gt;
Konva.Ellipse           radial scaling with&amp;lt;br&amp;gt;
aspect lock support.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Line                    Konva.Line              Point coordinate array&amp;lt;br&amp;gt;
scaling and rotation&amp;lt;br&amp;gt;
handling during&amp;lt;br&amp;gt;
transform.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Arrow                   Konva.Arrow             Custom 2-point anchor&amp;lt;br&amp;gt;
editing (head and tail&amp;lt;br&amp;gt;
moved independently).&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Polygon / Star          Konva.RegularPolygon /  Configurable vertex&amp;lt;br&amp;gt;
Konva.Star              count, inner/outer radius&amp;lt;br&amp;gt;
ratio.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Wedge / Arc             Konva.Wedge / Konva.Arc Custom selection overlay&amp;lt;br&amp;gt;
with start/end angle&amp;lt;br&amp;gt;
dragging.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Image                   Konva.Image             Crop rectangle math,&amp;lt;br&amp;gt;
shape masks (circle,&amp;lt;br&amp;gt;
star, heart, diamond),&amp;lt;br&amp;gt;
opacity, filters.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Video                   Konva.Image frame +     Video poster on canvas;&amp;lt;br&amp;gt;
HTML overlay            synchronized DOM player&amp;lt;br&amp;gt;
(max 3 videos per&amp;lt;br&amp;gt;
document).&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Button / Link           Custom Group (Rect +    Clickable interactive&amp;lt;br&amp;gt;
Text)                   hotspot, URL navigation,&amp;lt;br&amp;gt;
document action binding.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Frame                   SquareFrameRenderer /   Decorative organic image&amp;lt;br&amp;gt;
TornFrameRenderer       container with clipping&amp;lt;br&amp;gt;
masks.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Dispatch logic operates using a clean TypeScript discriminated union&amp;lt;br&amp;gt;
(CanvasItem).&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;What Worked Well &amp;amp; Architectural Strengths&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Dev--Prod Parity for Rendering&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Designs export to UCF JSON and render in the client viewing app with the&amp;lt;br&amp;gt;
identical Konva primitives. Creators see in preview exactly what&amp;lt;br&amp;gt;
end-users experience---zero rendering drift or font mismatches.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Hook-Based Interaction Logic&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Complex canvas behaviors are decomposed into dedicated, testable custom&amp;lt;br&amp;gt;
React hooks rather than one monolithic component:&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Custom React Hook                   Core Responsibility&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;useDragHandlers                   Single-item drag, multi-selection&amp;lt;br&amp;gt;
drag, and transformer drag&amp;lt;br&amp;gt;
coordination.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;useTransformHandlers              Resize, rotate, scale commit per&amp;lt;br&amp;gt;
item type with aspect ratio&amp;lt;br&amp;gt;
constraints.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;useSelectionHandlers              Single click, shift/cmd&amp;lt;br&amp;gt;
multi-select, background click&amp;lt;br&amp;gt;
deselect.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;useTextEditing                    Double-click text editing&amp;lt;br&amp;gt;
activation, textarea placement,&amp;lt;br&amp;gt;
keyboard commit.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;useArrowHandlers                  Two-point arrow anchor handle&amp;lt;br&amp;gt;
dragging and coordinate&amp;lt;br&amp;gt;
calculation.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;useSnapGridLines                  Real-time alignment guide&amp;lt;br&amp;gt;
calculation and snapping against&amp;lt;br&amp;gt;
canvas &amp;amp; elements.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;useCanvasEffects                  Transformer attachment lifecycle,&amp;lt;br&amp;gt;
keyboard nudge handling (arrow&amp;lt;br&amp;gt;
keys).&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;useHistory                        50-state undo/redo stack with state&amp;lt;br&amp;gt;
compression and debounced push.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;useAutosave                       Debounced 2-second canvas&amp;lt;br&amp;gt;
serialization and PATCH API save&amp;lt;br&amp;gt;
pipeline.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;This modular structure keeps canvas orchestration clean, readable, and&amp;lt;br&amp;gt;
maintainable.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Production Performance Benchmarks &amp;amp; Metrics&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;To maintain smooth interactions on resource-constrained client machines,&amp;lt;br&amp;gt;
the canvas engine underwent rigorous benchmarking:&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Performance Dimension   Production Metric       Engineering Mechanism&amp;lt;br&amp;gt;
Achieved&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Interaction Frame Rate  Solid 60 FPS across     Node ref mutations&amp;lt;br&amp;gt;
250+ canvas elements    bypass React virtual&amp;lt;br&amp;gt;
DOM during active&amp;lt;br&amp;gt;
dragging and transform&amp;lt;br&amp;gt;
cycles.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Transformer Rotation    &amp;lt; 12 ms per frame      Layer splitting:&amp;lt;br&amp;gt;
Latency                 redraw cycle            transformer anchors&amp;lt;br&amp;gt;
render on an isolated&amp;lt;br&amp;gt;
canvas layer without&amp;lt;br&amp;gt;
invalidating elements.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Autosave Network        94% reduction in API    2-second debounce timer&amp;lt;br&amp;gt;
Reduction               write volume            on state mutations;&amp;lt;br&amp;gt;
payload diffing&amp;lt;br&amp;gt;
prevents redundant&amp;lt;br&amp;gt;
PATCH requests.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;History Heap Memory     &amp;lt; 14 MB for 50-state   Structured cloning of&amp;lt;br&amp;gt;
undo/redo buffer        lightweight UCF state&amp;lt;br&amp;gt;
trees with debounced&amp;lt;br&amp;gt;
300ms snapshot&amp;lt;br&amp;gt;
intervals.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Production War Stories &amp;amp; Solved Edge Cases&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Building a production canvas editor revealed complex graphics and&amp;lt;br&amp;gt;
browser synchronization edge cases that standard documentation&amp;lt;br&amp;gt;
overlooks.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Challenge 1: Solving Text Blurriness on High-DPI / Retina Displays&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Symptoms: Vector shapes rendered crisply, but canvas text and stroke&amp;lt;br&amp;gt;
borders appeared slightly blurry on Apple Retina screens and 4K&amp;lt;br&amp;gt;
displays.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Root Cause: Browser window.devicePixelRatio (2x or 3x) scales&amp;lt;br&amp;gt;
canvas CSS display dimensions without automatically scaling the&amp;lt;br&amp;gt;
underlying canvas backing buffer resolution.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Production Fix: Konva automatically handles pixel ratio scaling, but&amp;lt;br&amp;gt;
custom formatted text painted via HTML5 2D Canvas context (sceneFunc)&amp;lt;br&amp;gt;
required explicit scale normalization:&amp;lt;br&amp;gt;
ctx.scale(pixelRatio, pixelRatio) to ensure sub-pixel font&amp;lt;br&amp;gt;
anti-aliasing matching native DOM text.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Challenge 2: The Google Fonts Asynchronous Loading Race Condition&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Symptoms: When opening a document with custom fonts such as Playfair&amp;lt;br&amp;gt;
Display and Montserrat, text elements briefly measured with default&amp;lt;br&amp;gt;
fallback fonts, resulting in incorrect line wraps, clipped bounding&amp;lt;br&amp;gt;
boxes, and transformer handle misalignments.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Root Cause: Konva renders immediately on mount before&amp;lt;br&amp;gt;
document.fonts.load() resolves webfont TTF files.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Production Fix: We implemented a font management provider that&amp;lt;br&amp;gt;
prefetches document fonts, listens to document.fonts.ready, and&amp;lt;br&amp;gt;
triggers an atomic stage batchDraw() with text node bounding box&amp;lt;br&amp;gt;
recalculations once font glyphs are resident in GPU memory.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Challenge 3: Transformer Corner Scaling vs.&amp;nbsp;Text Box Aspect Distortion&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Symptoms: Dragging a transformer corner handle on a text box caused&amp;lt;br&amp;gt;
font characters to stretch non-uniformly (ovaled glyphs) instead of&amp;lt;br&amp;gt;
reflowing text naturally.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Root Cause: Konva Transformer applies scaleX and scaleY matrix&amp;lt;br&amp;gt;
multipliers to the target node during transform.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Production Fix: On transformend, our transform handling hook&amp;lt;br&amp;gt;
intercepts the event, resets node.scaleX(1) and node.scaleY(1), and&amp;lt;br&amp;gt;
bakes the scale multiplier directly into the text element's fontSize&amp;lt;br&amp;gt;
and width properties:&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;newFontSize = Math.round(oldFontSize * scaleX)&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;This guarantees crisp, undistorted font rendering.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Challenge 4: CSS Zoom Matrix Decoupling&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Symptoms: When users zoomed the viewport using the footer slider&amp;lt;br&amp;gt;
(50% to 200%), inline text editing text areas and crop overlays drifted&amp;lt;br&amp;gt;
away from their target shapes.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Root Cause: Canvas pan and CSS scale zoom apply outside Konva's&amp;lt;br&amp;gt;
internal coordinate matrix.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Production Fix: In our UI position calculator, overlay screen&amp;lt;br&amp;gt;
coordinates are computed by multiplying the shape's absolute Konva&amp;lt;br&amp;gt;
transform matrix by the stage's parent CSS transform scale factor:&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;clientPos = shape.getAbsolutePosition() * zoomScale + stageOffset&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Exporting UCF JSON into High-Resolution Image Views for End Users&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Once a visual document is designed and saved as Universal Canvas Format&amp;lt;br&amp;gt;
(UCF) JSON, end users need to view, share, and consume it across various&amp;lt;br&amp;gt;
client devices. Our architecture supports two distinct consumption&amp;lt;br&amp;gt;
modes.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Real-Time Interactive Canvas Rehydration&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;In web applications across desktop and mobile devices, the document&amp;lt;br&amp;gt;
viewer mounts a lightweight, read-only Konva Stage. It consumes the UCF&amp;lt;br&amp;gt;
JSON directly and renders the scene graph using the same shape&amp;lt;br&amp;gt;
dispatchers---with zero editor overhead (no toolbars, no transformer&amp;lt;br&amp;gt;
handles, no editing textarea overlays). This enables smooth interactive&amp;lt;br&amp;gt;
page flips, video playback, and clickable hyperlink hotspots.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Headless Offscreen Image Generation (PNG/WebP/PDF)&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;For generating static thumbnails, social sharing cards, downloadable&amp;lt;br&amp;gt;
PNGs, and print-ready PDFs, the application executes a client-side&amp;lt;br&amp;gt;
headless rendering pipeline:&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Offscreen Stage Mount: An invisible DOM container is dynamically&amp;lt;br&amp;gt;
created outside the visible viewport (left: -10000px) with the&amp;lt;br&amp;gt;
exact width and height of the document page.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Asset Preload Verification: The headless viewer renders the UCF&amp;lt;br&amp;gt;
scene graph and pauses capture until all remote assets (Unsplash&amp;lt;br&amp;gt;
images, Google Fonts TTF files, custom shape masks) have fully&amp;lt;br&amp;gt;
resolved.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Frame Settling: Double requestAnimationFrame() cycles allow&amp;lt;br&amp;gt;
font kerning, image decodes, and canvas clipping paths to paint&amp;lt;br&amp;gt;
completely.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;High-DPI Raster Capture: We execute&amp;lt;br&amp;gt;
stage.toDataURL({ pixelRatio: 2, mimeType: 'image/png' }) on the&amp;lt;br&amp;gt;
rendered Konva stage. Setting pixelRatio: 2 produces ultra-sharp,&amp;lt;br&amp;gt;
publication-grade raster images without blurriness or distortion.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Automatic Cleanup: Once the image data URL / Blob is resolved&amp;lt;br&amp;gt;
for download or preview, the offscreen root is safely unmounted to&amp;lt;br&amp;gt;
prevent browser memory leaks.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Engineering Lessons&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;After building this editor, five lessons stood out:&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Don't fight the browser. Use the DOM for text editing.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Keep rendering deterministic. The editor and viewer should use&amp;lt;br&amp;gt;
the same rendering engine.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Performance starts with architecture. Optimizations matter less&amp;lt;br&amp;gt;
than choosing the right rendering model.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Serialize state, not pixels. JSON scales better than images.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Invest in reusable interaction hooks. Hooks kept our codebase&amp;lt;br&amp;gt;
maintainable as the editor grew.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Tech Stack &amp;amp; Further Resources&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;The editor is built on a modern React ecosystem centered around Next.js&amp;lt;br&amp;gt;
15 (App Router) and Konva.js with React-Konva, which together provide a&amp;lt;br&amp;gt;
scalable foundation for high-performance 2D canvas rendering, scene&amp;lt;br&amp;gt;
graph management, and interactive editing. React Context manages editor&amp;lt;br&amp;gt;
state, selections, history, and document metadata, while TanStack Query&amp;lt;br&amp;gt;
and an internal API client handle data fetching, caching, and debounced&amp;lt;br&amp;gt;
autosave operations.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;The interface is styled with Tailwind&amp;lt;br&amp;gt;
CSS,&amp;lt;br&amp;gt;
typography is powered by the Google Fonts API with a custom TTF loader&amp;lt;br&amp;gt;
for accurate font rendering, and media assets are sourced through the&amp;lt;br&amp;gt;
Unsplash API and stored in cloud storage backed by a CDN. Documents are&amp;lt;br&amp;gt;
serialized into a lightweight Universal Canvas Format (UCF) JSON,&amp;lt;br&amp;gt;
enabling fast persistence, portability, and pixel-perfect rendering&amp;lt;br&amp;gt;
consistency between the editor and viewer.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Developers interested in exploring the underlying technologies can refer&amp;lt;br&amp;gt;
to the official Konva.js&amp;lt;br&amp;gt;
documentation, including the&amp;lt;br&amp;gt;
Getting Started guides, React-Konva integration guide, API Reference,&amp;lt;br&amp;gt;
Performance Tips, Select &amp;amp; Transform documentation, Interactive Sandbox&amp;lt;br&amp;gt;
examples, and the Konva and React-Konva GitHub repositories.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Core Engineering Takeaways&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Building a production-grade canvas editor requires coordination across&amp;lt;br&amp;gt;
rendering, state management, browser APIs, networking, and user&amp;lt;br&amp;gt;
experience.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Konva.js provided the rendering engine, while the surrounding&amp;lt;br&amp;gt;
architecture handled hybrid editing, history management, autosave,&amp;lt;br&amp;gt;
performance optimization, and rendering fidelity across the editor and&amp;lt;br&amp;gt;
viewer. Beyond solving interesting engineering problems, the editor&amp;lt;br&amp;gt;
transformed our document creation workflow.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Tasks that previously required external design tools and lengthy&amp;lt;br&amp;gt;
collaboration can now be completed entirely within the application in&amp;lt;br&amp;gt;
minutes, while maintaining consistent rendering between editor and&amp;lt;br&amp;gt;
viewer.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;The current architecture was intentionally designed for extensibility.&amp;lt;br&amp;gt;
Planned capabilities include collaborative real-time editing, reusable&amp;lt;br&amp;gt;
templates, version history, AI-assisted layout generation, reusable&amp;lt;br&amp;gt;
design components, and plugin-based extensibility. Because the editor is&amp;lt;br&amp;gt;
built around a scene graph and serialized document model, these features&amp;lt;br&amp;gt;
can be introduced without fundamental architectural changes.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;The architecture and lessons shared in this article can help engineering&amp;lt;br&amp;gt;
teams avoid similar pitfalls when building scalable, production-ready&amp;lt;br&amp;gt;
canvas applications.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;For teams building web applications with complex interactions and&amp;lt;br&amp;gt;
demanding performance requirements, the right frontend architecture can&amp;lt;br&amp;gt;
shape how the product scales. Our Next.js Development&amp;lt;br&amp;gt;
Services support teams&amp;lt;br&amp;gt;
in building web applications designed for performance, maintainability,&amp;lt;br&amp;gt;
and growth.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Original article:&amp;lt;br&amp;gt;
GeekyAnts&amp;lt;/p&amp;gt;
&lt;/p&gt;

</description>
      <category>design</category>
      <category>aiproductengineering</category>
      <category>ai</category>
    </item>
    <item>
      <title>The Next Wave of Mobile Apps is The Instant Prototype</title>
      <dc:creator>GeekyAnts India Pvt Ltd</dc:creator>
      <pubDate>Thu, 06 Aug 2026 10:45:04 +0000</pubDate>
      <link>https://dev.to/geekyants/the-next-wave-of-mobile-apps-is-the-instant-prototype-4aaf</link>
      <guid>https://dev.to/geekyants/the-next-wave-of-mobile-apps-is-the-instant-prototype-4aaf</guid>
      <description>&lt;p&gt;By Amrit Saluja, Technical Content Writer at GeekyAnts. Originally published on &lt;a href="https://geekyants.com/blog/the-next-wave-of-mobile-apps-is-the-instant-prototype" rel="noopener noreferrer"&gt;GeekyAnts&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Is the local IDE becoming optional? Sanket Sahu discusses the rise of vibe-coding and how browser-native tools such as RapidNative are reshaping mobile app development.&lt;/p&gt;

&lt;p&gt;Editor's note&lt;br&gt;
Sanket Sahu, co-founder of GeekyAnts and creator of gluestack, recently explored how to build an entire development server inside the browser. The engineering is interesting, but the larger question is what this architecture means for founders, product managers, and the future of enterprise AI.&lt;/p&gt;

&lt;p&gt;We spoke with Sanket about the reasons behind the build, the browser-native technologies that make it possible, and the product opportunities created by near-instant feedback. The conversation below has been edited for clarity.&lt;/p&gt;

&lt;p&gt;Is the local IDE becoming optional?&lt;br&gt;
Amrit Saluja: We hear a great deal about vibe-coding. Does browser-native architecture make the local IDE optional, or are we moving toward a hybrid future?&lt;/p&gt;

&lt;p&gt;Sanket Sahu: Vibe-coding is growing because browser-based tools remove setup friction and make &lt;a href="https://geekyants.com/service/hire-mobile-app-development-services" rel="noopener noreferrer"&gt;building apps&lt;/a&gt; more accessible. Development is moving toward a hybrid model rather than abandoning local tools altogether.&lt;/p&gt;

&lt;p&gt;What did RapidNative change?&lt;br&gt;
AS: For readers who have not seen the technical deep dive, what did you build?&lt;/p&gt;

&lt;p&gt;SS: I rebuilt the development server inside the browser. RapidNative does not require npm run dev, a CLI, or an external server. A code change appears in the preview in under 100 milliseconds while preserving application state.&lt;/p&gt;

&lt;p&gt;AS: Why replace the earlier approach?&lt;/p&gt;

&lt;p&gt;SS: The previous version ran a sandbox in the cloud. That architecture worked, but an AI tool that streams code in real time makes every network round-trip visible. The goal was not merely a fast response. It was an instant one.&lt;/p&gt;

&lt;p&gt;How can a development server run in a browser tab?&lt;br&gt;
AS: A traditional development server handles a lot of work. How did you move those responsibilities into the browser?&lt;/p&gt;

&lt;p&gt;SS: A server such as Metro watches the file system, transpiles code, bundles modules, and serves the result over HTTP. We replaced each responsibility with a browser-native capability. Service Workers take the place of the HTTP server. IndexedDB and a virtual file system replace the physical file system. Babel Standalone performs transpilation, while Import Maps remove the need to bundle modules during development.&lt;/p&gt;

&lt;p&gt;AS: That sounds similar to Vite. Was it an influence?&lt;/p&gt;

&lt;p&gt;SS: Yes. Both approaches begin with the same observation: modern browsers understand ES modules, so development does not always need a bundling step. Vite still relies on &lt;a href="https://geekyants.com/hire-nodejs-developers" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; and a CLI. RapidNative extends the idea by moving the full development loop into the browser.&lt;/p&gt;

&lt;p&gt;Why use two virtual file systems?&lt;br&gt;
AS: What makes the dual-VFS architecture necessary?&lt;/p&gt;

&lt;p&gt;SS: The two file systems have separate responsibilities. The Source VFS holds the original TypeScript and JSX files. When a source file changes, the browser transforms it and writes plain JavaScript into the Destination VFS. The Service Worker serves only from that destination. Keeping source and output separate makes the pipeline predictable and fast.&lt;/p&gt;

&lt;p&gt;What does a sub-100ms preview mean for founders?&lt;br&gt;
AS: How does that preview speed help a founder or a non-technical decision-maker?&lt;/p&gt;

&lt;p&gt;SS: Fast iteration protects the creative flow. It helps teams produce better MVPs, test their thinking sooner, and reach a first paying user faster. For many people, seeing an app idea running on a phone in less than two minutes is the moment the product becomes real.&lt;/p&gt;

&lt;p&gt;AS: How is RapidNative different from Expo Snack?&lt;/p&gt;

&lt;p&gt;SS: The products serve different purposes. Snack is a browser-based REPL that helps developers test snippets and run them on devices. RapidNative focuses on building full apps with AI assistance and instant browser feedback. Its sub-100ms update loop matters when an AI is continuously streaming code changes.&lt;/p&gt;

&lt;p&gt;Who is RapidNative for today?&lt;br&gt;
AS: Is the current product aimed at startups or enterprises?&lt;/p&gt;

&lt;p&gt;SS: Today, it is best suited to individuals and startups that want to turn an idea into a working app. Customization, team features, and compliance capabilities are on the roadmap so that agencies and enterprises can adopt it as well.&lt;/p&gt;

&lt;p&gt;What comes next?&lt;br&gt;
AS: What remains on the technical roadmap?&lt;/p&gt;

&lt;p&gt;SS: Three major additions are planned: a TypeScript Language Server for editor autocomplete, browser-native Git operations through isomorphic-git, and native-device support through Expo Go. Together, they should combine instant browser feedback with the advantages of running an app on a real device.&lt;/p&gt;

&lt;p&gt;AS: You have built NativeBase, gluestack, and now RapidNative. Has AI changed your goal?&lt;/p&gt;

&lt;p&gt;SS: The goal remains the same: remove friction for developers, designers, founders, and product managers. AI is an enabler and an accelerator. It shortens the distance between imagining an idea and seeing it work on a screen.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mobile</category>
      <category>app</category>
    </item>
    <item>
      <title>OpenClaw.ai — Your Personal AI That Actually Does Things</title>
      <dc:creator>GeekyAnts India Pvt Ltd</dc:creator>
      <pubDate>Thu, 30 Jul 2026 13:21:16 +0000</pubDate>
      <link>https://dev.to/geekyants/openclawai-your-personal-ai-that-actually-does-things-4pn9</link>
      <guid>https://dev.to/geekyants/openclawai-your-personal-ai-that-actually-does-things-4pn9</guid>
      <description>&lt;p&gt;OpenClaw is a powerful, self-hosted AI assistant that connects to your tools to perform actions. Explore its Gateway architecture, real-world use cases, and security precautions.&lt;/p&gt;

&lt;p&gt;There is a new kind of &lt;a href="https://geekyants.com/case-studies/ai-interview-system-for-automated-candidate-screening" rel="noopener noreferrer"&gt;AI tool&lt;/a&gt; making waves. It is called OpenClaw, and it acts and does things.&lt;/p&gt;

&lt;p&gt;OpenClaw is an open-source, self-hosted &lt;a href="https://geekyants.com/blog/mirai-the-ai-powered-personal-growth-assistant-that-adapts-to-you" rel="noopener noreferrer"&gt;AI assistant&lt;/a&gt; created by Peter Steinberger. Launched as "Clawdbot" in November 2025, it is now called OpenClaw and has 145,000 GitHub stars. Nature, Wired, DigitalOcean, and VirusTotal have covered it.&lt;/p&gt;

&lt;p&gt;But what exactly is it? And more importantly, is it something you should set up?&lt;/p&gt;

&lt;h2&gt;
  
  
  Is OpenClaw for Everyone? No.
&lt;/h2&gt;

&lt;p&gt;OpenClaw is powerful, but it is not a plug-and-play consumer app. One of OpenClaw's own maintainers put it bluntly: "If you can't understand how to run a command line, this is far too dangerous a project for you to use safely."&lt;/p&gt;

&lt;p&gt;Here is why. OpenClaw runs on your machine with access to your files, shell, browser, and messaging apps. It installs extensions called "Skills." In February 2026, security researchers found over 300 malicious skills on ClawHub (the skill marketplace), disguising malware as helpful tools. A Cornell audit found 26% of skill packages contained vulnerabilities.&lt;/p&gt;

&lt;p&gt;OpenClaw partnered with VirusTotal for automated skill scanning and hired a security advisor. But they are clear: this is not a silver bullet. Prompt injection attacks—where malicious instructions hide in natural language—remain unsolved.&lt;/p&gt;

&lt;p&gt;If you understand what's installed on your system, can audit code, and know command-line tools, OpenClaw is exciting. If not, wait until it matures or work with someone who can set it up for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does OpenClaw Work—Through the Gateway?
&lt;/h2&gt;

&lt;p&gt;At OpenClaw's core sits the Gateway—a &lt;a href="https://geekyants.com/hire-nodejs-developers" rel="noopener noreferrer"&gt;Node.js process&lt;/a&gt; that controls everything.&lt;/p&gt;

&lt;p&gt;Think of it as an Agent Server. The Gateway is responsible for managing all your channel connections (WhatsApp, Telegram, Slack, Discord, and more), routing messages to the &lt;a href="https://geekyants.com/consulting-services/artificial-intelligence-consulting/agentic-ai" rel="noopener noreferrer"&gt;right AI agent&lt;/a&gt;, maintaining session state and conversation history, coordinating tool execution (file operations, shell commands, browser automation), and providing a WebSocket interface for CLI tools, &lt;a href="https://geekyants.com/service/hire-mobile-app-development-services" rel="noopener noreferrer"&gt;mobile apps&lt;/a&gt;, and the &lt;a href="https://geekyants.com/service/ui-ux-design-services" rel="noopener noreferrer"&gt;web UI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Every message, whether from WhatsApp or Telegram, flows through the Gateway, gets routed to the right agent, and the response flows back. By default, it runs on localhost:18789, keeping everything local.&lt;/p&gt;

&lt;p&gt;What makes this interesting: you can run multiple agents behind one Gateway, each with its own personality, workspace, model, and tool access. For example, route WhatsApp messages to Claude Sonnet and Telegram messages to Claude Opus, all from one Gateway.&lt;/p&gt;

&lt;p&gt;It is &lt;a href="https://geekyants.com/blog/microservices-architecture-from-theory-to-practice" rel="noopener noreferrer"&gt;microservices&lt;/a&gt; for personal AI.&lt;/p&gt;

&lt;h2&gt;
  
  
  For the Masses, What Does OpenClaw Actually Do?
&lt;/h2&gt;

&lt;p&gt;OpenClaw is an &lt;a href="https://geekyants.com/blog/building-a-smart-assistant-without-cloud-the-future-of-local-ai" rel="noopener noreferrer"&gt;AI assistant&lt;/a&gt; that performs actions. Unlike &lt;a href="https://geekyants.com/blog/how-to-build-ai-chatbots-using-chatgpt-api-with-live-demo-video" rel="noopener noreferrer"&gt;ChatGPT&lt;/a&gt; or Claude's chat interface, which respond with text, OpenClaw connects to your tools and systems. It reads and writes files on your computer, executes shell commands, browses the web, sends messages through your apps, and interacts with APIs.&lt;/p&gt;

&lt;p&gt;This is organized through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://geekyants.com/blog/revolutionizing-business-process-automation-with-ai-agents" rel="noopener noreferrer"&gt;Agents&lt;/a&gt;: The AI brains with isolated workspaces and sessions&lt;/li&gt;
&lt;li&gt;Tools: Built-in capabilities like exec, read, browser, cron, and message&lt;/li&gt;
&lt;li&gt;Skills: Community or custom packages that teach the agent how to use specific tools and &lt;a href="https://geekyants.com/hire-graphql-api-developers" rel="noopener noreferrer"&gt;APIs&lt;/a&gt;, like GitHub, Notion, Slack, or Google Calendar&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In plain language: You tell it what to do—through any messaging app you use—and it does it.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Do You Talk to Your OpenClaw AI Assistant?
&lt;/h2&gt;

&lt;p&gt;You do not need a special app to create an AI assistant with OpenClaw. This is one of OpenClaw's best design decisions. You use the messaging platforms you already have.&lt;/p&gt;

&lt;p&gt;OpenClaw supports WhatsApp, Telegram (recommended for first setup), Slack, Discord, Signal, iMessage, Google Chat, Microsoft Teams, and WebChat. It also supports Matrix, BlueBubbles, Zalo, and more. It can speak and listen on macOS, &lt;a href="https://geekyants.com/hire-ios-developers" rel="noopener noreferrer"&gt;iOS&lt;/a&gt;, and &lt;a href="https://geekyants.com/hire-android-app-developers" rel="noopener noreferrer"&gt;Android&lt;/a&gt; through companion apps.&lt;/p&gt;

&lt;p&gt;The experience: message your bot on Telegram, and it responds. It does not respond with just words but with actions as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can OpenClaw Schedule Things for You?
&lt;/h2&gt;

&lt;p&gt;Yes. And it is built right in.&lt;/p&gt;

&lt;p&gt;OpenClaw includes a powerful built-in scheduler called Cron, which runs inside the Gateway process itself. It supports full 5-field cron expressions with timezone awareness, one-shot reminders (e.g., "remind me at 4 PM"), recurring jobs (e.g., "every weekday at 9 AM, summarize my unread emails"), isolated agent turns where a scheduled job runs in its own session, and delivery to any connected channel — so the result can show up in your WhatsApp, Telegram, or Slack.&lt;/p&gt;

&lt;p&gt;Jobs persist under &lt;code&gt;~/.openclaw/cron/&lt;/code&gt;, so even if the Gateway restarts, your schedules survive.&lt;/p&gt;

&lt;p&gt;For example, you could set up a job that checks your email every 10 minutes. If it finds a message from a specific sender — say your manager or a key client — it immediately notifies you on WhatsApp. People are doing this today.&lt;/p&gt;

&lt;h2&gt;
  
  
  What About Webhooks and External Triggers?
&lt;/h2&gt;

&lt;p&gt;OpenClaw's Gateway provides a WebSocket interface and can be integrated with external systems in multiple ways. You can trigger agents via CLI commands, connect through the WebSocket API, set up cron-based polling workflows, and use skills that integrate with external services and APIs. The architecture is deliberately open-ended, encouraging creative integrations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real Use Cases that People are Building
&lt;/h2&gt;

&lt;p&gt;Here is where things get exciting. OpenClaw is a productivity multiplier. People are using it to manage their calendars by scheduling events, getting daily briefings, and rescheduling conflicts through a simple &lt;a href="https://geekyants.com/blog/how-to-build-a-chat-and-messaging-app-from-scratch" rel="noopener noreferrer"&gt;chat message&lt;/a&gt;. They are processing emails, with agents that scan your inbox, summarize important threads, draft replies, and flag urgent messages from specific senders.&lt;/p&gt;

&lt;p&gt;Developers are running coding agents in the background, using skills for Claude Code, Codex, and other &lt;a href="https://geekyants.com/blog/codegen-streamlining-your-journey-to-simplicity" rel="noopener noreferrer"&gt;code-generation&lt;/a&gt; tools that build features, run tests, and open pull requests — while they sleep. One user described kicking off Claude Code sessions from his phone and waking up to completed PRs.&lt;/p&gt;

&lt;p&gt;Early adopters are automating household workflows. One user configured OpenClaw to build a weekly meal planning system in Notion, saving his family an hour every week. Others are monitoring health data, connecting WHOOP and other services to track biomarkers and daily habits through chat.&lt;/p&gt;

&lt;p&gt;Some have even built entire websites from their phones, controlling file operations and deployment through Telegram messages.&lt;/p&gt;

&lt;p&gt;The pattern is that anything you would ask a skilled executive assistant to do. The assistants check information, draft content, and provide reminders. Anything you need to keep an eye on, it can be handled by OpenClaw.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example of OpenClaw Usage
&lt;/h3&gt;

&lt;p&gt;Wednesday, 6 AM: Your assistant checks email. Client needs a deliverable update. It drafts a reply and waits for your approval. Your accountant sent something about taxes - flagged as urgent. The newsletter you follow gets summarized and saved to Notion.&lt;/p&gt;

&lt;p&gt;7 AM: Health check on your staging server. Green. No alert.&lt;/p&gt;

&lt;p&gt;8 AM: Morning briefing hits your phone. "Three meetings today. First one at 10 AM. Two-hour focus block this afternoon. Your mom's birthday is tomorrow. Want me to order flowers?"&lt;/p&gt;

&lt;p&gt;You are still in bed. You type: "Yes."&lt;/p&gt;

&lt;p&gt;That is OpenClaw, running right now, on someone's laptop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can I run it Completely On-Premise?
&lt;/h2&gt;

&lt;p&gt;Yes. This is a key differentiator from existing chatbot or assistant &lt;a href="https://geekyants.com/blog/how-to-build-chatgpt-powered-mobile-apps" rel="noopener noreferrer"&gt;AI builders&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;OpenClaw is model-agnostic. While it works beautifully with cloud-based models like Claude, GPT-4, and &lt;a href="https://geekyants.com/blog/deepseek-r1-vs-openais-o1-the-open-source-disruptor-raising-the-bar" rel="noopener noreferrer"&gt;DeepSeek&lt;/a&gt;, you can run it entirely on local models using Ollama. This means zero data leaves your machine.&lt;/p&gt;

&lt;p&gt;Supported local models include Llama 3.x, Mistral, Qwen, Phi, DeepSeek-R1, and more. The setup is straightforward: install Ollama, pull a model, point OpenClaw's config at your local endpoint (&lt;code&gt;http://127.0.0.1:11434/v1&lt;/code&gt;), and you're running a fully private, on-premise AI assistant.&lt;/p&gt;

&lt;p&gt;OpenClaw even supports hybrid configurations — use a fast local model as your everyday coordinator and fall back to a cloud model for complex reasoning tasks.&lt;/p&gt;

&lt;p&gt;For organizations with strict data residency or compliance requirements, this is a game-changer.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Word on Security — Take It Seriously
&lt;/h2&gt;

&lt;p&gt;OpenClaw gives an AI agent real access to your system. That power comes with real risk.&lt;/p&gt;

&lt;p&gt;In the past few weeks, researchers discovered 341 malicious skills in a campaign called "ClawHavoc" that targeted &lt;a href="https://geekyants.com/blog/how-to-build-a-crypto-trading-app-like-coinbase-security-compliance--ux-tips" rel="noopener noreferrer"&gt;cryptocurrency wallets&lt;/a&gt;. Cisco's security team found third-party skills performing data exfiltration without user awareness. BitSight and CrowdStrike flagged exposed instances as enterprise security risks. 22% of enterprise customers in one study had employees running OpenClaw without IT approval.&lt;/p&gt;

&lt;p&gt;OpenClaw is improving: VirusTotal partnership, sandbox modes for Docker-isolated execution, tool allowlists and denylists, DM pairing for access control, and a formal security program at trust.openclaw.ai.&lt;/p&gt;

&lt;p&gt;But the responsibility falls on you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Audit skills before installing them&lt;/li&gt;
&lt;li&gt;Enable sandbox mode&lt;/li&gt;
&lt;li&gt;Restrict tool access per agent&lt;/li&gt;
&lt;li&gt;Keep sensitive credentials out of the agent's reach&lt;/li&gt;
&lt;li&gt;If deploying for a team, treat it like privileged infrastructure—with &lt;a href="https://geekyants.com/ai" rel="noopener noreferrer"&gt;governance&lt;/a&gt;, monitoring, and clear boundaries&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Mental Model Shift
&lt;/h2&gt;

&lt;p&gt;The tool is only as useful as the workflows you design for it.&lt;/p&gt;

&lt;p&gt;Setting it up is just the beginning. The real work—and the real value—comes from thinking about what you want automated. What tasks do you repeat every day? What decisions could be offloaded? What monitoring would save you from fire drills?&lt;/p&gt;

&lt;p&gt;OpenClaw is not magic. It is infrastructure. And like any infrastructure, it rewards planning.&lt;/p&gt;

&lt;p&gt;You need a mental model for what is possible, then build, iterate, and refine. The people getting the most out of OpenClaw are not the ones with the fanciest hardware—they're the ones who've thought about their workflows.&lt;/p&gt;

&lt;p&gt;At &lt;a href="https://geekyants.com/en-us" rel="noopener noreferrer"&gt;GeekyAnts&lt;/a&gt;, we help people plan, build, deploy, and manage personal AI assistants—from initial &lt;a href="https://geekyants.com/ai/business-process-automation-services" rel="noopener noreferrer"&gt;architecture to production automation&lt;/a&gt;. Whether you want to run OpenClaw on-premise, integrate it with your existing tools, or build custom skills for your team, &lt;a href="https://geekyants.com/hire" rel="noopener noreferrer"&gt;reach out&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was originally published on the &lt;a href="https://geekyants.com/blog/openclawai-your-personal-ai-that-actually-does-things" rel="noopener noreferrer"&gt;GeekyAnts blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
    </item>
    <item>
      <title>Exploring Anti-Design Through a Neo-Brutalist Product Experience</title>
      <dc:creator>GeekyAnts India Pvt Ltd</dc:creator>
      <pubDate>Tue, 28 Jul 2026 13:12:30 +0000</pubDate>
      <link>https://dev.to/geekyants/exploring-anti-design-through-a-neo-brutalist-product-experience-4men</link>
      <guid>https://dev.to/geekyants/exploring-anti-design-through-a-neo-brutalist-product-experience-4men</guid>
      <description>&lt;p&gt;&lt;em&gt;A comprehensive article on customising design systems, experimenting responsibly, and designing with intention in 2026's most defining trend.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  When Good Design Becomes Invisible
&lt;/h2&gt;

&lt;p&gt;Most &lt;a href="https://geekyants.com/service/digital-product-design-services" rel="noopener noreferrer"&gt;modern digital products&lt;/a&gt; are well designed. They are clean, usable, and follow best practices. Yet somewhere along the way, many of them started feeling interchangeable, polished to the point of sameness.&lt;/p&gt;

&lt;p&gt;During our early project discussions, one question kept surfacing: How do we create something that feels distinct without sacrificing usability?&lt;/p&gt;

&lt;p&gt;That tension became our entry point into anti-design—not as a visual trend to adopt, but as a design method to explore.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Anti-Design Is Defining 2026
&lt;/h2&gt;

&lt;p&gt;Anti-design has emerged as one of the dominant design trends of 2026, representing a fundamental shift in how designers approach their craft. After years of algorithm-friendly, hyper-polished aesthetics, the design community is experiencing what many are calling a creative rebellion.&lt;/p&gt;

&lt;p&gt;Industry leaders are witnessing a deliberate rejection of AI's overly smooth visual language in favour of work that feels unmistakably human. &lt;a href="https://geekyants.com/service/ui-ux-design-services" rel="noopener noreferrer"&gt;Designers&lt;/a&gt; are choosing imperfection, messiness, and rawness as proof that a person, not an algorithm, made this. This is not only an aesthetic preference; it is a response to digital saturation and a hunger for authenticity.&lt;/p&gt;

&lt;p&gt;The data backs up this shift:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Searches for bold fonts have surged over 65%&lt;/li&gt;
&lt;li&gt;Collage art and handmade textures continue to climb in popularity&lt;/li&gt;
&lt;li&gt;Brands are moving away from safe, predictable design toward experiences that feel alive, emotional, and intentionally chaotic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article documents how we rode this wave early by understanding anti-design as a principled methodology that could help us stand out in an increasingly homogenised market.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why We Started With Anti-Design, Not Ended With It
&lt;/h2&gt;

&lt;p&gt;Anti-design typically appears late in the process, applied as visual flair over an already-finished product. We took a different approach.&lt;/p&gt;

&lt;p&gt;We chose to explore anti-design from the beginning, working at the system level rather than the surface level. Instead of discarding our &lt;a href="https://geekyants.com/solution/design-system-development-service" rel="noopener noreferrer"&gt;design system&lt;/a&gt;, we used it as a foundation and began questioning its assumptions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What happens when typography leads instead of layout?&lt;/li&gt;
&lt;li&gt;What if spacing becomes expressive, not just consistent?&lt;/li&gt;
&lt;li&gt;What if components feel editorial rather than purely functional?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These questions shaped our early explorations and helped us test boundaries without losing control.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F32vwphpv7tswtfq9wxs0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F32vwphpv7tswtfq9wxs0.png" alt="Early Design System exploration with multiple button styles and interaction states" width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Early explorations showing multiple variations of the same screen or layout concept&lt;/p&gt;

&lt;h2&gt;
  
  
  Customising a Design System Without Breaking It
&lt;/h2&gt;

&lt;p&gt;The challenge was not to push boundaries; it was how to do it without creating chaos.&lt;/p&gt;

&lt;p&gt;Rather than changing everything at once, we focused on small, deliberate experiments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modified Button types to start establishing the new brutalism softly on the screen&lt;/li&gt;
&lt;li&gt;Introduced layout flexibility for content-heavy sections&lt;/li&gt;
&lt;li&gt;Created component variants instead of entirely new patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, we did not build new card components from scratch. Instead, we experimented with existing ones by introducing heavier borders, uneven internal spacing, and Bolder and larger typographic contrast.&lt;/p&gt;

&lt;p&gt;This kept us system-aligned while allowing the visual language to evolve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Neo-Brutalism Worked in a Product Context
&lt;/h2&gt;

&lt;p&gt;Neo-brutalism gave us a middle ground between expressive design and functional usability.&lt;/p&gt;

&lt;p&gt;Unlike traditional brutalism, which can feel harsh or inaccessible, neo-brutalism allows you to use bold typography without harming readability, create visual tension without confusion, and embrace rawness while maintaining structure.&lt;/p&gt;

&lt;p&gt;For us, this approach supported a magazine-inspired experience where content felt curated and intentional, not templated and generic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real-World Success Stories
&lt;/h3&gt;

&lt;p&gt;Platforms like Figma and Gumroad have embraced neo-brutalist approaches, demonstrating how raw, unpolished aesthetics can succeed in commercial contexts.&lt;/p&gt;

&lt;p&gt;Figma's brand refresh uses bold contrasts and unconventional typography to emphasize creative freedom and flexibility, perfectly aligning with their &lt;a href="https://geekyants.com/blog/top-10-ai-tools-every-uiux-designer-should-master" rel="noopener noreferrer"&gt;design tool's&lt;/a&gt; purpose. The visual language reinforces what the product enables—unrestricted creativity.&lt;/p&gt;

&lt;p&gt;Gumroad's raw aesthetic aligns with its mission of empowering independent creators. The rebellious visual language communicates that it is a platform for people charting their own paths, not another corporate marketplace. The deliberately utilitarian interface becomes part of the brand promise.&lt;/p&gt;

&lt;p&gt;These are strategic decisions that align visual identity with brand values, proving that neo-brutalism works when it serves a purpose beyond shock value.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv22g2n2kp1ln3z70zrqv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv22g2n2kp1ln3z70zrqv.png" alt="Design System layout blocks demonstrating typography scale and editorial influence" width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Typography scale experiments or layout blocks showing editorial influence&lt;/p&gt;

&lt;h2&gt;
  
  
  The Psychology Behind Why It Works
&lt;/h2&gt;

&lt;p&gt;There's solid research backing why anti-design captures attention. The Von Restorff Effect, a psychological principle documented by German psychiatrist Hedwig von Restorff in 1933, demonstrates that when multiple similar items are presented, the one that differs from the rest is significantly more likely to be remembered.&lt;/p&gt;

&lt;h3&gt;
  
  
  The 15-Second Window
&lt;/h3&gt;

&lt;p&gt;In a world where users spend an average of 15 seconds on a webpage, shock value works. A brutalist design does not ask for attention it demands it. The distinctive nature of anti-design creates what psychologists call enhanced memory encoding, making experiences more memorable than conventional alternatives.&lt;/p&gt;

&lt;p&gt;When users encounter something unexpected:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Their brain registers the deviation from the norm&lt;/li&gt;
&lt;li&gt;Additional cognitive resources are allocated to processing it&lt;/li&gt;
&lt;li&gt;The experience becomes more deeply encoded in memory&lt;/li&gt;
&lt;li&gt;Recall is significantly improved compared to conventional alternatives&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is a measurable impact on user engagement and brand recall, translating to higher engagement metrics, stronger word-of-mouth sharing, and more memorable user experiences.&lt;/p&gt;

&lt;h3&gt;
  
  
  Anti-Design ≠ Careless Design
&lt;/h3&gt;

&lt;p&gt;Anti-design that ignores fundamental principles is just bad design with a rebellious aesthetic. True anti-design respects these principles while finding new ways to express them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Anti-Design Must Still Respect Accessibility
&lt;/h2&gt;

&lt;p&gt;This is non-negotiable. WCAG (Web Content Accessibility Guidelines) organizes accessibility requirements under four principles: content must be Perceivable, Operable, Understandable, and Robust.&lt;/p&gt;

&lt;p&gt;Anti-design does not exempt you from these standards—it challenges you to meet them creatively.&lt;/p&gt;

&lt;h3&gt;
  
  
  What You MUST Do for Accessibility:
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Color Contrast (WCAG AA Standard)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Maintain a minimum contrast ratio of 4.5:1 for normal text and 3:1 for large text&lt;/li&gt;
&lt;li&gt;Bold typography and heavy borders can work if contrast ratios are maintained&lt;/li&gt;
&lt;li&gt;Use tools like WebAIM's contrast checker to verify compliance&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Typography &amp;amp; Readability
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Keep body text at minimum 16px&lt;/li&gt;
&lt;li&gt;Ensure generous line height (1.5x minimum)&lt;/li&gt;
&lt;li&gt;Avoid extremely condensed or decorative fonts for body copy&lt;/li&gt;
&lt;li&gt;Bold, expressive headlines are fine—just keep body text readable&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Keyboard Navigation &amp;amp; Focus States
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;All interactive elements must be keyboard-accessible&lt;/li&gt;
&lt;li&gt;Visible focus indicators are required (not just on hover)&lt;/li&gt;
&lt;li&gt;Logical tab order must be maintained even with unconventional layouts&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Alternative Text &amp;amp; Screen Readers
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;All images need descriptive alt text&lt;/li&gt;
&lt;li&gt;Ensure heading hierarchy (H1, H2, H3) follows logical structure&lt;/li&gt;
&lt;li&gt;Do not break semantic HTML structure for visual effect&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Sufficient Target Sizes
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Interactive elements must be at least 44x44 pixels&lt;/li&gt;
&lt;li&gt;Even if your design feels raw, buttons must be easily tappable/clickable&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What NOT to Do:
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Don not sacrifice contrast for aesthetics
&lt;/h4&gt;

&lt;p&gt;Low-contrast text might look sophisticated but excludes users with visual impairments and violates legal standards.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Do not hide navigation or controls
&lt;/h4&gt;

&lt;p&gt;Experimental layouts are fine, but users must always know how to navigate and complete tasks.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Do not rely solely on color to convey information
&lt;/h4&gt;

&lt;p&gt;Use additional indicators like icons, labels, or patterns alongside color.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Do not break fundamental interaction patterns
&lt;/h4&gt;

&lt;p&gt;Buttons should look clickable, links should be distinguishable, forms should be predictable.&lt;/p&gt;

&lt;h4&gt;
  
  
  5. Do not use motion without controls
&lt;/h4&gt;

&lt;p&gt;If you include animations, provide pause/stop controls and respect &lt;strong&gt;prefers-reduced-motion&lt;/strong&gt; settings.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real-World Balance
&lt;/h3&gt;

&lt;p&gt;Gumroad's raw aesthetic includes heavy borders and bold typography, but maintains proper contrast ratios and clear interactive states. The visual rebellion works because the accessibility fundamentals remain intact.&lt;/p&gt;

&lt;p&gt;The principle is to push visual boundaries, not accessibility boundaries.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fegtz1ipko9bzc8y4ke2e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fegtz1ipko9bzc8y4ke2e.png" alt="Gumroad homepage showing bold typography, heavy borders, and high-contrast design aesthetic" width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Anti-Design Still Follows Heuristic Principles
&lt;/h2&gt;

&lt;p&gt;Jakob Nielsen's 10 Usability Heuristics, developed in 1990 and refined in 1994, remain the gold standard for interface design. Anti-design does not reject these principles—it interprets them differently.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Anti-Design Aligns With Heuristics:
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Visibility of System Status
&lt;/h4&gt;

&lt;p&gt;Anti-design can actually enhance this through bold, unmissable feedback states. Heavy borders and strong typography make status changes more visible, not less.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Match Between System and Real World
&lt;/h4&gt;

&lt;p&gt;Neo-brutalism often embraces real-world metaphors—raw materials, physical textures, tactile elements. This can create stronger connections than sterile digital interfaces.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. User Control and Freedom
&lt;/h4&gt;

&lt;p&gt;Unconventional does not mean confusing. Clear "undo" actions, visible navigation, and predictable controls still apply—they just might look different.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Consistency and Standards
&lt;/h4&gt;

&lt;p&gt;This is where anti-design requires the most discipline. You can bend conventions, but you must be consistent within your own system. If one button has a heavy border, all buttons should follow a predictable pattern.&lt;/p&gt;

&lt;h4&gt;
  
  
  5. Error Prevention
&lt;/h4&gt;

&lt;p&gt;Bold visual treatments can actually improve error prevention by making warnings more noticeable and actions more deliberate.&lt;/p&gt;

&lt;h4&gt;
  
  
  6. Recognition Rather Than Recall
&lt;/h4&gt;

&lt;p&gt;Strong visual hierarchy and distinctive elements aid recognition. Anti-design's boldness can reduce cognitive load by making important elements impossible to miss.&lt;/p&gt;

&lt;h4&gt;
  
  
  7. Flexibility and Efficiency of Use
&lt;/h4&gt;

&lt;p&gt;Power users benefit from predictable patterns. Anti-design can support efficiency through clear visual affordances and consistent interaction models.&lt;/p&gt;

&lt;h4&gt;
  
  
  8. Aesthetic and Minimalist Design
&lt;/h4&gt;

&lt;p&gt;This seems contradictory, but it is not. The heuristic is about ensuring that visual elements support user goals, not about adhering to flat design. Bold typography can create a clearer hierarchy than minimalist layouts if used intentionally.&lt;/p&gt;

&lt;h4&gt;
  
  
  9. Help Users Recognise, Diagnose, and Recover from Errors
&lt;/h4&gt;

&lt;p&gt;Heavy borders, bold text, and strong colour can make error messages more noticeable and actionable.&lt;/p&gt;

&lt;h4&gt;
  
  
  10. Help and Documentation
&lt;/h4&gt;

&lt;p&gt;Even rebellious designs need clear documentation. The visual language might be unconventional, but the help content must remain accessible and searchable.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Key Difference:
&lt;/h3&gt;

&lt;p&gt;Traditional design applies heuristics conservatively. Anti-design applies them expressively—but it still applies them. The rebellion is in the execution, not the abandonment of principles.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Should You Use Anti-Design?
&lt;/h2&gt;

&lt;p&gt;Anti-design is not universally applicable, but it can be powerful when used intentionally.&lt;/p&gt;

&lt;h3&gt;
  
  
  It works well when:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Differentiation is a key product goal&lt;/li&gt;
&lt;li&gt;Brand personality matters&lt;/li&gt;
&lt;li&gt;Content needs to feel expressive or editorial&lt;/li&gt;
&lt;li&gt;Your audience is open to visual experimentation&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  It is less effective when:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Speed and efficiency are the primary user goals&lt;/li&gt;
&lt;li&gt;Accessibility constraints are extremely strict&lt;/li&gt;
&lt;li&gt;Users rely on predictable patterns under high-pressure conditions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key is knowing when expression adds value—and when it becomes noise.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Experiment Safely With Anti-Design
&lt;/h2&gt;

&lt;p&gt;If you are curious about anti-design but hesitant to try it in live projects, here is how to start:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Experiment early: Explore unconventional ideas before the system becomes locked in.&lt;/li&gt;
&lt;li&gt;Isolate risk: Test bold ideas on a few screens or components, not the entire product.&lt;/li&gt;
&lt;li&gt;Use the system as a base: Bend components before you replace them entirely.&lt;/li&gt;
&lt;li&gt;Document intent: Be prepared to explain every rule you break.&lt;/li&gt;
&lt;li&gt;Balance expression with restraint: Not everything needs to be loud. Some elements should anchor the chaos.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What This Approach Taught Us
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1zup0enzkwhelhbh4m6j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1zup0enzkwhelhbh4m6j.png" alt="Design system exploration with anti-design poster, sketches, and creative layout ideas on desk" width="799" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This project reinforced several principles worth carrying forward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Design systems should enable exploration, not restrict it&lt;/li&gt;
&lt;li&gt;Intentional experimentation leads to stronger outcomes than random novelty&lt;/li&gt;
&lt;li&gt;Anti-design works best when grounded in purpose, not rebellion&lt;/li&gt;
&lt;li&gt;Expression and usability do not have to compete—they can complement each other&lt;/li&gt;
&lt;li&gt;Accessibility and heuristics are creative challenges&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Riding the Wave of Biggest Design Shifts
&lt;/h2&gt;

&lt;p&gt;Anti-design is the design philosophy defining 2026. As the industry moves away from algorithmic perfection and toward human authenticity, designers who understand this shift will create experiences that truly resonate.&lt;/p&gt;

&lt;p&gt;Our exploration proved that anti-design is not about rejecting structure—it's about reshaping it with intention. When approached thoughtfully, it helps you move beyond visual sameness and create experiences that feel memorable, expressive, and purposeful.&lt;/p&gt;

&lt;p&gt;In a market flooded with polished sameness, imperfection has become the new differentiator. The brands and products that will stand out in 2026 are not the ones with the cleanest interfaces—they are the ones with personality, emotion, and unmistakable human touch.&lt;/p&gt;

&lt;p&gt;Sometimes, the most impactful design decisions begin with a simple question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What if we did not do it the usual way?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In 2026, that question is essential.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was originally published on the &lt;a href="https://geekyants.com/blog/exploring-anti-design-through-a-neo-brutalist-product-experience" rel="noopener noreferrer"&gt;GeekyAnts blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>design</category>
      <category>uxdesign</category>
    </item>
    <item>
      <title>Building a Self-Healing CI/CD System with an AI Agent</title>
      <dc:creator>GeekyAnts India Pvt Ltd</dc:creator>
      <pubDate>Fri, 24 Jul 2026 13:21:42 +0000</pubDate>
      <link>https://dev.to/geekyants/building-a-self-healing-cicd-system-with-an-ai-agent-5hea</link>
      <guid>https://dev.to/geekyants/building-a-self-healing-cicd-system-with-an-ai-agent-5hea</guid>
      <description>&lt;p&gt;Engineering teams know when CI pipelines fail. What follows is the problem: a developer stops what they are doing, opens the logs, spends twenty minutes tracing the error, writes a fix, and waits for the pipeline to run again.&lt;/p&gt;

&lt;p&gt;This pattern repeats 3-5 times per week per developer. Across a team of ten engineers, this compounds to 6-8 hours of interrupted work weekly.&lt;/p&gt;

&lt;p&gt;CI failure detection exists. The gap is automated failure resolution.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hidden Cost of CI Failures
&lt;/h2&gt;

&lt;p&gt;CI pipelines validate code changes before deployment. On each code push, the pipeline compiles the application, executes tests, and reports results. When everything works, developers barely notice it. Failures require immediate developer attention.&lt;/p&gt;

&lt;p&gt;Most failures are not complex. A dependency version changed. A test assertion has been updated. A configuration value is absent. These are routine maintenance issues.&lt;/p&gt;

&lt;p&gt;The cost lies in the interruption overhead. Interruption, context switching, and release cycle delays accumulate. For teams deploying 3-5 times daily, these delays compound.&lt;/p&gt;

&lt;p&gt;Automated error resolution addresses this gap.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Core Idea: A Pipeline That Fixes Itself
&lt;/h2&gt;

&lt;p&gt;The systems built by &lt;a href="https://geekyants.com/en-us" rel="noopener noreferrer"&gt;GeekyAnts&lt;/a&gt; treat CI failures as programmatically solvable problems. On failure, the system follows standard debugging workflow: it reads the logs, identifies what went wrong, looks at the relevant code, generates a fix, tests it, and submits the patch for review.&lt;/p&gt;

&lt;p&gt;This process follows systematic patterns recognizable across most CI failures. Error messages are structured. Stack traces identify affected files. Fixes are straightforward with proper context.&lt;/p&gt;

&lt;p&gt;These characteristics enable automation. An &lt;a href="https://geekyants.com/ai/ai-agent-development-services" rel="noopener noreferrer"&gt;AI agent&lt;/a&gt; with codebase access and failure context completes this process without context-switching overhead.&lt;/p&gt;

&lt;p&gt;The result is a self-healing CI/CD system, a pipeline that not only detects failures but responds to them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the System Is Made Of
&lt;/h2&gt;

&lt;p&gt;The platform is built across three layers, each with a distinct role.&lt;/p&gt;

&lt;p&gt;The Application Layer is a Spring Boot backend service representing a simple product management system. It handles user role management, inventory updates, and discount calculations. A test suite validates these services and provides failure scenarios during CI execution. A GitLab CI pipeline runs on every push: compile, test, report. Stage failures trigger agent analysis.&lt;/p&gt;

&lt;p&gt;The AI Agent Layer performs failure analysis and resolution. A &lt;a href="https://geekyants.com/hire-python-developers" rel="noopener noreferrer"&gt;Python service&lt;/a&gt; built with FastAPI monitors pipeline state. On failure detection, it fetches logs, analyzes them, queries the codebase structure, generates a fix, validates it, and creates a merge request.&lt;/p&gt;

&lt;p&gt;The agent uses multiple data sources: a language model for reasoning, a structural codebase map, and historical failure memory. These improve accuracy beyond single-source analysis. The agent is backed by a Neo4j graph database for codebase relationships and a Qdrant vector database for failure memory.&lt;/p&gt;

&lt;p&gt;The Monitoring Dashboard, built with &lt;a href="https://geekyants.com/hire-next-js-developers" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt;, provides visibility into active investigations, processing stages, generated fixes, and escalated failures. The dashboard surfaces agent activity and decision rationale in real time.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works: From Code Push to Merge Request
&lt;/h2&gt;

&lt;p&gt;Pipeline failure sequence:&lt;/p&gt;

&lt;p&gt;A developer pushes code. The GitLab pipeline starts: compile, test, report. The pipeline fails due to a broken test or a compilation error. The agent detects the failure event.&lt;/p&gt;

&lt;p&gt;Rather than passing the full raw log to an &lt;a href="https://geekyants.com/blog/ai-in-business-custom-models-for-scalable-innovation" rel="noopener noreferrer"&gt;AI model&lt;/a&gt;, which would be slow, expensive, and full of noise, the agent first cleans it. Dependency downloads, verbose build output, and unrelated stack traces are stripped out. What remains is signal: error messages, stack traces, failing test names, and affected source files. This reduces the search space and improves reasoning accuracy.&lt;/p&gt;

&lt;p&gt;The agent performs deep analysis: it queries the codebase structural map to identify component relationships before proposing changes.&lt;/p&gt;

&lt;p&gt;A fix is generated based on that full context. The fix is validated locally before pushing. If validation passes, the patch is pushed, and a merge request is created for developer review. If the agent cannot resolve the issue, it escalates with a structured diagnostic report rather than raw logs.&lt;/p&gt;

&lt;p&gt;The developer's role shifts from debugging to reviewing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Makes It More Than a Script
&lt;/h2&gt;

&lt;p&gt;Many &lt;a href="https://geekyants.com/blog/top-devops-automation-tools" rel="noopener noreferrer"&gt;CI automation tools&lt;/a&gt; detect failures and send alerts. This system differs through multi-layered analysis:&lt;/p&gt;

&lt;h3&gt;
  
  
  Log Intelligence
&lt;/h3&gt;

&lt;p&gt;Raw CI logs sent to language models produce suboptimal results. Raw logs contain high noise-to-signal ratios.&lt;/p&gt;

&lt;p&gt;The agent solves this with a dedicated cleaning stage. Before AI reasoning, deterministic parsing extracts error messages, stack traces, and test failures. The model then operates on a smaller, focused input, which improves both speed and accuracy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Codebase Understanding Using AST and Graph Modeling
&lt;/h3&gt;

&lt;p&gt;Knowing that a test failed is not enough context to fix it reliably. The system maintains a structural codebase map built through Java AST parsing.&lt;/p&gt;

&lt;p&gt;This extracts structural elements such as classes, methods, imports, method calls, and dependencies, all stored in a Neo4j graph database as connected relationships. Class contains Method. Method calls Method. Service depends on Repository.&lt;/p&gt;

&lt;p&gt;On failure, the agent traces affected components through the map before proposing fixes. This provides relationship context beyond error messages alone.&lt;/p&gt;

&lt;p&gt;To keep this map accurate without rebuilding it from scratch on every commit, the system performs incremental updates. For each commit, modified files are reprocessed, their AST recalculated, and the graph updated. The map stays current without unnecessary computation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Learning from Past Failures
&lt;/h3&gt;

&lt;p&gt;CI failures repeat across commits and projects. Recalculating a solution that has already been found once is wasteful.&lt;/p&gt;

&lt;p&gt;The agent maintains a searchable vector memory of historical failures using Qdrant. Each entry stores the error signature, failure context, and generated fix. When a new failure occurs, its error signature is embedded and the database is queried. If a similar failure is found, the system reuses the existing solution, reducing LLM token usage, response latency, and repeated reasoning costs.&lt;/p&gt;

&lt;p&gt;The system improves through accumulated failure data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Active Investigation, Not Passive Generation
&lt;/h3&gt;

&lt;p&gt;The agent provides investigation tools rather than log-only input: it can call getGitDiff() to inspect recent code changes, readFile() to retrieve file contents, queryGraph() to explore code relationships in Neo4j, and blastRadius() to determine the impact scope of a change.&lt;/p&gt;

&lt;p&gt;These tools enable hypothesis formation, evidence testing, and conclusion validation before fix generation. This shifts from single-shot generation to iterative investigation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-Time Visibility Into an Autonomous System
&lt;/h2&gt;

&lt;p&gt;Autonomous code changes require engineer visibility into system decisions.&lt;/p&gt;

&lt;p&gt;The dashboard connects to the agent via WebSocket, streaming updates without page refresh. Engineers observe each analysis stage and decision rationale. Events streamed include agent activity, pipeline updates, and metrics updates.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The dashboard surfaces four key views:&lt;/li&gt;
&lt;li&gt;The Overview shows aggregated metrics: total CI incidents, automated fix success rate, escalation rate, and recent pipeline activity.&lt;/li&gt;
&lt;li&gt;The Live Monitor shows the current pipeline, the active agent stage, and logs streaming from the backend.&lt;/li&gt;
&lt;li&gt;The History view lets engineers inspect past failures in detail: root cause analysis, generated patches, fix attempts, and merge request links.&lt;/li&gt;
&lt;li&gt;The Escalations view displays unresolved failures with diagnostic reports.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The dashboard enables team adoption.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Impact on Engineering Teams
&lt;/h2&gt;

&lt;p&gt;The immediate benefit is straightforward: fewer interruptions. When the agent handles a routine failure, developers do not need to context-switch. A merge request appears, they review it, and they move on.&lt;/p&gt;

&lt;p&gt;The downstream effects compound. Pipelines that recover faster stay green more often. Increased confidence enables more frequent deployment. Delivery cycles become predictable without debugging delays.&lt;/p&gt;

&lt;p&gt;Longer-term benefits accumulate: Initially, the agent analyzes each failure independent. Over time, it builds a library of known solutions. Common failure patterns resolve through memory lookup. The system becomes more valuable the longer it runs.&lt;/p&gt;

&lt;p&gt;For teams managing multiple projects, a single agent monitors all pipelines—coverage requiring multiple engineers to replicate manually.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where This Goes Next
&lt;/h2&gt;

&lt;p&gt;The current system is built around Java and Maven projects. The underlying architecture is not language-specific.&lt;/p&gt;

&lt;p&gt;The log cleaning logic, the vector memory, the LLM reasoning layer, and the merge request workflow are all transferable. &lt;a href="https://geekyants.com/hire-nodejs-developers" rel="noopener noreferrer"&gt;Node.js projects&lt;/a&gt;, Python services, Go &lt;a href="https://geekyants.com/blog/microservices-architecture-from-theory-to-practice" rel="noopener noreferrer"&gt;microservices&lt;/a&gt;—the same approach applies. The primary adaptation required is language-specific AST parsing in the code graph layer. Other components transfer without modification.&lt;/p&gt;

&lt;p&gt;The longer-term direction: a single agent monitoring polyglot organizations and handling CI failures across languages and building systems.&lt;/p&gt;

&lt;p&gt;Beyond language support, the system can expand failure type coverage. The current scope covers test failures and compilation errors. Future iterations could address environment-specific failures, infrastructure misconfigurations, and dependency resolution issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  From Reactive to Proactive: A Different Way to Think About CI/CD
&lt;/h2&gt;

&lt;p&gt;Traditional &lt;a href="https://geekyants.com/engineering/devops" rel="noopener noreferrer"&gt;CI/CD pipelines&lt;/a&gt; are built to report. They run when code is pushed, surface failures, and wait for a human to act.&lt;/p&gt;

&lt;p&gt;That model made sense when diagnosis required human judgment at every step. It makes less sense now. The patterns are recognizable. The process is systematic. The tooling to automate it exists.&lt;/p&gt;

&lt;p&gt;Self-healing CI/CD systems do not remove developers from the loop. The merge request step is deliberate. Human judgment belongs before fixes reach production. What changes is where developers enter that loop. Instead of starting with a raw log file and no context, they start with a proposed solution and a clear explanation of the problem.&lt;/p&gt;

&lt;p&gt;That shift from debugging to decision-making is where engineering time should be spent.&lt;/p&gt;

&lt;p&gt;Teams building this capability will resolve failures faster. They will compound that advantage with each independently resolved incident.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was originally published on the &lt;a href="https://geekyants.com/blog/building-a-self-healing-cicd-system-with-an-ai-agent" rel="noopener noreferrer"&gt;GeekyAnts blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Building an Autonomous Multi-Agent Fraud Detection System in Under 200ms</title>
      <dc:creator>GeekyAnts India Pvt Ltd</dc:creator>
      <pubDate>Wed, 22 Jul 2026 13:14:13 +0000</pubDate>
      <link>https://dev.to/geekyants/building-an-autonomous-multi-agent-fraud-detection-system-in-under-200ms-1p64</link>
      <guid>https://dev.to/geekyants/building-an-autonomous-multi-agent-fraud-detection-system-in-under-200ms-1p64</guid>
      <description>&lt;p&gt;Indian banks lose $1.49 billion USD to fraud every year. The systems built to stop it take 3 to 5 seconds to reach a decision. UPI payments settle in 2 seconds. By the time the fraud system responds, the money has already moved.&lt;/p&gt;

&lt;p&gt;At &lt;a href="https://geekyants.com/en-us" rel="noopener noreferrer"&gt;GeekyAnts'&lt;/a&gt; internal event, we tackled this problem with a different kind of system. Instead of a single, all-purpose AI model, we built five specialized AI programs that work together in sequence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Existing Fraud Detection Fails
&lt;/h2&gt;

&lt;p&gt;Before understanding the solution, it helps to understand why current systems fall short. There are five structural problems, and each makes the others worse.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. They are too slow.
&lt;/h3&gt;

&lt;p&gt;A 3 to 5 second response time may seem reasonable in isolation. But when payments settle in 2 seconds, a fraud decision that arrives after settlement is record-keeping instead of prevention.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. They cover too little ground.
&lt;/h3&gt;

&lt;p&gt;Most legacy systems were built to catch credit and debit card fraud. Today's threats include deepfake identity verification (where criminals use AI-generated faces to pass ID checks), social engineering over UPI, corporate email scams, and fake loan applications using fabricated identities. These largely go undetected.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. They cannot adapt quickly.
&lt;/h3&gt;

&lt;p&gt;When a new fraud pattern emerges, traditional systems need weeks of work before they can recognize it: data collection, model retraining, testing, and deployment. Criminals exploit that window across thousands of transactions.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. They generate too many false alarms.
&lt;/h3&gt;

&lt;p&gt;False positive rates, meaning legitimate transactions wrongly flagged as fraud, hover around 40%. Analysts spend the majority of their time investigating genuine payments while actual fraud slips through in the background.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. They are expensive to implement.
&lt;/h3&gt;

&lt;p&gt;Connecting a new bank to a fraud system is typically a six-month custom project.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture: Five Specialists, One Pipeline
&lt;/h2&gt;

&lt;p&gt;Our &lt;a href="https://geekyants.com/industry-expertise/banking-finance-insurance/regtech-compliance-automation/fraud-detection-software-development" rel="noopener noreferrer"&gt;multi-agent fraud detection system&lt;/a&gt; replaces a single overloaded model with five agents (specialized AI programs), each responsible for one task. A transaction enters the system, passes through all five in order, and exits with a decision in under 200 milliseconds.&lt;/p&gt;

&lt;p&gt;A shared context object, think of it as a growing document, travels through the entire pipeline. Each agent adds its findings. By the end, this document contains the full record of how the decision was made, and it is stored as a permanent, tamper-proof audit log.&lt;/p&gt;

&lt;p&gt;Here is what each agent does:&lt;/p&gt;

&lt;h3&gt;
  
  
  Agent 1: Signal Processor
&lt;/h3&gt;

&lt;p&gt;Cleans and standardizes the raw transaction data. Banks send information in different formats, currencies, and time zones. This agent converts everything into a consistent form so the agents that follow can work reliably.&lt;/p&gt;

&lt;h3&gt;
  
  
  Agent 2: Category Classifier
&lt;/h3&gt;

&lt;p&gt;Routes the transaction into one of nine fraud categories: account takeover, general transaction fraud, card-not-present fraud, mobile fraud, deepfake identity fraud, UPI fraud, loan fraud, wire/business email fraud, and insider fraud. Each category has its own specific rules. A social engineering scam over UPI looks nothing like a corporate wire fraud, and treating them the same wastes both computing resources and accuracy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Agent 3: Risk Scorer
&lt;/h3&gt;

&lt;p&gt;The core of the system. This agent assigns a risk score using the three-tier process described in detail below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Agent 4: Decision Agent
&lt;/h3&gt;

&lt;p&gt;Applies the risk score to a decision. Scores below 0.30 result in APPROVE. Scores between 0.30 and 0.70 trigger a CHALLENGE, a step-up verification request sent to the customer. Scores above 0.70 result in DECLINE. Each bank can configure its own thresholds.&lt;/p&gt;

&lt;h3&gt;
  
  
  Agent 5: Explanation Agent
&lt;/h3&gt;

&lt;p&gt;Produces a plain-language summary of why the decision was made: the top five contributing factors, the reasoning, and a confidence level. Indian and international financial regulations, including RBI, &lt;a href="https://geekyants.com/industry-expertise/banking-finance-insurance/regtech-compliance-automation/regulatory-reporting-compliance-development" rel="noopener noreferrer"&gt;PCI-DSS&lt;/a&gt;, and GDPR, require that automated decisions be explainable, so this step is not optional.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three-Tier Risk Engine
&lt;/h2&gt;

&lt;p&gt;Most &lt;a href="https://geekyants.com/blog/how-to-build-an-ai-powered-real-time-fraud-detection-system-in-the-usa" rel="noopener noreferrer"&gt;AI fraud systems&lt;/a&gt; send every transaction through the most powerful and most expensive model available. Our agent takes a different approach: start with the simplest tool, and only escalate when necessary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tier 1: Rules (10 milliseconds)
&lt;/h3&gt;

&lt;p&gt;Forty-eight configurable rules check things like transaction velocity (how many payments were made in quick succession), amount limits, device recognition, and time-of-day patterns. A routine ₹2,500 UPI payment from a recognized device to a known recipient resolves here in 10 milliseconds with no AI involved. Tier 1 handles 60% of all transactions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tier 2: Machine Learning (25 milliseconds)
&lt;/h3&gt;

&lt;p&gt;When Tier 1's confidence falls below a threshold, the transaction escalates to an XGBoost model (a type of machine learning algorithm known for speed and accuracy on structured data). It evaluates 65 or more factors and produces a score alongside an explanation of which factors drove it, using a technique called SHAP. This tier runs on standard computer processors with no specialized hardware required. Tier 2 handles 30% of all transactions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tier 3: AI with Memory (100 milliseconds)
&lt;/h3&gt;

&lt;p&gt;Only the genuinely ambiguous 5% reach here. A &lt;a href="https://geekyants.com/ai/large-language-model-development-services" rel="noopener noreferrer"&gt;large language model&lt;/a&gt; (an AI capable of reading and reasoning over text, similar to the technology behind chatbots) receives the transaction data, the factors from Tier 2, and the three most similar past cases retrieved from a database called ChromaDB. This grounds the AI's reasoning in real precedent rather than guesswork. Tier 3 handles 5% of all transactions.&lt;/p&gt;

&lt;p&gt;The end-to-end result is under 200 milliseconds. Because 95% of transactions never reach the large language model, the multi-agent costs 15 times less per transaction than systems that process everything through one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Self-Learning Without Retraining
&lt;/h2&gt;

&lt;p&gt;Traditional &lt;a href="https://geekyants.com/ai/machine-learning-development-services" rel="noopener noreferrer"&gt;machine learning&lt;/a&gt; operates on a fixed cycle: collect data, retrain the model, validate, and deploy. This can take weeks, but the agent closes that gap in seconds.&lt;/p&gt;

&lt;p&gt;When a human analyst overrides a system decision, for example, approving a transaction that was flagged because the customer was using a VPN while traveling abroad, three things happen at once:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The transaction details, the original decision, the override, and the analyst's note are converted into a vector embedding (a mathematical representation that captures meaning) and stored in ChromaDB.&lt;/li&gt;
&lt;li&gt;A permanent audit entry is created.&lt;/li&gt;
&lt;li&gt;The pattern library is updated.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The next time a similar transaction arrives from a different customer but matches the same pattern, the system retrieves the previous case and uses it as evidence. The AI now knows that a human verified this pattern as legitimate. No retraining. No data science work. The system learned in seconds.&lt;/p&gt;

&lt;p&gt;Over time, every analyst interaction adds to the system's institutional knowledge, and false positive rates fall continuously.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployment: One Configuration File
&lt;/h2&gt;

&lt;p&gt;The Agent deploys through a single configuration file written in YAML (a simple, human-readable format for settings). A bank provides its field mappings, data source, and preferred risk thresholds. One infrastructure command provisions the entire stack, including databases, data pipelines, and monitoring dashboards, in approximately 15 minutes.&lt;/p&gt;

&lt;p&gt;Rollout follows three phases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Days 1 to 2: Configuration and testing.&lt;/li&gt;
&lt;li&gt;Weeks 2 to 3: Shadow mode, where the Agent logs decisions without enforcing them, allowing the bank to validate accuracy.&lt;/li&gt;
&lt;li&gt;Go-live: Enabled with a single toggle, with no code changes required on the bank's side.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Technical Stack
&lt;/h2&gt;

&lt;p&gt;The system is built on &lt;a href="https://geekyants.com/hire-python-developers" rel="noopener noreferrer"&gt;Python&lt;/a&gt; for agent logic, &lt;a href="https://geekyants.com/hire-postgresql-developers" rel="noopener noreferrer"&gt;PostgreSQL&lt;/a&gt; for logs and configuration, Redis for caching, ChromaDB for vector storage, Apache Kafka for data ingestion, XGBoost for Tier 2 scoring, GPT-4o-mini for Tier 3 reasoning, Docker and &lt;a href="https://geekyants.com/engineering/devops/kubernetes-containerization-services" rel="noopener noreferrer"&gt;Kubernetes&lt;/a&gt; for deployment, Terraform for infrastructure, and Prometheus with Grafana for monitoring.&lt;/p&gt;

&lt;p&gt;Here are the metrics from our system:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;P50 Latency&lt;/td&gt;
&lt;td&gt;18ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P95 Latency&lt;/td&gt;
&lt;td&gt;85ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P99 Latency&lt;/td&gt;
&lt;td&gt;145ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fraud Categories&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configurable Rules&lt;/td&gt;
&lt;td&gt;48&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Signals per Transaction&lt;/td&gt;
&lt;td&gt;87+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Config to Shadow Mode&lt;/td&gt;
&lt;td&gt;~15 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Production Cost (1M txn/day)&lt;/td&gt;
&lt;td&gt;~$68K+/year&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The cost figure reflects the tiered design. Because 60% of transactions resolve at ₹0.001 each and only 5% reach the large language model at ₹0.12 each, the weighted average cost is approximately ₹0.002 per transaction. For a bank processing 1 crore (10 million) transactions per day, that is ₹64 Lakh per year against the potential to prevent hundreds of crores in losses, representing a roughly 785x return on investment.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Team Learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Decompose before you model. Fraud detection is five distinct tasks. Splitting them across specialized agents produced better accuracy, lower latency, and lower cost than any single model could.&lt;/li&gt;
&lt;li&gt;Speed is not a performance metric. It is a product feature. For real-time payments, the difference between 200 milliseconds and 3 seconds is the difference between preventing fraud and documenting it.&lt;/li&gt;
&lt;li&gt;Human oversight is the learning mechanism. Analyst overrides were designed for error correction. They turned out to be the most powerful component of the system, each one a training signal that propagates in seconds.&lt;/li&gt;
&lt;li&gt;Technical depth requires clear communication. The team rehearsed seven times and prepared answers to 16 anticipated questions. When judges pressed on token consumption, caching, and data segregation, the team had precise answers ready.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Comes Next
&lt;/h2&gt;

&lt;p&gt;The roadmap includes replacing the external AI API with a self-hosted &lt;a href="https://geekyants.com/open-source" rel="noopener noreferrer"&gt;open-source&lt;/a&gt; model to eliminate external dependency, an agent that automatically proposes new Tier 1 rules based on patterns identified in Tier 3, real-time testing between competing rule versions, and cross-bank federated learning where banks collectively benefit from shared fraud pattern knowledge without sharing individual customer data.&lt;/p&gt;

&lt;p&gt;The architecture is designed for production.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was originally published on the &lt;a href="https://geekyants.com/blog/building-an-autonomous-multi-agent-fraud-detection-system-in-under-200ms" rel="noopener noreferrer"&gt;GeekyAnts blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>fintech</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>A Real-Time AI Fraud Decision Engine Under 50ms</title>
      <dc:creator>GeekyAnts India Pvt Ltd</dc:creator>
      <pubDate>Mon, 20 Jul 2026 06:36:18 +0000</pubDate>
      <link>https://dev.to/geekyants/a-real-time-ai-fraud-decision-engine-under-50ms-3325</link>
      <guid>https://dev.to/geekyants/a-real-time-ai-fraud-decision-engine-under-50ms-3325</guid>
      <description>&lt;p&gt;Inside a high-performance Real-Time AI Fraud Decision Engine, a system that reviews a financial transaction and returns a decision in under 50 milliseconds.&lt;/p&gt;

&lt;p&gt;Every time you tap your phone to pay for something, a quiet competition is taking place. On one side are fraudsters looking to steal money. On the other side are detection systems trying to stop them in the time it takes to blink.&lt;/p&gt;

&lt;p&gt;At &lt;a href="https://geekyants.com/" rel="noopener noreferrer"&gt;GeekyAnts&lt;/a&gt;, a team of engineers set out to &lt;a href="https://geekyants.com/blog/how-to-build-an-ai-powered-real-time-fraud-detection-system-in-the-usa" rel="noopener noreferrer"&gt;build a fraud detection engine&lt;/a&gt; that could make that split-second call. The result is an Autonomous Multi-Agent Pipeline, a system capable of analyzing a financial transaction and deciding whether to approve, challenge, or block it in under 50 milliseconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem With Fraud Today
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://geekyants.com/industry-expertise/banking-finance-insurance/payments-and-digital-wallets" rel="noopener noreferrer"&gt;Digital payments&lt;/a&gt; have grown at a pace that has outrun traditional fraud prevention. The scale alone is staggering: large financial platforms process tens of thousands of transactions every minute. No team of human analysts can review that volume in real time.&lt;/p&gt;

&lt;p&gt;Four problems sit at the heart of the challenge:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Volume.&lt;/strong&gt; Thousands of transactions arrive every minute, far beyond human review capacity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;False alarms.&lt;/strong&gt; Many older systems block payments from real customers. These false declines push people away from digital banking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed of attack.&lt;/strong&gt; Once a fraudster gains access to an account, funds can be moved within minutes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No clear explanations.&lt;/strong&gt; Legacy systems often return error codes with no reasoning behind them, making it hard to communicate decisions to customers or regulators.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Three Layers of Intelligence
&lt;/h2&gt;

&lt;p&gt;Rather than rely on a single tool, the team built a system that combines three distinct layers of decision-making:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;a href="https://geekyants.com/ai/machine-learning-development-services" rel="noopener noreferrer"&gt;machine learning model&lt;/a&gt; that scores the risk of each transaction based on behavioral patterns.&lt;/li&gt;
&lt;li&gt;A rules engine that checks transactions against known fraud patterns.&lt;/li&gt;
&lt;li&gt;AI reasoning agents that generate written explanations of why a transaction was flagged.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Together, these layers handle what none could do alone: catch fraud at speed, explain decisions in plain language, and remain functional even when one component is unavailable.&lt;/p&gt;

&lt;h2&gt;
  
  
  How a Transaction Gets Reviewed
&lt;/h2&gt;

&lt;p&gt;When a transaction arrives, it passes through a sequence of specialized processes, each one focused on a specific task.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Signal Collection
&lt;/h3&gt;

&lt;p&gt;The system gathers and organizes the raw data attached to the transaction: device information, location, transaction amount, and account history. These are converted into a standard format the system can work with.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Fraud Category Identification
&lt;/h3&gt;

&lt;p&gt;Not all fraud looks the same. The system checks which of nine fraud categories the transaction might belong to, such as account takeover, card misuse, or wire transfer fraud. Identifying the category helps apply the right detection logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Risk Scoring
&lt;/h3&gt;

&lt;p&gt;A machine learning model evaluates fifteen risk signals to produce a fraud probability score. These signals include device risk, transaction speed, geographic location, and whether a VPN or proxy is in use, among others.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: The Decision
&lt;/h3&gt;

&lt;p&gt;Using the risk score and pattern matching against 27 known fraud scenarios, the system decides one of three outcomes: approve the transaction, challenge it (for example, by requesting additional verification), or decline it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: The Explanation
&lt;/h3&gt;

&lt;p&gt;In the background, an &lt;a href="https://geekyants.com/ai" rel="noopener noreferrer"&gt;AI&lt;/a&gt; reasoning process generates a written summary of why the decision was made. This explanation is stored for compliance teams, auditors, and customer support — anyone who needs to understand the reasoning later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Two Paths, One Decision
&lt;/h3&gt;

&lt;p&gt;The architecture separates speed from depth. The fast path handles the core decision in 5 to 15 milliseconds using the machine learning model and the rules engine. This is what keeps the payment experience smooth for the end user.&lt;/p&gt;

&lt;p&gt;The enrichment path runs in the background and completes within 200 milliseconds. It produces a fuller picture: threat severity, attack patterns, and recommended actions, all written in plain language rather than code.&lt;/p&gt;

&lt;p&gt;Splitting the two paths means the payment does not have to wait for deep analysis. Both can happen without slowing each other down.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why A Single Method Is Not Enough
&lt;/h2&gt;

&lt;p&gt;Machine learning is good at identifying unusual behavior — transactions that deviate from a user's normal patterns in ways that are hard to put into words. Rules, on the other hand, are good at catching specific, well-documented attack patterns with high confidence.&lt;/p&gt;

&lt;p&gt;This decision engine uses both. The rules catch what is known. The machine learning model catches what is unusual. The AI reasoning layer explains what was found. Each method covers the gaps of the others.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Nine Fraud Types the System Covers
&lt;/h2&gt;

&lt;p&gt;The system is built to recognize a wide range of fraud types common in digital finance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Account Takeover.&lt;/strong&gt; When a fraudster gains access to someone else's account, often through stolen credentials.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transaction Fraud.&lt;/strong&gt; Unauthorized payments made from a legitimate account.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Card-Not-Present Fraud.&lt;/strong&gt; Fraud that occurs when a physical card is not required, common in online purchases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mobile Banking Fraud.&lt;/strong&gt; Attacks that target users through &lt;a href="https://geekyants.com/service/hire-mobile-app-development-services" rel="noopener noreferrer"&gt;mobile apps&lt;/a&gt; or devices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Onboarding and Identity Fraud.&lt;/strong&gt; False identities used to open new accounts or pass verification checks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Digital Wallet Fraud.&lt;/strong&gt; Unauthorized use of payment apps and wallet services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Loan and Credit Fraud.&lt;/strong&gt; Applications for credit or loans using false information.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wire Transfer and Business Email Fraud.&lt;/strong&gt; Attackers impersonating executives or vendors to redirect payments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internal Employee Fraud.&lt;/strong&gt; Misuse of system access by people within an organization.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Across these nine categories, the system models 27 distinct fraud scenarios — specific attack patterns that the decision engine checks for during each review.&lt;/p&gt;

&lt;p&gt;The performance targets were set with real payment flows in mind. A decision that takes several seconds is too slow; customers expect near-instant responses.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Core decision time: 5–15 milliseconds&lt;/li&gt;
&lt;li&gt;Full analysis with explanation: under 200 milliseconds&lt;/li&gt;
&lt;li&gt;Fraud categories covered: 9&lt;/li&gt;
&lt;li&gt;Fraud scenarios modeled: 27&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Building This System Taught Us
&lt;/h2&gt;

&lt;p&gt;The project produced five practical conclusions about &lt;a href="https://geekyants.com/industry-expertise/banking-finance-insurance/regtech-compliance-automation/fraud-detection-software-development" rel="noopener noreferrer"&gt;fraud detection systems&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Speed is not optional. In payment flows, a slow decision is as disruptive as a wrong one.&lt;/li&gt;
&lt;li&gt;Explainability matters as much as accuracy. A system that cannot explain its decisions is a liability for compliance and customer communication.&lt;/li&gt;
&lt;li&gt;Hybrid systems outperform single-method systems. Rules and machine learning cover different failure modes.&lt;/li&gt;
&lt;li&gt;Observability is essential. Being able to trace each decision through the pipeline makes debugging complex systems possible.&lt;/li&gt;
&lt;li&gt;Rules remain necessary for critical decisions. AI reasoning is a valuable layer, but deterministic logic still provides the reliability that high-stakes decisions require.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Bigger Picture
&lt;/h2&gt;

&lt;p&gt;This multi-agent architecture reflects the direction that real-world fraud prevention is taking. Financial institutions increasingly depend on layered systems that combine structured rules, statistical models, and AI-generated reasoning to keep pace with attackers.&lt;/p&gt;

&lt;p&gt;As digital payments accelerate, systems built for the intersection of speed, accuracy, and transparency are no longer just a technical aspiration — they are a necessity. This project is a prime example of what that looks like in practice.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was originally published on the &lt;a href="https://geekyants.com/blog/a-real-time-ai-fraud-decision-engine-under-50ms" rel="noopener noreferrer"&gt;GeekyAnts blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
    </item>
    <item>
      <title>AI Code Healer for Fixing Broken CI/CD Builds Fast</title>
      <dc:creator>GeekyAnts India Pvt Ltd</dc:creator>
      <pubDate>Fri, 17 Jul 2026 13:16:12 +0000</pubDate>
      <link>https://dev.to/geekyants/ai-code-healer-for-fixing-broken-cicd-builds-fast-cdi</link>
      <guid>https://dev.to/geekyants/ai-code-healer-for-fixing-broken-cicd-builds-fast-cdi</guid>
      <description>&lt;h2&gt;
  
  
  The Problem Every Developer Knows
&lt;/h2&gt;

&lt;p&gt;You are on vacation. Your phone buzzes. A build has failed.&lt;/p&gt;

&lt;p&gt;You have no laptop, but the expectation is clear: find the problem and fix it. For developers who work with &lt;a href="https://geekyants.com/engineering/devops" rel="noopener noreferrer"&gt;CI/CD pipelines&lt;/a&gt;, this scenario is routine. Pipelines fail at the worst moments, blocking releases and forcing engineers to sift through thousands of lines of diagnostic logs from wherever they happen to be.&lt;/p&gt;

&lt;p&gt;Our internal engineering teams built a specialized Code Healer to address exactly this.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the System Works
&lt;/h2&gt;

&lt;p&gt;The solution is a centralized dashboard that connects to your GitHub or GitLab repositories. From this dashboard, developers can monitor their build pipelines, tracking progress, successes, and failures from any device, including a mobile phone.&lt;/p&gt;

&lt;p&gt;The platform goes beyond simple monitoring. When a pipeline fails, the system analyzes the failure and guides developers toward a resolution, without requiring them to manually read through massive log files. It delivers AI-powered analysis and specific suggestions for fixing the problem at the code level.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Two-Agent Architecture
&lt;/h2&gt;

&lt;p&gt;At the heart of the Code Healer is a two-agent AI architecture — meaning two distinct &lt;a href="https://geekyants.com/ai" rel="noopener noreferrer"&gt;AI systems&lt;/a&gt; that work in sequence to diagnose and solve build failures.&lt;/p&gt;

&lt;p&gt;The two agents are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A Local AI Agent:&lt;/strong&gt; A lighter &lt;a href="https://geekyants.com/blog/ai-in-business-custom-models-for-scalable-innovation" rel="noopener noreferrer"&gt;AI model&lt;/a&gt; that runs close to (or within) the developer's own infrastructure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An Advanced AI Agent:&lt;/strong&gt; A more powerful AI model capable of deeper reasoning.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When a developer clicks Analyze Failure, the full log from the failed build is sent to the &lt;a href="https://geekyants.com/engineering/backend" rel="noopener noreferrer"&gt;backend&lt;/a&gt;. The first task is to strip out the "noise" — CI logs frequently run to thousands of lines, but only a fraction of that content is relevant to understanding what went wrong.&lt;/p&gt;

&lt;p&gt;Once the log is cleaned and structured, it is passed to the Local AI Agent, which produces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A failure summary: A plain description of what went wrong.&lt;/li&gt;
&lt;li&gt;Impacted files: The specific files likely connected to the failure.&lt;/li&gt;
&lt;li&gt;Possible solutions: Initial recommendations for fixing the issue.&lt;/li&gt;
&lt;li&gt;A semantic prompt: A compressed, structured description of the problem context.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That semantic prompt is then forwarded to the Advanced AI Agent, which performs deeper analysis and returns refined failure summaries and detailed solution suggestions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code-Level Fixes
&lt;/h2&gt;

&lt;p&gt;Once the initial diagnosis is complete, the developer can click Advanced Assist. At this stage, a specialized &lt;a href="https://geekyants.com/ai/ai-agent-development-services" rel="noopener noreferrer"&gt;AI agent&lt;/a&gt; creates a code patch — a specific set of code modifications intended to fix the identified issue.&lt;/p&gt;

&lt;p&gt;The same layered methodology is used in this patch generation process: the request goes via the Local Agent before arriving at the Advanced Agent. This ensures that the input the advanced model receives is well-structured, which in turn produces more precise and useful code fixes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use a Local Agent at All?
&lt;/h2&gt;

&lt;p&gt;Our team implemented the Local Agent for two concrete reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cost and Speed:&lt;/strong&gt; Build logs are massive. Sending them in their entirety to a sophisticated AI model results in high latency and costs. The Local Agent serves as a compression layer, extracting only the pertinent context.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data Privacy:&lt;/strong&gt; Many organizations are cautious about sending source code to external systems. The Local Agent can be deployed entirely within the client's own cloud environment, ensuring sensitive data never leaves the organization's infrastructure.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Continuous Improvement
&lt;/h2&gt;

&lt;p&gt;The Local Agent is designed to operate independently, but the system also has a mechanism to improve its quality over time. When the Local Agent cannot resolve a problem with confidence, the system escalates to the Advanced Agent. The solution produced is then used as a training signal — feedback that gradually makes the Local Agent more capable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Broader Goal
&lt;/h2&gt;

&lt;p&gt;The vision our team holds is that developers should build products, not spend their time diagnosing broken pipelines. By combining pipeline monitoring, AI-driven failure analysis, and code-level suggestions, we are moving toward a future where build systems can identify and resolve their own problems with minimal intervention.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was originally published on the &lt;a href="https://geekyants.com/blog/ai-code-healer-for-fixing-broken-cicd-builds-fast" rel="noopener noreferrer"&gt;GeekyAnts blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
    </item>
    <item>
      <title>How We Built an AI System That Automates Senior Solution Architect Workflows</title>
      <dc:creator>GeekyAnts India Pvt Ltd</dc:creator>
      <pubDate>Thu, 16 Jul 2026 11:21:17 +0000</pubDate>
      <link>https://dev.to/geekyants/how-we-built-an-ai-system-that-automates-senior-solution-architect-workflows-5cl5</link>
      <guid>https://dev.to/geekyants/how-we-built-an-ai-system-that-automates-senior-solution-architect-workflows-5cl5</guid>
      <description>&lt;p&gt;30% of a senior architect's time goes into reading RFPs and writing proposals rather than designing systems or solving engineering problems.&lt;/p&gt;

&lt;p&gt;A 50-page enterprise RFP lands in an inbox. Two hours later, the architect has concluded what they suspected on page three: &lt;a href="https://geekyants.com/hire-react-native-developers" rel="noopener noreferrer"&gt;React Native&lt;/a&gt; frontend, &lt;a href="https://geekyants.com/hire-nodejs-developers" rel="noopener noreferrer"&gt;Node backend&lt;/a&gt;, &lt;a href="https://geekyants.com/hire-postgresql-developers" rel="noopener noreferrer"&gt;PostgreSQL&lt;/a&gt;, and Stripe for payments. The decision was predictable, but the process was manual and time-consuming.&lt;/p&gt;

&lt;p&gt;This manual work of extracting requirements, spotting contradictions, and drafting a coherent proposal repeats for each RFP. Our teams built an &lt;a href="https://geekyants.com/ai/ai-agent-development-services" rel="noopener noreferrer"&gt;AI-powered co-pilot&lt;/a&gt; to change that.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the AI Presales Co-Pilot Does
&lt;/h2&gt;

&lt;p&gt;This system assists with the presales cycle. You upload a client's documents — PDFs, Word docs, Excel sheets, or emails — and the system produces a draft technical proposal that an architect can review and refine in 15 minutes instead of writing from scratch for 3 hours.&lt;/p&gt;

&lt;p&gt;The value extends beyond document generation to reasoning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Detects Contradictions:&lt;/strong&gt; It flags tensions, such as a request for Native Mobile only paired with Critical SEO.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Surfaces Assumptions:&lt;/strong&gt; It states the assumptions it is making (e.g., assuming Stripe for payments) so an architect can confirm or override them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confidence Scoring:&lt;/strong&gt; It scores its own decisions, indicating where reviewers should focus attention.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How It Works: Four Specialized Agents
&lt;/h2&gt;

&lt;p&gt;The system runs &lt;a href="https://geekyants.com/consulting-services/artificial-intelligence-consulting/ai-pods" rel="noopener noreferrer"&gt;four specialized AI agents&lt;/a&gt; in sequence. The entire pipeline runs over a WebSocket connection, streaming progress to the dashboard in real time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Agent 1: Requirement Interpreter
&lt;/h3&gt;

&lt;p&gt;This agent parses raw, unstructured documents using format-specific tools (PyMuPDF, pandas, etc.). It extracts features, technical constraints, and non-functional requirements.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pattern Enrichment:&lt;/strong&gt; If a two-sided marketplace is mentioned, the system suggests features like ratings and booking based on a built-in knowledge base.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conflict Detection:&lt;/strong&gt; A rule engine identifies over-engineering or technical mismatches during initial analysis.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Agent 2: Solution Engine
&lt;/h3&gt;

&lt;p&gt;This agent produces tech stack recommendations and effort estimates. It uses a hybrid approach: deterministic rules suggest the baseline stack (e.g., &lt;a href="https://geekyants.com/hire-nest-js-developers" rel="noopener noreferrer"&gt;NestJS&lt;/a&gt;/PostgreSQL), while the &lt;a href="https://geekyants.com/ai/large-language-model-development-services" rel="noopener noreferrer"&gt;LLM&lt;/a&gt; validates that choice against the specific client context. Effort estimation provides optimistic-to-pessimistic ranges (e.g., "120–210 hours") to reflect real-world uncertainty.&lt;/p&gt;

&lt;h3&gt;
  
  
  Agent 3: Self-Critique
&lt;/h3&gt;

&lt;p&gt;Before a proposal is written, a critique agent reviews the solution for consistency. If an assumption contradicts a user input, the system sends a clarifying question back to the architect via WebSockets. Only when the critique approves does the pipeline proceed to generation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Agent 4: Proposal Composer
&lt;/h3&gt;

&lt;p&gt;The final agent selects a template (&lt;a href="https://geekyants.com/service/mvp-development-service" rel="noopener noreferrer"&gt;MVP&lt;/a&gt;, Enterprise, or Standard) and generates a Markdown proposal. The output covers Problem Understanding, Tech Stack, Architecture Overview, and Risk Mitigation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pipeline at a Glance
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stage&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. Parse&lt;/td&gt;
&lt;td&gt;Ingestion of any file type&lt;/td&gt;
&lt;td&gt;Combined raw text&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. Extract&lt;/td&gt;
&lt;td&gt;Conflict &amp;amp; pattern detection&lt;/td&gt;
&lt;td&gt;Structured requirements JSON&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. Design&lt;/td&gt;
&lt;td&gt;Rule-based stack matching&lt;/td&gt;
&lt;td&gt;Solution + effort mapping&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. Review&lt;/td&gt;
&lt;td&gt;Validation &amp;amp; User Clarification&lt;/td&gt;
&lt;td&gt;Approved technical solution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5. Write&lt;/td&gt;
&lt;td&gt;Template-based generation&lt;/td&gt;
&lt;td&gt;Polished Markdown/PDF proposal&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Engineering Insights
&lt;/h2&gt;

&lt;p&gt;Rule-based systems and LLMs complement each other: Conflict detection and effort mapping do not need an LLM — they need deterministic rules. LLMs handle ambiguity and prose generation.&lt;/p&gt;

&lt;p&gt;Transparency is the primary feature. The reasoning trace provides more value than the document itself. By showing why assumptions were made, the system enables architects to review proposals 5–10x faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Technical Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; &lt;a href="https://geekyants.com/hire-python-developers" rel="noopener noreferrer"&gt;Python&lt;/a&gt; with FastAPI for async orchestration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Layer:&lt;/strong&gt; OpenRouter (Claude, GPT-4, and Gemini) for multi-model reasoning.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Communication:&lt;/strong&gt; WebSockets for real-time streaming to a React-based frontend.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Knowledge Base:&lt;/strong&gt; JSON-based datasets for requirement patterns and stack decision rules.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Presales reasoning is repeatable. &lt;a href="https://geekyants.com/ai" rel="noopener noreferrer"&gt;AI systems&lt;/a&gt; that make reasoning transparent and reviewable accelerate the path from RFP to proposal.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was originally published on the &lt;a href="https://geekyants.com/blog/how-we-built-an-ai-system-that-automates-senior-solution-architect-workflows" rel="noopener noreferrer"&gt;GeekyAnts blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>From RFPs to Revenue: How We Built an AI Agent Team That Writes Technical Proposals in 60 Seconds</title>
      <dc:creator>GeekyAnts India Pvt Ltd</dc:creator>
      <pubDate>Wed, 15 Jul 2026 11:30:29 +0000</pubDate>
      <link>https://dev.to/geekyants/from-rfps-to-revenue-how-we-built-an-ai-agent-team-that-writes-technical-proposals-in-60-seconds-3oen</link>
      <guid>https://dev.to/geekyants/from-rfps-to-revenue-how-we-built-an-ai-agent-team-that-writes-technical-proposals-in-60-seconds-3oen</guid>
      <description>&lt;p&gt;The presales proposal process costs &lt;a href="https://geekyants.com/service/enterprise-software-development-services" rel="noopener noreferrer"&gt;software services companies&lt;/a&gt; 3 to 5 days per deal. DealRoom.ai reduces that to under 60 seconds using a pipeline of four coordinated &lt;a href="https://geekyants.com/ai/ai-agent-development-services" rel="noopener noreferrer"&gt;AI agents&lt;/a&gt; without compromising estimation accuracy or proposal quality.&lt;/p&gt;

&lt;p&gt;A technical proposal is the first deliverable a software company produces for a prospective client. It sets scope, cost expectations, and credibility. The process of producing one has not changed in years.&lt;/p&gt;

&lt;p&gt;An RFP arrives. A discovery call follows. Requirements are distributed across a PDF brief, a Word document, follow-up emails, and meeting notes. A solutions architect spends 3-5 days synthesizing these inputs into a proposal. The output is a static document that can be outdated by client review.&lt;/p&gt;

&lt;p&gt;This is where deals are won or lost, and the process is a bottleneck that companies accept as fixed. DealRoom.ai was built on the premise that it is not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where does the time go
&lt;/h2&gt;

&lt;p&gt;The time cost of presales is distributed unevenly. Analysis of the process across software services teams shows a consistent breakdown:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;40% — Reading and reviewing source documents&lt;/li&gt;
&lt;li&gt;25% — Feature estimation&lt;/li&gt;
&lt;li&gt;20% — Formatting and assembly&lt;/li&gt;
&lt;li&gt;15% — Review and revision&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Estimation carries the highest risk. Review of actual project sheets from delivered engagements found the same feature assigned 40 hours by one architect and 120 hours by another. Not because of error, but because there was no shared knowledge base, no institutional memory, and no standard method.&lt;/p&gt;

&lt;p&gt;For organizations running 20 or more active deals per month, that variance affects more than proposal quality. It limits revenue capacity.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gap lies in execution
&lt;/h2&gt;

&lt;p&gt;Every presales team has a list of use cases. Delivery pipelines break down. The AI use case gets handed to an existing engineering team. Generalist developers spend months learning new toolchains. The result is a prototype that works in a demo and breaks in production. The initiative stalls. The use case gets deprioritized.&lt;/p&gt;

&lt;p&gt;DealRoom.ai closes that gap at the presales stage, producing proposals that are accurate, structured, and ready to send.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four agents. One coordinated pipeline.
&lt;/h2&gt;

&lt;p&gt;DealRoom is not a single model that reads a document and returns a summary. It is four specialized agents, each with a defined role, passing structured output through a coordinated pipeline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;01 — The Analyst&lt;/strong&gt; ingests source materials — PDFs, Word documents, and follow-up emails — and extracts structured data: features, user roles, priorities, technical constraints, and integration requirements. It interprets intent. A reference to a map-based tracking feature is translated into its technical components: real-time data requirements, relevant APIs, and &lt;a href="https://geekyants.com/engineering/backend" rel="noopener noreferrer"&gt;backend service&lt;/a&gt; dependencies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;02 — The Architect&lt;/strong&gt; maps the Analyst's structured output into systems, modules, and a recommended &lt;a href="https://geekyants.com/en-in/blog/how-to-choose-the-right-tech-stack-to-build-a-mobile-app" rel="noopener noreferrer"&gt;technology stack&lt;/a&gt;. Each feature is enriched with hours and complexity data from a knowledge base built on historical actuals from delivered projects. Estimates reference what similar features took in production, not inference from a language model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;03 — The Estimator&lt;/strong&gt; produces three delivery strategies. Conservative defines a minimum viable scope with a lean team. Balanced covers the full scope with a right-sized team and standard timeline. Aggressive deploys a larger parallel team to compress delivery at a higher cost. Each strategy includes a cost breakdown, timeline, team composition, and risk profile.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;04 — The Devil's Advocate&lt;/strong&gt; reviews the output of the preceding agents and challenges assumptions. It identifies timelines that do not account for third-party API stabilization, flags compliance requirements present in the brief that are absent from the feature set, and surfaces integration dependencies that were not addressed during architecture. The proposal survives internal challenges before it reaches the client.&lt;/p&gt;

&lt;h2&gt;
  
  
  The output is a working interface, not a static document
&lt;/h2&gt;

&lt;p&gt;Most proposals are PDFs. Clients open them, scroll through, and send questions that take 48 hours to answer. That exchange delays decisions and adds friction to the close.&lt;/p&gt;

&lt;p&gt;DealRoom produces a web-based proposal that clients can explore. A scope map presents project structure as an expandable hierarchy. A feature toggle table allows stakeholders to include or exclude individual features; each change updates cost, timeline, and team size in real time — no revised estimates, no back-and-forth.&lt;/p&gt;

&lt;p&gt;The analytics section gives budget owners and technical decision-makers what they need to evaluate the proposal internally: cost distribution by system, effort by development phase, and team utilization across the delivery period. That data is part of the proposal itself, not a follow-up request.&lt;/p&gt;

&lt;p&gt;Every estimate carries a confidence score. A high score indicates grounding in historical project actuals. A lower score flags features estimated without historical precedent — the areas a presales lead should review before submission.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical implementation
&lt;/h2&gt;

&lt;p&gt;The frontend is built with &lt;a href="https://geekyants.com/hire-next-js-developers" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt;, deployed on Vercel. The backend runs on &lt;a href="https://geekyants.com/hire-python-developers" rel="noopener noreferrer"&gt;Python&lt;/a&gt; with FastAPI, deployed on Railway, orchestrating agents through an asynchronous pipeline with Server-Sent Events streaming updates to the interface as work proceeds.&lt;/p&gt;

&lt;p&gt;The architecture separates language model reasoning from deterministic computation. The Analyst and Architect use GPT-4.1 for document interpretation and system reasoning. The Estimator builds strategies through knowledge-base-driven computation. The Devil's Advocate runs on GPT-4.1-mini. Post-estimator agents execute in parallel via asyncio to maintain pipeline throughput.&lt;/p&gt;

&lt;p&gt;The knowledge base underpins every estimate: feature libraries with historical hour ranges from delivered projects, pricing benchmarks by role and seniority, team composition templates, and overhead formulas covering &lt;a href="https://geekyants.com/service/hire-quality-assurance-developers" rel="noopener noreferrer"&gt;QA&lt;/a&gt;, &lt;a href="https://geekyants.com/service/business-analysis-services" rel="noopener noreferrer"&gt;business analysis&lt;/a&gt;, tech lead, documentation, and deployment. When the system assigns 52 hours to a feature, that figure has a source in actual project data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three conclusions from development
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Pure language model pipelines are not sufficient for production estimation.
&lt;/h3&gt;

&lt;p&gt;Document interpretation and system reasoning require language model capabilities. Cost calculation and structured data assembly do not. Separating these concerns produces outputs that are analytic and contextually accurate. Conflating them produces outputs that are neither.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Internal challenge before client delivery is a quality mechanism, not an overhead.
&lt;/h3&gt;

&lt;p&gt;Proposals processed through the Devil's Advocate review carried timelines 15 to 20 percent longer — and were more defensible. The review identified integration dependencies and compliance gaps that the Architect had not addressed. The cost of that review is low. The cost of a client finding those gaps after submission is not.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Presentation format determines how the analysis is acted upon.
&lt;/h3&gt;

&lt;p&gt;An accurate proposal in a static document loses stakeholder attention before the scope is reviewed. The same content in an interactive format held attention through review and generated substantive questions from decision-makers. The format through which analysis is delivered shapes the quality of the decisions it produces.&lt;/p&gt;

&lt;h2&gt;
  
  
  Current scope and roadmap
&lt;/h2&gt;

&lt;p&gt;DealRoom supports &lt;a href="https://geekyants.com/industry/healthcare-app-development-services" rel="noopener noreferrer"&gt;healthcare&lt;/a&gt;, &lt;a href="https://geekyants.com/industry/ecommerce-app-development-services" rel="noopener noreferrer"&gt;e-commerce&lt;/a&gt;, and &lt;a href="https://geekyants.com/industry/education-software-development-services" rel="noopener noreferrer"&gt;edtech domains&lt;/a&gt;, each with domain-specific knowledge bases and feature libraries. &lt;a href="https://geekyants.com/industry/fintech-app-development-services" rel="noopener noreferrer"&gt;Fintech&lt;/a&gt;, logistics, and SaaS are next.&lt;/p&gt;

&lt;p&gt;A feedback mechanism is in development to route accepted proposals back into the knowledge base. Each completed engagement would refine the estimation data available to future proposals. The objective is a system whose accuracy improves with use, not one that remains static after deployment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://geekyants.com/en-us" rel="noopener noreferrer"&gt;GeekyAnts&lt;/a&gt; developed DealRoom.ai as part of the Age of Agents track. It applies multi-agent coordination to a high-frequency, high-stakes business process, demonstrating that &lt;a href="https://geekyants.com/blog/the-missing-link-in-autonomous-ai--agent-to-human-protocol-a2h" rel="noopener noreferrer"&gt;autonomous agent&lt;/a&gt; pipelines can deliver production-quality outputs in commercial workflows where accuracy and consistency are non-negotiable.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was originally published on the &lt;a href="https://geekyants.com/blog/from-rfps-to-revenue-how-we-built-an-ai-agent-team-that-writes-technical-proposals-in-60-seconds" rel="noopener noreferrer"&gt;GeekyAnts blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>technology</category>
    </item>
    <item>
      <title>How Playwright Agents Are Changing the Way We Write and Maintain Tests</title>
      <dc:creator>GeekyAnts India Pvt Ltd</dc:creator>
      <pubDate>Fri, 10 Jul 2026 08:10:24 +0000</pubDate>
      <link>https://dev.to/geekyants/how-playwright-agents-are-changing-the-way-we-write-and-maintain-tests-3abg</link>
      <guid>https://dev.to/geekyants/how-playwright-agents-are-changing-the-way-we-write-and-maintain-tests-3abg</guid>
      <description>&lt;p&gt;&lt;em&gt;Adapted from the original post on the &lt;a href="https://geekyants.com/blog/from-manual-testing-to-ai-assisted-automation-with-playwright-agents" rel="noopener noreferrer"&gt;GeekyAnts blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Ask any &lt;a href="https://geekyants.com/engineering/quality-assurance/qa-automation-testing" rel="noopener noreferrer"&gt;automation engineer&lt;/a&gt; what their week looks like and you'll hear some version of the same story: read the requirements, write the test cases, script the automation, watch a locator break, chase down why, fix it, run it again. That loop hasn't really gone anywhere — it just moved frameworks, from Selenium to Cypress to Playwright.&lt;/p&gt;

&lt;p&gt;So here's a question worth sitting with: what if the framework didn't just run your tests, but actually helped plan them, write them, and repair them when they broke? That's the pitch behind &lt;a href="https://geekyants.com/en-in/blog/how-ai-ml-are-transforming-quality-assurance-in-software-testing-with-playwright-examples" rel="noopener noreferrer"&gt;Playwright's Test Agents&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Shipped in Playwright 1.56, these agents bring &lt;a href="https://geekyants.com/ai/ai-agent-development-services" rel="noopener noreferrer"&gt;AI&lt;/a&gt; into three specific stages of the testing lifecycle — planning, writing, and healing — by looping against your actual running application rather than guessing from a prompt alone.&lt;/p&gt;

&lt;p&gt;This piece walks through what the agents do, how a project gets wired up to use them, what a seed test is for, what comes out the other end, and where this genuinely differs from just asking &lt;a href="https://geekyants.com/blog/top-8-ai-coding-tools-for-developers-in-the-usa-2025-edition" rel="noopener noreferrer"&gt;ChatGPT or Cursor&lt;/a&gt; to write you a test script.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Playwright Alone Wasn't Enough
&lt;/h2&gt;

&lt;p&gt;Playwright earned its popularity by killing off a lot of the pain that made older frameworks miserable — flaky waits, brittle timing, locators that broke for no obvious reason. Auto-waiting, role-based selectors, and built-in tracing meant engineers spent less time fighting the tool and more time actually testing.&lt;/p&gt;

&lt;p&gt;But none of that touched the manual work upstream and downstream of running the tests: translating a requirement doc into concrete scenarios, turning those scenarios into actual code, rewriting tests every time the UI shifts, and chasing broken selectors after every release. Agents are Playwright's attempt to close that gap.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Three Agents Actually Do
&lt;/h2&gt;

&lt;p&gt;Playwright Test Agents are &lt;a href="https://geekyants.com/blog/revolutionizing-business-process-automation-with-ai-agents" rel="noopener noreferrer"&gt;AI workflows&lt;/a&gt; that live inside a project and split the job into three roles.&lt;/p&gt;

&lt;p&gt;The Planner takes a plain-language description of what needs testing, then uses a "seed test" as its entry point into the app to explore flows and edge cases. It comes back with a structured written test plan — not code, but the kind of scenario breakdown a &lt;a href="https://geekyants.com/service/hire-quality-assurance-developers" rel="noopener noreferrer"&gt;QA engineer&lt;/a&gt; would write by hand.&lt;/p&gt;

&lt;p&gt;The Generator takes that plan and turns it into runnable Playwright code. Crucially, it does this while poking at the live app — checking that selectors actually resolve, that assertions match real UI state — rather than hallucinating locators from memory. Told to, it'll follow a Page Object Model layout too.&lt;/p&gt;

&lt;p&gt;The Healer steps in when a test fails. It re-runs the failing scenario, looks at the current DOM, works out what changed, and tries to patch the selector, wait, or interaction logic itself, instead of leaving that job to whoever's on call.&lt;/p&gt;

&lt;p&gt;Chain the three together and the loop becomes Planner, then Generator, then Healer — turning a sentence of intent into a working, self-repairing test suite.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up a Project
&lt;/h2&gt;

&lt;p&gt;Getting started involves scaffolding a standard Node and Playwright project first, exactly as any engineer already familiar with Playwright would expect. From there, Playwright's own agent tooling can be initialized, which adds a new folder of agent definitions into the project alongside the usual test folders.&lt;/p&gt;

&lt;p&gt;That new folder holds three files, one for each agent: the planner, the generator, and the healer, each written as a Markdown definition. Whatever AI assistant is driving the workflow, whether that's Claude Code, VS Code's Copilot, or another agentic coding tool, reads these definitions to understand how to behave in each role.&lt;/p&gt;

&lt;p&gt;Alongside the agent definitions, a typical project ends up with a folder for the Markdown plans the Planner produces, a folder for the actual generated Playwright test files, and a single seed test that acts as the Planner's starting point into the application. This layout is the convention Playwright's own tooling expects, so sticking to it keeps things predictable.&lt;/p&gt;

&lt;p&gt;The seed test matters more than it sounds like it should. It's the Planner's foothold: where to navigate first, what login step to run, what "home base" looks like for the application before any exploration begins. Alongside it, a small file of sample data (a couple of test user credentials, say — one valid, one intentionally invalid) gives the Planner enough grounding to write scenarios that are actually relevant to the app rather than generic boilerplate.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Planner Agent in Practice
&lt;/h2&gt;

&lt;p&gt;Think of the Planner less like a code generator and more like a QA analyst that happens to run on AI. Instead of jumping straight to code, it produces a Markdown test plan: scenarios, steps, expected outcomes, and the data each one needs.&lt;/p&gt;

&lt;p&gt;A prompt as simple as asking for a test plan covering login with both valid and invalid credentials, using the seed test as context, is enough to get it moving. The Planner explores the app through that seed test and writes out a plan as a readable document, not a script, meant to be read and approved before any code gets written. This is the step where a bad assumption gets caught early, before it turns into a bad test.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Generator Agent: Plan to Code
&lt;/h2&gt;

&lt;p&gt;Once a plan looks right, the same assistant can be switched into Generator mode and asked to turn that Markdown plan into actual TypeScript tests, following a Page Object Model structure if that's the preference.&lt;/p&gt;

&lt;p&gt;The Generator reads the plan, checks selectors and assertions against the live app as it writes, and produces test files — typically one for a straightforward happy path, one covering an edge case, and others built around shared helper functions. Each generated file maps back to a scenario from the plan. Because it's validating against the running app rather than guessing, the output tends to be noticeably more stable than what comes out of a plain prompt-to-code tool with no live context.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Healer Agent: Fixing What Breaks
&lt;/h2&gt;

&lt;p&gt;Tests fail. A button gets relabeled, a locator moves, and something that passed yesterday doesn't today. Normally that means opening the inspector, finding the new selector, and patching it by hand.&lt;/p&gt;

&lt;p&gt;The Healer automates that chase. Pointed at a specific failing test, it re-runs it in debug mode, inspects the current DOM for an equivalent element or flow, proposes a fix such as a new selector or an adjusted wait, and re-runs until it either passes or the agent concludes the failure actually reflects a real product change rather than a stale test. That second outcome matters: the goal isn't to force a green checkmark at any cost, it's to cut down the routine busywork of chasing UI churn.&lt;/p&gt;

&lt;h2&gt;
  
  
  Under the Hood: What's Actually Happening
&lt;/h2&gt;

&lt;p&gt;From the outside, all of this looks deceptively simple: type a sentence, get back a test plan or a fix. Underneath, the agents run a loop that reads project files, executes real test runs, drives the browser, and inspects the live DOM at every stage. The Planner explores through the seed test, the Generator checks selectors as it writes, the Healer replays failures to diagnose them. That complexity stays hidden — a prompt goes in, a plan, script, or fix comes out, and the orchestration in between isn't something anyone has to manage by hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping the Output Organized with Page Object Model
&lt;/h2&gt;

&lt;p&gt;If the generated code needs to stay maintainable long-term, and it should, it's worth being explicit about that in the prompt: asking for a Page Object Model structure with locators kept in separate page files. That nudges the Generator toward splitting locator definitions and reusable actions into their own files, separate from the test logic itself, which saves a lot of refactoring down the line.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Full Loop, End to End
&lt;/h2&gt;

&lt;p&gt;Run all three agents together and the shape of the workflow is: a seed test plus a prompt goes to the Planner, which writes a Markdown plan; that plan goes to the Generator, which writes the tests; those tests run, and any failures go to the Healer, which fixes what it can. What comes out the other side is a test suite that largely maintains itself. It's the same lifecycle a human QA team already runs, just with AI doing the first draft at every stage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where This Differs From Generic AI Coding Tools
&lt;/h2&gt;

&lt;p&gt;It's tempting to lump this in with Cursor, ChatGPT, or any other "AI writes my code" tool, but the comparison doesn't hold up well. Generic AI code generation can write code from a prompt, but it doesn't run the tests it writes, doesn't fix failures on its own, and doesn't check the live DOM while generating. Playwright Agents do all three, and they do it wired directly into Playwright's own tooling through MCP (Model Context Protocol), staying in the loop with the running application throughout rather than generating code from a prompt in isolation.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Few Things That Make This Work Better
&lt;/h2&gt;

&lt;p&gt;Giving the agents real context matters more than clever prompting — a well-built seed test and structured seed data make a bigger difference than a cleverly worded instruction. Prompts should be specific about architecture preferences, data sources, and expected outputs rather than left open-ended. Generated tests are still worth a human read-through; good scaffolding isn't the same as a finished, reviewed test. And in CI, healed or freshly generated tests are best treated as drafts until someone's actually looked at them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Between the Planner, Generator, and Healer, Playwright's agents take a real bite out of the manual overhead in test automation, turning a plain-language description into scenarios, code, and self-repair without cutting humans out of the review loop.&lt;/p&gt;

&lt;p&gt;Anyone with basic Playwright experience already has most of what they need to try this. It's the same lifecycle, with AI doing more of the first draft. Worth trying on a small project first: set up the agents, write a decent seed test, and see how far a simple prompt actually gets.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Adapted from the original article on the &lt;a href="https://geekyants.com/blog/from-manual-testing-to-ai-assisted-automation-with-playwright-agents" rel="noopener noreferrer"&gt;GeekyAnts blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>automation</category>
      <category>playwright</category>
      <category>ai</category>
    </item>
    <item>
      <title>Building a Production-Ready Image Cropper in React Native</title>
      <dc:creator>GeekyAnts India Pvt Ltd</dc:creator>
      <pubDate>Thu, 09 Jul 2026 07:13:15 +0000</pubDate>
      <link>https://dev.to/geekyants/building-a-production-ready-image-cropper-in-react-native-5ckm</link>
      <guid>https://dev.to/geekyants/building-a-production-ready-image-cropper-in-react-native-5ckm</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally published on the &lt;a href="https://geekyants.com/blog/building-a-production-ready-image-cropper-in-react-native" rel="noopener noreferrer"&gt;GeekyAnts Blog&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Build a production-ready, gesture-driven image cropper from scratch — supporting circular profile crops, rectangular cover crops, draggable windows, resizable corners, and pixel-perfect coordinate mapping back to the original image.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://geekyants.com/service/hire-mobile-app-development-services" rel="noopener noreferrer"&gt;modern mobile applications&lt;/a&gt;, image handling is a core experience. Whether uploading a profile picture or setting a cover image, users expect precision, control, and real-time feedback.&lt;/p&gt;

&lt;p&gt;While third-party libraries exist, they often introduce heavy dependencies or limit customization. In this article, we'll build a fully custom, gesture-driven image cropper using &lt;a href="https://geekyants.com/hire-react-native-developers" rel="noopener noreferrer"&gt;React Native&lt;/a&gt; and expo-image-manipulator — supporting both circular profile crops and rectangular cover crops.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why expo-image-manipulator?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;expo-image-manipulator&lt;/strong&gt; provides a native bridge for performing image transformations efficiently. All operations — crop, resize, rotate, flip — execute on the native thread, which means they don't block the JS runtime and scale well even on lower-end Android devices.&lt;/p&gt;

&lt;p&gt;Compared to pure JS image-processing approaches, the native execution path avoids decoding the full bitmap into a JS array buffer, which can easily exhaust memory on high-resolution photos. The library also handles format conversion (JPEG, PNG, WEBP) and compression in a single pass, so you aren't writing a cropped image to disk and then re-encoding it for upload — the final &lt;strong&gt;manipulateAsync&lt;/strong&gt; call produces the upload-ready file directly.&lt;/p&gt;

&lt;p&gt;The package ships two API styles. The legacy imperative API (&lt;strong&gt;manipulateAsync&lt;/strong&gt;) applies a list of transforms in a single async call — ideal for a one-shot crop like ours. The newer context-based API (&lt;strong&gt;useImageManipulator / ImageManipulator.manipulate&lt;/strong&gt;) enables chainable, background-threaded transforms and shines when you need to compose many operations interactively without writing intermediate files to disk. We'll use the imperative API throughout this post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation &amp;amp; Setup
&lt;/h2&gt;

&lt;p&gt;Install via the Expo CLI so the correct native version is automatically matched to your SDK:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx expo &lt;span class="nb"&gt;install &lt;/span&gt;expo-image-manipulator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a bare React Native project (without Expo Go), also run the iOS pod install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx pod-install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No additional permissions are required. The manipulator operates entirely on local file URIs produced by your image picker — it never touches the camera roll or network directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  expo-image-manipulator API Overview
&lt;/h2&gt;

&lt;p&gt;We'll use the imperative API — it's perfectly suited to a one-shot crop operation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Function
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;ImageManipulator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;manipulateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;        &lt;span class="c1"&gt;// local file URI or base64 data URI&lt;/span&gt;
  &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;// array of transformation objects&lt;/span&gt;
  &lt;span class="nx"&gt;saveOptions&lt;/span&gt; &lt;span class="c1"&gt;// format, compress, base64&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It returns a &lt;strong&gt;Promise&lt;/strong&gt; which resolves to:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;url&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;Local URI to the new file (cached)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;width&lt;/td&gt;
&lt;td&gt;number&lt;/td&gt;
&lt;td&gt;Width of the output image in pixels&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;height&lt;/td&gt;
&lt;td&gt;number&lt;/td&gt;
&lt;td&gt;Height of the output image in pixels&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;base64&lt;/td&gt;
&lt;td&gt;string?&lt;/td&gt;
&lt;td&gt;Base64 payload if base64: true was passed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Available Actions
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action key&lt;/th&gt;
&lt;th&gt;Parameters&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;crop&lt;/td&gt;
&lt;td&gt;originX, originY, width, height&lt;/td&gt;
&lt;td&gt;Crops a rectangular region (in original image pixels)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;resize&lt;/td&gt;
&lt;td&gt;width, height&lt;/td&gt;
&lt;td&gt;Scales the image; omit one dimension to keep ratio&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rotate&lt;/td&gt;
&lt;td&gt;degrees&lt;/td&gt;
&lt;td&gt;Clockwise rotation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;flip&lt;/td&gt;
&lt;td&gt;"horizontal" | "vertical"&lt;/td&gt;
&lt;td&gt;Mirror along an axis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;extent&lt;/td&gt;
&lt;td&gt;originX, originY, width, height, backgroundColor&lt;/td&gt;
&lt;td&gt;Canvas resize with optional padding fill&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Save Options
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;format&lt;/td&gt;
&lt;td&gt;SaveFormat&lt;/td&gt;
&lt;td&gt;JPEG&lt;/td&gt;
&lt;td&gt;JPEG, PNG, or WEBP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;compress&lt;/td&gt;
&lt;td&gt;0.0 – 1.0&lt;/td&gt;
&lt;td&gt;1.0&lt;/td&gt;
&lt;td&gt;1 = highest quality, 0 = maximum compression&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;base64&lt;/td&gt;
&lt;td&gt;boolean&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;td&gt;Include raw base64 in the result&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Component Architecture
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;&lt;/strong&gt; component lives inside an action sheet and owns three pieces of state that together describe the current crop selection:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;containerSize&lt;/strong&gt; — measured width and height of the image container, captured via onLayout&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;cropPosition&lt;/strong&gt; — the top-left corner of the crop window in container-space coordinates ({ x, y })&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;windowDimensions&lt;/strong&gt; — the current width and height of the crop window in container space&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All crop math operates in container space first, then gets converted to original image pixel space at the moment the user taps Crop. This separation keeps gesture handling fast and stateless — no expensive native calls happen during a drag.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnyytw8vyz9w9qpmrj0jg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnyytw8vyz9w9qpmrj0jg.png" alt="React Native image crop architecture with container sizing, crop position, and upload pipeline" width="800" height="157"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Props
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ImageCropProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;showCropper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;        &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;handleClose&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;        &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;selectedUploadType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cover&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;uploadFunction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ImageManipulator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ImageResult&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;tempImage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;          &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// local URI from image picker&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On mount, two effects run in sequence: the first sets &lt;strong&gt;windowDimensions&lt;/strong&gt; based on the upload type (square for profile, wide rectangle for cover), and the second centers the crop window inside the container once both sizes are known.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Profile: square up to 200 px. Cover: full width × 150 px.&lt;/span&gt;
&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;containerSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selectedUploadType&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;containerSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;setWindowDimensions&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setWindowDimensions&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;containerSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;containerSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selectedUploadType&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="c1"&gt;// Center the window once both sizes are known&lt;/span&gt;
&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;containerSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setCropPosition&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;containerSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;containerSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;containerSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Building The Drag &amp;amp; Resize System
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Dragging the crop window
&lt;/h3&gt;

&lt;p&gt;The crop window is a positioned &lt;strong&gt;View&lt;/strong&gt; sitting absolutely on top of the image. A &lt;strong&gt;PanResponder&lt;/strong&gt; attached to its inner area tracks the gesture delta (&lt;strong&gt;dx&lt;/strong&gt;, &lt;strong&gt;dy&lt;/strong&gt;) and updates &lt;strong&gt;cropPosition&lt;/strong&gt;, clamping it so the window never exits the container boundary.&lt;/p&gt;

&lt;p&gt;One subtle requirement: the pan responder must not activate when the touch originates inside one of the 20 px corner zones — otherwise the drag and resize responders fire simultaneously and produce jittery, conflicting movement. We check touch coordinates in &lt;strong&gt;onStartShouldSetPanResponder&lt;/strong&gt; and return &lt;strong&gt;false&lt;/strong&gt; for corner touches.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;panResponder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;PanResponder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;onStartShouldSetPanResponder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;locationX&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;locationY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nativeEvent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inCorner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;cs&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;cs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;cs&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;cs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;inCorner&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;onMoveShouldSetPanResponder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Mirrors onStartShouldSetPanResponder — keeps both predicates in sync&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;locationX&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;locationY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nativeEvent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;cs&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;cs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;cs&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;cs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;onPanResponderMove&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;dx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dy&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setCropPosition&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nx"&gt;cropPosition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;dx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;containerSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;
        &lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nx"&gt;cropPosition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;dy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;containerSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;
        &lt;span class="p"&gt;)),&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;containerSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cropPosition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why useMemo matters here
&lt;/h3&gt;

&lt;p&gt;The pan responder captures &lt;strong&gt;cropPosition&lt;/strong&gt; and &lt;strong&gt;windowDimensions&lt;/strong&gt; in its closure at creation time. Without &lt;strong&gt;useMemo&lt;/strong&gt;, a new responder is created on every render, but the gesture system holds a reference to the original — meaning your move handler reads stale state and the crop window drifts noticeably during a fast drag. Wrapping in &lt;strong&gt;useMemo&lt;/strong&gt; with the correct dependency array ensures the responder is always reading current values.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resizing with corner handles
&lt;/h2&gt;

&lt;p&gt;Each of the four corner handles has its own &lt;strong&gt;PanResponder&lt;/strong&gt;, created by a factory function. The geometry differs per corner: dragging bottom-right simply extends width and height, while dragging top-left must simultaneously shrink the window and shift its origin so the opposite corner stays anchored in place.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createCornerPanResponder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;corner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;topLeft&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;topRight&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bottomLeft&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bottomRight&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;PanResponder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;onStartShouldSetPanResponder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;onPanResponderMove&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;dx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dy&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;newW&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;newH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;newX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cropPosition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;newY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cropPosition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;corner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bottomRight&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;newW&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;minDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;dx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;newH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isProfile&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;newW&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;minDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;dy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;topLeft&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;newW&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;minDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;dx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;newH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isProfile&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;newW&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;minDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;dy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;newX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cropPosition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newW&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;newY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cropPosition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newH&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;topRight&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;newW&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;minDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;dx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;newH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isProfile&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;newW&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;minDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;dy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;newY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cropPosition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;newH&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bottomLeft&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;newW&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;minDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;dx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;newH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isProfile&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;newW&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;minDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;dy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;newX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cropPosition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newW&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// Commit only if the new geometry fits entirely within the container&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;newX&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;newY&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
      &lt;span class="nx"&gt;newX&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;newW&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;containerSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
      &lt;span class="nx"&gt;newY&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;newH&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;containerSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setWindowDimensions&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newW&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newH&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="nf"&gt;setCropPosition&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newY&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For profile mode, height is always forced equal to width (&lt;strong&gt;newH = newW&lt;/strong&gt;) regardless of which corner is dragged, preserving a perfect 1:1 aspect ratio at every resize step. Cover mode allows independent width and height resizing, subject to configurable minimum dimensions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Coordinate Mapping: Display → Original Pixels
&lt;/h2&gt;

&lt;p&gt;This is the most critical — and most commonly misunderstood — part of building a &lt;a href="https://geekyants.com/blog/image-cropping-and-optimised-transfer-in-flutter" rel="noopener noreferrer"&gt;custom cropper&lt;/a&gt;. Your crop window lives in &lt;em&gt;container space&lt;/em&gt; (screen pixels inside the &lt;strong&gt;View&lt;/strong&gt;), but &lt;strong&gt;manipulateAsync&lt;/strong&gt; expects coordinates in &lt;em&gt;original image pixel space&lt;/em&gt;. The two are not the same.&lt;/p&gt;

&lt;p&gt;When an image is rendered with &lt;strong&gt;contentFit="cover"&lt;/strong&gt;, React Native scales it so the shorter dimension fills the container exactly — and the longer dimension overflows and is clipped. This means part of the image is hidden off-screen, and any crop coordinate you compute from container space will be offset by exactly that hidden amount unless you correct for it.&lt;/p&gt;

&lt;p&gt;The conversion has five steps:&lt;/p&gt;

&lt;p&gt;Step 1 — Get the original image dimensions. Call &lt;strong&gt;manipulateAsync&lt;/strong&gt; with an empty actions array. This is a lightweight metadata read with no transformation cost.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imageInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ImageManipulator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;manipulateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;tempImage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;compress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 2 — Determine the displayed dimensions. Compare aspect ratios to find which axis is the constraining one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imgAR&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;imageInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;imageInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;containerAR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;containerSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;containerSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;displayedW&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;displayedH&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;imgAR&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;containerAR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Image is wider than container — height fills, width overflows left/right&lt;/span&gt;
  &lt;span class="nx"&gt;displayedH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;containerSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;displayedW&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;containerSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;imgAR&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Image is taller than container — width fills, height overflows top/bottom&lt;/span&gt;
  &lt;span class="nx"&gt;displayedW&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;containerSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;displayedH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;containerSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;imgAR&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 3 — Compute the overflow offset. The image is centered inside the container, so the hidden portion is split equally on both sides.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;offsetX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;displayedW&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;containerSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// 0 when image is taller&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;offsetY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;displayedH&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;containerSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// 0 when image is wider&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 4 — Compute scale factors between the original image and the displayed image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scaleX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;imageInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;  &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;displayedW&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scaleY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;imageInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;displayedH&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 5 — Convert UI coordinates to image coordinates.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;actualCropX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;cropPosition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;offsetX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;scaleX&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;actualCropY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;cropPosition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;offsetY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;scaleY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Executing The Crop — Profile &amp;amp; Cover
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Profile Photo (square, resized to 200 x 200)
&lt;/h3&gt;

&lt;p&gt;For a profile photo, we want a square crop. We clamp the crop size so it never requests pixels beyond the image boundary, then chain a resize to normalise all uploads to 200 × 200 regardless of how large the user's original photo was.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;actualCropSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;scaleX&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;finalSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;actualCropSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;imageInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;actualCropX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;imageInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;actualCropY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;croppedImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ImageManipulator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;manipulateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;tempImage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;crop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;originX&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;actualCropX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;originY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;actualCropY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="nx"&gt;finalSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="nx"&gt;finalSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="p"&gt;}},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;compress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ImageManipulator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SaveFormat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;JPEG&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;uploadFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;croppedImage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Cover photo (rectangular)
&lt;/h3&gt;

&lt;p&gt;The cover crop uses independent width and height scale factors and clamps each dimension separately so neither ever exceeds the remaining pixels after the crop origin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;actualCropW&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;  &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;scaleX&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;imageInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;actualCropX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;actualCropH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;scaleY&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;imageInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;actualCropY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;


&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;croppedImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ImageManipulator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;manipulateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;tempImage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;crop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;originX&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;actualCropX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;originY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;actualCropY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="nx"&gt;actualCropW&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="nx"&gt;actualCropH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}}],&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;compress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ImageManipulator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SaveFormat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;JPEG&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;uploadFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;croppedImage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Darkened Overlay Cutout
&lt;/h3&gt;

&lt;p&gt;Rather than a single semi-transparent layer with a punched-out hole (which requires SVG clip-paths or canvas rendering), we use four darkened Views — one for each side of the crop window. Their positions and sizes are derived directly from &lt;strong&gt;cropPosition&lt;/strong&gt; and &lt;strong&gt;windowDimensions&lt;/strong&gt;, so they update in real time as the user drags or resizes without any additional state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Top — spans full width, height = distance from top to crop window */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;absolute&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cropPosition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rgba(0,0,0,0.5)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Bottom — starts where the crop window ends */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;absolute&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;containerSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cropPosition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rgba(0,0,0,0.5)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Left — only spans the crop window's row to avoid double-darkening corners */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;absolute&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cropPosition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cropPosition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rgba(0,0,0,0.5)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Right — mirrors left */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;absolute&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cropPosition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;containerSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cropPosition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;windowDimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rgba(0,0,0,0.5)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the crop window, the border style switches between a full-radius dashed circle (borderRadius: 999, borderStyle: 'dashed') for profile mode and a plain solid rectangle for cover mode. A rule-of-thirds grid is drawn with four thin Views at 33% and 66% positions, giving users a professional alignment guide without any additional library.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ImageCrop&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./ImageCrop&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyScreen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;showCropper&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setShowCropper&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;pickedImage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="nx"&gt;setPickedImage&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleUpload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ImageManipulator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ImageResult&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;uploadToServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setShowCropper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... rest of your screen ... */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pickedImage&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ImageCrop&lt;/span&gt;
          &lt;span class="na"&gt;showCropper&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;showCropper&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;handleClose&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setShowCropper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;selectedUploadType&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"profile"&lt;/span&gt;
          &lt;span class="na"&gt;tempImage&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pickedImage&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;uploadFunction&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleUpload&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  UX Enhancements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Grid lines (rule of thirds)&lt;/li&gt;
&lt;li&gt;Corner handles for resizing&lt;/li&gt;
&lt;li&gt;Loading overlay during processing&lt;/li&gt;
&lt;li&gt;Auto-centered crop window&lt;/li&gt;
&lt;li&gt;Dynamic resizing based on container&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Performance Considerations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Avoid repeated &lt;strong&gt;manipulateAsync&lt;/strong&gt; calls&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;useMemo&lt;/strong&gt; for gesture handlers&lt;/li&gt;
&lt;li&gt;Perform crop only on user confirmation&lt;/li&gt;
&lt;li&gt;Use compression wisely (&lt;strong&gt;0.8–1&lt;/strong&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Advanced Extensions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Pinch-to-zoom support&lt;/li&gt;
&lt;li&gt;Rotation &amp;amp; flipping controls&lt;/li&gt;
&lt;li&gt;Circular live preview&lt;/li&gt;
&lt;li&gt;Cloud upload integration (S3/Firebase)&lt;/li&gt;
&lt;li&gt;Combined zoom + crop gestures&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary &amp;amp; Key Takeaways
&lt;/h2&gt;

&lt;p&gt;Building a custom image cropper in React Native gives you &lt;strong&gt;full control over &lt;a href="https://geekyants.com/service/ui-ux-design-services" rel="noopener noreferrer"&gt;UX&lt;/a&gt;, performance, and flexibility&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Key learnings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;expo-image-manipulator&lt;/strong&gt; handles heavy image processing natively&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PanResponder&lt;/strong&gt; is sufficient for complex gesture interactions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coordinate mapping is the backbone&lt;/strong&gt; of accurate cropping&lt;/li&gt;
&lt;li&gt;Overlay-based masking provides a clean UI without extra dependencies&lt;/li&gt;
&lt;li&gt;Supporting multiple crop modes requires thoughtful architecture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach is particularly valuable for applications handling user-generated content, where performance, flexibility, and consistent media output directly impact user experience and scalability.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Special thanks to Deepanshu Goyal for architectural guidance and review.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article was originally published on the &lt;a href="https://geekyants.com/blog/building-a-production-ready-image-cropper-in-react-native" rel="noopener noreferrer"&gt;GeekyAnts Blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
