mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-01 19:42:03 +00:00
* fix(docs): load the player from latest, not a pinned minor The catalog pages pinned the player CDN URL to a minor line, and that pin sat one line behind after the last release. Every page kept rendering, on the older build, so nothing surfaced it: the only symptom was that a fix published to npm never appeared on the docs. The generator derived its pin from the player's package.json, which is correct only if every page is regenerated on the release that moves it. That is the step that did not happen, and it has to happen across 175 generated pages plus three hand-written files for the pin to be true. A version carried in step across 178 places will be stale, and stale here is silent. Ask for latest instead and there is nothing to carry. This costs the ability to hold the docs back from a bad player release. Paid deliberately: the pin did not buy that either, it only delayed the good releases too. A test asserts no pinned version comes back, and fails if it stops finding the references at all, so it cannot pass by matching nothing. * refactor(scripts): list tracked files instead of walking the tree The pin guard hand-rolled a recursive directory walk with its own skip list and size cap, which the audit flagged: helpers living in a test file earn no coverage, so their complexity lands straight on the CRAP score. git already knows which files to read, and ignores node_modules and build output for us, so one call replaces the walker and both findings go away.
1130 lines
41 KiB
Plaintext
1130 lines
41 KiB
Plaintext
---
|
||
title: "Code Snippet - Monokai"
|
||
description: "VS Code workbench with per-character typing animation in the Monokai theme. Full editor chrome with activity bar, sidebar, tabs, terminal, and status bar."
|
||
---
|
||
|
||
import { InstallCommand } from "/snippets/install-command.jsx";
|
||
|
||
<iframe
|
||
className="w-full aspect-video rounded-xl border-0 bg-zinc-100 dark:bg-zinc-800"
|
||
title="code-snippet-monokai preview"
|
||
loading="lazy"
|
||
srcDoc={`<!doctype html><html><head><meta charset="utf-8"><style>html,body{margin:0;height:100%;overflow:hidden;background:transparent}hyperframes-player{display:block;width:100%;height:100%}</style><script src="https://cdn.jsdelivr.net/npm/@hyperframes/player@latest/dist/hyperframes-player.global.js"><\/script></head><body><script>fetch("/public/catalog/blocks/code-snippet-monokai.json").then(function(r){return r.json()}).then(function(d){var p=document.createElement("hyperframes-player");p.setAttribute("srcdoc",d.html);p.setAttribute("controls","");p.setAttribute("autoplay","");p.setAttribute("loop","");p.setAttribute("muted","");p.setAttribute("poster","https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-monokai.png");document.body.appendChild(p)});<\/script></body></html>`}
|
||
/>
|
||
|
||
## Install
|
||
|
||
<InstallCommand command="npx hyperframes add code-snippet-monokai" item="code-snippet-monokai" />
|
||
|
||
That writes `compositions/code-snippet-monokai.html`, plus 1 supporting file under `assets/`.
|
||
|
||
## Source
|
||
|
||
<Accordion title={`code-snippet-monokai.html`}>
|
||
|
||
```html
|
||
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=1920, height=1080" />
|
||
<title>Monokai VS Code Theme Composition</title>
|
||
</head>
|
||
<body>
|
||
<template id="vscode-monokai-template">
|
||
<div
|
||
class="vscode-theme-scene"
|
||
data-composition-id="vscode-monokai"
|
||
data-width="1920"
|
||
data-height="1080"
|
||
>
|
||
<main class="scene-content">
|
||
<section class="header">
|
||
<div>
|
||
<p class="kicker">Official VS Code built-in theme</p>
|
||
<h1 class="title"><span class="theme-label">Monokai</span></h1>
|
||
</div>
|
||
<p class="source-note">
|
||
Typing `functional_toolkit.py` with workbench colors from
|
||
<span class="theme-source">monokai-color-theme.json</span>.
|
||
</p>
|
||
</section>
|
||
|
||
<section class="workbench">
|
||
<div class="titlebar">
|
||
<div class="traffic"><span></span><span></span><span></span></div>
|
||
<div class="window-title">functional-toolkit - Visual Studio Code</div>
|
||
<div class="command-center">Search</div>
|
||
</div>
|
||
|
||
<aside class="activity" aria-label="Activity bar">
|
||
<svg class="activity-icon active" viewBox="0 0 24 24" aria-hidden="true">
|
||
<path
|
||
fill="currentColor"
|
||
d="M4 4h7v7H4V4Zm9 0h7v7h-7V4ZM4 13h7v7H4v-7Zm9 0h7v7h-7v-7Z"
|
||
/>
|
||
</svg>
|
||
<svg class="activity-icon" viewBox="0 0 24 24" aria-hidden="true">
|
||
<path
|
||
fill="none"
|
||
stroke="currentColor"
|
||
stroke-width="2"
|
||
d="m21 21-5.2-5.2M10.5 18a7.5 7.5 0 1 1 0-15 7.5 7.5 0 0 1 0 15Z"
|
||
/>
|
||
</svg>
|
||
<svg class="activity-icon" viewBox="0 0 24 24" aria-hidden="true">
|
||
<path
|
||
fill="none"
|
||
stroke="currentColor"
|
||
stroke-width="2"
|
||
d="M8 18 3 12l5-6m8 12 5-6-5-6"
|
||
/>
|
||
</svg>
|
||
<svg class="activity-icon" viewBox="0 0 24 24" aria-hidden="true">
|
||
<path
|
||
fill="none"
|
||
stroke="currentColor"
|
||
stroke-width="2"
|
||
d="M12 3v18m0-18 6 6m-6-6L6 9m6 12 6-6m-6 6-6-6"
|
||
/>
|
||
</svg>
|
||
</aside>
|
||
|
||
<aside class="sidebar">
|
||
<div class="sidebar-title">Explorer</div>
|
||
<div class="section-title">⌄ Functional Toolkit</div>
|
||
<div class="tree">
|
||
<div class="tree-row">⌄ src</div>
|
||
<div class="tree-row child selected">◇ functional_toolkit.py</div>
|
||
<div class="tree-row child">◇ test_toolkit.py</div>
|
||
<div class="tree-row">◇ pyproject.toml</div>
|
||
<div class="tree-row">◇ README.md</div>
|
||
</div>
|
||
</aside>
|
||
|
||
<section class="editor-area">
|
||
<div class="tabs">
|
||
<div class="tab">◇ functional_toolkit.py</div>
|
||
<div class="tab inactive">README.md</div>
|
||
</div>
|
||
<div class="breadcrumbs">functional-toolkit › src › functional_toolkit.py</div>
|
||
<div class="editor">
|
||
<div class="active-line"></div>
|
||
<div class="code"></div>
|
||
</div>
|
||
<div class="terminal">
|
||
<div class="panel-tabs">
|
||
<span class="active">Terminal</span><span>Problems</span><span>Output</span>
|
||
</div>
|
||
<div class="terminal-body">
|
||
<div><span class="prompt">functional-toolkit %</span> python -m pytest</div>
|
||
<div>collected 3 items</div>
|
||
<div>tests/test_toolkit.py ... <span class="tok-comment">passed</span></div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<footer class="statusbar">
|
||
<div class="status-left">
|
||
<span class="remote">main</span>
|
||
<span>0 errors</span>
|
||
<span>0 warnings</span>
|
||
</div>
|
||
<div class="status-right">
|
||
<span>Ln 17, Col 1</span>
|
||
<span>Spaces: 4</span>
|
||
<span>UTF-8</span>
|
||
<span>Python 3.12</span>
|
||
</div>
|
||
</footer>
|
||
</section>
|
||
</main>
|
||
<style>
|
||
* {
|
||
box-sizing: border-box;
|
||
letter-spacing: 0;
|
||
}
|
||
|
||
html,
|
||
body {
|
||
margin: 0;
|
||
width: 1920px;
|
||
height: 1080px;
|
||
overflow: hidden;
|
||
background: #000000;
|
||
font-family:
|
||
Inter,
|
||
-apple-system,
|
||
BlinkMacSystemFont,
|
||
"Segoe UI",
|
||
sans-serif;
|
||
}
|
||
|
||
.vscode-theme-scene {
|
||
--activity-bg: #181818;
|
||
--activity-fg: #d7d7d7;
|
||
--activity-muted: #868686;
|
||
--activity-active: #0078d4;
|
||
--sidebar-bg: #181818;
|
||
--sidebar-fg: #cccccc;
|
||
--sidebar-border: #2b2b2b;
|
||
--tab-bg: #181818;
|
||
--tab-active-bg: #1f1f1f;
|
||
--tab-active-fg: #ffffff;
|
||
--tab-inactive-fg: #9d9d9d;
|
||
--tab-border: #2b2b2b;
|
||
--editor-bg: #1f1f1f;
|
||
--editor-fg: #cccccc;
|
||
--editor-line: rgba(255, 255, 255, 0.04);
|
||
--gutter-fg: #6e7681;
|
||
--gutter-active-fg: #cccccc;
|
||
--panel-bg: #181818;
|
||
--panel-border: #2b2b2b;
|
||
--status-bg: #181818;
|
||
--status-fg: #cccccc;
|
||
--status-border: #2b2b2b;
|
||
--title-bg: #181818;
|
||
--title-fg: #cccccc;
|
||
--token-comment: #6a9955;
|
||
--token-keyword: #c586c0;
|
||
--token-function: #dcdcaa;
|
||
--token-string: #ce9178;
|
||
--token-number: #b5cea8;
|
||
--token-variable: #9cdcfe;
|
||
--token-parameter: #9cdcfe;
|
||
--token-operator: #d4d4d4;
|
||
--token-punctuation: #d4d4d4;
|
||
--token-class-name: #4ec9b0;
|
||
position: relative;
|
||
width: 1920px;
|
||
height: 1080px;
|
||
overflow: hidden;
|
||
background:
|
||
linear-gradient(180deg, rgba(0, 0, 0, 0.16), rgba(0, 0, 0, 0.32)),
|
||
url("../assets/background.jpeg") center / cover no-repeat;
|
||
color: var(--editor-fg);
|
||
}
|
||
|
||
.scene-content {
|
||
position: relative;
|
||
z-index: 1;
|
||
width: 100%;
|
||
height: 100%;
|
||
padding: 54px 70px 92px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 16px;
|
||
perspective: 2200px;
|
||
perspective-origin: 56% 52%;
|
||
}
|
||
|
||
.header {
|
||
display: flex;
|
||
align-items: end;
|
||
justify-content: space-between;
|
||
min-height: 66px;
|
||
text-shadow:
|
||
0 2px 12px rgba(0, 0, 0, 0.42),
|
||
0 14px 34px rgba(0, 0, 0, 0.32);
|
||
}
|
||
|
||
.kicker {
|
||
margin: 0 0 7px;
|
||
color: var(--gutter-fg);
|
||
font-size: 15px;
|
||
font-weight: 650;
|
||
text-transform: uppercase;
|
||
text-shadow:
|
||
0 2px 8px rgba(0, 0, 0, 0.48),
|
||
0 10px 26px rgba(0, 0, 0, 0.36);
|
||
}
|
||
|
||
.title {
|
||
margin: 0;
|
||
color: var(--editor-fg);
|
||
font-size: 44px;
|
||
line-height: 1;
|
||
font-weight: 760;
|
||
}
|
||
|
||
.source-note {
|
||
width: 510px;
|
||
color: var(--gutter-fg);
|
||
font-size: 16px;
|
||
line-height: 1.35;
|
||
text-align: right;
|
||
text-shadow:
|
||
0 2px 10px rgba(0, 0, 0, 0.46),
|
||
0 12px 30px rgba(0, 0, 0, 0.34);
|
||
}
|
||
|
||
.workbench {
|
||
height: 824px;
|
||
display: grid;
|
||
grid-template-columns: 54px 290px 1fr;
|
||
grid-template-rows: 36px 1fr 26px;
|
||
overflow: hidden;
|
||
border: 1px solid var(--sidebar-border);
|
||
border-radius: 8px;
|
||
background: var(--editor-bg);
|
||
box-shadow: 0 34px 90px rgba(0, 0, 0, 0.42);
|
||
transform: translateZ(0);
|
||
transform-origin: 82% 50%;
|
||
transform-style: preserve-3d;
|
||
will-change: transform;
|
||
}
|
||
|
||
.titlebar {
|
||
grid-column: 1 / -1;
|
||
display: grid;
|
||
grid-template-columns: 120px 1fr 210px;
|
||
align-items: center;
|
||
background: var(--title-bg);
|
||
color: var(--title-fg);
|
||
border-bottom: 1px solid var(--tab-border);
|
||
font-size: 12px;
|
||
}
|
||
|
||
.traffic {
|
||
display: flex;
|
||
gap: 8px;
|
||
padding-left: 18px;
|
||
}
|
||
|
||
.traffic span {
|
||
width: 12px;
|
||
height: 12px;
|
||
border-radius: 999px;
|
||
}
|
||
|
||
.traffic span:nth-child(1) {
|
||
background: #ff5f57;
|
||
}
|
||
.traffic span:nth-child(2) {
|
||
background: #ffbd2e;
|
||
}
|
||
.traffic span:nth-child(3) {
|
||
background: #28c840;
|
||
}
|
||
|
||
.window-title {
|
||
justify-self: center;
|
||
opacity: 0.84;
|
||
}
|
||
|
||
.command-center {
|
||
justify-self: end;
|
||
width: 176px;
|
||
height: 22px;
|
||
margin-right: 16px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border: 1px solid color-mix(in srgb, var(--title-fg), transparent 78%);
|
||
border-radius: 5px;
|
||
color: color-mix(in srgb, var(--title-fg), transparent 18%);
|
||
}
|
||
|
||
.activity {
|
||
grid-row: 2 / 3;
|
||
background: var(--activity-bg);
|
||
border-right: 1px solid var(--sidebar-border);
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
padding: 10px 0;
|
||
gap: 18px;
|
||
}
|
||
|
||
.activity-icon {
|
||
width: 28px;
|
||
height: 28px;
|
||
color: var(--activity-muted);
|
||
}
|
||
|
||
.activity-icon.active {
|
||
color: var(--activity-fg);
|
||
border-left: 2px solid var(--activity-active);
|
||
padding-left: 4px;
|
||
}
|
||
|
||
.sidebar {
|
||
grid-row: 2 / 3;
|
||
background: var(--sidebar-bg);
|
||
color: var(--sidebar-fg);
|
||
border-right: 1px solid var(--sidebar-border);
|
||
display: flex;
|
||
flex-direction: column;
|
||
min-width: 0;
|
||
}
|
||
|
||
.sidebar-title {
|
||
height: 38px;
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 0 20px;
|
||
color: var(--sidebar-fg);
|
||
font-size: 11px;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.section-title {
|
||
height: 24px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: 0 14px;
|
||
background: color-mix(in srgb, var(--sidebar-bg), var(--sidebar-fg) 5%);
|
||
border-top: 1px solid var(--sidebar-border);
|
||
border-bottom: 1px solid var(--sidebar-border);
|
||
color: var(--sidebar-fg);
|
||
font-size: 11px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.tree {
|
||
padding: 8px 0;
|
||
font-size: 13px;
|
||
line-height: 24px;
|
||
}
|
||
|
||
.tree-row {
|
||
height: 24px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 7px;
|
||
padding: 0 10px 0 18px;
|
||
color: color-mix(in srgb, var(--sidebar-fg), transparent 8%);
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.tree-row.child {
|
||
padding-left: 34px;
|
||
}
|
||
|
||
.tree-row.selected {
|
||
background: color-mix(in srgb, var(--sidebar-fg), transparent 88%);
|
||
color: var(--sidebar-fg);
|
||
}
|
||
|
||
.editor-area {
|
||
grid-row: 2 / 3;
|
||
display: grid;
|
||
grid-template-rows: 36px 30px 1fr 138px;
|
||
min-width: 0;
|
||
background: var(--editor-bg);
|
||
}
|
||
|
||
.tabs {
|
||
display: flex;
|
||
background: var(--tab-bg);
|
||
border-bottom: 1px solid var(--tab-border);
|
||
}
|
||
|
||
.tab {
|
||
width: 205px;
|
||
height: 36px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
padding: 0 13px;
|
||
border-right: 1px solid var(--tab-border);
|
||
background: var(--tab-active-bg);
|
||
color: var(--tab-active-fg);
|
||
border-top: 2px solid var(--activity-active);
|
||
font-size: 13px;
|
||
}
|
||
|
||
.tab.inactive {
|
||
background: var(--tab-bg);
|
||
color: var(--tab-inactive-fg);
|
||
border-top-color: transparent;
|
||
}
|
||
|
||
.breadcrumbs {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 7px;
|
||
padding: 0 18px;
|
||
color: var(--gutter-fg);
|
||
border-bottom: 1px solid color-mix(in srgb, var(--tab-border), transparent 20%);
|
||
font-size: 12px;
|
||
}
|
||
|
||
.editor {
|
||
position: relative;
|
||
overflow: hidden;
|
||
background: var(--editor-bg);
|
||
color: var(--editor-fg);
|
||
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
||
font-size: 18px;
|
||
line-height: 1.52;
|
||
}
|
||
|
||
.active-line {
|
||
position: absolute;
|
||
left: 0;
|
||
right: 0;
|
||
top: 0;
|
||
height: 28px;
|
||
background: var(--editor-line);
|
||
will-change: transform;
|
||
}
|
||
|
||
.code {
|
||
position: relative;
|
||
padding: 20px 36px 18px 0;
|
||
}
|
||
|
||
.line {
|
||
height: 28px;
|
||
display: grid;
|
||
grid-template-columns: 72px 1fr;
|
||
align-items: center;
|
||
}
|
||
|
||
.line-number {
|
||
padding-right: 18px;
|
||
color: var(--gutter-fg);
|
||
text-align: right;
|
||
user-select: none;
|
||
}
|
||
|
||
.line.is-active .line-number {
|
||
color: var(--gutter-active-fg);
|
||
}
|
||
|
||
.line-code {
|
||
white-space: pre;
|
||
}
|
||
|
||
.char {
|
||
opacity: 0;
|
||
}
|
||
|
||
.tok-comment {
|
||
color: var(--token-comment);
|
||
}
|
||
.tok-keyword {
|
||
color: var(--token-keyword);
|
||
}
|
||
.tok-function {
|
||
color: var(--token-function);
|
||
}
|
||
.tok-string {
|
||
color: var(--token-string);
|
||
}
|
||
.tok-number {
|
||
color: var(--token-number);
|
||
}
|
||
.tok-variable {
|
||
color: var(--token-variable);
|
||
}
|
||
.tok-parameter {
|
||
color: var(--token-parameter);
|
||
}
|
||
.tok-operator {
|
||
color: var(--token-operator);
|
||
}
|
||
.tok-punctuation {
|
||
color: var(--token-punctuation);
|
||
}
|
||
.tok-class-name {
|
||
color: var(--token-class-name);
|
||
}
|
||
|
||
.caret {
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0;
|
||
z-index: 3;
|
||
display: block;
|
||
width: 2px;
|
||
height: 22px;
|
||
background: var(--editor-fg);
|
||
pointer-events: none;
|
||
will-change: transform, opacity;
|
||
}
|
||
|
||
.terminal {
|
||
display: grid;
|
||
grid-template-rows: 32px 1fr;
|
||
background: var(--panel-bg);
|
||
border-top: 1px solid var(--panel-border);
|
||
color: var(--editor-fg);
|
||
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.panel-tabs {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 22px;
|
||
padding: 0 18px;
|
||
border-bottom: 1px solid var(--panel-border);
|
||
color: var(--gutter-fg);
|
||
font-family:
|
||
Inter,
|
||
-apple-system,
|
||
BlinkMacSystemFont,
|
||
"Segoe UI",
|
||
sans-serif;
|
||
font-size: 12px;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.panel-tabs .active {
|
||
color: var(--editor-fg);
|
||
border-bottom: 1px solid var(--activity-active);
|
||
height: 32px;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.terminal-body {
|
||
padding: 12px 20px;
|
||
color: var(--editor-fg);
|
||
line-height: 1.8;
|
||
}
|
||
|
||
.prompt {
|
||
color: var(--token-function);
|
||
}
|
||
|
||
.statusbar {
|
||
grid-column: 1 / -1;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
background: var(--status-bg);
|
||
color: var(--status-fg);
|
||
border-top: 1px solid var(--status-border);
|
||
font-size: 12px;
|
||
}
|
||
|
||
.status-left,
|
||
.status-right {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 18px;
|
||
padding: 0 12px;
|
||
}
|
||
|
||
.remote {
|
||
align-self: stretch;
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 0 12px;
|
||
margin-left: -12px;
|
||
background: var(--status-remote-bg, var(--activity-active));
|
||
color: var(--status-remote-fg, #ffffff);
|
||
}
|
||
|
||
svg {
|
||
display: block;
|
||
}
|
||
</style>
|
||
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
|
||
<script>
|
||
(() => {
|
||
const codeLines = [
|
||
[{ text: "# A small functional toolkit", token: "comment" }],
|
||
[
|
||
{ text: "def", token: "keyword" },
|
||
{ text: " ", token: "plain" },
|
||
{ text: "pluck_deep", token: "function" },
|
||
{ text: "(", token: "punctuation" },
|
||
{ text: "key", token: "parameter" },
|
||
{ text: "):", token: "punctuation" },
|
||
],
|
||
[
|
||
{ text: " ", token: "plain" },
|
||
{ text: "return", token: "keyword" },
|
||
{ text: " ", token: "plain" },
|
||
{ text: "lambda", token: "keyword" },
|
||
{ text: " ", token: "plain" },
|
||
{ text: "obj", token: "parameter" },
|
||
{ text: ": ", token: "punctuation" },
|
||
{ text: "reduce", token: "function" },
|
||
{ text: "(", token: "punctuation" },
|
||
{ text: "lambda", token: "keyword" },
|
||
{ text: " ", token: "plain" },
|
||
{ text: "acc", token: "parameter" },
|
||
{ text: ", ", token: "punctuation" },
|
||
{ text: "k", token: "parameter" },
|
||
{ text: ": ", token: "punctuation" },
|
||
{ text: "acc", token: "variable" },
|
||
{ text: "[", token: "punctuation" },
|
||
{ text: "k", token: "variable" },
|
||
{ text: "]", token: "punctuation" },
|
||
{ text: ", ", token: "punctuation" },
|
||
{ text: "key", token: "variable" },
|
||
{ text: ".split", token: "function" },
|
||
{ text: "(", token: "punctuation" },
|
||
{ text: "'.'", token: "string" },
|
||
{ text: "), ", token: "punctuation" },
|
||
{ text: "obj", token: "variable" },
|
||
{ text: ")", token: "punctuation" },
|
||
],
|
||
[],
|
||
[
|
||
{ text: "def", token: "keyword" },
|
||
{ text: " ", token: "plain" },
|
||
{ text: "compose", token: "function" },
|
||
{ text: "(", token: "punctuation" },
|
||
{ text: "*", token: "operator" },
|
||
{ text: "fns", token: "parameter" },
|
||
{ text: "):", token: "punctuation" },
|
||
],
|
||
[
|
||
{ text: " ", token: "plain" },
|
||
{ text: "return", token: "keyword" },
|
||
{ text: " ", token: "plain" },
|
||
{ text: "lambda", token: "keyword" },
|
||
{ text: " ", token: "plain" },
|
||
{ text: "res", token: "parameter" },
|
||
{ text: ": ", token: "punctuation" },
|
||
{ text: "reduce", token: "function" },
|
||
{ text: "(", token: "punctuation" },
|
||
{ text: "lambda", token: "keyword" },
|
||
{ text: " ", token: "plain" },
|
||
{ text: "acc", token: "parameter" },
|
||
{ text: ", ", token: "punctuation" },
|
||
{ text: "fn", token: "parameter" },
|
||
{ text: ": ", token: "punctuation" },
|
||
{ text: "fn", token: "function" },
|
||
{ text: "(", token: "punctuation" },
|
||
{ text: "acc", token: "variable" },
|
||
{ text: "), ", token: "punctuation" },
|
||
{ text: "fns", token: "variable" },
|
||
{ text: ", ", token: "punctuation" },
|
||
{ text: "res", token: "variable" },
|
||
{ text: ")", token: "punctuation" },
|
||
],
|
||
[],
|
||
[
|
||
{ text: "def", token: "keyword" },
|
||
{ text: " ", token: "plain" },
|
||
{ text: "unfold", token: "function" },
|
||
{ text: "(", token: "punctuation" },
|
||
{ text: "f", token: "parameter" },
|
||
{ text: ", ", token: "punctuation" },
|
||
{ text: "seed", token: "parameter" },
|
||
{ text: "):", token: "punctuation" },
|
||
],
|
||
[
|
||
{ text: " ", token: "plain" },
|
||
{ text: '"""Build a list by repeatedly applying f to a seed."""', token: "string" },
|
||
],
|
||
[
|
||
{ text: " acc", token: "variable" },
|
||
{ text: " = ", token: "operator" },
|
||
{ text: "[]", token: "punctuation" },
|
||
],
|
||
[
|
||
{ text: " while", token: "keyword" },
|
||
{ text: " ", token: "plain" },
|
||
{ text: "True", token: "className" },
|
||
{ text: ":", token: "punctuation" },
|
||
],
|
||
[
|
||
{ text: " result", token: "variable" },
|
||
{ text: " = ", token: "operator" },
|
||
{ text: "f", token: "function" },
|
||
{ text: "(", token: "punctuation" },
|
||
{ text: "seed", token: "variable" },
|
||
{ text: ")", token: "punctuation" },
|
||
],
|
||
[
|
||
{ text: " if", token: "keyword" },
|
||
{ text: " ", token: "plain" },
|
||
{ text: "result", token: "variable" },
|
||
{ text: " is ", token: "keyword" },
|
||
{ text: "None", token: "className" },
|
||
{ text: ":", token: "punctuation" },
|
||
],
|
||
[
|
||
{ text: " return", token: "keyword" },
|
||
{ text: " ", token: "plain" },
|
||
{ text: "acc", token: "variable" },
|
||
],
|
||
[
|
||
{ text: " acc", token: "variable" },
|
||
{ text: ".append", token: "function" },
|
||
{ text: "(", token: "punctuation" },
|
||
{ text: "result", token: "variable" },
|
||
{ text: "[", token: "punctuation" },
|
||
{ text: "0", token: "number" },
|
||
{ text: "])", token: "punctuation" },
|
||
],
|
||
[
|
||
{ text: " seed", token: "variable" },
|
||
{ text: " = ", token: "operator" },
|
||
{ text: "result", token: "variable" },
|
||
{ text: "[", token: "punctuation" },
|
||
{ text: "1", token: "number" },
|
||
{ text: "]", token: "punctuation" },
|
||
],
|
||
[],
|
||
];
|
||
|
||
const fallback = {
|
||
"activityBar.background": "#181818",
|
||
"activityBar.foreground": "#d7d7d7",
|
||
"activityBar.inactiveForeground": "#868686",
|
||
"activityBar.activeBorder": "#0078d4",
|
||
"sideBar.background": "#181818",
|
||
"sideBar.foreground": "#cccccc",
|
||
"sideBar.border": "#2b2b2b",
|
||
"tab.activeBackground": "#1f1f1f",
|
||
"tab.activeForeground": "#ffffff",
|
||
"tab.inactiveBackground": "#181818",
|
||
"tab.inactiveForeground": "#9d9d9d",
|
||
"tab.border": "#2b2b2b",
|
||
"editor.background": "#1f1f1f",
|
||
"editor.foreground": "#cccccc",
|
||
"editor.lineHighlightBackground": "#ffffff0a",
|
||
"editorLineNumber.foreground": "#6e7681",
|
||
"editorLineNumber.activeForeground": "#cccccc",
|
||
"panel.background": "#181818",
|
||
"panel.border": "#2b2b2b",
|
||
"statusBar.background": "#181818",
|
||
"statusBar.foreground": "#cccccc",
|
||
"statusBar.border": "#2b2b2b",
|
||
"titleBar.activeBackground": "#181818",
|
||
"titleBar.activeForeground": "#cccccc",
|
||
};
|
||
|
||
function color(theme, key) {
|
||
return theme.colors[key] || fallback[key] || theme.colors.foreground || "#cccccc";
|
||
}
|
||
|
||
function solarizedGrey(theme) {
|
||
return (
|
||
theme.colors["tab.inactiveForeground"] ||
|
||
theme.colors["editor.foreground"] ||
|
||
"#586E75"
|
||
);
|
||
}
|
||
|
||
function setVar(root, name, value) {
|
||
root.style.setProperty(name, value);
|
||
}
|
||
|
||
function applyTheme(root, theme) {
|
||
const solarizedUiGrey = theme.id === "solarized-light" ? solarizedGrey(theme) : null;
|
||
setVar(root, "--activity-bg", color(theme, "activityBar.background"));
|
||
setVar(
|
||
root,
|
||
"--activity-fg",
|
||
solarizedUiGrey || color(theme, "activityBar.foreground"),
|
||
);
|
||
setVar(
|
||
root,
|
||
"--activity-muted",
|
||
solarizedUiGrey || color(theme, "activityBar.inactiveForeground"),
|
||
);
|
||
setVar(root, "--activity-active", color(theme, "activityBar.activeBorder"));
|
||
setVar(root, "--sidebar-bg", color(theme, "sideBar.background"));
|
||
setVar(root, "--sidebar-fg", solarizedUiGrey || color(theme, "sideBar.foreground"));
|
||
setVar(root, "--sidebar-border", color(theme, "sideBar.border"));
|
||
setVar(root, "--tab-bg", color(theme, "tab.inactiveBackground"));
|
||
setVar(root, "--tab-active-bg", color(theme, "tab.activeBackground"));
|
||
setVar(
|
||
root,
|
||
"--tab-active-fg",
|
||
solarizedUiGrey || color(theme, "tab.activeForeground"),
|
||
);
|
||
setVar(
|
||
root,
|
||
"--tab-inactive-fg",
|
||
solarizedUiGrey || color(theme, "tab.inactiveForeground"),
|
||
);
|
||
setVar(root, "--tab-border", color(theme, "tab.border"));
|
||
setVar(root, "--editor-bg", color(theme, "editor.background"));
|
||
setVar(root, "--editor-fg", color(theme, "editor.foreground"));
|
||
setVar(root, "--editor-line", color(theme, "editor.lineHighlightBackground"));
|
||
setVar(root, "--gutter-fg", color(theme, "editorLineNumber.foreground"));
|
||
setVar(root, "--gutter-active-fg", color(theme, "editorLineNumber.activeForeground"));
|
||
setVar(root, "--panel-bg", color(theme, "panel.background"));
|
||
setVar(root, "--panel-border", color(theme, "panel.border"));
|
||
setVar(root, "--status-bg", color(theme, "statusBar.background"));
|
||
setVar(root, "--status-fg", color(theme, "statusBar.foreground"));
|
||
setVar(root, "--status-border", color(theme, "statusBar.border"));
|
||
setVar(root, "--status-remote-bg", color(theme, "statusBarItem.remoteBackground"));
|
||
setVar(
|
||
root,
|
||
"--status-remote-fg",
|
||
solarizedUiGrey || color(theme, "statusBarItem.remoteForeground"),
|
||
);
|
||
setVar(root, "--title-bg", color(theme, "titleBar.activeBackground"));
|
||
setVar(
|
||
root,
|
||
"--title-fg",
|
||
solarizedUiGrey || color(theme, "titleBar.activeForeground"),
|
||
);
|
||
setVar(root, "--token-comment", theme.tokens.comment);
|
||
setVar(root, "--token-keyword", theme.tokens.keyword);
|
||
setVar(root, "--token-function", theme.tokens.function);
|
||
setVar(root, "--token-string", theme.tokens.string);
|
||
setVar(root, "--token-number", theme.tokens.number);
|
||
setVar(root, "--token-variable", theme.tokens.variable);
|
||
setVar(root, "--token-parameter", theme.tokens.parameter);
|
||
setVar(root, "--token-operator", theme.tokens.operator);
|
||
setVar(root, "--token-punctuation", theme.tokens.punctuation);
|
||
setVar(root, "--token-class-name", theme.tokens.className);
|
||
}
|
||
|
||
function renderCode(root) {
|
||
const code = root.querySelector(".code");
|
||
codeLines.forEach((segments, index) => {
|
||
const line = document.createElement("div");
|
||
line.className = "line";
|
||
line.dataset.lineIndex = String(index);
|
||
|
||
const lineNumber = document.createElement("span");
|
||
lineNumber.className = "line-number";
|
||
lineNumber.textContent = String(index + 1);
|
||
line.appendChild(lineNumber);
|
||
|
||
const lineCode = document.createElement("span");
|
||
lineCode.className = "line-code";
|
||
segments.forEach((segment) => {
|
||
[...segment.text].forEach((char) => {
|
||
const span = document.createElement("span");
|
||
span.className =
|
||
segment.token === "plain"
|
||
? "char"
|
||
: "char tok-" +
|
||
segment.token.replace(/[A-Z]/g, (match) => "-" + match.toLowerCase());
|
||
span.dataset.lineIndex = String(index);
|
||
span.textContent = char;
|
||
lineCode.appendChild(span);
|
||
});
|
||
});
|
||
line.appendChild(lineCode);
|
||
code.appendChild(line);
|
||
});
|
||
|
||
const caret = document.createElement("span");
|
||
caret.className = "caret";
|
||
root.querySelector(".editor").appendChild(caret);
|
||
}
|
||
|
||
function caretPointForElement(editor, el) {
|
||
const editorBox = editor.getBoundingClientRect();
|
||
const charBox = el.getBoundingClientRect();
|
||
return {
|
||
x: charBox.right - editorBox.left + 2,
|
||
y: charBox.top - editorBox.top + 3,
|
||
};
|
||
}
|
||
|
||
function caretPointForLineStart(editor, line) {
|
||
const editorBox = editor.getBoundingClientRect();
|
||
const lineBox = line.getBoundingClientRect();
|
||
const codeBox = line.querySelector(".line-code").getBoundingClientRect();
|
||
return {
|
||
x: codeBox.left - editorBox.left,
|
||
y: lineBox.top - editorBox.top + 3,
|
||
};
|
||
}
|
||
|
||
function lineHighlightY(editor, line) {
|
||
const editorBox = editor.getBoundingClientRect();
|
||
const lineBox = line.getBoundingClientRect();
|
||
return lineBox.top - editorBox.top;
|
||
}
|
||
|
||
function buildTimeline(root, compositionId) {
|
||
const tl = gsap.timeline({ paused: true });
|
||
const editor = root.querySelector(".editor");
|
||
const caret = root.querySelector(".caret");
|
||
const activeLine = root.querySelector(".active-line");
|
||
const lineEls = gsap.utils.toArray(root.querySelectorAll(".line"));
|
||
const lineStartTimes = [];
|
||
const charSchedule = [];
|
||
let cursorTime = 0.95;
|
||
|
||
lineEls.forEach((line, lineIndex) => {
|
||
const lineChars = gsap.utils.toArray(line.querySelectorAll(".char"));
|
||
lineStartTimes[lineIndex] = cursorTime;
|
||
lineChars.forEach((char, charIndex) => {
|
||
charSchedule.push({ char, time: cursorTime + charIndex * 0.012 });
|
||
});
|
||
cursorTime += Math.max(lineChars.length * 0.012, 0.08) + 0.045;
|
||
});
|
||
|
||
gsap.set(activeLine, { y: lineHighlightY(editor, lineEls[0]) });
|
||
gsap.set(caret, caretPointForLineStart(editor, lineEls[0]));
|
||
|
||
tl.from(
|
||
root.querySelector(".header"),
|
||
{ y: 24, opacity: 0, duration: 0.45, ease: "power3.out" },
|
||
0,
|
||
);
|
||
tl.from(
|
||
root.querySelector(".workbench"),
|
||
{ y: 42, opacity: 0, scale: 0.986, duration: 0.58, ease: "power3.out" },
|
||
0.1,
|
||
);
|
||
tl.from(activeLine, { opacity: 0, duration: 0.22, ease: "power2.out" }, 0.74);
|
||
lineStartTimes.forEach((time, lineIndex) => {
|
||
const line = lineEls[lineIndex];
|
||
tl.set(activeLine, { y: lineHighlightY(editor, line) }, time);
|
||
tl.set(caret, caretPointForLineStart(editor, line), time);
|
||
tl.call(
|
||
() => {
|
||
lineEls.forEach((item) => item.classList.toggle("is-active", item === line));
|
||
},
|
||
[],
|
||
time,
|
||
);
|
||
});
|
||
charSchedule.forEach(({ char, time }) => {
|
||
tl.set(char, { opacity: 1 }, time);
|
||
tl.set(caret, caretPointForElement(editor, char), time + 0.002);
|
||
});
|
||
tl.to(
|
||
root.querySelector(".caret"),
|
||
{ opacity: 0, duration: 0.34, repeat: 25, yoyo: true, ease: "steps(1)" },
|
||
0.95,
|
||
);
|
||
tl.from(
|
||
root.querySelector(".terminal"),
|
||
{ y: 140, opacity: 0, duration: 0.56, ease: "power3.out" },
|
||
7.55,
|
||
);
|
||
tl.from(
|
||
root.querySelector(".terminal-body").children,
|
||
{ opacity: 0, y: 8, duration: 0.24, stagger: 0.16, ease: "power2.out" },
|
||
8.05,
|
||
);
|
||
tl.to(
|
||
root.querySelector(".workbench"),
|
||
{ rotateY: -10.5, z: 74, duration: 0.72, ease: "power2.inOut" },
|
||
9.35,
|
||
);
|
||
tl.to(
|
||
root.querySelector(".workbench"),
|
||
{ rotateY: 0, z: 0, duration: 0.62, ease: "power2.inOut" },
|
||
10.08,
|
||
);
|
||
|
||
window.__timelines = window.__timelines || {};
|
||
window.__timelines[compositionId] = tl;
|
||
|
||
const previewTime = new URLSearchParams(window.location.search).get("t");
|
||
if (previewTime !== null) {
|
||
tl.time(Number(previewTime));
|
||
}
|
||
}
|
||
|
||
window.createVSCodeThemeComposition = (compositionId, themeOrId) => {
|
||
const root =
|
||
document.querySelector(
|
||
'[data-composition-id="' + compositionId + '"] .vscode-theme-scene',
|
||
) ||
|
||
document.querySelector(
|
||
'.vscode-theme-scene[data-composition-id="' + compositionId + '"]',
|
||
) ||
|
||
document.querySelector('[data-composition-id="' + compositionId + '"]');
|
||
const theme =
|
||
typeof themeOrId === "string"
|
||
? window.VSCODE_THEME_REGISTRY.find((item) => item.id === themeOrId)
|
||
: themeOrId;
|
||
if (!root || !theme) return;
|
||
root.querySelector(".theme-label").textContent = theme.label;
|
||
root.querySelector(".theme-source").textContent = theme.sourceFile;
|
||
applyTheme(root, theme);
|
||
renderCode(root);
|
||
buildTimeline(root, compositionId);
|
||
};
|
||
})();
|
||
</script>
|
||
<script>
|
||
window.__timelines = window.__timelines || {};
|
||
window.__timelines["vscode-monokai"] =
|
||
window.__timelines["vscode-monokai"] || gsap.timeline({ paused: true });
|
||
window.createVSCodeThemeComposition("vscode-monokai", {
|
||
id: "monokai",
|
||
label: "Monokai",
|
||
sourceFile: "monokai-color-theme.json",
|
||
uiTheme: "vs-dark",
|
||
colors: {
|
||
"activityBar.background": "#272822",
|
||
"activityBar.foreground": "#f8f8f2",
|
||
"editor.background": "#272822",
|
||
"editor.foreground": "#f8f8f2",
|
||
"editor.lineHighlightBackground": "#3e3d32",
|
||
"editor.selectionBackground": "#878b9180",
|
||
"editorGroup.border": "#34352f",
|
||
"editorGroupHeader.tabsBackground": "#1e1f1c",
|
||
"editorLineNumber.activeForeground": "#c2c2bf",
|
||
"editorLineNumber.foreground": "#90908a",
|
||
"panel.border": "#414339",
|
||
"sideBar.background": "#1e1f1c",
|
||
"sideBarSectionHeader.background": "#272822",
|
||
"statusBar.background": "#414339",
|
||
"statusBarItem.remoteBackground": "#AC6218",
|
||
"tab.border": "#1e1f1c",
|
||
"tab.inactiveBackground": "#34352f",
|
||
"tab.inactiveForeground": "#ccccc7",
|
||
"titleBar.activeBackground": "#1e1f1c",
|
||
},
|
||
tokens: {
|
||
comment: "#88846f",
|
||
keyword: "#66D9EF",
|
||
function: "#66D9EF",
|
||
string: "#AE81FF",
|
||
number: "#AE81FFA0",
|
||
variable: "#FD971F",
|
||
parameter: "#FD971F",
|
||
operator: "#F92672",
|
||
punctuation: "#A6E22E",
|
||
className: "#66D9EF",
|
||
},
|
||
});
|
||
</script>
|
||
</div>
|
||
</template>
|
||
</body>
|
||
</html>
|
||
```
|
||
|
||
</Accordion>
|
||
|
||
## Usage
|
||
|
||
After installing, add the block to your host composition:
|
||
|
||
```html
|
||
<div
|
||
data-composition-id="code-snippet-monokai"
|
||
data-composition-src="compositions/code-snippet-monokai.html"
|
||
data-start="0"
|
||
data-duration="11"
|
||
data-track-index="1"
|
||
data-width="1920"
|
||
data-height="1080"
|
||
></div>
|
||
```
|
||
|
||
## Features
|
||
|
||
- Full VS Code workbench recreation — activity bar, sidebar, explorer tree, editor tabs, breadcrumbs, terminal panel, status bar
|
||
- Per-character typing animation with cursor tracking and active line highlight
|
||
- Colors sourced from official `microsoft/vscode` built-in theme JSON
|
||
- 3D perspective tilt at the end of the typing sequence
|
||
- Terminal panel with mock test output
|
||
|
||
{/* hf:generated-footer */}
|
||
|
||
Tagged `code` `developer` `showcase` `vscode`.
|
||
|
||
## Related topics
|
||
|
||
- [Browse the complete Catalog](/catalog)
|
||
- [Add assets and Catalog items in Studio](/studio/assets-and-blocks)
|
||
- [Build a richer composition](/go-further)
|