<?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: Getinfo Toyou</title>
    <description>The latest articles on DEV Community by Getinfo Toyou (@getinfotoyou).</description>
    <link>https://dev.to/getinfotoyou</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%2F3794901%2Fcdf356ed-ee53-474c-a1a2-73ee4d5bbeb5.png</url>
      <title>DEV Community: Getinfo Toyou</title>
      <link>https://dev.to/getinfotoyou</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/getinfotoyou"/>
    <language>en</language>
    <item>
      <title>How I Built a Zero-Dependency, Instant Unicode Search Engine</title>
      <dc:creator>Getinfo Toyou</dc:creator>
      <pubDate>Mon, 27 Jul 2026 14:30:33 +0000</pubDate>
      <link>https://dev.to/getinfotoyou/how-i-built-a-zero-dependency-instant-unicode-search-engine-26k6</link>
      <guid>https://dev.to/getinfotoyou/how-i-built-a-zero-dependency-instant-unicode-search-engine-26k6</guid>
      <description>&lt;p&gt;We've all been there: you're writing a Markdown document, styling a UI component, or drafting an email, and you need a specific symbol. Maybe it's a right-facing arrow (→), a checkmark (✓), or an obscure mathematical operator.&lt;/p&gt;

&lt;p&gt;Usually, the workflow looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open a new browser tab.&lt;/li&gt;
&lt;li&gt;Search "right arrow symbol copy paste".&lt;/li&gt;
&lt;li&gt;Click a website covered in ads.&lt;/li&gt;
&lt;li&gt;Highlight, copy, go back to your editor, and paste.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It is a minor interruption, but doing it ten times a day ruins your flow. That is the exact problem that led me to build SymbolHub, a clean, fast, and utility-first tool to search and copy any special character instantly. You can try the live version here: &lt;a href="https://symbolhub.getinfotoyou.com" rel="noopener noreferrer"&gt;https://symbolhub.getinfotoyou.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is how I built it, the technical choices I made, and the challenges of handling thousands of Unicode characters directly in the browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Goal: Zero Latency and High Precision
&lt;/h2&gt;

&lt;p&gt;When you need a symbol, you want it immediately. I wanted the search experience to feel as fast as typing in a terminal. That meant no database queries, no loading spinners, and no heavy client-side frameworks. &lt;/p&gt;

&lt;p&gt;The application needed to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Load in under 200ms.&lt;/li&gt;
&lt;li&gt;Support fuzzy search (e.g., typing "arrow" should show all arrows, but typing "right" should filter it down).&lt;/li&gt;
&lt;li&gt;Group symbols logically (e.g., Math, Punctuation, Currency, Emojis).&lt;/li&gt;
&lt;li&gt;Copy to clipboard with a single click.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;I chose to keep the stack incredibly lean:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend&lt;/strong&gt;: HTML5 and Vanilla CSS (using modern CSS variables and grid systems).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logic&lt;/strong&gt;: Vanilla JavaScript.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data&lt;/strong&gt;: A pre-processed JSON file containing approximately 1,500 of the most commonly used Unicode characters, classified by names, categories, and tags.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using vanilla JavaScript instead of React or Vue eliminated build-step overhead and kept the initial bundle size tiny. The entire site, including the symbol database, weighs under 100KB gzipped.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical Challenges
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Fast Fuzzy Searching in the Browser
&lt;/h3&gt;

&lt;p&gt;Since the database lives entirely on the client side, searching through 1,500+ items is fast but can still cause UI stuttering if not done carefully. If a user types quickly, triggering a DOM redraw on every keystroke blocks the main thread.&lt;/p&gt;

&lt;p&gt;To solve this, I implemented a simple debounce function for the input handler and used a lightweight indexing strategy. Instead of searching the entire JSON structure, each symbol object has a pre-compiled search string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a user types, we filter the array using a basic &lt;code&gt;indexOf&lt;/code&gt; check on this string. If the result set changes, we update the DOM.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. DOM Batching and Performance
&lt;/h3&gt;

&lt;p&gt;Redrawing 1,000 grid elements is expensive. To keep the UI responsive, SymbolHub uses a virtualized rendering approach. If a query returns hundreds of results, we only render the first 150 immediately. A simple &lt;code&gt;IntersectionObserver&lt;/code&gt; loads more as the user scrolls. This keeps the initial search response time under 10ms.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The Clipboard API vs. Browser Support
&lt;/h3&gt;

&lt;p&gt;Copying text to the clipboard seems simple with &lt;code&gt;navigator.clipboard.writeText()&lt;/code&gt;. However, older mobile browsers and certain webviews do not fully support this API, or they require strict user-interaction contexts.&lt;/p&gt;

&lt;p&gt;I wrote a fallback utility that falls back to the older &lt;code&gt;document.execCommand('copy')&lt;/code&gt; if the modern API fails:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;copyToClipboard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clipboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;textArea&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;textarea&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;textArea&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;textArea&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;textArea&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;copy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fallbackErr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;textArea&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Vanilla JS is still incredibly capable&lt;/strong&gt;: For utility apps, you rarely need a heavy SPA framework. The browser's native APIs are fast, mature, and easy to work with.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility matters for symbols&lt;/strong&gt;: Screen readers interpret Unicode differently. I added &lt;code&gt;aria-label&lt;/code&gt; attributes to each symbol card to describe what the symbol is, rather than letting the screen reader try to pronounce the raw Unicode character.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep the UX out of the way&lt;/strong&gt;: The best utility tools are the ones that require the fewest clicks.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Check It Out
&lt;/h2&gt;

&lt;p&gt;If you find yourself searching for special characters, bookmark &lt;a href="https://symbolhub.getinfotoyou.com" rel="noopener noreferrer"&gt;SymbolHub&lt;/a&gt;. It is completely free, runs entirely in your browser, and has no tracking or ads.&lt;/p&gt;

&lt;p&gt;Let me know what categories or features you would like to see added next!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>unicode</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Why I Built AIMarkdownPro: A Markdown Editor Designed for Flow</title>
      <dc:creator>Getinfo Toyou</dc:creator>
      <pubDate>Fri, 24 Jul 2026 14:30:27 +0000</pubDate>
      <link>https://dev.to/getinfotoyou/why-i-built-aimarkdownpro-a-markdown-editor-designed-for-flow-3fce</link>
      <guid>https://dev.to/getinfotoyou/why-i-built-aimarkdownpro-a-markdown-editor-designed-for-flow-3fce</guid>
      <description>&lt;p&gt;We write a lot of Markdown. Between project documentation, README files, API guides, and technical blog posts, it is the default language for developer communication. Yet, the writing process remains surprisingly fragmented. We draft in one editor, open a browser tab to chat with an AI for brainstorming or editing, copy-paste the output back, fix broken formatting, and look at a separate preview window.&lt;/p&gt;

&lt;p&gt;I built &lt;a href="https://aimarkdownpro.getinfotoyou.com" rel="noopener noreferrer"&gt;AIMarkdownPro&lt;/a&gt; to solve this specific workflow friction. It is a web-based Markdown editor with integrated AI assistance, designed to let you write, edit, preview, and format in a single workspace.&lt;/p&gt;

&lt;h3&gt;
  
  
  Who Benefits Most?
&lt;/h3&gt;

