Absolutely minimal view layer for building web interfaces.

Overview

Superfine

Superfine is a minimal view layer for building web interfaces. Think Hyperapp without the framework—no state machines, effects, or subscriptions—just the absolute bare minimum (1 kB minified+gzipped). Mix it with your favorite state management library or use it standalone for maximum flexibility.

Here's the first example to get you started. Try it here—no build step required!

<!DOCTYPE html>
<html lang="en">
  <head>
    <script type="module">
      import { h, text, patch } from "https://unpkg.com/superfine"

      const setState = (state) =>
        patch(
          document.getElementById("app"),
          h("main", {}, [
            h("h1", {}, text(state)),
            h("button", { onclick: () => setState(state - 1) }, text("-")),
            h("button", { onclick: () => setState(state + 1) }, text("+")),
          ])
        )

      setState(0)
    </script>
  </head>
  <body>
    <main id="app"></main>
  </body>
</html>

When describing how a page looks in Superfine, we don't write markup. Instead, we use the h() and text() functions to create a lightweight representation of the DOM (or virtual DOM for short), and patch() to actually render the DOM.

Superfine won't re-create the entire DOM every time we use patch(). By comparing the old and new virtual DOM we are able to change only the parts of the DOM that need to change instead of rendering everything from scratch.

Next up, let's take a look at a simple todo app. You can only add or cross off todos with it. Can you figure out what's happening just by poking around the code a bit? Have a go here.

<script type="module">
  import { h, text, patch } from "https://unpkg.com/superfine"

  const updateValue = (state, value) => ({ ...state, value })

  const addTodo = (state) => ({
    ...state,
    value: "",
    todos: state.todos.concat(state.value).filter(any => any),
  })

  const setState = (state) => {
    patch(
      document.getElementById("app"),
      h("main", {}, [
        h("h2", {}, text("To-do list")),
        h("ul", {},
          state.todos.map((todo) =>
            h("li", {}, [
              h("label", {}, [
                h("input", { type: "checkbox" }),
                h("span", {}, text(todo))
              ]),
            ])
          )
        ),
        h("section", {}, [
          h("input", {
            type: "text",
            value: state.value,
            oninput: ({ target }) =>
              setState(updateValue(state, target.value)),
          }),
          h("button",
            { onclick: () => setState(addTodo(state)) },
            text("Add todo")
          ),
        ]),
      ])
    )
  }

  setState({ todos: ["Learn Quantum Physics"], value: "" })
</script>

Check out more examples

Now it's your turn to take Superfine for a spin. Can you add a button to clear all todos? How about bulk-marking as done? If you get stuck or would like to ask a question, just file an issue and I'll try to help you out—have fun!

Installation

npm install superfine

Top-Level API

h(type, props, [children])

Create them virtual DOM nodes! h() takes the node type; an object of HTML or SVG attributes, and an array of child nodes (or just one child node).

h("main", { class: "relative" }, [
  h("label", { for: "outatime" }, text("Destination time:")),
  h("input", { id: "outatime", type: "date", value: "2015-10-21" }),
])

text(string)

Create a virtual DOM text node.

h("h1", {}, text("1.21 Gigawatts!?!"))

patch(node, vdom)

Render a virtual DOM on the DOM efficiently. patch() takes an existing DOM node, a virtual DOM, and returns the freshly patched DOM.

const node = patch(
  document.getElementById("app"),
  h("main", {}, [
    // ...
  ])
)

Attributes API

Superfine nodes can use any of the HTML attributes, SVG attributes, DOM events, and also keys.

class:

To specify one or more CSS classes, use the class attribute. This applies to all regular DOM and SVG elements alike. The class attribute expects a string.

const mainView = h("main", { class: "relative flux" }, [
  // ...
])

style:

Use the style attribute to apply arbitrary CSS rules to your DOM nodes. The style attribute expects a string.

Important: We don't recommend using the style attribute as the primary means of styling elements. In most cases, class should be used to reference classes defined in an external CSS stylesheet.

