As in-person events continue to be held online amid the ongoing Covid-19 pandemic, many events are finding new ways to connect with their audiences and deliver more personal, engaging experiences. It’s no different at Antler — we used to run physical Demo Day events to exhibit our portfolio companies, and now, we need to adapt the format for a decentralised, virtual audience.
在持续进行的Covid-19大流行期间,面对面活动继续在网上举行,许多活动正在寻找与观众建立联系并提供更多个性化,引人入胜的体验的新方法。 在Antler上也没有什么不同-我们过去经常举办物理演示日活动来展示我们的投资组合公司,现在,我们需要调整格式以适应分散的虚拟受众。
I’ve previously written about our first virtual event while explaining why we chose Gatsby over Next.js to achieve excellent performance. Now we wanted to build on top of this foundation to deliver an even better live experience.
之前,我曾写过关于我们的第一个虚拟事件的文章,解释了为什么我们选择Gatsby而不是Next.js来获得出色的性能。 现在,我们想在此基础上构建一个更好的现场体验。
We launched this new platform for our virtual Demo Day Rewired event in Sydney. For the first time, viewers could have their questions answered live, we actively surfaced useful information about each startup as they presented, and we made it even easier to get in touch with each startup’s founders.
我们为悉尼的虚拟演示日重新连线活动启动了这个新平台。 第一次,观众可以实时回答他们的问题,当他们展示时,我们积极展示了有关每个初创公司的有用信息,并且使与每个初创公司的创始人联系变得更加容易。
But Antler is present in 12 locations, each of which runs its own Demo Day, and we wanted to enable each site to deliver the same live experience we had in Sydney in one easy-to-use and customisable platform.
但是Antler分布在12个地点,每个地点都有自己的演示日,我们希望使每个站点都能在一个易于使用且可自定义的平台上提供与悉尼相同的现场体验。
Here’s how we did it.
这是我们的方法。
增强与Firestore侦听器的交互性 (Enhancing interactivity with Firestore Listeners)
From the start, we envisioned this new virtual event experience would augment the live viewing experience by updating the page with relevant information as the live stream progresses, without the user ever having to reload the page.
从一开始,我们就设想这种新的虚拟事件体验将通过在实时流进行时向页面更新相关信息来增强实时观看体验,而无需用户重新加载页面。
Specifically, we wanted to make it a lot easier for viewers to learn more about each startup as they presented by showing
具体来说,我们希望让观众更轻松地了解每个初创公司的展示方式,
- more information about what they do, 有关他们做什么的更多信息,
- background on who the founders are, and 创始人是谁的背景,以及
- a link to their slide deck that the viewer can read and download.观看者可以阅读和下载的指向幻灯片的链接。
All we needed was a way to say which startup was currently presenting.
需要所有我们是一个办法说哪个启动目前正在呈现。

