6 ms·
Show HN: Memlink, a self-contained web page in a link
- SemanticStrengh 4y agoI 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) cool project btw
- throwaway413 4y agoHey 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.
- alex14fr 4y agoYou could also use data: URLs to make it a true Serverless(c)(tm) experience data:text/html,<b>hello world</b>
- throwaway413 4y agoThat’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.
- kingcharles 4y agoMany 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.
- throwaway413 4y agoDefinitely, you’re right. Normally I’d say the possibilities are endless! But I think they end right around 2000 chars :D
- john-doe 4y agoHere is a table with the size limits per "platform": https://github.com/alcor/itty-bitty#:~:text=Size%20Limits https://github.com/alcor/itty-bitty#:~:text=Size%20Limits
- shakna 4y agoI 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. [0] https://github.com/shakna-israel/selfedit https://github.com/shakna-israel/selfedit
- throwaway413 4y agoGood 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.
- 4y ago
- nyolfen 4y agoif 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?
- throwaway413 4y agoHaha 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.
- Cloudef 4y agoProbably 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?
- hombre_fatal 4y agoIt's percent-encoded.
- throwaway413 4y agoYep exactly - individual components of the string are encoded at different stages to prevent pipes and other characters from breaking the parser. Clearly though all the kinks are not worked out as others here have reported breaking it with some characters. Work in progress for sure!
- kseistrup 4y agoThis reminds me of blinkots: https://github.com/akumpf/blinkot https://github.com/akumpf/blinkot (I'm unsure if there are still any blinkot viewers around).
- throwaway413 4y agoWow 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.
- kseistrup 4y agoWill 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.
- throwaway413 4y agoIndeed, 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.
- kseistrup 4y agoGreat to hear it. And I'm glad that the concept has been re-invented, because I really liked the blinkots when they were still around.
- no-reply 4y agoI assume you would need some sort of hash/encryption to make sure the link is not changed in anyway. I wonder who would need that though. Then again, with that long param at the end of the url, it looks like it should be unique anyway unless the message is the same.
- throwaway413 4y agoYeah 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!
- memalign 4y agoThanks for sharing! I think it’d be nice for privacy if the data came after a # in the URL so it’s never sent to a server.
- throwaway413 4y agoThat’s a great idea! I’m gonna try working that in. Thank you for checking it out.
- throwaway413 4y agoUpdate: 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!
- giantrobot 4y agoSimilar to itty.bitty site[0]. [0] https://itty.bitty.site/ https://itty.bitty.site/
- throwaway413 4y agoVery similar, but I love that name! Itty bitty indeed.
- deleted 4y ago[deleted]
- mano78 4y agoBrilliant! Quite clever and well-developed. I'll use it!
- throwaway413 4y agoThank you :) You made my day with your kind words.
- rurtrack 4y agoThis is like my webpage drum loop app! https://drummy.io https://drummy.io I love this concept
- throwaway413 4y agoNice, yeah! Cool app :) I make my own beats from time to time and will give a try for my next drum line jam. Neat you packed all that into the url!
- rurtrack 4y agoThank 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!
- valgaze 4y agoReminds o hashify.me, ex: https://hashify.me/WFhYIGFyZSBzZWxmLWNvbnRhaW5lZCwgbWljcm8gd2Vic2l0ZXMgdGhhdCBhcmUgZnVsbHkgZ2VuZXJhdGVkIGF0IHRoZSBlZGdlLgoKVXNlIGEgTWVtTGluayB0byBlYXNpbHkgc2hhcmUgbGlzdHMgb2YgbGlua3MsIGNvbnRhY3QgZGV0YWlscywgcHJvamVjdCBvdmVydmlld3MsIGFuZCBzbyBtdWNoIG1vcmUuCgpUaGUgbGluayBpcyB0aGUgd2ViIHBhZ2UuClhYWFggcGFnZXMgYXJlIGNvbXBvc2VkIG9mIGJsb2NrcyB0aGF0IGNhbiBiZSBhZGRlZCwgcmVtb3ZlZCwgYW5kIHJlYXJyYW5nZWQgdG8gbWFrZSB1bmlxdWUgYW5kIGNyZWF0aXZlIGNvbnRlbnQuCgpDcmVhdGUgeW91ciBvd24gWFhYIG5vdyBieSBjbGlja2luZyBFZGl0IHRoaXMgcGFnZSBiZWxvdy4KCgogICAgY29uc3QgdHlwZSA9IHJlcy5oZWFkZXJzLmdldCgnY29udGVudC10eXBlJykgYXMgc3RyaW5nCiAgICBjb25zdCBjb250ZW50RGlzcG8gPSByZXMuaGVhZGVycy5nZXQoJ2NvbnRlbnQtZGlzcG9zaXRpb24nKSBhcyBzdHJpbmcKICAgIGNvbnN0IGZpbGVOYW1lID0gY29udGVudERpc3BvLnNwbGl0KCc7JylbMV0uc3BsaXQoJz0nKVsxXS5yZXBsYWNlKC9cIi9nLCAnJykKICAgIGNvbnN0IGV4dGVuc2lvbiA9IGZpbGVOYW1lLnNwbGl0KCcuJykucG9wKCkgfHwgJycKCgo= https://hashify.me/WFhYIGFyZSBzZWxmLWNvbnRhaW5lZCwgbWljcm8gd...
- throwaway413 4y agoOh nice yeah, seen a handful of very similar projects posted. This one you shared has a rich editor experience! I like that - thank you for sharing.
- nmstoker 4y agoWhere's the privacy policy? 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.
- throwaway413 4y agoGreat 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.
- nmstoker 4y agoThanks! I figured you would be doing the decent thing (ie not listening in!). All the best with the project!
- throwaway413 4y agoThank you! You are too kind. 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.
- BeefWellington 4y agoA simple way around this is to store the data in the fragment, and do the parsing from that.
- mmphosis 4y agohttps://meml.ink/MTt8YTpTaG93JTI1MjBITiUyNTNBJTI1MjBNZW1saW5rJTI1MkMlMjUyMGElMjUyMHNlbGYtY29udGFpbmVkJTI1MjB3ZWIlMjUyMHBhZ2UlMjUyMGluJTI1MjBhJTI1MjBsaW5rO2h0dHBzJTNBJTJGJTJGbmV3cy55Y29tYmluYXRvci5jb20lMkZpdGVtJTNGaWQlM0QzMTU0MDYxNnxhOm1lbWwuaW5rO2h0dHBzJTNBJTJGJTJGbWVtbC5pbmslMkZ8YTp0aGlzJTI1MjBwYWdlO2h0dHBzJTNBJTJGJTJGbWVtbC5pbmslMkZNVHQ4WVRwVGFHOTNKVEkxTWpCSVRpVXlOVE5CSlRJMU1qQk5aVzFzYVc1ckpUSTFNa01sTWpVeU1HRWxNalV5TUhObGJHWXRZMjl1ZEdGcGJtVmtKVEkxTWpCM1pXSWxNalV5TUhCaFoyVWxNalV5TUdsdUpUSTFNakJoSlRJMU1qQnNhVzVyTzJoMGRIQnpKVE5CSlRKR0pUSkdibVYzY3k1NVkyOXRZbWx1WVhSdmNpNWpiMjBsTWtacGRHVnRKVE5HYVdRbE0wUXpNVFUwTURZeE5ueGhPbTFsYld3dWFXNXJPMmgwZEhCekpUTkJKVEpHSlRKR2JXVnRiQzVwYm1zbE1rWjhZVHAwYUdsekpUSTFNakJ3WVdkbE8yaDBkSEJ6SlROQkpUSkdKVEpHYldWdGJDNXBibXNsTWtaTlZIUTRXVlJ3VkdGSE9UTktWRWt4VFdwQ1NWUnBWWGxPVkU1Q1NsUkpNVTFxUWs1YVZ6RnpZVmMxY2twVVNURk5hMDFzVFdwVmVVMUhSV3hOYWxWNVRVaE9iR0pIV1hSWk1qbDFaRWRHY0dKdFZtdEtWRWt4VFdwQ00xcFhTV3hOYWxWNVRVaENhRm95Vld4TmFsVjVUVWRzZFVwVVNURk5ha0pvU2xSSk1VMXFRbk5oVnpWeVR6Sm9NR1JJUW5wS1ZFNUNTbFJLUjBwVVNrZGliVll6WTNrMU5Wa3lPWFJaYld4MVdWaFNkbU5wTldwaU1qQnNUV3RhY0dSSFZuUktWRTVIWVZkUmJFMHdVWHBOVkZVd1RVUlplRTV1ZUdoUGJURnNZbGQzZFdGWE5YSlBNbWd3WkVoQ2VrcFVUa0pLVkVwSFNsUktSMkpYVm5SaVF6VndZbTF6YkUxcldqaFpWSEF3WVVkc2VrcFVTVEZOYWtKM1dWZGtiRTh5YURCa1NFSjZTbFJPUWtwVVNrZEtWRXBIWWxkV2RHSkROWEJpYlhOc1RXdGFUbFpJVVRSWFZsSjNWa2RHU0U5VVRrdFdSV3Q0VkZkd1ExTldVbkJXV0d4UFZrVTFRMU5zVWtwTlZURnhVV3MxWVZaNlJucFpWbU14WTJ0d1ZWTlVSazVoTURGelZGZHdWbVZWTVVoU1YzaE9ZV3hXTlZSVmFFOWlSMHBJVjFoU1drMXFiREZhUldSSFkwZEtkRlp0ZEV0V1JXdDRWRmR3UTAweGNGaFRWM2hPWVd4V05WUlZhRU5oUm05NVZsZDRUbUZzVmpWVVZXUnpaRlZ3VlZOVVJrNWhhMHB2VTJ4U1NrMVZNWEZSYms1b1ZucFdlVlI2U205TlIxSkpVVzV3UzFaRk5VTlRiRkpMVWpCd1ZWTnJaR2xpVmxsNldUTnJNVTVXYTNsUFdGSmFZbGQ0TVZkV2FGTmtiVTV3VGxkd2FVMXFRbk5VVjNSaFkwZFNTRlp1VWt0V1JUVklXVlprVW1KRk1IZFZXSEJPVmtaVmQxUlZVbHBsUlRWMVpVZG9VR0pVUm5OWmJHUXpaRmRHV0U1WVNsQk5iV2QzV2tWb1EyVnJjRlZVYTBwTFZrVndTRk5zVWt0U01rcFlWbTVTYVZGNlZuZFpiVEY2WWtVeGNsZHFhR3BTUnpoc1RUQlJKVE5F https://meml.ink/MTt8YTpTaG93JTI1MjBITiUyNTNBJTI1MjBNZW1saW5...
- throwaway413 4y agoA 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.
- 627467 4y agoHow is this different from https://news.ycombinator.com/item?id=20317840 https://news.ycombinator.com/item?id=20317840?
- throwaway413 4y agoThat’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.
- sinab 4y agoSuper cool. Thanks for sharing. I would it be possible to hash the content in such a way that is addressable by a memorable phrase?
- Existenceblinks 4y agoTry my app link: data:text/html, <details style="padding-left: 1.5rem;" open> <summary><button onclick="fetch(location.href) .then(resp => resp.text()) .then(text => this.parentNode.insertAdjacentHTML('afterend', text))">+</button></summary> </details>
- willcipriano 4y agoThis is a fun concept to play with. I created a similar implementation but for any small arbitrary file: https://podje.li/ https://podje.li/ Works best for text files, my links end up looking like this: https://podje.li/?m=data%3Atext%2Fplain%3Bbase64&n=macbeth.txt&pl=%C2%B1%E1%8C%BA%E2%B3%AC%E5%8A%97%E1%A4%A3%E0%A7%B5%E6%A1%A0%E6%85%80%E3%AF%90%E5%AC%BA%E6%B5%8D%E6%9A%92%CE%BB%E2%86%A5%E4%A3%BE%E7%9D%8C%E1%81%90%E4%A0%BC%E0%B8%8D%E7%9D%82%CE%A3%E3%86%A5%E7%8B%AA%E7%88%AD%D5%8A%E1%A8%B8%E2%BA%A4%DD%97%E2%8E%B3%E5%97%B1%E6%99%A0%E6%86%8E%E3%88%B0%E1%A6%BC%E4%B3%8E%E4%9D%92%CD%A3%E2%97%AC%E4%83%B0%E6%BE%95%E3%A4%B0%E1%B5%BC%E0%B8%8D%E6%88%A7%E2%8D%A3%E1%92%A1%E6%9C%88%E6%86%87%E3%8A%A6%E4%8A%B0%E2%B7%AC%E4%88%A7%E2%8D%A3%E1%97%98%E4%83%B2%E7%8D%80%E3%91%92%E5%A1%BC%E4%B2%A4%DC%86%E7%A4%A3%E3%97%9D%E6%93%AA%E3%A9%80%E3%93%9A%E0%A0%BA%E2%BA%84%D8%B2%CF%83%D7%91%E4%A8%BA%E0%A9%B4%E3%9F%96%E1%A4%A8%E0%B1%AF%E1%88%A6%E0%AE%91%C7%85%E4%A3%B2%E6%BE%94%E1%98%B0%E1%A6%BD%E2%B6%AD%E4%88%A6%E7%AD%91%C7%AD%E5%BC%8A%E6%BA%84%E1%81%90%E5%AE%B9%D0%AC%E6%9D%B7%E1%8F%A9%E3%81%94%E1%93%86%E6%A6%87%E3%9D%94%E5%A6%BE%E2%B5%8D%E6%9A%92%CE%93%E3%B7%B1%E5%83%B2%E6%BA%87%E1%9C%B1%20 https://podje.li/?m=data%3Atext%2Fplain%3Bbase64&n=macbeth.t...
- JustinGarrison 4y agoIs 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. example link here https://meml.ink/MTs1fGgxOkp1c3RpbiUyNTIwR2Fycmlzb24ncyUyNTIwbGlua3N8aW1nOmh0dHBzJTI1M0ElMjUyRiUyNTJGanVzdGluZ2Fycmlzb24uY29tJTI1MkZpbWclMjUyRnByb2ZpbGUtcm91bmQucG5nOzElM0I1JTNCcHxwOldlbGNvbWUlMjUyMHRvJTI1MjBteSUyNTIwbGlua3MuJTI1MjBUaGlzJTI1MjBpcyUyNTIwd2hlcmUlMjUyMHlvdSUyNTIwY2FuJTI1MjBmaW5kJTI1MjBtZSUyNTIwb25saW5lLnxhOlR3aXR0ZXI7aHR0cHN8YTpZb3VUdWJlJTI1MjBjaGFubmVsO2h0dHBzfGE6VGlrVG9rO2h0dHBzfGE6TGlua2VkSW47aHR0cHN8YTpQZXJzb25hbCUyNTIwYmxvZztodHRwc3xhOjEyM2RldiUyNTIwbmV3c2xldHRlcjtodHRwczovLzEyM2Rldi5lbWFpbA== https://meml.ink/MTs1fGgxOkp1c3RpbiUyNTIwR2Fycmlzb24ncyUyNTI...
- throwaway413 4y agoThanks for checking it out! 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. Here's your updated page: https://meml.ink/MTs1fGgxOkp1c3RpbiUyNTIwR2Fycmlzb24ncyUyNTIwbGlua3N8aW1nOmh0dHBzJTI1M0ElMjUyRiUyNTJGanVzdGluZ2Fycmlzb24uY29tJTI1MkZpbWclMjUyRnByb2ZpbGUtcm91bmQucG5nO3IlM0JtJTNCY3xwOldlbGNvbWUlMjUyMHRvJTI1MjBteSUyNTIwbGlua3MuJTI1MjBUaGlzJTI1MjBpcyUyNTIwd2hlcmUlMjUyMHlvdSUyNTIwY2FuJTI1MjBmaW5kJTI1MjBtZSUyNTIwb25saW5lLnxhOlR3aXR0ZXI7aHR0cHN8YTpZb3VUdWJlJTI1MjBjaGFubmVsO2h0dHBzfGE6VGlrVG9rO2h0dHBzfGE6TGlua2VkSW47aHR0cHN8YTpQZXJzb25hbCUyNTIwYmxvZztodHRwc3xhOjEyM2RldiUyNTIwbmV3c2xldHRlcjtodHRwcw== https://meml.ink/MTs1fGgxOkp1c3RpbiUyNTIwR2Fycmlzb24ncyUyNTI... Hope this helps! My two favorite are: - 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.
- escot 4y agoSmall 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.
- throwaway413 4y agoYeah, so sorry about that, it does suck. 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.
- deleted 4y ago[deleted]