Turn Urban Street Networks & Buildings into
Live Optical Portrait Art
A map-locked spatial art engine. Binds any portrait photo to geographic bounding boxes or road networks, sampling pixel luminance into 5-stage reversible rule-based optical art.
✨ Live In-Browser Generative Studio
Select a portrait demo or upload your own, choose an art preset, and download the vector SVG artwork.
🎨 10 Curated Cartographic Art Presets
Professional cartographic palettes inspired by classic printmaking and modern digital aesthetics.
Cyberpunk 2077
Neon DarkVibrant high-contrast neon palette with glowing underlays on dark obsidian background.
Ink Portrait
MonochromeTraditional woodblock and ink printmaking on cream parchment background.
Blueprint
ArchitecturalArchitectural drafting blueprint with cyan stroke gradients and deep navy background.
Vintage Engraving
ClassicWarm copperplate engraving tones on vintage aged cotton paper.
Emerald Eco-Map
OrganicDeep forest and emerald greens for ecological urban compositions.
Nordic Slate
MinimalistCool Scandinavian slate and minimalist muted tones on off-white canvas.
💻 Quick Start Python Guide
import myface2city as mfc
# 1. Initialize portrait engine with image and geographic bbox
bounds = (27.10, 38.40, 27.20, 38.50) # (min_lon, min_lat, max_lon, max_lat)
portrait = mfc.UrbanPortrait("face.jpg", bounds)
# 2. Fetch OpenStreetMap road network for bbox
geojson_data = mfc.fetch_osm_network(bounds)
# 3. Apply optical portrait styling with Cyberpunk preset
styled_geojson = portrait.process_geojson(geojson_data, palette="Cyberpunk 2077")
# 4. Export standalone vector SVG poster
mfc.export_svg(styled_geojson, "portrait.svg", preset="Cyberpunk 2077")
import myface2city as mfc
from PIL import Image
# 1. Load image and define sampling function
img = Image.open("face.jpg").convert("L")
w, h = img.size
pixels = img.load()
def sample_fn(u: float, v: float) -> float:
return float(pixels[int(u * (w - 1)), int(v * (h - 1))])
# 2. Generate 80x80 variable-radius engraving dot grid
points = mfc.calculate_stipple_points(
0.0, 0.0, 100.0, 100.0,
grid_cols=80, grid_rows=80,
sample_fn=sample_fn,
max_radius=4.5,
preset="Ink Portrait"
)
# 3. Export to GeoJSON and SVG
stipple_geojson = mfc.stipple_to_geojson(points)
mfc.export_svg(stipple_geojson, "stipple.svg", preset="Ink Portrait")