Why we knot

KnotNode Studio began with a simple observation: when learning feels soft and structured, hands relax and patterns flow. We design courses that soothe overwhelm while building lasting skill, honoring the patient artistry of macramé.

Mission

To make macramé accessible and restorative by teaching technique with clarity, pacing practice with kindness, and celebrating the human touch in every knot.

Clarity Kindness Craft

Values

  • Teach the why behind every movement.
  • Favor calm repetition over rushed results.
  • Design with inclusivity, accessibility, and joy.

Milestones

2019 — A cord and a notebook

We prototyped the first tension drills and filled our notebooks with friendly diagrams.

2021 — Pilot classes

Our pilot cohort tied 12 pieces each, reporting calmer hands and more consistent spacing.

2026 — KnotNode Studio

We launched a unified learning path and a supportive community space—gentle gradients and all.

Team

AE
Ava Ellis
Founder & Lead Instructor

Ava blends design research with fiber craft to turn knot sequences into learnable rhythms.

RM
River Moore
Curriculum Designer

River sequences lessons with focus cues and micro-checkpoints to build confidence.

JL
Jun Lee
Community Lead

Jun tends our forums, modeling generous feedback and steady encouragement.

`; document.getElementById('site-header').innerHTML = headerHTML; // Inline exact footer const footerHTML = ` `; document.getElementById('site-footer').innerHTML = footerHTML; } function updateCartCount() { const count = localStorage.getItem('knotnode_cart_count') || '0'; const fallows = localStorage.getItem('knotnode_fallows_count') || '0'; const els = ['nav-cart-count','m-cart-count']; els.forEach(id => { const el = document.getElementById(id); if (el) el.textContent = count; }); const fel = document.getElementById('nav-fallows-count'); const mf = document.getElementById('m-fallows-count'); if (fel) fel.textContent = fallows; if (mf) mf.textContent = fallows; } function initTheme() { const apply = (mode) => { const r = document.documentElement; if (mode === 'dark') r.classList.add('dark'); else if (mode === 'light') r.classList.remove('dark'); else { matchMedia('(prefers-color-scheme: dark)').matches ? r.classList.add('dark') : r.classList.remove('dark'); } }; const saved = localStorage.getItem('knotnode_theme') || 'system'; apply(saved); window.__kn_applyTheme = (m) => { localStorage.setItem('knotnode_theme', m); apply(m); }; } function initModals() { const authModal = document.getElementById('auth-modal'); const closeAuth = document.getElementById('close-auth'); const authForm = document.getElementById('auth-form'); const authTitle = document.getElementById('auth-title'); function showAuth(mode) { if (authTitle) authTitle.textContent = mode === 'register' ? 'Create account' : 'Sign in'; authModal.classList.remove('hidden'); authModal.classList.add('flex'); } function hideAuth() { authModal.classList.remove('flex'); authModal.classList.add('hidden'); } // Bind login/register triggers (multiple ids) ['open-login','m-open-login','open-register','m-open-register'].forEach(id => { const el = document.getElementById(id); if (el) { el.addEventListener('click', () => { const mode = id.includes('register') ? 'register' : 'login'; showAuth(mode); }); } }); if (closeAuth) closeAuth.addEventListener('click', hideAuth); if (authForm) authForm.addEventListener('submit', (e) => { e.preventDefault(); alert('Account action completed successfully!'); hideAuth(); authForm.reset(); }); authModal.addEventListener('click', (e) => { if (e.target === authModal) hideAuth(); }); } function initMobileMenu() { const mobileBtn = document.getElementById('open-mobile'); const mobileMenu = document.getElementById('mobile-menu'); if (mobileBtn && mobileMenu) { mobileBtn.addEventListener('click', () => mobileMenu.classList.toggle('hidden')); } } function initThemeBtn() { const themeBtn = document.getElementById('open-theme'); if (themeBtn) { themeBtn.addEventListener('click', () => { const html = document.documentElement; const isDark = html.classList.contains('dark'); const newMode = isDark ? 'light' : 'dark'; if (window.__kn_applyTheme) window.__kn_applyTheme(newMode); }); } } function initCookieBanner() { const banner = document.getElementById('cookie-banner'); if (!banner) return; if (!localStorage.getItem('knotnode_cookie_consent')) { banner.classList.remove('hidden'); } const accept = document.getElementById('cookie-accept'); const decline = document.getElementById('cookie-decline'); if (accept) accept.addEventListener('click', () => { localStorage.setItem('knotnode_cookie_consent', 'accepted'); banner.classList.add('hidden'); }); if (decline) decline.addEventListener('click', () => { localStorage.setItem('knotnode_cookie_consent', 'declined'); banner.classList.add('hidden'); }); } function initAll() { loadHeaderFooter(); setTimeout(() => { updateCartCount(); initTheme(); initModals(); initMobileMenu(); initThemeBtn(); initCookieBanner(); }, 80); } window.onload = initAll;