Рубрики

sketches

How to sketch spring objects


spring_layout#

Position nodes using Fruchterman-Reingold force-directed algorithm.

The algorithm simulates a force-directed representation of the network treating edges as springs holding nodes close, while treating nodes as repelling objects, sometimes called an anti-gravity force. Simulation continues until the positions are close to an equilibrium.

There are some hard-coded values: minimal distance between nodes (0.01) and “temperature” of 0.1 to ensure nodes don’t fly away. During the simulation, k helps determine the distance between nodes, though scale and center determine the size and place after rescaling occurs at the end of the simulation.

Fixing some nodes doesn’t allow them to move in the simulation. It also turns off the rescaling feature at the simulation’s end. In addition, setting scale to None turns off rescaling.

Parameters : G NetworkX graph or list of nodes

A position will be assigned to every node in G.

k float (default=None)

Optimal distance between nodes. If None the distance is set to 1/sqrt(n) where n is the number of nodes. Increase this value to move nodes farther apart.

pos dict or None optional (default=None)

Initial positions for nodes as a dictionary with node as keys and values as a coordinate list or tuple. If None, then use random initial positions.

fixed list or None optional (default=None)

Nodes to keep fixed at initial position. Nodes not in G.nodes are ignored. ValueError raised if fixed specified and pos not.

iterations int optional (default=50)

Maximum number of iterations taken

threshold: float optional (default = 1e-4)

Threshold for relative error in node position changes. The iteration stops if the error is below this threshold.

weight string or None optional (default=’weight’)

The edge attribute that holds the numerical value used for the edge weight. Larger means a stronger attractive force. If None, then all edge weights are 1.

scale number or None (default: 1)

Scale factor for positions. Not used unless fixed is None . If scale is None, no rescaling is performed.

center array-like or None

Coordinate pair around which to center the layout. Not used unless fixed is None .

dim int

Dimension of layout.

seed int, RandomState instance or None optional (default=None)

Set the random state for deterministic node layouts. If int, seed is the seed used by the random number generator, if numpy.random.RandomState instance, seed is the random number generator, if None, the random number generator is the RandomState instance used by numpy.random.

Returns : pos dict

A dictionary of positions keyed by node

>>> G = nx.path_graph(4) >>> pos = nx.spring_layout(G) 

# The same using longer but equivalent function name >>> pos = nx.fruchterman_reingold_layout(G)





How Figma put the bounce in spring animations

An inside look at how Figma engineers used the laws of physics to bring spring animations to life.

We know how important animation is to bringing digital products to life. Animations can make scrolling from one item to the next in a list easy and intuitive, while liking something with a heart can feel playful and fun. In FigJam, animated emotes and high-fives are a core part of the magic of being in the file together, and we wanted to help our users build similar experiences. That’s why we recently launched spring animations, which allow you to design more fluid transition animations when prototyping.

Building spring animations took our engineering team back to the classroom—to make animations that are both natural and accurate, we borrowed principles from physics. We’re excited to share the mechanics behind the movement, and the story of how spring animations bounced their way into Figma.

Going from classroom to code

So we have our variables and formulas—but what good does that do developers? Thankfully, the calculations defining spring animations are settled science, and that stability helps us go from an abstract piece of physics calculations to clean code.

For our use-case, we used the WebKit SpringSolver to ease our development journey. The formula lets us plug in mass, stiffness, and damping into a spring timing function, and we get a value for x.

Still, this equation itself didn’t get us where we wanted to be. It turns out that tweaking mass, stiffness, and damping by hand can be pretty tricky. While these parameters represent physical constants, we as UI designers working with animations don’t necessarily think in terms of pure physics. We want animations to be faster or slower, to be more bouncy, or to have less overshoot—all terms that would make a physics professor break down in tears.

