Hacker News new | past | comments | ask | show | jobs | submit login
Draw SVG rope using JavaScript (muffinman.io)
1211 points by stankot on Dec 31, 2022 | hide | past | favorite | 66 comments



Author here.

Woah! This kinda exploded, thank you so much for the kind words!

Lately, I'm trying to add more interactivity to my posts. Mainly inspired by amazing work of Bartosz Ciechanowski [1].

I started drawing with code a few years ago and completely fell in love with it. Problems like this one scratch my itch for creative programming.

I hope some of my posts will inspire people to try making pictures using code, just for the sake of it. Programming should be fun :)

[1] https://ciechanow.ski/

edit: typos


It's interesting that you mentioned, Ciechanowski. It's definitely what I thought of when I saw your post.

After seeing the GPS post [1] on that website, I also decided that I wanted to write posts with more visualizations. I wonder how many people the author has inspired!

[1] https://ciechanow.ski/gps/


Extremely cool.

Something small seems a little off and I'm trying to quantify it. It's something to do with the rope in the tighter bends. Somehow I think the rope needs to be a little tighter — the twisted bits a little closer together as the bend tightens.

Maybe tightening the spacing between "knots" relative to the amount of curvature — rather than using a fixed spacing? Imagine some longitudinal compression occurs as the bend tightens.

Here's an example of an "analog" rope image that might be illustrative: https://cpartyrentals.com/wp-content/uploads/2015/06/rope-le...


Off topic, but wow, your generative art is incredible! I was already impressed and then saw that you're actually physically plotting everything which is next level. Love the fusion of art/math/robotics.


Thank you very much, it means a lot!

Plotting is the reason I always try to generate vector images. I'll probably try to plot a drawing with these ropes. But I would like to add some kind of shading and to figure out how to tie knots.


I love the fact that you use good old-fashioned pencil and paper to work out the details. Not enough of our students appreciate the value of such preparation.


Please make the SVG on the side of the viewport rather than on the top, it makes it difficult to read, since our screens are generally wider than they are tall. A similar effect is used on https://pomb.us/build-your-own-react/ if you wanted to take a look.


That said on mobile it is perfect to have it on top.


Media queries ;)


Or flex!


Feels silly to say it here but I couldn't find a way to contact you: on your blog archive page I can expand categories but not collapse them.


Can you please tell me which browser/os are you using? I'll look into it, although it works my laptop/phone.

P.S. Unfortunately I had some bad experiences with leaving contact info public.


Brave browser (basically Chrome) on Windows 10, and same behavior on Safari on iOS.


I'm not sure what is happening. I can replicate that behavior only when I disable javascript. If that case you can't close it as it relies on the url hash.

edit: typo


I don't have JavaScript disabled on any device. As an aside, it is possible to implement your feature without JavaScript (with <details> and <summary>).


Tip: this would be more beautiful if drawn with a calligraphic pen (source: just see any comic book).

(a calligraphic pen is simply a solid angled ellipse that you move along the stroked path without changing its orientation)


So , the sliders in ciechsnowskis website are really smooth. The animation starts as soon as the slider is moved but doesn't update "janky" , Suppose i jerk the slider a quick left and right , the animation doesn't update all the way to through every state the slider has been through the jerk . I find this very visually appealing and clever.


Your feed is invalid (XML parsing error)

https://muffinman.io/atom.xml


Thank you, I'll take care of it! It seems I broke it with HTML I'm using directly in markdown files.

EDIT: Fixed it, thanks again!


Your <content> elements are malformed, and spec-following feed readers will currently fail to get content, or mangle it: if using <content type="html">, the serialised HTML needs to be encoded as text, which it’s not currently. (Instead, you have a bunch of supposed-to-be-HTML XML tags in the Atom namespace.)

There’s also <content type="xhtml"> which requires an XHTML-namespaced wrapper div and goes full XML, but you should only use that if your tooling will guarantee its XML validity. <https://datatracker.ietf.org/doc/html/rfc4287#section-4.1.3> is the spec for all of this. Reflecting on this and your particular content, there’s a fun technicality that probably theoretically makes type="xhtml" unsuitable for you: you can only use <noscript> in HTML syntax, not XML syntax, because it’s resolved at parse time.


Thanks, subscribed.


Also thanks for https://muffinman.io/blog/get-lines-of-text-from-html-elemen... I think I had this requirement before but did not have desire to do it, your solution is very helpful.


My first thought when I saw this is it would also be useful to draw millipedes and snakes


What publishing system do you use to embed react in your post? Very cool post.


Thank you! I'm using Zola[1] static site generator. Interactivity is is all done in plain JavaScript, no React in this post.

[1] https://www.getzola.org/


It's worth spending some time exploring the rest of that blog - so much great content on there. I particularly enjoyed this one about generative art using Voronoi diagrams: https://muffinman.io/blog/breaking-down-krypton/


