Julimes

Preview

```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Julimes | The Rugged Frontier</title> <!-- Tailwind CSS --> <script src="https://cdn.tailwindcss.com"></script> <!-- Google Fonts --> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,600;1,400&family=Work+Sans:wght@300;400;500&display=swap" rel="stylesheet"> <!-- Three.js --> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> <!-- GSAP for smooth scroll animation --> <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/ScrollTrigger.min.js"></script> <!-- Simplex Noise for terrain generation --> <script src="https://cdnjs.cloudflare.com/ajax/libs/simplex-noise/2.4.0/simplex-noise.min.js"></script> <script> tailwind.config = { theme: { extend: { colors: { desert: { 100: '#F4ECD8', // Sand 200: '#E6D5B8', // Tan 300: '#D4B896', // Khaki 400: '#C19A6B', // Bronze dark: '#5D4037', // Dark Soil accent: '#20B2AA', // Rio Conchos (Seafoam/Murky) }, sage: '#8FBC8F', terracotta: '#CD7532' }, fontFamily: { serif: ['"Cormorant Garamond"', 'serif'], sans: ['"Work Sans"', 'sans-serif'], }, spacing: { '128': '32rem', } } } } </script> <style> body, html { margin: 0; padding: 0; overflow-x: hidden; background-color: #F4ECD8; color: #3E2723; } /* Paper Grain Overlay */ .grain-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 50; opacity: 0.08; background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E"); } /* Smooth Scrolling */ html { scroll-behavior: smooth; } /* Text Content Container Styling */ .glass-panel { background: rgba(244, 236, 216, 0.75); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); border: 1px solid rgba(210, 180, 140, 0.3); box-shadow: 0 4px 30px rgba(0, 0, 0, 0.05); } .organic-blob { border-radius: 255px 15px 225px 15px / 15px 225px 15px 255px; } /* Loader */ #loader { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: #F4ECD8; z-index: 100; display: flex; justify-content: center; align-items: center; font-family: 'Cormorant Garamond', serif; font-size: 1.5rem; color: #5D4037; transition: opacity 1s ease-out; } #canvas-container { position: fixed; top: 0; left: 0; width: 100%; height: 100vh; z-index: 0; } .content-section { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 2rem; position: relative; z-index: 20; pointer-events: none; /* Let clicks pass through empty areas */ } .content-container { max-width: 45rem; pointer-events: auto; } /* Hide scrollbar for cleaner look but allow scrolling */ ::-webkit-scrollbar { width: 8px; } ::-webkit-scrollbar-track { background: #F4ECD8; } ::-webkit-scrollbar-thumb { background: #C19A6B; border-radius: 4px; } </style> </head> <body> <!-- Grain Texture --> <div class="grain-overlay"></div> <!-- Loading Screen --> <div id="loader"> <div class="flex flex-col items-center"> <span class="mb-4 italic">Entering the Frontier</span> <div class="w-16 h-1 bg-terracotta opacity-50 rounded-full overflow-hidden"> <div class="h-full bg-terracotta animate-pulse w-2/3"></div> </div> </div> </div> <!-- 3D Canvas --> <div id="canvas-container"></div> <!-- Text Content --> <main> <!-- Hero Section --> <section class="content-section" id="hero"> <div class="content-container text-center"> <div class="glass-panel organic-blob p-8 md:p-12 transform transition hover:scale-105 duration-[2s] ease-out"> <h1 class="font-serif text-6xl md:text-8xl text-desert-dark mb-4 italic">Julimes</h1> <p class="font-sans text-lg md:text-xl text-stone-700 tracking-wide uppercase border-t border-stone-400 pt-4 mt-4"> Chihuahua &bull; Mexico </p> </div> </div> </section> <!-- Geography Section --> <section class="content-section" id="geography"> <div class="content-container"> <div class="glass-panel organic-blob p-8 md:p-10 md:rounded-3xl"> <h2 class="font-serif text-4xl md:text-5xl text-desert-dark mb-6">Vast Northern Expanse</h2> <p class="font-serif text-xl md:text-2xl text-stone-700 leading-relaxed mb-6"> Nestled within the vast northern expanse of the Mexican state of Chihuahua, Julimes represents a quintessential, rugged frontier territory. </p> <p class="font-sans text-lg leading-loose text-stone-800"> As a second-level administrative division, its identity is deeply shaped by the dramatic landscapes of the Lower Grande region, characterized by expansive deserts, rugged canyons, and the life-giving ribbon of the Rio Conchos. </p> </div> </div> </section> <!-- Economy Section --> <section class="content-section" id="economy"> <div class="content-container"> <div class="glass-panel organic-blob p-8 md:p-10 md:rounded-3xl"> <h2 class="font-serif text-4xl md:text-5xl text-desert-dark mb-6">The Rhythm of Land</h2> <p class="font-serif text-xl md:text-2xl text-stone-700 leading-relaxed mb-6"> This sparsely populated area sustains a traditional economy largely based on extensive cattle ranching and dryland agriculture, practices intrinsically adapted to the arid climate. </p> <div class="flex items-center gap-4 mt-8 text-stone-600"> <svg class="w-8 h-8 opacity-60" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1" d="M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 104 0 2 2 0 012-2h1.064M15 20.488V18a2 2 0 012-2h3.064M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg> <span class="font-sans italic">Ranching &bull; Resilience &bull; Adaptation</span> </div> </div> </div> </section> <!-- Culture Section --> <section class="content-section" id="culture"> <div class="content-container"> <div class="glass-panel organic-blob p-8 md:p-10 md:rounded-3xl"> <h2 class="font-serif text-4xl md:text-5xl text-desert-dark mb-6">Heritage & Spirit</h2> <p class="font-serif text-xl md:text-2xl text-stone-700 leading-relaxed mb-6"> Culturally, it forms part of the broader northern Mexican <em>charrería</em> and ranching traditions, while also incorporating elements of the region's indigenous heritage. </p> <div class="grid md:grid-cols-2 gap-6 mt-8 font-sans text-stone-700"> <div class="p-4 border-l-4 border-terracotta"> <strong class="block text-desert-dark mb-2">Tradition</strong> The art of horsemanship and the charro suit are living symbols of this frontier identity. </div> <div class="p-4 border-l-4 border-sage"> <strong class="block text-desert-dark mb-2">Ancestry</strong> Indigenous roots whisper through the canyons, blending with Spanish colonial history. </div> </div> </div> </div> </section> <!-- Conclusion --> <section class="content-section" id="finale"> <div class="content-container text-center"> <div class="glass-panel organic-blob p-8 md:p-12"> <h2 class="font-serif text-3xl md:text-4xl text-desert-dark mb-6">Enduring Spirit</h2> <p class="font-serif text-2xl text-stone-700 italic mb-8"> "Julimes embodies the serene, isolated, and self-reliant character of rural Chihuahua, offering a stark contrast to the urban and industrial centers of the state, and stands as a testament to the enduring spirit of Mexico's northern frontier." </p> </div> </div> </section> <footer class="h-24 relative z-20 flex justify-center items-center text-stone-500 font-sans text-sm"> <p>&copy; 2023 Julimes Tribute. Crafted with Biophilic Principles.</p> </footer> </main> <script> // --- Config --- const CONFIG = { fogColor: 0xe8d7ca, // Warm sandy fog skyColor: 0xfff0e6, // Pale morning sky sunColor: 0xffaa55, // Warm golden sun terrainColorLow: 0x8d6e63, // Brown terrainColorHigh: 0xd7ccc8, // Light sand rock waterColor: 0x2dd4bf, // Rio Conchos teal/murky green segmentCount: 64, // Grid res worldSize: 200, noiseScale: 0.03, riverWidth: 8, riverDepth: 12 }; // --- Init Scene --- const container = document.getElementById('canvas-container'); const scene = new THREE.Scene(); scene.fog = new THREE.FogExp2(CONFIG.fogColor, 0.008); scene.background = new THREE.Color(CONFIG.skyColor); const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.set(0, 40, 100); const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); renderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.PCFSoftShadowMap; container.appendChild(renderer.domElement); // --- Helpers --- const simplex = new SimplexNoise(); const getRiverDistance = (x, z) => { // Create a winding river path roughly diagonally from upper left to lower right // Using a combination of sine waves to simulate a natural meander // Adjusted to pass through (0,0) roughly const normalizedX = x / CONFIG.worldSize * 2; // approx -2 to 2 const pathY = Math.sin(normalizedX * 1.5) * (CONFIG.worldSize * 0.4) + Math.cos(normalizedX * 0.5) * (CONFIG.worldSize * 0.1); return Math.abs(z - pathY); }; // --- Terrain Mesh --- const geometry = new THREE.PlaneGeometry(CONFIG.worldSize, CONFIG.worldSize, CONFIG.segmentCount, CONFIG.segmentCount); // Rotate to be XZ plane geometry.rotateX(-Math.PI / 2); const positionAttribute = geometry.attributes.position; const vertex = new THREE.Vector3(); for (let i = 0; i < positionAttribute.count; i++) { vertex.fromBufferAttribute(positionAttribute, i); // 1. Base Noise let elevation = simplex.noise2D(vertex.x * CONFIG.noiseScale, vertex.z * CONFIG.noiseScale) * 10; elevation += simplex.noise2D(vertex.x * CONFIG.noiseScale * 2, vertex.z * CONFIG.noiseScale * 2) * 4; // 2. Carve River Valley const riverDist = getRiverDistance(vertex.x, vertex.z); const riverInfluence = Math.max(0, CONFIG.riverWidth - riverDist) / CONFIG.riverWidth; // 1 at center, 0 at edge // Smooth the influence curve const smoothInfluence = riverInfluence * riverInfluence * (3 - 2 * riverInfluence); elevation -= smoothInfluence * CONFIG.riverDepth; // Flatten very low areas to water level approx if(elevation < -5) elevation = -5; positionAttribute.setY(i, elevation); } geometry.computeVertexNormals(); // Vertex Colors for variation const colors = []; const colorLow = new THREE.Color(CONFIG.terrainColorLow); const colorHigh = new THREE.Color(CONFIG.terrainColorHigh); for (let i = 0; i < positionAttribute.count; i++) { const y = positionAttribute.getY(i); const normalizedHeight = (y + 8) / 18; // Normalize approx -8 to 10 range const clamped = Math.max(0, Math.min(1, normalizedHeight)); const color = colorLow.clone().lerp(colorHigh, clamped); colors.push(color.r, color.g, color.b); } geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3)); const material = new THREE.MeshStandardMaterial({ vertexColors: true, roughness: 0.9, metalness: 0.1, flatShading: true, // Low-poly look, Wabi-Sabi feel }); const terrain = new THREE.Mesh(geometry, material); terrain.receiveShadow = true; scene.add(terrain); // --- River Ribbon --- // Construct a ribbon along the river path const ribbonPoints = []; const steps = 100; const xStart = -CONFIG.worldSize/2 + 10; const xStep = CONFIG.worldSize / steps; for(let i=0; i<=steps; i++) { const x = xStart + i * xStep; const z = Math.sin(x * 0.015) * (CONFIG.worldSize * 0.4) + Math.cos(x * 0.005) * (CONFIG.worldSize * 0.15); ribbonPoints.push(new THREE.Vector3(x, -2, z)); // Slightly below average terrain } const curve = new THREE.CatmullRomCurve3(ribbonPoints); // Create tube geometry for river const ribbonGeo = new THREE.TubeGeometry(curve, 128, 2.5, 8, false); // Flatten it slightly to look like a river bed? Or just a ribbon flowing. // Let's make it a flat strip const ribbonMesh = new THREE.Mesh(ribbonGeo, new THREE.MeshLambertMaterial({ color: CONFIG.waterColor, transparent: true, opacity: 0.7, side: THREE.DoubleSide })); scene.add(ribbonMesh); // --- Lighting --- const ambientLight = new THREE.AmbientLight(0xffffff, 0.4); scene.add(ambientLight); const sunLight = new THREE.DirectionalLight(CONFIG.sunColor, 1.2); sunLight.position.set(50, 80, 50); sunLight.castShadow = true; sunLight.shadow.mapSize.width = 2048; sunLight.shadow.mapSize.height = 2048; sunLight.shadow.camera.near = 0.5; sunLight.shadow.camera.far = 300; sunLight.shadow.camera.left = -100; sunLight.shadow.camera.right = 100; sunLight.shadow.camera.top = 100; sunLight.shadow.camera.bottom = -100; scene.add(sunLight); // --- Particles (Dust) --- const particlesGeo = new THREE.BufferGeometry(); const particleCount = 600; const posArray = new Float32Array(particleCount * 3); for(let i=0; i<particleCount * 3; i++) { posArray[i] = (Math.random() - 0.5) * CONFIG.worldSize * 1.5; } particlesGeo.setAttribute('position', new THREE.BufferAttribute(posArray, 3)); const particlesMat = new THREE.PointsMaterial({ size: 0.4, color: 0x5D4037, transparent: true, opacity: 0.4, blending: THREE.AdditiveBlending }); const particlesMesh = new THREE.Points(particlesGeo, particlesMat); scene.add(particlesMesh); // --- Interaction Logic --- let scrollPercent = 0; const totalHeight = document.body.scrollHeight - window.innerHeight; // Map scroll to camera flight path // Camera start: Hero view (0) // Camera end: Low angle flying over terrain const startPos = new THREE.Vector3(0, 30, 90); const endPos = new THREE.Vector3(20, 5, -60); // End near the bottom of page const startTarget = new THREE.Vector3(0, 0, 0); const endTarget = new THREE.Vector3(0, 0, 80); // Look up the river function updateCamera() { // Linear interpolation based on scroll const t = Math.max(0, Math.min(1, scrollPercent)); // Lerp position camera.position.lerpVectors(startPos, endPos, t); // Lerp target (lookAt) const currentTarget = new THREE.Vector3().lerpVectors(startTarget, endTarget, t); camera.lookAt(currentTarget); // Rotate terrain slightly based on scroll to add dynamism terrain.rotation.z = scrollPercent * Math.PI * 0.1; // Gentle turn } // Scroll Event (using raw scroll for simplicity, though GSAP ScrollTrigger is smoother) window.addEventListener('scroll', () => { scrollPercent = window.scrollY / totalHeight; }); // Mouse Interaction (Parallax) let mouseX = 0; let mouseY = 0; window.addEventListener('mousemove', (e) => { mouseX = (e.clientX / window.innerWidth) * 2 - 1; mouseY = -(e.clientY / window.innerHeight) * 2 + 1; }); // --- Animation Loop --- const clock = new THREE.Clock(); function animate() { const time = clock.getElapsedTime(); // Subtle particle movement particlesMesh.rotation.y = time * 0.02; const positions = particlesGeo.attributes.position.array; for(let i=1; i<positions.length; i+=3) { positions[i] += Math.sin(time + positions[i-1]) * 0.02; // Bob up and down } particlesGeo.attributes.position.needsUpdate = true; // Subtle terrain wave (simulate heat haze or flowing sand - slow) terrain.position.y = Math.sin(time * 0.1) * 0.2; // Mouse influence on camera rig (secondary motion) const parallaxX = mouseX * 2; const parallaxY = mouseY * 2; camera.position.x += parallaxX * 0.05; camera.position.y += parallaxY * 0.05; // Call update updateCamera(); renderer.render(scene, camera); requestAnimationFrame(animate); } // --- Responsive --- window.addEventListener('resize', () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); }); // --- Init --- // Hide loader after "simulated" init window.onload = () => { setTimeout(() => { document.getElementById('loader').style.opacity = '0'; setTimeout(() => { document.getElementById('loader').style.display = 'none'; }, 1000); }, 1500); animate(); // initial target set camera.lookAt(startTarget); }; // GSAP for flawless scrolling integration (optional enhancement for smoothness) gsap.registerPlugin(ScrollTrigger); // Create a proxy object to sync GSAP scroll with our scrollPercent variable if desired // But the raw scroll + lerp in the loop is already very smooth if we use damping. // Let's stick to the manual implementation to keep strict control over the flight path, // but we can use GSAP to animate sections appearance. gsap.utils.toArray('.content-container').forEach(container => { gsap.from(container, { scrollTrigger: { trigger: container, start: "top 80%", toggleActions: "play none none reverse" }, y: 50, opacity: 0, duration: 1.5, ease: "power3.out" }); }); </script> </body> </html> ```

virtual tours

Thanks to our Virtual Reality technology, we transport you to Julimes for unique observations.
This feature requires payment.

Upgrade to the premium version!

Air quality

The data below describes the current air quality at Julimes. Based on the European Air Quality Index (AQI), calculated using the data below, {AQI}

Dust 0 μg/m³
Carbon Dioxide CO2 450 ppm
Nitrogen Dioxide NO2 6.8 μg/m³
Sulphur Dioxide SO2 0.9 μg/m³
Ammonia NH3 3.4 μg/m³

Meteo

The data below describes the current weather in Julimes.

Temperature 12.8 °C
Rain 0 mm
Showers 0 mm
Snowfall 0 cm
Cloud Cover Total 96 %
Sea Level Pressure 1013.7 hPa
Wind Speed 20.3 km/h