<?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: Nicolas A. R.</title>
    <description>The latest articles on DEV Community by Nicolas A. R. (@nalarconrapela).</description>
    <link>https://dev.to/nalarconrapela</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%2Fuser%2Fprofile_image%2F3745851%2Fbd6294f2-7b31-4b20-9a7e-a48a0fe828af.png</url>
      <title>DEV Community: Nicolas A. R.</title>
      <link>https://dev.to/nalarconrapela</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nalarconrapela"/>
    <language>en</language>
    <item>
      <title>TaskCanvas: Visualizing task.md with Sanity</title>
      <dc:creator>Nicolas A. R.</dc:creator>
      <pubDate>Mon, 05 Oct 2026 06:38:55 +0000</pubDate>
      <link>https://dev.to/nalarconrapela/taskcanvas-visualizing-taskmd-with-sanity-47o5</link>
      <guid>https://dev.to/nalarconrapela/taskcanvas-visualizing-taskmd-with-sanity-47o5</guid>
      <description>&lt;h1&gt;
  
  
  AnTaskCanvas
&lt;/h1&gt;

&lt;p&gt;This is a submission for the &lt;a href="https://dev.to/challenges/sanity-2026-09-16"&gt;Sanity Challenge, Path Two: Vibe-Code Something Strange&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;AnTaskCanvas started with a fairly ordinary problem.&lt;/p&gt;

&lt;p&gt;I tried a lot of task management tools: Linear, Trello, GitHub Projects, Notion, Microsoft To Do, Google Tasks, and quite a few others. They all solve parts of the problem well, but in my case I always ended up with the same friction: planning and the actual repository lived in different places.&lt;/p&gt;

&lt;p&gt;I would create tasks for one project, move on to another, then another one, and after a while that planning would be disconnected from its original context. I had to remember which workspace belonged to which repository, which notes belonged to which idea, and where I had written down that task I quickly captured so I would not forget it.&lt;/p&gt;

&lt;p&gt;The end result was much less sophisticated than all those tools promised: a folder full of paper notes, random reminders, Google Keep, and scattered ideas.&lt;/p&gt;

&lt;p&gt;The idea for AnTaskCanvas had actually been in my head for quite a while.&lt;/p&gt;

&lt;p&gt;Originally, I imagined it as a VS Code extension: something that would let me open a project and see its tasks directly from the same place where I was writing code.&lt;/p&gt;

&lt;p&gt;The problem was that I never really had the time to build all the infrastructure around it.&lt;/p&gt;

&lt;p&gt;And with the rise of vibe coding, the problem became even more obvious to me.&lt;/p&gt;

&lt;p&gt;You can build an application very quickly now, but you can also end up with bugs, half-finished screens, and decisions you made in a hurry and barely remember a week later. The faster you move, the easier it becomes to lose track of what you were doing and what was still pending.&lt;/p&gt;

&lt;p&gt;The idea still made sense, but building it meant solving persistence, data modeling, users, state, and a whole infrastructure layer before getting to the part I actually cared about:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;turning tasks into something visual without falling back to keeping everything locally — and quietly hoping my computer never decides to explode.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Then Sanity entered the picture.&lt;/p&gt;

&lt;p&gt;Suddenly, a large part of that infrastructure no longer had to be the project itself. Sanity gave me a foundation for modeling and persisting the information without first having to build an API, a database, and all the infrastructure around it.&lt;/p&gt;

&lt;p&gt;For me, that was hard to ignore.&lt;/p&gt;

&lt;p&gt;The boring part already had a solid foundation.&lt;/p&gt;

&lt;p&gt;What was left was the visual part.&lt;/p&gt;

&lt;p&gt;And an idea I had been postponing for a long time could finally become something real.&lt;/p&gt;

&lt;p&gt;The idea behind AnTaskCanvas is deliberately simple: each project can carry its own planning in a &lt;code&gt;TASKS.md&lt;/code&gt; file, keep that file versionable and portable, and still turn it into something visual.&lt;/p&gt;

&lt;p&gt;That file can be imported into the application, viewed and organized through a Canvas or Kanban view, and exported back to Markdown.&lt;/p&gt;

&lt;p&gt;The application also tries to sanitize the file, because real &lt;code&gt;TASKS.md&lt;/code&gt; files are rarely pristine. Tasks get written quickly, structures become inconsistent, and small formatting mistakes appear when the only thing that matters at that moment is not forgetting an idea.&lt;/p&gt;

&lt;p&gt;What matters to me is not turning Markdown into another closed database.&lt;/p&gt;

&lt;p&gt;It is keeping the planning directly connected to the project it belongs to.&lt;/p&gt;

&lt;p&gt;Sanity sits just before that planning becomes part of the repository's official history.&lt;/p&gt;

&lt;p&gt;An idea can appear at any time: during a commute, during a sleepless night, or while working on a completely different project. You do not necessarily want to turn it into a commit immediately. Sometimes you just want to keep it, see it in context, and decide later whether it deserves to make it into production.&lt;/p&gt;

&lt;p&gt;That is where Sanity gets a second role.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub preserves what we finally decided to build.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sanity also preserves what we are still thinking about.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AnTaskCanvas uses that persistence to keep working state and project context even before everything has to become part of the Git history.&lt;/p&gt;

&lt;p&gt;That creates a fairly natural separation:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sanity is the living state of the project.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;&lt;code&gt;TASKS.md&lt;/code&gt; is its portable representation.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;GitHub is its versioned history.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AnTaskCanvas sits between those three layers.&lt;/p&gt;

&lt;p&gt;It is not trying to replace Linear, Trello, Notion, or GitHub Projects. It also does not require AI to manage tasks.&lt;/p&gt;

&lt;p&gt;Its goal is much more specific: take something as flat and simple as a &lt;code&gt;TASKS.md&lt;/code&gt; file and turn it into a visual, persistent, understandable workspace without breaking its relationship with the repository.&lt;/p&gt;

&lt;p&gt;Because the problem I am trying to solve is not that we lack task managers.&lt;/p&gt;

&lt;p&gt;It is that too often our ideas about a project live in one place, while the actual project lives somewhere else.&lt;/p&gt;


&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I built &lt;strong&gt;AnTaskCanvas&lt;/strong&gt;, an application that turns a &lt;code&gt;TASKS.md&lt;/code&gt; file into a more visual way of working with the tasks inside a project.&lt;/p&gt;

&lt;p&gt;The idea is simple: &lt;code&gt;TASKS.md&lt;/code&gt; remains the portable source of truth, but instead of working only with a text file, AnTaskCanvas can import it, interpret it, and organize its tasks through &lt;strong&gt;Canvas and Kanban&lt;/strong&gt; views.&lt;/p&gt;

&lt;p&gt;The application also tries to sanitize the file during import.&lt;/p&gt;

&lt;p&gt;In real projects, these documents are often written in a hurry, with inconsistent structures or small formatting errors. Before representing them visually, AnTaskCanvas analyzes and normalizes that information so it can work with it more predictably.&lt;/p&gt;

&lt;p&gt;Once inside the application, tasks can be organized visually and persisted using &lt;strong&gt;Sanity&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Sanity stores the structured representation of the tasks as well as information that does not belong inside the Markdown itself, such as positions, dimensions, and the visual state of groups inside the Canvas.&lt;/p&gt;

&lt;p&gt;When we want to return to the portable format, the planning can be exported back to &lt;code&gt;TASKS.md&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The current main flow is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TASKS.md
   ↓
import
   ↓
analyze / sanitize
   ↓
task model
   ↓
Canvas / Kanban
   ↓
persist with Sanity
   ↓
export TASKS.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Direct GitHub integration — authentication, importing directly from a repository, and automatic synchronization — belongs to the next phase and is not part of the current demo.&lt;/p&gt;

&lt;p&gt;AnTaskCanvas is mainly aimed at individual developers, indie hackers, and small teams working across multiple projects who want to keep planning close to the repository without turning it into yet another workspace that has to be remembered and maintained separately.&lt;/p&gt;