We initially used Algolia to get a restricted public subset of our startups’ data and reduce the number of bytes downloaded by the user with its small JavaScript library (at only 7.5 kB gzipped). Unfortunately, by design, Algolia only fetches data once, and we can’t easily update the front-end whenever data changes. So if we were to continue using it, we would need to periodically fetch new data — a very inefficient method, especially when there are no changes to data between each fetch.
我们最初使用Algolia来获取初创公司数据的受限公共子集,并使用其小型JavaScript库(压缩后仅7.5 kB)减少了用户下载的字节数。 不幸的是,根据设计,Algolia仅获取一次数据,并且每当数据更改时我们都无法轻松地更新前端。 因此,如果要继续使用它,我们将需要定期获取新数据-一种非常低效的方法,尤其是在每次获取之间数据没有更改时。
But since we already stored all our data on a Firestore database, we could use Listeners to get realtime updates to our data effortlessly. Then, we could store which startup was currently presenting in a single Firestore document, listen to that doc’s updates, and update the page accordingly. And we don’t even have to do any particular configuration or write new code thanks to community-supported libraries like react-firebase-hooks
.
但是,由于我们已经将所有数据存储在Firestore数据库中,因此我们可以使用侦听器毫不费力地获取数据的实时更新。 然后,我们可以在单个Firestore文档中存储当前正在呈现的启动公司,聆听该文档的更新,并相应地更新页面。 而且,由于社区支持的库(例如react-firebase-hooks
,我们甚至不必进行任何特定的配置或编写新代码。
With this setup, we could also make it much easier for viewers to contact each startup through a specialised pop-up form. This experience is a marked improvement from the previous in-person one, which asked viewers to physically divert attention from the presenters and open a specific URL on their phone. Now they could do that without even switching the tab — that’s a lot less work required.
通过此设置,我们还可以使观看者通过专门的弹出式表格更轻松地与每个初创企业联系。 与以前的亲身体验相比,这种体验有了显着改善,后者要求观众将注意力从演示者身上转移开,并在手机上打开特定的URL。 现在,他们甚至不需要切换标签就可以做到这一点-所需的工作量大大减少。

Additionally, we partnered with Slido, which provides easy tools to add Q&A and polls for live events, allowing viewers’ questions to be answered by presenters live on air.
此外,我们还与Slido合作,后者提供了简便的工具来为现场活动添加问答和民意测验,从而使主持人可以现场直播观众的提问。
Adding these features enhances the level of interactivity in the live experience. It shows the viewer that we truly rethought the event format for an online virtual audience and not just a rudimentary port of the original.
添加这些功能可以提高实时体验中的交互性。 它向观众显示,我们真正地重新考虑了在线虚拟观众的事件格式,而不仅仅是原始的原始端口。
使用Firetable启用自定义 (Enabling customisation with Firetable)
Now that we’d settled on using Firestore to show the currently presenting startup in realtime, we could also use the same document to store the configuration for each event, such as the event title, time, and live stream URL.
现在,我们决定使用Firestore实时显示当前正在演示的启动,我们还可以使用同一文档来存储每个事件的配置,例如事件标题,时间和实时流URL。
We wanted our global teams to configure their Demo Day as they see fit, so we needed a user-friendly UI to expose this config document to them. Thankfully, we didn’t have to build an entirely new UI to facilitate this, and we avoided the additional baggage of having to update the code when we add a new setting or creating a new UI element to configure a specific field.
我们希望我们的全球团队根据需要配置他们的演示日,因此我们需要一个用户友好的UI来向他们公开此配置文件。 值得庆幸的是,我们不必构建全新的UI来简化此操作,并且避免了在添加新设置或创建新UI元素来配置特定字段时不得不更新代码的额外负担。
We were already using Firetable, our open-source project that combines a spreadsheet UI with the full power of Firestore. At Antler, it allows our team to easily manage and update our internal database and automate day-to-day tasks that involve it.
我们已经在使用Firetable ,这是我们的开源项目,该项目将电子表格UI与Firestore的全部功能结合在一起。 在Antler,它使我们的团队可以轻松地管理和更新内部数据库,并使涉及该数据库的日常任务自动化。

We could continue to using Firetable to expose those configuration fields directly — from text fields to toggles to dropdowns that link to other documents in the database — with minimal extra work on our part and little additional training for our team. Now we just had to decide what can be configured and write the code to enable that in our Demo Day web app.
我们可以继续使用Firetable直接公开那些配置字段(从文本字段到切换到链接到数据库中其他文档的下拉列表),而这方面的工作量很少,而对团队的培训也很少。 现在我们只是要决定什么可以被配置和编写代码来实现,在我们的演示日的Web应用程序。
While we initially used this setup for configuring basic settings for each event, we realised we could also use it to give our team full control over the viewing experience. Our Demo Day app has four pages:
当我们最初使用此设置配置每个事件的基本设置时,我们意识到我们也可以使用它来使我们的团队完全控制观看体验。 我们的演示日应用程序有四个页面:
- a registration page to collect info on the viewer, 一个注册页面以收集有关查看器的信息,
- a pre-event page so those who just registered can preview the startups, 活动前页面,以便刚注册的人可以预览创业公司,
- the live stream page with interactivity, and 具有互动性的实时流页面,以及
- a post-event page so viewers can rewatch individual pitches.活动后页面,这样观众就可以重新观看各个音高。
Instead of setting timers to switch between states, we could now allow our team to change the page displayed through toggles.
现在,我们无需允许计时器在状态之间进行切换,而是可以允许我们的团队通过切换来更改显示的页面。

Enabling this is especially useful if, for example, the live stream was running late and they weren’t ready to switch over from the pre-event page. And since it directly updates the Firestore document, it would also trigger the Firestore listener on the front-end, so again there would be zero page refreshes required. We were even able to extend this by adding small tweaks requested by one event as toggles, so we don’t modify other events and to let future events opt-in to these tweaks.
举例来说,如果直播流的播放时间晚了,而他们还没有准备好从活动前页面进行切换,则启用此功能特别有用。 而且,由于它直接更新Firestore文档,因此也会在前端触发Firestore侦听器,因此再次需要零页面刷新。 我们甚至能够通过添加一个事件请求的小调整作为切换来扩展此功能,因此我们不会修改其他事件,也不会让以后的事件选择加入这些调整。
通过盖茨比确保性能 (Ensuring performance with Gatsby)
While we were willing to accept the small performance cost of switching from the lean Algolia library to the beefier Firestore one, I wanted to continue to improve the performance of the app, especially during the first load.
虽然我们愿意接受从精简的Algolia库切换到功能更强大的Firestore库所带来的低性能成本,但我想继续提高应用程序的性能,尤其是在首次加载期间。
As detailed in the previous article, we had minimal use of static site generation: we only used it to render the page skeleton while we waited for the Algolia query to finish. We wanted to eliminate this by including a snapshot of the config document as part of Gatsby’s static build. Then, when the Firestore Listener first loads, it will update the page data with the latest (mostly minor) updates.
如上一篇文章中所述,我们很少使用静态网站生成:我们仅在等待Algolia查询完成时才使用它来呈现页面框架。 我们希望通过将配置文档的快照作为Gatsby静态构建的一部分来消除这种情况。 然后,在首次加载Firestore侦听器时,它将使用最新(大多数是次要)更新来更新页面数据。
Also, embedding configs in the static build became a necessity since we allow our team to set each event’s meta tags, which Facebook, LinkedIn, and Google use to display on their sites. These platforms’ crawlers perform a single HTTP request on the main webpage and don’t run any JavaScript (such as the Firestore Listener), so we need to include this in the static build.
另外,将配置嵌入到静态版本中也成为必需,因为我们允许我们的团队设置每个事件的元标记,Facebook,LinkedIn和Google会使用这些标记在其网站上显示。 这些平台的抓取工具在主网页上执行单个HTTP请求,并且不运行任何JavaScript(例如Firestore Listener),因此我们需要将其包含在静态版本中。

To retrieve the Firestore document during Gatsby’s build process, we used @deanc/gatsby-source-firestorer
so the doc can be accessible in Gatsby’s GraphQL layer. Now I know what you’re thinking: this seems like unnecessary extra work to achieve this in Gatsby and looks a lot simpler to implement in something like… Next.js. Unfortunately, we didn’t have enough time to build and test a Next.js implementation, and the current Gatsby implementation achieved the same result for our viewers anyway.
要在Gatsby的构建过程中检索Firestore文档,我们使用@deanc/gatsby-source-firestorer
以便可以在Gatsby的GraphQL层中访问该文档。 现在,我知道您在想什么:在Gatsby中实现此目标似乎是不必要的额外工作,并且在诸如Next.js之类的方法中实现起来似乎要简单得多。 不幸的是,我们没有足够的时间来构建和测试Next.js实现,并且无论如何,当前的Gatsby实现也为我们的观众带来了相同的结果。
Now that we cached our configs for the static build, we could rebuild the site at any time so that the viewer gets the latest data right as they load the page. But the question was now: when do we rebuild the site? We couldn’t do this every time the config doc was updated — this would be every time a new startup presents, or every few minutes — and each rebuild would only update a small portion of the page. Rebuilding every time would be very inefficient and cost unnecessary build minutes from Netlify.
现在我们已经缓存了用于静态构建的配置,我们可以随时重建站点,以便查看者在加载页面时可以正确获取最新数据。 但是现在的问题是:我们何时重建站点? 每次更新配置doc时,我们就无法执行此操作-这是每次出现新的启动项时,或者每隔几分钟-每次重建都只会更新页面的一小部分。 每次重建都是非常低效的,并且会花费Netlify不必要的构建时间。
We knew we had specific situations where a rebuild is necessary: when our team updates the social media meta tags and when they switch the current page. If the static-generated site displays another page to the one set in the config doc, it will flash to the new page when the Listener loads. This flashing is a poor and potentially confusing user experience, especially if a previously-registered user logs on to the live stream page, but has to see a flash of the registration page.
我们知道在某些特定情况下需要进行重建:当我们的团队更新社交媒体元标记以及何时切换当前页面时。 如果静态生成的站点在配置文档中显示了与该页面中设置的页面不同的另一页面,则在加载侦听器时它将闪烁到新页面。 闪烁会带来不良的用户体验,并可能使用户感到困惑,尤其是如果先前注册的用户登录到实时流页面,但必须看到注册页面的闪烁。
Luckily, we could use Netlify’s Build Hooks feature to trigger a new build via a Cloud Function. Then, our team could activate it right in Firetable with the single click of a button, again providing full control of the virtual event to our team.
幸运的是,我们可以使用Netlify的Build Hooks功能通过Cloud Function触发新的构建。 然后,我们的团队只需单击一个按钮就可以在Firetable中立即激活它,从而再次为我们的团队提供虚拟事件的完全控制权。

缩略图带来更多性能优势 (More performance wins with thumbnails)
At the end of the previous article, I wrote about how we were displaying uncompressed images uploaded directly by our founders: this meant we were loading potentially lossless images, thousands of pixels wide, for an area that was only 80px wide.
在上一篇文章的末尾,我写了一篇关于我们如何显示由创始人直接上传的未压缩图像的信息:这意味着我们正在加载可能无损的图像,数千像素宽,只有80像素宽。
I also complained about the lack of WebP support in Safari (i.e. all iOS devices). Thankfully, the next major version, Safari 14, will support this. Unfortunately for WebP, I came across an article via Hacker News that details why WebP isn’t any better than a well-compressed JPEG.
我还抱怨Safari(即所有iOS设备)缺乏WebP支持。 幸运的是,下一个主要版本Safari 14将支持此功能。 不幸的是,对于WebP,我在Hacker News上看到了一篇文章,其中详细介绍了为什么WebP并不比压缩得很好的JPEG更好。
Considering these two factors, I decided to stick with JPEG and PNG when writing a Cloud Function that generates multiple, lossy-compressed thumbnails when images are upload. (I first wrote it for displaying thumbnails on Firetable and reused it here.) These thumbnails reduced the number of bytes loaded significantly, down from multiple megabytes to just hundreds of kilobytes!
考虑到这两个因素,我决定在编写Cloud Function时坚持使用JPEG和PNG,该Cloud Function在上传图像时会生成多个有损压缩的缩略图。 (我最初写它的目的是在Firetable上显示缩略图,并在此处重复使用。)这些缩略图将加载的字节数从几兆字节减少到几百千字节,从而大大减少了!

Now, most viewers don’t have to look at whitespace when scrolling down the page or when new startups appear on-screen — those bytes should be downloading the live stream anyway. Our team can now also upload any image without worrying about its size. Plus, we won’t have to ask for images to be uploaded at specific sizes, and they won’t have to resize it in an image editor — or even learn how to use one.
现在,当向下滚动页面或屏幕上出现新的启动程序时,大多数查看者都无需查看空格-无论如何,这些字节都应下载实时流。 我们的团队现在还可以上传任何图像而无需担心其大小。 另外,我们不必要求以特定大小上传图像,也不必在图像编辑器中调整其大小,甚至不必学习如何使用它们。
Thanks for reading! While I still can’t link the source code, you can have a look at our virtual Demo Day events here.
谢谢阅读! 虽然我仍然无法链接源代码,但是您可以在此处查看我们的虚拟演示日活动。
You can follow me on Twitter @nots_dney as I write more about what we’re building with Firetable.
您可以在Twitter @nots_dney上关注我,因为我写了更多关于我们使用Firetable构建的内容的信息。
If you’re launching a product and are hungry to build your next company, Antler would love to hear from you. We are accepting applications all across the world! Apply here.
如果您要发布产品并且渴望建立下一家公司,那么Antler希望能收到您的来信。 我们接受世界各地的申请! 在这里申请。
Are you interested in learning more about how startups are using nocode tools? We’ll also be presenting more about Firetable in this virtual event with Nucode.
您是否有兴趣了解有关创业公司如何使用Nocode工具的更多信息? 我们还将通过Nucode在此虚拟事件中展示有关Firetable的更多信息。