&lt;p&gt;While anyone writing Markdown can use it, AIMarkdownPro was built for two specific groups who stand to gain the most:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Technical Writers and Bloggers&lt;/strong&gt;&lt;br&gt;
If you publish on platforms like Dev.to, Hashnode, or Medium, you know the cognitive load of turning raw notes into polished articles. The AI helper in the editor acts as a sounding board. You can highlight a paragraph and ask the assistant to make it more concise, check the technical tone, or suggest subheadings—without leaving your draft. It helps maintain flow by keeping your focus on a single screen.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Developers Maintaining Documentation&lt;/strong&gt;&lt;br&gt;
Writing documentation is rarely a developer's favorite task. Creating READMEs, release notes, or installation guides often gets postponed. By using integrated templates and quick formatting shortcuts, developers can quickly generate structured documentation outlines. The editor parses code snippets correctly, ensuring that your technical instructions remain accurate and readable.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Tech Stack
&lt;/h3&gt;

&lt;p&gt;I kept the stack lightweight and focused on performance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend:&lt;/strong&gt; Next.js and TypeScript for a robust, typed application shell.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Editor:&lt;/strong&gt; A customized text area with real-time regex-based syntax highlighting, rather than a heavy IDE wrapper, to keep load times fast.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Markdown Engine:&lt;/strong&gt; Unified, remark, and rehype to parse, sanitize, and render the live preview side-by-side.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Integration:&lt;/strong&gt; A serverless API route connecting to LLM providers, optimized for streaming responses directly into the editor buffer.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Technical Challenges
&lt;/h3&gt;

&lt;p&gt;One major challenge was handling real-time rendering during AI streaming. When an LLM streams text, it outputs fragments. If you parse the entire document on every new token, the preview pane flashes, and the UI lags. I solved this by implementing a debounced partial parser. The preview only updates the block currently being edited during active typing or streaming, while full document parsing runs during idle periods.&lt;/p&gt;

&lt;p&gt;Another hurdle was managing cursor position. If the AI inserts text or formats a block, the cursor should ideally stay where the user expects it, rather than jumping to the end of the document. I built a custom state tracker that calculates offset shifts in the text area buffer, adjusting the selection range dynamically after each AI insertion.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lessons Learned
&lt;/h3&gt;

&lt;p&gt;Building this tool reinforced the value of constraint. It is tempting to add every editor feature under the sun—folder trees, custom themes, cloud syncing. But the real value lies in the writing experience. By focusing purely on formatting stability, fast previews, and a responsive AI interface, the editor remains lightweight and useful.&lt;/p&gt;

&lt;p&gt;I also learned that prompting for markdown generation is a specific science. General-purpose models tend to wrap their code in markdown blocks &lt;em&gt;inside&lt;/em&gt; the markdown editor, leading to nested blocks. I had to design strict system prompts to ensure the AI output blends directly into the user's active document format.&lt;/p&gt;

&lt;h3&gt;
  
  
  Give It a Try
&lt;/h3&gt;

&lt;p&gt;AIMarkdownPro is live, free to use, and designed to make your writing process a bit more cohesive. You can try it out at &lt;a href="https://aimarkdownpro.getinfotoyou.com" rel="noopener noreferrer"&gt;aimarkdownpro.getinfotoyou.com&lt;/a&gt;. I would love to hear your feedback on the writing flow and how the AI integration works for your specific documentation tasks.&lt;/p&gt;

</description>
      <category>markdown</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Why I Built a Privacy-First Period Tracker: Client-Side Predictions Without the Cloud</title>
      <dc:creator>Getinfo Toyou</dc:creator>
      <pubDate>Wed, 22 Jul 2026 14:30:44 +0000</pubDate>
      <link>https://dev.to/getinfotoyou/why-i-built-a-privacy-first-period-tracker-client-side-predictions-without-the-cloud-4d7d</link>
      <guid>https://dev.to/getinfotoyou/why-i-built-a-privacy-first-period-tracker-client-side-predictions-without-the-cloud-4d7d</guid>
      <description>&lt;p&gt;We track everything today: steps, screen time, and budgets. But when it comes to tracking a menstrual cycle, the options are surprisingly frustrating. For years, the choices have been divided into two camps: building a complex manual spreadsheet yourself, or handing over highly sensitive health data to corporate databases.&lt;/p&gt;

&lt;p&gt;Here is a breakdown of what it looks like to do this the hard way, why I built a middle ground, and the technical decisions behind it.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Hard Way: Spreadsheets vs. Privacy Concerns
&lt;/h3&gt;

&lt;p&gt;If you want to track your cycle privately, your first instinct might be a custom spreadsheet. I have seen spreadsheets with complex conditional formatting, date calculations, and rolling averages designed to predict the next cycle start date.&lt;/p&gt;

&lt;p&gt;While spreadsheets respect your privacy, the developer experience and user experience are painful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mobile friction:&lt;/strong&gt; Opening a giant Google Sheet or Excel file on a phone while dealing with a tiny virtual keyboard is a frustrating experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintenance overhead:&lt;/strong&gt; One accidental swipe can delete a cell formula, breaking the prediction logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lack of clean UI:&lt;/strong&gt; Logically viewing cycle trends or logging daily symptoms like mood or cramps becomes cluttered.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The alternative is using commercial apps. But in exchange for a polished UI, these services often demand that you create an account, sync your data to the cloud, and agree to lengthy privacy policies that allow them to monetize your health trends. For many health-conscious individuals, this is a non-starter.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Middle Ground: A Local-First Web App
&lt;/h3&gt;

&lt;p&gt;I wanted something that combined the convenience of a modern app with the privacy of an offline spreadsheet. That is why I built &lt;a href="https://periodtracker.getinfotoyou.com" rel="noopener noreferrer"&gt;PeriodTracker&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The premise is straightforward: you load the site, log your cycles, and see predictions. There are no accounts, no logins, and no servers storing your information. Everything stays in your browser.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Tech Stack
&lt;/h3&gt;

&lt;p&gt;I decided to keep the stack simple to ensure long-term maintainability and speed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend:&lt;/strong&gt; Plain HTML, CSS, and modern client-side JavaScript.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage:&lt;/strong&gt; &lt;code&gt;localStorage&lt;/code&gt; for quick retrieval of cycle histories and preferences.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Portability:&lt;/strong&gt; A JSON-based backup system allowing users to export their data to a local file and import it on other devices.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By avoiding a backend database, the hosting is static, cost-effective, and secure by default. There is no server to hack, and no database for anyone to leak.&lt;/p&gt;

&lt;h3&gt;
  
  
  Technical Challenges &amp;amp; Implementation
&lt;/h3&gt;

&lt;p&gt;Building a local-first application without a backend presented some interesting architectural challenges.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Calculating Predictions Locally
&lt;/h4&gt;

&lt;p&gt;Without a server to run calculations, all cycle predictions must run efficiently in the user's browser. I implemented a moving average algorithm that analyzes the user's last six cycles to predict the next start date and the corresponding fertile window.&lt;/p&gt;

&lt;p&gt;Here is a simplified snippet of how the cycle length average is calculated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;calculateAverageCycleLength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cycles&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cycles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Default fallback&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;totalDays&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;cycles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cycles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;startDate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cycles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;startDate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;diffTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;diffDays&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;diffTime&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nx"&gt;totalDays&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;diffDays&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;totalDays&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cycles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Data Loss Prevention
&lt;/h4&gt;

