<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: InfernusReal</title>
    <description>The latest articles on DEV Community by InfernusReal (@infernusreal).</description>
    <link>https://dev.to/infernusreal</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3592408%2Fda56df6f-b362-4bf8-8748-c9d886e912c9.jpeg</url>
      <title>DEV Community: InfernusReal</title>
      <link>https://dev.to/infernusreal</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/infernusreal"/>
    <language>en</language>
    <item>
      <title>ScrollForge: Causal Graph Programming — unify state, logic, and style.</title>
      <dc:creator>InfernusReal</dc:creator>
      <pubDate>Sat, 01 Nov 2025 13:37:16 +0000</pubDate>
      <link>https://dev.to/infernusreal/scrollforge-causal-graph-programming-unify-state-logic-and-style-4025</link>
      <guid>https://dev.to/infernusreal/scrollforge-causal-graph-programming-unify-state-logic-and-style-4025</guid>
      <description>&lt;p&gt;&lt;strong&gt;Made by Nasa Space Apps Contender 2025:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://www.spaceappschallenge.org/2025/find-a-team/perseverance5/" rel="noopener noreferrer"&gt;https://www.spaceappschallenge.org/2025/find-a-team/perseverance5/&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;TL;DR&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Paradigm: Causal Graph Programming (CGP) — you wire functions, not components; the framework auto-detects what each function needs and “snaps” it into a single causal graph (UI ⇄ logic ⇄ effects ⇄ style ⇄ backend).&lt;/li&gt;
&lt;li&gt;Three engines:&lt;/li&gt;
&lt;li&gt;ScrollMesh → component/templating via context auto-wiring (unlimited functions, zero manual wiring).&lt;/li&gt;
&lt;li&gt;ScrollScript → universal signal store (client + server) with actions, watchers, derived signals, time travel.&lt;/li&gt;
&lt;li&gt;ScrollWeave → logic-reactive styling (state/logic drives CSS &amp;amp; animations at runtime).&lt;/li&gt;
&lt;li&gt;Why now: less boilerplate, fewer classes/hooks/providers, more causality visibility.&lt;/li&gt;
&lt;li&gt;Showcase: real-time chat app in &amp;lt; 500 lines (HTML + JS + a tiny server).&lt;/li&gt;
&lt;li&gt;Use cases: dashboards, real-time apps, design systems that react to logic, compact full-stack prototypes.&lt;/li&gt;
&lt;li&gt;One-liner: ScrollForge – Causal Graph Programming: unify state, logic, style, and backend into one reactive graph.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;What is “Causal Graph Programming”?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The short version:&lt;/strong&gt;&lt;br&gt;
Instead of pushing data through props and bouncing events back  through callbacks (typical UI frameworks), CGP lets you register as many functions as you want. Each function declares its intent implicitly by its signature (parameters), and the engine auto-provides matching contexts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;({ ...stateProps }) =&amp;gt; ui → UI renderer (gets state)&lt;/li&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;li&gt;(events, state) =&amp;gt; { ... } → event logic&lt;/li&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;li&gt;(state, weave) =&amp;gt; { ... } → styling/animation driven by state&lt;/li&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;li&gt;(state, effects) =&amp;gt; { ... } → reactive effects&lt;/li&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;li&gt;() =&amp;gt; ({ ... }) → initial state provider
&lt;em&gt;(…and several more contexts, all optional.)&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Order doesn’t matter. Wiring doesn’t exist. The framework assembles a causal graph out of your functions and keeps it live.&lt;/p&gt;

&lt;p&gt;**&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;## Why this is different?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No props drilling, no provider pyramids, no manual event buses.&lt;/li&gt;
&lt;li&gt;UI, logic, effects, and styles coordinate through shared, reactive signals (ScrollScript) and auto-wired contexts (ScrollMesh).&lt;/li&gt;
&lt;li&gt;Style is not static: ScrollWeave treats CSS as a live system, not a file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;**&lt;/p&gt;
&lt;h2&gt;
  
  
  The three engines (in one project)
&lt;/h2&gt;

&lt;p&gt;**&lt;/p&gt;
&lt;h2&gt;
  
  
  1) &lt;strong&gt;ScrollMesh&lt;/strong&gt; — recursive component assembly (auto-wiring):
