Update the website with an evolved roadmap and new product screenshots/videos

This commit is contained in:
Keavon Chambers 2025-11-10 00:06:10 -08:00
parent 2f45cf7ff2
commit f5ef1a94fe
10 changed files with 410 additions and 166 deletions

File diff suppressed because one or more lines are too long

View File

@ -25,7 +25,7 @@ meta_description = "Open source free software. A vector graphics creativity suit
<h1 class="balance-text">Your <span>procedural</span> toolbox for 2D content creation</h1>
<p class="balance-text">Graphite is a free, open source vector and raster graphics editor, available now in alpha. Get creative with a fully nondestructive editing workflow that combines layer-based compositing with node-based generative design.</p>
<p class="balance-text">Graphite is a free, open source vector graphics editor and animation engine, available now in alpha. Get creative with a fully nondestructive editing workflow that combines layer-based compositing with node-based generative design.</p>
</div>
</section>
@ -85,15 +85,15 @@ meta_description = "Open source free software. A vector graphics creativity suit
<section id="screenshots" class="carousel window-size-1" data-carousel data-carousel-jostle-hint>
<div class="carousel-slide" data-carousel-slide>
<img src="https://static.graphite.rs/content/index/gui-mockup-nodes__8.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="" style="transform: translateX(-100%)" data-carousel-image />
<img src="https://static.graphite.rs/content/index/gui-demo-creative-coding-poster.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="" style="transform: translateX(-100%)" data-carousel-image />
<!-- Above is a copy of the last -->
<img onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="" style="transform: translateX(-100%)" data-carousel-image width="1920" height="1080" loading="lazy" src="https://static.graphite.rs/content/index/gui-demo-painted-dreams__3.avif" />
<img onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="" style="transform: translateX(-100%)" data-carousel-image width="1920" height="1080" loading="lazy" src="https://static.graphite.rs/content/index/magazine-page-layout__2.avif" />
<img onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="" style="transform: translateX(-100%)" data-carousel-image width="1920" height="1080" loading="lazy" src="https://static.graphite.rs/content/index/gui-demo-node-graph-isometric-fountain.avif" />
<img onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="" style="transform: translateX(-100%)" data-carousel-image width="1920" height="1080" loading="lazy" src="https://static.graphite.rs/content/index/gui-demo-fractal__3.avif" />
<img onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="" style="transform: translateX(-100%)" data-carousel-image width="1920" height="1080" loading="lazy" src="https://static.graphite.rs/content/index/gui-mockup-nodes__8.avif" />
<img onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="" style="transform: translateX(-100%)" data-carousel-image width="1920" height="1080" loading="lazy" src="https://static.graphite.rs/content/index/gui-demo-painted-dreams__4.avif" />
<img onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="" style="transform: translateX(-100%)" data-carousel-image width="1920" height="1080" loading="lazy" src="https://static.graphite.rs/content/index/gui-demo-magazine-page-layout.avif" />
<video style="transform: translateX(-100%)" data-carousel-image width="1920" height="1080" loop muted disablepictureinpicture disableremoteplayback preload="none" poster="https://static.graphite.rs/content/index/gui-demo-animation-twirl-poster.avif"><source src="https://static.graphite.rs/content/index/gui-demo-animation-twirl.webm" type="video/webm" /><source src="https://static.graphite.rs/content/index/gui-demo-animation-twirl.mp4" type="video/mp4" /></video>
<video style="transform: translateX(-100%)" data-carousel-image width="1920" height="1080" loop muted disablepictureinpicture disableremoteplayback preload="none" poster="https://static.graphite.rs/content/index/gui-demo-creative-coding-poster.avif"><source src="https://static.graphite.rs/content/index/gui-demo-creative-coding.webm" type="video/webm" /><source src="https://static.graphite.rs/content/index/gui-demo-creative-coding.mp4" type="video/mp4" /></video>
<img onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="" style="transform: translateX(-100%)" data-carousel-image width="1920" height="1080" loading="lazy" src="https://static.graphite.rs/content/index/gui-demo-fractal__4.avif" />
<!-- Below is a copy of the first -->
<img src="https://static.graphite.rs/content/index/gui-demo-painted-dreams__3.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="" style="transform: translateX(-100%)" data-carousel-image />
<img src="https://static.graphite.rs/content/index/gui-demo-painted-dreams__4.png" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="" style="transform: translateX(-100%)" data-carousel-image />
</div>
<div class="carousel-slide torn left" data-carousel-slide-torn-left></div>
@ -139,14 +139,14 @@ meta_description = "Open source free software. A vector graphics creativity suit
Design for a magazine spread, a preview of the upcoming focus on desktop publishing
</p>
<p data-carousel-description>
<a href="https://editor.graphite.rs/#demo/isometric-fountain"><em>Isometric Fountain</em></a> — All layer stacks are represented, under the hood, by a nondestructive node graph
Procedurally generated animation demonstrating Graphite's approach to creative coding with nodes
</p>
<p data-carousel-description>
Procedurally generated animation demonstrating Graphite's approach to creative coding with nodes
</p>
<p data-carousel-description>
Mandelbrot fractal filled with a noise pattern, procedurally generated and infinitely scalable
</p>
<p data-carousel-description>
Coming soon: this user interface mockup shows the raster image editing features planned for 2025
</p>
</div>
@ -189,7 +189,7 @@ The latest major update is out now! See what the team has been cooking up recent
<div class="diptych sizzle-video">
<div class="block text">
Starting life as a vector editor, Graphite is evolving into a general-purpose, all-in-one graphics toolbox that is built more like a game engine than a conventional creative app. The editor's tools wrap its node graph core, providing user-friendly workflows for vector, raster, animation, and beyond.
Starting life as a vector editor, Graphite is evolving into a general-purpose, all-in-one graphics toolbox that is built more like a game engine than a conventional creative app. The editor's tools wrap its node graph core, exposing user-friendly workflows for vector, raster, animation, and beyond.
<a href="https://editor.graphite.rs" class="button arrow">Start creating</a>
@ -299,7 +299,7 @@ Presently, Graphite is a lightweight offline web app with features primarily ori
## Desktop-first and web-ready
Where's the download? The web app is [currently live](https://editor.graphite.rs) and desktop apps for Windows, Mac, and Linux will be available in Q4 2025.
Where's the download? The web app is [currently live](https://editor.graphite.rs) and desktop apps for Windows, Mac, and Linux will be released in December 2025.
Graphite is designed principally as a professional desktop application that is also accessible in a browser for quick access from anywhere. It's built for speed with (nearly) no JavaScript. And regardless of platform, it runs locally and privately on your own hardware— there is no server.

