{"id":12,"date":"2025-09-15T06:20:55","date_gmt":"2025-09-15T06:20:55","guid":{"rendered":"https:\/\/keeganmeistre.co.za\/?page_id=12"},"modified":"2025-09-15T08:29:37","modified_gmt":"2025-09-15T08:29:37","slug":"home","status":"publish","type":"page","link":"https:\/\/keeganmeistre.co.za\/index.php\/home\/","title":{"rendered":"Home"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"12\" class=\"elementor elementor-12\">\n\t\t\t\t<div class=\"elementor-element elementor-element-fe29d24 e-flex e-con-boxed e-con e-parent\" data-id=\"fe29d24\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-328af77 elementor-widget elementor-widget-spacer\" data-id=\"328af77\" data-element_type=\"widget\" data-widget_type=\"spacer.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-spacer\">\n\t\t\t<div class=\"elementor-spacer-inner\"><\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-139a3a8 e-con-full e-flex e-con e-parent\" data-id=\"139a3a8\" data-element_type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-8fd8b64 elementor-widget elementor-widget-html\" data-id=\"8fd8b64\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!-- Butterfly PNG particles: smooth motion + soft bounce + cursor dispersion -->\r\n\r\n<div class=\"flow-wrap\">\r\n  <canvas id=\"flowShapes\"\r\n    data-shape-url=\"https:\/\/keeganmeistre.co.za\/wp-content\/uploads\/2025\/09\/butterfly-white-scaled.png\"\r\n    data-bg=\"#23211d\"\r\n    data-tile=\"160\"\r\n    data-scale=\"0.25\"\r\n    data-speed=\"0.35\"\r\n    data-intensity=\"1.2\"\r\n    data-avoid=\"true\"\r\n    data-avoid-radius=\"0.36\"\r\n    data-avoid-burst=\"900\"\r\n    data-avoid-lead=\"0.12\"\r\n    data-avoid-threshold=\"0.12\"\r\n    data-avoid-min=\"0.08\"\r\n    data-count-delta=\"10\"\r\n    data-smooth=\"0.16\"          <!-- pointer smoothing (0.1\u20130.3) -->\r\n    aria-hidden=\"true\"><\/canvas>\r\n\r\n  <style>\r\n    .flow-wrap { position: fixed; inset: 0; z-index: -1; }\r\n    #flowShapes { width: 100%; height: 100%; display: block; }\r\n    .flow-glass { background: rgba(10,12,14,.28); backdrop-filter: blur(12px);\r\n                  border: 1px solid rgba(255,255,255,.08); border-radius: 18px; }\r\n  <\/style>\r\n<\/div>\r\n\r\n<script>\r\n(function(){\r\n  function start(){\r\n    const cvs = document.getElementById('flowShapes');\r\n    if(!cvs) return;\r\n\r\n    const ctx  = cvs.getContext('2d', { alpha: true });\r\n    const DPR  = Math.min(window.devicePixelRatio || 1, 2);\r\n\r\n    \/\/ Options\r\n    const bg        = cvs.dataset.bg || '#23211d';\r\n    const tilePx    = Math.max(24, +cvs.dataset.tile || 160);\r\n    const scale     = Math.max(0.1, +cvs.dataset.scale || 0.25);\r\n    const speed     = Math.max(0.01, +cvs.dataset.speed || 0.35);\r\n    const intensity = Math.max(0.1, +cvs.dataset.intensity || 1.2);\r\n    const fixedCount = cvs.dataset.count ? Math.max(1, parseInt(cvs.dataset.count, 10)) : null;\r\n    const countDelta = cvs.dataset.countDelta ? parseInt(cvs.dataset.countDelta, 10) : 0;\r\n\r\n    \/\/ Avoid \/ disperse\r\n    const AVOID_ENABLED   = (cvs.dataset.avoid || 'true') !== 'false';\r\n    const AVOID_RADIUS_FR = Math.max(0.05, +cvs.dataset.avoidRadius || 0.36);\r\n    const AVOID_BURST     = Math.max(50,  +cvs.dataset.avoidBurst  || 900);\r\n    const AVOID_LEAD      = Math.max(0,   +cvs.dataset.avoidLead   || 0.12);\r\n    const AVOID_SPEED_THR = Math.max(0.01,+cvs.dataset.avoidThreshold || 0.12);\r\n    const AVOID_MIN_FR    = Math.max(0.02,+cvs.dataset.avoidMin    || 0.08); \/\/ hard ring\r\n\r\n    \/\/ Smoothing \/ physics clamps\r\n    const PTR_SMOOTH = Math.min(0.5, Math.max(0.05, +cvs.dataset.smooth || 0.16)); \/\/ exp smoothing\r\n    const MAX_ACCEL  = 2600;  \/\/ px\/s^2\r\n    const MAX_SPEED  = 240;   \/\/ px\/s\r\n    const LIN_DAMP   = 0.985; \/\/ velocity damping per frame\r\n    const SPRING_K   = 1400;  \/\/ spring stiffness in the no-fly ring\r\n\r\n    \/\/ Size & resize\r\n    function fit(){\r\n      const w = Math.floor(cvs.clientWidth  * DPR);\r\n      const h = Math.floor(cvs.clientHeight * DPR);\r\n      if (cvs.width !== w || cvs.height !== h){ cvs.width = w; cvs.height = h; }\r\n    }\r\n\r\n    \/\/ Load PNG sprite\r\n    const img = new Image();\r\n    img.crossOrigin = 'anonymous';\r\n    img.src = (cvs.dataset.shapeUrl || '').trim();\r\n\r\n    const sprite = document.createElement('canvas');\r\n    const sctx = sprite.getContext('2d');\r\n\r\n    function buildSprite(){\r\n      const size = Math.round(tilePx * DPR);\r\n      const drawSize = Math.max(8, Math.round(size * scale));\r\n      sprite.width = sprite.height = size;\r\n      sctx.clearRect(0,0,size,size);\r\n      if (img.complete && img.naturalWidth){\r\n        sctx.imageSmoothingEnabled = true;\r\n        sctx.imageSmoothingQuality = 'high';\r\n        const ox = (size - drawSize) \/ 2;\r\n        const oy = (size - drawSize) \/ 2;\r\n        sctx.drawImage(img, ox, oy, drawSize, drawSize);\r\n      }\r\n    }\r\n\r\n    \/\/ Particles\r\n    let particles = [];\r\n    function estimateGridCount(){\r\n      const size = Math.round(tilePx * DPR);\r\n      const cols = Math.ceil(cvs.width \/ size) + 1;\r\n      const rows = Math.ceil(cvs.height \/ size) + 1;\r\n      return Math.max(12, Math.floor(cols * rows * 0.5));\r\n    }\r\n    function seedParticles(){\r\n      particles.length = 0;\r\n      const base = fixedCount || estimateGridCount();\r\n      const N = Math.max(1, base + countDelta);\r\n      for (let i = 0; i < N; i++){\r\n        \/\/ smooth wander seeds\r\n        const s1 = Math.random()*Math.PI*2;\r\n        const s2 = Math.random()*Math.PI*2;\r\n        particles.push({\r\n          x: Math.random() * cvs.width,\r\n          y: Math.random() * cvs.height,\r\n          vx: 0, vy: 0,\r\n          ax: 0, ay: 0,     \/\/ acceleration (for smoothing)\r\n          rot: Math.random() * Math.PI * 2,\r\n          spin: (Math.random()*2 - 1) * 0.35,\r\n          scl: 1 + (Math.random()*0.15 - 0.075),\r\n          seed1: s1, seed2: s2\r\n        });\r\n      }\r\n    }\r\n\r\n    \/\/ Pointer + smoothing + prediction\r\n    const mouse = { \r\n      x:0.5, y:0.5,  \/\/ smoothed\r\n      tx:0.5, ty:0.5,\/\/ target (raw)\r\n      vx:0, vy:0, vmag:0,\r\n      inside:false\r\n    };\r\n\r\n    function updateFromEvent(e){\r\n      const r  = cvs.getBoundingClientRect();\r\n      const pt = ('touches' in e ? e.touches[0] : e);\r\n      const cx = pt.clientX, cy = pt.clientY;\r\n      mouse.inside = (cx >= r.left && cx <= r.right && cy >= r.top && cy <= r.bottom);\r\n      mouse.tx = (cx - r.left) \/ r.width;\r\n      mouse.ty = (cy - r.top)  \/ r.height;\r\n    }\r\n    function onMove(e){ updateFromEvent(e); }\r\n    function onEnter(){ mouse.inside = true; }\r\n    function onLeave(){ mouse.inside = false; }\r\n\r\n    window.addEventListener('mousemove',  onMove,  { passive: true });\r\n    window.addEventListener('touchmove',  onMove,  { passive: true });\r\n    window.addEventListener('mouseenter', onEnter, { passive: true });\r\n    document.addEventListener('mouseleave', onLeave, { passive: true });\r\n    window.addEventListener('touchstart', onEnter, { passive: true });\r\n\r\n    \/\/ Animation\r\n    let last = performance.now();\r\n    let tSec = 0; \/\/ time in seconds\r\n    let rafId = null;\r\n\r\n    function step(now){\r\n      const dt = Math.min(0.05, (now - last) \/ 1000);\r\n      last = now;\r\n      tSec += dt;\r\n\r\n      \/\/ smooth pointer (exponential)\r\n      const pxPrev = mouse.x, pyPrev = mouse.y;\r\n      mouse.x += (mouse.tx - mouse.x) * PTR_SMOOTH;\r\n      mouse.y += (mouse.ty - mouse.y) * PTR_SMOOTH;\r\n      mouse.vx = (mouse.x - pxPrev) \/ dt;\r\n      mouse.vy = (mouse.y - pyPrev) \/ dt;\r\n      mouse.vmag = Math.hypot(mouse.vx, mouse.vy);\r\n\r\n      \/\/ background\r\n      ctx.globalCompositeOperation = 'source-over';\r\n      ctx.globalAlpha = 1;\r\n      ctx.fillStyle = bg;\r\n      ctx.fillRect(0, 0, cvs.width, cvs.height);\r\n\r\n      const minDim = Math.min(cvs.width, cvs.height);\r\n      const repelRadius = minDim * AVOID_RADIUS_FR;\r\n      const repelPow    = repelRadius * repelRadius;\r\n      const noFlyR      = minDim * AVOID_MIN_FR;\r\n      const noFlyPow    = noFlyR * noFlyR;\r\n\r\n      const spriteSize = Math.round(tilePx * DPR);\r\n      const leadX = (mouse.x + (mouse.vx * AVOID_LEAD)) * cvs.width;\r\n      const leadY = (mouse.y + (mouse.vy * AVOID_LEAD)) * cvs.height;\r\n\r\n      \/\/ constants for wander\r\n      const WANDER_FORCE = 36 * speed;   \/\/ smooth ambient motion\r\n      const WANDER_FREQ1 = 0.35;\r\n      const WANDER_FREQ2 = 0.48;\r\n\r\n      for (const p of particles){\r\n        \/\/ reset accel\r\n        let ax = 0, ay = 0;\r\n\r\n        \/\/ smooth wander (continuous)\r\n        ax += Math.cos(p.seed1 + tSec * WANDER_FREQ1) * WANDER_FORCE;\r\n        ay += Math.sin(p.seed2 + tSec * WANDER_FREQ2) * WANDER_FORCE;\r\n\r\n        if (AVOID_ENABLED && mouse.inside){\r\n          const mx = mouse.x * cvs.width;\r\n          const my = mouse.y * cvs.height;\r\n\r\n          \/\/ hard no-fly ring via spring (soft, non-snappy)\r\n          let dx = p.x - mx, dy = p.y - my;\r\n          let d2 = dx*dx + dy*dy + 1e-6;\r\n\r\n          if (d2 < noFlyPow){\r\n            const d = Math.sqrt(d2);\r\n            const nx = dx \/ d, ny = dy \/ d;\r\n            const stretch = (noFlyR - d);\r\n            const springF = SPRING_K * stretch; \/\/ Hooke's law\r\n            ax += nx * springF;\r\n            ay += ny * springF;\r\n          }\r\n\r\n          \/\/ baseline repulsion in wider radius\r\n          dx = p.x - mx; dy = p.y - my;\r\n          d2 = dx*dx + dy*dy + 1e-6;\r\n          if (d2 < repelPow){\r\n            const d = Math.sqrt(d2);\r\n            const nx = dx \/ d, ny = dy \/ d;\r\n            const falloff = 1 - (d2 \/ repelPow);\r\n            const baseF = (220 * intensity) * falloff;\r\n            ax += nx * baseF;\r\n            ay += ny * baseF;\r\n          }\r\n\r\n          \/\/ anticipatory burst in front of moving cursor\r\n          if (mouse.vmag * dt > AVOID_SPEED_THR * 0.5){\r\n            dx = p.x - leadX; dy = p.y - leadY;\r\n            d2 = dx*dx + dy*dy + 1e-6;\r\n            if (d2 < repelPow){\r\n              const d = Math.sqrt(d2);\r\n              const nx = dx \/ d, ny = dy \/ d;\r\n              const falloff = 1 - (d2 \/ repelPow);\r\n              const burst = (AVOID_BURST * intensity) * falloff;\r\n              ax += nx * burst;\r\n              ay += ny * burst;\r\n            }\r\n          }\r\n        }\r\n\r\n        \/\/ clamp acceleration\r\n        const amag = Math.hypot(ax, ay);\r\n        if (amag > MAX_ACCEL){ ax = ax \/ amag * MAX_ACCEL; ay = ay \/ amag * MAX_ACCEL; }\r\n\r\n        \/\/ integrate velocity with damping\r\n        p.vx = (p.vx + ax * dt) * LIN_DAMP;\r\n        p.vy = (p.vy + ay * dt) * LIN_DAMP;\r\n\r\n        \/\/ clamp speed\r\n        const vmag = Math.hypot(p.vx, p.vy);\r\n        if (vmag > MAX_SPEED){ p.vx = p.vx \/ vmag * MAX_SPEED; p.vy = p.vy \/ vmag * MAX_SPEED; }\r\n\r\n        \/\/ integrate position\r\n        p.x += p.vx * dt;\r\n        p.y += p.vy * dt;\r\n\r\n        \/\/ spin based on speed (subtle)\r\n        p.rot += (p.spin + 0.0006 * vmag) * dt;\r\n\r\n        \/\/ wrap edges\r\n        const margin = spriteSize * 0.5 + 10;\r\n        if (p.x < -margin) p.x = cvs.width + margin; else if (p.x > cvs.width + margin) p.x = -margin;\r\n        if (p.y < -margin) p.y = cvs.height + margin; else if (p.y > cvs.height + margin) p.y = -margin;\r\n\r\n        \/\/ draw\r\n        if (sprite.width > 0){\r\n          ctx.save();\r\n          ctx.translate(p.x, p.y);\r\n          ctx.rotate(p.rot * 0.12);\r\n          ctx.scale(p.scl, p.scl);\r\n          ctx.drawImage(sprite, -spriteSize*0.5, -spriteSize*0.5);\r\n          ctx.restore();\r\n        }\r\n      }\r\n\r\n      requestAnimationFrame(step);\r\n    }\r\n\r\n    function init(){\r\n      fit();\r\n      buildSprite();\r\n      seedParticles();\r\n      requestAnimationFrame(step);\r\n    }\r\n\r\n    window.addEventListener('resize', ()=>{ fit(); seedParticles(); });\r\n    document.addEventListener('visibilitychange', ()=>{ \/* keep running; optional pause *\/ });\r\n\r\n    if (img.complete && img.naturalWidth){ init(); }\r\n    else { img.onload = init; img.onerror = ()=>{ console.warn('Butterfly PNG failed to load.'); fit(); seedParticles(); requestAnimationFrame(step); }; }\r\n  }\r\n\r\n  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', start);\r\n  else start();\r\n})();\r\n<\/script>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d034e27 elementor-widget elementor-widget-image\" data-id=\"d034e27\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img fetchpriority=\"high\" decoding=\"async\" width=\"1024\" height=\"724\" src=\"https:\/\/keeganmeistre.co.za\/wp-content\/uploads\/2025\/09\/butterfly2-1024x724.png\" class=\"attachment-large size-large wp-image-85\" alt=\"\" srcset=\"https:\/\/keeganmeistre.co.za\/wp-content\/uploads\/2025\/09\/butterfly2-1024x724.png 1024w, https:\/\/keeganmeistre.co.za\/wp-content\/uploads\/2025\/09\/butterfly2-300x212.png 300w, https:\/\/keeganmeistre.co.za\/wp-content\/uploads\/2025\/09\/butterfly2-768x543.png 768w, https:\/\/keeganmeistre.co.za\/wp-content\/uploads\/2025\/09\/butterfly2-1536x1086.png 1536w, https:\/\/keeganmeistre.co.za\/wp-content\/uploads\/2025\/09\/butterfly2-2048x1448.png 2048w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4b07802 elementor-widget elementor-widget-heading\" data-id=\"4b07802\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Coming Soon<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-23d279b elementor-widget elementor-widget-image\" data-id=\"23d279b\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"1024\" height=\"242\" src=\"https:\/\/keeganmeistre.co.za\/wp-content\/uploads\/2025\/09\/on-the-sumit-2-1024x242.png\" class=\"attachment-large size-large wp-image-86\" alt=\"\" srcset=\"https:\/\/keeganmeistre.co.za\/wp-content\/uploads\/2025\/09\/on-the-sumit-2-1024x242.png 1024w, https:\/\/keeganmeistre.co.za\/wp-content\/uploads\/2025\/09\/on-the-sumit-2-300x71.png 300w, https:\/\/keeganmeistre.co.za\/wp-content\/uploads\/2025\/09\/on-the-sumit-2-768x182.png 768w, https:\/\/keeganmeistre.co.za\/wp-content\/uploads\/2025\/09\/on-the-sumit-2-1536x363.png 1536w, https:\/\/keeganmeistre.co.za\/wp-content\/uploads\/2025\/09\/on-the-sumit-2-2048x484.png 2048w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ad0b4db elementor-widget elementor-widget-heading\" data-id=\"ad0b4db\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">experiences@onthesummit.co.za  <br> +27 72 725-6480<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Coming Soon experiences@onthesummit.co.za +27 72 725-6480<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"neve_meta_sidebar":"full-width","neve_meta_container":"full-width","neve_meta_enable_content_width":"off","neve_meta_content_width":100,"neve_meta_title_alignment":"","neve_meta_author_avatar":"","neve_post_elements_order":"","neve_meta_disable_header":"on","neve_meta_disable_footer":"on","neve_meta_disable_title":"on","footnotes":""},"class_list":["post-12","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/keeganmeistre.co.za\/index.php\/wp-json\/wp\/v2\/pages\/12","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/keeganmeistre.co.za\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/keeganmeistre.co.za\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/keeganmeistre.co.za\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/keeganmeistre.co.za\/index.php\/wp-json\/wp\/v2\/comments?post=12"}],"version-history":[{"count":117,"href":"https:\/\/keeganmeistre.co.za\/index.php\/wp-json\/wp\/v2\/pages\/12\/revisions"}],"predecessor-version":[{"id":137,"href":"https:\/\/keeganmeistre.co.za\/index.php\/wp-json\/wp\/v2\/pages\/12\/revisions\/137"}],"wp:attachment":[{"href":"https:\/\/keeganmeistre.co.za\/index.php\/wp-json\/wp\/v2\/media?parent=12"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}