Skip to content

binaryjack/pulsar.dev

Repository files navigation

Pulsar

A reactive UI framework with TypeScript-first JSX transformation and fine-grained reactivity

Version 0.7.0-alpha TypeScript 5.0+ MIT License Alpha

AboutFeaturesQuick StartGetting Started GuideRoadmapEcosystemContributing

follow me


What is Pulsar?

Pulsar is a reactive UI framework that combines compile-time JSX transformation with runtime reactivity primitives. It transforms JSX syntax into direct DOM operations at build time and uses signal-based reactivity for surgical, fine-grained updates.

Framework or Library?

Pulsar is a framework because it provides:

  • A complete runtime system with lifecycle management
  • Opinionated architecture for component composition
  • Integrated tooling (TypeScript transformer + Vite plugin)
  • Built-in patterns for routing, dependency injection, and error handling
  • A complete application bootstrap system

While it's modular and allows selective feature usage, it prescribes a specific approach to building reactive UIs with transformed JSX.

Core Philosophy

// Components run ONCE, not on every state change
export const Counter = ({ initialCount = 0 }) => {
  const [count, setCount] = useState(initialCount)

  // count() is a getter - accessing it subscribes this DOM node
  return <div>{count()}</div>
  // Future updates: ONLY this text node changes, not entire component
}

Pulsar combines:

  • React's familiar hooks API (useState, useEffect, useMemo)
  • SolidJS's signal-based reactivity for surgical updates
  • Svelte's compile-time philosophy (JSX → optimized DOM code)
  • TypeScript's full type safety with first-class transformer support

Core Features

✅ Core Features (v0.7.0-alpha)

🎯 Signal-Based Reactivity createSignal, createEffect, createMemo
• Fine-grained dependency tracking
• Automatic subscription management
• Batched updates with batch()
🪝 React-Like Hooks useState - State management with signals
useEffect - Side effects with dependencies
useMemo - Computed values
useRef - Mutable references
🗃️ State Management • Redux-style stores with signals
createStore, dispatch, subscribe
• Undo/redo middleware (time-travel debugging)
• Persistence (localStorage/sessionStorage)
• Redux DevTools integration
• Memoized selectors with select()
reconcile() - Immutable reconciliation
🧭 Enhanced Router • Path parameters: /users/:id
• Query string parsing with useSearchParams()
• Navigation hooks: useRouter(), useNavigate(), useParams()
• Route guards: beforeEach, afterEach
• Nested routes with <Outlet />
🎨 Design System • Framework-agnostic design tokens
• CSS variable generation (build-time)
• Dark mode support (automatic)
• 200+ design variables exported
🔍 TypeScript Compiler API • Type-safe routing (param extraction)
• DI circular dependency detection
• Enhanced error messages with suggestions
• Auto prop validation from types
• Route type integration
• JSX prop validation
🔄 TypeScript Transformer • JSX → Direct DOM compilation
• Zero runtime JSX overhead
• Automatic reactivity injection
• Full type safety preserved
⚡ Control Flow <Show> - Conditional rendering
<For> - Keyed list rendering
<Index> - Non-keyed list rendering
<Dynamic> - Dynamic component resolution
• Reactive updates only where needed
📦 Resource Management createResource - Async data fetching
createTrackedResource - Multi-resource tracking
<Waiting> component for loading states
• Built-in caching and deduplication
📝 Form Management 🆕 v0.9.0 useFormular() - formular.dev integration
• Signal-based reactive forms
• Built-in validation (sync/async/custom)
• Nested objects and arrays support
• Form state tracking (dirty/touched/valid)
• 41 passing tests (100%)
🔄 Immutable Updates 🆕 v0.9.0 produce() - Immer-style API
• Nested draft tracking
• Structural sharing optimization
• Array and object proxy support
• Type-safe with generics
• 29 passing tests (100%)
🧬 Context System createContext / useContext
• React-like Context API
• Provider-based value propagation
🎭 Portals <Portal> component
• Render content outside component tree
• Modal and overlay support
🛡️ Error Boundaries <Tryer> / <Catcher> components
• Declarative error handling
• Component error isolation
💉 Dependency Injection ServiceManager - IoC container
ServiceLocator - Service resolution
• Singleton, transient, and scoped lifetimes
• Type-safe service registration
🚀 Bootstrap System bootstrapApp - Application builder
createApp / createOutlet
• Lifecycle management
• Multiple mount points support
🎪 Event System • Event delegation for performance
• Synthetic event wrappers
• Automatic cleanup on unmount
🔌 Vite Plugi� Build Optimization • Tree shaking analyzer implemented
• CSS variable generator working
In Progress: Automatic dead code elimination (40%)
Planned: Component lazy loading, route splitting
Status: Foundation complete, automation pending
🎨 Styling System • Manual style management works
• Design tokens available
Missing: CSS-in-JS runtime, scoped styles, styled components
Status: Planned for future release
🔍 DevTools ⚠️ Partial (v0.9.0) • Redux DevTools integration ✅
• Time-travel debugging support (via Redux DevTools)
• State inspection in Redux DevTools
Browser Extension: ⏳ Planned (separate repo)
• Component tree inspector (planned)
• Signal/state inspector (planned)
• formular.dev form debugger (planned)
Status: 20% complete - Redux DevTools only
⚙️ Server-Side Rendering ✅ v0.8.0 renderToString() - Server-side rendering
hydrate() - Client-side hydration
generateStatic() - Static site generation
• HTML escaping and XSS protection
• State serialization/deserialization
• 15+ passing tests (100%)
🧪 Testing Utilities ✅ v0.9.0 • Component test renderer
• Event simulation (fireEvent, click, type)
• Async utilities (waitFor, waitForElement)
• DOM queries (screen.getByText, getByRole)
• formular.dev helpers (fillField, submitForm, createMockForm)
• Mock utilities (mockRouter, mockService)
• 25+ formular tests passing (100%)
🌐 HTTP Client ✅ v0.8.0 useHttp() - Reactive HTTP hook
• Request/response/error interceptors
• Automatic caching with TTL
• Retry logic with exponential backoff
• Full TypeScript support
• 25+ passing tests (100%)
🛠️ CLI Tool ✅ v0.8.0 pulsar create - Project scaffolding
pulsar generate - Code generation
pulsar add - Integration setup
pulsar build - Production builds
• Interactive prompts and templates
🔄 Lazy Loading & Code Splitting ✅ v0.6.0 lazy() - Dynamic component import
• Multiple preload strategies (eager, idle, visible, hover)
• Route-based code splitting
usePrefetch() - Manual route prefetching
• Integration with <Waiting> boundaries
• Automatic bundle optimization
🔍 Component Lifecycle Tracing ✅ v0.6.0 traceComponentMount/Update/Unmount()
• Performance monitoring (render time, update count)
• Memory leak detection
• Excessive update warnings
• Development-mode only (zero production overhead)