&lt;p&gt;The biggest risk of client-side tracking is that if a user clears their browser storage, they lose their history. To mitigate this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The UI actively reminds users to download a periodic backup.&lt;/li&gt;
&lt;li&gt;The import/export feature parses uploaded JSON files, validates the structure to prevent malformed data injection, and populates the local state.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Lessons Learned
&lt;/h3&gt;

&lt;p&gt;Building a zero-database application taught me the value of friction removal. When users do not have to fill out an email form, verify their account, or set a password, they are far more likely to engage with the tool.&lt;/p&gt;

&lt;p&gt;Furthermore, local-first applications offer high performance. Because there are no API calls or server round-trips, the UI transitions are instantaneous.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;You do not need a complex backend or invasive data collection to build a functional utility. If you are looking for a straightforward, private way to track your cycle, check out the live version at &lt;a href="https://periodtracker.getinfotoyou.com" rel="noopener noreferrer"&gt;PeriodTracker&lt;/a&gt; and let me know your thoughts in the comments.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>privacy</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Why I Built My Own GPA Calculator (and How I Handled Multi-Scale Grade Math in JavaScript)</title>
      <dc:creator>Getinfo Toyou</dc:creator>
      <pubDate>Mon, 20 Jul 2026 14:30:28 +0000</pubDate>
      <link>https://dev.to/getinfotoyou/why-i-built-my-own-gpa-calculator-and-how-i-handled-multi-scale-grade-math-in-javascript-500e</link>
      <guid>https://dev.to/getinfotoyou/why-i-built-my-own-gpa-calculator-and-how-i-handled-multi-scale-grade-math-in-javascript-500e</guid>
      <description>&lt;p&gt;Every finals week in college followed the exact same stressful ritual: sitting in front of a messy spreadsheet at 2 AM, trying to figure out what score I needed on a 30% final exam to keep my 3.5 cumulative GPA. To make matters worse, different courses used different credit weightings, and half of the online tools I tried were either covered in intrusive ads, broken by math edge cases, or locked behind account paywalls just to calculate a target grade.&lt;/p&gt;

&lt;p&gt;That frustration is why I built &lt;strong&gt;GradePoint Pro&lt;/strong&gt; (&lt;a href="https://gradepointpro.getinfotoyou.com" rel="noopener noreferrer"&gt;gradepointpro.getinfotoyou.com&lt;/a&gt;), a free web app designed to let students and parents calculate semester GPA, track cumulative GPA across multiple grading scales, and solve target grade requirements without hassle.&lt;/p&gt;

&lt;p&gt;Here is a breakdown of why I built it, the technical hurdles I ran into, the tech stack I chose, and the lessons learned along the way.&lt;/p&gt;




&lt;h3&gt;
  
  
  Why I Built It
&lt;/h3&gt;

&lt;p&gt;Most generic grade calculators assume every school follows a rigid 4.0 scale with standard letter-to-grade point conversions. In reality, academic institutions vary wildly. Some use 4.3 scales (where an A+ is 4.3), others use 5.0 scales for AP/Honors courses, and many use custom percentage cutoffs.&lt;/p&gt;

&lt;p&gt;I wanted to build a utility that was:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Flexible&lt;/strong&gt;: Adaptable to multiple grading scales and credit weightings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instant &amp;amp; Privacy-Focused&lt;/strong&gt;: No sign-ups, no database tracking, and instant calculations directly in the browser.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Actionable&lt;/strong&gt;: Beyond just calculating past GPA, it had to answer the most urgent question students ask: &lt;em&gt;"What grade do I need on my final exam to hit my target GPA?"&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  The Tech Stack
&lt;/h3&gt;

&lt;p&gt;I kept the stack lean and performance-focused to ensure minimal load times:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend&lt;/strong&gt;: Vanilla JavaScript (ES6+) with modern CSS for lightweight execution and zero build overhead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State Management&lt;/strong&gt;: Reactive custom state container using &lt;code&gt;Proxy&lt;/code&gt; objects for reactive UI updates whenever grade inputs change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage&lt;/strong&gt;: Browser &lt;code&gt;localStorage&lt;/code&gt; API for persisting course lists and grade setups locally without sending user data to a server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment&lt;/strong&gt;: Static hosting via Cloudflare Pages for global edge caching and minimal latency.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Technical Challenges
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Multi-Scale Grade Normalization
&lt;/h4&gt;

&lt;p&gt;Supporting multiple scales (4.0, 4.3, 5.0, and percentage-based systems) meant I couldn't just hardcode letter-point lookups. I had to build a flexible normalization pipeline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Weighted Points = sum(Grade Point * Credits)&lt;/li&gt;
&lt;li&gt;GPA = Weighted Points / Total Credits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When converting between scales or aggregating cumulative historical semesters with current semester data, floating-point arithmetic quirks in JavaScript (like &lt;code&gt;0.1 + 0.2 === 0.30000000000000004&lt;/code&gt;) posed a real threat to accurate display. I implemented exact rounding utilities for display values while keeping full floating precision in internal state.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Building the Target Grade Solver
&lt;/h4&gt;

&lt;p&gt;Calculating the required final exam grade sounds straightforward, but edge cases make it tricky. The solver calculates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Required Final = (Target Overall - (Current Grade * (1 - Final Weight))) / Final Weight&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Handling edge cases—like when a student sets a mathematically impossible target grade given their current standing—required clear feedback UI rather than returning silent &lt;code&gt;NaN&lt;/code&gt; or unhelpful negative scores.&lt;/p&gt;




&lt;h3&gt;
  
  
  Lessons Learned
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Client-side storage builds user trust&lt;/strong&gt;: Users appreciate not having to create yet another account for a quick utility tool. Utilizing &lt;code&gt;localStorage&lt;/code&gt; gave students data persistence while respecting their privacy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic UI layout needs careful input validation&lt;/strong&gt;: When users rapidly add or remove rows, type partial numbers, or switch grading scales mid-stream, input sanitization and defensive state updates prevent subtle rendering bugs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solving a real personal pain point yields better products&lt;/strong&gt;: Building something I genuinely wished had existed during my own college years made it much easier to prioritize useful features over feature creep.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Conclusion &amp;amp; Try It Out
&lt;/h3&gt;

&lt;p&gt;GradePoint Pro was a rewarding project that grew into a refined tool for academic tracking. If you are a student preparing for finals, a college student mapping out your semester, or a parent helping track academic progress, feel free to try &lt;a href="https://gradepointpro.getinfotoyou.com" rel="noopener noreferrer"&gt;GradePoint Pro&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I would love to hear your thoughts, feedback, or suggestions on the math engine and UX in the comments below!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>showdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Handling Mixed-Unit API Payloads: Why I Built a Zero-Ad Unit Converter</title>
      <dc:creator>Getinfo Toyou</dc:creator>
      <pubDate>Wed, 15 Jul 2026 14:30:26 +0000</pubDate>
      <link>https://dev.to/getinfotoyou/handling-mixed-unit-api-payloads-why-i-built-a-zero-ad-unit-converter-jeg</link>
      <guid>https://dev.to/getinfotoyou/handling-mixed-unit-api-payloads-why-i-built-a-zero-ad-unit-converter-jeg</guid>
      <description>&lt;p&gt;If you have ever integrated a legacy IoT device, worked with hardware sensors, or managed database schemas designed across different international offices, you know the pain of dealing with mixed measurement units. A few weeks ago, I was debugging a webhook payload from a remote weather monitoring station. One service was reporting system temperatures in Fahrenheit, another was reporting wind speed in knots, and our new central analytics engine expected Celsius and meters per second.&lt;/p&gt;

