{"id":20170153,"url":"https://github.com/marcodpt/merlin","last_synced_at":"2025-10-26T22:38:51.576Z","repository":{"id":111252434,"uuid":"575364629","full_name":"marcodpt/merlin","owner":"marcodpt","description":"A functional JS framework that values ​​elegance, simplicity and minimalism.","archived":false,"fork":false,"pushed_at":"2024-09-26T18:48:19.000Z","size":127,"stargazers_count":9,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-24T03:53:18.550Z","etag":null,"topics":["component","components","elm","elm-architecture","esmodule","esmodules","framework","frontend-framework","hyperapp","hyperscript","javascript-framework","js","microframework","microfrontends","no-build","router","spa","ssr","vdom","vue"],"latest_commit_sha":null,"homepage":"https://marcodpt.github.io/merlin/","language":"HTML","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/marcodpt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2022-12-07T10:52:05.000Z","updated_at":"2024-12-03T13:45:02.000Z","dependencies_parsed_at":"2023-03-12T08:00:42.142Z","dependency_job_id":"d12ee4c7-ec50-4b4c-93ee-a21a0b41d3b6","html_url":"https://github.com/marcodpt/merlin","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcodpt%2Fmerlin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcodpt%2Fmerlin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcodpt%2Fmerlin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcodpt%2Fmerlin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marcodpt","download_url":"https://codeload.github.com/marcodpt/merlin/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248143685,"owners_count":21054821,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["component","components","elm","elm-architecture","esmodule","esmodules","framework","frontend-framework","hyperapp","hyperscript","javascript-framework","js","microframework","microfrontends","no-build","router","spa","ssr","vdom","vue"],"created_at":"2024-11-14T01:17:28.736Z","updated_at":"2025-10-26T22:38:46.538Z","avatar_url":"https://github.com/marcodpt.png","language":"HTML","readme":"# ![](favicon.ico) The Merlin JS framework\n\nA functional JS framework that values elegance, simplicity and minimalism. \n\n\n[![Demo](https://img.shields.io/badge/Demo-blue)](https://marcodpt.github.io/merlin/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![GitHub Tag](https://img.shields.io/github/v/tag/marcodpt/merlin)](https://github.com/marcodpt/merlin/tags)\n[![bundlejs](https://deno.bundlejs.com/badge?q=https%3A%2F%2Fraw.githubusercontent.com%2Fmarcodpt%2Fmerlin%2Fmain%2Findex.js\u0026treeshake=%5B*%5D)](https://bundlejs.com/?q=https%3A%2F%2Fraw.githubusercontent.com%2Fmarcodpt%2Fmerlin%2Fmain%2Findex.js\u0026treeshake=%5B*%5D)\n\n[State Management](https://github.com/marcodpt/ring) +\n[vDom](https://github.com/jorgebucaran/superfine) +\n[Template Engine](https://github.com/marcodpt/tint) +\n[SPA Router](https://github.com/marcodpt/wand) =  ❤️\n\n## ❤️ Features\n - No building tools.\n - Single HTML file by default.\n - Built by combining ideas from small modules following the\n[UNIX philosophy](https://en.wikipedia.org/wiki/Unix_philosophy).\n - Pure functional ELM architecture state management\n[library](https://github.com/marcodpt/ring).\n - Ultrafast [vDom](https://github.com/jorgebucaran/superfine).\n - Server side rendered by default\n([templates](https://marcodpt.github.io/tint/syntax/intro.html) are valid html).\n - Built-in Single Page Application [Router](https://github.com/marcodpt/wand).\n - Ridiculously small API. After reading this file you will understand `Merlin`\nbetter than me.\n\n## 💡 Showcase\n[![Demo](https://img.shields.io/badge/Demo-blue)](https://marcodpt.github.io/merlin/examples/todo.html)\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003ctitle\u003eTodo - The Merlin JS framework\u003c/title\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n    \u003cmain\u003e\n      \u003ch1\u003eTo do list\u003c/h1\u003e\n      \u003cinput type=\"text\" value:=\"value\" oninput:=\"NewValue\"\u003e\n      \u003cul\u003e\n        \u003cli each:=\"todos\" text:\u003e\u003c/li\u003e\n      \u003c/ul\u003e\n      \u003cbutton onclick:=\"AddTodo\"\u003eNew!\u003c/button\u003e\n    \u003c/main\u003e\n    \u003cscript type=\"module\"\u003e\n      import {app} from \"https://cdn.jsdelivr.net/gh/marcodpt/merlin/index.min.js\"\n\n      app({\n        node: document.body.querySelector('main'),\n        init: {\n          value: '',\n          todos: []\n        },\n        register: update =\u003e ({\n          NewValue: ev =\u003e update(state =\u003e ({\n            ...state,\n            value: ev.target.value\n          })),\n          AddTodo: () =\u003e update(({todos, value}) =\u003e ({\n            todos: todos.concat(value),\n            value: ''\n          }))\n        }),\n        view: (state, events) =\u003e ({\n          ...state,\n          ...events\n        })\n      })\n    \u003c/script\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\n## 💯 Examples\n - Counter:\n[![Demo](https://img.shields.io/badge/Demo-blue)](https://marcodpt.github.io/merlin/examples/counter.html)\n[![Source](https://img.shields.io/badge/Source-gray)](https://github.com/marcodpt/merlin/blob/main/examples/counter.html)\n - Todo SSR:\n[![Demo](https://img.shields.io/badge/Demo-blue)](https://marcodpt.github.io/merlin/examples/todo_ssr.html)\n[![Source](https://img.shields.io/badge/Source-gray)](https://github.com/marcodpt/merlin/blob/main/examples/todo_ssr.html)\n - Clock:\n[![Demo](https://img.shields.io/badge/Demo-blue)](https://marcodpt.github.io/merlin/examples/clock.html)\n[![Source](https://img.shields.io/badge/Source-gray)](https://github.com/marcodpt/merlin/blob/main/examples/clock.html)\n - Stopwatch:\n[![Demo](https://img.shields.io/badge/Demo-blue)](https://marcodpt.github.io/merlin/examples/stopwatch.html)\n[![Source](https://img.shields.io/badge/Source-gray)](https://github.com/marcodpt/merlin/blob/main/examples/stopwatch.html)\n - Table:\n[![Demo](https://img.shields.io/badge/Demo-blue)](https://marcodpt.github.io/merlin/examples/table.html)\n[![Source](https://img.shields.io/badge/Source-gray)](https://github.com/marcodpt/merlin/blob/main/examples/table.html)\n - Components:\n[![Demo](https://img.shields.io/badge/Demo-blue)](https://marcodpt.github.io/merlin/examples/components.html)\n[![Source](https://img.shields.io/badge/Source-gray)](https://github.com/marcodpt/merlin/blob/main/examples/components.html)\n - SPA Router:\n[![Demo](https://img.shields.io/badge/Demo-blue)](https://marcodpt.github.io/merlin/examples/spa.html)\n[![HTML](https://img.shields.io/badge/HTML-red)](https://github.com/marcodpt/merlin/blob/main/examples/spa.html)\n[![JS](https://img.shields.io/badge/JS-gray)](https://github.com/marcodpt/merlin/blob/main/examples/spa.js)\n\n## 📖 API\n`Merlin` uses [Tint](https://github.com/marcodpt/tint) as its template engine,\nyou should read the [docs](https://marcodpt.github.io/tint/syntax/intro.html)\nfor a complete reference.\n\n### app({node, template?, view?, init, register}) =\u003e stop\n\n#### node: DOM Node \nWhere to mount the `app`.\n\n#### template: Dom Node\nAn optional `template` to render, if nothing is passed the `node` itself will\nbe used.\n\n#### view: (state, events) =\u003e data\nExactly as defined in [Ring](https://github.com/marcodpt/ring#-api).\n\nThe only exception is that it returns `data` that will be used for\n[Tint](https://github.com/marcodpt/tint) to render the page,\nif not passed the unmodified `state` will be returned to\n[Tint](https://github.com/marcodpt/tint).\n\n#### init: _\nExactly as defined in [Ring](https://github.com/marcodpt/ring#-api).\n\nThe initial `state` of the `app`. It can be any type of data.\n\n#### register: (update, dispatch) =\u003e events\nExactly as defined in [Ring](https://github.com/marcodpt/ring#-api).\n\nIt is called before initializing the `app` returning the `registered`\n`events`.\n\n#### stop: () =\u003e ()\nExactly as defined in [Ring](https://github.com/marcodpt/ring#-api).\n\nReturns a function that `stops` the `app`.\n\n### spa({node, routes, plugins?}) =\u003e stop\n\n#### node: DOM Node\nWhere to mount the `spa`.\n\n#### routes: {route: {template?, init?, view?, register?}}\n\n##### route: string\nExactly as defined in [Wand](https://github.com/marcodpt/wand#-api).\n\nAccepts `*` to match any path and `:param` to declare variable.\n\n##### template: Dom Node\nA template to be rendered on the route, if nothing is passed it will use the\noriginal content of the `node`.\n\n##### init: routeData =\u003e state\nAn optional function that will be called every time the route is started,\nreturning the initial state. If not passed, `Params` from `routeData` will be\nused as the initial `state`.\n\n##### view, register\nExactly as defined in `app`\n\n#### plugins: [routeData =\u003e ()]\nExactly as defined in [Wand](https://github.com/marcodpt/wand#-api).\n\nAn optional array of `plugins`, which are executed sequentially with each\n`route` `change` and which can modify the `routeData`.\n\n#### stop: () =\u003e ()\nExactly as defined in [Wand](https://github.com/marcodpt/wand#-api).\n\nReturns a function that stops the `spa`.\n\n#### routeData {url, route, path, Params, query, Query}\nExactly as defined in [Wand](https://github.com/marcodpt/wand#-api).\n\n`Plugins` can introduce new properties or change existing ones.\n\n##### url: string\nThe `url` as it was passed.\n\n##### route: string\nThe `route` that matched as declared.\n\n##### path: string\nThe part of the `url` before the `?`.\n\n##### Params: object\nObject containing the variables declared in the `route` with the associated\nvalues in the current `path`.\n\n##### query: string\nThe part of `url` after the `?`.\n\n##### Query: object\nParsed query string.\n\n## 🤝 Contributing\nIt's a very simple project.\nAny contribution, any feedback is greatly appreciated.\n\n## ⭐ Support\nIf this project was useful to you, consider giving it a star on github, it's a\nway to increase evidence and attract more contributors.\n\n## 🙏 Acknowledgment\nThis work is hugely influenced by these amazing projects:\n - [superfine](https://github.com/jorgebucaran/superfine)\n - [raj](https://github.com/andrejewski/raj)\n - [ring](https://github.com/marcodpt/ring)\n - [tint](https://github.com/marcodpt/tint)\n - [wand](https://github.com/marcodpt/wand)\n - [hyperapp](https://github.com/jorgebucaran/hyperapp)\n - [elm](https://github.com/elm)\n\nA huge thank you to all the people who contributed to these projects.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcodpt%2Fmerlin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarcodpt%2Fmerlin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcodpt%2Fmerlin/lists"}