Architecture Overview

How It Works

1. Build-Time Transformation

// Your JSX code
<button onClick={increment}>{count()}</button>;

// Transforms to (simplified):
(() => {
  const el0 = document.createElement('button');
  el0.addEventListener('click', increment);
  createEffect(() => {
    el0.textContent = String(count());
  });
  return el0;
})();

Key Benefits:

  • No virtual DOM diffing
  • No reconciliation overhead
  • Direct DOM operations
  • Minimal runtime footprint (~5-10KB)

2. Signal-Based Reactivity

const [count, setCount] = useState(0);
// Returns: [getter, setter]

count(); // Read value (subscribes to changes)
setCount(5); // Write value (notifies subscribers)

How it works:

  • State values wrapped in Signals
  • Reading count() inside an Effect automatically subscribes
  • Writing via setCount() triggers ONLY subscribed effects
  • Automatic dependency tracking
  • Surgical updates to specific DOM nodes

3. Component Lifecycle

export const Component = (props) => {
  // 🔵 Component function runs ONCE
  const [state, setState] = useState(0)

  useEffect(() => {
    // 🟢 Effects re-run when dependencies change
    console.log(state())
  }, [state])

  // 🔵 Returns DOM elements (not re-rendered)
  return <div>{state()}</div>
  // 🟢 Only text node updates when state changes
}

No Re-renders:

  • Components run once at creation
  • State changes don't trigger re-renders
  • Effects track dependencies automatically
  • Updates are surgical, not cascading

Roadmap

eary works

first version started: february 02, 2023

  • rendering and prototyping core features january 2023
  • forms libs creation march 2023
  • component libs v1
  • component libs v2
  • component libs v3 june ~ 2023
  • formular.dev january 2024
  • formular.dev v.1 february 2025
  • pulsar-framework march 2025

current

Current Version: v0.7.0-alpha ✅
Next Release: v1.0.0-stable (Q2 2026)
Last Updated: January 27, 2026

🎯 Current Status

v0.7.0-alpha - IN PROGRESS (85%)

  • ✅ formular.dev integration (useFormular() hook) - 41 tests passing
  • produce() utility (Immer-style API) - 29 tests passing
  • ✅ Testing utilities (component testing, form helpers) - 25 tests passing
  • ✅ Dev Tools APIs - Registry Inspector, Event Inspector, Performance Monitor (29 files)
  • ⚠️ DevTools UI - Browser extension planned for v1.0

v0.8.0-alpha - SHIPPED ✅ (January 2026)

  • ✅ HTTP Client with useHttp() hook (25+ tests)
  • ✅ CLI tool (pulsar create, pulsar generate, pulsar add)
  • ✅ SSR/SSG foundation (renderToString, hydrate, generateStatic)

🚀 Coming Next

v1.0.0 - Production Ready (Q2 2026)

  • Stable API with semver guarantees
  • Comprehensive documentation site
  • Real-world example applications
  • Performance benchmarks vs React/Solid/Vue
  • Long-term support (LTS) commitment
  • Community contribution guidelines

📊 What's Complete (v0.1.0-v0.7.0)

