Easy-breezy interactive 3d in FramerJS with Sketchfab API Utility

Back to overview

Sketchfab community member Pavel Laptev uses the Sketchfab API with the UX design tool Framer to create interactive experiences. He bases his work on the high-level Sketchfab API by Shaderbytes, which gives easy access to most viewer functionality. We have republished this article with Pavel’s permission – you can find the original here.

Hello, everyone! I’m a UI/UX designer and most of the time I make interfaces, sometimes some illustrations in 2d as well, but I have other passions — 3D, is my hobby, and I try to put 3D everywhere where I can, also, JS and things what you could do with code.

Today I want to tell how to make interactive app prototype with Sketchfab and Framer.

What is Framer?

I’m sure that not some many 3d-artist who will read this article familiar with Framer and other prototyping tools, so let me explain what is Framer.

At this moment in UI/UX world, designers have several most popular tools for prototyping like Principle, Flinto, Invision and Framer. All of these tools are good for certain purposes but Framer in this list is a prototyping tool that allows designers to bring real data, interactions into their prototypes and make high-definition prototypes. Framer consists of multiple parts and features

  • Framer JS — It’s a JS library written on CoffeeScript. Actually, it is a framework with already prepared interactions, methods and components. Because it is a JS you could change and manage everything by yourself as well, write your own components and classes, expand and improve current classes and interactions.
  • Framer Studio — UI shell for JS library. Editor with “Design” and “Code” modes, that’s what makes this tool closer to designers and beginners.

  • Framer cloud and Framer app — share, manage and download prototypes. Test your prototypes with Framer app on iOS and Android devices.
  • Also, Framer has strong and friendly community and a lot of tutorials.

Basically, Framer, it’s a JS so we could do almost everything what we want and could do on the web.

Why Sketchfab?

Also, I’m a big fan of Sketchfab, I remembber how met with this service two yers ago. For me it is a good chance to mix two awesome tools.

Of course I chose Sketchfab not only because I’m “bigest fan”. Why not ThreeJS, p3d, AFrame, TOOLBAG or something else?

Sketchfab at this moment it’s the only one platform who provide for you:

  • online viewer with VR-mode
  • PBR materials
  • Subsurface scattering and translucent materials
  • Online 3d editor
  • Growing and strong community + interesting blog posts
  • Animation support
  • Annotation support
  • Post-effects
  • Skethfab API — change materials, annotations, nodes, camera position and much more
  • You could use any model on Sketchfab (even download some of them)
  • Freemium type, until you don’t mind to have additional info in the viewer

That’s why when you need a simple 3d constructor or realistic 3d model on your website Sketchfab could be a good approach for this. For example ThreeJS it’s too complicated and doesn’t provide easily PBR materials or HDR illumination. AFrame is a very cool framework by the way but not for that propose. Toolbag is actually very good but compares to Sketchfab they want too much money if you are just a beginner or just want to embed 3d models, difficult to share. Plus like I mentioned, Sketchfab has a bunch of cool features that you can’t find on other platforms.

And combine this two things — easy, realistic 3d viewer and JS framework for designers, we could achieve awesome results.

Let’s dive into it

If you don’t have Framer Studio, you could download a trial version here. Also, you could download a template project with prepared UI in design mode.

What do we need first, to reach 3d models is add two scripts in Framer. In the template it’s already added.

insertScript = (src) ->
 parseScr = Utils.domLoadDataSync src
 script = document.createElement "script"
 script.type = "text/javascript"
 script.innerHTML = parseScr
 document.head.appendChild(script)
insertScript("framer/sketchfab-viewer-1.0.0.js")
insertScript("framer/SketchfabAPIUtility.js")

Now we could embed our 3d model. To do this we will need to create a new layer and include inside HTML Sketchfab iframe code.

What we also need to do is disable Framer events “ignoreEvents: false” and setting up hight of iframe equal to screen height minus our controller container(menuContainer) height.

sketchFabView = new Layer
 ignoreEvents: false
 height: Screen.height-menuContainer.height
 width: Screen.width
 backgroundColor: null
 html: """<iframe id="api-frame" style="border: 0;" src="" width="#{Screen.width}" height="#{Screen.height-menuContainer.height}" allowfullscreen="allowfullscreen"></iframe>"""
 parent: mainLayer sketchFabView.sendToBack()

Next step is initialisation and adding our 3d model with Sketchfab utility. We will make our own model. What is cool in Sketchfab Utility is that you could see all objects (nodes) and materials in the console and just copy names from there.

We will use Cinema 4d, really simple and powerful tool for modelling, rendering and sculpting. Also Cinema 4d has an export plugin for Sketchfab wich is very convenient.

Preparing our model

Our model will be a Framer logo on a pedestal, where we will be capable of changing colours of the logo — top, middle and bottom material.

Another interesting question is how will be looking Framer logo in 3 dimensions. I know it looks like a folded list of paper but in 3d it not so impressive. Always start from sketches.

And proceed in 3d editor. I made this speedy screencast, so you could see the whole process.

  1. Making a model
  2. Export to sketchfab
  3. Adjust materials, environment and lights
  4. Publish your model

Controllers

When our model is ready, we could start to code controllers in Framer, but of course not necessary in this order, you could prepare controllers first.

The idea of this prototype is to create a carousel with different names of Framer groups and while we spin this carousel our 3d logo changing colours to colours of current Framer group name.

So I made a few sketches:

