slopmapp: the map of ai-generated posters in catalonia

do you like ai-generated posters? if not, on slopmapp.cat you can mark where you've seen one.
it's a map i launched in september. you take a photo of the poster, the point lands where you saw it, and the report shows up straight away. each report is a photo and a point on the map, with no scores or rankings of businesses. there's also es.slopmapp.com, in spanish and covering the whole of spain, but it's the same map with the same reports. as of 6 october there were 38, all in catalonia.
which ai-generated posters are on the map
the biggest group is bars, restaurants, cafés and takeaways, 14 of the 32 reports that aren't about institutions. the classification is mine, going by the name and the photo, because a report has no category field. picking one takes time when you're in the street with your phone in your hand, and it changes nothing about how a report is moderated or resolved.
the other 6 are about public institutions:
- in mollerussa, two town council campaigns, one about dog poo and the other about leaving furniture in the street, and a leaflet about scooters. i posted those three myself
- in viladecavalls, the official poster for the festa major, the town's yearly festival. it's the same image as the cover of the programme the council publishes
- at the universitat de lleida, the academic calendar infographic and the poster for an event at the faculty of arts

nowhere does the map say an image is ai-generated. it says someone reported it as ai-generated, because there's no detector behind it. the /guia page (the guide) explains the clues you can see from the pavement, like six fingers or text you can't read, and also that none of them proves it.
a catalogue, not a pillory
the project's vision document has one sentence that decides almost everything about it. the subject is the image, never the owner. a small restaurant that bought a cheap poster from a print shop hasn't done anything wrong, and the map can't make it look as if it has. in practice:
- there are no scores or rankings of the worst businesses.
- red can never colour a business or a report, and that doesn't depend on code review. a lint rule,
no-red-on-business, fails if a map or report component uses a red class. red is kept for destructive actions and form errors. - the business is optional context. the point is where the poster was seen, which isn't always the business's door. since 5 october, if you pick a business and have no other point, the report goes on the business, because most posters are in shop windows. the photo's gps or a point picked on the map always take priority.
- since 20 september you can like a report and take the like back, but it decides nothing. it doesn't change the status or the order of the feed or the map, which stay chronological. the count is public. who gave it isn't.
- a business can dispute a report without an account, at /ets-el-negoci ("are you the business?"). if it disputes that the image is ai-generated, the report is hidden by default. a single point is worth little, and arguing over it costs more.
how the map empties
most maps of bad things only pile up. this one can also empty, and it's the part i thought about most.
anyone with an account can answer «sí, encara hi és» (yes, still there) or «ja no hi és» (no longer there). each person answers once per report, and the answer counts for 90 days. when the «ja no hi és» answers outnumber the «encara hi és» ones by two, the report is resolved. it stays on the map, drawn as resolved, because the map also has to show the posters that have already been taken down.

the comment next to the constant explains why two:
// how far the people saying gone have to outnumber the people saying present
// before a visible entry turns resolved. one person is a mistake or a grudge,
// not a fact about the street; two is the smallest number that is a small
// crowd rather than a single say-so.
export const RESOLUTION_THRESHOLD = 2;
it works both ways. an «encara hi és» after a report is resolved can reopen it, with no moderator involved. two accounts can game it, and that's accepted. the prize is a point drawn as resolved, not deleted, and building defences against that on a map of posters isn't worth it.
a new photo of the same poster counts for more than any answer, and when one arrives, all the earlier answers stop counting. and a report nobody has seen in 90 days reads as expired. that isn't stored anywhere. the api works it out every time it serves the report, from the last date someone saw it, so there's no scheduled job and no state change to undo. the 90-day clock comes from the streetcomplete app and openstreetmap's check_date tag, and the two buttons come from waze.
that's the theory. as of 8 october, none of the 38 reports is resolved, and only one has a «ja no hi és».
the photos, without your home location
phone photos carry the gps position in their metadata. the api doesn't keep the original. it decodes it, rotates it according to its orientation and re-encodes it at 320, 640 and 1,280 pixels, in avif and webp. since it rebuilds the pixels, the exif goes away more reliably than editing it with a library would, and a 4 to 8 mb original can't leak if it doesn't exist. the six versions add up to about 180 kb.
the «on soc ara» (where am i now) button only shows while the photo is recent, within five minutes, so that a draft opened at home hours later doesn't pick up your home location. faces aren't blurred. the upload screen asks you to photograph the poster rather than people, and it's a known limitation. there's no automatic content filter either. you need an account to post, and the moderation queue gets read every day.
knowing where people come from
most visits have come from reddit, and they tend to land on a specific report someone linked there, not on the map. what spreads is the report, often through channels that don't say where the visit came from: a link pasted into whatsapp sends no referrer.
links shared from the map carry utm parameters. without utm_source=share, those visits would show up as direct. the emails i sent to illustrators use a short address, /i, which adds the parameters when it redirects. a link whose visible text leads to a different url has the shape of a phishing email, and filters score it that way.
three bugs that gave no warning
in mid-september, reports sent from iphones arrived empty. webkit stores a Blob in indexeddb as a reference to the file the camera wrote, not as a copy. when ios deletes that file, the record stays and even its size reads correctly, but the content comes back empty. chromium copies the bytes, which is why it didn't fail anywhere i tested it. now the queue stores an ArrayBuffer.
on 1 october i cut the report form down to two screens, the camera and the send screen. up to 3 october, analytics counted three photos added and not a single «envia» (send), when in the two weeks before, 13 reports had been sent from 20 photos. without a point, the button stayed disabled and nothing said why. i made it always clickable, with a message saying what was missing, and on the night of the 4th two iphone sessions pressed it 18 times without ever opening the map. now the button opens the map itself.
every merge to main recreated all the containers, and for a minute the site answered with 5xx errors. on 13 september googlebot hit /cerca (the search page) 48 seconds into one of those windows. coolify doesn't do rolling deploys for a compose service, so now a morning's deploys get folded into the last one. on top of that, the deploy step doesn't count anything as good until /health answers with the sha of the commit it has just built. coolify's webhook replies before recreating anything, and an "is it answering at all" check would have passed against the version being replaced.
what the map doesn't show
most reports are in lleida, 21 of the 38, and i posted 14 of them, 10 in the city of lleida and 4 in mollerussa. the map shows where someone is looking, not where there are more.
the project's first commit, on 6 september, already said the risk wasn't technical but a cold map. a map of catalonia with forty points looks abandoned, and nobody comes back to report into an empty room. a month later, it had 38.