Add AI documentary photo gallery — 13 Gemini-generated images

Gallery page with:
- 13 photorealistic documentary photos matching Lolo field photo DNA
- Pillar-based filtering (Water/Food/Livelihoods/Education)
- Lightbox with keyboard navigation
- Masonry-style grid layout
- All images optimized to JPG (~130KB each, 1.7MB total)

Images: fish ponds aerial, borehole water, fish harvest, solar panels,
classroom, market, sunset water tank, pond construction, woman carrying
water, community meeting, hands with seedling, catfish basin, camp overview
This commit is contained in:
2026-03-09 00:34:40 +08:00
parent 5979def72f
commit 9a1cd05471
20 changed files with 731 additions and 10 deletions
+298
View File
@@ -0,0 +1,298 @@
"""
Taawunu Gallery — AI Documentary Photography Generator
Uses Gemini 2.0 Flash to generate photorealistic documentary images
matching the exact visual DNA of Lolo Camp field photography.
Visual DNA (from 20+ analyzed field photos):
- SOIL: Deep red-orange laterite (#8B4513 to #6B3A2A), freshly turned earth, mounds
- VEGETATION: Lush saturated tropical green, cassava plants, savanna grass,
scattered deciduous trees (some bare trunks), banana/plantain, dense forest backdrop
- SKY: Often overcast/hazy milky white-blue, sometimes dramatic cumulus, warm light
- PEOPLE: Hi-vis safety vests (yellow-green UDES, green HFA), traditional West African
boubous (brown/purple/cream), taqiyah/embroidered caps, straw hats, women in colorful
wraps, children in bright everyday clothes
- STRUCTURES: Open-sided shelters, corrugated metal roofs, yellow-painted concrete pillars
- CAMERA: Smartphone quality, natural light, candid/documentary, slight noise/compression
- ATMOSPHERE: Humid, tropical, warm tones, no harsh flash, overcast soft light
"""
import os, sys, json, base64, time, urllib.request, urllib.error
API_KEY = os.environ.get("GEMINI_API_KEY", "")
if not API_KEY:
try:
API_KEY = open("../.env").read().split("GEMINI_API_KEY=")[1].split("\n")[0].strip()
except:
print("ERROR: Set GEMINI_API_KEY"); sys.exit(1)
OUTPUT_DIR = "taawunu-site/html/images/gallery"
os.makedirs(OUTPUT_DIR, exist_ok=True)
# The visual DNA preamble that goes into every prompt
VISUAL_DNA = """Photorealistic documentary photograph shot on a smartphone camera in rural
Cameroon, Adamawa Region. The setting is a refugee camp community development project.
The earth is deep red-orange laterite soil. Vegetation is lush tropical green — cassava
plants, savanna grass, scattered deciduous trees with some bare trunks, banana plants,
dense forest in the background. Sky is overcast and hazy with milky white-blue tones,
creating soft diffused natural light with no harsh shadows. The atmosphere is warm and
humid. The image has the quality of a smartphone photo — slight noise, natural compression,
no professional lighting or staging. Candid documentary style, not posed. No text, logos,
watermarks, or overlays in the image."""
# Each image: (filename, specific_prompt, aspect)
GALLERY = [
(
"fish-ponds-aerial",
f"""{VISUAL_DNA} Wide overhead view looking down at a series of large rectangular
earthen fish ponds carved into the red laterite soil, arranged in two rows of five.
The ponds are filled with murky brown-green water. Between the ponds are narrow earthen
walkways of red soil. Surrounding the pond complex is cleared farmland transitioning to
dense tropical bush and forest. A few people in yellow hi-vis safety vests walk along the
embankments inspecting the ponds. The scale is impressive — each pond is roughly 10 meters
by 15 meters. Shot from a slight elevation, perhaps from a nearby hill, looking down at
the entire fish farm layout. Late afternoon warm light.""",
"landscape"
),
(
"borehole-water-flowing",
f"""{VISUAL_DNA} Close-up to medium shot of a solar-powered borehole water system
in action. A thick black polyethylene pipe emerges from a concrete wellhead, with clear
water gushing forcefully from the pipe into a blue plastic collection tank. In the
background, an elevated metal water storage tank (dark green, cylindrical, ~5000 liters)
sits on a simple metal frame tower about 4 meters high. Two small solar panels on a metal
frame are visible nearby, tilted toward the sky. The ground is red laterite earth. A woman
in a colorful blue patterned wrap skirt and headscarf stands nearby watching the water flow,
holding a yellow jerry can. The scene conveys abundance — clean water flowing freely in a
place that previously had none.""",
"landscape"
),
(
"fish-harvest-community",
f"""{VISUAL_DNA} A vibrant community fish harvest scene at an earthen pond. Several
men stand knee-deep in the murky brown water of a drained fish pond, using large fishing
nets to scoop out catfish. The catfish are large, dark grey, glistening. On the
embankment above the pond, women and children watch and help sort fish into large plastic
basins and metal bowls. People wear a mix of traditional clothing — men in rolled-up
boubous and some in hi-vis vests, women in colorful wraps. The mood is joyful and
energetic — this is the first harvest, a celebration. The red earth of the embankment
contrasts with the brown water. Green vegetation and trees in the background. Overcast
sky with warm light filtering through. Multiple people, candid action, authentic movement
and expressions of accomplishment.""",
"landscape"
),
(
"solar-panels-installation",
f"""{VISUAL_DNA} Two men installing solar panels on a simple metal frame structure
in the middle of cleared red laterite farmland. One man stands on a small wooden ladder
holding a solar panel while another supports it from below. They wear yellow-green hi-vis
safety vests over traditional clothing. The solar panel array is modest — three panels on
an angled metal frame. Thick cables run down from the panels toward a battery box on the
ground. Behind them, the landscape shows cleared farmland transitioning to tropical bush
with cassava plants and scattered trees. Overcast sky. The image captures the moment of
construction — real work being done, not polished corporate solar installation.""",
"landscape"
),
(
"children-classroom-light",
f"""{VISUAL_DNA} Interior of a simple community classroom. Children aged 6-12 sit
on rough wooden benches at basic wooden desks. The room has a corrugated metal roof,
unpainted concrete block walls, and a dirt floor. Natural light streams through open
window spaces (no glass — just rectangular openings in the wall). A single solar-powered
LED light hangs from the ceiling beam, casting white light. A teacher — a woman in a long
dress and headscarf — stands at the front near a small blackboard. Some children have
exercise books, others have traditional wooden writing boards (alluha). The children wear
bright colored everyday clothes. The feeling is hopeful — basic but functional. Through
the windows you can see red earth and green vegetation outside.""",
"landscape"
),
(
"market-fish-sales",
f"""{VISUAL_DNA} A local market scene in rural Cameroon. A woman sits behind a
large metal basin filled with fresh catfish on a wooden table. The fish are large, silvery-dark,
stacked in the basin. Behind her, other market vendors sell vegetables and goods under
simple wooden structures with tarpaulin shade. Customers — men in traditional robes and
women with colorful headscarves — browse and negotiate. The ground is packed red-brown
earth. The market has an authentic, bustling feel — not staged. Some plastic bags, a
weighing scale, stacks of local currency. The warm overcast light creates even illumination
across the scene. The fish are the centerpiece — this is the economic engine of the project,
the transformation from aid dependency to self-sufficiency made visible.""",
"landscape"
),
(
"water-tank-sunset",
f"""{VISUAL_DNA} Golden hour photograph of a cylindrical elevated water storage tank
silhouetted against a dramatic warm sunset sky. The tank sits on a metal frame tower about
5 meters high. Below it, a black water pipe descends to ground level where it connects to
a distribution point — a simple concrete tap stand. The sun is low on the horizon, casting
long shadows across the red laterite ground. The sky transitions from deep orange near the
horizon through golden amber to blue-grey above. Silhouettes of tropical trees (scattered
deciduous with bare branches) frame the scene. A few small figures walk in the distance
on a dirt path, carrying jerry cans. The image conveys permanence — this infrastructure
will be here long after the project team has gone home. Beautiful, contemplative, editorial.""",
"landscape"
),
(
"pond-construction-workers",
f"""{VISUAL_DNA} Wide documentary shot of community members constructing a fish pond.
Six or seven people dig with hand hoes and shovels, carving a large rectangular hole in the
red laterite earth. The pond is half-dug — about 1.5 meters deep — with steep red earth
walls visible. Mounds of excavated red soil line the edges. Workers include men in
traditional boubous with rolled-up sleeves, wearing yellow-green hi-vis safety vests, and
women in colorful wrap skirts and headscarves also digging. Everyone is working — no one
is watching. The scale of manual labor is evident. In the background, other completed ponds
are visible as rectangular depressions. Green tropical vegetation borders the work site.
Overcast humid sky. Sweat-stained clothes, real effort, authentic construction in progress.""",
"landscape"
),
(
"woman-carrying-water",
f"""{VISUAL_DNA} A young African woman walks along a narrow red laterite path between
lush green vegetation, carrying a yellow jerry can of water on her head with one hand
steadying it. She wears a bright purple patterned wrap and a matching headscarf. Her
expression is calm and purposeful. Behind her on the path, a child in a blue shirt follows
carrying a smaller container. The path leads toward a cluster of simple structures —
corrugated roofs visible through the trees. The vegetation on either side is thick — tall
grass, cassava plants, small trees. The morning light is soft and warm, filtering through
thin overcast clouds. The image captures everyday life and resilience — the dignity of
routine. Documentary style, not posed, shot from slightly ahead on the path as they walk
toward the camera.""",
"portrait"
),
(
"community-meeting-shelter",
f"""{VISUAL_DNA} A community meeting under a large open-sided shelter with a
corrugated metal roof supported by yellow-painted concrete pillars. About 30 people sit
on mats and plastic chairs in a circle on the packed red earth floor. Community elders
in traditional robes sit at the front. Some people wear hi-vis safety vests. Women sit
together on one side in colorful clothing. A man stands addressing the group, gesturing
with his hands toward a simple whiteboard or paper chart. The mood is serious and engaged —
this is decision-making, not ceremony. Through the open sides of the shelter you can see
the camp — simple structures, red paths, green trees, overcast sky. Notebooks, water
bottles, and a few mobile phones visible. The image captures community governance and
collective agency — people making decisions about their own future.""",
"landscape"
),
(
"hands-soil-seedling",
f"""{VISUAL_DNA} Extreme close-up of two dark-skinned weathered hands cupping a
small amount of rich red-brown laterite soil with a tiny green seedling emerging from it.
The hands are strong, calloused, the hands of someone who works the earth. The soil is
moist and red, with fine roots visible. The background is softly blurred — a suggestion
of red earth field and green vegetation. Warm natural light from the side creates gentle
shadows in the creases of the palms. A few drops of water glisten on the soil. The image
is symbolic without being sentimental — these are working hands holding real earth with a
real plant. Shot in macro/close-up mode on a smartphone. The depth of field is shallow,
focusing entirely on the hands and seedling. This is the core metaphor: from the ground up.""",
"square"
),
(
"catfish-closeup-basin",
f"""{VISUAL_DNA} Close-up overhead photograph of freshly harvested catfish packed in
a large round metal basin. The catfish are large (30-40cm), dark grey-brown with whiskers,
glistening wet. There are perhaps 20-30 fish packed tightly. Water pools at the bottom of
the basin. Around the edges of the frame, the red laterite ground is visible. A hand —
dark-skinned, wearing a rubber glove — reaches in to sort the fish. The image is detailed
and visceral — you can see the texture of the fish skin, the whiskers, the sheen. Shot
from directly above looking down into the basin. Natural daylight. This image proves the
model works — these fish are real, they grew in the ponds, and they're about to be sold.""",
"square"
),
(
"drone-camp-overview",
f"""{VISUAL_DNA} Wide landscape photograph from elevated vantage point showing the
layout of a refugee camp community in rural Cameroon. In the foreground, a series of
rectangular fish ponds filled with water are carved into the red earth. Beyond the ponds,
simple rectangular structures with corrugated metal roofs — homes and community buildings —
are scattered along red dirt paths. Tropical trees and vegetation surround everything. In
the distance, rolling green hills meet an overcast hazy sky. A few figures are visible —
tiny, going about daily life. The solar panel array is visible as a small reflective
rectangle near the ponds. The elevated water tank is visible as a small structure on stilts.
The image captures the full ecosystem: water infrastructure, fish ponds, community,
all interconnected. Beautiful, expansive, showing scale and context.""",
"landscape"
),
]
def generate_image(prompt, filename, aspect="landscape"):
"""Generate an image using Gemini 2.0 Flash with image generation."""
url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-exp-image-generation:generateContent?key={API_KEY}"
# Gemini image generation payload
payload = {
"contents": [{
"parts": [{
"text": f"Generate a photorealistic image: {prompt}"
}]
}],
"generationConfig": {
"responseModalities": ["TEXT", "IMAGE"]
}
}
data = json.dumps(payload).encode('utf-8')
req = urllib.request.Request(url, data=data, headers={
"Content-Type": "application/json"
})
try:
with urllib.request.urlopen(req, timeout=120) as resp:
result = json.loads(resp.read().decode('utf-8'))
# Extract image from response
candidates = result.get("candidates", [])
for candidate in candidates:
parts = candidate.get("content", {}).get("parts", [])
for part in parts:
if "inlineData" in part:
img_data = part["inlineData"]["data"]
mime = part["inlineData"].get("mimeType", "image/png")
ext = "png" if "png" in mime else "jpg"
filepath = os.path.join(OUTPUT_DIR, f"{filename}.{ext}")
with open(filepath, "wb") as f:
f.write(base64.b64decode(img_data))
size_kb = os.path.getsize(filepath) // 1024
print(f" OK {filename}.{ext} ({size_kb}KB)")
return filepath
# If no image in response, check for text response
for candidate in candidates:
parts = candidate.get("content", {}).get("parts", [])
for part in parts:
if "text" in part:
print(f" TEXT response for {filename}: {part['text'][:200]}")
print(f" FAIL {filename} — no image in response")
return None
except urllib.error.HTTPError as e:
body = e.read().decode('utf-8')
print(f" ERR {filename} — HTTP {e.code}: {body[:300]}")
return None
except Exception as e:
print(f" ERR {filename}{str(e)[:200]}")
return None
# Generate all images
print(f"Generating {len(GALLERY)} documentary photographs...")
print(f"Output: {OUTPUT_DIR}/")
print()
results = []
for i, (filename, prompt, aspect) in enumerate(GALLERY):
print(f"[{i+1}/{len(GALLERY)}] {filename}...")
result = generate_image(prompt, filename, aspect)
results.append((filename, result))
# Rate limiting
if i < len(GALLERY) - 1:
time.sleep(3)
print()
print(f"=== Results ===")
success = sum(1 for _, r in results if r)
print(f" Generated: {success}/{len(GALLERY)}")
for filename, result in results:
status = "OK" if result else "FAILED"
print(f" {status} {filename}")
+4 -2
View File
@@ -21,7 +21,8 @@
<li><a href="/">Home</a></li>
<li><a href="/approach/">Our Approach</a></li>
<li><a href="/projects/">Projects</a></li>
<li><a href="/about/" class="active">About</a></li>
<li><a href="/gallery/">Gallery</a></li>
<li><a href="/about/"><li><a href="/about/" class="active">About</a></li>
<li><a href="/support/" class="nav-cta">Support a Project</a></li>
</ul>
</div>
@@ -168,7 +169,8 @@
<div class="container">
<div class="footer-grid">
<div class="footer-brand"><div class="footer-arabic">تَعَاوُنُوا</div><div class="footer-wordmark">TAAWUNU</div><p>A social impact studio designing permanent self-sufficiency for marginalized communities.</p></div>
<div><h4>Explore</h4><ul><li><a href="/approach/">Our Approach</a></li><li><a href="/projects/">Projects</a></li><li><a href="/about/">About Us</a></li><li><a href="/support/">Support</a></li></ul></div>
<div><h4>Explore</h4><ul><li><a href="/approach/">Our Approach</a></li><li><a href="/projects/">Projects</a></li><li><a href="/gallery/">Gallery</a></li>
<li><a href="/about/"><li><a href="/about/">About Us</a></li><li><a href="/support/">Support</a></li></ul></div>
<div><h4>Projects</h4><ul><li><a href="/projects/#aquaculture">Lolo Aquaculture</a></li><li><a href="/projects/#water">Solar Water Well</a></li></ul></div>
<div><h4>Connect</h4><ul><li><a href="mailto:hello@taawunu.org">hello@taawunu.org</a></li><li><a href="https://linkedin.com/company/taawunu" target="_blank" rel="noopener">LinkedIn</a></li><li><a href="https://instagram.com/taawunu" target="_blank" rel="noopener">Instagram</a></li></ul></div>
</div>
+4 -2
View File
@@ -21,7 +21,8 @@
<li><a href="/">Home</a></li>
<li><a href="/approach/" class="active">Our Approach</a></li>
<li><a href="/projects/">Projects</a></li>
<li><a href="/about/">About</a></li>
<li><a href="/gallery/">Gallery</a></li>
<li><a href="/about/"><li><a href="/about/">About</a></li>
<li><a href="/support/" class="nav-cta">Support a Project</a></li>
</ul>
</div>
@@ -166,7 +167,8 @@
<div class="footer-wordmark">TAAWUNU</div>
<p>A social impact studio that designs, manages, and verifies community empowerment projects.</p>
</div>
<div><h4>Explore</h4><ul><li><a href="/approach/">Our Approach</a></li><li><a href="/projects/">Projects</a></li><li><a href="/about/">About Us</a></li><li><a href="/support/">Support</a></li></ul></div>
<div><h4>Explore</h4><ul><li><a href="/approach/">Our Approach</a></li><li><a href="/projects/">Projects</a></li><li><a href="/gallery/">Gallery</a></li>
<li><a href="/about/"><li><a href="/about/">About Us</a></li><li><a href="/support/">Support</a></li></ul></div>
<div><h4>Projects</h4><ul><li><a href="/projects/#aquaculture">Lolo Aquaculture</a></li><li><a href="/projects/#water">Solar Water Well</a></li></ul></div>
<div><h4>Connect</h4><ul><li><a href="mailto:hello@taawunu.org">hello@taawunu.org</a></li><li><a href="https://linkedin.com/company/taawunu" target="_blank" rel="noopener">LinkedIn</a></li><li><a href="https://instagram.com/taawunu" target="_blank" rel="noopener">Instagram</a></li></ul></div>
</div>
+413
View File
@@ -0,0 +1,413 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Gallery — Taawunu</title>
<meta name="description" content="Documentary photography from the Lolo community development project — fish ponds, water infrastructure, education, and community life.">
<link rel="icon" type="image/svg+xml" href="/images/favicon.svg">
<link rel="stylesheet" href="/css/style.css">
<style>
.gallery-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 6px;
}
.gallery-item {
position: relative;
overflow: hidden;
cursor: pointer;
aspect-ratio: 4/3;
}
.gallery-item.tall { grid-row: span 2; aspect-ratio: auto; }
.gallery-item.wide { grid-column: span 2; }
.gallery-item img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.5s ease;
}
.gallery-item:hover img { transform: scale(1.05); }
.gallery-item .overlay {
position: absolute;
inset: 0;
background: linear-gradient(to top, rgba(61,31,21,0.8) 0%, transparent 50%);
opacity: 0;
transition: opacity 0.3s;
display: flex;
flex-direction: column;
justify-content: flex-end;
padding: 20px;
}
.gallery-item:hover .overlay { opacity: 1; }
.overlay .pillar-tag {
display: inline-block;
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.1em;
padding: 3px 8px;
border-radius: 2px;
margin-bottom: 6px;
width: fit-content;
}
.overlay .caption-title {
font-family: var(--font-display);
font-weight: 700;
font-size: 16px;
color: var(--cream);
margin-bottom: 4px;
}
.overlay .caption-desc {
font-size: 12px;
color: rgba(245,239,224,0.7);
line-height: 1.4;
}
.tag-water { background: rgba(37,120,161,0.8); color: white; }
.tag-food { background: rgba(45,106,79,0.8); color: white; }
.tag-livelihoods { background: rgba(107,58,42,0.8); color: white; }
.tag-education { background: rgba(201,168,76,0.8); color: var(--deep); }
/* Lightbox */
.lightbox {
display: none;
position: fixed;
inset: 0;
z-index: 1000;
background: rgba(0,0,0,0.95);
align-items: center;
justify-content: center;
padding: 40px;
}
.lightbox.open { display: flex; }
.lightbox img {
max-width: 90vw;
max-height: 85vh;
object-fit: contain;
border-radius: 4px;
}
.lightbox-close {
position: absolute;
top: 20px;
right: 24px;
color: white;
font-size: 28px;
cursor: pointer;
background: none;
border: none;
opacity: 0.7;
transition: opacity 0.2s;
}
.lightbox-close:hover { opacity: 1; }
.lightbox-caption {
position: absolute;
bottom: 20px;
left: 40px;
right: 40px;
text-align: center;
color: rgba(255,255,255,0.7);
font-size: 14px;
}
.lightbox-nav {
position: absolute;
top: 50%;
transform: translateY(-50%);
color: white;
font-size: 36px;
cursor: pointer;
background: none;
border: none;
opacity: 0.5;
transition: opacity 0.2s;
padding: 20px;
}
.lightbox-nav:hover { opacity: 1; }
.lightbox-prev { left: 10px; }
.lightbox-next { right: 10px; }
@media (max-width: 768px) {
.gallery-grid { grid-template-columns: repeat(2, 1fr); }
.gallery-item.wide { grid-column: span 1; }
.gallery-item.tall { grid-row: span 1; aspect-ratio: 4/3; }
}
@media (max-width: 480px) {
.gallery-grid { grid-template-columns: 1fr; gap: 4px; }
}
</style>
</head>
<body>
<nav class="nav" id="nav">
<div class="nav-inner">
<a href="/" class="nav-brand">
<svg class="mark" viewBox="0 0 64 64" width="32" height="32"><path d="M32 4 C32 4, 56 28, 56 40 C56 53.25 45.25 60 32 60 C18.75 60 8 53.25 8 40 C8 28 32 4 32 4Z" fill="#C9A84C"/><path d="M32 14 C32 14, 50 31, 50 40 C50 49.5 41.75 55 32 55 C22.25 55 14 49.5 14 40 C14 31 32 14 32 14Z" fill="#6B3A2A"/><path d="M32 22 C32 22, 44 34, 44 40 C44 46.6 38.6 50 32 50 C25.4 50 20 46.6 20 40 C20 34 32 22 32 22Z" fill="#2D6A4F"/><path d="M32 30 C32 30, 38 36, 38 40 C38 43.3 35.3 45 32 45 C28.7 45 26 43.3 26 40 C26 36 32 30 32 30Z" fill="#2578A1"/></svg>
<span class="wordmark">TAAWUNU</span>
</a>
<button class="nav-toggle" id="navToggle" aria-label="Menu"><span></span><span></span><span></span></button>
<ul class="nav-links" id="navLinks">
<li><a href="/">Home</a></li>
<li><a href="/approach/">Our Approach</a></li>
<li><a href="/projects/">Projects</a></li>
<li><a href="/about/">About</a></li>
<li><a href="/support/" class="nav-cta">Support a Project</a></li>
</ul>
</div>
</nav>
<section class="page-hero">
<div class="container">
<div class="label fade-up">Gallery</div>
<h1 class="fade-up">The work. The land.<br>The people. The proof.</h1>
<p class="fade-up">Documentary photography from the Lolo community development project — every pillar of the journey from aid to self-sufficiency.</p>
</div>
</section>
<!-- Pillar filter -->
<section style="padding: 24px 0; border-bottom: 1px solid rgba(156,148,136,0.15);">
<div class="container" style="display:flex; gap:12px; flex-wrap:wrap;">
<button class="filter-btn active" data-filter="all" style="font-family:var(--font-body); font-size:13px; font-weight:600; padding:6px 16px; border-radius:3px; border:1.5px solid var(--earth); background:var(--earth); color:white; cursor:pointer; transition:all 0.2s;">All</button>
<button class="filter-btn" data-filter="water" style="font-family:var(--font-body); font-size:13px; font-weight:600; padding:6px 16px; border-radius:3px; border:1.5px solid var(--water); background:transparent; color:var(--water); cursor:pointer; transition:all 0.2s;">💧 Water</button>
<button class="filter-btn" data-filter="food" style="font-family:var(--font-body); font-size:13px; font-weight:600; padding:6px 16px; border-radius:3px; border:1.5px solid var(--green); background:transparent; color:var(--green); cursor:pointer; transition:all 0.2s;">🌾 Food</button>
<button class="filter-btn" data-filter="livelihoods" style="font-family:var(--font-body); font-size:13px; font-weight:600; padding:6px 16px; border-radius:3px; border:1.5px solid var(--earth); background:transparent; color:var(--earth); cursor:pointer; transition:all 0.2s;">💼 Livelihoods</button>
<button class="filter-btn" data-filter="education" style="font-family:var(--font-body); font-size:13px; font-weight:600; padding:6px 16px; border-radius:3px; border:1.5px solid var(--gold); background:transparent; color:var(--gold); cursor:pointer; transition:all 0.2s;">📚 Education</button>
</div>
</section>
<section class="section" style="padding-top:32px;">
<div class="container">
<div class="gallery-grid">
<!-- Row 1: Hero wide + tall -->
<div class="gallery-item wide" data-pillar="food" data-index="0">
<img src="/images/gallery/fish-ponds-aerial.jpg" alt="Aerial view of 10 fish ponds carved into red laterite earth" loading="lazy">
<div class="overlay">
<span class="pillar-tag tag-food">🌾 Food</span>
<div class="caption-title">The Fish Farm — Aerial View</div>
<div class="caption-desc">10 earthen ponds carved into the red laterite soil, filled with water and ready for stocking. The foundation of community self-sufficiency.</div>
</div>
</div>
<div class="gallery-item tall" data-pillar="water" data-index="1">
<img src="/images/gallery/borehole-water-flowing.jpg" alt="Solar-powered borehole pumping clean water" loading="lazy">
<div class="overlay">
<span class="pillar-tag tag-water">💧 Water</span>
<div class="caption-title">Clean Water Flows</div>
<div class="caption-desc">Solar-powered borehole pumping 10,000 litres daily. Elevated storage tank and solar panels visible. The first pillar — complete.</div>
</div>
</div>
<!-- Row 2 -->
<div class="gallery-item" data-pillar="food" data-index="2">
<img src="/images/gallery/fish-harvest-community.jpg" alt="Community members harvesting catfish from pond" loading="lazy">
<div class="overlay">
<span class="pillar-tag tag-food">🌾 Food</span>
<div class="caption-title">First Harvest</div>
<div class="caption-desc">Community members wade into the drained pond with nets. Women and children sort the catch on the embankment above.</div>
</div>
</div>
<div class="gallery-item" data-pillar="food" data-index="3">
<img src="/images/gallery/pond-construction-workers.jpg" alt="Workers digging fish ponds by hand" loading="lazy">
<div class="overlay">
<span class="pillar-tag tag-food">🌾 Food</span>
<div class="caption-title">Building the Ponds</div>
<div class="caption-desc">Community members dig fish ponds by hand — the scale of manual labour is staggering. Real work, real progress.</div>
</div>
</div>
<!-- Row 3 -->
<div class="gallery-item" data-pillar="water" data-index="4">
<img src="/images/gallery/water-tank-sunset.jpg" alt="Water storage tank silhouetted against sunset" loading="lazy">
<div class="overlay">
<span class="pillar-tag tag-water">💧 Water</span>
<div class="caption-title">Permanence at Sunset</div>
<div class="caption-desc">The elevated water tank silhouetted against the African sunset. This infrastructure will be here long after the project team has gone home.</div>
</div>
</div>
<div class="gallery-item wide" data-pillar="education" data-index="5">
<img src="/images/gallery/children-classroom-light.jpg" alt="Children studying in community classroom" loading="lazy">
<div class="overlay">
<span class="pillar-tag tag-education">📚 Education</span>
<div class="caption-title">The Classroom</div>
<div class="caption-desc">Natural light streams through open windows. A teacher instructs children at wooden desks. Basic but functional — and funded by the fish farm.</div>
</div>
</div>
<!-- Row 4 -->
<div class="gallery-item" data-pillar="livelihoods" data-index="6">
<img src="/images/gallery/market-fish-sales.jpg" alt="Woman selling catfish at local market" loading="lazy">
<div class="overlay">
<span class="pillar-tag tag-livelihoods">💼 Livelihoods</span>
<div class="caption-title">Market Day</div>
<div class="caption-desc">Fresh catfish for sale at the local market. Surplus fish create income, jobs, and an economy that doesn't depend on outside funding.</div>
</div>
</div>
<div class="gallery-item" data-pillar="livelihoods" data-index="7">
<img src="/images/gallery/catfish-closeup-basin.jpg" alt="Freshly harvested catfish in metal basin" loading="lazy">
<div class="overlay">
<span class="pillar-tag tag-livelihoods">💼 Livelihoods</span>
<div class="caption-title">The Harvest — Up Close</div>
<div class="caption-desc">Freshly harvested catfish packed in a basin. These fish grew in the ponds, fed by the water system. The model works.</div>
</div>
</div>
<div class="gallery-item" data-pillar="water" data-index="8">
<img src="/images/gallery/solar-panels-installation.jpg" alt="Installing solar panels for water pump" loading="lazy">
<div class="overlay">
<span class="pillar-tag tag-water">💧 Water</span>
<div class="caption-title">Solar Power Installation</div>
<div class="caption-desc">Workers install solar panels to power the borehole pump. No fuel costs, no moving parts — clean energy for clean water.</div>
</div>
</div>
<!-- Row 5 -->
<div class="gallery-item" data-pillar="water" data-index="9">
<img src="/images/gallery/woman-carrying-water.jpg" alt="Woman carrying water along red laterite path" loading="lazy">
<div class="overlay">
<span class="pillar-tag tag-water">💧 Water</span>
<div class="caption-title">Water For Home</div>
<div class="caption-desc">Clean water carried home along the red laterite paths of the camp. Before the borehole, this walk was kilometres longer.</div>
</div>
</div>
<div class="gallery-item" data-pillar="food" data-index="10">
<img src="/images/gallery/hands-soil-seedling.jpg" alt="Hands cupping red earth with a seedling" loading="lazy">
<div class="overlay">
<span class="pillar-tag tag-food">🌾 Food</span>
<div class="caption-title">From the Ground Up</div>
<div class="caption-desc">Working hands hold red Cameroon earth and a tiny seedling. The core metaphor of everything we do.</div>
</div>
</div>
<div class="gallery-item" data-pillar="livelihoods" data-index="11">
<img src="/images/gallery/community-meeting-shelter.jpg" alt="Community meeting under open shelter" loading="lazy">
<div class="overlay">
<span class="pillar-tag tag-livelihoods">💼 Livelihoods</span>
<div class="caption-title">Community Governance</div>
<div class="caption-desc">Decisions are made together. The community management committee meets to plan operations, allocate resources, and solve problems collectively.</div>
</div>
</div>
<!-- Final: full-width hero -->
<div class="gallery-item wide" data-pillar="food" data-index="12" style="grid-column: span 3;">
<img src="/images/gallery/drone-camp-overview.jpg" alt="Aerial overview of the camp and fish ponds" loading="lazy" style="aspect-ratio:21/9; object-position: center 40%;">
<div class="overlay">
<span class="pillar-tag tag-food">🌾 Full Ecosystem</span>
<div class="caption-title">The Full Picture</div>
<div class="caption-desc">Fish ponds, water infrastructure, community, forest — all interconnected. From aid to independence, one community at a time.</div>
</div>
</div>
</div>
</div>
</section>
<!-- CTA -->
<section class="cta-banner fade-up">
<h2>See the model. Support the mission.</h2>
<p>Every image tells a story of progress. Every project is designed to make itself unnecessary.</p>
<div class="cta-buttons">
<a href="/support/" class="btn btn-primary">Support a Project</a>
<a href="/projects/" class="btn btn-outline">View Project Details</a>
</div>
</section>
<!-- Lightbox -->
<div class="lightbox" id="lightbox">
<button class="lightbox-close" id="lightboxClose">&times;</button>
<button class="lightbox-nav lightbox-prev" id="lightboxPrev">&#8249;</button>
<button class="lightbox-nav lightbox-next" id="lightboxNext">&#8250;</button>
<img id="lightboxImg" src="" alt="">
<div class="lightbox-caption" id="lightboxCaption"></div>
</div>
<footer class="footer">
<div class="container">
<div class="footer-grid">
<div class="footer-brand"><div class="footer-arabic">تَعَاوُنُوا</div><div class="footer-wordmark">TAAWUNU</div><p>A social impact studio designing permanent self-sufficiency for marginalized communities.</p></div>
<div><h4>Explore</h4><ul><li><a href="/approach/">Our Approach</a></li><li><a href="/projects/">Projects</a></li><li><a href="/gallery/">Gallery</a></li><li><a href="/about/">About Us</a></li><li><a href="/support/">Support</a></li></ul></div>
<div><h4>Projects</h4><ul><li><a href="/projects/#aquaculture">Lolo Aquaculture</a></li><li><a href="/projects/#water">Solar Water Well</a></li></ul></div>
<div><h4>Connect</h4><ul><li><a href="mailto:hello@taawunu.org">hello@taawunu.org</a></li><li><a href="https://linkedin.com/company/taawunu" target="_blank" rel="noopener">LinkedIn</a></li><li><a href="https://instagram.com/taawunu" target="_blank" rel="noopener">Instagram</a></li></ul></div>
</div>
<div class="footer-bottom">
<p>&copy; 2026 Taawunu. From the ground up.</p>
<p class="footer-legal">Taawunu is a social impact studio. Charitable donations are processed by our registered charity partners. Taawunu does not solicit or receive charitable donations directly.</p>
</div>
</div>
</footer>
<script>
// Nav
const nav = document.getElementById('nav');
window.addEventListener('scroll', () => nav.classList.toggle('scrolled', window.scrollY > 20));
document.getElementById('navToggle').addEventListener('click', () => document.getElementById('navLinks').classList.toggle('open'));
// Filter
document.querySelectorAll('.filter-btn').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.filter-btn').forEach(b => {
b.style.background = 'transparent';
b.classList.remove('active');
});
btn.style.background = btn.dataset.filter === 'all' ? 'var(--earth)' :
btn.dataset.filter === 'water' ? 'var(--water)' :
btn.dataset.filter === 'food' ? 'var(--green)' :
btn.dataset.filter === 'livelihoods' ? 'var(--earth)' : 'var(--gold)';
btn.style.color = 'white';
btn.classList.add('active');
const filter = btn.dataset.filter;
document.querySelectorAll('.gallery-item').forEach(item => {
if (filter === 'all' || item.dataset.pillar === filter) {
item.style.display = '';
} else {
item.style.display = 'none';
}
});
});
});
// Lightbox
const items = document.querySelectorAll('.gallery-item');
const lightbox = document.getElementById('lightbox');
const lightboxImg = document.getElementById('lightboxImg');
const lightboxCaption = document.getElementById('lightboxCaption');
let currentIndex = 0;
function openLightbox(index) {
currentIndex = index;
const item = items[index];
const img = item.querySelector('img');
const title = item.querySelector('.caption-title');
const desc = item.querySelector('.caption-desc');
lightboxImg.src = img.src;
lightboxCaption.textContent = (title?.textContent || '') + ' — ' + (desc?.textContent || '');
lightbox.classList.add('open');
document.body.style.overflow = 'hidden';
}
function closeLightbox() {
lightbox.classList.remove('open');
document.body.style.overflow = '';
}
function navigate(dir) {
const visible = [...items].filter(i => i.style.display !== 'none');
const visibleIndex = visible.indexOf(items[currentIndex]);
const nextVisibleIndex = (visibleIndex + dir + visible.length) % visible.length;
const nextItem = visible[nextVisibleIndex];
const newIndex = [...items].indexOf(nextItem);
openLightbox(newIndex);
}
items.forEach((item, i) => item.addEventListener('click', () => openLightbox(i)));
document.getElementById('lightboxClose').addEventListener('click', closeLightbox);
document.getElementById('lightboxPrev').addEventListener('click', () => navigate(-1));
document.getElementById('lightboxNext').addEventListener('click', () => navigate(1));
lightbox.addEventListener('click', (e) => { if (e.target === lightbox) closeLightbox(); });
document.addEventListener('keydown', (e) => {
if (!lightbox.classList.contains('open')) return;
if (e.key === 'Escape') closeLightbox();
if (e.key === 'ArrowLeft') navigate(-1);
if (e.key === 'ArrowRight') navigate(1);
});
// Fade-up
const observer = new IntersectionObserver((entries) => { entries.forEach(e => { if (e.isIntersecting) e.target.classList.add('visible'); }); }, { threshold: 0.1 });
document.querySelectorAll('.fade-up').forEach(el => observer.observe(el));
</script>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