&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Live demo:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://ancanvastask-pro.onrender.com/" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;ancanvastask-pro.onrender.com&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Screenshots:&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;Experience the primary interactive modes of &lt;strong&gt;AnTaskCanvas&lt;/strong&gt;:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Infinite Spatial Canvas (&lt;code&gt;tldraw&lt;/code&gt; v5)
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Visual freeform canvas with custom &lt;code&gt;TaskCard&lt;/code&gt; nodes, section groups, and live Directed Acyclic Graph (DAG) dependency connections (&lt;code&gt;blockedBy&lt;/code&gt;).&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  2. Interactive Kanban Board
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;High-density column workflow (&lt;code&gt;Todo&lt;/code&gt;, &lt;code&gt;In Progress&lt;/code&gt;, &lt;code&gt;Done&lt;/code&gt;, &lt;code&gt;Blocked&lt;/code&gt;) with instant drag-and-drop state updates and inline editing.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  3. Live Split Markdown Editor
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Side-by-side CodeMirror Markdown editor with bi-directional AST synchronization—type in Markdown or edit visually with zero data loss.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  4. Monorepo Document Explorer &amp;amp; Context-Aware Filters
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Manage multi-scope task files (&lt;code&gt;frontend/TASKS.md&lt;/code&gt;, &lt;code&gt;backend/TASKS.md&lt;/code&gt;) with filter dropdowns that reactively reconcile with active document tags.&lt;/p&gt;
&lt;/blockquote&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%2F2bdxhj0vacxcaoer5xgl.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%2F2bdxhj0vacxcaoer5xgl.png" alt=" " width="800" height="380"&gt;&lt;/a&gt;&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%2Fmecloecwxnqssvemmubi.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%2Fmecloecwxnqssvemmubi.png" alt=" " width="800" height="380"&gt;&lt;/a&gt;&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%2Fppquqwynqg7wx8qiyges.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%2Fppquqwynqg7wx8qiyges.png" alt=" " width="800" height="380"&gt;&lt;/a&gt;&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%2F2zn5y0ihhcymt13nwpu1.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%2F2zn5y0ihhcymt13nwpu1.png" alt=" " width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The main demo flow shows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;real TASKS.md
   ↓
import
   ↓
normalization
   ↓
Canvas
   ↓
Kanban
   ↓
editing
   ↓
persistence
   ↓
reload project
   ↓
restore visual context
   ↓
export TASKS.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal of the demo is to show the real workflow, not just a collection of polished screens with controlled sample data.&lt;/p&gt;




&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;The source code for AnTaskCanvas is available on GitHub:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repository:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/anappwilos/AnCanvasTask_END" rel="noopener noreferrer"&gt;https://github.com/anappwilos/AnCanvasTask_END&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Branch:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;main&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The application is built with &lt;strong&gt;React, Vite, and TypeScript&lt;/strong&gt;, using &lt;strong&gt;Tailwind CSS v4&lt;/strong&gt; for the interface and &lt;strong&gt;tldraw&lt;/strong&gt; as the Canvas engine.&lt;/p&gt;

&lt;p&gt;To work with &lt;code&gt;TASKS.md&lt;/code&gt;, AnTaskCanvas uses a normalizer built on &lt;code&gt;unified&lt;/code&gt;, &lt;code&gt;remark-parse&lt;/code&gt;, and &lt;code&gt;remark-stringify&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Its job is not simply to read Markdown.&lt;/p&gt;

&lt;p&gt;It first interprets and normalizes the document into a structure that can be used by Canvas or Kanban, while still allowing the original Markdown workflow to remain intact.&lt;/p&gt;

&lt;p&gt;At a high level, the flow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TASKS.md
    ↓
markdownNormalizer.ts
    ↓
task model
    ↓
Canvas / Kanban
    ↓
sanityService.ts
    ↓
Sanity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Sanity integration is kept separate from the logic responsible for interpreting Markdown.&lt;/p&gt;

&lt;p&gt;That way, the file, its visual representation, and its persistent state do not depend directly on one another.&lt;/p&gt;

&lt;h3&gt;
  
  
  Main stack
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;React&lt;/li&gt;
&lt;li&gt;Vite&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;Tailwind CSS v4&lt;/li&gt;
&lt;li&gt;tldraw&lt;/li&gt;
&lt;li&gt;unified / remark&lt;/li&gt;
&lt;li&gt;Sanity&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@sanity/client&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Main pieces
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/utils/markdownNormalizer.ts
→ TASKS.md parsing and normalization

src/services/sanityService.ts
→ Sanity integration

src/services/workspaceService.ts
→ workspace and persistence operations

src/sanity/schemas/
→ Sanity content model
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The main architectural decision was to keep three responsibilities separate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TASKS.md
→ portable content

AnTaskCanvas
→ editing and visual representation

Sanity
→ persistent structure and visual memory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows AnTaskCanvas to store information that only makes sense to the application — such as the position and dimensions of a card inside the Canvas — without polluting &lt;code&gt;TASKS.md&lt;/code&gt; with metadata that would be meaningless when opening the file directly in an editor.&lt;/p&gt;




&lt;h2&gt;
  
  
  My Build Process
&lt;/h2&gt;

&lt;p&gt;AnTaskCanvas did not start with all of this architecture already figured out.&lt;/p&gt;

&lt;p&gt;The first idea was much smaller: open a &lt;code&gt;TASKS.md&lt;/code&gt; file and stop looking at it as a flat list of text.&lt;/p&gt;

&lt;p&gt;A large part of the project started through vibe coding.&lt;/p&gt;

&lt;p&gt;At first I mainly worked with &lt;strong&gt;Google AI Studio / Gemini and Antigravity&lt;/strong&gt; to get the early versions up quickly. As the application grew, I also started using agents such as Codex for more focused reviews, debugging, audits, and changes where I wanted to avoid overly aggressive edits.&lt;/p&gt;

&lt;p&gt;That shift ended up teaching me a lot about how I wanted to use AI during the project.&lt;/p&gt;

&lt;h3&gt;
  
  
  01 — Make it visual first
&lt;/h3&gt;

&lt;p&gt;I started with React, TypeScript, and &lt;code&gt;tldraw&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The first version had little more than a top bar, an infinite canvas, and a few fake task cards.&lt;/p&gt;

&lt;p&gt;Before thinking about persistence, synchronization, or GitHub, I wanted to answer one question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does it actually make sense to look at a &lt;code&gt;TASKS.md&lt;/code&gt; this way?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Then I added a second view in Kanban format.&lt;/p&gt;

&lt;p&gt;That is where the core of AnTaskCanvas started to appear:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;the same set of tasks could be seen as Markdown, as a Canvas, or as a board.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  02 — Turning &lt;code&gt;TASKS.md&lt;/code&gt; into more than plain text
&lt;/h3&gt;

&lt;p&gt;The next step was reading a real file.&lt;/p&gt;

&lt;p&gt;I started with the most basic Markdown tasks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; [ ] Pending task
&lt;span class="p"&gt;-&lt;/span&gt; [x] Completed task
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then came headings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Backend&lt;/span&gt;
&lt;span class="gu"&gt;## Frontend&lt;/span&gt;
&lt;span class="gu"&gt;## Bugs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which became visual groups.&lt;/p&gt;

&lt;p&gt;From there I started adding metadata:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ID
Priority
Blocked by
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Priorities from &lt;code&gt;P0&lt;/code&gt; to &lt;code&gt;P3&lt;/code&gt; could be represented visually, and &lt;code&gt;Blocked by&lt;/code&gt; made it possible to draw dependencies between tasks as connections inside the Canvas.&lt;/p&gt;

&lt;p&gt;At that point it stopped being just a Markdown viewer.&lt;/p&gt;

&lt;p&gt;The document was starting to behave like a structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  03 — Editing without breaking the source of truth
&lt;/h3&gt;

&lt;p&gt;This introduced one of the more important problems.&lt;/p&gt;

&lt;p&gt;I did not want the Canvas to become another database completely disconnected from the original file.&lt;/p&gt;

&lt;p&gt;If I changed a task visually, that change had to be able to return to Markdown.&lt;/p&gt;

&lt;p&gt;So I added editing operations such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;changing a title;&lt;/li&gt;
&lt;li&gt;completing a task;&lt;/li&gt;
&lt;li&gt;changing priority;&lt;/li&gt;
&lt;li&gt;creating tasks;&lt;/li&gt;
&lt;li&gt;deleting tasks;&lt;/li&gt;
&lt;li&gt;moving tasks between groups.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those changes needed to make their way back into the document.&lt;/p&gt;

&lt;p&gt;The rule was simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;TASKS.md&lt;/code&gt; had to remain portable and understandable outside AnTaskCanvas.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  04 — Sanity started much smaller
&lt;/h3&gt;

&lt;p&gt;The first Sanity integration was fairly limited.&lt;/p&gt;

&lt;p&gt;The initial idea was to use it only for information that did not really belong inside &lt;code&gt;TASKS.md&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;card positions;&lt;/li&gt;
&lt;li&gt;dimensions;&lt;/li&gt;
&lt;li&gt;visual groups;&lt;/li&gt;
&lt;li&gt;Canvas state;&lt;/li&gt;
&lt;li&gt;representation-specific configuration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The content itself would still belong to Markdown.&lt;/p&gt;

&lt;p&gt;But once persistence was working, Sanity started to occupy a fairly natural place inside the project.&lt;/p&gt;