✅ Core Runtime (100%)

  • Signal-based reactivity, hooks, control flow (<Show>, <For>, <Index>, <Dynamic>), context, error boundaries, portals

✅ State Management (100%)

  • Redux-style stores, undo/redo, persistence, DevTools integration, immutable updates (produce())

✅ Router (100%)

  • Path params, query strings, guards, nested routes, lazy loading

✅ Forms (100%)

  • Via formular.dev integration - framework-agnostic, reactive, validated forms

✅ DI System (100%)

  • IoC container with multiple lifetime scopes

✅ Server-Side Rendering (100%)

  • renderToString(), hydrate(), generateStatic() with full state management

✅ HTTP Client (100%)

  • useHttp() hook, interceptors, caching, retry logic

✅ Testing Utilities (100%)

  • Component renderer, event simulation, form helpers, async utilities

➡️ For detailed roadmap: See ROADMAP.md


Strategic Differentiation from Competitors

Pulsar + formular.dev aims to differentiate through four core pillars:

1. True Framework Agnosticism 🌐 ⭐ UNIQUE ADVANTAGE

  • formular.dev works with Pulsar, React, Vue, Angular, or vanilla JS
  • Build forms once, reuse across frameworks
  • No vendor lock-in for form logic
  • Migrate frameworks without rewriting forms
  • Competitors: Angular Forms (Angular only), React Hook Form (React only)

2. TypeScript Powerhouse 🔮

  • Deepest TypeScript Compiler API integration of any framework
  • Compile-time validation and optimization beyond standard tooling
  • Type-safe everything: routing, DI, themes, state machines, forms
  • Zero-cost abstractions that compile away

