Activity

NellowTCS

I PUBLISHED ITTTTTT!!!

This was the final cleanup sprint before shipping lexepub v0.1.0, and it ended up being a surprisingly big set of changes across docs, CI, workflows, and the README. Nothing glamorous, but all the stuff that makes a project feel real instead of “a folder on my computer.”

Docs Cleanup + Expansion

I went through the entire docs site and updated everything:

  • Rust adapter docs now include resource APIs, TOC APIs, and link normalization notes.
  • WASM adapter docs now list the full API surface, including get_resource() and the chapter‑relative resource helpers.
  • C/C++ adapter docs got updated with the new functions and a clearer API reference.
  • Quickstart now includes useful commands, WASM build instructions, and resource‑loading examples.
  • The homepage got a new “Resource + TOC Utilities” card and a clearer adapter parity section.

Basically: the docs now actually reflect what lexepub can do.

README Overhaul

The README got the cleanup it always deserved (and needed)

  • Proper formatting
  • Clearer feature list
  • NPM + crates.io links
  • Better installation instructions
  • Cleaner demo section
  • Updated build instructions

GitHub Pages Workflow Refactor

I rewrote (ahem, copied from Tamaru) the entire Pages deployment workflow:

  • fixed Node version
  • fixed root/base paths
  • fixed demo paths
  • fixed docs paths
  • fixed the deploy directory structure
  • fixed the index redirect

Release CI

I added proper release workflows:

  • cargo publish (with dry‑run option)
  • wasm-pack build
  • C header generation
  • release tarball creation
  • GitHub Release upload

It even handles platform‑specific artifacts cleanly and doesn’t hardcode paths anymore (I fixed that… again).

Resource API + WASM Updates

I added:

  • get_resource(path)
  • better resource resolution
  • normalized internal paths
  • improved TOC extraction
  • updated TypeScript definitions

The WASM adapter is now fully capable of powering the demo without hacks.

I Published It!!!!!!!!!!!!!!

Yep!
lexepub is now on crates.io and npm!

Attachment
Attachment
Attachment
0
NellowTCS

lexepub now has a Proper browser demo that actually renders EPUBs, images, CSS, TOC, everything!!!!
using the WASM build. I didn’t plan on building a renderer for v0.1.0, but here we are.

HTMLReader‑borrowed Demo

I put together a small demo that was yanked from HTMLReader (hey, again why remake the wheel if I already have a good UI/modular thing) that loads EPUBs through the WASM adapter and renders them directly in the browser. It works well!!!
(and shows off what lexepub can do without needing any external libraries)

It now supports:

  • chapter images
  • proper table of contents (using inferred chapter titles instead of raw filenames)
  • CSS from <link> tags
  • internal resource loading
  • normalized paths
  • and a clean UI for navigating chapters

Honestly, it’s starting to feel like a real reader, which feels insane…
I showed it to a friend and they actually thought it was like ePubJS or something haha, not my own thing!!!

Chapter Images + Resource Loading

I added get_chapter_resource and resolve_chapter_resource_path to the WASM API so the demo can fetch images and other linked assets.
This required adding:

  • path normalization
  • chapter-relative resolution
  • fallback logic for weird EPUB structures (why is this such a badly standardized format omg… I have ANOTHER project idea now, a new ebook format sob)

Images now display correctly inside chapters.

Proper TOC Support

Chapters now have a title field inferred from:

  1. <h1>, <h2>, or <title> in the AST
  2. otherwise the first non-empty text
  3. otherwise the filename stem

The WASM adapter exposes get_toc() and get_toc_json(), and the demo uses this to build a real table of contents.

CSS from <link> Tags

Linked CSS files now load and apply correctly.
This required:

  • resolving relative paths
  • reading CSS resources
  • parsing them
  • applying them to the AST before rendering

It’s still a simple CSS engine, but it’s enough for EPUBs.

Internal Path Normalization

EPUBs love weird paths (../, ./, backslashes, nested folders), so I added a normalize_internal_path() helper and integrated it into:

  • resource resolution
  • AST link normalization
  • href/src rewriting

This fixed a bunch of rendering/random other issues

TODO Updates

Added then checked off:

  • chapter images
  • proper TOC
  • CSS from <link>
  • demo added
  • internal path fixes

All that’s left really is cleanup and publishing and docs and so on, nothing major honestly, the TODO all has stuff that is beyond v0.1.0

Attachment
Attachment
Attachment
Attachment
1

Comments

Cyclic(John fire department) not FD

This is cool

NellowTCS

I added a basic demo!
The demo is based off HTMLReader, which i modified and stripped out epubjs from and replaced with the WASM compilation of LexePub. It works cleanly but there’s no formatting sob since like LexePub doesn’t have a proper renderer yet haha.

Attachment
Attachment
Attachment
0
NellowTCS

Today (well yesterday, I was tired, okay?) ended up being a pretty productive set of commits, nothing too dramatic, but a lot of important groundwork and cleanup that makes lexepub feel more complete and consistent across all adapters.

API Parity Across Rust, WASM, and C/C++

I finally checked off the “1‑1 API functionality” item, then unchecked it when I added CSS, then rechecked it in the same commit loll
This mostly meant adding the missing sync wrappers (get_metadata_sync, has_cover_sync, cover_image_sync) and wiring them into the C‑FFI layer.
(very annoying thing dealing with Diplomat’s restrictions, the thing I made, Saikuro is so much betterrrr and much cleaner and more languages are automatically supported.

Minimal CSS Parser that turned into a pretty average simple one

I added a small CSS parser, handrolled because cssparser from Servo, is difficult to deal with (future project, better api for it, 👀), just enough to handle basic selectors, declarations, and at‑rules.
It’s simple, sadly, but it works well for EPUB‑level CSS.
There’s a tiny AST (Stylesheet, CssRule, StyleRule), comment removal, declaration parsing, and some tests to make sure it doesn’t defy my expectations for CSS (copied from an ebook btw).

Documentation Pass

I added docs!

  • Rust adapter page includes full API references, sync wrappers, and CSS/AST behavior.
  • C/C++ adapter page lists the full generated API and includes a full example.
  • WASM adapter page has a proper API reference and example usage.
  • Quickstart has with optional features, sync wrappers, and convenience functions.

README Cleanup

The README got a big trim.
Most of the detailed examples and API references moved into the docs site, which is where they belong.
The README is now much cleaner and points people to the proper documentation. (Though I don’t know what late night me was thinking with the links being code lines like what?!?

TODO Updates

Checked off:

  • API parity
  • CSS parsing + application
  • Streaming cover image support

The majority of the TODO’s left are stuff that are probably for the future haha, but I do need to make a small HTMLReader-but-using-LexePub-demo

Attachment
Attachment
Attachment
0
NellowTCS

Just a tiny devlog this time, I’m learning :O

But I did add my default Docs with a capital D setup and the accompanying CI, and added streaming cover image support.

What I Did

I added docs.
And yes, I did borrow the folder structure from other projects.
I’m not reinventing the wheel when I already invented it twice (Tamaru, Saikuro, S-eco, need I name more?).
Please respect my efficiency.

And THEN, ONE MORE TODO: I implemented streaming cover image support.
As in:
cover_image_to_writer
Zero allocations.
Direct streaming.
AsyncWrite.
The whole thing.

It works, streams, and is like actually really nice!!!

TODO Updates

The TODO list shrank again, -2 more things…
I’m starting to worry I’m going to run out of TODOs and have to invent new ones.

Attachment
Attachment
Attachment
0
NellowTCS

Chaos Devlog time!!!

I added EPUB version detection.
Like, real version detection.
lexepub now looks at <package version="3.0"> and goes “oh okay cool” instead of staring blankly like a goldfish.

Then I added cover image format detection!
The manifest used to be a cute little HashMap<String, String> and now it’s a full (href, media-type) tuple because I decided lexepub should know MIME types like a sommelier knows wine.
This broke EVERYTHING.
Every. Thing.
Every .join(href) became .join(&href.0) aaaagh.

And then I fixed WASM.
Not “fixed WASM” like “haha a typo,”
I mean FIXED WASM like “rewrote half the bindings because Past Me was clearly having a moment’ (second time i’ve said that today haha).
Everything returns proper Result<T, JsValue> now.
Metadata serializes.
Chapters serialize.
Cover extraction works.

Oh and AST parsing?
Yeah that’s real now.
extract_ast() actually does AST things instead of returning ast: None like a liar.
WASM uses it too.
ParsedChapter is serializable.
Chapter is serializable (but I skipped the raw bytes because I’m not a monster).
This was supposed to be a “later” thing.
It is no longer a “later” thing.

Now we got:

EPUB Version: 3.0
Has Cover: true
Cover Format: image/jpeg

And the TODO list?
Oh my god the TODO list.
I chugged through TODOs fast as fluff.
WASM support? Done.
AST parsing? Done.
Version detection? Done.
Cover format detection? Done.
I swear the TODO list is shrinking faster than my sanity.

I also updated integration tests because apparently I’m responsible now.
They actually check MIME types and cover presence and error cases and everything.
Who am I.

Anyway.
I love how lexepub is turning out.
It started as a tiny little “haha unzip EPUB” thing and now it’s a full parsing engine with metadata, ASTs, WASM bindings, cover extraction, version detection, and a manifest that actually knows what it’s doing.

Attachment
Attachment
0
NellowTCS

SHOOOOOOOOOOOOT
I’m so good at forgetting projects existed sighhh.

So this is a lot less hours logged than I originally spent (a majority was googling HOW ePubs work (and why they’re so… hard to parse)) but I guess 2 and a half hours is fine whatever…

Okay so you all get the everything I did up to now devlog. Warning, this will be insanely rambly:

So. EPUBs.
Right.

You’d think “oh it’s just a zip file with some HTML in it” and you would be CORRECT but also WRONG because the way they organize everything is kind of a nightmare and I spent way too long just figuring out the file structure before I wrote a single line of Rust.

Okay so the gist: an EPUB is a zip file, inside that zip file is a META-INF/container.xml which points you to an OPF file (like OEBPS/content.opf or wherever), and THAT file has all the metadata AND a manifest (list of all files) AND a spine (the reading order). So you can’t just iterate the zip entries in order, you have to parse the OPF spine to figure out what order chapters actually go in.
Which is fun.
Very fun.
Super fun.

So I built the whole thing in layers basically. There’s an EpubExtractor at the bottom that just knows how to open a zip and read files out of it, and it can do this from a file path, from raw bytes, OR from a streaming async reader. That last one was kind of annoying to get right because async_zip has opinions about what traits your reader needs to implement and I had to do some fun (/sarc) stuff to get it to work.

Then on top of that there’s the actual parsing layer, ContainerParser for container.xml, OpfParser for the OPF file (metadata + spine + manifest), and ChapterParser / extract_text_content for turning the XHTML chapters into actual readable text using the scraper crate.

The main LexEpub struct is what you actually use and it caches chapters and metadata so you’re not re-parsing the whole thing every time you call get_metadata() twice.

Oh also there’s a lowmem feature flag that swaps out the scraper-based HTML parser for a dumb little hand-rolled state machine that just strips tags manually. It’s not as good at handling block elements and whitespace but it doesn’t build a full DOM tree which is the point. Useful for embedded targets theoretically.

The streaming story is… partially done. ChapterStream implements futures::Stream so you can consume chapters one at a time without loading all of them into memory at once. The benchmarks use jemalloc to actually measure heap allocation delta per operation which I’m pretty happy about as a setup.

For some reason I thought making benchmarks would be fun so there’s Criterion benches for from_bytes, from_reader, and extract_text_only. The CI runs cargo bloat to check binary size which is something I actually care about for once because the end goal is for this to be usable in WASM and potentially on embedded stuff (esp32 ahem)

WASM bindings exist in theory (src/wasm.rs) but they’re kind of broken right now, extract_with_ast() doesn’t exist, has_cover() doesn’t exist, cover_image() doesn’t exist. Those are all in the TODO. The C FFI via Diplomat is in better shape and actually generates a real header file.

The test suite is… extensive? Like maybe embarrassingly extensive for something this early. There’s unit tests, integration tests, API tests, edge case tests, streaming tests, performance tests, and a memory threshold test that reads /proc/self/status to check RSS delta. I went a little overboard. The edge case tests especially are kind of a placeholder graveyard right now, most of them are just “open the test epub and hope nothing crashes” because actually testing edge cases properly requires mock EPUBs and I have not built those yet.

The big things left:

  • A lot (just kidding, there’s a TODO.md)

Anyway that’s the summary and stuff thanks for coming to my TED Talk hope you enjoy.

Attachment
Attachment
0
NellowTCS

Shipped this project!

I built Tamaru, a physics‑driven virtual trackball widget for the web!
It lets you scroll any page or container by flicking a little 3D orb, complete with inertia, audio, haptics, themes, and now… Stick Mode (pointer‑lock scrolling), which nearly broke me (/silly) but was so worth it.

The hardest part was definitely Stick Mode. Pointer lock, scroll‑target cycling, highlight logic, restoring state, and making it all feel like a real trackball was a whole boss fight. I figured it out by rewriting half the scroll engine, adding a target‑cycling system, and bribing the browser with sheer stubbornness (yes your browser’s now corrupt 😔).

I’m really proud of how polished it feels now, the physics, the audio, the theming, the demo, the docs, everything. It started as a tiny 6 AM experiment and somehow turned into a full npm package with real features and real users. I’m honestly so happy with how it turned out.

NellowTCS

So uh.

I DID IT.
I ACTUALLY SHIPPED TAMARU.
It’s on npm.
It’s real.
It’s alive.
It has provenance logs and everything.
I’m screaming.

(I’m using the bookmarklet, by the way, in the first two images)

Attachment
Attachment
Attachment
2

Comments

NellowTCS
NellowTCS 2 days ago

*Last two images, the upload order is backwards

NellowTCS
NellowTCS 2 days ago

HEY REVIEWERS/READERS

SO someone asked me to make this an extension. firstly WHY DIDN’T I THINK OF THAT, and secondly I’m working on that and will reship soon™

NellowTCS

so uh. stick mode.

I finally did it.
I added stick to cursor mode.
And let me tell you:

this was
SO
HARD.

like “why am I doing this to myself” hard
like “pointer lock is a demon” hard
like “scroll target cycling is a cursed ritual” hard

BUT ALSO
SO
WORTH IT.

the descent into stick‑mode madness

pointer lock hell

I had to fight the browser for custody of the mouse.
It did NOT want to give it to me.
I won.
with a smirk cause why not >:3

mini‑mode orb

stick mode now force‑minimizes the orb
centers it

absolute movement scrolling

no more dragging the orb
no more “go to the corner”
just pure raw mouse movement -> scroll velocity
like a REAL trackball
but digital!

target cycling

hold Shift
scroll wheel (or two fingers on laptop)
Tamaru goes:

“oh you want to scroll THAT div?
okay let me highlight it for you”

it even scrolls it into view configurably
because I’m extra.

state management purgatory

enter stick mode
exit stick mode
restore position
restore size
restore sanity (attempted, not guaranteed, often fails)

UI updates

added a cute little ⌖ button
it mocks me
but it works

do these exist? yes. was it pain? yes.

  • stick mode button (desktop only because mobile said “no”)
  • pointer‑lock based scrolling
  • scroll target cycling with Shift + wheel
  • highlighting the active scroll target
  • auto‑snap into mini mode when entering stick mode
  • auto‑restore when exiting
  • scrollIntoView because I’m dramatic
  • scroll engine now respects stick mode like it’s a law of nature

bugs I fixed (and bugs I created then fixed)

  • stick mode not restoring size
  • stick mode not restoring position
  • stick mode scrolling the wrong thing
  • stick mode scrolling nothing
  • stick mode scrolling EVERYTHING
  • highlight not clearing
  • highlight clearing too fast
  • highlight clearing too slow
  • scroll engine forgetting what a scrollable element is
  • me forgetting what a scrollable element is
  • me forgetting who I am

demo

updated the demo again
because of course I did
stick mode works
it’s beautiful
it’s terrifying
I love it

Attachment
Attachment
Attachment
0
NellowTCS

So uh…
I kinda want to ship this today…
Maybe a bit obsessed but here’s another devlog haha.

I decided to try not to do like 10 things in one devlog.
And then I…
did not do that.
Apparently I cannot touch this project without accidentally doing a full renovation.

Anyway.

Stuff I Did

  • fixed the GitHub Pages workflow (for real this time… I think… I hope…)
  • added a favicon because the docs looked naked without one
  • added an icon.png because why stop at one image when you can have two
  • updated the docs config so the favicon actually shows up instead of silently judging me
  • added OpenGraph images so sharing Tamaru links doesn’t look like a 404
  • added a “Try the Demo” link because yes, you should try the demo (duh)
  • updated the README to stop lying about “no external dependencies” (pain)
  • tweaked the TODO list because I keep pretending I’m done
  • moved “tweak base config” to Done because it actually is good now
  • stared at the workflow file like it personally betrayed me
  • committed something
  • realized I forgot something
  • committed again
  • realized I forgot something else
  • and realized i made the devlog look like an essay again

Bugs I Fixed

  • “I thought I changed this” (I did not)
  • “why is the favicon not showing up” (wrong path)
  • “why is the docs folder empty” (wrong folder)
  • “why is the README lying” (me)
  • “why is the demo favicon broken” (also me)
  • “why is this taking so long” (me again)

Demo

Updated the demo again and it now is curvomorphic and prettyyy :3
Now with a working favicon.
Probably.
Confirmed now, yeah it works
I love it, it’s perfect :D

Attachment
Attachment
0
NellowTCS

So uh.

I did… a lot of things.
Like, a silly amount of things for someone who allegedly “was just fixing bugs.”

This commit arc is basically:

“I’m only going to clean my room a little”
proceeds to renovate the entire house, add two new rooms, repaint the walls, and fix a installed sound system

Anyway.

Stuff I Did

  • rewrote some janky code because Past Me was clearly having a moment
  • fixed like 6 bugs that were all conspiring together
  • made mini‑mode actually behave
  • added visibility + blur handlers so the orb stops rolling when you tab away (polite orb!!)
  • fixed pointer‑events so the widget stops gatekeeping interaction (polite orb x2!!!)
  • made the rolling sound smoother, less “grate‑y”, more “roll‑y”
  • tuned the filters again because apparently I’m an audio engineer now (if that was ever a question)
  • fixed the tiny audio gap when continuously scrolling (this one was haunting me, I don’t like not seamless sound)
  • improved haptics with iOS detection + rate limiting so it doesn’t vibrate itself into another dimension
  • added scrollbar‑hiding CSS because WebKit refuses to listen to me (seriously Apple?!! why must you be so different)
  • updated the theme loader
  • updated the README
  • updated the demo
  • updated the TODO (again…)
  • oh and uhhh

I added two new themes

neon

gradient, heheheheheheh
(I NEED MORE GIVE ME MOREEEEEEEEEE)

sunset

Orange, mic drop.
(but also it looks like mars sob)

Features

  • smoother rolling sound with smarter fade logic
  • mini‑mode that doesn’t break when you click it (yay)
  • scrollbars that disappear like they were never there
  • haptics that actually work and don’t fire 900 times a second
  • glossy theme is now ✨ glossier
  • rolling physics + audio feel way more natural now
  • the orb is just… nicer?? like it has manners now almost??

Bugs I Fixed

  • rollSoundLevel mysteriously breaking (fixed)
  • rolling continuing after tabbing away (fixed)
  • clicking the mini trackball breaking the ball (fixed)
  • stuff near the trackball not being interactive (fixed)
  • WebKit scrollbars ignoring me (fixed via CSS war crimes)
  • tiny audio gap during continuous scroll (fixed)
  • haptics not working (fixed)
  • glossy theme not glossy enough (fixed)
  • rolling too grate‑y (fixed)

Demo

Updated the demo again because if I’m suffering, you get to see the results :3

Attachment
Attachment
Attachment
0
NellowTCS

So… I did a bunch of one thing:

This commit message best summarizes it:

I just wrote a manual audio engine
d6e51b1
 · 
2 hours ago
this took ages

help
help me
someone
/j this is normal for me I made an *audio codec*
no it isn't why didn't i use audio files
WAIT
OH
OMG
AAAAAAAAAAAAAAAAAAA

So uh.
I sat down to “add some sounds.”

Anyway, I guess I wrote a manual audio engine.

Like.
A whole one.

From scratch.

Why?
I don’t know.
Ask the version of me who thought “hm yes, procedural rolling‑bearing noise with dynamic playbackRate modulation sounds fun.”

Stuff I Did (aka: why am I like this)

  • Built a full WebAudio pipeline with:

    • master gain
    • compressor
    • noise generator
    • rolling loop buffer
    • bandpass / highshelf filters
    • waveshaper distortion
    • dynamic envelopes
    • speed‑scaled playback
    • and a tiny sprinkle of “why didn’t I just use .wav files”
  • Added per‑event sound design:

    • grab -> crunchy mechanical click
    • release -> softer mechanical click
    • snap -> UI‑meets‑industrial “thunk”
    • spin -> tick‑tick‑tick with speed‑based pitch
    • stop -> inertia decay with settling noise
    • rolling -> continuous bearing rumble with dynamic stuff
  • Implemented a rolling sound layer that:

    • loops seamlessly
    • crossfades
    • modulates playbackRate based on speed
    • tears itself down when idle like a polite guest
  • Added speed‑aware feedback everywhere so the widget feels alive and so realistic.

Features

  • Rolling bed sound with adjustable intensity (rollSoundLevel).
  • Speed‑scaled spin ticks so fast spins sound fast and slow spins sound like a sleepy hamster wheel.
  • Grab/release/snap/stop events that feel like a physical object instead of a div.
  • Automatic fade‑outs, teardown, and cleanup so your CPU doesn’t cry.
  • Configurable everything because apparently I can’t stop adding knobs.

A Bug I Fixed (and by “bug” I mean “my sanity”)

  • Prevented the rolling layer from stacking 400 overlapping loops because I forgot to gate it.
    (It sounded like a jet engine and now my ears hurt.)

Demo

Updated the demo to expose rollSoundLevel because if I suffered for this, you get to play with the dial.

1

Comments

NellowTCS
NellowTCS 4 days ago

Yes I’m serious, I actually forgot that music files existed and that people have made audio clips of trackballs before.

NellowTCS

DEVLOG TIMEEEEEEE
Hackatime is behaving much more nicely, kudos to the maintainers. XD

I did stuff.

Okay, actually, I turned the little trackball experiment into a proper, modular toolkit with theming, config, and haptics.

Stuff I did

  • Added a config/type system so users can pass options and they merge with sensible defaults (types.ts, config wiring in main.ts).
  • Theme system: JSON themes + a loader, added multiple theme files (default, aqua, glossy, metal, red) and wired them to CSS variables so themes actually apply
  • Scroll mode & utilities: initial scroll helpers landed (page/nearest/horizontal/momentum), plus a scroll engine to drive snapping and scroll behavior
  • Modularization: split the code into small modules: DOM manager, controls manager, physics loop, scroll engine, sound, and haptics, so each piece is easier to reason about and test
  • Haptics: integrated the tactus package and added a simple haptic engine that calls triggerHaptic(duration)
  • Auto-reconfig: when config changes after mount, things reapply (theme, physics params), so runtime updates are respected (main.ts, physicsEngine.ts).

Features (what you, yes you John, get now)

  • themes loaded from JSON.
  • CSS-variable theming so switching a theme is immediate and global.
  • Trackball scrolling with multiple scroll modes and snap behavior.
  • Haptics through tactus for native-feeling pulses.
  • Auto reconfiguration so changing options at runtime updates behavior.

A bug/UX fix

  • Made theme application safe and non-destructive so it won’t “explode” rendering; also added a small delay/guard where needed so controls hide/show behavior is nicer.

Demo (cause we all need one in our lives dont we)

  • Updated the demo to show the new stuff using something really cool hehe
Attachment
Attachment
Attachment
Attachment
Attachment
Attachment
0
NellowTCS

So first devlog for Tamaru!!!

I initially made this today at like 6 AM as a small JS experiment, then was like, this is actually so useful!!!

Then i decided to make this an npm module/library, for fun :3.

Stuff I did to the original JS module

  • Made into TypeScript to be cleaner (almost just a rename to .ts, not much complexity)
  • MODULARIZATION: core movement/physics, DOM helpers, and entry point.
  • Styles are imported as text and injected at runtime for a self-contained build (I don’t like having to import styles separately for a few reasons)
  • Used tsup for TypeScript bundling.
  • Symlinked Build/dist to Demo/dist for easy demo updates. (so useful omg i should do this everywhere)
  • Copied a bunch of CI, Config, etc from another project, Sairin, and edited it for Tamaru
  • Created Demo/index.html to showcase the widget.
  • Added a large block of lorem ipsum in a scrollable div to test trackball scrolling.
  • Disabled native page scrolling; only the trackball or scroll area can scroll content.

Features

  • pseudo-3d ball
  • pseudo-3d ball (it’s so cool omg)
  • Draggable, floating widget with snap-to-edge logic.
  • Trackball area for scrolling with inertia.
  • Minimize/restore toggle.

A bug that was fixed

  • Controls popup uses a delay before hiding, so i don’t have to speed click before the controls hide.
Attachment
Attachment
Attachment
Attachment
1

Comments

NellowTCS
NellowTCS 15 days ago

i used the demo page to make the banner
that’s so funny to me
it’s just the Tamaru with the orb and it’s perfect

NellowTCS

Shipped this project!

Hours: 8.71
Cookies: 🍪 159
Multiplier: 18.22 cookies/hr

So… this is floEditor.

A metadata editor for a new audio format I made.
The hardest thing by far was knowing when to stop. :P

flo has SO MANY FEATURES, but a practical metadata editor can’t implement everything in one go; it’s bad for both developer UX, user UX, and most importantly, the UI.

I had to optimize (I do this for every project as a habit I ingrained) to get it working extremely quickly and smoothly on a Chromebook (my preferred testing device, because it’s so bad that everything else just works)!

I am so proud of the theming, it took ages to perfect, and especially since color is really, really important for your app’s personality and stuff.

Feel free to check it out and

NellowTCS

It seems my mysteriously missing coding time has returned!

But all I did was clean up the repo to get ready to ship it!

0
NellowTCS

Two more things finished (yesterday)!

  • remix_chain (Remixes of remixes of remixes of remixes of the original track?)
  • artist_signature(Image of the artist’s signature or watermark)

I also reorganized the Artwork section to reduce the time it takes to scroll the page.

Attachment
Attachment
Attachment
0
NellowTCS

Well 3 more things done!
user_urls (custom URLs)
musician_credits (extra musicians)
involved_people (other involved people)

And I improved the lyrics stuff!!!!

Now you can add multiple SYLT/USLT pairs to your flo files, and choose between them in the players that support them (HTMLPlayer apparently doesn’t support it yet (but only the UI) 😭)!

This was also added to ID3Editor haha

Attachment
Attachment
Attachment
Attachment
0
NellowTCS

Well I added a TODO.md and almost completely finished it within an hour and a half.

Productive, much?

The list of tags supported is quite large, so it will be in a comment, but in short, almost every tag that flo supports is editable/viewable/set.

I added two new components:

  • AdvancedTags.tsx: for the slightly excessive/extra tags that are useful, but unneeded for most people. This is collapsed by default, and can expand with a click.
  • ViewInfo.tsx: tags that encoders such as reflo set and aren’t editable

Looking at the UI, it’s getting a bit long.
I may split it into tabs, but that’d require a rather large UI revamp… 🤦

But first I want to get all tags supported!

What’s left?
(this is copy-pasted straight from the TODO lol):


## Unimplemented/Missing metadata fields in floEditor

### INVOLVED PEOPLE / CREDITS

- [ ] `involved_people` (array of [role, name])
- [ ] `musician_credits` (array of [instrument, name])

### URLS (not surfaced in UI, though TS has them and some are )

- [ ] `user_urls`

### COMPLEX/ADVANCED (might complete after v0.1.0)

- [ ] `spectrum_fingerprint`
- [ ] `integrated_loudness_lufs`
- [ ] `loudness_range_lu`
- [ ] `true_peak_dbtp`
- [ ] `remix_chain`
- [ ] `artist_signature`

### COVERAGE

- [ ] Some `PictureType` and `SectionType` options exist in Rust but are not accessible in the UI
  - [ ] “bright_coloured_fish”, ”video_screen_capture”,
  - [ ] Section markers like “breakdown”, “drop”, “instrumental”, “silence”, “other”
Attachment
Attachment
Attachment
1

Comments

NellowTCS
NellowTCS 3 months ago

What I finished:

Read-only by user:

  • encoding_time
  • tagging_time
  • encoder_settings
  • flo_encoder_version
  • source_format
  • original_filename
  • Encoded By

IDENTIFICATION / BASIC INFO

  • subtitle
  • content_group
  • original_album
  • set_subtitle
  • original_artist
  • original_lyricist
  • playlist_delay

DATES / TIMES

  • recording_time (string)
  • release_time
  • original_release_time

RIGHTS / LEGAL / SORTING

  • produced_notice
  • file_owner
  • radio_station
  • radio_station_owner
  • album_sort
  • artist_sort
  • title_sort

INVOLVED PEOPLE / CREDITS

  • remixer

URLS

  • url_copyright
  • url_audio_file
  • url_artist
  • url_audio_source
  • url_radio_station
  • url_payment
  • url_publisher
NellowTCS

WE HAVE A LOGO

Also finished 3 more of flo’s features!

BUT WE HAVE A LOGO

Attachment
Attachment
Attachment
Attachment
Attachment
3

Comments

NellowTCS
NellowTCS 3 months ago

oh no the banner borked

NellowTCS
NellowTCS 3 months ago

Stuff left that flo supports:
Loudness profile (LUFS points)
Remix chain (track history)
Spectrum fingerprint (audio fingerprint)
Flo-specific: encoder version, source format, custom fields

NellowTCS
NellowTCS 3 months ago

It seems I am missing a lot more stuff than I realized
A LOT more.

NellowTCS

Some more tiny improvements.

I added the Popularimeter tag for rating and play counts
Also KeyChanges for “[tracking] musical key changes over time” (basically BpmMap but for the key, as both bpm and key are usually not constant throughout the entire song)

(i’m not sure if markdown links work in flavortown lol, i hope they do)

Attachment
Attachment
2

Comments

NellowTCS
NellowTCS 3 months ago

they do!

NellowTCS
NellowTCS 3 months ago

Stuff left that flo supports:
Loudness profile (LUFS points)
Creator notes (timestamped notes)
Collaboration credits (roles and names)
Remix chain (track history)
User text (custom key-value pairs)
Spectrum fingerprint (audio fingerprint)
Flo-specific: encoder version, source format, custom fields

NellowTCS

This is something cool that flo supports: pre-generated waveform peaks.

Basically it stores the peaks in the audio data to help make visualizers (such as the ones in HTMLPlayer) easier to generate/play. Instead of generating the data on demand, it generates it while encoding, directly into the file.

floEditor now does this automatically!

If you’re worried about the file size increase, I calculated it, and there’s only a 5-6 KB increase for a 2 minute song, so, no need to worry ;D

Attachment
1

Comments

NellowTCS
NellowTCS 3 months ago

Stuff left that flo supports:
Key changes (key shifts)
Loudness profile (LUFS points)
Creator notes (timestamped notes)
Collaboration credits (roles and names)
Remix chain (track history)
User text (custom key-value pairs)
Popularimeter (rating/play count)
Spectrum fingerprint (audio fingerprint)
Flo-specific: encoder version, source format, custom fields

NellowTCS

A retheme.
It looks so good :O

This better follows flo’s colors and looks more unique from the original base.

Also a tiny bugfix for the Process and Download icon.

(just noticed that it says FloEditor but should be floEditor, will fix that)

Attachment
Attachment
0
NellowTCS

I got so much done :D

Stuff left that flo supports:
Key changes (key shifts)
Loudness profile (LUFS points)
Creator notes (timestamped notes)
Collaboration credits (roles and names)
Remix chain (track history)
User text (custom key-value pairs)
Popularimeter (rating/play count)
Waveform data (peaks for visualization)
Spectrum fingerprint (audio fingerprint)
Flo-specific: encoder version, source format, custom fields

Attachment
1

Comments

NellowTCS
NellowTCS 3 months ago

WHAT
MY TIME SPENT
It should not be that little :O

NellowTCS

Well a bunch of debugging why my library wasn’t initializing later (Vite being picky about WASM):

IT WORKS

mostly

Attachment
2

Comments

mannlohchab
mannlohchab 3 months ago

great work . are u using wasm in this ?

NellowTCS
NellowTCS 3 months ago

great work . are u using wasm in this ?

Thank you!
The main flo libraries are Rust-based, so I am using those compiled to wasm, yep