&lt;/h2&gt;

&lt;p&gt;Write components by passing functions. The engine reads signatures and provides what you need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
import { HTMLScrollMesh } from 'scrollforge/dist/mesh-full.browser.js';

const Counter = HTMLScrollMesh(
  // UI (gets state via destructuring)
  ({ count }) =&amp;gt; `&amp;lt;button class="btn"&amp;gt;Count: ${count}&amp;lt;/button&amp;gt;`,

  // Logic (gets events + state)
  (events, state) =&amp;gt; {
    events.on('click', '.btn', () =&amp;gt; state.count++);
  },

  // Initial state
  () =&amp;gt; ({ count: 0 })
);

Counter.mount('#app');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2) &lt;strong&gt;ScrollScript&lt;/strong&gt; — universal data flow (signals, actions, derived):
&lt;/h2&gt;

&lt;p&gt;Client and server share the same API. Signals update; watchers react; derived signals memoize computed values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Create global signals
app.Script.signal('messages', []);
app.Script.signal('username', '');
app.Script.watch('messages', (msgs) =&amp;gt; console.log('Count:', msgs.length));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3)** ScrollWeave **— logic-reactive styling
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Let state and logic shape style at runtime.

(state, weave) =&amp;gt; {
  weave.when('.status',
    state.online,
    { background: 'rgba(76, 175, 80, .2)' },
    { background: 'rgba(244, 67, 54, .2)' }
  );

  // Micro-interaction
  weave.spring('.btn', { transform: 'scale(1.0)' }, { stiffness: 200, damping: 20 });
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  **The &amp;lt;500-line demo: real-time chat
&lt;/h2&gt;

&lt;p&gt;Using this paradigm, we made a fully working chatapp in under 500 lines of code (present in the github repo at the end).&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;ScrollMesh Context Auto-Wiring - Deep Dive&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The Revolutionary Breakthrough&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ScrollMesh Context is the most powerful feature in ScrollForge. It allows you to pass UNLIMITED functions that automatically detect what they need and connect themselves.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How It Works&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { HTMLScrollMesh } from 'scrollforge/mesh';

const component = HTMLScrollMesh(
  function1,
  function2,
  function3,
  // ... add as many as you want!
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The framework:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;    Reads each function's signature (parameters)&lt;/li&gt;
&lt;li&gt;    Detects what contexts each function needs&lt;/li&gt;
&lt;li&gt;    Automatically provides those contexts&lt;/li&gt;
&lt;li&gt;    Wires everything together&lt;/li&gt;
&lt;li&gt;    NO manual configuration required! ✨&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The 8 Available Contexts:&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Every function can request any of these contexts by adding them as parameters:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. state - Reactive State Proxy&lt;/strong&gt;&lt;br&gt;
Get it by: Adding state as parameter&lt;br&gt;
What you can do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
(state) =&amp;gt; {
  // READ
  const count = state.count;
  const name = state.user.name;

  // WRITE (triggers re-render!)
  state.count++;
  state.user.name = 'Jane';

  // Deep updates work
  state.user.profile.settings.theme = 'dark';

  // Arrays
  state.items.push(newItem);
  state.items = [...state.items, newItem];
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. events - Event System&lt;/strong&gt;&lt;br&gt;
Get it by: Adding events as parameter&lt;br&gt;
What you can do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(events, state) =&amp;gt; {
  // Listen to DOM events
  events.on('click', '.button', (e) =&amp;gt; {
    state.count++;
  });

  events.on('input', '.search', (e) =&amp;gt; {
    state.query = e.target.value;
  });

  // Custom events
  events.emit('customEvent', { data: 'value' });

  events.on('customEvent', (data) =&amp;gt; {
    console.log('Event:', data);
  });

  // Remove listener
  events.off('click', '.button', handler);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. effects - Side Effects&lt;/strong&gt;&lt;br&gt;
Get it by: Adding effects as parameter&lt;br&gt;
What you can do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(state, effects) =&amp;gt; {
  // Watch state changes
  effects.when('count', (count) =&amp;gt; {
    console.log('Count changed:', count);
    document.title = `Count: ${count}`;
  });

  // Watch with old value
  effects.when('status', (newStatus, oldStatus) =&amp;gt; {
    console.log(`${oldStatus} → ${newStatus}`);
  });

  // Run once on mount
  effects.once('mounted', () =&amp;gt; {
    console.log('Component mounted!');
  });

  // Async effects
  effects.when('userId', async (userId) =&amp;gt; {
    const user = await fetchUser(userId);
    state.user = user;
  });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. weave - Styling (ScrollWeave)&lt;/strong&gt;&lt;br&gt;
Get it by: Adding weave as parameter&lt;br&gt;
What you can do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(state, weave) =&amp;gt; {
  // Apply styles
  weave.apply('.element', {
    background: 'blue',
    padding: '20px'
  });

  // Conditional
  weave.when('.button',
    state.isActive,
    { background: 'green' },
    { background: 'gray' }
  );

  // Animations
  weave.fadeIn('.modal', 300);
  weave.spring('.card', { transform: 'scale(1)' });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5. api - API Calls&lt;/strong&gt;&lt;br&gt;
Get it by: Adding api as parameter&lt;br&gt;
What you can do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async (state, api) =&amp;gt; {
  // Fetch when signal changes
  api.when('userId', async (userId) =&amp;gt; {
    const response = await api.fetch(`/api/users/${userId}`);
    const user = await response.json();
    state.user = user;
  });

  // Manual fetch
  const response = await api.fetch('/api/data');
  const data = await response.json();
  state.data = data;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6. storage - Persistence&lt;/strong&gt;&lt;br&gt;
Get it by: Adding storage as parameter&lt;br&gt;
What you can do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(state, storage) =&amp;gt; {
  // Save
  storage.persist('settings', state.settings);

  // Load (async)
  const saved = await storage.load('settings');
  if (saved) state.settings = saved;

  // Remove
  storage.remove('settings');
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;WARNING: storage.load() is async - don't use in state function for initial load!&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;() =&amp;gt; ({
  todos: JSON.parse(localStorage.getItem('todos') || '[]')  // Sync!
}),

(state, effects) =&amp;gt; {
  effects.when('todos', (todos) =&amp;gt; {
    localStorage.setItem('todos', JSON.stringify(todos));  // Save
  });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;7. validate - Validation&lt;/strong&gt;&lt;br&gt;
Get it by: Adding validate as parameter&lt;br&gt;
What you can do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(validate) =&amp;gt; {
  validate.rule('email',
    (value) =&amp;gt; /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value),
    'Invalid email format'
  );

  validate.rule('age',
    (value) =&amp;gt; value &amp;gt;= 18,
    'Must be 18 or older'
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;8. analytics - Analytics Tracking&lt;/strong&gt;&lt;br&gt;
Get it by: Adding analytics as parameter&lt;br&gt;
What you can do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(state, analytics) =&amp;gt; {
  analytics.track('buttonClicked', () =&amp;gt; state.clickCount);

  analytics.track('pageView', () =&amp;gt; ({
    page: state.currentPage,
    user: state.username
  }));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Auto-Detection Rules&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The framework detects function type by its signature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**Signature Detected As Gets**
({ count }) =&amp;gt; ...  UI Function State (destructured)
(state) =&amp;gt; ...  Logic/Effect    State proxy
(events) =&amp;gt; ... Logic   Events
(events, state) =&amp;gt; ...  Logic   Events + State
(state, weave) =&amp;gt; ...   Styling State + Weave
(state, effects) =&amp;gt; ... Effects State + Effects
(state, api) =&amp;gt; ... API State + API
() =&amp;gt; ({ ... }) State Provider  Nothing (returns state)
(state, events, weave, effects, api, storage, validate, analytics) =&amp;gt; ...   All Contexts    All 8!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;State Function Special Rules&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Must have ZERO parameters and return object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//  CORRECT
() =&amp;gt; ({
  count: 0,
  user: { name: 'John' }
})

//  WRONG - has parameters
(someParam) =&amp;gt; ({
  count: 0
})

// WRONG - doesn't return object
() =&amp;gt; {
  const count = 0;
  // Missing return!
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Can include special properties:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;() =&amp;gt; ({
  // Regular state
  count: 0,
  email: '',

  // Computed properties (auto-update!)
  computed: {
    doubleCount: (state) =&amp;gt; state.count * 2
  },

  // Selectors (memoized)
  selectors: {
    evenCount: (state) =&amp;gt; state.count % 2 === 0
  },

  // Middleware (intercept changes)
  middleware: {
    count: (oldValue, newValue) =&amp;gt; {
      return newValue &amp;lt; 0 ? 0 : newValue;  // Prevent negative
    }
  },

  // Validation (runtime checks)
  validate: {
    email: (value) =&amp;gt; /^[^\s@]+@[^\s@]+/.test(value) || 'Invalid email'
  },

  // Options
  immutable: true,  // Freeze state
  debug: {
    logChanges: true,
    breakOnChange: ['count']
  }
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;HTMLScrollMesh - Quick Reference&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;HTMLScrollMesh = ScrollMesh Context + HTML template strings&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Basic Pattern:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { HTMLScrollMesh } from 'scrollforge/mesh';

const App = HTMLScrollMesh(
  // UI - Write HTML directly
  ({ count }) =&amp;gt; `&amp;lt;button&amp;gt;${count}&amp;lt;/button&amp;gt;`,

  // Events
  (events, state) =&amp;gt; {
    events.on('click', 'button', () =&amp;gt; state.count++);
  },

  // State
  () =&amp;gt; ({ count: 0 })
);

App.mount('#app');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;All 8 Contexts Work Identically&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;HTMLScrollMesh has the SAME context auto-wiring as ScrollMesh:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(events, state) → Events + State&lt;/li&gt;
&lt;li&gt;(state, weave) → State + ScrollWeave styling&lt;/li&gt;
&lt;li&gt;(state, effects) → State + Side effects&lt;/li&gt;
&lt;li&gt;(state, api) → State + API calls&lt;/li&gt;
&lt;li&gt;(storage) → Storage context&lt;/li&gt;
&lt;li&gt;(validate) → Validation&lt;/li&gt;
&lt;li&gt;(analytics) → Analytics&lt;/li&gt;
&lt;li&gt;() =&amp;gt; ({ ... }) → State provider (zero params!)&lt;/li&gt;
&lt;li&gt;Same rules. Same auto-detection. Just HTML instead of JS objects.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;HTML Features&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;({ items, isLoggedIn, user }) =&amp;gt; `
  &amp;lt;!-- Conditionals --&amp;gt;
  ${isLoggedIn ? `&amp;lt;p&amp;gt;Hello ${user.name}&amp;lt;/p&amp;gt;` : `&amp;lt;p&amp;gt;Login&amp;lt;/p&amp;gt;`}

  &amp;lt;!-- Loops --&amp;gt;
  &amp;lt;ul&amp;gt;
    ${items.map(i =&amp;gt; `&amp;lt;li&amp;gt;${i.name}&amp;lt;/li&amp;gt;`).join('')}
  &amp;lt;/ul&amp;gt;

  &amp;lt;!-- Expressions --&amp;gt;
  &amp;lt;p&amp;gt;Total: $${(price * quantity).toFixed(2)}&amp;lt;/p&amp;gt;
`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Difference from ScrollMesh Context:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
1. ScrollMesh                            HTMLScrollMesh
2. { tag: 'div', content: 'Hi' }     &amp;lt;div&amp;gt;Hi&amp;lt;/div&amp;gt;
3. JS Objects                            HTML Strings
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ** Using ScrollWeave with HTMLScrollMesh**
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The Pattern:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTMLScrollMesh(
  // UI function
  ({ count }) =&amp;gt; `&amp;lt;button class="my-btn"&amp;gt;${count}&amp;lt;/button&amp;gt;`,

  // Weave function - gets (state, weave) automatically!
  (state, weave) =&amp;gt; {
    // Apply reactive styles based on state
    weave.when('.my-btn',
      state.count &amp;gt; 10,
      { background: 'green', fontSize: '2rem' },  // If count &amp;gt; 10
      { background: 'blue', fontSize: '1rem' }    // Else
    );
  },

  // Other functions...
  (events, state) =&amp;gt; {
    events.on('click', '.my-btn', () =&amp;gt; state.count++);
  },

  () =&amp;gt; ({ count: 0 })
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The framework automatically:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Detects (state, weave) signature&lt;/li&gt;
&lt;li&gt;Provides state proxy + ScrollWeave instance&lt;/li&gt;
&lt;li&gt;Styles update when state changes&lt;/li&gt;
&lt;li&gt;Zero manual wiring! ✨&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How It Works&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTMLScrollMesh(
  // Function with (state, weave) parameters
  (state, weave) =&amp;gt; {
    // Framework provides:
    // - state: reactive component state
    // - weave: ScrollWeave instance (app.Weave)

    // Use state to drive styles
    weave.apply('.element', {
      color: state.isActive ? 'green' : 'gray',
      fontSize: state.count &amp;gt; 5 ? '2rem' : '1rem'
    });
  }
);

// Framework auto-detects parameter names!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Complete Example&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Counter = HTMLScrollMesh(
  // UI
  ({ count, isHigh }) =&amp;gt; `
    &amp;lt;div class="counter"&amp;gt;
      &amp;lt;h1 class="display"&amp;gt;${count}&amp;lt;/h1&amp;gt;
      &amp;lt;button class="increment"&amp;gt;+&amp;lt;/button&amp;gt;
      &amp;lt;button class="decrement"&amp;gt;-&amp;lt;/button&amp;gt;
      ${isHigh ? `&amp;lt;p class="warning"&amp;gt;⚠️ High count!&amp;lt;/p&amp;gt;` : ''}
    &amp;lt;/div&amp;gt;
  `,

  // Weave - Reactive styling!
  (state, weave) =&amp;gt; {
    // Style changes based on state
    weave.when('.display',
      state.count &amp;gt; 10,
      { 
        color: 'green', 
        fontSize: '4rem',
        fontWeight: 'bold'
      },
      { 
        color: 'blue', 
        fontSize: '2rem',
        fontWeight: 'normal'
      }
    );

    // Button styling
    weave.when('.increment',
      state.count &amp;gt;= 20,
      { background: '#ccc', cursor: 'not-allowed' },
      { background: '#4CAF50', cursor: 'pointer' }
    );

    // Animate warning
    if (state.isHigh) {
      weave.spring('.warning', {
        opacity: 1,
        transform: 'scale(1)'
      });
    }
  },

  // Events
  (events, state) =&amp;gt; {
    events.on('click', '.increment', () =&amp;gt; {
      if (state.count &amp;lt; 20) state.count++;
    });

    events.on('click', '.decrement', () =&amp;gt; {
      if (state.count &amp;gt; 0) state.count--;
    });
  },

  // State
  () =&amp;gt; ({
    count: 0,

    computed: {
      isHigh: (state) =&amp;gt; state.count &amp;gt; 15
    }
  })
);

Counter.mount('#app');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;State changes → Weave updates styles → UI reflects changes! ✨&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Points&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get weave context: Add weave as parameter after state&lt;/li&gt;
&lt;li&gt;Signature: (state, weave) =&amp;gt; { ... }&lt;/li&gt;
&lt;li&gt;Framework provides: Your app's app.Weave instance automatically&lt;/li&gt;
&lt;li&gt;Use state: Access component state to drive styles&lt;/li&gt;
&lt;li&gt;Reactive: Styles update automatically when state changes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it! Just add weave parameter and you get reactive styling! &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Links:&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/scrollforge" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/scrollforge&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.infernusreal.com" rel="noopener noreferrer"&gt;www.infernusreal.com&lt;/a&gt; -&amp;gt; Portfolio website&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thank you &amp;lt;3, also although I have tested all the features and examples I have shown and even used it to make many small samples, if you find any problems with it, kindly contact me through the number given in the portfolio website!&lt;/p&gt;

&lt;p&gt;I am only 16 so hopefully I am not embarrassing myself here, I also just entered Nasa space apps challenge 2025 this year, you can find the link to that page here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.spaceappschallenge.org/2025/find-a-team/perseverance5/" rel="noopener noreferrer"&gt;https://www.spaceappschallenge.org/2025/find-a-team/perseverance5/&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