&lt;p&gt;It is a minor problem in the grand scheme of software development, but it breaks your mental flow. Every time I needed to double-check my conversion logic, I found myself googling the formula or landing on unit conversion websites. Most of those sites are bloated with cookie prompts, auto-playing video ads, and layout shifts that jump around while you try to type. It was incredibly frustrating for what should be a simple utility.&lt;/p&gt;

&lt;p&gt;That frustration is why I built ConvertEase. I wanted a fast, zero-ad, single-page utility that gives instant conversion grids across length, weight, temperature, volume, speed, area, data, time, and currency. No clutter, no popups, just the numbers you need.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Tech Stack: Why I Went Vanilla
&lt;/h3&gt;

&lt;p&gt;For a tool that needs to load instantly and work on any device, throwing a heavy modern JavaScript framework at the problem felt unnecessary. I chose a lightweight, standard stack to keep things fast:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTML5 &amp;amp; Vanilla CSS&lt;/strong&gt;: For structural simplicity, fast rendering, and styling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vanilla JavaScript&lt;/strong&gt;: All conversion logic runs locally in the client, meaning zero network latency for conversions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;External Currency API&lt;/strong&gt;: Fetching currency rates asynchronously only when the currency tab is active, caching them in local storage to minimize API hits and reduce network requests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By avoiding framework overhead and build-step bloat, the entire app footprint is under 50KB, loading in milliseconds even on slow mobile networks or legacy hardware.&lt;/p&gt;

&lt;h3&gt;
  
  
  Technical Challenge: Floating-Point Math and Dynamic Grids
&lt;/h3&gt;

&lt;p&gt;Building a unit converter sounds trivial until you start handling JavaScript’s native floating-point arithmetic. If you convert 0.1 + 0.2, JavaScript evaluates it to 0.30000000000000004. In engineering calculations or currency exchange, small rounding errors can compound quickly and lead to bug tracking nightmares.&lt;/p&gt;

&lt;p&gt;To solve this, I implemented a custom rounding helper that handles precision dynamically based on the input magnitude. For standard everyday measurements, it trims to a clean decimal place, but preserves significant digits for very small scientific values, ensuring accuracy without cluttering the screen with trailing zeros.&lt;/p&gt;

&lt;p&gt;Another challenge was creating the conversion grid. Instead of making the user select 'From' and 'To' drop-downs every time, I wanted them to type a value once and see it converted to all related units instantly. Building a highly responsive grid layout that handles dozens of dynamic updates without triggering massive browser repaints required careful DOM manipulation and CSS Grid optimization. I had to ensure that the layout remains stable even when swapping between currency lists and scientific units.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lessons Learned
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Keep utilities client-side&lt;/strong&gt;: Whenever possible, compute locally. It is faster for the user, eliminates API latency, and makes hosting simple and cheap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prioritize input flow&lt;/strong&gt;: If a user has to click three times before they can start typing a number, the UI has failed. Focus should immediately land on the active input field.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Say no to ads for utility apps&lt;/strong&gt;: The modern web is currently cluttered with ads. Building something clean and free is a differentiator that builds genuine user trust.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSS variables are powerful&lt;/strong&gt;: Using CSS variables allowed me to implement theme switching and responsive layout adjustments with minimal JavaScript intervention.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you are a developer, student, or engineer who frequently jumps between metrics, you can try it out directly at &lt;a href="https://convertease.getinfotoyou.com" rel="noopener noreferrer"&gt;https://convertease.getinfotoyou.com&lt;/a&gt;. I would love to hear your feedback on how to make it even more helpful for your daily workflow, or what unit categories you would like to see added next.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>showdev</category>
      <category>javascript</category>
      <category>productivity</category>
    </item>
    <item>
      <title>I Was Tired of Bloated Typing Tests, So I Built a Vanilla JS Alternative</title>
      <dc:creator>Getinfo Toyou</dc:creator>
      <pubDate>Fri, 10 Jul 2026 14:30:21 +0000</pubDate>
      <link>https://dev.to/getinfotoyou/i-was-tired-of-bloated-typing-tests-so-i-built-a-vanilla-js-alternative-212j</link>
      <guid>https://dev.to/getinfotoyou/i-was-tired-of-bloated-typing-tests-so-i-built-a-vanilla-js-alternative-212j</guid>
      <description>&lt;p&gt;Have you ever sat down to write code or draft an email, only to feel like your fingers couldn't keep up with your brain? Or worse, you decide to quickly check your typing speed, search for a typing test, and end up on a page covered in banner ads, cookie consent prompts, and demands to create an account just to see your results?&lt;/p&gt;

&lt;p&gt;It is a common frustration. A simple tool that should take sixty seconds to use shouldn't require navigating a minefield of modern web bloat. I wanted a typing test that was clean, fast, and completely out of the way. When I couldn't find one that fit the bill without loading megabytes of scripts, I decided to build my own: &lt;a href="https://turbotypingtest.getinfotoyou.com" rel="noopener noreferrer"&gt;TurboTypingTest&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why I Built It
&lt;/h3&gt;

&lt;p&gt;As developers, keyboard comfort is directly tied to our daily productivity. We spend hours typing, and minor improvements in speed or accuracy accumulate over time. When I wanted to practice, I wanted to open a tab, hit a key, and start typing. No onboarding flow, no profile setup, and no flashy animations that make my laptop fan spin up.&lt;/p&gt;

&lt;p&gt;My goal was to create a tool focused entirely on the core utility: measuring raw words per minute (WPM) and accuracy in real-time, with a clean and distraction-free interface.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Tech Stack
&lt;/h3&gt;

&lt;p&gt;I chose a minimalist stack to keep the page load time under 100 milliseconds:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;HTML5&lt;/strong&gt;: For semantic layout.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vanilla CSS&lt;/strong&gt;: A responsive, dark-first layout with smooth transitions and subtle micro-interactions to make the typing experience feel tactile and responsive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vanilla JavaScript&lt;/strong&gt;: For the typing logic, timer management, and real-time statistics calculation.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By avoiding frameworks like React or Vue, I kept the bundle size to a few kilobytes. The app does not need a virtual DOM or complex state management libraries to track character inputs, and the performance benefit is noticeable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Technical Challenges and Solutions
&lt;/h3&gt;

&lt;p&gt;Building a typing test seems simple on the surface, but rendering text updates dynamically on every keystroke presents a few interesting challenges.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Efficient Character Tracking
&lt;/h4&gt;

&lt;p&gt;At first, I tried re-rendering the entire text block whenever the user typed a letter. However, this caused tiny micro-stutters, especially on mobile devices or older machines.&lt;/p&gt;

&lt;p&gt;To solve this, I parsed the test text into individual &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; elements for each character during the initial load. When a user types, the application only updates the CSS classes of the current character and the next character. By targeting only the specific DOM nodes that change, the update cycles are incredibly fast and memory usage remains minimal.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Accurate WPM Calculation
&lt;/h4&gt;

&lt;p&gt;Calculating WPM isn't just about counting words. A standard "word" in typing metrics is defined as 5 characters (including spaces). The formula I implemented is:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;WPM = (Total Typed Characters / 5) / (Time Elapsed in Minutes)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To prevent skewed metrics during the first few seconds, the timer only starts on the very first keystroke. Real-time feedback updates the WPM and accuracy percentage on every character typed, giving users an instant representation of their current pace.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Responsive Text Wrapping
&lt;/h4&gt;