&lt;p&gt;There was information I did not yet want to turn into repository history, but I also did not want to lose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;working state;&lt;/li&gt;
&lt;li&gt;visual context;&lt;/li&gt;
&lt;li&gt;positions;&lt;/li&gt;
&lt;li&gt;grouping;&lt;/li&gt;
&lt;li&gt;structured information around tasks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The architecture started to split in a way I had not originally planned:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sanity as living state.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;&lt;code&gt;TASKS.md&lt;/code&gt; as the portable representation.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Git as versioned history.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sanity eventually grew into a deeper integration, with structured persistence, visual state, and an embedded Studio inside the application.&lt;/p&gt;
&lt;h3&gt;
  
  
  05 — Auto organize
&lt;/h3&gt;

&lt;p&gt;Once groups, priorities, and dependencies existed, manually placing every task stopped being fun.&lt;/p&gt;

&lt;p&gt;With five cards, it is manageable.&lt;/p&gt;

&lt;p&gt;With fifty, not so much.&lt;/p&gt;

&lt;p&gt;That is how &lt;code&gt;Auto organize&lt;/code&gt; appeared.&lt;/p&gt;

&lt;p&gt;The idea was to use a layout engine to automatically distribute Canvas elements and create a reasonable starting arrangement.&lt;/p&gt;

&lt;p&gt;After that, the user could still move things manually.&lt;/p&gt;

&lt;p&gt;This also revealed something that happened repeatedly throughout the project: a feature can be technically correct and still be annoying in real use.&lt;/p&gt;

&lt;p&gt;We later had to adjust behaviors such as automatic centering and Canvas movement to avoid camera jumps and interactions that interrupted the workflow.&lt;/p&gt;
&lt;h3&gt;
  
  
  06 — Real Markdown is much messier than demo Markdown
&lt;/h3&gt;

&lt;p&gt;Up to this point, the examples worked beautifully.&lt;/p&gt;

&lt;p&gt;Then real files arrived.&lt;/p&gt;

&lt;p&gt;Duplicate IDs.&lt;/p&gt;

&lt;p&gt;Broken dependencies.&lt;/p&gt;

&lt;p&gt;Invalid priorities.&lt;/p&gt;

&lt;p&gt;Inconsistent indentation.&lt;/p&gt;

&lt;p&gt;Unknown metadata.&lt;/p&gt;

&lt;p&gt;Checkboxes written in slightly different ways.&lt;/p&gt;

&lt;p&gt;And tasks written quickly because the only important thing at that moment was not forgetting them.&lt;/p&gt;

&lt;p&gt;That ended up creating a part of the project that was not in the original plan at all: the &lt;strong&gt;safe Markdown normalizer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of silently modifying the document, AnTaskCanvas can analyze the file and generate a normalization proposal.&lt;/p&gt;

&lt;p&gt;Before accepting the changes, the user can review a diff and decide what to apply.&lt;/p&gt;

&lt;p&gt;The original stays untouched until the operation is confirmed.&lt;/p&gt;

&lt;p&gt;It is probably one of the features that best represents how AnTaskCanvas evolved:&lt;/p&gt;

&lt;p&gt;it exists because real usage broke assumptions that worked perfectly in the prototype.&lt;/p&gt;
&lt;h3&gt;
  
  
  07 — Real files
&lt;/h3&gt;

&lt;p&gt;Then came the less exciting but necessary part:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;opening &lt;code&gt;.md&lt;/code&gt; files;&lt;/li&gt;
&lt;li&gt;drag and drop;&lt;/li&gt;
&lt;li&gt;importing;&lt;/li&gt;
&lt;li&gt;exporting;&lt;/li&gt;
&lt;li&gt;saving;&lt;/li&gt;
&lt;li&gt;detecting changes;&lt;/li&gt;
&lt;li&gt;handling different documents.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The application started to move away from being a demo built around controlled data and toward something capable of working with real documents.&lt;/p&gt;

&lt;p&gt;Over time this also evolved into the idea of workspaces and multiple-document handling.&lt;/p&gt;
&lt;h3&gt;
  
  
  08 — AI-generated design became a problem
&lt;/h3&gt;

&lt;p&gt;This is where the process changed quite a bit.&lt;/p&gt;

&lt;p&gt;For a large part of the development I worked with Google AI Studio and Antigravity.&lt;/p&gt;

&lt;p&gt;The models were very good at adding things.&lt;/p&gt;

&lt;p&gt;That was exactly the problem.&lt;/p&gt;

&lt;p&gt;Every request like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;improve the interface&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;could turn into another card, another button, another gradient, another shadow, another badge, or another section.&lt;/p&gt;

&lt;p&gt;In some iterations I ended up with more decoration than actual improvement.&lt;/p&gt;

&lt;p&gt;The application started to develop that very recognizable AI-generated interface look:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;too many cards;&lt;/li&gt;
&lt;li&gt;too much empty space;&lt;/li&gt;
&lt;li&gt;gradients;&lt;/li&gt;
&lt;li&gt;glassmorphism;&lt;/li&gt;
&lt;li&gt;shadows;&lt;/li&gt;
&lt;li&gt;huge buttons;&lt;/li&gt;
&lt;li&gt;excessive rounding;&lt;/li&gt;
&lt;li&gt;repeated information;&lt;/li&gt;
&lt;li&gt;landing-page aesthetics applied to a work tool.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The more I asked:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Make it more modern.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;the worse it got.&lt;/p&gt;

&lt;p&gt;The model interpreted “improve” as “add.”&lt;/p&gt;

&lt;p&gt;So I started doing the opposite:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;remove.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Gradients, glassmorphism, shadows, and unnecessary decoration were stripped away.&lt;/p&gt;

&lt;p&gt;Border radii were reduced, information density increased, and functional hierarchy became more important than ornament.&lt;/p&gt;

&lt;p&gt;That process also changed my prompts.&lt;/p&gt;

&lt;p&gt;I went from asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;make it more modern&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;to defining concrete rules around density, typography, spacing, hierarchy, responsive behavior, accessibility, and especially when &lt;strong&gt;not to create anything new&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I also started adding documentation and rules for agents.&lt;/p&gt;

&lt;p&gt;It was no longer enough to say what I wanted.&lt;/p&gt;

&lt;p&gt;I had to explain what I did &lt;strong&gt;not&lt;/strong&gt; want.&lt;/p&gt;
&lt;h3&gt;
  
  
  09 — Internationalization: when the prompt had to mature too
&lt;/h3&gt;

&lt;p&gt;One of the later major phases was i18n.&lt;/p&gt;

&lt;p&gt;I wanted developers to keep writing readable source text while message extraction happened automatically, without manually maintaining keys like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tasks.actions.delete&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal was a compiler-first architecture.&lt;/p&gt;

&lt;p&gt;By this point the prompt itself looked very different from the prompts I used at the beginning.&lt;/p&gt;

&lt;p&gt;Instead of simply saying “add translations,” I started by defining the architecture I wanted and the things the agent should not do.&lt;/p&gt;

&lt;p&gt;One of the real prompts was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Implement a modern, automatic, compiler-first internationalization architecture across the entire project.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Developers should work with readable source text.&lt;/p&gt;

&lt;p&gt;I do not want manual semantic keys such as &lt;code&gt;t("tasks.delete")&lt;/code&gt; or manually maintained translation dictionaries.&lt;/p&gt;

&lt;p&gt;Before modifying code, detect the framework, bundler, TypeScript setup, existing i18n system, and component structure.&lt;/p&gt;

&lt;p&gt;Do not replace a valid existing solution unless necessary.&lt;/p&gt;

&lt;p&gt;Prioritize a small, typed solution with no external translation APIs at runtime.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The full prompt eventually covered automatic extraction, ID generation, pluralization, accessibility, regional formatting, CI, and even which strings should not be translated.&lt;/p&gt;

&lt;p&gt;The implementation ended up using Lingui.&lt;/p&gt;

&lt;p&gt;And, as often happens, the plan was simpler than the implementation.&lt;/p&gt;

&lt;p&gt;At one point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lingui extract
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;returned:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 messages
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;even though the application was full of text.&lt;/p&gt;

&lt;p&gt;I had to review configuration, macros, and versions.&lt;/p&gt;

&lt;p&gt;After fixing the issue, extraction found:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;193 messages
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the project compiled correctly again.&lt;/p&gt;

&lt;p&gt;That episode captures fairly well how my use of AI changed:&lt;/p&gt;

&lt;p&gt;less&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“build this for me”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and more&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“work inside these constraints and inspect what already exists first.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  10 — Bugs that do not appear in the nice screenshot
&lt;/h3&gt;

&lt;p&gt;There were also plenty of less photogenic moments.&lt;/p&gt;

&lt;p&gt;One deployed version ended up as a completely blank white screen.&lt;/p&gt;