View File

@ -73,267 +73,327 @@ Marrying vector and raster under one roof enables both art forms to complement e
<div class="roadmap">
<div class="feature-icons">
<!-- Pre-Alpha -->
<div class="feature-icon complete heading" title="Began February 2021" data-year="2021">
<div class="feature-icon complete heading" data-year="2021">
<h3>— Pre-Alpha —</h3>
</div>
<div class="feature-icon complete" title="Development Complete">
<img class="atlas" style="--atlas-index: 1" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 1" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Editor systems; basic vector art tools</span>
</div>
<!-- Alpha 1 -->
<div class="feature-icon complete heading" title="Began February 2022" data-year="2022">
<div class="feature-icon complete heading" data-year="2022">
<h3>— Alpha 1 —</h3>
</div>
<div class="feature-icon complete" title="Development Complete">
<img class="atlas" style="--atlas-index: 2" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 2" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Better tools; node graph prototyping</span>
</div>
<!-- Alpha 2 -->
<div class="feature-icon complete heading" title="Began February 2023" data-year="2023">
<div class="feature-icon complete heading" data-year="2023">
<h3>— Alpha 2 —</h3>
</div>
<div class="feature-icon complete" title="Development Complete">
<img class="atlas" style="--atlas-index: 6" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 6" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Node graph integration in documents</span>
</div>
<!-- Alpha 3 -->
<div class="feature-icon complete heading" title="Began February 2024" data-year="2024">
<div class="feature-icon complete heading" data-year="2024">
<h3>— Alpha 3 —</h3>
</div>
<div class="feature-icon complete" title="Development Complete">
<img class="atlas" style="--atlas-index: 8" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 8" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Procedural vector editing and usability</span>
</div>
<!-- Alpha 4 -->
<div class="feature-icon ongoing heading" title="Began February 2025" data-year="2025">
<div class="feature-icon ongoing heading" data-year="2025">
<h3>— Alpha 4 —</h3>
</div>
<div class="feature-icon complete" title="Development Complete">
<img class="atlas" style="--atlas-index: 46" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 46" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Parametric animation</span>
</div>
<div class="feature-icon complete" title="Development Complete">
<img class="atlas" style="--atlas-index: 1" src="https://static.graphite.rs/icons/icon-atlas-features__2.png" alt="" />
<span>Instancer repeat nodes</span>
<img class="atlas" style="--atlas-index: 58" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Instancer nodes for looped generation</span>
</div>
<div class="feature-icon complete" title="Development Complete">
<img class="atlas" style="--atlas-index: 9; transform: scaleX(-1)" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>Table-based graphical data</span>
<img class="atlas" style="--atlas-index: 59" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Enhanced Pen, Path, and Shape tools</span>
</div>
<div class="feature-icon complete" title="Development Complete">
<img class="atlas" style="--atlas-index: 63" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Table-based graphical data format</span>
</div>
<div class="feature-icon complete" title="Development Complete">
<img class="atlas" style="--atlas-index: 67" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Data panel for graphical introspection</span>
</div>
<div class="feature-icon complete" title="Development Complete">
<img class="atlas" style="--atlas-index: 13" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Layer clipping masks</span>
</div>
<div class="feature-icon complete" title="Development Complete">
<img class="atlas" style="--atlas-index: 66" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>All-around performance optimizations</span>
</div>
<div class="feature-icon ongoing" title="Development Ongoing">
<img class="atlas" style="--atlas-index: 7" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 7" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Desktop app (Windows, Mac, Linux)</span>
</div>
<div class="feature-icon ongoing" title="Development Ongoing">
<img class="atlas" style="--atlas-index: 12" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 12" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>GPU-accelerated raster rendering</span>
</div>
<div class="feature-icon ongoing" title="Development Ongoing">
<img class="atlas" style="--atlas-index: 10" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>Evolution of the graphical data format</span>
<img class="atlas" style="--atlas-index: 10" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Expanded imaging model data format</span>
</div>
<div class="feature-icon ongoing" title="Development Ongoing">
<img class="atlas" style="--atlas-index: 48" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>Robust vector mesh editing/rendering</span>
</div>
<div class="feature-icon ongoing" title="Development Ongoing">
<img class="atlas" style="--atlas-index: 43; transform: rotate(90deg)" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 71" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Automatic image trace vectorization</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 41" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>Timeline panel for animation curves</span>
<img class="atlas" style="--atlas-index: 51" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Context menus throughout the editor</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 40" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 40" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Simplified main properties panel</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 9" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>Custom attributes for table data</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 57" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>Signed distance field rendering</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 53" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>Local fonts access</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 54" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>Local file browser for saving/loading</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 18" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 64" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Node version management</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 17" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 17" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Stable document format</span>
</div>
<!-- <div class="feature-icon ongoing" title="Development Ongoing">
<img class="atlas" style="--atlas-index: 0" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>Imaginate tool</span>
</div> -->
<!-- Beta -->
<div class="feature-icon heading">
<h3>— Beta —</h3>
<!-- Beta 1 -->
<div class="feature-icon heading" data-year="2026">
<h3>— Beta 1 —</h3>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 56" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>Variable color swatches</span>
<img class="atlas" style="--atlas-index: 53" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Local fonts access</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 52" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>Command palette and context menus</span>
<img class="atlas" style="--atlas-index: 54" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Saving over local files (web version)</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 28" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>Physical units of measure</span>
<img class="atlas" style="--atlas-index: 41" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Timeline panel for animation curves</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 5" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>Brush tool rewrite</span>
<img class="atlas" style="--atlas-index: 62" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Nested documents as custom nodes</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 43" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>Stylus and touch interaction</span>
<img class="atlas" style="--atlas-index: 56" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Variables and color swatches</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 11" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 9" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Custom attributes for table data</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 28" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Physical measurement units</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 65" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Text-on-path tool support</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 3" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Per-glyph text style controls</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 48" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Robust vector mesh editing/rendering</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 50" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Nondestructive shape builder tool</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 11" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Broader SVG support including filters</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 50" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>Shape builder tool</span>
<img class="atlas" style="--atlas-index: 45" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Parametric art standalone export</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 24" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 5" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>New and improved brush tool</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 43" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Stylus and touch interaction</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 70" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>MIDI and audio-reactive visualization</span>
</div>
<!-- Beta 2 -->
<div class="feature-icon heading" data-year="2027">
<h3>— Beta 2 —</h3>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 24" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Dockable and multi-window panels</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 16" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 52" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Command palette</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 68" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Onion skinning mode for animation</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 69" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Animatable deformation meshes/rigs</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 72" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Simulation domains</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 57" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Signed distance field rendering</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 14" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Procedural PBR material generation</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 16" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Code editor for custom nodes</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 18" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>Document history management</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 39" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>Offline edit resolution with CRDTs</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 22" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>History brush and clone stamp tools</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 34" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 34" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Asset libraries and node marketplace</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 27" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>Automation and batch processing</span>
<img class="atlas" style="--atlas-index: 27" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Automation/batch processing tools</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 45" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>Standalone parametric documents</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 19" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>Raw photo processing</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 21" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 21" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Select mode (marquee masking)</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 25" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 0" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Raster adjustments, filters, and effects</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 25" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Liquify and warp transforms</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 31" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>Advanced typography and typesetting</span>
<img class="atlas" style="--atlas-index: 19" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Raw photo processing</span>
</div>
<!-- LTS Releases -->
<div class="feature-icon heading">
<h3>— LTS Releases —</h3>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 32" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 31" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Advanced typesetting features</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 32" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>PDF, EPS, AI, DXF, PSD, and TIFF</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 55" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 55" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>CMYK, spot color, and ICC profiles</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 33" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 33" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>HDR and WCG color handling</span>
</div>
<!-- 1.0 Release -->
<div class="feature-icon heading">
<h3>— 1.0 Release —</h3>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 23" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>Internationalization and accessibility</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 4" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 4" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Outliner panel (node graph tree view)</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 49" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 18" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Document history management</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 39" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Offline edit resolution with CRDTs</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 22" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>History brush and clone stamp tools</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 23" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Internationalization and accessibility</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 49" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>AI nodes and tools (e.g. magic wand)</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 20" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 20" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Procedural styling of paint brushes</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 11" src="https://static.graphite.rs/icons/icon-atlas-features__2.png" alt="" />
<img class="atlas" style="--atlas-index: 60" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Infinite generative vector patterns</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 29" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>CAD style constraint relationships</span>
<img class="atlas" style="--atlas-index: 29" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Geometric constraint system solver</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 30" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>Responsive design constraint solvers</span>
<img class="atlas" style="--atlas-index: 30" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Responsive design layout solver</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 16" src="https://static.graphite.rs/icons/icon-atlas-features__2.png" alt="" />
<img class="atlas" style="--atlas-index: 61" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Authoring animated SVGs, Lottie, etc.</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 42" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 42" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Live video stream compositing</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 44" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>iPad app and keyboard-free controls</span>
<img class="atlas" style="--atlas-index: 44" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Tablet app and keyboard-free controls</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 37" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>Cloud document storage</span>
<img class="atlas" style="--atlas-index: 26" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Media collection manager/browser</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 38" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 37" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Cloud document storage/device sync</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 38" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Multiplayer collaborative editing</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 35" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 35" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Predictive graph rendering/caching</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 36" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>Distributed graph rendering</span>
<img class="atlas" style="--atlas-index: 36" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Multi-device distributed rendering</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 15" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<span>Cloud rendering accelerator service</span>
<img class="atlas" style="--atlas-index: 15" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span>Hosted rendering accelerator service</span>
</div>
<div class="feature-icon">
<img class="atlas" style="--atlas-index: 47" src="https://static.graphite.rs/icons/icon-atlas-roadmap__3.png" alt="" />
<img class="atlas" style="--atlas-index: 47" src="https://static.graphite.rs/icons/icon-atlas-roadmap__4.png" alt="" />
<span><em>…and that's all just the beginning…</em></span>
</div>
</div>
@ -341,3 +401,45 @@ Marrying vector and raster under one roof enables both art forms to complement e
</div>
</section>
<section>
<div class="block">
## Roadmap spotlight: keyframe animation
Coming early 2026, Graphite will expand its animation toolset beyond parametrically-driven motion to include traditional keyframe animation. The Timeline panel pictured below will let animators drive parameters using keyframes and curves through a traditional dopesheet interface.
Node parameters can be set to a constant value in the Properties panel, exposed to the graph for procedural animation, or exposed to a channel in the upcoming Timeline panel for hand-authored keyframing.
The panel will enable users to scrub through time with the playhead and choose between timing with discrete frames or continuous seconds. A dedicated curves editing mode (not pictured) will enable fine-tuning parameters with a labeled Y-axis, while the dopesheet allows individual channels to be expanded to view and edit the shape and smoothness of curves inline.
Work-in-progress design mockup:
<img src="https://static.graphite.rs/content/features/mockup-timeline-panel.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="" />
</div>
</section>
<section>
<div class="block">
## Roadmap spotlight: raster image editing
The vision since Graphite's inception has been to open up the traditional raster image editing workflow to the greater degree of flexibility found in node-based compositors, without one approach compromising the ergonomics of the other.
As with Graphite's current vector toolset, raster editing will interpret the user's interactive edits as modifications to the construction of layers in the underlying node graph rather than destructive alterations to layer pixel data (as in other image editors). By containing only a description of the user's editing operations without the data, documents will remain ultra tiny when source assets are linked externally.
Brushes, selection tools, masks, filters, effects, adjustment layers, and other tools used to manipulate raster layers will all be presented in a familiar form when Graphite's raster toolset nears maturity by the end of beta.
Work-in-progress design mockup:
<img src="https://static.graphite.rs/content/features/mockup-viewport.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="" />
<img src="https://static.graphite.rs/content/features/mockup-node-graph.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="" />
</div>
</section>