&lt;p&gt;Managing the cursor position across multiple lines of wrapping text can be tricky. Using absolute positioning for the cursor indicator often breaks when the browser window is resized. I resolved this by utilizing CSS grid and inline-block layout rules to let the cursor flow naturally with the text, combined with simple JS boundary checks to scroll the text container when the user moves to a new line.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lessons Learned
&lt;/h3&gt;

&lt;p&gt;Building TurboTypingTest reminded me of the power of simplicity. In a web ecosystem dominated by heavy frameworks, vanilla JavaScript is still incredibly capable. For single-purpose utility tools, skipping the framework overhead leads to a better user experience.&lt;/p&gt;

&lt;p&gt;If you are looking to test your keyboard speed or just want to squeeze in a quick practice session between compiling builds, give it a run. You can try the tool directly at &lt;a href="https://turbotypingtest.getinfotoyou.com" rel="noopener noreferrer"&gt;turbotypingtest.getinfotoyou.com&lt;/a&gt;. Let me know your speed in the comments, and if you have any feedback on the typing physics!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Overcoming Decision Paralysis: Building a Zero-Signup Activity Engine with Vanilla JS</title>
      <dc:creator>Getinfo Toyou</dc:creator>
      <pubDate>Mon, 06 Jul 2026 14:30:28 +0000</pubDate>
      <link>https://dev.to/getinfotoyou/overcoming-decision-paralysis-building-a-zero-signup-activity-engine-with-vanilla-js-gin</link>
      <guid>https://dev.to/getinfotoyou/overcoming-decision-paralysis-building-a-zero-signup-activity-engine-with-vanilla-js-gin</guid>
      <description>&lt;p&gt;We have all experienced those moments where we have free time, open our phone or laptop, scroll through feeds for twenty minutes, and still feel completely bored. It is rarely a lack of available options—it is decision paralysis. When everything is accessible at once, choosing a single activity becomes surprisingly exhausting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why I Built It
&lt;/h3&gt;

&lt;p&gt;I wanted to build a practical tool to solve this exact loop. Most modern web applications try to maximize user retention by keeping people glued to a feed. I wanted to build the opposite: an instant, friction-free tool that gives you a single, concrete idea—a quick creative challenge, a physical task, or a mini learning project—and helps you move on to doing something active.&lt;/p&gt;

&lt;p&gt;Key requirements from day one were zero friction: no user accounts, no onboarding flows, no tracking cookies, and no paywalls. You open the page, press a button, and get a realistic activity idea immediately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tech Stack
&lt;/h3&gt;

&lt;p&gt;To keep performance high and maintainability simple, I chose a minimal stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTML5 &amp;amp; Vanilla CSS&lt;/strong&gt;: Designed with custom properties for rapid dark mode switching, standard CSS Grid layouts, and subtle CSS transitions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vanilla JavaScript (ES6+)&lt;/strong&gt;: Pure client-side logic without full framework overhead, keeping the entire application bundle under 45KB.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web Storage API&lt;/strong&gt;: Utilized &lt;code&gt;localStorage&lt;/code&gt; to save user preferences, custom activity history, and bookmark favorites without requiring a backend database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Static Site Hosting&lt;/strong&gt;: Deployed via static distribution for sub-second global page loads.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Technical Challenges
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Preventing Duplicate Suggestions Without User Accounts
&lt;/h4&gt;

&lt;p&gt;Without saving user profiles on a server database, ensuring users do not get the same activity twice in a short session required a client-side solution. I created a lightweight queue algorithm in JavaScript that maintains a rolling history buffer in &lt;code&gt;localStorage&lt;/code&gt;. Each time a random suggestion is generated, the algorithm checks the buffer history, filters out recently presented IDs, and updates the queue dynamically.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Schema Design and Filtering Performance
&lt;/h4&gt;

&lt;p&gt;A boredom cure is only effective if suggestions match a user's current situation (e.g., indoor vs. outdoor, solo vs. group, low effort vs. active). I structured the dataset using a clean JSON schema with category tags, difficulty markers, and estimated time commitments. Filtering these attributes in real time on the client side ensures instant UI updates without network latency.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Low-Latency Performance Optimization
&lt;/h4&gt;

&lt;p&gt;When a user is bored, even a two-second load screen can cause them to abandon the site and go back to passive scrolling. By avoiding external UI libraries and heavy JavaScript runtimes, the initial load time is nearly instantaneous even on slow mobile networks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lessons Learned
&lt;/h3&gt;

&lt;p&gt;Building this project reinforced an important lesson: not every web application needs a backend database, OAuth authentication, or a full frontend framework. Stripping away non-essential architecture often results in a faster, more reliable, and far more user-friendly tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  Try It Out
&lt;/h3&gt;

&lt;p&gt;If you ever find yourself stuck deciding what to do next, you can try the project live at &lt;a href="https://borednomore.getinfotoyou.com" rel="noopener noreferrer"&gt;BoredNoMore&lt;/a&gt;. It is completely free, instant, and requires no registration. I would love to hear any technical feedback or ideas for new activity categories you think should be added!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>showdev</category>
      <category>buildinpublic</category>
    </item>
    <item>
      <title>Building a Zero-Cost, High-Performance Runner Game for the Browser</title>
      <dc:creator>Getinfo Toyou</dc:creator>
      <pubDate>Wed, 01 Jul 2026 14:30:40 +0000</pubDate>
      <link>https://dev.to/getinfotoyou/building-a-zero-cost-high-performance-runner-game-for-the-browser-41m5</link>
      <guid>https://dev.to/getinfotoyou/building-a-zero-cost-high-performance-runner-game-for-the-browser-41m5</guid>
      <description>&lt;h1&gt;
  
  
  Building a Zero-Cost, High-Performance Runner Game for the Browser
&lt;/h1&gt;

&lt;p&gt;Modern gaming often comes with a hidden tax. Even when a game is labeled "free-to-play," you are usually greeted by multi-gigabyte downloads, intrusive registration forms, pay-to-win mechanics, or aggressive advertisements. As a developer and a casual gamer, I missed the simplicity of the early web: clicking a link and instantly playing a game.&lt;/p&gt;

&lt;p&gt;That is why I built Echo Runner, a fast-paced browser runner game where you run, dodge obstacles, and chase high scores. It is completely free, runs directly in your browser, and requires no downloads or sign-ups. You can play it right now at &lt;a href="https://echorunner.getinfotoyou.com" rel="noopener noreferrer"&gt;https://echorunner.getinfotoyou.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is how I designed and engineered this game with a strict budget of zero dollars for both myself and the player.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Goal: High Performance on a Free Tier
&lt;/h2&gt;

&lt;p&gt;My primary challenge was infrastructure. I wanted to host the game without recurring server costs, meaning I had to rely on free static hosting. However, free hosting plans have limits on bandwidth. If the game assets were too large, a sudden surge in traffic would quickly exhaust my free tier allocation.&lt;/p&gt;

&lt;p&gt;To solve this, I set a strict budget for the initial load size: under 100 KB total.&lt;/p&gt;

&lt;p&gt;By avoiding heavy game engines like Unity or Phaser, I kept the codebase lean. I built the entire game engine using native HTML5 Canvas and vanilla JavaScript. By writing custom physics, collision detection, and rendering loops from scratch, I eliminated external dependencies. The entire production build—including code, styling, and sound effects—comes in at just under 75 KB.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical Challenges
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Achieving 60 FPS with Canvas
&lt;/h3&gt;

