Skip to content

Commit

Permalink
add a blog post and the diary, move the welcome page to the root
Browse files Browse the repository at this point in the history
  • Loading branch information
whatsrupp committed Jan 25, 2025
1 parent 6ed6276 commit ea4385e
Show file tree
Hide file tree
Showing 3 changed files with 300 additions and 5 deletions.
170 changes: 170 additions & 0 deletions src/lib/Blog/Blog.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import { Meta, ArgTypes, Story, Canvas, Source, Markdown, Primary } from "@storybook/blocks";

import * as FidgetSpinnerStories from "../FidgetSpinner/FidgetSpinner.stories"

<Meta title="Blog/Blog" />


# What has 8 files, 312kb of unpacked volume and nearly 1000 downloads? 🏰

**It's this really silly little bundle of code that I wrote over Christmas 🎄**

It’s called `react-fidget-spinner` and it's a small bit of code that is designed to take a small part of a website, maybe an image, whatever you like, and transform it into a something that spins when you click it.


**Sort of like a fidget spinner. 🤷‍♂️**

(It's all a bit tenuous but I had to name it something)



---

**Click Me ⬇️**
<Canvas of={FidgetSpinnerStories.Primary} />


Like a fidget spinner, the premise is simple:

- The more you click it
- The faster it spins
- And the larger is gets
- It starts shooting out sparks it’s going so fast
- And then some bubbles
- Then it stops.

But also, like a fidget spinner, **this package is realistically not that useful for anything**

But it *was fun to make* and I learnt a few things along the way so...



## What can we learn from this silly christmas project?

I kept some detailed notes as I went in a [dev diary](/docs/blog-diary--docs)
and I'll go through a few of my favourite learnings in a bit more detail here.

<Canvas of={FidgetSpinnerStories.TasteOfItaly} />

### Storybook is great, if communication is important within a project.

I mean, you are reading this blog here, live and direct from Storybook.

Some interactive bits here. Some nice looking markdown and formatting there. You can host it easily and for free on GitHub, right alongside where you keep your code. A lot of it can be generated from doc strings.

It is absolutely **fabulous for communicating** technical components.

However, strong communication and documentation is often the cherry on top in fast moving project teams. This is a side project. I think the burden of a good storybook could be tough for a team where designing components wasn't the core role.

For component library teams, or package authors though? Seems like a great choice.




<Canvas of={FidgetSpinnerStories.VelocityBreakpoints} />


### Animation configuration gets fiddly, *fast*

An interesting animation needs variety. Highly repetitive elements don't look or feel natural. They aren't engaging. But to make something look nice the cost is having to express that variety in configuration in multiple dimensions.

#### Issue 1 - Lots of configuration options

Even in a simple project like this one there are 63 things you could configure if you wanted to. They were all linked to different aspects of the animations. That's quite a lot of config already.

#### Issue 2 - Describing variety in configuration

Of those 63 configuration options, some of them you would want to vary. For example, you don't want every bubble to be the same size, or have the same velocity.
I ended up with something I called a `NumericControl`. Which was a nice consistent way of describing variety of a control. At runtime you can then parse the control using generators to get the random value in the expressed range.

```tsx
// Between 90 and 110
const bubbleSize : NumericControl = {
value: 100,
variation: {
type: 'PlusMinus',
unit: 'Percent',
value: 10
}
}

// Between 20 and 25
const sparkVelocity : NumericControl = {
value: 20,
variation: {
type: 'Plus',
unit: 'Absolute',
value: 5
}
}

```

#### Issue 3 - Describing configuration changes in relation to spinning velocity

I really didn't want to go down the path of writing something like keyframes for this project...

and I thought I had managed to avoid writing my own keyframe code.


> 💡 A keyframe is an animation term that describes how you might change something over time.
>
> For example, you might want an animated bubble to start small and grow over time. You could express this by specifying the start size of the bubble, the end size of the bubble and how long it takes to grow.
>
> (It can get more fiddly than that, but that's the jist.)
But in reflection, I did end up with something *suspiciously close* to keyframes. **Velocity breakpoints.** (I stole the name from CSS Breakpoints 🤫)

These allow you to change the configuration of the animation as the veloctiy of the fidget spinner changes.

Here's a basic example. Which Changes the scale to x3 at 90% of the max velocity. and x2 at 70% of the max velocity. Behind the scenes you need to add in some logic to make the step changes not feel too sudden. But I won't go into that.

```
export const defaultVelocityBreakpoints: VelocityBreakpointInput[] = [
{
breakpoint: 0.9, // Triggers at 90% of the max velocity
config: {
scaleConfig: {scale: 3},
},
},
{
breakpoint: 0.7, // Triggers at 70%
config: {
scaleConfig: {scale: 2},
},
},
];
```

<Canvas of={FidgetSpinnerStories.FullConfiguration} />

### Getting a working prototyp with AI is quick but with tradeoffs.

This project sprung up from a silly idea I had when I was ill on the sofa and I got a small interactive animation working quickly.
But to communicate the ideas in it, and turn it into a package that someone with no context might be able to configure and understand? That took a lot longer.
But, an AI consuming from AI world awaits, human communication and clarity becomes less important as long as it **just works**. But for the moment. It is symbiotic and I think good packages still need to communicate clearly.






### Thank you

If you've made it through all this. *Thank you for reading.* I hope a small snippet into the world of making interactive animations was somewhat interesting.

If you make a fidget spinner on this site by using the interactive controls. Let me know ❤️

Nick

---

ps. a big shoutout to Dani who must have heard me say
> "ooo look how it spins *now*"
about 100 times. What a patient woman. 🧘‍♀️





123 changes: 123 additions & 0 deletions src/lib/Blog/Diary.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { Meta, ArgTypes, Story, Canvas, Source, Markdown, Primary } from "@storybook/blocks";

<Meta title="Blog/Diary" />
# Development Diary

I've jotted down some key decisions about this project, some learnings and a very brief diary of the project.

Hopefully this will be nice to come back to in a few years 🪿



## Decision Drivers 🏎️

A short list of the main drivers around the project and what actions I took to address them.

- Initially wanted to make a silly animation when feeling a bit ill, it also was possibly a fun easter egg for someting at work
- Spike with AI
- Animation was very satisfying to use (from my perspective)
- I wanted to be able to use it in react - Find template project and make it my own
- I wanted to make the ai spike more grounded in physics rather than some fairly sketch ai initial work
- rework and refactor the spike
- I wanted the state of the spinner to be able to interact with other aspects of animation
- Velocity breakpointing added, this is the most complicated aspect of the project, it makes the animations really cool but I don’t think people will “Get” this feature - you need to be quite in the weeds to get the most value out of it.
- I wanted to be able to own the project but also allow people to use the package in an open source way, there is clearly an appetite for quick fun given packages like react-confetti
- Published it on npm
- I wanted the project to be highly customisable and configurable
- had to double down on consistent config building with objects in react
- I wanted the config to be easily documentable and also well documented
- learnt about and used storybook
- I wanted to be able to express variety in numerical expressions succinctly and clearly
- NumericControl introduced


## Key Project Takeaways/ Learnings 🧠
- Taking a component and making it into a package that other people can actually use is hard work
- Interface, is it clear, can it be used quickly
- Docs, are things explained
- Defaults, are they sensible
- Edge cases, are they validated
- Handling Breaking interface changes
- Storybook is good but doesn’t deal with a few things that well
- Deep objects in props isn’t great
- Creating Documentation around types and non component related concepts automatically, but there might be other better ways to do that
- Storybook exposes uneditable examples as whole webpages
- Can host for free using GitHub pages
- Mobile storybook isn’t great when it comes to editing config
- Storybook type inference isn’t great when it comes to documenting props
- Can’t change the rendered component/ add react props in the configuration editor
- Expressing variety in animations is fairly complicated
- Found myself somewhat wanting to replicate the css animation interface without realising it until later
- Is the react animation loop that I have chosen performant and how can I test it
- Publishing a package was fairly simple with the template setup
- CSS modules are a good way to write a package because it compiles down and avoids vendor prefixing
- Need to work out a good way to host images / gifs in docs
- Knowing what the right things to be consistent on at the start is hard, it was good to wait a bit with a few concepts eg the variation/ Numeric control and useConfig
- Even if you scope a package to be very limited there’s still a lot of overhead, but in general it is nice to work on something a lot smaller that you can make daily changes to and then release. This was nice on holiday and also for doing a project in a non stressful way.
- 700ish people have downloaded the package which is cool, although the numbers are a bit naive, there is marketing needed when creating a package - not sure which channels are best, software engineering friends is not enough network, might need reddit/ hackernews/ other more nerdy forum spaces
- You need to see people actually using the thing, lots of surprises when asking people to
- Need a good platform for non technical people to try it out and also act as a bit of a buzz.
- Making interactive animations is really really satisfying (for me)

## Diary 📖

Sat 14th December 2024
- Start
- Spike using AI

Sun 15th
- General react project template setup
- Rough refactoring into react from the initial spike

Wed 18th
- Create Gif, make the project template my own and remove guff
- Actually publish the package and claim react-fidget-spinner

Sun 22nd
- Extract out Bubble and Spark concepts into spawner components and give them space in the storybook

Wed 25th
- Make use of the bubble and spark spawner

Thurs 26th
- Make bubbles and sparks a lot more customisable by allowing react nodes

Friday 27th
- Extract out everything into config which was a big job, also generally working out the structure of config from a what are the different “blocks” perspective and setting good defaults and how to handle defaults

Sat 28th
- Really learn about what’s possible with storybook in terms of generating docs and components
- Try and get the docs looking nice but the types and default overriding wasn’t particularly compatible with storybooks approach, ie I want people to pass in overrides for multiple complicated objects

Sun 29th
- Work to get “MVP” release actually out there
- and really get stuck into writing the docs
- Enable turning off of sparks and bubbles
- Checking storybook works a bit etc

30th
- Fly to Berlin
- Wrap up docs on the plane
- Add various discoverablility things in npm - name keywords etc
- Fix some bugs around the gifs not being visible


Wed 1st 2025
- Fix bug around the border select colour on phones, adopted vendor prefix approach
- Change approach with breakpointing where the breakpoints “Build on” the base config rather than replacing them, this made them much easier to define. It might be even easier in the future to define breakpoints by building on the last breakpoint so you don’t have to define a property everytime.

Thurs 2nd
- Add storybook badge and add docs on velocity breakpoints
- Make some more examples and post about it on instagram
- Add deep controls to the docs so that the control inputs are a bit better

Sat 4th
- Introduce the concept of a NumericControl - this allows you to define a number but also the variation of that number as a starting point for an animation - ie it becomes a number that can cover a defined range in a number of ways, by percentage or absolute terms - it might be nice to expand this to include just an absolute range

Sun 5th Jan 2025
- Coding while waiting for a delayed flight
- Use the new numeric controls
- Create a useConfig hook - it allows config to be overwritten and reinitialised in an efficient way. It also standardises the approach for resetting and setting the config. There was bug where, if you updated the initial config it wouldn’t reset the config which had become saved in state.
- Add config for clicker components
- Add clickConfig and actual spinner config to the velocity breakpoints so that all config can be managed in the same way and be controlled from breakpoints
- Write a bit of a dev diary on the plane and some reflection
12 changes: 7 additions & 5 deletions src/lib/Welcome.mdx
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
import { Meta, ArgTypes, Story, Canvas, Source, Markdown, Primary } from "@storybook/blocks";
import * as FidgetSpinnerStories from "./FidgetSpinner/FidgetSpinner.stories"

<Meta title="Welcome" of={FidgetSpinnerStories} />
<Meta title="Welcome"/>


# 🪿 React Fidget Spinner

Turn your react component into a fun clickable spinning widget.
# 🪿 React Fidget Spinner

Click Me ⬇️
Turn your react component into a fun clickable spinning widget. Click Me ⬇️

<Primary />

<Primary of={FidgetSpinnerStories} />

## Quickstart

```bash
npm i react-fidget-spinner
```



```jsx
import {FidgetSpinner} from "react-fidget-spinner"

Expand All @@ -32,6 +33,7 @@ const MyFidgetSpinner = () => {
}
```


## Using These Docs

Each exported component has a docs page and a primary example.
Expand Down

0 comments on commit ea4385e

Please sign in to comment.