Everything about this is stunning and incredible. It’s one of those webpages that is art itself. Such a beautiful presentation. It’s also amazing to see someone walking through this kind of problem. It escapes me entirely but you make it look so obvious in the end!


Computer graphics is such a fun area to work in. This rope is a perfect example of how having strong high school level math skills and a good idea can turn you into a kind of wizard. It’s a really special feeling when you bring to life a dynamic illustration that you can customize programmatically. If you let it go to your head, if kind of makes you feel like a god.


> I'm a visual thinker. For me drawing things on paper makes any problem easier to solve. I would suggest you try the same. Keep a pen and paper near your computer and reach out for them before you start typing code.

I feel the same way. Of course it's easier for visual tasks like this one, but I tend to think of programs developing in space and time as trees and graphs, even for abstract stuff like complex algorithms and data structures.

Though I think most programmers are more language-oriented. It is often hard for me to find the exact syntax required for coding a particular problem which is fully formed in my mind eye as visual steps. Programming languages are oriented to represent each concept with a precise linguistic abstract syntax, instead of representing concrete changes in the program state, and most developers don't seem to mind.


Same boat, checking in. My notebooks are full of scribbles even though I do lots of non-visual programming. It’s my primary thinking aid.

I’ve found this to work out well for me:

- Use languages and tools that let you defer correctness while prototyping. I lose track of “the bigger picture” if I have to context switch to thinking pedantically about syntax and type systems. That’s ok when everything is in place, but is disruptive when experimenting.

- Find good visualization aids, such as sequence diagrams, dependency trees, call graphs etc. Even if you just do it on paper, they can be great tools.

- Read up a bit about dataflow programming. It fits my brain very well, and you can apply the thinking in any language. (Unfortunately existing dataflow oriented programming environments are quite limited and come with other downsides).

Let me know if you have tips to share as well.


Yeah, I've worked with dataflow languages and they're a very good fit for data transformations (not so much for complex runtime control flow). Functional-reactive languages like spreadsheets also make it way easier to reason about than imperative programming.

I like environments where you can keep visualization aids close to the code to which they apply; nowadays, that means using online notebooks a la Jupyter and ObservableHQ, or at least markdown files with a preview plugin integrated in your IDE. There you can represent diagrams as code, like Graphviz and Mermaid.

I long for the day that those visual representations can be accessed programmatically and used as part of the code itself, like VB6 interactive widgets were created graphically yet usable in the application; e.g. creating state machines visually by representing states and transitions as boxes and arrows, then compiling the diagram to add conditions and access their values from code (there are some libraries doing this in some environments and languages, but I'm not aware of one that is portable to many languages). I think we're really close to that being possible with modern languages.


Absolutely beautiful, excellent work.

I would like to comment that for the animation it has the rope anchored on the left. I think that a up and down loop animation would be most natural to have the center of the rope anchored since that motion is generated with two hands going in and out, the center should not look like it slides back and forth as the visible length changes.


Ha, you are completely right. I didn't think about it at all.

I've kept the interactive image short on purpose, so it doesn't cover too much content. Then I tried to squeeze as much movement in that short area.

I may go back and update examples a little bit.


I see things like this and I think, "Wow, should I be calling myself a programmer?" ... even after ~40 years at it! But that feeling makes me love programming even more. I adore this project!


The fact that you are still reading Hacker News, and programming, STILL, says it all :D

37 years in myself


Yeah the SVG and animation are cool but the blog post is phenomenal! Great stuff!


Agree; I was stunned by the interactivity and progressive build of the blog post itself.


"Depending on your needs, you could stop right here," but he doesn't and continues to make it better. What a great write-up and site!


It's like when I watch sped up digital painting videos on YouTube, every time I think "this is perfect" the artist continues and redefines what "perfect" means.


What a fantastic write up - love the choice of "accurate" vs "good enough" - wonder if there are any edge cases that this fails at - might find some time in the new year to check this! Lots of potential for "whip" mechanics in browser.


This is excellent, and SVG is so cool. It's somehow overlooked and not used as often as it should, but it makes so many things possible!


SVG is nice but could be better.

unfortunately SVG 2 has been stuck in draft for pretty much an eternity


I wonder, could you turn this into a sort if generalized version using coordinate space transformations? Sort of like this:

- design a rope pattern as you like (or any other pattern) as if it were perfectly straight - e.g. design your pattern as if the X axis were the path and the Y axis were the normals.

- now take your actual (non-straight) path, divide it into sections and calculate the normals just as described in the post. Don't do any skewing.

For now, I assume the path has a fixed length, so the length of your pattern must be the same as the length of the path.

- divide the pattern into the same number of sections as the path has.

- now you have a 1:1 correspondence between sections on the path and sections on the pattern. Each section begins and ends with a normal perpendicular to the length of the path or pattern. The only difference is that the pattern's sections are rectangular while the path's sections are trapezoids.

- you can map the coordinate systems between them with a linear transformation.

- finally, you can take the vectors that make up your rope pattern and transformation them into the coordinate systems of the path, section by section. Now your previously straight pattern follows the path!

Caveats:

1) This assumes your path has a fixed length and your pattern is defined over the entire length. It would probably be more practical to have a repeating pattern or a function that can generate a pattern given the desired path length.