&lt;p&gt;I had to review dependencies, package management, Vite configuration, and runtime errors.&lt;/p&gt;

&lt;p&gt;I eventually added a &lt;code&gt;RootErrorBoundary&lt;/code&gt; so that a startup failure would no longer leave the user with nothing but a blank page.&lt;/p&gt;

&lt;p&gt;There were also problems inside &lt;code&gt;tldraw&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, an early attempt to prevent certain shapes from being created intercepted the process too early and broke the internal store.&lt;/p&gt;

&lt;p&gt;The solution was not to add another abstraction.&lt;/p&gt;

&lt;p&gt;It was to let &lt;code&gt;tldraw&lt;/code&gt; complete its operation correctly and intervene afterward.&lt;/p&gt;

&lt;p&gt;These are not the most attractive parts of the project.&lt;/p&gt;

&lt;p&gt;But they probably explain the build process better than the polished screenshots do.&lt;/p&gt;

&lt;h3&gt;
  
  
  11 — What changed in the way I use AI
&lt;/h3&gt;

&lt;p&gt;I started by using AI mostly to generate.&lt;/p&gt;

&lt;p&gt;I ended up using it much more to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;inspect;&lt;/li&gt;
&lt;li&gt;compare;&lt;/li&gt;
&lt;li&gt;look for regressions;&lt;/li&gt;
&lt;li&gt;apply small changes;&lt;/li&gt;
&lt;li&gt;validate;&lt;/li&gt;
&lt;li&gt;work within constraints.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One pattern I ended up reusing was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Before modifying anything, inspect the project and understand how it currently works.&lt;/p&gt;

&lt;p&gt;Do not rebuild the architecture.&lt;/p&gt;

&lt;p&gt;Do not add unnecessary dependencies.&lt;/p&gt;

&lt;p&gt;Do not modify components unrelated to the problem.&lt;/p&gt;

&lt;p&gt;Identify the root cause first.&lt;/p&gt;

&lt;p&gt;Then apply the smallest necessary change.&lt;/p&gt;

&lt;p&gt;Verify the result with build, TypeScript, lint, and tests if available.&lt;/p&gt;

&lt;p&gt;If something cannot be verified, say so explicitly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;inspect → understand → fix → verify&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Do not add code “just in case.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It may sound obvious.&lt;/p&gt;

&lt;p&gt;In practice, it produced better results than many huge prompts.&lt;/p&gt;

&lt;p&gt;The prompts changed too.&lt;/p&gt;

&lt;p&gt;At the beginning they mostly described what I wanted to appear.&lt;/p&gt;

&lt;p&gt;By the end they mostly described the boundaries within which the agent was allowed to work.&lt;/p&gt;

&lt;p&gt;I think that was one of the most interesting lessons from the project.&lt;/p&gt;

&lt;p&gt;With vibe coding, generating code is often not the hardest part.&lt;/p&gt;

&lt;p&gt;The hard part is making sure every new generation does not destroy the intention of the previous one.&lt;/p&gt;




&lt;h2&gt;
  
  
  Sanity Project Details
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Project ID:&lt;/strong&gt; &lt;code&gt;or19faat&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Dataset:&lt;/strong&gt; &lt;code&gt;production&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;API Version:&lt;/strong&gt; &lt;code&gt;2024-03-01&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Public Dataset URL:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://or19faat.api.sanity.io/v2024-03-01/data/query/production?query=%2A%5B0...20%5D%7B_id%2C_type%7D" rel="noopener noreferrer"&gt;https://or19faat.api.sanity.io/v2024-03-01/data/query/production?query=%2A%5B0...20%5D%7B_id%2C_type%7D&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sanity is the layer that allows AnTaskCanvas to go beyond simply turning a Markdown file into a visual interface.&lt;/p&gt;

&lt;p&gt;The starting point is still &lt;code&gt;TASKS.md&lt;/code&gt;: a flat, portable format that is easy to keep next to the project.&lt;/p&gt;

&lt;p&gt;But Markdown has a fairly obvious limitation once you try to turn it into something visual.&lt;/p&gt;

&lt;p&gt;It can describe a task, its status, or its subtasks, but it does not know that a card was placed at a particular position on the Canvas, inside a certain group, or with specific dimensions.&lt;/p&gt;

&lt;p&gt;That is where Sanity comes in.&lt;/p&gt;
&lt;h3&gt;
  
  
  The model
&lt;/h3&gt;

&lt;p&gt;AnTaskCanvas currently uses three main document types.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;code&gt;workspace&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Represents the general context of a project.&lt;/p&gt;

&lt;p&gt;It stores workspace information and relates the tasks that belong to it.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;code&gt;task&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Represents the structured version of a task found in &lt;code&gt;TASKS.md&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It can store information such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;title;&lt;/li&gt;
&lt;li&gt;description;&lt;/li&gt;
&lt;li&gt;status;&lt;/li&gt;
&lt;li&gt;priority;&lt;/li&gt;
&lt;li&gt;tags;&lt;/li&gt;
&lt;li&gt;subtasks;&lt;/li&gt;
&lt;li&gt;group or section;&lt;/li&gt;
&lt;li&gt;dependencies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means that a line of Markdown stops being only text and becomes structured content that the application can query and represent in different ways.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;code&gt;canvasVisualState&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;This is probably the most important piece for the AnTaskCanvas idea.&lt;/p&gt;

&lt;p&gt;The content of a task and the way we choose to organize it visually are two different things.&lt;/p&gt;

&lt;p&gt;That is why Canvas state is stored separately.&lt;/p&gt;

&lt;p&gt;For each task, it can keep information such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;taskId
x
y
width
height
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and for each group:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;groupTitle
x
y
width
height
isCollapsed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes it possible to move a card, resize it, or reorganize a group without artificially modifying the content of &lt;code&gt;TASKS.md&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In other words:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Markdown stores what a task is.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sanity can store how we had organized it visually.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why separate &lt;code&gt;task&lt;/code&gt; and &lt;code&gt;canvasVisualState&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;I could have stored everything inside the task document itself.&lt;/p&gt;

&lt;p&gt;I did not, because that would have mixed two different concepts.&lt;/p&gt;

&lt;p&gt;A task can move many times without its content changing.&lt;/p&gt;

&lt;p&gt;Likewise, I can edit the title, priority, or a subtask without wanting to modify its position inside the Canvas.&lt;/p&gt;

&lt;p&gt;Keeping them separate allows each part to evolve for a different reason:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;task
→ changes when the content changes

canvasVisualState
→ changes when the representation changes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It also keeps view-specific information out of the task model.&lt;/p&gt;

&lt;p&gt;Kanban, for example, needs to know the state of a task.&lt;/p&gt;

&lt;p&gt;It does not need to know its X/Y coordinates inside the Canvas.&lt;/p&gt;

&lt;h3&gt;
  
  
  From flat file to Canvas
&lt;/h3&gt;

&lt;p&gt;The current flow can be summarized like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TASKS.md
   ↓
parser + normalizer
   ↓
structured task model
   ↓
Canvas / Kanban
   ↓
Sanity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Semantic changes made from Canvas or Kanban can be reflected back into the Markdown content, while Sanity stores the structured representation and the spatial state of the project.&lt;/p&gt;

&lt;p&gt;That keeps the separation fairly clear:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TASKS.md
→ portable and interoperable content

AnTaskCanvas
→ editing and visual representation

Sanity
→ structured persistence and visual state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Persistence between sessions
&lt;/h3&gt;

&lt;p&gt;AnTaskCanvas combines Sanity with a small local cache layer.&lt;/p&gt;

&lt;p&gt;When restoring the visual state of a project, the application tries to retrieve it from Sanity using its &lt;code&gt;projectId&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It can also keep a local copy of the visual state as a fallback if Sanity is unavailable or the connection takes too long.&lt;/p&gt;

&lt;p&gt;That means that when reopening a project, we can recover more than just its tasks.&lt;/p&gt;

&lt;p&gt;We can also recover how the workspace had been organized.&lt;/p&gt;

&lt;p&gt;That was an important part of the original problem: coming back to a project months later and finding more than a list of pending tasks.&lt;/p&gt;

&lt;p&gt;I wanted to recover some of the visual context I had been working with as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is persisted and what is not
&lt;/h3&gt;

&lt;p&gt;Not everything needs to live in Sanity.&lt;/p&gt;

&lt;p&gt;Sanity stores:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;workspaces;&lt;/li&gt;
&lt;li&gt;structured tasks;&lt;/li&gt;
&lt;li&gt;relationships between workspace and tasks;&lt;/li&gt;
&lt;li&gt;visual state of cards;&lt;/li&gt;
&lt;li&gt;group position and dimensions;&lt;/li&gt;
&lt;li&gt;expanded or collapsed state of groups.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the other hand, temporary interface state such as the current selection, zoom level, camera position, active filters, temporary searches, or open modals does not need to become persistent data.&lt;/p&gt;