3. Enterprise-Ready Out-of-Box 🏢

  • formular.dev: 6 languages + 12 countries built-in (vs Angular's manual setup)
  • Most sophisticated DI system in any reactive framework
  • Built-in patterns for large-scale applications
  • Micro-frontend support out of the box
  • Observable and debuggable at production scale

4. Performance First

  • Smaller bundle: ~10KB (Pulsar core gzipped)
  • vs Angular: ~70KB (Core + Forms)
  • vs React: ~45KB (runtime alone)
  • vs SolidJS: ~7KB (similar architecture)
  • Fine-grained reactivity with compile-time optimization
  • Zero virtual DOM overhead

5. Developer Experience & Observability 🔍 ⭐ UNIQUE ADVANTAGE

  • Component lifecycle tracing built into core (not afterthought extension)
  • Performance monitoring: render time, update counts, memory usage
  • Automatic excessive update detection
  • Development warnings with actionable hints
  • Signal state debugging with dependency graphs
  • Zero production overhead (dev tools stripped at build)
  • vs React/Vue: Requires browser extension for similar features

6. Advanced Code Splitting 📦

  • Multiple preload strategies: eager, idle, visible, hover-based
  • Route-level code splitting with prefetch hooks
  • Automatic bundle optimization and dead code elimination
  • Lazy component loading with integrated loading states
  • vs Competitors: Most only offer basic dynamic imports

Target Audience:

  • Teams building global applications (need i18n/multi-country out-of-box)
  • TypeScript-heavy teams and organizations
  • Enterprise applications requiring advanced patterns (DI, observability)
  • Teams migrating from Angular seeking modern DX with familiar patterns
  • Projects prioritizing type safety and build-time optimization
  • Performance-critical applications requiring fine-grained reactivity
  • Multi-framework teams (formular.dev works across React, Vue, Angular)

🔮 Future Vision (v2.0+)

Near-term (v1.0 - Q2 2026):

  • 🔍 DevTools browser extension - Component tree, signal inspector, time-travel, profiler
  • 📊 Performance profiler - Built-in component performance monitoring
  • 🧪 Test coverage reporting - Integrated coverage tools

Experimental (v2.0+):

  • 🌐 Edge runtime support (Cloudflare Workers, Deno Deploy)
  • 🤖 AI-powered code generation and refactoring
  • 🎮 Web Components compilation target
  • 📱 React Native bridge for native apps
  • 🔗 GraphQL/tRPC first-class integration
  • 🎯 Automatic accessibility (a11y) validation
  • 🌍 Built-in i18n with compile-time extraction

Framework Comparison

How Pulsar Compares

Feature React Vue 3 Svelte SolidJS Pulsar
Reactivity VDOM diffing Proxy-based Compile-time Fine-grained signals Fine-grained signals
Updates Re-render tree Re-render component Compile to updates Update specific nodes Update specific nodes
State Syntax count count.value $count count() count()
Virtual DOM Yes Yes No No No
Bundle Size ~45KB ~34KB ~2KB ~7KB ~10KB
Component Model Function reruns Function reruns Compile away Run once Run once
TypeScript Compiler No No No No Yes (API integration)
Built-in DI No Limited No No Enterprise-grade
Lazy Loading Basic Basic Basic Basic Advanced (6 strategies)
Component Tracing Extension only Extension only Extension only Extension only Built-in (dev mode)
Preload Strategies Manual Manual Manual Manual Automatic (4 strategies)
JSX/Templates JSX Templates/JSX Templates JSX JSX (transformed)
SSR/SSG Yes Yes Yes Yes Yes (v0.8.0)
DevTools Excellent Excellent Good Good Partial (Redux only) ⚠️
Ecosystem Huge Large Growing Growing New (v0.9.0)

When to Choose Pulsar

Choose Pulsar if you want:

  • ✅ React-like hooks API without virtual DOM overhead
  • ✅ Fine-grained reactivity with automatic dependency tracking
  • TypeScript Compiler API integration (type-safe routing, DI validation)
  • Enterprise DI patterns built-in (Angular-style, but lightweight)
  • Advanced lazy loading (6 preload strategies vs basic dynamic imports)
  • Component lifecycle tracing built into framework (not extension-only)
  • ✅ Compile-time optimizations with no runtime JSX overhead
  • ✅ Minimal bundle size (~10KB vs React's 45KB)
  • SSR/SSG complete (renderToString, hydrate, generateStatic) ✅
  • Framework-agnostic forms via formular.dev (works with React, Vue, Angular)
  • Production-ready HTTP client with interceptors, caching, retry logic
  • CLI tools for scaffolding, code gen, and integration setup
  • Development observability without needing browser extensions
  • ✅ To learn cutting-edge reactive patterns

Choose Pulsar OVER SolidJS if you:

  • 🎯 Need advanced dependency injection (decorators, lifetimes, modules)
  • 🎯 Want TypeScript Compiler API integration (not just good TS support)
  • 🎯 Require built-in component tracing and performance monitoring
  • 🎯 Need multiple lazy loading strategies (hover, idle, visible, eager)
  • 🎯 Want enterprise patterns without building them yourself
  • 🎯 Prefer opinionated framework over library
  • 🎯 Building design-system-first applications
  • 🎯 Migrating from Angular and want modern DX with familiar patterns

Consider alternatives if you need:

  • ❌ Immediate API stability guarantees → use SolidJS (v1.8+ stable) or wait for Pulsar v1.0 (Q2 2026)
  • ❌ Full-stack meta-framework → use Next.js, Nuxt, SolidStart (Pulsar is client-first)
  • ❌ Massive third-party ecosystem → use React (millions of packages)
  • ❌ Extensive pre-built component libraries → use React, Vue, Angular
  • ❌ Framework with 5+ years of battle-testing → use React, Vue (Pulsar is new)

Quick Start

Using Pulsar CLI (Recommended)

# Install CLI globally
npm install -g @pulsar-framework/cli

# Create new project
pulsar create my-app --template basic
cd my-app

# Install dependencies
npm install

# Start dev server
npm run dev

Manual Setup

See the complete Getting Started Guide for detailed setup instructions.

Minimal setup requires:

  1. Dependencies:

    npm install @pulsar-framework/pulsar.dev @pulsar-framework/vite-plugin
    npm install -D vite typescript
  2. Vite Configuration:

    import { defineConfig } from 'vite';
    import { pulsarPlugin } from '@pulsar-framework/vite-plugin';
    
    export default defineConfig({
      plugins: [pulsarPlugin()],
      esbuild: {
        jsxFactory: 'h',
        jsxFragment: 'Fragment',
        jsxInject: `import { h, Fragment } from '@pulsar-framework/pulsar.dev'`,
      },
    });
  3. Bootstrap Your App:

    import { AppContextProvider, bootstrapApp } from '@pulsar-framework/pulsar.dev';
    import { App } from './App';
    
    const appRoot = bootstrapApp()
      .root('#app')
      .onMount((el) => console.log('Mounted', el))
      .onError((err) => console.error('Error:', err))
      .build();
    
    const app = (
      <AppContextProvider
        root={appRoot}
        context={{ appName: 'My App', version: '1.0.0' }}
      >
        <App />
      </AppContextProvider>
    );
    
    document.getElementById('app')?.appendChild(app);

📖 For complete setup guide: Getting Started

Quick Example

import { createSignal, createMemo, Show } from '@pulsar-framework/pulsar.dev';

export const Counter = ({ initialCount = 0 }: { initialCount?: number }) => {
  const [count, setCount] = createSignal(initialCount);

  // Memoized computation - only re-runs when count changes
  const doubleCount = createMemo(() => count() * 2);

  // Fine-grained updates: only this text node updates
  const isPositive = createMemo(() => count() > 0);

  return (
    <div class="counter">
      <h2>Count: {count()}</h2>
      <h3>Double: {doubleCount()}</h3>

      {/* Conditional rendering with Show */}
      <Show when={isPositive()}>
        <p style="color: green;">Positive number! 🎉</p>
      </Show>

      <div>
        <button onClick={() => setCount(count() + 1)}>Increment</button>
        <button onClick={() => setCount(count() - 1)}>Decrement</button>
        <button onClick={() => setCount(0)}>Reset</button>
      </div>
    </div>
  );
};

Portal Pattern Example:

import { createSignal, Show, Portal } from '@pulsar-framework/pulsar.dev';
import { Modal } from '@pulsar-framework/ui';

export const ModalExample = () => {
  const [isOpen, setIsOpen] = createSignal(false);
  const [data, setData] = createSignal('');

  return (
    <div>
      <button onClick={() => setIsOpen(true)}>Open Modal</button>

      <Show when={isOpen()}>
        <Modal id="example-modal" isOpen={isOpen} onClose={() => setIsOpen(false)} />

        <Portal id="example-modal" target="body">
          <input
            type="text"
            value={data()}
            onInput={(e) => setData(e.target.value)}
            placeholder="Component-local state"
          />
          <p>Value: {data()}</p>
        </Portal>
      </Show>
    </div>
    </div>
  )
}

Getting Started

Installation

# Clone the monorepo
git clone https://github.com/binaryjack/visual-schema-builder.git
cd visual-schema-builder

# Install dependencies
pnpm install

# Build Pulsar
cd packages/pulsar
pnpm build

# Run demo applications
cd ../demo
pnpm dev

Quick Example

import { useState, useEffect, useMemo } from 'pulsar/hooks'
import { bootstrapApp } from 'pulsar/bootstrap'

const Counter = ({ initialCount = 0 }) => {
  const [count, setCount] = useState(initialCount)
  const [multiplier, setMultiplier] = useState(2)

  // Computed value (automatically tracks dependencies)
  const result = useMemo(() => count() * multiplier(), [count, multiplier])

  // Side effect (runs when count changes)
  useEffect(() => {
    console.log(`Count: ${count()}`)
  }, [count])

  return (
    <div className="counter">
      <h2>Count: {count()}</h2>
      <p>Result: {result()}</p>
      <button onClick={() => setCount(count() + 1)}>Increment</button>
      <button onClick={() => setCount(count() - 1)}>Decrement</button>
    </div>
  )
}

// Bootstrap your app
bootstrapApp({
  rootElement: () => <Counter initialCount={0} />,
  targetSelector: '#app'
})

Lazy Loading with Preload Strategies 🆕 v0.6.0

import { lazy } from 'pulsar/lazy-loading'
import { Waiting } from 'pulsar/resource'

// Basic lazy loading
const HeavyChart = lazy(() => import('./components/HeavyChart'))

// With preload strategies
const Dashboard = lazy(() => import('./Dashboard'), {
  preloadStrategy: 'onIdle', // Load when browser is idle
})

const UserProfile = lazy(() => import('./UserProfile'), {
  preloadStrategy: 'onVisible', // Load when element is visible
})

const Settings = lazy(() => import('./Settings'), {
  preloadStrategy: 'onHover', // Load when user hovers
})

const App = () => {
  return (
    <div>
      <Waiting fallback={<Spinner />}>
        <HeavyChart data={chartData} />
      </Waiting>

      <Dashboard />
      <UserProfile />
      <Settings />
    </div>
  )
}

Form Management with formular.dev 🆕 v0.9.0

Note: formular.dev is a separate, framework-agnostic form library that works with Pulsar, React, Vue, Angular, or vanilla JS. While Pulsar provides a useFormular() hook for seamless integration, formular.dev can be used independently.

Why separate?

  • ✅ No vendor lock-in - use same form code across frameworks
  • ✅ Smaller Pulsar core bundle (~10KB instead of ~22KB)
  • ✅ formular.dev can be adopted without Pulsar
  • ✅ Teams can migrate frameworks without rewriting forms

Integration Example:

import { useFormular } from '@pulsar-framework/pulsar.dev'

const SignupForm = () => {
  const form = useFormular({
    initialValues: { name: '', email: '', age: 18 },
    validators: {
      name: 'required|minLength:2',
      email: 'required|email',
      age: 'required|number|min:18',
    },
    onSubmit: async (values) => {
      await api.post('/signup', values)
    },
  })

  return (
    <form onSubmit={form.handleSubmit}>
      <input
        type="text"
        value={form.fields.name.value()}
        onInput={(e) => form.fields.name.setValue(e.target.value)}
        placeholder="Name"
      />
      {form.fields.name.error() && <span class="error">{form.fields.name.error()}</span>}

      <button type="submit" disabled={form.isSubmitting()}>
        {form.isSubmitting() ? 'Submitting...' : 'Sign Up'}
      </button>
    </form>
  )
}

For standalone usage or React/Vue/Angular integration, see:

Immutable Updates with produce() 🆕 v0.9.0

import { produce } from '@pulsar-framework/pulsar.dev';

const [users, setUsers] = useState([
  { id: 1, name: 'Alice', age: 30 },
  { id: 2, name: 'Bob', age: 25 },
]);

// Immer-style immutable updates
const updateUserAge = (id: number, newAge: number) => {
  setUsers(
    produce(users(), (draft) => {
      const user = draft.find((u) => u.id === id);
      if (user) {
        user.age = newAge; // Mutate the draft directly!
      }
    })
  );
};

// Works with nested structures
const [state, setState] = useState({
  user: {
    profile: {
      settings: {
        theme: 'light',
      },
    },
  },
});

setState(
  produce(state(), (draft) => {
    draft.user.profile.settings.theme = 'dark'; // Deep mutation made easy
  })
);

Testing Your Components 🆕 v0.9.0

import { render, screen, fillField, submitForm, waitFor } from '@pulsar-framework/pulsar.dev';

describe('SignupForm', () => {
  it('should submit form with valid data', async () => {
    const onSubmit = vi.fn();
    render(SignupForm, { props: { onSubmit } });

    // Fill form fields
    fillField(screen.getByPlaceholder('Name'), 'John Doe');
    fillField(screen.getByPlaceholder('Email'), 'john@example.com');

    // Submit form
    const form = screen.getByRole('form');
    await submitForm(form, { waitForValidation: true });

    // Assert
    expect(onSubmit).toHaveBeenCalledWith({
      name: 'John Doe',
      email: 'john@example.com',
    });
  });
});

Project Structure

packages/
├── pulsar/         # Core framework
│   ├── src/
│   │   ├── reactivity/      # Signal system
│   │   ├── hooks/           # useState, useEffect, etc.
│   │   ├── control-flow/    # Show, For components
│   │   ├── context/         # Context API
│   │   ├── resource/        # Async resource management
│   │   ├── portal/          # Portal system
│   │   ├── error-boundary/  # Error handling
│   │   ├── di/              # Dependency injection
│   │   ├── router/          # Basic routing (WIP)
│   │   ├── lifecycle/       # Component lifecycle
│   │   ├── events/          # Event system
│   │   └── bootstrap/       # App initialization
│   └── art-kit/            # Brand assets
├── transformer/    # TypeScript JSX transformer
├── vite-plugin/    # Vite integration
└── demo/           # Example applications

Performance Characteristics

Benchmarks (v0.9.0-alpha)

Metric Pulsar React SolidJS Notes
Initial Render Fast ⚡ Medium Fast No VDOM creation overhead
Updates Fastest ⚡⚡⚡ Medium Fastest Surgical DOM updates only
Memory Low 💚 High Low No fiber tree or VDOM
Bundle Size ~10KB ~45KB ~7KB Transformer at build time
Large Lists Fastest ⚡⚡⚡ Slower Fastest Fine-grained updates with For

Note: Formal benchmarks pending. These are qualitative assessments based on architecture.


Real-World Examples

Live Showcase

🎨 See it in action: pulsar-ui.dev showcase - 80+ examples demonstrating advanced patterns

1. Fine-Grained Reactivity

// Signal-based state with automatic dependency tracking
export const SignalDemo = ({ firstName, setFirstName, age, setAge }: Props) => {
  return (
    <div>
      <div>
        <strong>Name:</strong> {firstName()} {/* Auto-subscribes */}
        <strong>Age:</strong> {age()}
      </div>
      <button onClick={() => setAge(age() + 1)}>Increment Age</button>
    </div>
  );
};

Key Features:

  • Only subscribed DOM nodes update
  • No virtual DOM diffing
  • Surgical, fine-grained updates

2. Portal/PortalSlot Architecture

// Advanced pattern: Modal with content projection
export component ModalDemo() {
  const [isOpen, setIsOpen] = createSignal(false);
  const [count, setCount] = createSignal(0);

  return (
    <div>
      <button onClick={() => setIsOpen(true)}>Open Modal</button>

      <Show when={isOpen()}>
        {/* Modal provides PortalSlots */}
        <Modal id="demo-modal" isOpen={isOpen} onClose={() => setIsOpen(false)} />

        {/* Project content into slots while keeping logic local */}
        <Portal id="demo-modal" target="header">
          <h3>Modal Title</h3>
        </Portal>

        <Portal id="demo-modal" target="body">
          <p>State is maintained in component scope: {count()}</p>
          <button onClick={() => setCount(count() + 1)}>
            Increment ({count()})
          </button>
        </Portal>

        <Portal id="demo-modal" target="footer">
          <button onClick={() => setIsOpen(false)}>Close</button>
        </Portal>
      </Show>
    </div>
  );
}

Benefits:

  • UI projected globally (portal)
  • Logic stays local (component scope)
  • Clean separation of concerns

3. Error Boundaries

// Tryer/Catcher pattern for graceful error handling
import { Tryer, Catcher } from '@pulsar-framework/pulsar.dev';

export component ErrorBoundaryDemo() {
  const [throwError, setThrowError] = createSignal(false);

  const BuggyComponent = () => {
    if (throwError()) throw new Error('Component crash!');
    return <div>All good ✅</div>;
  };

  return (
    <Tryer>
      <BuggyComponent />
      <Catcher>
        {(error) => (
          <div style="color: red;">
            ⚠️ Error: {error.message}
          </div>
        )}
      </Catcher>
    </Tryer>
  );
}

Features:

  • Independent boundaries
  • Errors don't crash entire app
  • Fallback UI for failed sections

4. Resources with Caching

// createResource with stale-while-revalidate
export const CacheDemo = () => {
  const [fetchCount, setFetchCount] = createSignal(0);

  const cachedResource = createResource(
    () => {
      setFetchCount((c) => c + 1);
      return fetchUser(1);
    },
    { staleTime: 5000 }
  ); // Fresh for 5s

  return (
    <div>
      <button onClick={() => cachedResource.refetch()}>Refetch</button>

      <div>Network Requests: {fetchCount()}</div>

      <Show when={cachedResource.data}>
        <div>
          <h4>{cachedResource.data.name}</h4>
          <p>{cachedResource.data.email}</p>
          <p>{Date.now() - cachedResource.fetchedAt < 5000 ? '✅ Fresh' : '⚠️ Stale'}</p>
        </div>
      </Show>
    </div>
  );
};

Caching Strategy:

  • Instant cache hits within staleTime
  • Stale-while-revalidate after expiry
  • Automatic refetch management

5. Dependency Injection

// ServiceManager with lifetime management
import { ServiceManager } from '@pulsar-framework/pulsar.dev';

// Setup services
const services = new ServiceManager();

services.register('analytics', () => new Analytics(), {
  lifetime: 'singleton'  // Single instance app-wide
});

services.register('logger', () => new Logger(), {
  lifetime: 'transient'  // New instance each time
});

// Use in components
export component MyComponent() {
  const analytics = inject('analytics');
  const logger = inject('logger');

  const trackEvent = () => {
    analytics.track('button_clicked');
    logger.log('Event tracked');
  };

  return <button onClick={trackEvent}>Track Event</button>;
}

// Bootstrap with DI
pulse(App, {
  root: '#app',
  services  // Available throughout app
});

Patterns:

  • Singleton: Shared instances (API clients, config)
  • Transient: Fresh instances (loggers, factories)
  • Scoped: Per-request instances (sessions)

6. Control Flow

// Show - Conditional rendering
<Show when={isLoggedIn()}>
  <Dashboard />
</Show>

<Show when={user()} fallback={<Spinner />}>
  {(u) => <Profile user={u} />}
</Show>

// For - Keyed lists (optimal updates)
<For each={items()}>
  {(item, index) => (
    <div>
      {index()}: {item.name}
      <button onClick={() => removeItem(item.id)}>Remove</button>
    </div>
  )}
</For>

// Index - Index-based iteration
<Index each={colors()}>
  {(color, i) => (
    <div style={`color: ${color()}`}>
      Item {i}: {color()}
    </div>
  )}
</Index>

ForRegistry:

  • Keyed by item ID
  • Minimal re-renders
  • Smooth animations

Index:

  • Keyed by position
  • Useful for primitive arrays
  • Efficient reshuffling

7. Advanced Patterns

// Batch updates for performance
import { batch } from '@pulsar-framework/pulsar.dev';

const updateMultiple = () => {
  batch(() => {
    setFirstName('John');
    setLastName('Doe');
    setAge(30);
    setEmail('john@example.com');
  });
  // Only ONE update cycle for all changes
};

// Memos for expensive computations
const fullName = createMemo(() => {
  console.log('Computing full name...');
  return `${firstName()} ${lastName()}`;
});

// Effects for side effects
createEffect(() => {
  console.log(`User is now ${age()} years old`);
  localStorage.setItem('age', String(age()));
});

Complete Examples

Demo Applications:

# Run the showcase
cd packages/pulsar-ui.dev
pnpm showcase:dev

Why Pulsar?

Pulsar isn't about radical innovation—it's about synthesis without compromise.

Born from 15+ years of building with jQuery, Knockout, Angular, Vue, and React, Pulsar combines proven patterns:

  • Angular's dependency injection → without the bloat
  • React's hooks API → without the virtual DOM
  • SolidJS's fine-grained reactivity → with familiar patterns
  • Svelte's compiler approach → with TypeScript-first design
  • Vue's progressive enhancement → with type safety

The result? A framework where you don't choose between:

  • Performance vs developer experience
  • Bundle size vs features
  • Innovation vs familiarity
  • Type safety vs simplicity

Current Limitations (Beta)ramework-agnostic form management library

  • ✅ Works with Pulsar, React, Vue, Angular, vanilla JS
  • ✅ 6 languages built-in (EN, FR, ES, DE, PT, IT)
  • ✅ 12+ country validation (phone, postal, SSN)
  • ✅ 18+ validators with intelligent caching
  • ✅ IoC/DI patterns that inspired Pulsar's architecture
  • ✅ 45KB core (12KB gzipped), zero dependencies

Pulsar v0.9.0-alpha Status:

  • SSR/SSG Support - Full server-side rendering implemented (v0.8.0)
  • Enhanced Router - Path params, guards, nested routes complete
  • ⚠️ DevTools Integration - Redux DevTools working; dedicated browser extension planned for v1.0
  • Forms Integration - formular.dev integration with full validation
  • HTTP Client - Production-ready with caching and interceptors
  • CLI Tools - Scaffolding, generation, and integration commands
  • Testing Utilities - Component testing and form helpers
  • ⚠️ Small Ecosystem - Few third-party libraries (growing)
  • ⚠️ Breaking Changes Possible - API stabilizing for v1.0
  • ⚠️ Documentation Growing - Core docs complete, more examples needed

Production Readiness:

  • Suitable for production with stable APIs (core, router, state, forms, SSR)
  • ✅ Core features battle-tested with 300+ passing tests
  • ⚠️ Monitor releases for breaking changes until v1.0.0
  • ✅ Enterprise patterns (DI, state management) production-ready

Best for:

  • 🚀 Production applications (with caution for API changes)
  • 🏭 Enterprise internal tools and dashboards
  • 📚 Learning modern reactive patterns
  • 🔬 Building type-safe, reactive UIs
  • 🧪 Prototyping and experiments
  • 💻 Contributing to open-source frameworks

Not recommended for:

  • ❌ Mission-critical applications requiring 100% API stability (wait for v1.0.0)
  • ❌ Projects heavily dependent on extensive third-party React/Vue ecosystems
  • ❌ Teams unable to monitor and adapt to breaking changes

Documentation

Core Guides

Feature Documentation

Examples


Ecosystem

Pulsar is a modular framework with dedicated packages for each concern:

Core Packages

Package Description Repository
pulsar.dev Main framework with reactivity, router, DI, lifecycle GitHub
@pulsar/transformer TypeScript JSX transformer for compile-time optimization GitHub
@pulsar/vite-plugin Vite integration plugin GitHub
@pulsar/design-tokens Framework-agnostic design tokens & brand assets GitHub
@pulsar/ui Component library built with Pulsar GitHub
pulsar-demo Example applications and demos GitHub

Related Projects

  • formular.dev - Form management with IoC/DI patterns that inspired Pulsar's architecture

Contributing

Pulsar is in active development (v0.7.0-alpha). Contributions are welcome!

Ways to Contribute

  • 🐛 Report bugs - Open issues with detailed reproduction steps
  • 💡 Suggest features - Share ideas for framework improvements
  • 📖 Improve docs - Help make our documentation clearer
  • 🧪 Write tests - Increase coverage and catch regressions
  • 💻 Submit PRs - Implement features or fix bugs
  • 🎨 Build components - Contribute to the component library
  • 📢 Spread the word - Share Pulsar with other developers

Development Setup

For Contributors: Full Monorepo with Submodules

Pulsar is developed as a monorepo with multiple packages distributed across separate Git repositories linked as submodules.

# Clone the main monorepo
git clone https://github.com/binaryjack/visual-schema-builder.git
cd visual-schema-builder

# Initialize and clone all submodules (pulsar.dev, formular.dev, pulsar-demo, etc.)
git submodule init
git submodule update --recursive

# Install dependencies across all packages
pnpm install

# Build all packages in correct dependency order
pnpm build

# Run demo applications
cd packages/pulsar-demo
pnpm dev

Submodule packages:

  • packages/pulsar.dev - Core framework (GitHub)
  • packages/formular.dev - Form library (GitHub)
  • packages/pulsar-demo - Demo apps (GitHub)
  • packages/pulsar-transformer - TypeScript transformer (GitHub)
  • packages/pulsar-vite-plugin - Vite plugin (GitHub)
  • packages/pulsar-design-system - Design tokens (GitHub)
  • packages/pulsar-ui.dev - Component library (GitHub)
  • packages/pulsar-formular-ui - Form examples (GitHub)

Updating submodules:

# Pull latest changes from all submodule repositories
git submodule update --remote --recursive

# Commit submodule updates to main repo
git add packages/
git commit -m "chore: update submodules to latest"

For Package Development: Individual Package

If you only want to work on a specific package:

# Clone individual package repository
git clone https://github.com/binaryjack/pulsar.dev.git
cd pulsar.dev

# Install dependencies
pnpm install

# Build
pnpm build

# Run tests
pnpm test

Code Guidelines

  • ✅ TypeScript strict mode (no any types)
  • ✅ Feature slice pattern (one item per file)
  • ✅ Prototype-based classes for core APIs
  • ✅ Comprehensive JSDoc comments
  • ✅ Test coverage >80% for new features
  • ✅ Follow existing code style and patterns

See CONTRIBUTING.md for detailed guidelines.


License

MIT License - Copyright (c) 2026 Pulsar Framework

See LICENSE for full details.


Acknowledgments

Built with ⚡ by Tadeo Piana and contributors who refuse to compromise.

Special thanks to the authors of React, SolidJS, Svelte, and Vue for pioneering the patterns that made Pulsar possible.


Pulsar Framework - v0.7.0-alpha
TypeScript-first reactive UI framework with compile-time JSX transformation

GitHubConnect with the Creator

IssuesRoadmapDocs

About

React signal based like frontend lightweight framework

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors