Sitelet https://github.com/OrbeJmnz/glyphFlow
Skip to content

Repository files navigation

glyphflow

npm MIT
Leer en español

glyphflow

Lucide icons that actually move, for Angular — per-shape choreography on the native Web Animations API. No @angular/animations, no third-party animation library, nothing to configure. Plus morphing between icons, in its own entry point.

Free, MIT, no backend. See NOTICE for third-party attribution.

npm i glyphflow

Import one icon, pay for one icon

Measured in CI on every push, not promised — npm run bundle-check:

What you import gzip
The component alone, no icons 5.50 KB
One icon ([iconDef]="bellIcon") 5.87 KB
The whole catalog (name="bell") 174.74 KB

An icon costs about 0.36 KB on top of the runtime. Looking one up by name forces the bundler to keep all 1767, because it cannot know which one you will ask for — so that route is opt-in via provideIconCatalog(ANIMATED_ICONS), never a hidden fallback.

import { GfIconComponent, bellIcon } from 'glyphflow';
<gf-icon [iconDef]="bellIcon" trigger="hover" /> <gf-icon [iconDef]="searchIcon" label="Search" />

Triggers

trigger Fires
group (default) Draws on mount, animates on the nearest .group hover — the same ancestor Tailwind's group-hover: reads. Falls back to its own hover with no .group around.
hover Pointer enters.
tap Click.
view Enters the viewport. viewOnce (default true) decides once vs. every re-entry.
auto On mount.
manual Never on its own.

manual pairs with three public methods — grab the instance with ViewChild/viewChild():

@ViewChild(GfIconComponent) icon!: GfIconComponent;

this.icon.play('pulse'); // plays a VARIANT — not a trigger; no argument replays `animation`
this.icon.reverse(); // reverses the animation currently running
this.icon.cancel(); // stops it and resets to the base pose

On touch screens

A touch screen has no pointer passing over things, so hover-driven icons (group, hover) only draw on mount there. That is on purpose: a tap fires a synthetic pointerenter, and animating on it would swallow the feel of the tap. The touch input is the opt-in:

touch On a touch screen
none (default) Nothing new — the behavior above.
press Pressing with a finger plays the hover variant; lifting it reverses it when the variant has reverseOnLeave. For buttons and controls.
view Only on screens without hover ((hover: none)): plays the hover variant when the icon enters the viewport. For grids and lists.
<button type="button"><gf-icon [iconDef]="bellIcon" touch="press" /> Notify me</button>

It only adds listeners: mouse hover keeps working exactly as before, and tap, view, auto and manual ignore it. Set it once for the whole app with provideGfIcons({ touch: 'press' }); an icon's own touch input wins over the global one.

Inside a web component whose real <button> lives in its shadow root — <ion-button>, <ion-tab-button>, a clickable <ion-item>, or any other — the icon hooks onto the component itself, so hover and press count over the whole button, not just over the icon.

The catalog

Total icons 1767 — the complete canonical Lucide 1.31 set
Hand-choreographed 1767 — every one, motion with intent
More than one gesture 1095 — a second variant beyond default

Every icon in the catalog is now hand-choreographed: generated-icons.ts is empty, and stays as the landing zone for whatever a future Lucide release adds. The two files exist on purpose (curated-icons.ts and generated-icons.ts): the generator never touches the curated ones. Choreography with intent is human judgement, icon by icon. See CONTRIBUTING.md.

Accessibility: one rule, not a matrix

You never coordinate aria-hidden with aria-label. You either pass a label or you don't:

<!-- Decorative: the button already says "Save" -->
<button><gf-icon [iconDef]="saveIcon" /> Save</button>

<!-- Semantic: no text, so the icon carries the meaning -->
<button><gf-icon [iconDef]="saveIcon" label="Save" /></button>

Both components honour prefers-reduced-motion by default — but honouring it means something different in each, and that is deliberate. In <gf-icon> the choreography is decoration on an icon that is already correct, so it holds still. In <gf-icon-morph> holding still would leave you staring at the wrong icon, so it jumps straight to the destination. Reduced motion removes the motion, not the state change.

Morphing

Lives in a separate entry point, glyphflow/morph, so anyone who only wants animated icons doesn't pay for shape-interpolation math.

import { GfIconMorphComponent } from 'glyphflow/morph';
// The binding IS the state: changing [icon] transitions from the previous value.

The first value renders statically — morphing "from nothing" doesn't exist. SSR and browsers without WAAPI land there too: you see the icon, it just doesn't animate.

import { Component } from '@angular/core';
import { GfIconMorphComponent } from 'glyphflow/morph';
import { moonIcon, sunIcon } from 'glyphflow';

@Component({
  imports: [GfIconMorphComponent],
  template: `
    <button (click)="dark = !dark">
      <gf-icon-morph [icon]="dark ? moonIcon : sunIcon" />
    </button>
  `,
})
export class ThemeToggle {
  dark = false;
}

Speed control

One multiplier for every calculated duration — choreography and morph transitions alike:

import { provideGfIcons } from 'glyphflow';

providers: [provideGfIcons({ durationScale: 0.8 })]; // 20% faster, everywhere

1 is the default — no change. It applies from the next playback: anything already animating keeps the duration WAAPI already received when it started.

Compatibility

Angular 20, 21 and 22 — each version is tested in CI by scaffolding a fresh app with that version's CLI, installing the real .tgz, and building it with SSR prerendering. The peerDependencies range reflects only what that matrix confirmed.

Workspace

  • projects/glyphflow — the library (ng-packagr, gf prefix → <gf-icon>).
  • projects/playground — the live site: icon catalog, patterns, geometry editor and authoring lab. It consumes the published package from npm, never the source in this repo, so that anything the public API fails to cover shows up immediately.
npm install
ng build glyphflow
ng test glyphflow
ng serve playground

npm run verify:clean      # wipes node_modules/dist and runs the whole pipeline from scratch
npm run generate:icons    # regenerates generated-icons.ts from lucide-static
npm run lucide:diff       # diffs the catalog against the installed Lucide version

License

MIT — see LICENSE.

About

Animated Lucide icons for Angular. Native Web Animations API, zero runtime dependencies, tree-shakeable, MIT.

Topics

Resources

Contributing

Security policy

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages