<?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: Meng Li</title>
    <description>The latest articles on DEV Community by Meng Li (@limeng05).</description>
    <link>https://dev.to/limeng05</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%2F4204475%2Fb0483fe0-5a3d-42a0-b9bc-f23e12ae5038.png</url>
      <title>DEV Community: Meng Li</title>
      <link>https://dev.to/limeng05</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/limeng05"/>
    <language>en</language>
    <item>
      <title>Not Every Useful Web App Is an AI Tool: What I'm Curating on AINavly</title>
      <dc:creator>Meng Li</dc:creator>
      <pubDate>Sat, 24 Oct 2026 11:04:17 +0000</pubDate>
      <link>https://dev.to/limeng05/not-every-useful-web-app-is-an-ai-tool-what-im-curating-on-ainavly-4i52</link>
      <guid>https://dev.to/limeng05/not-every-useful-web-app-is-an-ai-tool-what-im-curating-on-ainavly-4i52</guid>
      <description>&lt;p&gt;A directory can have hundreds of links and still leave you wondering what to click.&lt;/p&gt;

&lt;p&gt;That's something I've been thinking about while working on &lt;a href="https://ainavly.com/" rel="noopener noreferrer"&gt;AINavly&lt;/a&gt;, a curated directory of useful projects from around the web. Despite the name, it isn't only about AI. There are plenty of small web apps and browser games worth discovering, too.&lt;/p&gt;

&lt;p&gt;The question I'm trying to answer isn't &lt;em&gt;"How many tools can I list?"&lt;/em&gt; It's &lt;em&gt;"Can someone look at an entry and quickly decide whether this is worth their time?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here's what belongs in the collection, and how I think about choosing it.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. AI tools with a clear job to do
&lt;/h2&gt;

&lt;p&gt;AI is the obvious starting point, but "uses AI" isn't a useful category by itself.&lt;/p&gt;

&lt;p&gt;I'm interested in tools that help with specific tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Chat and research:&lt;/strong&gt; ChatGPT, Claude, and Perplexity represent different ways to ask questions, work through ideas, or find sources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coding:&lt;/strong&gt; Cursor and newer AI coding products belong here when there's a clear development workflow to explain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Images and creative work:&lt;/strong&gt; Midjourney and other visual tools are easier to evaluate when you know what kind of output you're trying to make.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Writing and productivity:&lt;/strong&gt; Tools such as Notion AI are most useful when their role in an existing workflow is clear.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The directory's submission categories also make room for AI video, audio, writing, agents, marketing, and model APIs. That doesn't mean every category is equally full today; it's the scope of projects I want to be able to evaluate.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Small web apps that solve surprisingly specific problems
&lt;/h2&gt;

&lt;p&gt;Some of the most interesting projects don't need an AI label at all.&lt;/p&gt;

&lt;p&gt;A browser-based embroidery lettering tool, a digital flower-gift builder, or a controller calibration utility might serve a narrow audience. But if it solves a real problem, that's enough reason to look closer.&lt;/p&gt;

&lt;p&gt;Projects already featured on AINavly include &lt;strong&gt;Stitch Typewriter&lt;/strong&gt;, &lt;strong&gt;Bloomify&lt;/strong&gt;, &lt;strong&gt;Learn Arduino&lt;/strong&gt;, and &lt;strong&gt;DualShock Calibration GUI&lt;/strong&gt;. They don't all belong to the same industry, and that's the point: usefulness is more important than fitting a trendy label.&lt;/p&gt;

&lt;p&gt;For this group, I want to explain what someone can actually do on the site, whether it requires an account, and what limitations to check before investing time in it.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Browser games and unusual interactive projects
&lt;/h2&gt;

&lt;p&gt;I also include games that run in the browser.&lt;/p&gt;

&lt;p&gt;They range from quick experiments to more involved projects: &lt;strong&gt;CrazyCattle3D&lt;/strong&gt;, &lt;strong&gt;Brisbane Streets&lt;/strong&gt;, &lt;strong&gt;Busy Nurse&lt;/strong&gt;, and &lt;strong&gt;Mela Chaloge&lt;/strong&gt; are a few examples in the current collection.&lt;/p&gt;

&lt;p&gt;Game listings need different information from productivity tools. Instead of promising that something will "boost efficiency," they should tell you things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What kind of game is it?&lt;/li&gt;
&lt;li&gt;Can you play immediately, or is setup required?&lt;/li&gt;
&lt;li&gt;What controls, languages, or save options are available?&lt;/li&gt;
&lt;li&gt;Is this the original project, a fan-made version, or an unofficial mirror?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sometimes knowing what &lt;em&gt;not&lt;/em&gt; to expect is the most useful part of a listing.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Projects can come from anywhere
&lt;/h2&gt;

&lt;p&gt;A useful tool doesn't have to live on a polished company domain. Interesting projects show up on Vercel, GitHub Pages, Cloudflare Pages, and independent sites.&lt;/p&gt;

&lt;p&gt;That creates a discovery problem: two projects may have similar names, one might have moved, and another might be an outdated demo. A directory should help people find the right destination, not just repeat whatever URL happens to rank in search.&lt;/p&gt;

&lt;p&gt;AINavly's main site covers projects across the wider web. There's also a sister directory focused more specifically on Vercel-hosted discoveries. The overlap is intentional, but each listing should be written for the audience using that directory.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. What makes a project worth listing?
&lt;/h2&gt;

&lt;p&gt;I don't think a listing should be just a logo, a one-line pitch, and a button.&lt;/p&gt;

&lt;p&gt;These are the questions I try to answer:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;What does it actually do?&lt;/strong&gt; Give a concrete use case, not a collection of buzzwords.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How do you start?&lt;/strong&gt; Explain the basic steps or access requirements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What should users know first?&lt;/strong&gt; Mention pricing, language limitations, privacy considerations, or anything else that affects the decision.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Is the source clear?&lt;/strong&gt; Link to the relevant official project and distinguish it from lookalikes when necessary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What are the alternatives?&lt;/strong&gt; Give readers enough context to choose, rather than pushing them toward a single option.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Submissions are reviewed rather than automatically published. Broken links, duplicates, misleading claims, and harmful projects aren't the kind of entries I want to add just to grow a number on the homepage.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. The hard part is keeping the directory useful
&lt;/h2&gt;

&lt;p&gt;Adding a new card is easy. Keeping it useful after a project changes its name, pricing, features, or URL is the real work.&lt;/p&gt;

&lt;p&gt;That's why I think &lt;strong&gt;when something was added&lt;/strong&gt;, &lt;strong&gt;when its description was updated&lt;/strong&gt;, and &lt;strong&gt;when its source was checked&lt;/strong&gt; are different pieces of information. A recent editorial edit doesn't automatically mean every product claim was retested.&lt;/p&gt;

&lt;p&gt;I'm still learning what makes a directory genuinely useful, but one lesson is already clear: the number of links isn't the product. The context around those links is.&lt;/p&gt;

&lt;p&gt;If you've built or regularly used a tool directory, what information do you look for before opening a project you've never heard of?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How I Built a Tool Directory with Astro and Cloudflare Pages</title>
      <dc:creator>Meng Li</dc:creator>
      <pubDate>Sat, 24 Oct 2026 10:41:45 +0000</pubDate>
      <link>https://dev.to/limeng05/how-i-built-a-tool-directory-with-astro-and-cloudflare-pages-48i0</link>
      <guid>https://dev.to/limeng05/how-i-built-a-tool-directory-with-astro-and-cloudflare-pages-48i0</guid>
      <description>&lt;p&gt;A tool directory sounds simple: store some links, put them into categories, and add a search box.&lt;/p&gt;

&lt;p&gt;Then you start adding tools. You need individual pages, pagination, working links, useful descriptions, and a way to ship updates without turning the project into a maintenance job.&lt;/p&gt;

&lt;p&gt;That's the problem I've been working through with &lt;a href="https://navsprout.com/" rel="noopener noreferrer"&gt;NavSprout&lt;/a&gt;, a small directory of web tools, creative apps, and browser-based projects.&lt;/p&gt;

&lt;p&gt;I chose &lt;strong&gt;Astro&lt;/strong&gt; for the content-heavy pages and &lt;strong&gt;Cloudflare Pages&lt;/strong&gt; for deployment. Here's what has mattered so far—and what I'd do differently if I started again.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Static first, interactive where it counts
&lt;/h2&gt;

&lt;p&gt;Most visitors come to a directory to do one of three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Discover something useful.&lt;/li&gt;
&lt;li&gt;Check whether it fits their task.&lt;/li&gt;
&lt;li&gt;Open the original tool.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of those steps needs a server-rendered page for every request.&lt;/p&gt;

&lt;p&gt;Astro makes a good default for this kind of site: generate the content pages ahead of time, then add client-side behavior only where it helps. On NavSprout, the directory includes filtering, search, saved tools, and comparisons, but the actual tool information should still be readable without waiting for a large JavaScript application to boot.&lt;/p&gt;

&lt;p&gt;The important distinction is &lt;strong&gt;static content doesn't mean a static experience&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The data model matters more than the cards
&lt;/h2&gt;

&lt;p&gt;My first instinct with a directory was to focus on the layout. In practice, deciding what information belongs to each tool entry matters much more.&lt;/p&gt;

&lt;p&gt;A useful profile should answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What does this tool actually help me do?&lt;/li&gt;
&lt;li&gt;Who is it a good fit for?&lt;/li&gt;
&lt;li&gt;Why was it included?&lt;/li&gt;
&lt;li&gt;What should I check before using it?&lt;/li&gt;
&lt;li&gt;Where is the official source?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's a &lt;em&gt;simplified example&lt;/em&gt; of the kind of structured data that supports those questions—not a copy of my production schema:&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Tool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;slug&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="nl"&gt;name&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="nl"&gt;category&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="nl"&gt;useCase&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="nl"&gt;whyHere&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="nl"&gt;officialUrl&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="nl"&gt;limitations&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A directory page can look nice and still be unhelpful. The goal is to give someone a reason to click—or a reason to skip a tool that isn't right for them.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Static pagination without manually reshuffling pages
&lt;/h2&gt;

&lt;p&gt;Pagination was one of the first problems I had to think through.&lt;/p&gt;

&lt;p&gt;If new entries appear first, adding one tool changes which items belong on page 1, page 2, and so on. I didn't want to manually maintain those pages.&lt;/p&gt;

&lt;p&gt;Astro's &lt;code&gt;paginate()&lt;/code&gt; function handles the page generation at build time. The following is an &lt;strong&gt;illustrative version&lt;/strong&gt; of the pattern, using 12 items per page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
// Example: src/pages/[...page].astro
import { tools } from '../data/tools';

export function getStaticPaths({ paginate }) {
  const newestFirst = [...tools].sort(
    (a, b) =&amp;gt; Date.parse(b.addedAt) - Date.parse(a.addedAt)
  );

  return paginate(newestFirst, { pageSize: 12 });
}

const { page } = Astro.props;
---

&amp;lt;section&amp;gt;
  {page.data.map((tool) =&amp;gt; (
    &amp;lt;a href={`/tools/${tool.slug}/`}&amp;gt;{tool.name}&amp;lt;/a&amp;gt;
  ))}
&amp;lt;/section&amp;gt;

&amp;lt;nav aria-label="Pagination"&amp;gt;
  {page.url.prev &amp;amp;&amp;amp; &amp;lt;a href={page.url.prev}&amp;gt;Previous&amp;lt;/a&amp;gt;}
  &amp;lt;span&amp;gt;Page {page.currentPage} of {page.lastPage}&amp;lt;/span&amp;gt;
  {page.url.next &amp;amp;&amp;amp; &amp;lt;a href={page.url.next}&amp;gt;Next&amp;lt;/a&amp;gt;}