&lt;p&gt;Those are momentary working states, not part of the project itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Recovering context, not just data
&lt;/h3&gt;

&lt;p&gt;This distinction became more important than I expected.&lt;/p&gt;

&lt;p&gt;When I return to an old project, I do not only want to know that ten tasks are still pending.&lt;/p&gt;

&lt;p&gt;It also helps to remember how I had grouped them.&lt;/p&gt;

&lt;p&gt;Which tasks were close together.&lt;/p&gt;

&lt;p&gt;Which group I had left open.&lt;/p&gt;

&lt;p&gt;Which part of the project I had mentally separated from the rest.&lt;/p&gt;

&lt;p&gt;That kind of information is difficult to express inside Markdown without polluting the file with purely visual metadata.&lt;/p&gt;

&lt;p&gt;Sanity lets AnTaskCanvas preserve that context without turning &lt;code&gt;TASKS.md&lt;/code&gt; into a proprietary format.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sanity Studio inside AnTaskCanvas
&lt;/h3&gt;

&lt;p&gt;The project also integrates Sanity Studio inside the application itself.&lt;/p&gt;

&lt;p&gt;This makes it possible to inspect and manage structured documents without completely leaving the AnTaskCanvas interface.&lt;/p&gt;

&lt;p&gt;During development, this was particularly useful because I could inspect what the application was actually generating instead of relying only on what I could see on the Canvas.&lt;/p&gt;

&lt;h3&gt;
  
  
  No realtime yet
&lt;/h3&gt;

&lt;p&gt;One of the things I simplified during the latest refactor was real-time synchronization.&lt;/p&gt;

&lt;p&gt;The current version does not maintain a permanent subscription through &lt;code&gt;client.listen()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Persistence happens explicitly when the user modifies or saves state.&lt;/p&gt;

&lt;p&gt;That was a deliberate decision for this version.&lt;/p&gt;

&lt;p&gt;AnTaskCanvas is currently aimed mainly at individual developers, so there was no need yet to introduce the complexity of multi-user collaboration, conflicts, or simultaneous change resolution.&lt;/p&gt;

&lt;p&gt;That can come later if the product actually needs collaborative editing.&lt;/p&gt;

&lt;h3&gt;
  
  
  The relationship with &lt;code&gt;TASKS.md&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;An important decision was not to use Sanity as a replacement for Markdown.&lt;/p&gt;

&lt;p&gt;If AnTaskCanvas disappeared tomorrow, the file should still be useful.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;TASKS.md&lt;/code&gt; does not need AnTaskCanvas in order to exist.&lt;/p&gt;

&lt;p&gt;The user can export it and continue working with it from an editor, a repository, or any other Markdown-compatible tool.&lt;/p&gt;

&lt;p&gt;Sanity adds persistence and structure.&lt;/p&gt;

&lt;p&gt;But it does not try to trap the project's content inside the application.&lt;/p&gt;

&lt;h3&gt;
  
  
  A deliberate decision
&lt;/h3&gt;

&lt;p&gt;I also deliberately avoided storing the entire &lt;code&gt;TASKS.md&lt;/code&gt; file as one big text block inside Sanity.&lt;/p&gt;

&lt;p&gt;That would have been easier.&lt;/p&gt;

&lt;p&gt;But it would also have removed much of the benefit of structured content.&lt;/p&gt;

&lt;p&gt;AnTaskCanvas separates:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;content&lt;/strong&gt;,&lt;br&gt;&lt;br&gt;
&lt;strong&gt;structure&lt;/strong&gt;,&lt;br&gt;&lt;br&gt;
&lt;strong&gt;visual representation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Markdown remains portable and readable outside the application.&lt;/p&gt;

&lt;p&gt;Sanity stores the parts that actually benefit from being structured and persistent.&lt;/p&gt;

&lt;p&gt;And the Canvas uses both to turn something fundamentally flat into a visual workspace.&lt;/p&gt;
&lt;h3&gt;
  
  
  The same content, multiple representations
&lt;/h3&gt;

&lt;p&gt;The same task can appear in different views without being duplicated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;task
   ├── Canvas
   ├── Kanban
   └── TASKS.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All three representations refer to the same task.&lt;/p&gt;

&lt;p&gt;But each one needs different information.&lt;/p&gt;

&lt;p&gt;Markdown needs content.&lt;/p&gt;

&lt;p&gt;Kanban mainly needs status and grouping.&lt;/p&gt;

&lt;p&gt;Canvas also needs position and dimensions.&lt;/p&gt;

&lt;p&gt;The Sanity schema keeps those differences separate instead of forcing one structure to solve every use case at once.&lt;/p&gt;

&lt;h3&gt;
  
  
  In one sentence
&lt;/h3&gt;

&lt;p&gt;If I had to summarize Sanity's role in AnTaskCanvas:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;TASKS.md&lt;/code&gt; remembers the tasks. Sanity remembers the structured and visual context around them.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is what allows AnTaskCanvas to be more than a Markdown viewer.&lt;/p&gt;

&lt;p&gt;It becomes a workspace you can return to and continue from where you left off.&lt;/p&gt;




&lt;h2&gt;
  
  
  Agent Session
&lt;/h2&gt;

&lt;p&gt;I do not have a public Agent Session associated with the project.&lt;/p&gt;

&lt;p&gt;A large part of AnTaskCanvas was developed using &lt;strong&gt;Google AI Studio / Gemini and Antigravity&lt;/strong&gt;, and later I used other agents for more focused review, debugging, and auditing tasks.&lt;/p&gt;

&lt;p&gt;Instead of linking to a session that does not exist, I want to include one of the real prompts that best represents how my way of working with agents changed during the project.&lt;/p&gt;

&lt;p&gt;At the beginning, my instructions were much more open-ended.&lt;/p&gt;

&lt;p&gt;As AnTaskCanvas grew, I found that I got better results by defining the constraints first, the expected architecture, and especially what the agent &lt;strong&gt;should not do&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This was one of the prompts used while implementing the internationalization system:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Implement a modern, automatic, compiler-first internationalization architecture across the entire project.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Developers should work with readable source text.&lt;/p&gt;

&lt;p&gt;I do not want manual semantic keys such as:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;t("tasks.actions.delete")&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;or manually maintained translation dictionaries.&lt;/p&gt;

&lt;p&gt;Before modifying code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;detect the framework;&lt;/li&gt;
&lt;li&gt;detect the bundler;&lt;/li&gt;
&lt;li&gt;detect TypeScript;&lt;/li&gt;
&lt;li&gt;detect the existing i18n system;&lt;/li&gt;
&lt;li&gt;detect the component structure;&lt;/li&gt;
&lt;li&gt;detect the build system.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not replace a valid existing solution unnecessarily.&lt;/p&gt;

&lt;p&gt;The final solution must be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;compiler-first;&lt;/li&gt;
&lt;li&gt;typed;&lt;/li&gt;
&lt;li&gt;automatically extracted;&lt;/li&gt;
&lt;li&gt;without external translation APIs at runtime;&lt;/li&gt;
&lt;li&gt;without manually created semantic keys;&lt;/li&gt;
&lt;li&gt;with as little architectural noise as possible.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;The full prompt was considerably longer.&lt;/p&gt;

&lt;p&gt;It eventually covered pluralization, interpolation, regional formats, accessibility, message extraction, CI, automatic ID generation, and which types of strings should not be translated.&lt;/p&gt;

&lt;p&gt;The result did not work correctly on the first attempt either.&lt;/p&gt;

&lt;p&gt;During implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lingui extract
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;at one point found:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 messages
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The configuration and macro imports had to be reviewed before the issue was found.&lt;/p&gt;

&lt;p&gt;After fixing it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;193 messages
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;were detected and the project compiled correctly again.&lt;/p&gt;

&lt;p&gt;This part of the development summarizes my experience with vibe coding in AnTaskCanvas fairly well:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;the prompt stopped being just a description of what I wanted to build and started becoming a set of boundaries within which the agent was allowed to work.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>sanitychallenge</category>
      <category>devchallenge</category>
      <category>sanity</category>
      <category>ai</category>
    </item>
    <item>
      <title>AnMemoryNest: A Place to Preserve the Stories Behind Our Photographs</title>
      <dc:creator>Nicolas A. R.</dc:creator>
      <pubDate>Mon, 13 Jul 2026 06:15:15 +0000</pubDate>
      <link>https://dev.to/nalarconrapela/anmemorynest-a-place-to-preserve-the-stories-behind-our-photographs-2oed</link>
      <guid>https://dev.to/nalarconrapela/anmemorynest-a-place-to-preserve-the-stories-behind-our-photographs-2oed</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/weekend-2026-07-09"&gt;Weekend Challenge: Passion Edition&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;This time, I decided to create an application that, although it is not directly connected to my main professional field, is deeply related to something I truly care about: &lt;strong&gt;memories&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A photograph has the ability to freeze time. It can preserve a journey, a friendship, a family celebration, or an ordinary moment that becomes incredibly valuable years later.&lt;/p&gt;

