Viscose ships a commercial typeface inside an MIT repository
A wheel of work that never quite sets. Cards fuse as they meet, and draw into threads as they part.
At a glance
- What is it?
- A portfolio carousel drawn as one full-screen WebGL fragment shader of signed distance fields, where a commercial font is committed to an MIT-licensed repository for development only, the sample images are other people's work, the clone command points at a different repository name, and every measurement in the project is quoted against one 14-inch MacBook Pro.
- Who is it for?
- Viscose is worth reading as shader craft rather than adopting as a template, because the whole ring is one fragment shader computing signed distance fields, and the melting between neighbouring cards and the thinning threads between them fall out of the same field rather than being drawn on top of it. That is the technique worth taking.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 53 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 7, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A commercial typeface sits inside an MIT repository
The font table lists three families with their licences, and one of them does not belong to the project. Satoshi is free from Fontshare, Geist is under the SIL Open Font License, and PP Neue Montreal is marked as a commercial Pangram Pangram typeface. An admonition below the table says it plainly: PP Neue Montreal is not licensed by this project, the file is included for local development and evaluation only, it is not covered by the repository's MIT licence, and it must not be used for commercial purposes. If you ship anything with it, buy your own licence, or swap the `textFont` value in `params.js` for Satoshi, which is free for commercial work and already included. The disclosure is thorough and the remedy is one line, so the risk is entirely in whether a reader reads the font section before deploying. A repository whose licence file says MIT and whose assets include a font that says otherwise is the kind of mismatch that survives to production.
The clone command names a repository that is not this one
The quick start says Node 20 or newer, then:
git clone https://github.com/Yousuf-developer/viscose.git
cd viscose
npm install
npm run devYou are then told to open `http://localhost:3000`. The repository this document describes is `Yousuf-developer/Viscose-carousel`, and the URL in the clone command is `Yousuf-developer/viscose`. Those are two different names, and the instruction to change into a `viscose` directory follows from the first one. The manifest name is `viscose`, so the discrepancy is between the GitHub repository and the package name rather than a typo in the package. It is the first command a new user runs, and it either 404s or clones something other than the code being described. Everything after it is accurate: the four scripts are `next dev`, `next build`, `next start` and `eslint`, the dependencies are GSAP, lil-gui, Next 16.3.0, React 19.2.8 and Three.js, and the stylesheet layer is Tailwind v4 with its PostCSS plugin.
Every measurement in the project is quoted against one 14-inch MacBook Pro
Before it explains any tunable, the document tells you to do something and it is the most practically useful instruction on the page. Open the `fit` folder in the dev panel and check that `scale` reads 1.000. Every pixel measurement in the project is quoted against a reference window, which is a 14 inch MacBook Pro 1512 points wide, and on a different screen you would be tuning against a scale factor that is not 1, with a result that looks right for you and wrong for everyone else. There is a `use this window as ref` button that recalibrates in one click. The `fit` folder holds the reference window, the scale clamps and the two responsive breakpoints, which is a sensible division, since those three settings are what make the rest of the numbers portable. The panel itself is development only, gated behind a dynamic import and a check on `NODE_ENV`, and lil-gui is a runtime dependency rather than a development one, so the library ships in the production bundle unless the tree-shaking path is taken.
Around 136 tunables in one panel, and the threading is not drawn
In development a lil-gui panel appears in the top right with roughly 136 tunables, grouped by what they affect: `fit` for the reference window and breakpoints, `shape` for card size, count, ring radius, corner and art crossfade, `timing` and `stage` for the entry animation, `meta` for the type either side of the ring, `pointer` and `side cards` for cursor reaction, `honey` for the threads between cards, and `glass` for the refracting lip along the top and bottom edges. The mechanism is the part worth understanding. The whole ring is one full-screen fragment shader drawing signed distance fields, and that is what lets neighbouring cards melt into one another as they close up. The threads are not drawn between the cards, they are part of the same field, so they thin, sag and dissolve on their own as the gap opens. The glass lip is the same shader pass refracting the two neighbours into swept shapes. Cursor movement draws nothing either, it softens the surface beneath it and leans nearby cards toward it.
One array does four jobs, and reordering it is the intended way to sequence
The content model is a single array in `components/ring/projects.js`, and each row is small:
{ file: "10.webp", name: "Matchday", type: "Motion", year: "2025" }Drop an image into `public/` and add a row. The array does four jobs at once, serving as the atlas packing order, the order art is dealt around the ring, the project column in the top right, and the numbering that runs from 01 to 18. Reordering rows moves all four together, which is an elegant piece of economy. There is a warning attached, though, and it is the kind of warning that saves an afternoon. The list is in ring order rather than filename order, so it reads shuffled against the file numbers, and that is deliberate: entry n sits one slot along the ring from entry n minus one, which is what makes the visible column count up as the carousel turns. The instruction is to reorder the rows to change the sequence and not to reach for `imageOffset`, which rotates the art without moving the list with it.
The sample content is invented and the images belong to other people
The data section is where the project is most candid about itself. Every `type` and `year` in the sample set is invented, names marked with an asterisk are guesses at the subject, and the images are other people's work, collected to build the layout against rather than authored for it. That is an honest framing for a demo, and it is also the reason the repository cannot be a portfolio template in the direct sense: a fork that keeps the sample content is displaying someone else's images under invented credits. The project points at a separate section about the artwork, so the details are documented rather than glossed. The name of the thing is a pun worth noting too, since the document spells it out: a viscous state, and a fibre spun by drawing that state into a thread, which is what the cards do when they pull apart.
Fonts are served as OTF and TTF, and the page says to convert them
One line at the end of the font section is an unshipped optimisation stated plainly: the fonts are served as `.otf` and `.ttf` totalling around 340 KB, and converting them to `woff2` would cut that by roughly 60 percent, which the document says is worth doing before this goes anywhere real. The three families are declared in `app/globals.css` and looked up by name from `components/ring/params.js`, so swapping one means changing it in both places, which is a small coupling to be aware of before you replace a typeface. A repository that names its own missing optimisation in the readme is easier to trust than one that does not, and this is a case where the note and the artefact disagree in a way the reader is expected to resolve. The other structural detail in the tree is a `shader` entry at the top level, alongside `app/`, `components/`, `docs/` and `public/`.
Editorial conclusion
Viscose is worth reading as shader craft rather than adopting as a template, because the whole ring is one fragment shader computing signed distance fields, and the melting between neighbouring cards and the thinning threads between them fall out of the same field rather than being drawn on top of it. That is the technique worth taking. What you take it into, check first. A commercial typeface from Pangram Pangram is committed to the repository and is explicitly outside the project's MIT licence, so a fork that ships it has a licensing problem the licence file does not describe. The sample images are other people's work collected to build a layout against. The clone instructions name a repository that is not this one. And every pixel measurement in the project is calibrated to a 1512 point reference window, so the numbers in the source mean nothing until you recalibrate against your own display. The last commit on the default branch main is dated 15 August 2026 and there are no releases.
Frequently asked questions
How is the Viscose carousel rendered?
As a single full-screen fragment shader drawing signed distance fields, not as images in a grid. Neighbouring cards melt into one another as they close up because they share one field, the threads between them thin and dissolve as the gap opens for the same reason, and the glass lip refracting the two neighbours is the same shader pass.
Can I use the fonts in Viscose commercially?
Satoshi and Geist can, being free from Fontshare and under the OFL respectively. PP Neue Montreal cannot: it is a commercial Pangram Pangram typeface included for local development and evaluation only, is not covered by the repository's MIT licence, and must be replaced with your own licence or swapped for Satoshi in params.js.
How do I add a project to the Viscose carousel?
Add an image to public/ and add a row to the array in components/ring/projects.js with a file, name, type and year. The array drives the atlas packing order, the ring order, the project column and the 01 to 18 numbering together, and the rows are in ring order rather than filename order by design.
What does the Viscose dev panel let me change?
Around 136 tunables grouped by effect, covering the reference window and breakpoints, card shape and ring radius, the entry animation, ring type, cursor reaction, the threads between cards and the refracting glass lip. The panel and lil-gui are behind a dynamic import guarded by NODE_ENV so they never ship.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/yousuf-developer-viscose-carousel)