View File

@ -9,9 +9,7 @@ js = ["/js/youtube-embed.js"]
css = ["/component/youtube-embed.css"]
+++
Welcome to the Graphite user manual. Keep reading to to learn how the software can help bring your 2D creative ideas to life.
You may choose to read this sequentially and learn from the structured introduction and sample projects. Or you may jump to chapters of interest that also serve as quick reference.
Welcome to the Graphite user manual. Keep reading to learn how the software can help bring your 2D creative ideas to life.
## More chapters on the way

View File

@ -23,12 +23,6 @@ On the left, the [**menu bar**](./menu-bar) provides quick access to many editor
<!-- In the (forthcoming) macOS desktop release, the menu bar is absent from the editor window; its functions are instead located in macOS menu bar. -->
### Document title
In the center, the **document title** displays the name of the active document. That name is given a `*` suffix if the file has unsaved changes. For example, *Painting.graphite** would be unsaved but *Painting.graphite* would have no changes following its last save.
<p><img src="https://static.graphite.rs/content/learn/interface/document-title.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="The document title" /></p>
### Window buttons
On the right, the **window buttons** provide platform-specific controls for the application.
@ -37,7 +31,7 @@ On the right, the **window buttons** provide platform-specific controls for the
| | |
|-|-|
| **Web** | <p>A button to enter fullscreen mode is displayed.</p><p>The label "*Go fullscreen to access all hotkeys*" indicates that some shortcut keys like <kbd>Ctrl</kbd><kbd>N</kbd> (macOS: <kbd></kbd><kbd>N</kbd>) are reserved by the web browser and can only be used in fullscreen mode. (An alternative to going fullscreen: include <kbd>Alt</kbd> in the shortcut combinations for browser-reserved hotkeys.)</p><p><img src="https://static.graphite.rs/content/learn/interface/window-buttons-web.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Fullscreen button" /></p> |
| **Web** | <p>A button to enter fullscreen mode is displayed.</p><p>Some shortcut keys like <kbd>Ctrl</kbd><kbd>N</kbd> (macOS: <kbd></kbd><kbd>N</kbd>) are reserved by the web browser and can only be used in fullscreen mode. (Alternative to going fullscreen: include <kbd>Alt</kbd> in the shortcut combinations for browser-reserved hotkeys.)</p><p><img src="https://static.graphite.rs/content/learn/interface/window-buttons-web.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Fullscreen button" /></p> |
<!-- | **Windows<br />& Linux** | The standard window controls are displayed: minimize, maximize/restore down, and close.<br /><br /><img src="https://static.graphite.rs/content/learn/interface/window-buttons-windows-linux.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Minimize/maximize/close window buttons" /> | -->
<!-- | **macOS** | The standard window controls are displayed: close, minimize, and fullscreen. These are located on the left of the title bar.<br /><br /><img src="https://static.graphite.rs/content/learn/interface/window-buttons-macos.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Close/minimize/fullscreen window buttons" /> | -->

