Join Us Tuesday, May 19

When Joe Poynton went to the grocery store, he dutifully worked through his shopping list — before getting to the bottom and realizing he’d passed those items aisles ago.

The things he’d forgotten would taunt him from across the store, forcing him back to produce or pasta. The busy 44-year-old father — he’s worked in the UK fire service for 20 years, where he handles daily emergencies — had resigned himself to suffering this mild inefficiency every time he went shopping.

No more. Poynton has finally fixed his grocery store problem — by building an app to optimize grocery runs based on how you navigate the store.

Poynton is part of a small but growing group of civilian coders: regular people who can solve daily annoyances and inefficiencies with their own hyper-specific programs. It’s a practice called “vibe coding,” and it doesn’t involve programming skills. Poynton, for instance, has never taken a tech course. Instead, users chat with an AI bot like Claude or Lovable and tell it what they want to build — think of it as bossing around your very own eager-to-please programmer.

“I just started by saying, ‘I’m brand new to this, treat me like an idiot. I don’t know a single word of code. This is my vision. What’s the steps that I need to take to get there?'” Poynton said.

To create the app, Poynton bounced between Claude and Gemini, using the two LLMs to troubleshoot each other. He began with a roughly $25 Gemini Pro subscription, which walked him through app development 101.


Poynton has friends, family, and a few folks online sorting their shopping lists with his app.  

Pål Hansen for BI

“I’m now lucky enough to have drifted into that period of life where I’m a little bit older, which means that I’m trying to be a little bit more creative in a whole range of aspects of my life,” Poynton said.

Gemini talked him through each step, detailing what the process might cost and what software he’d need. He learned he’d need XCode, an Apple tool package for app developers, and have Gemini create files in Swift, the coding platform for Apple. His XCode, along with his app previews and icons, would have to go through the app review process before the app could go live.

“It was fun,” Poynton said. “It’s a bit like trying to write a book in a language that you don’t speak, and I’m just doing it through a translator.”

Since Claude had a better reputation for coding, Poynton uploaded his code to a free version and asked for feedback. Claude made tweaks and told him how it would do things differently, and he incorporated the new feedback. Gemini helped him take his iPad drawings from brainstorms into graphics. The entire process, which took place in spurts between work and other obligations, lasted about two to three months.



AI Conversation Embed — Annotated


).join(”);

root.innerHTML = `

`;

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 {
if (m.role === ‘user’) {
msgDiv.innerHTML = ‘

‘ + esc(m.text || ”) + ‘

‘ + markerHtml;
} else {
msgDiv.innerHTML = markerHtml + ‘

‘ + esc(m.text || ”) + ‘

‘;
}
}

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]));
}
})();



Read the full article here

Share.
Leave A Reply