This is the very first article that talks about the idea, motivation and the mvp of JSCity.
I learned a lot while doing it and hopefully you will also find something interesting to take out of it as well.
react-three-fiber
So, late last year I started creating JSCity. The ultimate goal was to visualize JavaScript projects as cities. But why?
It all started when I saw the following tweet by Paul Henschel.
Paul Henschel@0xca0ahere's some thing i've been dedicating 1 hour each evening for the last week: a game written in react and threejs (react-three-fiber) wanted to see if i can pull it off but waste too much time on it so i'll abandon it: i2160.csb.app it's still missing damage/collision21:48 PM - 16 Oct 2019
My reaction was: "Wow! That's really cool and it's built with React
, how?!"
The answer was react-three-fiber. I was amazed by the project 🤯. It is a React
reconciler for Threejs, and I got really curious to see what it does.
On one side there is React
, a very popular and robust library to build UIs. Because of its declarative nature React
is really good for a lot of things and the community is always pushing the ecosystem forward.
On the other side, there is Threejs
, the most popular 3D library for JavaScript
with a very powerful and rich API.
Although it is very possible to combine them together the Threejs
imperative nature makes that a non-trivial work. For example, synchronizing React
state with the 3D canvas can be painful.
Now let's take checkout this sandbox. Feel free to play around with it.
react-three-fiber
builds the bridge between the composable and declarative React
nature and the powerful API from Threejs
.
A lot of initial setup and complexity is abstracted. However, the main part is that it exposes a very good API, handy hooks and maps objects from Threejs
to React
components.
Now we can leverage of the best of these two different universes.
Matching an intention with an idea
I immediately wanted to try it. But what should I do?
I made a few examples using react-three-fiber
on CodeSandbox, but I wanted to continually explore and build something bigger.
I've used Threejs
in the past to build a project called SwiftCity (no longer maintained) - a visualizer of Swift code. Then it clicked 💡! I can bring that same idea of visualizing code as cities, but this time applying to JavaScript universe.
I would also be able to explore some other interesting topics like react-three-fiber
, ASTs, babel
, etc.
Besides, 3D things are so cool, right?
JSCity
So JSCity idea came to visualize JavaScript code as cities. My intention was to build a demo to get a sense of how that would look like.
Explaining "The City Metaphor"
To summarize, the idea behind City Metaphor is to analyze and view software systems as cities. The key point is to explore and understand the complexity of a system by mapping the source code to a city.
The concepts
Before rushing to implement the MVP we have to define how to translate JavaScript code into a city. For example, cities have buildings, right? And also blocks. So here are the building blocks that I've chosen for our city:
- What piece of code does a building represent?
- How do we define the dimensions of a building (width, height and length) ?
- How do we show the code hierarchy as areas of a city?
The buildings in the city
In the original metaphor, a building was mapped to represent a Java class. However, various elements can own a lot of responsibilities in JavaScript.
For instance, the buildings could be Functions, Classes, Objects, etc. Beyond that, functions might appear as IFFEs, arrow functions, closures, function expressions and more.
I decided then to only consider simple function definitions and its clojures for the purpose of the demo.
Dimensions
Several metrics can be taken to define the measurements of a building. I decided that the building height would be given by the number of lines of code of the analyzed function. The width and length then would be defined by the amount of calls to other functions inside the examined function.
Topology
The city topology is mapped to elements of the system hierarchy.
Since there are no packages, namespaces or anything equivalent in JavaScript, the mapping will limit to the following levels: the project, directories and the files.
function sum(a, b) {
return a + b
}
function calculate(a,b) {
function log(text) {
console.log(text)
}
log(sum(a, b));
log(minus(a, b));
log(times(a, b));
}
function minus(a, b) {
return a - b
}
function times(a, b) {
return a * b
}
The code above would look something like this:
Function definitions that belong to a file will appear inside the file limits. In the image above, the light grey area represents a file and its functions are the buildings.
Function declarations that are declared inside another function (clojures) will have their own block stacked on top of the building that represents their parent function. We can see that the largest building represents a function that has a clojure inside of it.
Building the MVP
Even having previous experience with the concept and knowing more or less what I would need to build, I still wanted to keep it minimal at first.
I will not go into implementations details here. But do not worry! The next posts will be really focused on exploring every part.
In summary, the steps that I took were:
- Created functions where I could read the content of a JavaScript file and parse it to get its
AST
. For that I've used babel-parser. - Coded something to navigate the
AST
and collect the necessary data from the functions. Instead of using tools like babel-traverse for this, I actually implemented it myself (and I regret it 😅)! - Implemented an algorithm to create the city grid and place the buildings in the right place from scratch. Although I still have the code from SwiftCity, I can barely understand it anymore 😬.
- Used
react-three-fiber
to read the city definition and to render the city. - Used
React
to build the app and handle the input file that would be imported.
The first version
I made it in the end 🎉! The live version is available at JSCity and the code is on GitHub as well.
I've just put live a very limited version of JSCity🏙. For instance, considers just function declarations, height is the line of codes and width/length is function calls. It only supports one file at the moment.
Live at: peaonunes.github.io/jscity/
Feedback is very appreciated🙌🏽☺️09:58 AM - 04 Dec 2019
There is a lot that this first version does not cope with. For example, as I opt in to just consider function definitions a lot of modern JavaScript code will not be represented. One example is functions defined using the the arrow notation.
Some conclusions
I got inspired and could not rest until trying out react-three-fiber
. All because of a tweet. And that is a lesson to me:
Share your work whatever that is. It may inspire someone.
My initial intention was to focus on experimenting with 3D through react-three-fiber
, but what ended up happening was me spending most of the time trying to get a good enough city creation algorithm... That was hard! Another lesson here was:
Choose a project that will let you focus on what you want to learn.
Nonetheless, it was really fun to build it: I got to play around with other nice tools like babel-parser
.
What is next?
I got it working. Now I want to make it better.
The code is very limited and fragile at the moment. I want to extend JSCity and be able to load a directory and build the entire city from that.
From now on I will be diving deep into each part of the implementation one at the time. I'll be sharing it through posts and I hope some of these things are interesting to someone else too!
Let me know what do you think about the idea. Thoughts, suggestions and comments are always welcome. See you in the next chapter.
Top comments (0)