DEV Community

Victor Moni
Victor Moni

Posted on Edited on

Building SP Layers: Exploring São Paulo Through Photography and Cloudinary

São Paulo has many rhythms: busy avenues, street art, food markets, historic buildings, and green spaces tucked between the concrete.

I built SP Layers — São Paulo in Layers as an interactive way to explore those different sides of the city.

Created for the Cloudinary November Mini-Hack: Celebrate Where You're From, the project combines photo stories, small discoveries, and personalized postcards.

🌎 Explore the live app

💻 View the source on GitHub

SP Layers homepage with the São Paulo introduction and a photograph of Liberdade

Exploring the city through its layers

The experience brings together 20 photo stories across four categories:

  • Flavors: food and the encounters around it.
  • Street Art: color and expression in public spaces.
  • Breathing Spaces: places to slow down.
  • City & Memory: architecture and urban history.

Visitors can open stories, choose three places, reorder their selection, and open an outing in Google Maps for walking, driving, or cycling.

The app supports Brazilian Portuguese, English, and Spanish, along with light and dark themes.

SP Layers gallery showing category filters and photo stories about São Paulo

Where Cloudinary fits in

Photography is central to the experience. The same image needs to work in a gallery, a portrait comparison, and a postcard.

I used Cloudinary’s URL-based transformations to prepare different versions of each photograph.

For the newer images, the gallery recipe looks like this:

f_jpg,q_auto,c_fill,g_auto,w_720,h_518
Enter fullscreen mode Exit fullscreen mode

This produces a 720 × 518 JPEG crop with automatic quality and gravity.

The treated portrait uses:

f_jpg,q_auto,c_fill,g_auto,w_720,h_960/e_saturation:25/e_tint:12:df9a65
Enter fullscreen mode Exit fullscreen mode

This creates a taller crop, increases saturation, and applies a warm tint.

The app includes a before-and-after comparison so visitors can see how cropping and color treatment change the presentation. The reference image is also resized and compressed; it is a baseline without the additional color treatment.

Before-and-after comparison of Cloudinary cropping and warm color treatment

You can find the actual recipes and preparation details in the Cloudinary integration documentation.

Preparing media separately from visits

One architectural decision was to separate image preparation from the browsing experience.

The workflow is:

  1. Upload the photographs to Cloudinary.
  2. Generate the required transformations.
  3. Download and validate the prepared files.
  4. Publish those files with the static app.

The collection contains 61 prepared media files: three versions of each of the 20 photographs, plus the cover image.

Visits do not make Cloudinary requests. Browsing, comparisons, quizzes, and postcard generation use the bundled assets. Preparing or updating those assets still consumes Cloudinary quota.

This approach suits a curated collection with a known set of image variants. Adding new photographs requires an explicit preparation step.

For traceability, the project includes a provenance manifest with transformation URLs, MIME types, file sizes, and SHA-256 hashes.

Turning exploration into a postcard

Visitors can select three photos, add a personal message, and export a postcard as a PNG.

The postcard is composed locally in the browser using Canvas. On supported devices, visitors can share the file through native sharing; downloading provides a fallback.

Personalized São Paulo postcard featuring Liberdade, street art, and Ibirapuera, with photo credits

Photo attribution travels with the exported postcards, and the original sources and licenses remain available in the project.

There is also a discovery mechanic: each story includes an observation question. Answering eight questions correctly unlocks a special postcard featuring all 20 photographs.

Keeping the implementation small

SP Layers uses HTML, CSS, and vanilla JavaScript, with no package dependencies or build step. Vercel serves the static dist/ directory.

The implementation also includes:

  • Lazy loading for comparison images.
  • Reserved image dimensions to reduce layout shifts.
  • Keyboard navigation support and a skip link.
  • Reduced-motion support.
  • Browser storage for preferences and discovery progress.
  • An optional map embed that loads after an explicit click.

No account is required. Personal postcard messages are not saved or included in shared selection links.

What this project brings together

SP Layers connects image processing with something visitors can explore and take away.

Cloudinary prepares the visual variations, the static app presents the stories, and Canvas turns a visitor’s selection into a personal postcard.

The project is also a chance to present São Paulo through smaller details: a meal, a mural, a park, or a building that makes someone stop and look.

Try SP Layers and let me know: which three places would you put on your São Paulo postcard?

Photography belongs to the credited authors. Sources and licenses are available in the app and in the photo credits.

Top comments (2)

Collapse
 
jenlooper profile image
Jen Looper •

Really nice way to showcase local vibes!

Collapse
 
victormoni profile image
Victor Moni •

Thanks, Jen! I really appreciate it 💙