&amp;lt;/nav&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With a rest parameter route like &lt;code&gt;[...page].astro&lt;/code&gt;, the first page can live at &lt;code&gt;/&lt;/code&gt;, followed by &lt;code&gt;/2/&lt;/code&gt;, &lt;code&gt;/3/&lt;/code&gt;, and so on. When the dataset changes, the next build regenerates the appropriate pages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One detail worth keeping separate:&lt;/strong&gt; paginated listing URLs are not the identity of a tool. Each tool should have its own stable, descriptive URL, so an item moving from page 1 to page 2 doesn't change its permanent address.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. SEO: a directory needs more than lots of URLs
&lt;/h2&gt;

&lt;p&gt;It's easy to generate hundreds of pages with Astro. It's much harder to make those pages worth visiting.&lt;/p&gt;

&lt;p&gt;A few decisions have been especially important to me:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Give detail pages a real job.&lt;/strong&gt; A tool page shouldn't just repeat its homepage tagline. Include the use case, selection rationale, source links, and limitations where known.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use normal HTML links.&lt;/strong&gt; Pagination and tool detail links should be actual anchors, not destinations that only appear after JavaScript runs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep metadata specific.&lt;/strong&gt; Titles and descriptions should reflect the individual tool or category. Avoid giving every page the same generic SEO copy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Treat pagination honestly.&lt;/strong&gt; Page 2 contains different tools from page 1, so it shouldn't automatically canonicalize to page 1. Each indexable listing page needs a sensible canonical strategy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't confuse more pages with more value.&lt;/strong&gt; If two entries describe essentially the same thing, adding both doesn't make the directory more useful.&lt;/p&gt;

&lt;p&gt;A sitemap helps search engines discover generated routes, but it doesn't replace thoughtful internal linking or good content.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Deploying with Cloudflare Pages
&lt;/h2&gt;

&lt;p&gt;For a mostly static Astro site, the deployment setup can be wonderfully boring.&lt;/p&gt;

&lt;p&gt;The standard Cloudflare Pages configuration is:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&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;Build command&lt;/td&gt;
&lt;td&gt;&lt;code&gt;npm run build&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output directory&lt;/td&gt;
&lt;td&gt;&lt;code&gt;dist&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Production branch&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;main&lt;/code&gt; (or your chosen branch)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;With the repository connected, pushing a content update can trigger a new build and deployment. Preview deployments are useful for catching broken routes, bad metadata, or unexpected pagination changes before they go live.&lt;/p&gt;

&lt;p&gt;The bigger benefit is operational simplicity. I don't want to manage a server just to serve directory pages. If I add something that genuinely needs a dynamic backend, I can evaluate that separately rather than making the entire site dynamic from day one.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. What I'd pay attention to next
&lt;/h2&gt;

&lt;p&gt;As the number of tools grows, the challenges shift:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Content quality:&lt;/strong&gt; keeping entries accurate as products change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discovery:&lt;/strong&gt; helping people find the right tool without scrolling through endless cards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build health:&lt;/strong&gt; catching duplicate slugs, broken links, and missing metadata before deployment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Useful signals:&lt;/strong&gt; learning which pages actually help visitors, not just which pages get impressions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If I were starting a directory today, I'd still choose a static-first approach. But I'd design the content schema and URL structure &lt;em&gt;before&lt;/em&gt; polishing the homepage.&lt;/p&gt;

&lt;p&gt;The main lesson so far: &lt;strong&gt;a directory is a content system first and a collection of links second&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you've built a directory with Astro, I'm curious how you handle updates and pagination once the catalog grows.&lt;/p&gt;

</description>
      <category>deployment</category>
      <category>frontend</category>
      <category>tools</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