That gap can be described with a simple question: How do we slow down an animation? A physicist would tell us that we can increase mass to do that, but how about stiffness and damping? Do they affect the animation too? The answer is yes, which means that we need to make decisions about which of the parameters to edit and how much to adjust them by. It’s a difficult triangulation, but in order to give designers the most natural way of tweaking their animations, we needed to create a specialized tool that puts all three variables in one place. How we did that was another question completely. It turns out the answer was staring us right in the face.

Getting a handle on spring animations

If you’ve ever used Figma to create bezier animations, you’ll know that there are two handles to adjust the curve. It gives designers a degree of control over what they’re animating without having to manually adjust any inputs. Nikolas Klein, our Product Designer, realized that, while adjusting each of the variables in spring animations by hand could give you something approaching the realization we wanted, it didn’t make much sense for designers to have to fumble around in physics equations. We wanted to give users the same degree of control over spring animations as they had over bezier animations, so we created a UI to do just that—handles and all.

Adjusting the handles changes the bounciness and duration of a spring animation

We knew we wanted handles to play a central role in the spring animation UI, and the idea permeated into our designs and jam sessions. Figma has always focused on “direct manipulation” when it comes to making adjustments; we’d rather make it easy to change visual features intuitively than have to tweak a bunch of numbers. As Nikolas iterated on different variations on the Information Architecture (IA), a small dot that sat on the spring curve was one of the few things that remained constant. That was our handle, yearning to be included in the final design.

Still, we had questions that circled around our three variables of mass, stiffness, and damping. How does moving the handle affect the mathematical formula in the spring curve, and vice versa? How many constraints are in play? Do we need one handle, two, or even three? Do they move horizontally, vertically, or both? Does it have to stick to the curve, or is that even possible?

We started off by building a single horizontal handle because of the predictability of a given spring’s oscillation period. (The period is based on the ratio between mass and stiffness.) The vertical position was trickier. We tried a version where we ran a numerical optimization to have the spring curve match the handle position, but it quickly gave way to instability. After more experimenting, we realized that this position could be related to the ratio between damping and mass, something called the “damping ratio.” Put simply, the more damping a spring has relative to its mass, the lower the handle should be.

Experimenting with mass, stiffness, and damping

Through prototyping, we got the validation we needed for the vertical handle. In addition to being technically feasible, it also felt really good as a team to find that solution. By boiling down the number of variables from three (mass, stiffness, and damping) to two (horizontal and vertical dragging) we created a simple and intuitive spatial model for animators and designers to interact with the curve in a hands-on way. It just so happens that now the vertical position of the handle controls overshoot, and the horizontal position controls the relative speed of the animation.

So we had created good control for speed and overshoot, but what about how long an animation should stay, well, animated? At this point in the tool’s design, users could visually see what a spring animation would be like, but they didn’t know how long these animations would last. For a spring animation like the example below, a designer doesn’t know whether it lasted for two seconds or seven seconds, which is a huge range when making prototypes. We decided to add a way to see and update duration for a spring animation.

In order to give users more control, we included a duration handle to signal where an animation will officially stop. That may seem trivial, but since we’re using physics principles to power spring animations, an animation’s “bounce” can sometimes last way too long.

The spring animation handles

And one more thing: We know that animators don’t work alone, so we also wanted to make sure that spring animations were intuitive for entire design teams, including developers. Thankfully, spring animations are supported by multiple APIs, including Framer motion and react-spring. In fact, we drew quite a bit of inspiration from the react-spring visualizer when we were initially building this in Figma.

In Figma, we made it possible for you to export spring values from the inspect panel and use those values however your developers see fit. For those of you handing off spring animations to your team, we want to note that the terms mass, damping, and stiffness are used in Framer motion and mass, friction, and tension are used in react-spring.

All of these details are focused on one thing: Giving designers and their teams the most intuitive experience, so they can create intuitive experiences for their users.

Try out spring animations in this playground file. If this type of work interests you, check out our open roles—we’re hiring across product, design, engineering, and beyond.

Colin Wynn
the authorColin Wynn

Leave a Reply