&lt;p&gt;However, today we take hundreds or even thousands of photographs that are often forgotten. They get lost among countless files, remain hidden inside a backup, or gather digital dust on an old hard drive.&lt;/p&gt;

&lt;p&gt;Many images also stay on our phones and are never shared with the friends or family members who experienced those moments with us.&lt;/p&gt;

&lt;p&gt;That is why I decided to create &lt;strong&gt;MemoryNest&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;MemoryNest is an application designed to bring together, organize, and preserve photographs, memories, and stories among families and groups of friends.&lt;/p&gt;

&lt;p&gt;I did not want to create just another photo gallery or another cloud storage service.&lt;/p&gt;

&lt;p&gt;I wanted to create a space where photographs could recover their context, their stories, and their connection to the people who appear in them.&lt;/p&gt;

&lt;p&gt;A place where memories are not only stored, but also shared, completed, and preserved over time.&lt;/p&gt;

&lt;h3&gt;
  
  
  What MemoryNest Offers
&lt;/h3&gt;

&lt;p&gt;MemoryNest allows users to create collaborative albums where family members and friends can contribute their own photographs, add stories, and rebuild memories together.&lt;/p&gt;

&lt;p&gt;The application can be used to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Collect photographs from a trip with friends.&lt;/li&gt;
&lt;li&gt;Create collaborative family albums.&lt;/li&gt;
&lt;li&gt;Preserve stories from parents and grandparents.&lt;/li&gt;
&lt;li&gt;Organize weddings, celebrations, and family gatherings.&lt;/li&gt;
&lt;li&gt;Build travel journals and document important life stages.&lt;/li&gt;
&lt;li&gt;Add context, dates, locations, and people.&lt;/li&gt;
&lt;li&gt;Keep memories inside a private space.&lt;/li&gt;
&lt;li&gt;Preserve a digital legacy for the future.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, after an Interrail trip, each person may have different photographs stored on their phone.&lt;/p&gt;

&lt;p&gt;One person may have the landscapes, another the meals, another the train journeys, and someone else those spontaneous moments that nobody else managed to capture.&lt;/p&gt;

&lt;p&gt;Normally, all those images remain scattered across several devices, messaging conversations, and cloud services.&lt;/p&gt;

&lt;p&gt;With MemoryNest, all those different perspectives can be brought together in one place and transformed into a shared story.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Role of Artificial Intelligence
&lt;/h2&gt;

&lt;p&gt;Artificial intelligence is part of MemoryNest as a support tool for organizing and recovering memories.&lt;/p&gt;

&lt;p&gt;When someone has hundreds or thousands of photographs, reviewing every image, sorting it, and adding information can become an endless task.&lt;/p&gt;

&lt;p&gt;AI helps reduce that workload.&lt;/p&gt;

&lt;p&gt;It can suggest:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Album titles.&lt;/li&gt;
&lt;li&gt;Photograph descriptions.&lt;/li&gt;
&lt;li&gt;Tags and categories.&lt;/li&gt;
&lt;li&gt;Groups of related images.&lt;/li&gt;
&lt;li&gt;Possible dates or locations.&lt;/li&gt;
&lt;li&gt;Duplicate or highly similar photographs.&lt;/li&gt;
&lt;li&gt;Memories that are still incomplete.&lt;/li&gt;
&lt;li&gt;An initial structure for the story of a trip or event.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;MemoryNest also includes a memory assistant that can help users explore their albums, find specific memories, and draft stories based on the information already preserved.&lt;/p&gt;

&lt;p&gt;For example, a user could ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What memories do we have from our trip to Italy?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Or:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Help me write a short story about this family album.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Artificial intelligence is not intended to replace people or invent memories.&lt;/p&gt;

&lt;p&gt;It can help recognize that several photographs belong to the same trip, but only the people who lived that moment can explain why it mattered.&lt;/p&gt;

&lt;p&gt;That is why AI acts as an assistant inside MemoryNest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Artificial intelligence helps organize the photographs.&lt;br&gt;
People preserve the meaning of the memory.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;You can try MemoryNest using the following links:&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://anmemorynest.ai.studio" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;anmemorynest.ai.studio&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The demo is prepared so that users can explore the application without creating an account.&lt;/p&gt;

&lt;p&gt;It includes sample albums, family stories, trips, and memories to demonstrate how the collaborative experience works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;MemoryNest was developed as a modern full-stack web application.&lt;/p&gt;

&lt;p&gt;The main technologies used are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;Tailwind CSS&lt;/li&gt;
&lt;li&gt;Node.js&lt;/li&gt;
&lt;li&gt;Express&lt;/li&gt;
&lt;li&gt;Firebase&lt;/li&gt;
&lt;li&gt;Google Cloud Firestore&lt;/li&gt;
&lt;li&gt;Google AI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The artificial intelligence integration runs on the server to protect credentials and keep sensitive information away from the browser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub Repository:&lt;/strong&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/anappwilos" rel="noopener noreferrer"&gt;
        anappwilos
      &lt;/a&gt; / &lt;a href="https://github.com/anappwilos/AnMemoryNest" rel="noopener noreferrer"&gt;
        AnMemoryNest
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      An
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/86bcf8eed3617be69c1d9c85006886e151bb77c49fe9e80ae334ebeaef6d098a/68747470733a2f2f61692e676f6f676c652e6465762f7374617469632f736974652d6173736574732f696d616765732f73686172652d6169732d3531333331353331382e706e67"&gt;&lt;img width="1200" height="475" alt="GHBanner" src="https://camo.githubusercontent.com/86bcf8eed3617be69c1d9c85006886e151bb77c49fe9e80ae334ebeaef6d098a/68747470733a2f2f61692e676f6f676c652e6465762f7374617469632f736974652d6173736574732f696d616765732f73686172652d6169732d3531333331353331382e706e67" class="js-gh-image-fallback"&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Run and deploy your AI Studio app&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;This contains everything you need to run your app locally.&lt;/p&gt;
&lt;p&gt;View your app in AI Studio: &lt;a href="https://ai.studio/apps/ad2fb8cf-3728-4ab7-8970-91ec637ca344" rel="nofollow noopener noreferrer"&gt;https://ai.studio/apps/ad2fb8cf-3728-4ab7-8970-91ec637ca344&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Run Locally&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt;  Node.js&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install dependencies:
&lt;code&gt;npm install&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Set the &lt;code&gt;GEMINI_API_KEY&lt;/code&gt; in &lt;a href="https://github.com/anappwilos/AnMemoryNest/.env.local" rel="noopener noreferrer"&gt;.env.local&lt;/a&gt; to your Gemini API key&lt;/li&gt;
&lt;li&gt;Run the app:
&lt;code&gt;npm run dev&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/anappwilos/AnMemoryNest" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;One of the main goals during development was to make sure that MemoryNest did not feel like a traditional file manager.&lt;/p&gt;

&lt;p&gt;I did not want to create a cold or overly technical interface.&lt;/p&gt;

&lt;p&gt;The application uses a warm and calm visual style inspired by family albums, journals, and memory books.&lt;/p&gt;

&lt;p&gt;Photographs and stories are given more visual importance than technical metadata.&lt;/p&gt;

&lt;p&gt;The experience is designed so that anyone can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explore memories.&lt;/li&gt;
&lt;li&gt;Create albums.&lt;/li&gt;
&lt;li&gt;Invite family members or friends.&lt;/li&gt;
&lt;li&gt;Add photographs.&lt;/li&gt;
&lt;li&gt;Complete stories.&lt;/li&gt;
&lt;li&gt;Use AI to organize content.&lt;/li&gt;
&lt;li&gt;Collaborate with other people.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Privacy was also treated as a priority.&lt;/p&gt;

&lt;p&gt;Photographs, family stories, and personal memories should remain protected and accessible only to authorized people.&lt;/p&gt;

&lt;p&gt;MemoryNest is designed as a private and collaborative space, not as a public social network.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Best Use of Google AI 🏆
&lt;/h3&gt;

&lt;p&gt;MemoryNest uses Google AI to help transform large collections of photographs into memories that are organized, accessible, and easier to share.&lt;/p&gt;

&lt;p&gt;Artificial intelligence can assist with image classification, duplicate detection, title generation, and the creation of descriptions or stories.&lt;/p&gt;

&lt;p&gt;The memory assistant can also answer questions related to albums and help users recover information stored inside their collection.&lt;/p&gt;