&lt;p&gt;Creating a smooth, responsive runner game requires consistent frame rates. Since the game is targeting mobile browsers alongside desktop, I had to optimize the render loop.&lt;/p&gt;

&lt;p&gt;Instead of constantly recreating objects in memory (which triggers the JavaScript garbage collector and causes stuttering), I implemented an object pool pattern. Obstacles and background elements are recycled. When an obstacle moves off-screen, it is deactivated and placed back into the pool to be reused later. This keeps memory usage completely flat during gameplay.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Resolution-Independent Rendering
&lt;/h3&gt;

&lt;p&gt;Browser games are played on everything from high-resolution desktop monitors to low-end smartphones. To handle this variability, I structured the game logic around a virtual resolution (e.g., 800x450). The game logic updates using these fixed coordinates, while the canvas scales dynamically to fit the viewport.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;resizeCanvas&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scaleX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerWidth&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;virtualWidth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scaleY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHeight&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;virtualHeight&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scaleToFit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scaleX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;scaleY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;virtualWidth&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;scaleToFit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;virtualHeight&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;scaleToFit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scaleToFit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;scaleToFit&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;This approach guarantees that the gameplay area remains consistent across devices, ensuring a fair challenge for all players regardless of their screen size.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Graphics &amp;amp; Logic&lt;/strong&gt;: Vanilla HTML5 Canvas and JavaScript. No external rendering libraries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Styling&lt;/strong&gt;: Minimal, responsive CSS using modern flexbox to center the game canvas and style the UI menus.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audio&lt;/strong&gt;: Web Audio API to synthesize sound effects programmatically, eliminating the need to load external MP3 or WAV files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment&lt;/strong&gt;: Static hosting via GitHub Pages, utilizing a global CDN to deliver the game assets instantly to users worldwide.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;p&gt;Building Echo Runner taught me that constraint breeds creativity. When you cannot rely on a pre-built engine to handle physics or rendering, you are forced to understand how these systems work under the hood.&lt;/p&gt;

&lt;p&gt;Furthermore, optimizing for low bandwidth and hosting efficiency directly translates to a better user experience. Players do not have to wait for a loading screen or download an app from an app store. They just visit the site and start playing.&lt;/p&gt;

&lt;p&gt;If you are looking for a quick distraction or want to see how the performance holds up, head over to &lt;a href="https://echorunner.getinfotoyou.com" rel="noopener noreferrer"&gt;https://echorunner.getinfotoyou.com&lt;/a&gt; and try to beat the high score. It won't cost you a thing.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>gamedev</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I Built a Random Wheel Spinner and Learned That Simple Tools Are the Hardest to Get Right</title>
      <dc:creator>Getinfo Toyou</dc:creator>
      <pubDate>Fri, 26 Jun 2026 16:48:42 +0000</pubDate>
      <link>https://dev.to/getinfotoyou/i-built-a-random-wheel-spinner-and-learned-that-simple-tools-are-the-hardest-to-get-right-hih</link>
      <guid>https://dev.to/getinfotoyou/i-built-a-random-wheel-spinner-and-learned-that-simple-tools-are-the-hardest-to-get-right-hih</guid>
      <description>&lt;h2&gt;
  
  
  The Itch I Needed to Scratch
&lt;/h2&gt;

&lt;p&gt;Every few weeks, someone in a group chat would ask: "How do we decide?" Movie night. Who pays. Which game to play next. And every time, we'd spend more time arguing about &lt;em&gt;how&lt;/em&gt; to decide than actually deciding.&lt;/p&gt;

&lt;p&gt;I wanted something dead simple. Paste in some options, spin, done. But every tool I found either required an account, threw ads at you, or had so many settings you needed a tutorial. So I built &lt;a href="https://spindecide.getinfotoyou.com" rel="noopener noreferrer"&gt;SpinDecide&lt;/a&gt; — a free, no-login random wheel spinner that just works.&lt;/p&gt;

&lt;p&gt;This post is about why "just works" is deceptively hard to build.&lt;/p&gt;




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

&lt;p&gt;I kept it deliberately lean:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vanilla HTML, CSS, and JavaScript&lt;/strong&gt; — no framework overhead&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Canvas API&lt;/strong&gt; for rendering and animating the wheel&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSS transitions&lt;/strong&gt; for UI polish&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployed as a static site&lt;/strong&gt; — fast, cheap, no server costs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No React. No build pipeline. No dependencies to maintain. The goal was that anyone could open the source and understand it in under ten minutes.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Technical Challenges (Yes, Even a Spinner Has Them)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Making the Spin Feel Real
&lt;/h3&gt;

&lt;p&gt;A wheel that stops abruptly feels broken. A wheel that always decelerates the same way feels fake. Getting the easing curve right took more iteration than I expected.&lt;/p&gt;

&lt;p&gt;I ended up using a custom cubic-bezier-style deceleration applied to the rotation delta per frame. The key insight: the &lt;em&gt;perception&lt;/em&gt; of randomness matters as much as actual randomness. If the wheel always stops in roughly the same quadrant, users notice — even if the math is correct. I added a random offset to the final resting position so it never felt predictable.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Label Rendering on Canvas
&lt;/h3&gt;

&lt;p&gt;Canvas text doesn't wrap. If someone adds a long option like "Hawaiian pizza (controversial but valid)", you either truncate it, shrink the font, or let it overflow the segment.&lt;/p&gt;

&lt;p&gt;I implemented dynamic font sizing: measure the text width, compare it to the segment arc length at a given radius, and scale down if needed. It's not perfect for extreme edge cases, but it handles 95% of real-world inputs gracefully without any user intervention.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Segment Color Distribution
&lt;/h3&gt;

&lt;p&gt;With fewer than 6 options, a fixed color palette works fine. With 20 options, you need to auto-generate colors that are visually distinct and don't accidentally repeat next to each other.&lt;/p&gt;

&lt;p&gt;I went with HSL color generation — evenly distributed hue values with slight saturation/lightness variation. Adjacent segments get hues far apart on the wheel. Simple, and it looks good across all segment counts.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. State Management Without a Framework
&lt;/h3&gt;

&lt;p&gt;With no framework, managing app state — the list of options, spin history, current result — means discipline. I used a single &lt;code&gt;appState&lt;/code&gt; object and explicit update functions. Boring, but it made debugging easy and the code readable six months later.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Simplicity is a product decision, not just a technical one.&lt;/strong&gt; Every feature I considered adding (weighted options, saved wheels, user accounts) would have made the tool slightly more powerful and significantly more complicated. I cut most of them. The constraint made the product better.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Canvas is powerful but verbose.&lt;/strong&gt; For a project like this it's the right call — no library weight, full control. But I wrote a lot of boilerplate I'd abstract into helpers on the next project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Small tools still need good UX copy.&lt;/strong&gt; The button says "Spin!" not "Submit" or "Randomize." The result shows up big and bold. These tiny decisions took real thought.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deployment friction kills momentum.&lt;/strong&gt; Static hosting meant I could push changes and see them live in seconds. That speed kept me motivated to iterate.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;If you've got a group that can't decide on anything, or you're a teacher who needs a random name picker, or you're settling a debate the civilized way — give it a spin:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://spindecide.getinfotoyou.com" rel="noopener noreferrer"&gt;spindecide.getinfotoyou.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No account. No ads in your face. Just add your options and spin.&lt;/p&gt;




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

