A map of your own · the prompt
Build it yourself
A prompt to give your own AI, so it builds this map for you.
You don’t need to read the prompt below. Copy it and give it to your own AI, and it will build the map with you. It’s written for the AI, so it’s technical on purpose.
The map keeps the places where you catch your breath, finds one when you need it, and never sends anything off your phone. Take it, change it, and make it yours.
The prompt is a declaration. It tells your AI what to build, and what it must never do.
Build a map app for one person's own neighbourhood. It records the small places where they go to catch their breath, which it calls sanctuaries, and it finds one when they need it. It works offline, and everything stays on their device.
Build it in these six parts.
1. A database that is a file
Use SQLite in the browser, through wa-sqlite or sql.js with an OPFS backend. It is one file the person can export, copy to a USB stick, or delete. No account exists.
2. A page that opens with nothing behind it
Make it a static progressive web app. Add a manifest with display set to standalone, and a service worker that caches the shell so the app opens in flight mode. Fetch nothing at start-up.
3. A position, used and discarded
Read the position with navigator.geolocation.getCurrentPosition at the moment the person asks, and never write it anywhere. Compute the bounding box for the search from it, then throw both away.
4. Capture that takes five seconds
Build one screen for logging a spot: a name, three sliders and two toggles. Logging a spot must take less time than sitting down on it, or nobody will log anything and the map stays empty.
5. A backup the person can hold
Let the person export the .sqlite file. That is the whole backup.
6. Nothing else
Do not add a sync service, an account, a share button or a feed. Each one turns a private map into a public one.
Create the database with this schema. It has three tables: a place, what that place is like, and what it was like each time the person went. Keep the third one. It is what makes the map get better instead of just longer.
-- One file. This is the whole database.
CREATE TABLE sanctuaries (
id TEXT PRIMARY KEY, -- uuid, so two devices never collide
latitude REAL NOT NULL,
longitude REAL NOT NULL,
name TEXT,
created_at INTEGER NOT NULL
);
CREATE TABLE profiles (
id TEXT PRIMARY KEY,
sanctuary_id TEXT NOT NULL,
noise_level INTEGER, -- 1 silent .. 5 traffic
visual_privacy INTEGER, -- 1 exposed .. 5 hidden
foot_traffic INTEGER,
sun_exposure TEXT,
wind_block BOOLEAN,
ground_condition TEXT,
has_seating BOOLEAN,
seating_quality INTEGER,
FOREIGN KEY (sanctuary_id) REFERENCES sanctuaries(id)
);
CREATE TABLE visits (
id TEXT PRIMARY KEY,
sanctuary_id TEXT NOT NULL,
visited_at INTEGER NOT NULL,
season TEXT,
time_of_day TEXT,
note TEXT,
FOREIGN KEY (sanctuary_id) REFERENCES sanctuaries(id)
);
CREATE INDEX idx_lat_lon ON sanctuaries(latitude, longitude);
To find a place, search for sanctuaries with a noise level of 2 or under and a visual privacy of 4 or over, inside a box around where the person is standing, and sort the results by distance on the device. Use this query, and fill :lat and :lon from the position and :d from the size of the box:
-- Low noise and high visual privacy, inside a box around the person.
SELECT s.name, s.latitude, s.longitude
FROM sanctuaries s
JOIN profiles p ON p.sanctuary_id = s.id
WHERE p.noise_level <= 2
AND p.visual_privacy >= 4
AND s.latitude BETWEEN :lat - :d AND :lat + :d
AND s.longitude BETWEEN :lon - :d AND :lon + :d;
The query does not sort. Work out the distance to each result in the app, and sort by it there.