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

Pavel Laptev
7 min readSep 16, 2017

Let’s talk a little about 3d, or if be more specific, about online 3d publishing platform Sketchfab and how to bring cool looking 3d into your prototypes or websites especially today where everyone is talking about VR and AR.

Why Sketchfab?

I just want to explain my choice and benefits from Sketchfab. Why not ThreeJS, p3d, AFrame, TOOLBAG. 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 just realistic a 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.

Why Framer?

I think it’s a good approach for beginners, the good framework with already prepared methods and functions for you, also useful in terms of real data. And combine this two things — easy, realistic 3d viewer and easy JS framework for designers, we could achieve awesome results.

Let’s dive into it

What do we need first, to reach 3d models is add two scripts in Framer. Also, you could download this template.

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 models. To do this we will need to create a new layer and include inside HTML Sketchfab iframe code.

Also, to get rid of “info layers” like this

We could do a little trick, like make a parent layer; it could be an artboard for instance because we will place our Sketchfab layer behind all layers and stretch the hight of this layer until this “info layers” will be invisible. And if you have your own model you could set camera position and perspective in the 3d editor, if not, you could set all of this by Sketchfab API.

sketchFabView = new Layer
ignoreEvents: false
height: Screen.height
width: Screen.width
backgroundColor: null
y: -50
html: """<iframe style="border:0" width="#{Screen.width}" height="#{Screen.height+100}" src="" id="api-frame" allowfullscreen mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>"""
parent: mainLayer

Next step is initialisation and adding our 3d model with Sketchfab Utility. 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 make our own model in Cinema 4d, really simple and very powerful tool for modelling, rendering and sculpting. Also cinema 4d has export plugin for Sketchfab, but you could upload your model in different ways.

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 make and code controllers in Framer, but of course not necessary in this order, you could prepare controllers before the model.

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

I chose the third version, because there’s something vintage in this carousel it reminds me photo optics or vintage radios.

I don’t want to explain each line of code, I think it could be, actually, very confusing.

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()
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()
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.

Link to the model https://sketchfab.com/models/cb1bcda4edb14c4c9251d562b89e2ec7

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

Function structure
Your model ID

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 in the end, I thought that I also could demonstrate how easy you could toggle the visibility of any parts(nodes) of your 3d models. In the log, we see a name for the stand “stand_obj”.

In this model is the only one obvious geometry what we could hide. To do this, we need to write in onSketchfabUtilityReady() some toggle vars and conditions, also, of course, don’t forget to add the toggle button.

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("stand_obj", false)
vm.setNodeVisibility("light_obj", false)
hideStandLine.visible = true
else
toogleFlag = !toogleFlag
vm.setNodeVisibility("stand_obj", true)
vm.setNodeVisibility("light_obj", true)
hideStandLine.visible = false

That is all! Our prototype now is ready.

Live prototype you could grab here

Thanks for reading :-)

--

--