&lt;p&gt;Building something simple taught me more about product thinking than any complex project has. When you strip away the features, what's left has to actually work — and work well. The wheel spins, a winner appears, someone loses the argument about pineapple on pizza.&lt;/p&gt;

&lt;p&gt;That's the whole product. And getting that right took real effort.&lt;/p&gt;

&lt;p&gt;If you're building small tools, I'd love to hear what you're working on in the comments.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>showdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Who Actually Uses ASCII Art in 2024? (And Why I Built a Browser Tool for Them)</title>
      <dc:creator>Getinfo Toyou</dc:creator>
      <pubDate>Wed, 24 Jun 2026 14:31:33 +0000</pubDate>
      <link>https://dev.to/getinfotoyou/who-actually-uses-ascii-art-in-2024-and-why-i-built-a-browser-tool-for-them-23dg</link>
      <guid>https://dev.to/getinfotoyou/who-actually-uses-ascii-art-in-2024-and-why-i-built-a-browser-tool-for-them-23dg</guid>
      <description>&lt;h2&gt;
  
  
  The Niche That Kept Asking
&lt;/h2&gt;

&lt;p&gt;I never planned to build an ASCII art generator. But after watching the same three groups of people repeatedly struggle with clunky desktop software or sketchy upload-your-image sites, I figured someone should just solve it properly. That someone ended up being me.&lt;/p&gt;

&lt;p&gt;The result is &lt;a href="https://asciiartmaster.getinfotoyou.com" rel="noopener noreferrer"&gt;Asciiartmaster&lt;/a&gt; — a free, browser-based converter that transforms images and text into customizable ASCII art without sending a single byte to a server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Actually Benefits Most
&lt;/h2&gt;

&lt;p&gt;Before I talk tech, let me be specific about who this tool is genuinely for, because it's not everyone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Developers&lt;/strong&gt; are probably the heaviest users. If you've ever wanted a text-based logo for your CLI tool's startup banner, a README header that doesn't need an image asset, or retro-styled output for a terminal app, you've probably cobbled something together with a Python script or an npm package. This replaces that workflow with something you can use in 30 seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Digital artists&lt;/strong&gt; working in demoscene aesthetics, pixel art adjacent spaces, or generative art often want to experiment with character-based rendering. Having a fast feedback loop in the browser matters here — you want to tweak density settings and character sets without rerunning a script.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Retro tech enthusiasts&lt;/strong&gt; are the most enthusiastic users. These are the people setting up BBS emulators for fun, adding ANSI art to their dotfiles, or just deeply appreciating that terminals used to be the entire visual interface. They get it immediately.&lt;/p&gt;

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

&lt;p&gt;The core challenge was doing meaningful image processing entirely client-side, without a backend, without WebAssembly initially, and without the conversion feeling sluggish.&lt;/p&gt;

&lt;p&gt;The approach uses the HTML5 Canvas API heavily. When you load an image, it gets drawn to an off-screen canvas, and then I sample pixel luminance values across a grid. Each cell maps to a character from a density string — traditionally something like &lt;code&gt;.:-=+*#%@&lt;/code&gt; ordered from least to most opaque. The character chosen for each grid cell depends on how bright that region of the image is.&lt;/p&gt;

&lt;p&gt;The tricky part was getting the sampling grid right. Go too coarse and you lose detail. Go too fine and the output becomes unreadable noise. The solution was making the character density and output width configurable, letting users tune the balance for their specific image.&lt;/p&gt;

&lt;p&gt;For text-to-ASCII (the big blocky letter mode), I used a different approach — mapping each letter to a pre-defined multi-line character pattern, then assembling them horizontally with proper baseline alignment. Sounds simple, but handling variable character widths and spacing without everything going jagged took more iteration than expected.&lt;/p&gt;

&lt;p&gt;The stack is deliberately minimal: vanilla JavaScript, Canvas API, and CSS. No frameworks. No build step. The whole thing loads instantly because there's nothing to bundle.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Privacy Decision Was Non-Negotiable
&lt;/h2&gt;

&lt;p&gt;A lot of similar tools ask you to upload your image to their server. That's fine for stock photos, but people routinely want to convert screenshots, internal diagrams, or personal photos. Sending those to a third party for processing is a reasonable thing to want to avoid.&lt;/p&gt;

&lt;p&gt;Doing everything in the browser eliminates that concern entirely. The image never leaves your machine. This wasn't a marketing angle I bolted on afterward — it was a constraint I set before writing the first line of code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Browser APIs are more capable than you remember.&lt;/strong&gt; Canvas-based image manipulation used to feel like a workaround. Now it feels like the right tool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configurability matters more than defaults.&lt;/strong&gt; The first version had fixed output width and a single character set. Half the feedback I got was people wanting to control those things. The current version lets you adjust both, and the tool feels significantly more useful as a result.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Simple" tools have non-obvious edge cases.&lt;/strong&gt; Transparent PNG backgrounds, very dark images, very light images, images with thin line detail — each of these required specific handling to produce readable output.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;If any of those three groups sound like you, &lt;a href="https://asciiartmaster.getinfotoyou.com" rel="noopener noreferrer"&gt;Asciiartmaster&lt;/a&gt; is free, runs entirely in your browser, and takes about ten seconds to get your first result out.&lt;/p&gt;

&lt;p&gt;If you're a developer and end up using it for a README or CLI banner, I'd genuinely like to see what you make with it.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>devtools</category>
    </item>
    <item>
      <title>Building a Lightweight Tech &amp; Online Safety Guide for India's Next Billion Users</title>
      <dc:creator>Getinfo Toyou</dc:creator>
      <pubDate>Mon, 22 Jun 2026 14:30:55 +0000</pubDate>
      <link>https://dev.to/getinfotoyou/building-a-lightweight-tech-online-safety-guide-for-indias-next-billion-users-jh5</link>
      <guid>https://dev.to/getinfotoyou/building-a-lightweight-tech-online-safety-guide-for-indias-next-billion-users-jh5</guid>
      <description>&lt;p&gt;India's digital growth over the last decade has been rapid. Millions of people, from students in small towns to grandparents in cities, have gained access to the internet. However, this swift onboarding has created a significant gap: digital literacy hasn't grown at the same pace as digital access. Every day, people are targeted by UPI scams, fake job offers, phishing links, and AI-generated misinformation.&lt;/p&gt;

&lt;p&gt;Most technology websites focus on hardware reviews, smartphone comparisons, or high-end developer news. There is a lack of simple, direct resources that focus on digital safety and foundational technology concepts for everyday users. That is why I built Tech, a platform designed to bridge this gap.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Core Problem
&lt;/h3&gt;

&lt;p&gt;When my own relatives started receiving fraudulent text messages mimicking bank alerts, I realized how vulnerable the average user is. They don't need to know the clock speed of the latest processor; they need to know how to spot a fake website or how to verify a UPI request.&lt;/p&gt;

&lt;p&gt;With the sudden rise of artificial intelligence, there is also a mix of curiosity and fear. People want to use AI tools for learning and work, but they don't know where to start or how to navigate these platforms safely. The main goal of Tech is to provide clear, jargon-free explainers on AI tools, timely scam alerts, and relevant tech news that directly impacts daily life.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Tech Stack and Architecture
&lt;/h3&gt;