2) Each section is transformed individually, so if in the pattern, you have a straight line that crosses a section boundary, the line will have a visible kink after transformation. A way to mitigate this would be to use multiple overlapping sets of sections and interpolate the transformation between them.

3) The shape of the path sections is only determined by the two normals bounding the section - so all the path curvature inside a section is lost. If the path is very "curvy" and the sections are too coarse, the pattern will not correctly follow the path. This can be improved by increasing the number of sections and making the individual sections smaller.



Love the preview widget that changes as your scroll through each section. Truly great work.


> The image below will stay in the viewport and update as you scroll.

This blew my mind for some reason.


This is great. I hope you get into Beziers next, I get the strong feeling they can be elegant if done programmatically but I haven't yet put my finger on how and still kinda eyeball them.


Try pressing F10 0 . , and see the background keyboard layout on the blog. It's semi-easter-egg right there, pretty nice.

* I have vimium binded, so the sample keys aren't conflict


There are few things in design as beautiful as animations that update intuitively as you scroll. Bravo! I will be using this for my own scrollytelling inspiration :)


This is why I visit HN.


Nice work, but I have to say that it looks like a voronoi diagram, which triggers trypophobia for some internet people. I would make them assuming the robe as a segmented 3d cylinder object and tangle it with another one as we do in real life


Should be noted, a lot of phobias are common but trypophobia is not one of them. There are hardly any case studies where pattern-based imagery has actually sent someone into fight-or-flight the same way that spiders or heights can. Most of the time when it's discussed on the internet it's a rather mild disgust/horror reaction rather than a clinical phobia. It's possible the term has only gained popularity from internet communities where people intentionally share wacky images, which isn't exactly a useful support group.

That's not to say it's not possible, just so extremely rare that it's not a reasonable design consideration.


Pretty cool. Was crossing my fingers that they would show how to make the rope go over AND under itself (like tying a knot).


And that is why it is so important to solve the problem first.

Best and clearest advice I've seen for quite a while :)


I want to see gpt doing this


It cannot. This is its result: ```svg Copy code <svg width="100" height="100"> <defs> <pattern id="rope-texture" patternUnits="userSpaceOnUse" width="10" height="10"> <rect x="0" y="0" width="5" height="10" fill="#333" /> <circle cx="7.5" cy="5" r="2.5" fill="#333" /> </pattern> </defs> <path d="M20,50 C20,30 50,30 50,50 C50,70 20,70 20,50" fill="url(#rope-texture)" /> </svg> ```


Integrating this with Verlet integration would be cool


Breaks down at high width and low thickness.


wow, that is how you have to present something like that :). Well done! I'm impressed.


Looks good, but is a bit overcomplicated…

The proper way to bend some graphics around a curve is by transforming it to the tangent frame.


Could you elaborate on how you came to that decision? I really want to understand how to think in graphics, and I feel like there aren't any good books that explain that.


Consider that a 2D bitmap is just a function p(x, y) = (r(x, y), g(x, y), b(x, y)), that assigns colors to (x, y) coordinates.

If you have a parametric curve c(t) = (x(t), y(t)), it’s easy to see that for each parameter value t, the tangent of the curve is going to point towards dc/dt = (dx/dt, dy/dt). You can take a perpendicular vector to this tangent by rotating it 90 degrees, and the two vectors will form a so-called tangent frame at t.

If you want to bend your bitmap around this curve, the key idea is to transform the domain of the bitmap. That is, instead of putting your bitmap pixel at (x, y), you would put it at something like c(x) + (dc/dt)(y) (some scaling factors omitted for brevity).

(In practice, you would want to invert this mapping, and map the pixels around the curve back to the domain of the bitmap, to avoid holes, but that’s an implementation detail. The key idea is thinking in terms of warping the bitmap’s domain.)


I don't agree that what you propose is less complicated. Deriving an UV mapping along the curve could be done, but for a cubic bezier spline is not exactly as trivial as you paint it. For an example implementation along a quadratic bezier spline, see https://www.shadertoy.com/view/NltBRB. A cubic bezier is more complex to map since you have to solve an equation of 5th degree. I also think that the author wants to keep everything in vector format to be able to draw the results with a plotter. You could displace the vertices of a straight vector model of the rope using the UVs, but I am not sure that it would be any simpler.


Neat.

Now do it in a webgl vertex shader


This is too cool


Does this work well on iOS?, I experienced some issues with foreignObject, and I failed to import an SVG in a react project, does anyone have an idea what I can do about that?

https://chagai.website/chagai-website-react/

Or the code here:

https://github.com/chagai95/chagai-website-react




Consider applying for YC's W25 batch! Applications are open till Nov 12.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: