{"id":31588541,"url":"https://github.com/hrutavmodha/twiggle","last_synced_at":"2026-05-15T22:31:25.003Z","repository":{"id":317007835,"uuid":"1055710431","full_name":"hrutavmodha/twiggle","owner":"hrutavmodha","description":"A basic frontend framework for building UIs through JSX","archived":false,"fork":false,"pushed_at":"2025-11-15T05:46:16.000Z","size":2173,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-15T07:20:15.409Z","etag":null,"topics":["framework","frontend","jsx","reactive","web"],"latest_commit_sha":null,"homepage":"https://twiggle-docs.onrender.com/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hrutavmodha.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-12T17:18:27.000Z","updated_at":"2025-11-15T05:46:19.000Z","dependencies_parsed_at":"2025-10-17T07:20:49.664Z","dependency_job_id":"a658eb71-200b-4573-a9ea-875627cd90f3","html_url":"https://github.com/hrutavmodha/twiggle","commit_stats":null,"previous_names":["hrutavmodha/twiggle"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/hrutavmodha/twiggle","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hrutavmodha%2Ftwiggle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hrutavmodha%2Ftwiggle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hrutavmodha%2Ftwiggle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hrutavmodha%2Ftwiggle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hrutavmodha","download_url":"https://codeload.github.com/hrutavmodha/twiggle/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hrutavmodha%2Ftwiggle/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32497812,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-30T13:12:12.517Z","status":"online","status_checked_at":"2026-05-01T02:00:05.856Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["framework","frontend","jsx","reactive","web"],"created_at":"2025-10-06T02:10:36.597Z","updated_at":"2026-05-01T12:32:54.632Z","avatar_url":"https://github.com/hrutavmodha.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Twiggle\n\n![Twiggle Logo](./website/static/logo.png)\n\nTiny, focused front-end primitives: a custom JSX runtime, minimal DOM renderer, and a reactive state primitive.\n\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](#license)\n[![Version](https://img.shields.io/badge/version-1.1.1-brightgreen)](https://www.npmjs.com/package/twiggle)\n\n\u003e **Note:** Twiggle is currently in its early stage and should not be used in the production apps.\n\nJoin [Discord](https://discord.com/channels/1429102316652597290/1429102317248053331) for any queries\n\nMaintainer: Hrutav Modha\n\nLicense: MIT\n\n---\n\n## Table of Contents\n\n- [Why Twiggle](#why-twiggle)\n- [Installation](#installation)\n- [Quick start](#quick-start)\n- [Core concepts](#core-concepts)\n    - [JSX \u0026 createElement](#jsx--createelement)\n    - [Renderer](#renderer)\n    - [State primitive](#state-primitive)\n- [Vite plugin](#vite-plugin)\n- [API reference](#api-reference)\n- [Development](#development)\n- [Contributing](#contributing)\n- [FAQ](#faq)\n- [License](#license)\n\n---\n\n## Why Twiggle\n\nTwiggle is intentionally minimal. It focuses on clarity and a small runtime surface for use-cases like:\n\n- Learning how frameworks work under the hood.\n- Small demos, playgrounds, documentation sites.\n- Projects that prefer direct DOM manipulation and minimal dependencies.\n\nDesign principles:\n\n- Minimal and transparent (small, well-commented code).\n- Simple reactivity — explicit effect tracking and subscription.\n- Works with modern tooling via a small Vite plugin.\n\n---\n\n## Installation\n\nInstall from npm:\n\n```bash\nnpm install twiggle\n```\n\nOr use the package from the monorepo during local development (root of workspace):\n\n```bash\nnpm install\ncd packages/twiggle\nnpm run start\n```\n\nAvailable scripts (in `packages/twiggle/package.json`):\n\n- `start` — start Vite dev server\n- `build` — run Vite build\n- `test` — run Vitest\n- `test:ui` — run Vitest UI\n\n---\n\n## Quick Start\n\nMinimal example (TypeScript / TSX):\n\n```tsx\n/** src/main.tsx */\nimport render from 'twiggle'\nimport Home from './pages/Home'\n\nconst root = document.getElementById('root')!\nrender(\u003cHome /\u003e, root)\n```\n\nFunction component example:\n\n```tsx\nfunction Greeting(props: { name: string }) {\n    return \u003cdiv\u003eHello, {props.name}!\u003c/div\u003e\n}\n\nrender(\u003cGreeting name=\"Alice\" /\u003e, document.getElementById('root'))\n```\n\nNote: The JSX transform must target Twiggle's runtime (see Vite plugin section) or you can import the runtime directly in your build config.\n\n## Playground\n\nTry Twiggle immediately in the browser using the interactive playground:\n\n[Open the Twiggle Playground](https://livecodes.io/?config=https://raw.githubusercontent.com/hrutavmodha/twiggle/main/.livecodes/config.json)\n\nThe playground loads a small example and lets you edit components live. It's a great way to experiment without cloning the repo.\n\n---\n\n## Core Concepts\n\n### JSX \u0026 CreateElement\n\nTwiggle implements a small JSX runtime. When JSX is compiled it calls `createElement(type, props)`. Supported `type` values:\n\n- string tag (e.g. `'div'`) — creates a DOM element and applies props/children\n- `'Fragment'` — returns a `DocumentFragment`\n- function component — `type(props)` is invoked and must return a DOM node or fragment\n\nProps convention:\n\n- `children` may be string, number, element, array of elements\n- DOM event handlers use lowercase names (e.g. `onclick`, not `onClick`)\n\n### Renderer\n\n`render(element, parent)` mounts a DOM node or fragment to the `parent` node. The current implementation clears `parent.innerHTML` and appends the element. This is intentionally simple to keep the runtime small.\n\n### State Primitive\n\nAPI:\n\n- `createState\u003cT\u003e(initial)` — returns `{ get: () =\u003e T, set: (v: T) =\u003e void }`\n- `runSideEffect(fn)` — runs `fn` and tracks any `get()` calls performed during the execution. When a tracked state updates, the effect is re-run.\n\nThis is a minimal reactive system built around an effect stack and per-state subscriber lists. It is not a full reactive framework but is tiny and easy to reason about.\n\nExample counter:\n\n```tsx\nimport { createState, runSideEffect } from 'twiggle'\n\nconst counter = createState(0)\n\nexport default function Counter() {\n    runSideEffect(() =\u003e {\n        // reads counter.get() to subscribe\n        const value = counter.get()\n        // re-run when counter.set is called\n        console.log('counter', value)\n    })\n\n    return (\n        \u003cdiv\u003e\n            \u003cspan\u003e{counter.get()}\u003c/span\u003e\n            \u003cbutton onclick={() =\u003e counter.set(counter.get() + 1)}\u003eIncrement\u003c/button\u003e\n        \u003c/div\u003e\n    )\n}\n```\n\n## Vite Plugin\n\nUse the official Vite plugin in this monorepo to compile JSX for Twiggle and enable reactive transforms.\n\nInstall and add to `vite.config.js`:\n\n```js\nimport { defineConfig } from 'vite'\nimport twiggle from 'vite-plugin-twiggle'\n\nexport default defineConfig({\n    plugins: [twiggle()],\n})\n```\n\nWhat the plugin does:\n\n- Runs Babel to transform JSX using `@babel/preset-react` configured with `runtime: 'automatic'` and `importSource: 'twiggle/jsx'`.\n- Applies a small custom Babel plugin bundled in `packages/vite-plugin-twiggle` to support reactive expression transforms used by Twiggle's runtime.\n\nIf you don't use the plugin, ensure your JSX compiler targets the Twiggle runtime or import the proper runtime functions directly.\n\n---\n\n## API Reference\n\nRenderer\n\n- `createElement(type, props)` — internal JSX entry point.\n- `render(element: HTMLElement | DocumentFragment, parent: HTMLElement): void` — mount node to parent.\n\nState\n\n- `createState\u003cT\u003e(value: T): { get: () =\u003e T; set: (v: T) =\u003e void }`\n- `runSideEffect(fn: () =\u003e void): void`\n\nSee the `src` folder for implementation details and comments.\n\n---\n\n## Development\n\nClone and install dependencies from the monorepo root:\n\n```bash\ngit clone https://github.com/hrutavmodha/twiggle.git\nnpm install\n```\n\nRun the example/dev server for the `twiggle` package:\n\n```bash\ncd packages/twiggle\nnpm run start\n```\n\nBuild the package:\n\n```bash\ncd packages/twiggle\nnpm run build\n```\n\nRun tests:\n\n```bash\ncd packages/twiggle\nnpm run test\n```\n\nQuality checks you should run before opening a PR:\n\n- Build: `npm run build`\n- Tests: `npm run test`\n- Type checks (optional): `tsc --noEmit` from the package directory\n\n---\n\n## Contributing\n\nContributions are welcome. Please follow these guidelines:\n\n1. Fork the repo and create a descriptive branch name.\n2. Keep changes small and focused. Add tests where applicable.\n3. Run the test suite and ensure the build passes.\n4. Open a pull request describing the problem, approach, and any migration notes.\n\nSee `CONTRIBUTING.md` for the project's broader contribution rules.\n\n---\n\n## FAQ\n\n1. Is Twiggle a full framework?\n\nNo. Twiggle is a tiny set of primitives meant for learning, demos, and small apps.\nIt lacks many features of full frameworks (advanced component lifecycles, SSR, etc.)\n\n2. Can I use Twiggle in production?\n\nYou can, but consider the tradeoffs (small feature set, simpler reactivity). For production apps that need scaling, a more feature-complete framework is recommended.\n\n---\n\n## License\n\nMIT — see the `LICENSE` file for details.\n\n---\n\nMaintainer: Hrutav Modha — please open issues for bugs or feature requests.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhrutavmodha%2Ftwiggle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhrutavmodha%2Ftwiggle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhrutavmodha%2Ftwiggle/lists"}