const alertView = h("h1", { style: "color:red" }, text("Great Scott!"))

key:

Keys help identify nodes whenever we update the DOM. By setting the key property on a virtual DOM node, you declare that the node should correspond to a particular DOM element. This allows us to re-order the element into its new position, if the position changed, rather than risk destroying it.

Important: Keys must be unique among sibling nodes.

import { h } from "superfine"

export const imageGalleryView = (images) =>
  images.map(({ hash, url, description }) =>
    h("li", { key: hash }, [
      h("img", {
        src: url,
        alt: description,
      }),
    ])
  )

Recycling

Superfine will patch over server-side rendered HTML, recycling existing content instead of creating new elements. This technique enables better SEO, as search engine crawlers will see the fully rendered page more easily. And on slow internet or slow devices, users will enjoy faster time-to-content as HTML renders before your JavaScript is downloaded and executed.

<!DOCTYPE html>
<html lang="en">
  <head>
    <script type="module">
      import { h, text, patch } from "https://unpkg.com/superfine"

      const setState = (state) =>
        patch(
          document.getElementById("app"),
          h("main", {}, [
            h("h1", {}, text(state)),
            h("button", { onclick: () => setState(state - 1) }, text("-")),
            h("button", { onclick: () => setState(state + 1) }, text("+")),
          ])
        )

      setState(0)
    </script>
  </head>
  <body>
    <main id="app"><h1>0</h1><button>-</button><button>+</button></main>
  </body>
</html>

Notice that all the necessary HTML is already served with the document.

Superfine expects the markup to be identical between the server and the client. Treat mismatches as bugs and fix them! Now you just need a way to send content to browsers.

JSX

JSX is a language syntax extension that lets you write HTML tags interspersed with JavaScript. To compile JSX to JavaScript, install the JSX transform plugin, and create a .babelrc file in the root of your project like this:

{
  "plugins": [["transform-react-jsx", { "pragma": "h" }]]
}

Superfine doesn't support JSX out of the box, but adding it to your project is easy.

import { h, text } from "superfine"

const jsx = (type, props, ...children) =>
  typeof type === "function"
    ? type(props, children)
    : h(type, props || {}, children.flatMap((any) =>
        typeof any === "string" || typeof any === "number" ? text(any) : any
      )
    )

Import that everywhere you're using JSX and you'll be good to go. Here's a working example.

import jsx from "./jsx.js"
import { patch } from "superfine"

License

MIT