&lt;p&gt;To build a platform aimed at a wide audience across India, performance and accessibility were the primary technical goals. Many users access the web on budget smartphones with unstable 3G or 4G connections.&lt;/p&gt;

&lt;p&gt;Here is the stack I chose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Frontend&lt;/strong&gt;: Next.js with static site generation (SSG). This ensures pages are pre-rendered and load almost instantly, even on poor connections.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Styling&lt;/strong&gt;: Pure CSS with a mobile-first design pattern. I avoided heavy UI libraries to keep the bundle size as small as possible.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Content Management&lt;/strong&gt;: Markdown-based files stored in the repository. This allows for quick edits and version control without the overhead of querying a database for every page load.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Hosting &amp;amp; CDN&lt;/strong&gt;: Vercel combined with global edge caching to ensure low latency across different regions in India.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Technical Challenges
&lt;/h3&gt;

&lt;p&gt;The biggest technical challenge was optimizing the page weight. Every kilobyte of Javascript deferred is a win for a user on a low-end device. I spent a significant amount of time audit-profiling the site, removing unnecessary dependencies, and lazy-loading non-critical resources.&lt;/p&gt;

&lt;p&gt;Another challenge was designing a layout that remains highly readable on small, low-resolution screens. I implemented scalable typography using CSS container queries and custom properties, ensuring that text is legible even on older smartphone models.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lessons Learned
&lt;/h3&gt;

&lt;p&gt;Building this site taught me that technical complexity is not always the answer. When building for the next billion users, simplicity in both code and design is the most critical feature.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Performance is accessibility&lt;/strong&gt;: If a safety warning page takes ten seconds to load on a slow connection, it fails its purpose. Speed is a functional requirement, not just a metric.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Jargon-free writing is hard&lt;/strong&gt;: Translating complex terms like "phishing" or "generative adversarial networks" into straightforward terms requires deep understanding. The UX must support this simplicity.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Try it out
&lt;/h3&gt;

&lt;p&gt;The website is fully live and open to everyone. You can explore the explainers and active alerts at &lt;a href="https://tech.getinfotoyou.com" rel="noopener noreferrer"&gt;https://tech.getinfotoyou.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you have feedback on how to make the content more accessible, or if you want to suggest a topic that needs a simple explainer, I would love to hear your thoughts in the comments.&lt;/p&gt;

</description>
      <category>security</category>
      <category>webdev</category>
      <category>a11y</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>I Built an AI Text Detector from Scratch — Here's What I Learned About Doing It the Hard Way First</title>
      <dc:creator>Getinfo Toyou</dc:creator>
      <pubDate>Fri, 19 Jun 2026 14:31:12 +0000</pubDate>
      <link>https://dev.to/getinfotoyou/i-built-an-ai-text-detector-from-scratch-heres-what-i-learned-about-doing-it-the-hard-way-first-1p09</link>
      <guid>https://dev.to/getinfotoyou/i-built-an-ai-text-detector-from-scratch-heres-what-i-learned-about-doing-it-the-hard-way-first-1p09</guid>
      <description>&lt;h2&gt;
  
  
  The Hard Way
&lt;/h2&gt;

&lt;p&gt;Before I shipped &lt;a href="https://aidetector.getinfotoyou.com" rel="noopener noreferrer"&gt;Aidetector&lt;/a&gt;, I spent two weeks doing AI detection &lt;em&gt;manually&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I'm not joking. A client asked me to review a batch of blog posts for AI-generated content, and I had no reliable free tool. So I did what any developer does when they're stubborn and slightly overconfident — I started reading papers.&lt;/p&gt;

&lt;p&gt;I pulled research on AI writing patterns. I opened a spreadsheet. I flagged things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sentence length variance (AI texts are suspiciously uniform)&lt;/li&gt;
&lt;li&gt;Overuse of hedging language ("it is important to note that...")&lt;/li&gt;
&lt;li&gt;Low lexical diversity in paragraph transitions&lt;/li&gt;
&lt;li&gt;Predictable semantic structure — topic sentence, three supporting points, wrap-up&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I was manually scoring documents on a 12-point rubric. It took me about 20 minutes per article. For 40 articles.&lt;/p&gt;

&lt;p&gt;That's when I thought: &lt;em&gt;this should be a tool.&lt;/em&gt;&lt;/p&gt;




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

&lt;p&gt;Most free AI detectors at the time were either:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Capped at 500 words (useless for long-form content)&lt;/li&gt;
&lt;li&gt;Requiring signup or API keys&lt;/li&gt;
&lt;li&gt;Running on a single heuristic with no transparency about what they were actually checking&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I wanted something that ran entirely in the browser, explained its reasoning, supported recent models like GPT-5 and Claude 3.7, and had zero word limits. No backend. No user data. No nonsense.&lt;/p&gt;




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

&lt;p&gt;The entire thing runs client-side:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vanilla JavaScript&lt;/strong&gt; — no framework overhead, just fast DOM manipulation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTML/CSS&lt;/strong&gt; — keeping it lightweight and accessible&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No external APIs&lt;/strong&gt; — everything is computed locally in the browser&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The detection logic runs 12 linguistic pattern checks derived from published NLP research. These include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Burstiness score (variance in sentence lengths)
- Perplexity approximation (word predictability heuristics)
- Hedging phrase frequency
- Passive voice ratio
- Transition word overuse
- Semantic flatness (paragraph topic variance)
... and six more
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each check returns a weighted score. The final result is a composite confidence percentage, broken down so the user can actually see &lt;em&gt;why&lt;/em&gt; the tool flagged something.&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;1. Approximating perplexity without an LLM&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;True perplexity requires a language model to score token probabilities. I don't have a backend, so I approximated it using a trigram frequency lookup built from a curated corpus. It's not perfect, but it's directionally accurate for the patterns I care about.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Avoiding false positives on technical writing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Technical documentation naturally has low sentence variance and formal structure — exactly what my detector was flagging as AI. I had to add a context-aware exemption layer that detects domain-specific vocabulary density and adjusts scoring accordingly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Keeping up with new models&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;GPT-5 and Claude 3.7 write noticeably differently than earlier models. I had to collect new sample sets and re-weight several heuristics. This is an ongoing calibration problem — the patterns shift as models improve.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Doing it the hard way first was actually useful.&lt;/strong&gt; Building a manual rubric before automating it forced me to understand the problem domain deeply. I wasn't just wiring up someone else's API — I actually knew what I was detecting and why.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Transparency builds trust.&lt;/strong&gt; Showing users which patterns triggered and why has been the most-praised feature. People don't want a black box percentage. They want to understand the reasoning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No-login tools get used.&lt;/strong&gt; Friction kills adoption. Removing signup entirely meant people actually came back and shared it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Browser-only is a genuine constraint, not just a gimmick.&lt;/strong&gt; You have to think carefully about what's computationally feasible without a server. Some things I wanted to add (real perplexity scoring, model fine-tuning) are simply not possible client-side at scale.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;If you're an educator reviewing student submissions, a content editor checking freelance work, or just curious how your own writing scores — give it a shot: &lt;a href="https://aidetector.getinfotoyou.com" rel="noopener noreferrer"&gt;aidetector.getinfotoyou.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No word limits. No login. No API key. Paste your text and see what it finds.&lt;/p&gt;

&lt;p&gt;I'm still actively improving the heuristics. If you find a false positive or a miss, I'd genuinely like to know.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