&lt;p&gt;The main idea is not to use AI to create artificial memories.&lt;/p&gt;

&lt;p&gt;Its purpose is to help people find, organize, and preserve their real memories.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why MemoryNest Is Different
&lt;/h2&gt;

&lt;p&gt;There are many applications for storing photographs.&lt;/p&gt;

&lt;p&gt;However, storing an image does not mean preserving its story.&lt;/p&gt;

&lt;p&gt;A photograph can remain inside a folder for years without anyone remembering who appears in it, where it was taken, or what happened that day.&lt;/p&gt;

&lt;p&gt;MemoryNest tries to recover that context.&lt;/p&gt;

&lt;p&gt;It does not focus only on saving files, but on preserving:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;People.&lt;/li&gt;
&lt;li&gt;Relationships.&lt;/li&gt;
&lt;li&gt;Places.&lt;/li&gt;
&lt;li&gt;Stories.&lt;/li&gt;
&lt;li&gt;Emotions.&lt;/li&gt;
&lt;li&gt;Different perspectives of the same memory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A gallery stores photographs.&lt;/p&gt;

&lt;p&gt;MemoryNest tries to preserve everything that exists behind them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s Next
&lt;/h2&gt;

&lt;p&gt;In the future, I would like to expand MemoryNest with features such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Audio memories.&lt;/li&gt;
&lt;li&gt;Transcription of family stories.&lt;/li&gt;
&lt;li&gt;Interactive travel maps.&lt;/li&gt;
&lt;li&gt;Automatic timelines.&lt;/li&gt;
&lt;li&gt;People grouping with explicit consent.&lt;/li&gt;
&lt;li&gt;Importing collections from old hard drives.&lt;/li&gt;
&lt;li&gt;Restoration of damaged photographs.&lt;/li&gt;
&lt;li&gt;Digital time capsules.&lt;/li&gt;
&lt;li&gt;Family trees connected to memories.&lt;/li&gt;
&lt;li&gt;Printable album exports.&lt;/li&gt;
&lt;li&gt;Mobile applications.&lt;/li&gt;
&lt;li&gt;Advanced digital legacy options.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One of my future goals is for MemoryNest to help recover old collections stored on hard drives, inside disorganized folders, and in forgotten backups.&lt;/p&gt;

&lt;p&gt;The idea is to transform all that content into albums that families and friends can rediscover together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;MemoryNest was born from a simple idea.&lt;/p&gt;

&lt;p&gt;Today, we have an extraordinary ability to capture moments, but we do not always know how to preserve them.&lt;/p&gt;

&lt;p&gt;Photographs remain on our phones, disappear inside backups, or are forgotten on old hard drives.&lt;/p&gt;

&lt;p&gt;Over time, their context also disappears.&lt;/p&gt;

&lt;p&gt;We stop remembering who appears in them, where they were taken, or why that moment was important.&lt;/p&gt;

&lt;p&gt;MemoryNest tries to change that.&lt;/p&gt;

&lt;p&gt;It aims to provide a space where family members and friends can bring their photographs together, complete their stories, and preserve a shared legacy.&lt;/p&gt;

&lt;p&gt;Because saving a photograph is important.&lt;/p&gt;

&lt;p&gt;But sharing its story is what truly preserves the memory.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
    </item>
    <item>
      <title>AnGithubManager: an application for my day-to-day life as a developer</title>
      <dc:creator>Nicolas A. R.</dc:creator>
      <pubDate>Wed, 04 Mar 2026 14:27:22 +0000</pubDate>
      <link>https://dev.to/nalarconrapela/angithubmanager-an-application-for-my-day-to-day-life-as-a-developer-9if</link>
      <guid>https://dev.to/nalarconrapela/angithubmanager-an-application-for-my-day-to-day-life-as-a-developer-9if</guid>
      <description>&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.amazonaws.com%2Fuploads%2Farticles%2Fab214t66yx659tgnrgnw.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.amazonaws.com%2Fuploads%2Farticles%2Fab214t66yx659tgnrgnw.png" alt="Logo AngithubManager" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built with Google Gemini
&lt;/h2&gt;

&lt;p&gt;My last few months have been focused on creating various projects as part of my AI learning journey.&lt;/p&gt;

&lt;p&gt;I'm a Git and GitHub enthusiast, but I didn't interact much with the interface. Lately, however, I've found myself needing to use it, but working on multiple projects simultaneously made navigating the GitHub interface quite cumbersome. To address this, I started the AnGithubManager project using Google AI Studio.&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.amazonaws.com%2Fuploads%2Farticles%2Fbhbewjf07vbh6afijupk.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.amazonaws.com%2Fuploads%2Farticles%2Fbhbewjf07vbh6afijupk.png" alt="Login" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is where Gemini solves my main problem: creating a simple pull request without having to think about it automatically, saving a significant amount of time, and above all, providing invaluable support when my head is spinning with problems.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;tbody&gt;&lt;tr&gt;
    &lt;td&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.amazonaws.com%2Fuploads%2Farticles%2Fnl9olr7z4sru4uy12zgf.png" alt="Image 1" width="543" height="490"&gt;&lt;br&gt;
      Welcome
    &lt;/td&gt;
    &lt;td&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.amazonaws.com%2Fuploads%2Farticles%2Fhw22878bmkmzyhaazo07.png" alt="Image 2" width="800" height="2940"&gt;&lt;br&gt;
      Lista
    &lt;/td&gt;
    &lt;td&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.amazonaws.com%2Fuploads%2Farticles%2Fwiy1auo3cdlh8hv04573.png" alt="Image 3" width="800" height="559"&gt;&lt;br&gt;
      Navegación
    &lt;/td&gt;
    &lt;td&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.amazonaws.com%2Fuploads%2Farticles%2Fucawf7qg64qhytoq2ltg.png" alt="Image 4" width="800" height="435"&gt;&lt;br&gt;
      Detalle
    &lt;/td&gt;
  &lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://angithubmanagerbeta.onrender.com/" rel="noopener noreferrer"&gt;https://angithubmanagerbeta.onrender.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Images creating PR: &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.amazonaws.com%2Fuploads%2Farticles%2F8kdkqcj298359j2jkj7t.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2F8kdkqcj298359j2jkj7t.jpg" width="800" height="1733"&gt;&lt;/a&gt;&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.amazonaws.com%2Fuploads%2Farticles%2Fh3owminppbz8dbod9l1n.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2Fh3owminppbz8dbod9l1n.jpg" alt=" " width="800" height="1733"&gt;&lt;/a&gt;&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.amazonaws.com%2Fuploads%2Farticles%2Fu6k5e1wn7t942k7axsry.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2Fu6k5e1wn7t942k7axsry.jpg" alt=" " width="800" height="1733"&gt;&lt;/a&gt;&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.amazonaws.com%2Fuploads%2Farticles%2Fn5doqtmcjku6z8g3l45y.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2Fn5doqtmcjku6z8g3l45y.jpg" alt=" " width="800" height="1733"&gt;&lt;/a&gt;&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.amazonaws.com%2Fuploads%2Farticles%2F0ktf2bwrk8ib2qqhmx14.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2F0ktf2bwrk8ib2qqhmx14.jpg" alt=" " width="800" height="1733"&gt;&lt;/a&gt;&lt;br&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.amazonaws.com%2Fuploads%2Farticles%2F4d8qmvp6366wwsalcf4f.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2F4d8qmvp6366wwsalcf4f.jpg" alt=" " width="800" height="1733"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;I learned about the real-world, production implementation of Gemeni services.&lt;br&gt;
As a side effect, I also learned to use Google AI Studio.&lt;/p&gt;

&lt;h2&gt;
  
  
  Google Gemini Feedback
&lt;/h2&gt;

&lt;p&gt;What worked best was that it could be implemented from day one.&lt;br&gt;
The most complicated part at the time was keeping it running in different environments such as Google AI Studio, local, and production, due to technical limitations in Google AI Studio, which didn't support enviorments by default. Therefore, I had to hardcode a backend URL to call if it couldn't find a valid environments.&lt;/p&gt;

&lt;h1&gt;
  
  
  gemini #googleaistudio #github #anappwilos
&lt;/h1&gt;

</description>
      <category>devchallenge</category>
      <category>geminireflections</category>
      <category>gemini</category>
    </item>
    <item>
      <title>🛒Shopping list to make shopping faster - AnQuickMerca</title>
      <dc:creator>Nicolas A. R.</dc:creator>
      <pubDate>Mon, 02 Mar 2026 06:53:57 +0000</pubDate>
      <link>https://dev.to/nalarconrapela/lista-de-la-compra-para-hacer-mas-rapido-las-compras-anquickmerca-4ea9</link>
      <guid>https://dev.to/nalarconrapela/lista-de-la-compra-para-hacer-mas-rapido-las-compras-anquickmerca-4ea9</guid>
      <description>&lt;h2&gt;
  
  
  The Community