Comments
  • Unexpected reordering after keyed removal

    Unexpected reordering after keyed removal

    Per this example using current unstable picodom @2.0.0

    https://jsfiddle.net/4eunk2um/

    Click to remove elements from the list, and note how the removed element always ends up at the bottom of the range - because it doesn't get destroyed until 2 seconds later.

    Keyed updates presumably exist, for one, so you can do this sort of thing?

    bug discussion 
    opened by mindplay-dk 63
  • What if: class components?

    What if: class components?

    About class components (https://github.com/jorgebucaran/superfine/issues/134), I was thinking, what if we could do something like this?

    import { h, Super, patch } from "superfine"
    
    class Hi extends Super {
      state = { say: "Hi" }
    
      render = () => (
        <h1>{this.say}</h1>
      )
    }
    
    patch(null, <Hi />, document.body)
    

    Just throwing crazy ideas out there?

    discussion wontfix 
    opened by jorgebucaran 55
  • `oncreate` vs `onupdate`

    `oncreate` vs `onupdate`

    I noticed that onupdate doesn't fire during the first update, is this intentional?

    I think, in most systems that offer both a create and update notification, the initial creation triggers both a create and an update notification, because there isn't typically much use for an update notification that doesn't fire the first time.

    Typically the notifications you need are for creation, for destruction, or for all updates - rarely does anyone need a notification for "all updates except the first one".

    Thoughts?

    discussion 
    opened by mindplay-dk 45
  • Remove `parent` as 1st mandatory argument for patch

    Remove `parent` as 1st mandatory argument for patch

    Having parent as first argument works very well when the all app is designed and wrote with picodom but not that much when used in a mixed libs app. (yes it happens in real world)

    You cannot then just render / create a component to get its main node and then append it manually to a parent node of your choice at the time you choose.

    To get around this you have to create a fake parent with document.createElement but that add a useless layer.

    I'm also not a big fan of that kind of dependency injection and lake of separation which introduce a dependence between the child and its parent, I do prefer the other way, parent knowing its children, but I think this is just a matter of taste.

    discussion wontfix 
    opened by JSteunou 43
  • Lifecycle Events

    Lifecycle Events

    4b3593b23cc49e367aa8d019af84105e2bd81c6f dropped support for lifecycle events without much fanfare, what's the rationale and the recommendation for implementing features that would otherwise have been implemented with lifecycle events (e.g. hyperapp had a thorough discussion about a similar change).

    opened by elyobo 35
  • Improve TypeScript types and add TypeScript compilation tests

    Improve TypeScript types and add TypeScript compilation tests

    I've added some sample TypeScript files to validate the typings in the repo.

    • add JSDoc comments
    • add lifecycle methods and key property

    I've taken the feedback from @Swizz PR in hyperapp and incorporated it here. Let me know if I've missed anything.

    I'll be adding comments to the PR about the reason for each change.

    Resolves #34, #35

    enhancement 
    opened by andrewiggins 31
  • Missing `ondestroy` event for deep removals

    Missing `ondestroy` event for deep removals

    It appears the onremove event isn't triggered for children, when the parent is removed - I believe the following test demonstrates the problem:

    https://github.com/mindplay-dk/picodom/commit/f108584890bdc936b44e8db5c071384bae3f3476

    Looks like a bug? I'm unsure how to address it.

    discussion 
    opened by mindplay-dk 30
  • Added computed keys based on attribute names to prevent reinsertion on prepend

    Added computed keys based on attribute names to prevent reinsertion on prepend

    I don't want this merged — only for discussion. All of the unit tests are passing, however I'm sure this change has unintended consequences that are not covered by the tests.

    Changes I'm proposing are to add a computed key based on the passed attributes — keys only as values are more likely to change between renders. If attributes are added/removed between renders then the element will be reinserted and can be solved by specifying a key manually, but I do believe that attributes are generally consistent between renders – only their values will differ.

    Due to above change I've had to modify one of the tests where an attribute was removed (xlink:href). It was failing because an attribute was removed and so its key differed. Solutions to this are:

    • Specify the key manually (chosen solution for the test);
    • Select the use again (via querySelector) as it's a new element;
    • Be explicit and add "xlink:href": null to the attribute list;
    enhancement 
    opened by Wildhoney 23
  • 2.0 API

    2.0 API

    [email protected] is coming to you very soon. The signature of patch needs to change, and I need your feedback to get it right.

    Closes

    • https://github.com/picodom/picodom/issues/80: I don't understand this issue.
    • https://github.com/picodom/picodom/issues/77: I will add new tests.
    • https://github.com/picodom/picodom/issues/92: Either one of below proposals will enable you to target a DOM element to be replaced instead of always pre-pending to a container.
    • https://github.com/picodom/picodom/issues/89: The "Double Espresso Steamed Soy Milk Foam" proposal below fixes this issue, but I'll likely proceed with "Bitter Tea" and close that issue as wontfix. There is no way to please everyone.
    • https://github.com/picodom/picodom/issues/65: I'll give a shot at adding types for VDOM events and close there.

    Bitter Tea

    Bring back the old pre-1.0 signature. This API is more flexible and easier to implement at the expense of a slightly worse developer experience (is it?). The justification is that Picodom is intended to be used to create tiny Hyperapp-like view frameworks instead of directly consumed. Still, this is IMO much better than similar popular alternatives.

    import { h, patch } from "picodom"
    
    // First and every other patch.
    let element = patch(
      container,
      element,
      oldNode,
      newNode
    )
    

    Double Espresso Steamed Soy Milk Foam

    This proposal arguably improves the surface API providing at the expense of "slightly" less flexibility. This also has out of the box SSR DOM rehydration. This API makes consuming picodom directly more fun, but a bit awkward to integrate into your own library because you need to be aware there would be essentially two ways to call patch, the first time you call it, and every other time.

    SSR recycling is enabled by providing a recycleElement to patch that works the same way as https://github.com/hyperapp/hyperapp/pull/590.

    import { h, patch } from "picodom"
    
    // First patch.
    let element = patch(vnode, containerElement)
    
    // or first patch with server side rendered rehydration
    
    let element = patch(vnode, containerElement, recycleElement)
    
    // Every other patch.
    patch(vnode, element)
    

    /cc @mindplay-dk @JSteunou @estrattonbailey @pspeter3 @maxholman @dancespiele

    discussion 
    opened by jorgebucaran 22
  • Indistinguishable properties and attributes

    Indistinguishable properties and attributes

    Currently, the patch() function treats every JSX attribute simultaneously as a property and an attribute - it initializes both, which means you have no ability to update them individually.

    Blindly treating every JSX attribute as both a property and an attribute means that most updates are unnecessarily being done twice - one of them generating either a meaningless property or a meaningless DOM attribute. The DOM accumulates a lot of garbage this way.

    For example, <div innerHTML={content}> will inject literal HTML via the innerHTML property, but will also create a useless innerHTML attribute - or in some cases, such as <input value={value}>, will initialize the value twice, first using the value property, then again using setAttribute('value', ...).

    I don't have a lot of references, but snabbdom for one separates properties from attributes - which seems sort of inevitable, at the VDOM level, if we want to solve this problem?

    discussion 
    opened by mindplay-dk 22
  • V7 and Document Fragments

    V7 and Document Fragments

    I really love new simplified patch usage and the simplified algorithm.

    However, it seems we assume that the node.parentNode always exists in https://github.com/jorgebucaran/superfine/blob/master/src/index.js#L265

    This works for the most part, but fails when the provided node is a DocumentFragment, since DocumentFragment won't have a parentNode.

    The patch in this case errors out with:

    image

    To add more context, I have a web-components wrapper based on Superfine, which was invoking the patch in v6 as https://github.com/osdevisnot/supertag/blob/master/src/supertag.ts#L94

    With V7, I believe the correct usage would simply be something like:

    this[ROOT] = patch(this[ROOT], this.render());
    

    But this fails with above error since this[ROOT] is a DocumentFragment created using

    this[ROOT] = this.attachShadow({ mode: 'open' });
    

    Any pointers on how we can use the V7 patch with DocumentFragments? Or am I missing something?

    opened by osdevisnot 20
  • Add support for declarative shadow dom

    Add support for declarative shadow dom

    This addresses my issue #188.

    This PR would allow you to write views that create shadow-roots. For example when using JSX:

    function view () {
      return <div>
        <h1>Heading 1</h1>
        <div>The styles inside this shadow-root below are completely scoped to that node. This pairs great with importing CSS from JavaScript imports.</div>
        <div shadow-root='open'>
          <h1>
            <style>{'h1 { display: flex; padding: 12px; color: white; background: dodgerblue; } div { padding: 0 24px; }'}</style>
            <button onclick={increment}>Increment</button>
            <div>{state.count}</div>
            <button onclick={decrement}>Decrement</button>
          </h1>
        </div>
      </div>
    }
    

    Where the DOM output would look like: (The root h1 inside shadow-root is required to mount children into it and the parent div has to exist so we have a place to mount the shadow-root to.)

    image

    Here's a codepen of the PR in action. https://codepen.io/dustindowell/pen/rNYeLxg

    If this is not something you're interested in it's no problem! I just think it's really cool to have encapsulation of styles and scripts without having to touch the custom elements api!

    To briefly walk over the changes.

    • I added a slot variable, because children will need to go into the shadow-root instead of the original node if the property shadow-root exists.
    • Inside the new condition, these are the minimum steps needed to create a new shadow node. Shadow root elements can only be a few different tags. The list of valid root tags can be found here: https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow. However the most common is obviously <div>. ~~I defaulted to div because I couldn't think of a good way to configure that. This is maybe something that could adjusted.~~ (see changes)
    • Finally, changing the node.appendChild to slot.appendChild so the children nodes are appended to the correct parent node.

    EDIT: ~~Perhaps a solution to configuring the node you attach inside the shadow-root would be to not allow "fragments" inside a node which has a shadow-root property. I'll think about this and make some changes.~~ (see changes)

    EDIT 2: ~~I also didn't account for patching. 😅 So I do have some work to do still.~~ (patching works fine)

    opened by whaaaley 6
  • Support for React-like `ref`s?

    Support for React-like `ref`s?

    Wouldn't it be a nice and useful feature if superfine supported ref pseudo properties like React, Preact, Dyo, uhtml etc. do?

    const elemRef = { current: null }
    // [...]
    const content = h('some-element', { ref: elemRef })
    

    Here's a little demo (based on a R&D web-component toy library that uses a ref-supporting patched version of superfine internally): TypeScript version JavaScript version

    FYI: Here's a naive quick'n'dirty implementation which obviously only provides part of the requested functionality: LINK

    enhancement 
    opened by mcjazzyfunky 23
  • How to unmount?

    How to unmount?

    React has unmountComponentAtNode, preact has render(null, element), etc.

    How would that work in Superfine?

    patch(null, null, container) // ?
    
    // or
    
    unmount(container) //?
    

    What is it expected from this operation?

    discussion enhancement 
    opened by jorgebucaran 20
  • Add type declarations

    Add type declarations

    @andrewiggins I figured I'd create a separate issue for this one, since your work is already enough to get projects up and going without it.

    It would be great if we could also get some type-checking for elements and attributes - standard DOM as well as pico's oncreate etc., and possibly SVG elements. (does pico support SVG?)

    I tried something like [elemName in keyof ElementTagNameMap]?: any; in the IntrinsicElements declaration - I think I've seen others doing something similar, but I couldn't make it work.

    Snabbdom redeclares the whole kit'n'kaboodle, I guess maybe that's a necessary evil if we want type-checking for elements/attributes?

    Either way, we can leave this for a future version, once the overall type-declarations are fully in place.

    types 
    opened by mindplay-dk 13
Releases(8.2.0)
  • 8.2.0(Feb 8, 2021)

  • 8.1.0(Jan 28, 2021)

    • Mirror Hyperapp VDOM shape (jorgebucaran/hyperapp@8e6a490).
    • Set pkg.main to index.js and don't minify just for CDN usage.
    • Fix bug in internal createNode function (#183).
      • Forgot to update replaced vnodes in the vdom while appending children.
    Source code(tar.gz)
    Source code(zip)
  • 8.0.0(Jul 27, 2020)

    Superfine 8 is smaller, faster, and more memory efficient than every Superfine that came before. This rewrite is heavily based on Hyperapp's latest VDOM modifications, but it doesn't come without a cost, so let's break it down. 🎱🛸

    Text nodes

    The most important thing to be aware of is that now we use a new text function to create text nodes.

    import { h, text } from "superfine"
    
    const hello = h("h1", {}, text("Hello"))
    

    Nested arrays

    Another important change is that h no longer flattens nested arrays. So if you were doing something like this:

    import { h, text } from "superfine"
    
    const fruitView = (list) => list.map((item) => h("li", {}, text(item)))
    
    const favoriteFruitView = () =>
      h("section", {}, [
        h("h1", {}, "My Favorite Fruit"),
        fruitView(["apple", "grapes", "melon", "mango"]),
      ])
    

    you should do instead:

    import { h, text } from "superfine"
    
    const fruitView = (list) => list.map((item) => h("li", {}, text(item)))
    
    const favoriteFruitView = () =>
      h("section", {}, [
        h("h1", {}, "My Favorite Fruit"),
        ...fruitView(["apple", "grapes", "melon", "mango"]),
      ])
    

    or just:

    import { h, text } from "superfine"
    
    const fruitView = (list) => list.map((item) => h("li", {}, text(item)))
    
    const favoriteFruitView = () =>
      h("section", {}, [
        h("h1", {}, "My Favorite Fruit"),
        h("ul", {}, fruitView(["apple", "grapes", "melon", "mango"])),
      ])
    

    JSX

    These changes are not backward compatible with previous JSX support and Superfine is no longer compatible with JSX "out of the box". But you can still use JSX by wrapping h to handle variable arguments and nested arrays. Here's a way to do that:

    import { h, text, patch } from "superfine"
    
    const jsxify = (h) => (type, props, ...children) =>
      typeof type === "function"
        ? type(props, children)
        : h(
            type,
            props || {},
            []
              .concat(...children)
              .map((any) =>
                typeof any === "string" || typeof any === "number" ? text(any) : any
              )
          )
    
    const jsx = jsxify(h) /** @jsx jsx */
    
    Source code(tar.gz)
    Source code(zip)
  • 7.0.0(Jul 26, 2019)

    • Simplify patch usage (read the quickstart for details).
      • New signature: patch(dom, vdom) (no need to keep track of the old DOM anymore).
      • Revert to replacing/recycling the DOM node with the rendered VDOM.
      • Remove recycle function as the behavior is now built-in.
    • Remove lifecycle events (see https://github.com/jorgebucaran/superfine/issues/167 and https://github.com/jorgebucaran/hyperapp/issues/717 for alternatives and discussion).
    • Remove xlink:* support as SVG 2 now works in Safari (mostly).
    • Remove built-in style attribute-as-object support; use a string instead. If what you have is an object, build the style string yourself:
      const styleToString = style =>
        Object.keys(style).reduce(
          (str, key) =>
            `${str}${key.replace(/[A-Z]/g, "-$&").toLowerCase()}:${style[key]};`,
          ""
        )
      
    Source code(tar.gz)
    Source code(zip)
  • 6.0.0(Jul 7, 2018)

    • Use faster reconciliation algorithm.
      • Rename render to patch.
      • Fix delayed element removals in onremove ocassionally failing.
      • Improve handling DOM attributes: draggable, spellcheck, and translate.
    • Add new recycle export function, enabling you to patch over server-side rendered markup instead of rendering your view from scratch.
    • Improve SVG and add xlink:* support.
    • Bring back built-in pure JSX component support.
    Source code(tar.gz)
    Source code(zip)
  • 5.0.0(Jun 26, 2018)

    • Rename the project to Superfine.
    • Rename the exported window global to window.superfine.
    • Bring back the old render signature render(lastNode, nextNode, container).
      • We used to store the reference to the last node in the container's first element child. Now is up to you to do it. As a result 5.0.0 is thinner and less magical.
    Source code(tar.gz)
    Source code(zip)
  • 3.0.0(Apr 19, 2018)

    • Fix asynchronously removal of elements (#107).
    • Replace patch with new render function and a simpler signature. Support for patching a specific element directly and SSR recycling has been removed. 100% client-side apps. The render function is essentially an overly simplified ReactDOM.render, without component lifecycle.
      • Remove built-in JSX functional component support.
    • Fix unexpected reordering after keyed removal (#68).
    • Don't double up event listeners when reusing elements.
    • Bring back h.
    Source code(tar.gz)
    Source code(zip)
  • 2.0.0(Mar 2, 2018)

    • Rename h to createNode.
    • Store the DOM element the first time you use patch, so you don't have to.
    • Add server-side rendered (SSR) DOM recycling. The first time you patch a DOM element, we'll attempt to reuse the element and its children (instead of creating everything from scratch) enabling SEO optimization and improving your application time-to-interactive.
    Source code(tar.gz)
    Source code(zip)
  • 1.0.0(Oct 12, 2017)

Owner
Jorge Bucaran
🌞
Jorge Bucaran
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
DOM ViewModel - A thin, fast, dependency-free vdom view layer

domvm (DOM ViewModel) A thin, fast, dependency-free vdom view layer (MIT Licensed) Introduction domvm is a flexible, pure-js view layer for building h

null 604 Dec 8, 2022
Javascript (TypeScript) library for building web user interfaces

ivi · ivi is a javascript (TypeScript) library for building web user interfaces. Status Maintenance mode. Bug fixes and documentation updates only. Qu

Boris Kaul 538 Dec 19, 2022
Dyo is a JavaScript library for building user interfaces.

Dyo A JavaScript library for building user interfaces. Installation Use a Direct Download: <script src=dyo.js></script> Use a CDN: <script src=unpkg.c

Dyo 949 Dec 23, 2022
A plugin for Strapi CMS that adds a preview button and live view button to the content manager edit view.

Strapi Preview Button A plugin for Strapi CMS that adds a preview button and live view button to the content manager edit view. Get Started Features I

Matt Milburn 53 Dec 30, 2022
StarkNet support extension for VSCode. Visualize StarkNet contracts: view storage variables, external and view functions, and events.

StarkNet Explorer extension This VSCode extension quickly shows relevant aspects of StarkNet contracts: Storage variables of the current contract, and

Crytic 6 Nov 4, 2022
A minimal presentation package for Svelte, including a "Presenter" and "Presentation View"

svelte - presenter A minimal presentation package for Svelte, includes synchronized "Presenter" and "Presentation" views. Adding Slides All slides are

Stephane 17 Sep 16, 2022
The Web 3.0 social layer built on top of Twitter

Niftycase – The Web 3.0 Chrome extension for Twitter Niftycase is a open-source Chrome extension that allows you to view anybody's NFTs directly on Tw

Matt Welter 16 Jul 14, 2022
Gatsby-starter-minimal-blog - Typography driven, feature-rich blogging theme with minimal aesthetics.

Gatsby-starter-minimal-blog - Typography driven, feature-rich blogging theme with minimal aesthetics. Includes tags/categories support and extensive features for code blocks such as live preview, line numbers, and line highlighting.

Priya Chakraborty 0 Jan 29, 2022
A monorepo for comma.ai web interfaces and packages

comma webapps This mono-repository contains the web applications and packages for the web UIs of comma.ai Contributing Just pick something and work on

null 5 Sep 27, 2022
Solid.js library adding a services layer for global shared state.

Solid Services Services are "global" objects useful for features that require shared state or persistent connections. Example uses of services might i

Maciej Kwaśniak 55 Dec 30, 2022
A platform designed specifically as an additional layer on top of Google Classroom for students to gain the best out of online evaluations

Peer-Learning-Platform A platform designed specifically as an additional layer on top of Google Classroom for students to gain the best out of online

Rahul Dhakar 3 Jun 12, 2022
BI, API and Automation layer for your Engineering Operations data

Faros Community Edition Faros Community Edition (CE) is an open-source engineering operations platform that connects the dots between all your operati

Faros AI 272 Dec 23, 2022
🪐 The IPFS gateway for NFT.Storage is not "another gateway", but a caching layer for NFTs that sits on top of existing IPFS public gateways.

nftstorage.link The IPFS gateway for nft.storage is not "another gateway", but a caching layer for NFT’s that sits on top of existing IPFS public gate

NFT.Storage 37 Dec 19, 2022
🍰 An extensible, layer based shader material for ThreeJS

lamina ?? An extensible, layer based shader material for ThreeJS These demos are real, you can click them! They contain the full code, too. ?? More ex

Poimandres 811 Jan 6, 2023
An abstraction layer on top of @replit/crosis that makes Repl connection management and operations so easy, a Furret could do it! 🎉

Crosis4Furrets An abstraction layer on top of @replit/crosis that makes Repl connection management and operations so easy, a Furret could do it! ?? In

Ray 18 Dec 29, 2022
Next-level mongoose caching layer with event based cache clearing

SpeedGoose ## About The Project This project is a next-level mongoose caching library which is fully written in typescript. It's caching on two levels

Arkadiusz Gil 17 Dec 15, 2022