The Bangerville Fishing Report
🌙 Solunar Predictions
Solunar Score: 78 / 100
Major: 6:10 AM – 8:00 AM
Minor: 1:20 PM – 2:05 PM
Moon Phase: Waxing Gibbous
Moonrise: 5:42 PM • Moonset: 4:12 AM
Solunar times are approximate demo values.
🌬️ Wind Map
Live wind overview for the Gaviota → Malibu stretch.
Powered by Windy.com — live wind overlay.
Best Window
6:45 AM – 9:10 AM
🌊 Surf & Conditions
Swell: 2–3 ft @ 14s
Direction: WNW 285°
Wind: 4 mph offshore
Water Temp: 59°F
Water Clarity: Clean
📈 Tide Chart — Ventura, CA
Tide forecasts by
SeaLegs • NOAA Station #9411189 Ventura, CA
🎣 Shore Report
• Perch biting at Leo Carrillo on sand crabs
• Corbina cruising the inside at Zuma
• Halibut caught near County Line on swimbaits
🚤 Boat Report
• Ventura boats limiting on rockfish
• Lingcod at 120–150 ft on jigs
• Sheephead biting on shrimp + squid combo
🔥 Today’s Best Bet
Spot: Leo Carrillo
Bait: Sand crabs
Rig: Carolina rig, 6lb fluoro
Why: Clean water, rising tide, light wind
const now = new Date();
const pad = n => String(n).padStart(2,’0′);
const today = `${now.getFullYear()}${pad(now.getMonth()+1)}${pad(now.getDate())}`;
document.getElementById(‘tideDate’).textContent =
now.toLocaleDateString(‘en-US’,{weekday:’short’,month:’short’,day:’numeric’});
const url = `https://api.tidesandcurrents.noaa.gov/api/prod/datagetter` +
`?begin_date=${today}&end_date=${today}` +
`&station=9411189&product=predictions&datum=MLLW` +
`&time_zone=lst_ldt&interval=h&units=english` +
`&application=bangerville&format=json`;
let labels = [], data = [];
try {
const res = await fetch(url);
const json = await res.json();
if (!json.predictions) throw new Error(‘no data’);
json.predictions.forEach(p => {
const hour = parseInt(p.t.split(‘ ‘)[1].split(‘:’)[0]);
const h12 = hour === 0 ? 12 : hour > 12 ? hour – 12 : hour;
labels.push(h12 + (hour < 12 ? 'AM' : 'PM'));
data.push(parseFloat(p.v));
});
document.getElementById('tideLoading').style.display = 'none';
// High/Low badges
const peaks = [];
for (let i = 1; i < data.length - 1; i++) {
if (data[i] >= data[i-1] && data[i] >= data[i+1]) peaks.push({type:’High’, time:labels[i], val:data[i]});
if (data[i] <= data[i-1] && data[i] <= data[i+1]) peaks.push({type:'Low', time:labels[i], val:data[i]});
}
document.getElementById('tideHighLow').innerHTML = peaks.map(p =>
`
${p.type}
${p.time} ${p.val.toFixed(1)} ft`
).join(”);
} catch(e) {
document.getElementById(‘tideLoading’).textContent = ‘⚠️ Live data unavailable — showing estimated tides.’;
labels = [’12AM’,’1AM’,’2AM’,’3AM’,’4AM’,’5AM’,’6AM’,’7AM’,’8AM’,’9AM’,’10AM’,’11AM’,
’12PM’,’1PM’,’2PM’,’3PM’,’4PM’,’5PM’,’6PM’,’7PM’,’8PM’,’9PM’,’10PM’,’11PM’];
data = [1.8,2.4,3.1,3.8,4.3,4.5,4.2,3.6,2.8,2.0,1.3,0.9,0.8,1.1,1.6,2.2,2.9,3.5,3.9,3.6,2.9,2.2,1.8,1.5];
}
new Chart(document.getElementById(‘tideChart’), {
type: ‘line’,
data: {
labels,
datasets: [{
label: ‘Tide Height (ft)’, data,
borderColor: ‘#39FF14’, backgroundColor: ‘rgba(57,255,20,0.15)’,
tension: 0.4, fill: true, borderWidth: 3, pointRadius: 0
}]
},
options: {
responsive: true,
plugins: {
legend: { display: false },
tooltip: { callbacks: { label: c => ` ${c.parsed.y.toFixed(2)} ft` } }
},
scales: {
y: { beginAtZero: false, grid: { color: ‘rgba(255,255,255,0.1)’ }, ticks: { color: ‘#aaa’, callback: v => v.toFixed(1)+’ ft’ } },
x: { grid: { color: ‘rgba(255,255,255,0.05)’ }, ticks: { color: ‘#aaa’, maxTicksLimit: 13 } }
}
}
});
}
loadTideChart();
/* ── LEAFLET MAPS ───────────────────────────────────────── */
// OpenStreetMap tiles — fast, free, no API key
const TILE = ‘https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png’;
const ATTR = ‘©
OpenStreetMap‘;
const ICON = L.divIcon({
className: ”,
html: ‘
‘,
iconSize: [16,16], iconAnchor: [8,8]
});
function hideSpinner(id) {
const el = document.getElementById(id);
if (el) { el.style.opacity = ‘0’; setTimeout(() => el.remove(), 400); }
}
function makeMap(id, spinnerId, lat, lng, zoom) {
const map = L.map(id, { zoomControl:true, scrollWheelZoom:false }).setView([lat,lng], zoom);
const layer = L.tileLayer(TILE, { attribution:ATTR, maxZoom:19 }).addTo(map);
layer.on(‘load’, () => hideSpinner(spinnerId));
// Fallback — hide spinner after 6s even if tiles are slow
setTimeout(() => hideSpinner(spinnerId), 6000);
return map;
}
const mainMap = makeMap(‘mainMap’, ‘mainSpinner’, 34.0412, -118.9625, 13);
const structureMap = makeMap(‘structureMap’, ‘structureSpinner’, 34.04, -118.96, 11);
let mainPin = L.marker([34.0412,-118.9625], {icon:ICON}).addTo(mainMap);
let structPin = L.marker([34.04,-118.96], {icon:ICON}).addTo(structureMap);
/* ── BEACH DATA ─────────────────────────────────────────── */
const beaches = {
“zuma”: {
window:”7:10 AM – 9:45 AM”, spot:”Zuma Beach”, confidence:”76%”,
swell:”Swell: 3–4 ft @ 12s”, direction:”Direction: W 270°”,
wind:”Wind: 5 mph offshore”, temp:”Water Temp: 60°F”, clarity:”Water Clarity: Light green”,
shore:[“• Corbina cruising the inside”,”• Perch on sandworms”,”• Halibut near the river mouth”],
boat:[“• Rockfish 2 miles out”,”• Lingcod at 140 ft”,”• Sheephead on shrimp”],
bestBet:{spot:”Zuma Beach”,bait:”Sand crabs”,rig:”Carolina rig”,why:”Clean water + rising tide”},
lat:34.021, lng:-118.823, zoom:13, sLat:34.021, sLng:-118.823, sZoom:11,
windSrc:”https://embed.windy.com/embed2.html?lat=34.021&lon=-118.823&detailLat=34.021&detailLon=-118.823&width=650&height=300&zoom=11&level=surface&overlay=wind&product=ecmwf&menu=&message=true&marker=true&calendar=now&pressure=&type=map&location=coordinates&detail=&metricWind=mph&metricTemp=%C2%B0F&radarRange=-1″
},
“leo”: {
window:”6:30 AM – 8:50 AM”, spot:”Leo Carrillo”, confidence:”88%”,
swell:”Swell: 2–3 ft @ 15s”, direction:”Direction: WNW 285°”,
wind:”Wind: 3 mph offshore”, temp:”Water Temp: 59°F”, clarity:”Water Clarity: Clean”,
shore:[“• Perch biting on sand crabs”,”• Corbina spotted in the trough”,”• Halibut on swimbaits”],
boat:[“• Rockfish limits offshore”,”• Lingcod at 120 ft”,”• Sheephead on shrimp”],
bestBet:{spot:”Leo Carrillo”,bait:”Sand crabs”,rig:”Carolina rig”,why:”Clean water + structure”},
lat:34.046, lng:-118.933, zoom:13, sLat:34.046, sLng:-118.933, sZoom:11,
windSrc:”https://embed.windy.com/embed2.html?lat=34.046&lon=-118.933&detailLat=34.046&detailLon=-118.933&width=650&height=300&zoom=11&level=surface&overlay=wind&product=ecmwf&menu=&message=true&marker=true&calendar=now&pressure=&type=map&location=coordinates&detail=&metricWind=mph&metricTemp=%C2%B0F&radarRange=-1″
},
“county line”: {
window:”6:45 AM – 9:10 AM”, spot:”County Line”, confidence:”82%”,
swell:”Swell: 2–3 ft @ 14s”, direction:”Direction: WNW 285°”,
wind:”Wind: 4 mph offshore”, temp:”Water Temp: 59°F”, clarity:”Water Clarity: Clean”,
shore:[“• Halibut on swimbaits”,”• Perch on sand crabs”,”• Corbina in the inside”],
boat:[“• Rockfish limits”,”• Lingcod at 150 ft”,”• Sheephead on shrimp”],
bestBet:{spot:”County Line”,bait:”Sand crabs”,rig:”Carolina rig”,why:”Clean water + rising tide”},
lat:34.0412, lng:-118.9625, zoom:13, sLat:34.04, sLng:-118.96, sZoom:11,
windSrc:”https://embed.windy.com/embed2.html?lat=34.04&lon=-118.96&detailLat=34.04&detailLon=-118.96&width=650&height=300&zoom=11&level=surface&overlay=wind&product=ecmwf&menu=&message=true&marker=true&calendar=now&pressure=&type=map&location=coordinates&detail=&metricWind=mph&metricTemp=%C2%B0F&radarRange=-1″
}
};
const DEFAULT = beaches[“county line”];
function applyBeach(b) {
document.getElementById(“bestWindow”).textContent = b.window;
document.getElementById(“bestSpot”).textContent = b.spot;
document.getElementById(“confidence”).textContent = b.confidence;
document.getElementById(“swell”).textContent = b.swell;
document.getElementById(“direction”).textContent = b.direction;
document.getElementById(“windCond”).textContent = b.wind;
document.getElementById(“temp”).textContent = b.temp;
document.getElementById(“clarity”).textContent = b.clarity;
document.getElementById(“shore1”).textContent = b.shore[0];
document.getElementById(“shore2”).textContent = b.shore[1];
document.getElementById(“shore3”).textContent = b.shore[2];
document.getElementById(“boat1”).textContent = b.boat[0];
document.getElementById(“boat2”).textContent = b.boat[1];
document.getElementById(“boat3”).textContent = b.boat[2];
document.getElementById(“bestBetSpot”).textContent = “Spot: ” + b.bestBet.spot;
document.getElementById(“bestBetBait”).textContent = “Bait: ” + b.bestBet.bait;
document.getElementById(“bestBetRig”).textContent = “Rig: ” + b.bestBet.rig;
document.getElementById(“bestBetWhy”).textContent = “Why: ” + b.bestBet.why;
mainMap.setView([b.lat, b.lng], b.zoom);
mainPin.remove();
mainPin = L.marker([b.lat, b.lng], {icon:ICON}).addTo(mainMap);
structureMap.setView([b.sLat, b.sLng], b.sZoom);
structPin.remove();
structPin = L.marker([b.sLat, b.sLng], {icon:ICON}).addTo(structureMap);
document.getElementById(“windFrame”).src = b.windSrc;
}
applyBeach(DEFAULT);
document.getElementById(“searchBar”).addEventListener(“input”, function () {
const q = this.value.toLowerCase().trim();
if (beaches[q]) {
applyBeach(beaches[q]);
document.getElementById(“returnBtn”).style.display = “block”;
}
});
document.getElementById(“returnBtn”).onclick = () => {
document.getElementById(“searchBar”).value = “”;
document.getElementById(“returnBtn”).style.display = “none”;
applyBeach(DEFAULT);
};
}; // end window.onload