And chose the third version, because there’s something vintage in this carousel it reminds me photo optics or vintage radios. You could see this version in the design mode if you downloaded the template. Let’s start to code controllers.

Array of objects

Make an array of objects of all Framer groups exactly what we need. Because after that we could easily separate and manipulate these objects and we will have one place for all our colours, and names in strong order.

The structure for our objects will look like this

Name = {
  Framer group name;
  Top material color for logo;
  Middle material color for logo;
  Bottom material color for logo;
}

And with real data

framerGroups = []
FramerOfficial = {name: "Framer Official", top: "#c1f3ff", middle: "#47a8f8", bottom: "#1958f5"}
FramerKorea = {name: "Framer Korea", top: "#fff", middle: "#ed4235", bottom: "#47a8f8"}
FramerBerlin = {name: "Framer Berlin", top: "#040404", middle: "#ff2825", bottom: "#ffc800"}
FramerSeattle = {name: "Framer Seattle", top: "#fff", middle: "#8dfbdb", bottom: "#327990"}
FramerNYC = {name: "Framer NYC", top: "#fff", middle: "#b3b3b3", bottom: "#4c4c4c"}
FramerAmsterdam = {name: "Framer Amsterdam", top: "#ec4235", middle: "#fcfffc", bottom: "#48a9f8"}
framerGroups.push(FramerOfficial,FramerKorea,FramerBerlin,FramerSeattle,FramerNYC,FramerAmsterdam)

PageComponent

Now we need to create a new PageComponent. In this PageComponent we will push all or Framer groups names — it will be our carousel. All elements I made in design mode, therefore, we could just copy them or their properties.

page = new PageComponent
 width: Screen.width
 height: menuContainer.height
 scrollVertical: false
 parent: menuContainer
 contentInset: {right: 100}

Through the loop, we will create and push in the PageComponent our Framer group names.

FGnames = []
for i in [0...framerGroups.length]
 FGname = btn0.copySingle() #clone from original btn
 FGname.name = "FGname#{i+1}"
 FGname.props =
 x: 100+200*i
 opacity: 0.3

 Framer["btnText#{i+1}"] = new TextLayer
  parent: FGname
  fontSize: groupName.fontSize
  textAlign: "center"
  y: groupName.y-2
  color: "black"
  text: framerGroups[i].name
  name: framerGroups[i].name

 FGname.width = Utils.textSize(Framer["btnText#{i+1}"].html).width+60
 Framer["btnText#{i+1}"].width = FGname.width
 FGname.parent = page.content
 FGnames.push(FGname)

btn0.destroy() #delete original btn
page.snapToPage(FGnames[2])
page.currentPage.opacity = 1

The final part of carousel is to change opacity of our group names and change position of lines below names.

page.on "change:currentPage", ->
 for i in FGnames
  i.animate
   opacity: 0.3
   options:
   time: 0.2
 page.currentPage.animate
  opacity: 1
lineContainer.x = -page.horizontalPageIndex(page.currentPage)*40

page.content.on "change:x", ->
 lineContainer.x = Utils.modulate(@x/200,[0,1],[0,40])

sketchfabAPIUtility

Our components are ready to rock, all we need now is setup and connect them with our 3d model through Sketchfab API utility.

To init Sketchfab API, all you need is create new SketchfabAPIUtility:

sketchfabAPIUtility = new SketchfabAPIUtility('96500a575b6049d29a2af56052b97d96', document.getElementById('api-frame'), onSketchfabUtilityReady,{autospin: -0.3});

In onSketchfabUtilityReady() we will change colours each time when we change the current page in PageComponent. But first, we also need to write parser function for framerGroups array.

framerColors = (groupName) ->
 sketchfabAPIUtility.setColor("top", sketchfabAPIUtility.AlbedoPBR, groupName.top)
 sketchfabAPIUtility.setColor("middle", sketchfabAPIUtility.AlbedoPBR, groupName.middle)
 sketchfabAPIUtility.setColor("bottom", sketchfabAPIUtility.AlbedoPBR, groupName.bottom)

And in onSketchfabUtilityReady()

onSketchfabUtilityReady = () ->
 framerColors(framerGroups[2])#set up default colors
page.on "change:currentPage", ->
 framerColors(framerGroups[page.horizontalPageIndex(page.currentPage)])

All done, but we have one more button “hideStandBtn”. By this button we could demonstrate how easy is toggle the visibility of any parts(nodes) of your 3d model. In the log, we see a name for the stand “stand_obj”.

To hide this, we need to write in onSketchfabUtilityReady() some toggle vars and conditions.

The whole code in onSketchfabUtilityReady() will look like this

onSketchfabUtilityReady = () ->
 vm = this
 toogleFlag = false
 framerColors(framerGroups[2])
 page.on "change:currentPage", ->
framerColors(framerGroups[page.horizontalPageIndex(page.currentPage)])

 hideStandBtn.onTap ->
  if toogleFlag is false
   toogleFlag = !toogleFlag
   vm.setNodeVisibility("standobj", false)
   vm.setNodeVisibility("lightobj", false)
   hideStandLine.visible = true
  else
   toogleFlag = !toogleFlag
   vm.setNodeVisibility("standobj", true)
   vm.setNodeVisibility("lightobj", true)
   hideStandLine.visible = false

That’s all! Our prototype now is ready.

You can see the live prototype here.

Thanks for reading 🙂



 

About the author

Pavel Laptev

UX/UI designer and 3d enthusiast in spare time.


Leave a Reply

Your email address will not be published. Required fields are marked *

Related articles