&lt;/h2&gt;

&lt;p&gt;I don't know if my community exists, but if it doesn't, it wouldn't be bad to create one; it's simply about going shopping.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;What I created (or what I tried to create 😅) is a shopping list app, but with a key difference compared to other apps: it optimizes your route within the supermarket. The idea is to shop more quickly and efficiently, avoiding that feeling of wandering around thirty times to pick up three things… or worse, arriving at a new supermarket and getting lost in the aisles looking for a loaf of bread or even a stocker, who's always there… until you need them and they mysteriously disappear 🫥.&lt;/p&gt;

&lt;p&gt;The app is based on a very popular supermarket in Spain (Mercadona), mainly because of its physical layout, data availability, and because it's the one I frequent most (hehe). Even so, the approach can easily be applied to any other store.&lt;/p&gt;

&lt;p&gt;And this is where the community comes in: it would be responsible for updating locations, notifying users of stock shortages, or other details that a company normally can't (or doesn't want to) share. &lt;em&gt;It's true that I still need to polish this part a bit (hehe), but the idea is clear&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Remember that this is a demo; therefore, some data may not be 100% accurate, and it's not yet available to end users. But if it's successful, and the community supports it, we could develop it further and implement it for real-world use. 🙂&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&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.amazonaws.com%2Fuploads%2Farticles%2Fajmhc62on63dcxuzwnyp.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2Fajmhc62on63dcxuzwnyp.jpg" alt=" "&gt;&lt;/a&gt;&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.amazonaws.com%2Fuploads%2Farticles%2F4ouxhb7vu3myotccb2st.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2F4ouxhb7vu3myotccb2st.jpg" alt=" "&gt;&lt;/a&gt;&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.amazonaws.com%2Fuploads%2Farticles%2F81mip9gsld940tag7ue4.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2F81mip9gsld940tag7ue4.jpg" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Idea
&lt;/h3&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.amazonaws.com%2Fuploads%2Farticles%2Frzysqcbljk6rmtahgi45.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.amazonaws.com%2Fuploads%2Farticles%2Frzysqcbljk6rmtahgi45.png" alt=" "&gt;&lt;/a&gt;&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.amazonaws.com%2Fuploads%2Farticles%2Fwoadzyeb6tesniwwp5og.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.amazonaws.com%2Fuploads%2Farticles%2Fwoadzyeb6tesniwwp5og.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nicolasalarconrapela" rel="noopener noreferrer"&gt;
        nicolasalarconrapela
      &lt;/a&gt; / &lt;a href="https://github.com/nicolasalarconrapela/AnQuickMerca" rel="noopener noreferrer"&gt;
        AnQuickMerca
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Un gestor de compras en supermercado fisico
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/nicolasalarconrapela/AnQuickMerca/public/icon.svg"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fnicolasalarconrapela%2FAnQuickMerca%2Fpublic%2Ficon.svg" alt="AnQuickMerca Logo" width="120" height="120"&gt;&lt;/a&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;AnQuickMerca&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Optimize your shopping in seconds&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/nicolasalarconrapela/AnQuickMerca/./LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f8df3091bbe1149f398a5369b2c39e896766f9f6efba3477c63e9b4aa940ef14/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e" alt="License"&gt;&lt;/a&gt;
&lt;a href="https://github.com/nicolasalarconrapela/AnQuickMerca/./public/manifest.json" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9508337e240bf025c7720dc5d8e830ab4aa88c08595aa91c36bac743e85ca9f6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5057412d72656164792d707572706c65" alt="PWA"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/nicolasalarconrapela/AnQuickMerca/imgs/image-3.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fnicolasalarconrapela%2FAnQuickMerca%2Fimgs%2Fimage-3.png" alt="loading" width="140"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/nicolasalarconrapela/AnQuickMerca/imgs/image.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fnicolasalarconrapela%2FAnQuickMerca%2Fimgs%2Fimage.png" alt="welcome" width="140"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/nicolasalarconrapela/AnQuickMerca/imgs/image-1.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fnicolasalarconrapela%2FAnQuickMerca%2Fimgs%2Fimage-1.png" alt="lista gazpacho" width="140"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/nicolasalarconrapela/AnQuickMerca/imgs/image-2.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fnicolasalarconrapela%2FAnQuickMerca%2Fimgs%2Fimage-2.png" alt="navegacion" width="136"&gt;&lt;/a&gt;
&lt;/p&gt;


&lt;/div&gt;

&lt;p&gt;🌐 &lt;a href="https://anquickmerca-frontend.onrender.com" rel="nofollow noopener noreferrer"&gt;https://anquickmerca-frontend.onrender.com&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What is AnQuickMerca?&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;AnQuickMerca is a &lt;strong&gt;Progressive Web App (PWA)&lt;/strong&gt; built to optimize your Mercadona shopping in real time. Create smart shopping lists, get an efficient in-store route, and search products with AI assistance.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Key Features&lt;/h2&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;🛒 &lt;strong&gt;Shopping lists&lt;/strong&gt; — Create, edit, and organize multiple lists&lt;/li&gt;
&lt;li&gt;🗺️ &lt;strong&gt;In-store navigation&lt;/strong&gt; — Optimized aisle routes to reduce time and backtracking&lt;/li&gt;
&lt;li&gt;🔍 &lt;strong&gt;AI-assisted search&lt;/strong&gt; — Find products using Google Gemini assistance&lt;/li&gt;
&lt;li&gt;🌍 &lt;strong&gt;Store picker&lt;/strong&gt; — Interactive Spain map with Mercadona locations&lt;/li&gt;
&lt;li&gt;📱 &lt;strong&gt;Installable PWA&lt;/strong&gt; — Works offline and feels like a native app on mobile&lt;/li&gt;
&lt;li&gt;🌐 &lt;strong&gt;Bilingual UI&lt;/strong&gt; — Full interface in Spanish and English&lt;/li&gt;
&lt;li&gt;🔁 &lt;strong&gt;Recurring lists&lt;/strong&gt; — Schedule daily, weekly, monthly, or yearly shopping&lt;/li&gt;
&lt;li&gt;💰 &lt;strong&gt;Estimated total&lt;/strong&gt; — Real-time cost estimate as you build your list&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Tech Stack&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;&lt;div class="table-wrapper-paragraph"&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;table&gt;

&lt;thead&gt;

&lt;tr&gt;

&lt;th&gt;Technology&lt;/th&gt;

&lt;th&gt;Purpose&lt;/th&gt;

&lt;/tr&gt;

&lt;/thead&gt;

&lt;tbody&gt;

&lt;tr&gt;

&lt;td&gt;React 19 + TypeScript&lt;/td&gt;

&lt;td&gt;Frontend framework&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Vite 6&lt;/td&gt;

&lt;td&gt;Build tool &amp;amp; dev server&lt;/td&gt;

&lt;/tr&gt;

&lt;/tbody&gt;

&lt;/table&gt;&lt;/div&gt;…&lt;p&gt;&lt;/p&gt;&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nicolasalarconrapela/AnQuickMerca" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;





&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;It is a Vite and Typescript project with persistence in localstorage &lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>showdev</category>
    </item>
    <item>
      <title>devnewyear2026 Portfolio - Nicolás Alarcón Rapela</title>
      <dc:creator>Nicolas A. R.</dc:creator>
      <pubDate>Mon, 02 Feb 2026 07:33:43 +0000</pubDate>
      <link>https://dev.to/nalarconrapela/devnewyear2026-portfolio-nicolas-alarcon-rapela-40fn</link>
      <guid>https://dev.to/nalarconrapela/devnewyear2026-portfolio-nicolas-alarcon-rapela-40fn</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/new-year-new-you-google-ai-2025-12-31"&gt;New Year, New You Portfolio Challenge Presented by Google AI&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About Me
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Portfolio
&lt;/h2&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag__cloud-run"&gt;
  &lt;iframe height="600px" src="https://anportafolioia-66989787089.us-west1.run.app"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;




&lt;p&gt;Don't forget to include the dev label!GC&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;I have used Google AI Studio and AnGravity&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm Most Proud Of
&lt;/h2&gt;

&lt;p&gt;Well, what I'm most proud of is being able to put it together with such short notice, since I only found out last week, but honestly, it turned out much better than I could have ever imagined.&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/nicolasalarconrapela/AnPortafolioIA" rel="noopener noreferrer"&gt;https://github.com/nicolasalarconrapela/AnPortafolioIA&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>googleaichallenge</category>
      <category>portfolio</category>
      <category>gemini</category>
    </item>
  </channel>
</rss>