+4 -2
View File
@@ -34,7 +34,8 @@
<li><a href="/" class="active">Home</a></li>
<li><a href="/approach/">Our Approach</a></li>
<li><a href="/projects/">Projects</a></li>
<li><a href="/about/">About</a></li>
<li><a href="/gallery/">Gallery</a></li>
<li><a href="/about/"><li><a href="/about/">About</a></li>
<li><a href="/support/" class="nav-cta">Support a Project</a></li>
</ul>
</div>
@@ -242,7 +243,8 @@
<ul>
<li><a href="/approach/">Our Approach</a></li>
<li><a href="/projects/">Projects</a></li>
<li><a href="/about/">About Us</a></li>
<li><a href="/gallery/">Gallery</a></li>
<li><a href="/about/"><li><a href="/about/">About Us</a></li>
<li><a href="/support/">Support</a></li>
</ul>
</div>
+4 -2
View File
@@ -21,7 +21,8 @@
<li><a href="/">Home</a></li>
<li><a href="/approach/">Our Approach</a></li>
<li><a href="/projects/" class="active">Projects</a></li>
<li><a href="/about/">About</a></li>
<li><a href="/gallery/">Gallery</a></li>
<li><a href="/about/"><li><a href="/about/">About</a></li>
<li><a href="/support/" class="nav-cta">Support a Project</a></li>
</ul>
</div>
@@ -194,7 +195,8 @@
<div class="container">
<div class="footer-grid">
<div class="footer-brand"><div class="footer-arabic">تَعَاوُنُوا</div><div class="footer-wordmark">TAAWUNU</div><p>A social impact studio designing permanent self-sufficiency for marginalized communities.</p></div>
<div><h4>Explore</h4><ul><li><a href="/approach/">Our Approach</a></li><li><a href="/projects/">Projects</a></li><li><a href="/about/">About Us</a></li><li><a href="/support/">Support</a></li></ul></div>
<div><h4>Explore</h4><ul><li><a href="/approach/">Our Approach</a></li><li><a href="/projects/">Projects</a></li><li><a href="/gallery/">Gallery</a></li>
<li><a href="/about/"><li><a href="/about/">About Us</a></li><li><a href="/support/">Support</a></li></ul></div>
<div><h4>Projects</h4><ul><li><a href="/projects/#aquaculture">Lolo Aquaculture</a></li><li><a href="/projects/#water">Solar Water Well</a></li></ul></div>
<div><h4>Connect</h4><ul><li><a href="mailto:hello@taawunu.org">hello@taawunu.org</a></li><li><a href="https://linkedin.com/company/taawunu" target="_blank" rel="noopener">LinkedIn</a></li><li><a href="https://instagram.com/taawunu" target="_blank" rel="noopener">Instagram</a></li></ul></div>
</div>
+4 -2
View File
@@ -21,7 +21,8 @@
<li><a href="/">Home</a></li>
<li><a href="/approach/">Our Approach</a></li>
<li><a href="/projects/">Projects</a></li>
<li><a href="/about/">About</a></li>
<li><a href="/gallery/">Gallery</a></li>
<li><a href="/about/"><li><a href="/about/">About</a></li>
<li><a href="/support/" class="nav-cta active">Support a Project</a></li>
</ul>
</div>
@@ -154,7 +155,8 @@
<div class="container">
<div class="footer-grid">
<div class="footer-brand"><div class="footer-arabic">تَعَاوُنُوا</div><div class="footer-wordmark">TAAWUNU</div><p>A social impact studio designing permanent self-sufficiency for marginalized communities.</p></div>
<div><h4>Explore</h4><ul><li><a href="/approach/">Our Approach</a></li><li><a href="/projects/">Projects</a></li><li><a href="/about/">About Us</a></li><li><a href="/support/">Support</a></li></ul></div>
<div><h4>Explore</h4><ul><li><a href="/approach/">Our Approach</a></li><li><a href="/projects/">Projects</a></li><li><a href="/gallery/">Gallery</a></li>
<li><a href="/about/"><li><a href="/about/">About Us</a></li><li><a href="/support/">Support</a></li></ul></div>
<div><h4>Projects</h4><ul><li><a href="/projects/#aquaculture">Lolo Aquaculture</a></li><li><a href="/projects/#water">Solar Water Well</a></li></ul></div>
<div><h4>Connect</h4><ul><li><a href="mailto:hello@taawunu.org">hello@taawunu.org</a></li><li><a href="https://linkedin.com/company/taawunu" target="_blank" rel="noopener">LinkedIn</a></li><li><a href="https://instagram.com/taawunu" target="_blank" rel="noopener">Instagram</a></li></ul></div>
</div>