View File

@ -13,7 +13,7 @@ Any (sub)graph can import/export data from/to the outside world. For example, a
In the Graphite editor UI, here is an example graph of artwork that imports no data but exports its content to the canvas:
<img src="https://static.graphite.rs/content/index/gui-mockup-nodes__5.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Node graph UI mockup" />
<img src="https://static.graphite.rs/content/features/mockup-node-graph.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Node graph UI mockup" />
The graph shown above represents the full artwork, meaning it's the root-level graph in its document. But there is nothing special about that graph compared to any subgraph. To avoid the confusion of calling it a graph or subgraph which comes with implications about user-facing concepts in the context of a document, we will use the less-ambiguous term **network** in the context of Graphene's internal concepts and codebase.

View File

@ -95,12 +95,6 @@ Based on the experience and insight brought to the table by the student, the nat
</details>
### Native development
#### Graphite desktop app engineering
*This is a newly added project pending a full written overview. Come ask on Discord for details.*
### Rendering and graphics
Several of these require a good understanding of computer graphics rendering techniques and algorithms. Experience in game development and writing your own rendering engines is a plus.

View File

@ -8,7 +8,7 @@
touch-action: pan-y pinch-zoom;
cursor: grab;
img {
:is(img, video) {
position: relative;
display: inline-block;
user-select: none;
@ -33,7 +33,7 @@
}
}
&:not(.dragging, .jostling) .carousel-slide img {
&:not(.dragging, .jostling) .carousel-slide :is(img, video) {
transition: transform 500ms;
}
@ -141,11 +141,11 @@
}
}
&.window-size-1 .carousel-slide img {
&.window-size-1 .carousel-slide :is(img, video) {
width: 100%;
}
&.window-size-2 .carousel-slide img {
&.window-size-2 .carousel-slide :is(img, video) {
width: calc((100% / 2) - 10px);
padding: 0 10px;
@ -158,7 +158,7 @@
}
}
&.window-size-3 .carousel-slide img {
&.window-size-3 .carousel-slide :is(img, video) {
width: calc((100% / 3) - 10px * (4 / 3));
padding: 0 10px;

View File

@ -17,7 +17,8 @@ window.addEventListener("pointermove", dragMove);
* dragLastClientX: number | undefined,
* velocityDeltaWindow: Array<{ time: number, delta: number }>,
* jostleNoLongerNeeded: boolean,
* requestAnimationFrameActive: boolean
* requestAnimationFrameActive: boolean,
* videoSyncInterval: ReturnType<typeof setTimeout> | undefined,
* }} Carousel
*/
@ -34,8 +35,8 @@ function initializeCarousel() {
if (!(insertInsideElement instanceof HTMLElement)) return;
slideImages.forEach((image) => {
const clonedImage = image.cloneNode(true);
if (!(clonedImage instanceof HTMLImageElement)) return;
clonedImage.alt = "";
if (!(clonedImage instanceof HTMLImageElement) && !(clonedImage instanceof HTMLVideoElement)) return;
if (clonedImage instanceof HTMLImageElement) clonedImage.alt = "";
insertInsideElement.insertAdjacentElement("beforeend", clonedImage);
});
});
@ -61,6 +62,7 @@ function initializeCarousel() {
velocityDeltaWindow,
jostleNoLongerNeeded,
requestAnimationFrameActive: false,
videoSyncInterval: undefined,
};
carousels.push(carousel);
@ -166,6 +168,160 @@ function slideTo(carousel, index, smooth) {
slideImages[clamp(offsetIndex + 2, 0, slideImages.length - 1)].removeAttribute("loading");
setCurrentTransform(carousel, index * -100, "%", smooth);
// Manage video preloading and playback
manageVideoPlayback(carousel, index);
}
/**
* Get all video elements for a given slide index (main + torn edge copies)
* @param {Carousel} carousel
* @param {number} index
*/
function getVideosForSlide(carousel, index) {
// Account for the first image being the faded-out last image
const offsetIndex = index + 1;
const slideImages = Array.from(carousel.carouselContainer.querySelectorAll("[data-carousel-slide] [data-carousel-image]"));
const tornLeftImages = Array.from(carousel.carouselContainer.querySelectorAll("[data-carousel-slide-torn-left] [data-carousel-image]"));
const tornRightImages = Array.from(carousel.carouselContainer.querySelectorAll("[data-carousel-slide-torn-right] [data-carousel-image]"));
const mainElement = slideImages[offsetIndex];
const tornLeftElement = tornLeftImages[offsetIndex];
const tornRightElement = tornRightImages[offsetIndex];
return {
main: mainElement instanceof HTMLVideoElement ? mainElement : null,
tornLeft: tornLeftElement instanceof HTMLVideoElement ? tornLeftElement : null,
tornRight: tornRightElement instanceof HTMLVideoElement ? tornRightElement : null,
};
}
/**
* Check if the carousel is currently in transition (dragging or animating)
* @param {Carousel} carousel
*/
function isCarouselInTransition(carousel) {
// Check if user is dragging
if (carousel.dragLastClientX !== undefined) return true;
// Check if carousel has the "dragging" class (set during drag)
if (carousel.carouselContainer.classList.contains("dragging")) return true;
// Check if any slide has a transition in progress by looking at the computed style
const firstImage = carousel.images[1];
if (firstImage instanceof HTMLElement) {
const style = window.getComputedStyle(firstImage);
// If transform is transitioning, we're in motion
if (style.transitionProperty.includes("transform") && style.transitionDuration !== "0s") {
return true;
}
}
return false;
}
/**
* Preload and manage playback of videos on current and adjacent slides
* @param {Carousel} carousel
* @param {number} currentIndex
*/
function manageVideoPlayback(carousel, currentIndex) {
const totalSlides = carousel.dots.length;
// Clear any existing sync interval
if (carousel.videoSyncInterval !== undefined) {
clearTimeout(carousel.videoSyncInterval);
carousel.videoSyncInterval = undefined;
}
// Stop all videos that aren't on current or adjacent slides
for (let i = 0; i < totalSlides; i++) {
if (Math.abs(i - currentIndex) > 1) {
const videos = getVideosForSlide(carousel, i);
[videos.main, videos.tornLeft, videos.tornRight].forEach((video) => {
if (video) {
video.pause();
video.currentTime = 0;
}
});
}
}
// Preload and potentially play videos on current and adjacent slides
const indicesToPreload = [currentIndex - 1, currentIndex, currentIndex + 1].filter((index) => index >= 0 && index < totalSlides);
indicesToPreload.forEach((index) => {
const videos = getVideosForSlide(carousel, index);
// Exit early if not a video slide
if (!videos.main) return;
// Preload the video
if (videos.main.readyState < 3) videos.main.load();
// If this is the current slide, play the main video when ready
if (index === currentIndex) {
const playWhenReady = () => {
if (videos.main && videos.main.readyState >= 3) {
// Start the main video
videos.main.currentTime = 0;
videos.main.play().catch(() => {});
} else if (videos.main) {
// Video not ready yet, check again
videos.main.addEventListener("canplaythrough", playWhenReady, { once: true });
}
};
playWhenReady();
// Monitor for transitions and sync torn videos when in motion
updateVideoSyncForTransitions(carousel, videos);
}
});
}
/**
* Set up monitoring to play/pause torn edge videos based on transition state
* @param {Carousel} carousel
* @param {{ main: HTMLVideoElement | null, tornLeft: HTMLVideoElement | null, tornRight: HTMLVideoElement | null }} videos
*/
function updateVideoSyncForTransitions(carousel, videos) {
if (!videos.main) return;
const syncTornVideos = () => {
const inTransition = isCarouselInTransition(carousel);
// During transition: sync and play all copies
if (inTransition && videos.main) {
const mainTime = videos.main.currentTime;
[videos.tornLeft, videos.tornRight].forEach((video) => {
if (!video) return;
if (video.paused) {
video.currentTime = mainTime;
video.play().catch(() => {
// Ignore autoplay errors
});
} else {
// Keep synced
const drift = Math.abs(video.currentTime - mainTime);
if (drift > 0.1) {
video.currentTime = mainTime;
}
}
});
}
// Not in transition: pause torn edge videos to save performance
else {
if (videos.tornLeft && !videos.tornLeft.paused) videos.tornLeft.pause();
if (videos.tornRight && !videos.tornRight.paused) videos.tornRight.pause();
}
// Continue checking while in transition, or check again soon in case transition starts
carousel.videoSyncInterval = setTimeout(syncTornVideos, 100);
};
syncTornVideos();
}
/**

View File

@ -140,7 +140,7 @@
<a href="/press" class="link not-uppercase">Press</a>
<a href="/contact" class="link not-uppercase">Contact</a>
</nav>
<span>Copyright &copy; {{ now() | date(format = "%Y") }} Graphite Labs, LLC (an open source organization)</span>
<span>Copyright &copy; {{ now() | date(format = "%Y") }} Graphite Labs, LLC (an open source community organization)</span>
</footer>
</div>
</body>