Final Review: austin-things-to-do-v2¶
Date: 2026-05-02
Requirement Results¶
| # | Requirement | Status | Notes |
|---|---|---|---|
| 1 | Live event calendar (do512/eventbrite/austinchronicle/timeout, next 30 days) | PARTIAL FAIL | 60 events, 59 in range, but only eventbrite and supplemental sources present — do512, austinchronicle, and timeout are missing |
| 2 | Maps section with Leaflet markers | PASS | Leaflet CDN linked, map initialized with CartoDB tiles, markers plotted for events + happy hour + sushi with filter tabs |
| 3 | Happy Hour section (16 spots, full schema) | PASS | Exactly 16 spots, all have required schema fields, all have lat/lng coords |
| 4 | Sushi section (13 spots) | PASS | Exactly 13 spots, all have lat/lng coords, full schema |
| 5 | Asset-heavy premium design, no stock-placeholder look | PASS | 46 real CC-licensed images across hero/, sections/, icons/, textures/; attribution manifest present |
Detailed Findings¶
Requirement 1: Live Event Calendar¶
60 events total in data/events.json. Date coverage:
- 59 events fall within May 2 – May 31, 2026 (within 30 days of today).
- 1 event out of range:
evt_040"Lens on Nature Photo Walk" dated2026-06-13— 42 days out. It will be silently excluded at render time by the JS date filter (lines 46–49 ofscript.js), so it will not appear in the calendar. Not a crash bug but wasted data.
Source gap (the core failure): The requirement specifies events sourced from do512, eventbrite, austinchronicle, and timeout. Actual source field values in the data:
| Source | Count |
|---|---|
eventbrite |
44 |
supplemental |
16 |
Sources do512, austinchronicle, and timeout are entirely absent. The 16 supplemental events are labeled generically and attributed to sites like austintexas.gov, visitaustin.com, stubbsaustin.com — not the named event discovery platforms. The filter chip UI will surface eventbrite and supplemental as the only source options, which does not match the spec.
JS rendering: renderCalendar in script.js (lines 42–63) correctly fetches data/events.json, filters to the 30-day window, builds source and category filter chips, and renders date-grouped event cards. The rendering logic is solid; the data is the gap.
Requirement 2: Maps Section¶
index.html line 12: Leaflet 1.9.4 CSS linked with integrity hash. Line 638: Leaflet JS loaded with integrity hash and defer. Section id="map-section" present at line 391. Nav link href="#map-section" present at line 54.
script.js initMap() function (lines 271–343):
- Initializes L.map('event-map') with scrollWheelZoom: false.
- Uses CartoDB Positron tile layer (clean, readable).
- Adds dot markers for all three data types using color-coded L.divIcon (events: #e63946, happy-hour: #f4a261, sushi: #2a9d8f).
- Guards: checks for ev.lat/ev.lng before plotting, so partial-coordinate records won't crash.
- fitBounds on all markers when present, fallback setView to Austin center.
- Map tab filter buttons (All / Events / Happy Hour / Sushi) wire up actual addTo/removeLayer calls (lines 332–342), not just visual state.
All happy hour and sushi spots have lat/lng populated. Events all have coordinates. Map legend in HTML matches the color scheme in JS. No issues found.
Requirement 3: Happy Hour Section¶
data/happy_hour.json contains exactly 16 spots (confirmed by count, matches meta.spot_count: 16).
All 16 spots pass schema validation for required fields: name, neighborhood, happy_hour_days, happy_hour_times, price_tier, signature_drink, source_url. All spots also include optional signature_bite and vibe fields.
All 16 spots have lat and lng coordinates, so they will appear as markers on the map.
script.js renderHappyHour() (lines 176–219) renders name, neighborhood, price tier, hours, days, signature drink, optional bite, vibe, and link. Section id="happy-hour" present in HTML at line 437. Nav link present.
Requirement 4: Sushi Section¶
data/sushi.json contains exactly 13 spots (confirmed by count, matches meta.spot_count: 13).
All 13 spots have lat/lng. All have required fields: name, neighborhood, price_tier, style, signature_dish, hours_summary, reservations_required, vibe, source_url.
script.js renderSushi() (lines 224–266) renders name, neighborhood, price tier, style, signature dish, hours, reservations badge, vibe, and link. Section id="sushi" present in HTML at line 478.
Note: su-012 ("East Side King – Liberty") is listed under style: "fusion" with a description that explicitly states "not a sushi bar." This is an editorial call by the content author, not a data error.
Requirement 5: Design Quality¶
Assets directory: 46 real images across four subdirectories:
- hero/: 7 Austin skyline and landmark photos (157–532 KB each — genuine photographs)
- sections/: 12 section-specific photos (food, music, nightlife, happy hour, events, maps, sushi, etc.)
- icons/: 25 emoji/icon PNG files (Twemoji, CC BY 4.0) plus 2 Austin-specific JPGs
- textures/: 3 overlay textures (bokeh, concrete, paper vintage)
No placeholder images. All images are real CC-licensed photographs sourced from Flickr/Wikimedia/Twemoji.
styles.css design indicators:
- Hero: full-bleed background photo with dual-layer gradient overlay (rgba(15,13,11,0.45) → rgba(15,13,11,0.68)), grain texture pseudo-element, wave SVG divider.
- Dark sections: per-section background images assigned via CSS IDs (#music, #nightlife, #calendar, #happy-hour) with parallax background-attachment: fixed (disabled on mobile).
- Texture overlays: paper-vintage.jpg at 4% opacity on light sections; dark-concrete.jpg at 6% opacity on dark sections.
- Cards: hover lift with translateY(-3px), dark-section card override with amber border glow.
- Typography: Fraunces (display) + Inter (body), loaded from Google Fonts.
- Responsive grid: 1 → 2 → 3 columns at 640px and 960px breakpoints.
Attribution manifest: assets/ATTRIBUTION.md present with a complete table of all 46 assets, license types, and source URLs. assets/provenance.json also present.
Cross-Cutting Checks¶
Asset paths: All 25 asset paths referenced in index.html and styles.css were verified against the filesystem. Zero missing files.
JS errors (static analysis):
- All functions called in script.js are defined within the IIFE: renderCalendar, unique, buildChips, makeChip, capitalize, renderEventGroups, renderHappyHour, renderSushi, initMap, dotIcon, escHtml, escAttr.
- No undefined variable references detected.
- L (Leaflet) is guarded with typeof L === 'undefined' check at line 274 before use.
- One minor logic note: index.html lines 660–666 contain a second chips forEach for .filter-chip click toggle. This runs before JS populates chips (the inline script runs after defer scripts). In practice this is harmless because querySelectorAll('.filter-chip') will return an empty list at that point and the real chip toggle is handled in script.js buildChips() line 81. Not a bug, just dead code in the inline script.
Anchor links: All 10 nav links (#outdoor, #food-and-drink, #music, #nightlife, #calendar, #map-section, #happy-hour, #sushi, #family-friendly, #free) have matching id attributes on their target sections. #main-content on the skip link also resolves correctly.
Attribution manifest: Present at assets/ATTRIBUTION.md. Full table with 46 entries, license types (CC BY 4.0, CC BY 2.0, CC BY-NC-ND 2.0, CC BY-NC-SA 2.0), author attribution, and source URLs. assets/provenance.json also exists as a machine-readable companion.
Punch List¶
-
Events source gap (blocker for Req 1):
data/events.jsonhas no events withsourcevalues ofdo512,austinchronicle, ortimeout. All 60 events are taggedeventbriteorsupplemental. The filter chips will only surface those two sources. Either re-source some events from the required platforms and update theirsourcefield accordingly, or negotiate a spec change with the director to acceptsupplementalas the substitute for the three missing sources. -
evt_040out of range: "Lens on Nature Photo Walk" (date_start: 2026-06-13) falls 42 days out, beyond the 30-day filter. It will never render. Either move the date to within 30 days or remove the record. -
Dead chip-toggle code in inline script (minor):
index.htmllines 660–666 set up a.filter-chipclick listener that fires before JS populates chips, making it unreachable. No user-facing impact, but it should be removed to avoid confusion. -
sections/martini-bar.jpgis anomalously small (19,255 bytes vs 100–530 KB for other section photos). Worth verifying the image looks acceptable at section-background scale; it may be a low-resolution or cropped file.
Overall Recommendation¶
NEEDS REVISION
The build is 80% complete and solid. All infrastructure passes: Leaflet map with three data layers, happy hour (16 spots, full schema), sushi (13 spots), real-image premium design, zero broken asset paths, clean JS, and correct anchor routing.
The single blocking gap is Requirement 1: the three named sources (do512, austinchronicle, timeout) are absent from events.json. The spec was explicit. Fix: add at least a representative batch of events tagged with those three source values and their source_url pointing to the relevant listing page. The rendering pipeline is ready; it is a data-only change.