The logic behind it
  • Minimalism - no dependencies, efficient code
  • Modularity - users are in control, billions of possible patterns
  • Accessible - not fully yet
  • Sounds & 3D Layers - cinematic & immersive experience
  • Touchscreen & Convergence - works on (almost) all devices, hovering or using a cursor are not requirements for interracting with the ui, usually not fully taken into consideration by devs & frameworks. Here it is!
  • Transparency - semitransparent multilayers, support for os integration with transparent windows
  • Searchable & open on demand - to reduce physical space and help you focus
  • Private - all data stays on your device
  • Supports both the https:// and file:/// protocols - most frameworks don't do that, we do, so you can use the apps statically & offline too, without any server, compiling, nodejs etc. required.
How do I use it on my own projects?

In any way you want, as long as you keep it open source and follow the AGPL 3.0 License here. Propper documentation is coming soon

I see glitches or errors. How do I reset it?

EFY or

Or clear your browser's cache, try a different browser, device etc.

Run your own Piped EFY Instance

Thanks Ruby for the instructions 馃憦

git clone --branch efy --recurse-submodules
cd Piped
echo '!.eslintrc.cjs' >> .dockerignore
docker build . --tag piped-efy

Go to your piped docker-compose and change the image from 1337kavin/piped-frontend to piped-efy. I recommend building with buildx because its faster:

docker buildx build . --tag piped-efy

Public Instances:

How do I repport bugs or share my ideas?

On Github or Matrix. Try to specify how you encountered the bugs, on what device, browser etc. And for ideas, why they should be implemented and what use cases they have.

Is it stable / production-ready?

EFY is currently in Beta, so expect potential bugs. Features and apps that are unstable are usually marked this way:


- unavailable now, but expected to come up
- unsafe to use, lots of bugs
- safer to use, less bugs
What efy stands for

Nothing. It's just a name, like Andy or Izzy.

Add a background image


More coming soon...

This is just the beginning...

Learn how to use efy

  • It sets the mode, the default value is default
  • Options: light_light , light_sepia , light_trans , dark_dark , dark_nord , dark_black , dark_trans


  • 1st part: can be light or dark to indicate the general mode
  • 2nd part: indicates the specific type of light / dark mode: light sepia trans dark nord black
  • trans = Transparent - it makes the background invisible so that you can see behind the window (if your web engine, browser or operating system supports it) or the image you choose from the sidebar menu


Specific mode:

[efy_mode=light_sepia] { your css }

All light modes:

[efy_mode*=light] { your css }

Not this specific mode:

:not([efy_mode=light_sepia]) { your css }

Remove selector if any light mode is on:

$('[efy_mode*=light] #your_selector').remove()
- create html

$add('Tag', {Attributes}, ['Text', Children], Parent, 'Position')


Only Tag is required. Other parameters are optional

Tag - html tag like: div, p, img etc

Attributes - one or multiple html attributes like: class, type, height etc

Text - text content

Children - nested html tags

Parent - parent of the tag where it should be added. If not specified it defaults to the body tag

Position - where the tag should be added in relationship to the parent:
beforebegin , afterbegin , beforeend , afterend


Add an empty button to body after all existent children


Add a css styled button inside the #test selector, before other children

$add('button', {style: 'background: red; padding: 20rem'}, 'Text', $('#test'), 'afterbegin')

Range input with some attributes before #test ends

$add('input', {
        type: 'range', value: '50', min: '0', max: '100', step: '1',
        class: 'test', id: 'test',
        style: 'margin: 0; padding: 15rem'
    }, [], $('#test')

2 nested buttons inside a div

$add('div', {}, [
    ['button', {}, '1'],
    ['button', {}, '2']
More coming soon...

This is just the beginning...

<i efy_icon="star"></i>

efy_color = color, range:min-max
  • it uses the OKLCH format, which renders vibrant, human intuitive colors
  • color = name, lightness (0 - 1), chroma (0 - 0.37), hue (0 - 360), alpha (0 - 1), id (optional)
  • range (optional): min (0 - 100) - max (1 - 100)
<div efy_color="Demo 0.7 0.2 100 1"></div>
<div efy_color="1 0.5 0.2 0 1, 2 0.7 0.2 100 1, 3 0.5 0.2 200 1, range:1-9"></div>
$add('div', {efy_color: 'Demo 0.7 0.2 100 1'})
$add('div', {efy_color: '1 0.5 0.2 0 1, 2 0.7 0.2 100 1, 3 0.5 0.2 200 1, range:1-9'})

$notify('time', 'text', 'text', 'lang', function)

lang & function are optional time = short, long, infinite or seconds (example: 3) lang - use efy translation variables instead of normal text
$notify('short', 'Short', 'Disappears in 5s')
$notify('long', 'Long', 'Disappears in 30s')
$notify('infinite', 'Infinite', 'Never disappears')
// Attach it to a click event $event(selector, 'click', ()=> $notify('short', 'Test', 'Test'))

efy_clock = empty, 12 (hour format, default is 24), hms (hour : minute : second) or 12hms (12 + hms)
<div efy_clock></div>
<div efy_clock="12"></div>
<div efy_clock="hms"></div>
<div efy_clock="12hms"></div>
$add('div', {efy_clock: ''})
$add('div', {efy_clock: '12'})
$add('div', {efy_clock: 'hms'})
$add('div', {efy_clock: '12hms'})

efy_timer = id, seconds (until it stops), reverse (count backwards)
id, seconds, reverse are optional
<div efy_timer></div>
<div efy_timer="efy_demo, 5, reverse"></div>
$add('div', {efy_timer: ''})
$add('div', {efy_timer: 'efy_demo, 5, reverse'})

Select Menu



  • Add efy_select to a details tag, the Name inside a summary and your radio / checkbox inputs inside a div
  • It works this way cuz it's semantic html, so you can add other html too, like div, img, etc.
<details efy_select>
<input type="radio" name="demo_radio" id="demo_radio1"> <label for="demo_radio1">Radio 1</label> <input type="radio" name="demo_radio" id="demo_radio2"> <label for="demo_radio2">Radio 2</label>
<input type="checkbox" name="demo_checkbox" id="demo_checkbox1"> <label for="demo_checkbox1">Checkbox 1</label> <input type="checkbox" name="demo_checkbox" id="demo_checkbox2"> <label for="demo_checkbox2">Checkbox 2</label>

  • Add efy_tabs to a div. Inside, an efy_tabs class with nested efy_tab buttons and efy_content divs (where you can add your html)
  • Add efy_active to the efy_tab and efy_content you want open by default
  • The matching efy_tab and efy_content should have the same name and efy_tabs should have an unique name, unless you want to control a duplicate set of tabs
  • You can nest tabs if you add them inside an efy_content div
<div efy_tabs="demo">
    <div class="efy_tabs">
        <button efy_tab="tab1" efy_active>Tab 1</button>
        <button efy_tab="tab2">Tab 2</button>
    <div efy_content="tab1" efy_active>Your HTML 1</div>
    <div efy_content="tab2">Your HTML 2</div>
$add('div', {efy_tabs: 'demo'}, [
    ['div', {class: 'efy_tabs'}, [
        ['button', {efy_tab: 'tab1', efy_active: ''}, 'Tab 1'],
        ['button', {efy_tab: 'tab2'}, 'Tab 2']
    ['div', {efy_content: 'tab1', efy_active: ''}, 'Your HTML 1'],
    ['div', {efy_content: 'tab2'}, 'Your HTML 2']