That’s a neat idea, I’m gonna have to play around with that! Thanks for the tip.
I’d imagine the length issue would become much more of a problem sooner, and any interactivity via JS will add to the size of the link considerably. The benefit of the block mapping is you can house relatively complex components behind a simple string map without adding that bloat to the url itself.
The idea is that once you have the renderer - whether it’s the hosted site, a native app packaging similar to a “browser” of sorts - you could load and view any Memlink page entirely clientside. The current app is a static html/JS SPA sitting on a small VPS and only handles serving the initial renderer code if not cached locally already.
I managed to fit a hacky text editor inside a URL [0] without too many issues, and I didn't bother with any minification or custom packing of the data. So you can easily take it a lot further!
I found there were a lot of edge cases with data URIs that made sharing them kinda annoying. Like email providers stripping the data URI when you email it (not getting spam-binned. The link would get deleted. Even if you left it as a plain text email.)
Firefox doesn't appear to have a URL length limit. Unfortunately, the world is standardising on Chrome, and that absolutely does (about 2,097,152 characters for the entire URI). Chrome also _sometimes_, but not always, opens a data:text/html link in Quirks Mode.
Good info thank you! Yeah I’ve noticed some weird stripping behavior in some clients like iMessage and Slack. Not sure if it’s the encoding or the length of the string that is my current issue but they both seem to play a role.
Many things on the Net have a 2000 character limit for URLs. Still, I bet some creative minds could do a lot in 2000 characters. We should start a demo scene.
It’s ok, this person incorrectly assumed I’m hearing about the concept for the first time, instead of just not thinking of it first. So not only was their comment degrading, but also unfounded.
A page within a page, huh? Getting fancy. I haven’t figured out a good way to solve this concept. It works better if you make the page and then use a url shortener to refer to that page, so you don’t have the entire contents of the sub page in the first page :D fun stuff! Any ideas? Thanks for trying it out.
Update: this is now live! If you navigate to a legacy path w/o a #, it will redirect you on load to the new router protected by the #. This was a great idea for privacy, and I really appreciated this feedback.
Please give it a go and let me know if it works for you, if you get the chance. Thanks!
if anyone is curious, the link data is the following in base64:
1;1|fig:MemLink;5;2;c|h2:In-memory micro web pages;5;3;c|p:MemLinks are self-contained, micro websites that are fully generated at the edge.|p:Use a MemLink to easily share lists of links, contact details, project overviews, and so much more.|h3:The link is the web page.;1;3|p:Memlink pages are composed of blocks that can be added, removed, and rearranged to make unique and creative content.|p:Create your own Memlink now by clicking Edit this page below.
is this a bespoke markup format or just something i don't recognize?
Haha thanks for posting this! It is a custom templating syntax I came up with to store the document data as compact as possible before encoding.
You have:
<doc_config> | <block_data>
Where doc config is:
<palette_index> ; <background_index>
And block data is a list of blocks separated by | that have the following structure:
<block_type> : <block_value> ; <block_config>
And block_config is an additional set of characters separated by semicolon. Right now each block reads its metadata differently, so the order of the metadata options depends on the block they’re used for. I’d like to standardize them eventually. Most start with:
<background_color_index> ; <text_color_index>
The color indexes map to the index position of the given document palette selected. Every palette’s first two colors are white, and black.
Probably could make this shorter by applying compression optimized for text. Also I wonder what happens if you enter | into the custom text field, can user input break this or will the special characters be escaped / handled some way?
If the content is encoded in the URL then that's all going to the server (unless the # idea someone mentions below gets implemented) and thus everything being shared is visible to the site owners. For savvy people that's probably understood but others might not get it, and either way it helps to understand the site's policy regarding this.
Great point - no privacy policy yet (have spent only a handful of hours on this PoC so far). I hope to get around the server-data issue like you mentioned with the hashbang suggestion from another commenter.
For the record, I am completely ignoring the path server-side, and just proxying the request via nginx to a single page Next.js client that is completely client-side rendered. The server doesn’t need the path at all, so yes I do hope to avoid sending it altogether. Going to try to implement that update this weekend without breaking backwards compatibility with already live links.
FYI this is now deployed and live, the privacy point was huge and I wanted to make it clear that this is CSR only, and the # was perfect. Now if you route to a legacy path i.e. without a #, you will be redirected to the memlink protected behind the #.
I will still work on a privacy policy that outlines these things :) Thank you again for the great feedback.
Thank you! Awesome that you want to try it, this app is just a small part of a bigger app that I am developing, a mix between Twitch and Zoom, but for musicians and other performing arts. I hope to launch it soon here in HN, will let you know, i feel you might be interested! Best of lucks for ya!
Is there a link to documentation for the metadata? I'm trying to add an image and center it but it scales to the full paged width. Wondering if that can be changed in the metadata.
I need to add some syntax docs, but ideally I want to abstract out the syntax for an easier-to-use form based block config so you know how to use the block.
For the image tag, it currently takes three options:
<img-style> ; <img-size> ; <justify-content>
img-style can be: "r" for rounded, or "s" for square (for some reason square isn't working right now, need to check on that...)
img-size can be: "xs" for x-small, "s" for small, "m" for medium, "l" for large and "f" for full-width
and justify-content can be : 's' for flex-start, 'c' for center, and 'e' for flex-end. The image is wrapped in a flex box that uses this setting to justify the image.
In writing this comment I just realized I missed the bg-color config for the image block! :D Going to add that.
- the Tweet block, you can just pass it a tweet ID and it's options are <bg-color>;<alignment> where alignment is 'l', 'r', or 'c' for left, right and center respectively
- the ASCII text block which uses figlet under the hood. Right now it only takes <bg-color> ; <text-color> but I want to also expose different figlet fonts you could set.
I hard refreshed and started getting a client side error in Chrome but was able to load it in Firefox still.
I seemed to have lost the ability to re-order the blocks.
Do you have plans to make redirects possible so I don't have to update the URL everywhere I would want to use it? eg meml.ink/justin could always go to the latest version of a profile page? Page stats would also be interesting to see (similar to adding + to the end of a bit.ly url)
It seems like with those features you'd be re-creating linkstree, about.me, or a million other generic profile pages. I guess I'm interested what your plans are.
Thanks for the heads up! I pushed a fix and drag-n-drop should be functioning properly again, sorry about that.
Linktree was definitely an inspiration to recreate - the big differentiator between Memlink and Linktree (and pretty much every other competitor in the space) is that, Linktree requires you to be connected to the internet. Once you've loaded Memlink once, for any page you visit first, you can load any new Memlink site entirely offline (granted, dynamic blocks like the Tweet block will show an offline state until you're back online). This is because the block parser and renderer is cached once you've loaded it, and Memlink operates as a PWA and can still render content without hitting a server. You can try it out on your end by:
1) Make sure you've gone to meml.ink at least once on your phone
2) Create a new site using Memlink on your laptop or desktop
3) Put your phone in airplane mode/disconnect from WiFi etc
4) Scan the Memlink QR code from your laptop/desktop onto your phone
5) The Memlink page should load fine on your offline phone
This could be hugely useful for a variety of reasons such as limited access to internet, limitations on bandwidth usage, resiliency for important documentation/info against network failures, censorship, last-mile connectivity, etc.
Also just noticed your links got stripped. I was seeing that issue with decoding the ":" in the URL, but thought I had pushed a bug fix for that yesterday...going to investigate that more. Really appreciate you using it, the best of feedback and learning :)
Edit: I wasn't able to replicate the stripping issue on my end when I updated the link, so maybe there was a cached version that you got from before I pushed the fix - if you don't mind please trying a hard refresh on your end and giving the link another go, if you choose to use it again! Thank you.
Wow yeah very similar, thanks for sharing! I’ll have to dive into this. This person was way ahead of me having done this 8 years ago, I wonder how things have changed in that time and what they would change today. The vision they share seems very much inline with my perspective - unique, instantly shareable bite-sized content with zero associated storage cost. Great for usage in tweets, social media, internal communication, etc.
Will it be open-source, I wonder? It would be cool to be able to use other servers/viewers just by taking the right-hand side after the /. It would also make it more resistant to censorship.
Indeed, I agree! I will definitely be open sourcing this in the next week or two. Right now it’s all spaghetti code proof-of-concept (wrote most of it on my iPad touchscreen on the couch…laziness?) but I’ve already started cleaning and standardizing the pieces to be able to open source it all.
The key piece will be the parser module + block component set, which I plan to release as a standalone package, so any app could render these Memlink strings natively and easily.
Yeah the encoded param is regenerated on any block change, so you’ll know if there’s a change. I’ve been thinking of ways to lock down content. Maybe a separate hashed entity in the document config that is only able to be decoded with a localStorage key on the client that authored the content. Thanks for your input!
Small thing, your page hijacks history so you can’t navigate back. Im guessing this happens because you update the url by pushing to history on page load.
It’s only for “legacy”[1] links that aren’t using the hashbang for privacy, the page will redirect to the hashbang. This causes the back button loop. If you create a new page or link to a new link, this shouldn’t occur anymore. Since the link has the page, and I posted this before I added the hashbangs, it will always have this issue unfortunately. C’est la vie - thanks for the feedback there.
[1] The project is less than a week old and there are already legacy concepts that need maintaining, that’s a first for me.
That’s a cool one too, thanks for sharing - hadn’t seen it before.
I think biggest difference is the drag and drop block-based authoring experience of Memlink. Looks like that author has an additional cool project called link-lock to provide protected links - going to look more into it.
I managed to make it crash by spamming letters:
>
Unchecked runtime.lastError: A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received
framework-a87821de553db91d.js:1
Error: code length overflow. (23804>23648)
Hey thanks for breaking it! :) the templating lang is definitely brittle right now and will need to be revamped for anything close to real usage.
I managed to add emoji support last night, which ended up increasing my encoded payload size by about 30%.
I need to add some debouncing to the block updates as it’s real time right now but with all of the encoding seems to overwhelm the page if you type too fast.