Friday, 29 May 2026

CNCB News

International News Portal

She had a baby, tried AI coding, and built the nutrition app she actually wanted

She had a baby, tried AI coding, and built the nutrition app she actually wanted

Lisa Lin had worked in tech for years, but had never tried coding. When she had her baby, she vibe coded a nutrition app for him.

Lisa Lin

Lisa Lin had long worked alongside coders. When she had her son, she tried it for herself.

The 33-year-old has worked in operations roles at a variety of tech companies, including Uber. But she was "non-technical," as her industry would call it; she couldn't code.

Then came the AI revolution, and her baby. Lin moved from a full-time operations role to a contractor while taking on the new job of stay-at-home mom.

She'd heard horror stories about those early months, but has been pleasantly surprised. "He's a happy baby," she said.

When her baby was about 5 months old, she began testing out nutritional apps to introduce solid foods and identify allergens. She tried a popular nutrition app but found it overwhelming. "Day to day, it's a lot of information to digest," she said.

AI Conversation Embed — Annotated ' ).join(''); root.innerHTML = ` ${p.logo} ${esc(displayName)} ${captionHtml} ${sidebarHtml} `; const msgsEl = document.getElementById('messages'); (cfg.messages || []).forEach((m, i) => { if (m.role === 'divider') { const d = document.createElement('div'); d.className = 'divider'; d.style.transitionDelay = (Math.min(i, 6) * 80) + 'ms'; d.innerHTML = m.label ? '' + esc(m.label) + '' : ''; msgsEl.appendChild(d); return; } const row = document.createElement('div'); row.className = 'msg-row'; row.style.transitionDelay = (Math.min(i, 6) * 80) + 'ms'; row.dataset.index = i; const msgDiv = document.createElement('div'); msgDiv.className = 'msg ' + (m.role === 'user' ? 'user' : 'assistant'); const markerHtml = m._noteNum ? '' + m._noteNum + '' : ''; if (m.image) { const cap = m.caption ? '' + esc(m.caption) + '' : ''; if (m.role === 'user') { msgDiv.innerHTML = '' + '' + esc(m.alt || '') + '' + cap + '' + markerHtml; } else { msgDiv.innerHTML = markerHtml + '' + '' + esc(m.alt || '') + '' + cap + ''; } } else { const bodyHtml = renderText(m.text || ''); if (m.role === 'user') { msgDiv.innerHTML = '' + bodyHtml + '' + markerHtml; } else { msgDiv.innerHTML = markerHtml + '' + bodyHtml + ''; } } row.appendChild(msgDiv); // Inline note for mobile — placed before the annotated message if (m.note) { const inlineNote = document.createElement('div'); inlineNote.className = 'note-inline msg-row'; inlineNote.style.transitionDelay = (Math.min(i, 6) * 80) + 'ms'; inlineNote.innerHTML = esc(m.note); msgsEl.appendChild(inlineNote); } msgsEl.appendChild(row); }); // Animate in const items = msgsEl.querySelectorAll('.msg-row, .divider'); const sideNotes = document.querySelectorAll('.note-sidebar'); if ('IntersectionObserver' in window) { const io = new IntersectionObserver((entries) => { entries.forEach(e => { if (e.isIntersecting) { e.target.classList.add('in'); // Also reveal matching sidebar note const idx = e.target.dataset && e.target.dataset.index; if (idx !== undefined) { const sn = document.querySelector('.note-sidebar[data-for="' + idx + '"]'); if (sn) sn.classList.add('in'); } io.unobserve(e.target); } }); }, { root: msgsEl, threshold: 0.15, rootMargin: '0px 0px -20px 0px' }); items.forEach(el => io.observe(el)); requestAnimationFrame(() => { const cr = msgsEl.getBoundingClientRect(); items.forEach(el => { const r = el.getBoundingClientRect(); if (r.top < cr.bottom && r.bottom > cr.top) { el.classList.add('in'); const idx = el.dataset && el.dataset.index; if (idx !== undefined) { const sn = document.querySelector('.note-sidebar[data-for="' + idx + '"]'); if (sn) sn.classList.add('in'); } io.unobserve(el); } }); }); } else { items.forEach(el => el.classList.add('in')); sideNotes.forEach(el => el.classList.add('in')); } // Show sidebar notes after a short delay setTimeout(() => { document.querySelectorAll('.note-sidebar').forEach(el => el.classList.add('in')); }, 600); function esc(s) { return String(s).replace(/[&<>"']/g, c => ({ '&':'&','<':'<','>':'>','"':'"',"'":''' }[c])); } // Render text with hanging indent on bulleted lines function renderText(s) { const lines = String(s).split('\n'); return lines.map(line => { if (line.trim() === '') { return ' '; } // Detect leading whitespace and bullet character const m = line.match(/^(\s*)([•◦●○\-*])\s+(.*)$/); if (m) { const ws = m[1].length; const depth = ws >= 8 ? 2 : 1; return '' + esc(m[2] + ' ' + m[3]) + ''; } // Indented non-bullet line const indentMatch = line.match(/^(\s+)(.*)$/); if (indentMatch && indentMatch[2]) { return '' + esc(indentMatch[2]) + ''; } return '' + esc(line) + ''; }).join(''); } })();