mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-12-23 10:11:54 +00:00
Add the user manual to the website (#1390)
This commit is contained in:
parent
4d9e76063d
commit
9d3344808f
48 changed files with 970 additions and 300 deletions
|
|
@ -340,11 +340,21 @@ impl LayoutHolder for MenuBarMessageHandler {
|
|||
true,
|
||||
MenuBarEntryChildren(vec![
|
||||
vec![MenuBarEntry {
|
||||
label: "About Graphite".into(),
|
||||
label: "About Graphite…".into(),
|
||||
icon: Some("GraphiteLogo".into()),
|
||||
action: MenuBarEntry::create_action(|_| DialogMessage::RequestAboutGraphiteDialog.into()),
|
||||
..MenuBarEntry::default()
|
||||
}],
|
||||
vec![MenuBarEntry {
|
||||
label: "User Manual".into(),
|
||||
action: MenuBarEntry::create_action(|_| {
|
||||
FrontendMessage::TriggerVisitLink {
|
||||
url: "https://graphite.rs/learn/".into(),
|
||||
}
|
||||
.into()
|
||||
}),
|
||||
..MenuBarEntry::default()
|
||||
}],
|
||||
vec![
|
||||
MenuBarEntry {
|
||||
label: "Report a Bug".into(),
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ title = "Web-based vector graphics editor and design tool"
|
|||
template = "section.html"
|
||||
|
||||
[extra]
|
||||
css = ["/index.css"]
|
||||
js = ["/image-interaction.js", "/fundraising.js", "/video-embed.js"]
|
||||
css = ["index.css"]
|
||||
js = ["image-interaction.js", "video-embed.js"]
|
||||
+++
|
||||
|
||||
<!-- ▛ LOGO ▜ -->
|
||||
|
|
@ -333,7 +333,9 @@ You can help realize Graphite's ambitious vision of building the ultimate 2D cre
|
|||
Graphite is built by a small, dedicated crew of volunteers in need of resources to grow.
|
||||
</p>
|
||||
|
||||
<!-- ### Summer 2023 fundraising goal:
|
||||
<!-- [Re-include the import for `"fundraising.js"` when re-enabling this.]
|
||||
|
||||
### Summer 2023 fundraising goal:
|
||||
|
||||
<div class="fundraising loading" data-fundraising>
|
||||
<div class="fundraising-bar" data-fundraising-bar style="--fundraising-percent: 0%">
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
title = "About Graphite"
|
||||
|
||||
[extra]
|
||||
css = ["/about.css"]
|
||||
css = ["about.css"]
|
||||
+++
|
||||
|
||||
<section>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ This article explores the current thinking about the problems and potential engi
|
|||
|
||||
<!-- more -->
|
||||
|
||||
# Node-based editing
|
||||
## Node-based editing
|
||||
|
||||
A core feature is Graphite's reliance on procedural content generation using a node graph engine called Graphene. In traditional editors like Photoshop and Gimp, certain operations like "blur the image" modify the image pixels permanently, destroying the original (unblurred) image information.
|
||||
|
||||
|
|
@ -29,45 +29,45 @@ Many nodes process raster image data, but others work on data types like vector
|
|||
|
||||
Different nodes may take microseconds, milliseconds, seconds, or occasionally even minutes to run. Most should not take more than a few seconds, and those which take appreciable time should run infrequently. During normal operations, hundreds of milliseconds should be the worst case for ordinary nodes that run frequently. Caching is used heavily to minimize the need for recomputation.
|
||||
|
||||
## Node authorship
|
||||
### Node authorship
|
||||
|
||||
The nodes that process the node graph data can be computationally expensive. The goal is for the editor to ordinarily run and render (mostly) in real-time in order to be interactive. Because operations are arranged in a directed acyclic graph rather than a sequential list, there is opportunity to run many stages of the computation and rendering in parallel.
|
||||
|
||||
Nodes are implemented by us as part of a built-in library, and by some users who may choose to write code using a built-in development environment. Nodes can be written in Rust to target the CPU with the Rust compilation toolchain (made conveniently accessible for users). The same CPU Rust code can be reused (with modifications where necessary) for authoring GPU compute shaders via the [rust-gpu](https://github.com/EmbarkStudios/rust-gpu) compiler. This makes it easier to maintain both versions without using separate code files and even languages between targets.
|
||||
|
||||
## Sandboxing
|
||||
### Sandboxing
|
||||
|
||||
For security and portability, user-authored nodes are compiled into WebAssembly (WASM) modules and run in a sandbox. Built-in nodes provided with Graphite run natively to avoid the nominal performance penalty of the sandbox. When the entire editor is running in a web browser, all nodes use the browser's WASM executor. When running in a distributed compute cluster on cloud machines, the infrastructure provider may be able to offer sandboxing to sufficiently address the security concerns of running untrusted code natively.
|
||||
|
||||
# The Graphene distributed runtime
|
||||
## The Graphene distributed runtime
|
||||
|
||||
In the product architecture, Graphene is a distributed runtime environment for quickly processing data in the node graph by utilizing a pool of CPU and GPU compute resources available on local and networked machines. Jobs are run where latency, speed, and bandwidth availability will be most likely to provide a responsive user experience.
|
||||
|
||||
<img src="https://static.graphite.rs/content/blog/2022-05-12-distributed-computing-in-the-graphene-runtime/local-and-cloud.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Graphene in a local and cloud environment" />
|
||||
|
||||
## Scheduler
|
||||
### Scheduler
|
||||
|
||||
If users are running offline, their CPU threads and GPU (or multiple GPUs) are assigned jobs by the local Graphene scheduler. If running online, some jobs are performed locally while others are run in the cloud, an on-prem compute cluster, or just a spare computer on the same network. The schedulers generally prioritize keeping quicker, latency-sensitive jobs local to the client machine or LAN while allowing slower, compute-intensive jobs to usually run on the cloud.
|
||||
|
||||
Each cluster in a locality—such as the local machine, an on-prem render farm, and the cloud data center—runs a scheduler that commands the available compute resources. The multiple schedulers in different localities must cooperatively plan the high-level allocation of resources in their respective domains while avoiding excessive chatter over the network about the minutiae of each job invocation.
|
||||
|
||||
## Cache manager
|
||||
### Cache manager
|
||||
|
||||
Working together with the scheduler, the Graphene cache manager stores intermediate node evaluation results and intelligently evicts them when space is limited. If the user changes the node graph, it can reuse the upstream cached data but will need to recompute downstream nodes where the data changed. Memoization can be used to avoid recomputation when an input to a node is the same as received in the past, and that result is available in the cache.
|
||||
|
||||
## Progressive enhancement
|
||||
### Progressive enhancement
|
||||
|
||||
The scheduler and cache manager work in lockstep to utilize available compute and cache storage resources on the local machine or cluster in order to minimize latency for the user. Immediate feedback is needed when, for example, drawing with a paintbrush tool.
|
||||
|
||||
Sometimes, nodes can be run with quality flags. Many nodes (like the paintbrush rasterizer) are implemented using several different algorithms that produce different results trading off speed for quality. This means it runs once with a quick and ugly result, then runs again later to render a higher quality version, and potentially several times subsequently to improve the visual fidelity when the scheduler has spare compute resources and time. Anti-aliasing, for example, will usually pop in to replace aliased renders after a few seconds of waiting.
|
||||
|
||||
## Batched execution
|
||||
### Batched execution
|
||||
|
||||
It is important to reduce the overhead between executions. Sometimes, Graphene will predict, or observe during runtime, the frequent execution of code paths (or rather, *node paths*) with significant sequential (not parallel) execution steps. These are good candidates for optimization by reducing the overhead between each execution.
|
||||
|
||||
In these cases, Graphene will batch multiple sequentially-run nodes by recompiling them such that they are inlined as one execution unit. This can happen for both CPU-based programs and GPU-based compute shaders. This is conceptually similar to how just-in-time (JIT) compilers can predict, or observe at runtime, frequently-run code paths in order to apply compiler optimizations where they are most impactful.
|
||||
|
||||
## Data locality
|
||||
### Data locality
|
||||
|
||||
When dealing with sequential chains of nodes, if they haven't already been recompiled as a batched execution unit, the Graphene scheduler may also frequently prioritize grouping together a set of related nodes to be run together on the same machine for memory and cache locality.
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ Sequential nodes allocated to the same physical hardware can avoid the overhead
|
|||
|
||||
Graphene should recognize when a certain intermediate result already lives in RAM or VRAM and prioritize using that CPU or GPU to compute the tasks which rely on that data. But when that's not possible, we need a fast architecture to transfer data between machines. For GPUs, it might be possible to use a DMA (Direct Memory Access) strategy like Microsoft's new DirectStorage API for DirectX and transfer data into or out of VRAM straight to SSDs or networked file systems. Efficiently transferring the final result, and maybe occasionally intermediate cache results, between networks (like the cloud and client) with latency and bandwidth considerations is also important.
|
||||
|
||||
# Conclusion
|
||||
## Conclusion
|
||||
|
||||
Presently, we are experimenting with CPU and GPU node composition for the beginnings of the Graphene visual programming language. Most of what was described in this post will likely evolve as we get further into the implementation stage and when we learn more from experts in the fields of computer science that Graphene overlaps with.
|
||||
|
||||
|
|
|
|||
|
|
@ -7,10 +7,14 @@ title = "Contact the team"
|
|||
|
||||
# Contact the team
|
||||
|
||||
* Members of the press, please see the [press resources](/press) page.
|
||||
* For general discussions, reach out on [Discord](https://discord.graphite.rs) or [Reddit](https://www.reddit.com/r/graphite/).
|
||||
* To report a bug or request a feature, please [file an issue](https://github.com/GraphiteEditor/Graphite/issues/new) on GitHub.
|
||||
* For other inquiries, get in touch by email at <contact@graphite.rs>.
|
||||
<article>
|
||||
|
||||
- Members of the press, please see the [press resources](/press) page.
|
||||
- For general discussions, reach out on [Discord](https://discord.graphite.rs) or [Reddit](https://www.reddit.com/r/graphite/).
|
||||
- To report a bug or request a feature, please [file an issue](https://github.com/GraphiteEditor/Graphite/issues/new) on GitHub.
|
||||
- For other inquiries, get in touch by email at <contact@graphite.rs>.
|
||||
|
||||
</article>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
title = "Donate"
|
||||
|
||||
[extra]
|
||||
css = ["/donate.css"]
|
||||
js = ["/fundraising.js"]
|
||||
css = ["donate.css"]
|
||||
# js = ["fundraising.js"]
|
||||
+++
|
||||
|
||||
<section>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
title = "Graphite features"
|
||||
|
||||
[extra]
|
||||
css = ["/features.css"]
|
||||
css = ["features.css"]
|
||||
+++
|
||||
|
||||
<section>
|
||||
|
|
|
|||
|
|
@ -7,8 +7,22 @@ page_template = "book.html"
|
|||
book = true
|
||||
+++
|
||||
|
||||
The user manual is coming very soon. Please check back in a few days.
|
||||
<br />
|
||||
|
||||
<!-- Learn how to use Graphite like a pro. -->
|
||||

|
||||
|
||||
<!--  -->
|
||||
Welcome to the Graphite user manual. Get ready 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.
|
||||
|
||||
## More chapters coming soon
|
||||
|
||||
Additional manual chapters are being added over time. Check back often!
|
||||
|
||||
## Jump right in
|
||||
|
||||
If you're eager to skip the reading, head straight to the [hands-on quickstart video](./introduction) in the next chapter for a beginner project walkthrough you can follow along with.
|
||||
|
||||
## Need help?
|
||||
|
||||
If you're ever stuck or confused, ask your questions in the `#🧭user-help` channel of the [Graphite Discord server](https://discord.graphite.rs) or post a thread in the [discussion board](https://github.com/GraphiteEditor/Graphite/discussions) on GitHub.
|
||||
|
|
|
|||
13
website/content/learn/_todo/graph/_index.md
Normal file
13
website/content/learn/_todo/graph/_index.md
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
+++
|
||||
title = "Graph"
|
||||
template = "book.html"
|
||||
page_template = "book.html"
|
||||
|
||||
[extra]
|
||||
order = 4
|
||||
+++
|
||||
|
||||
- Opening the graph
|
||||
- Document graph vs. layer graph, limitations
|
||||
- Adding nodes
|
||||
- Connecting nodes
|
||||
|
|
@ -2,5 +2,5 @@
|
|||
title = "Layers"
|
||||
|
||||
[extra]
|
||||
order = 3
|
||||
order = 2
|
||||
+++
|
||||
10
website/content/learn/_todo/node-catalog/_index.md
Normal file
10
website/content/learn/_todo/node-catalog/_index.md
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
+++
|
||||
title = "Node catalog"
|
||||
template = "book.html"
|
||||
page_template = "book.html"
|
||||
|
||||
[extra]
|
||||
order = 9
|
||||
+++
|
||||
|
||||
## Graphical data types
|
||||
6
website/content/learn/_todo/node-catalog/raster-nodes.md
Normal file
6
website/content/learn/_todo/node-catalog/raster-nodes.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
+++
|
||||
title = "Raster nodes"
|
||||
|
||||
[extra]
|
||||
order = 2
|
||||
+++
|
||||
6
website/content/learn/_todo/node-catalog/vector-nodes.md
Normal file
6
website/content/learn/_todo/node-catalog/vector-nodes.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
+++
|
||||
title = "Vector nodes"
|
||||
|
||||
[extra]
|
||||
order = 1
|
||||
+++
|
||||
13
website/content/learn/_todo/raster-editing/_index.md
Normal file
13
website/content/learn/_todo/raster-editing/_index.md
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
+++
|
||||
title = "Raster editing"
|
||||
template = "book.html"
|
||||
page_template = "book.html"
|
||||
|
||||
[extra]
|
||||
order = 6
|
||||
+++
|
||||
|
||||
- Opening the graph
|
||||
- Document graph vs. layer graph, limitations
|
||||
- Adding nodes
|
||||
- Connecting nodes
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
+++
|
||||
title = "Tools"
|
||||
title = "Layers"
|
||||
|
||||
[extra]
|
||||
order = 2
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
+++
|
||||
title = "Interface"
|
||||
title = "Nodes"
|
||||
|
||||
[extra]
|
||||
order = 1
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
+++
|
||||
title = "Node graph"
|
||||
title = "Tools"
|
||||
template = "book.html"
|
||||
page_template = "book.html"
|
||||
|
||||
[extra]
|
||||
order = 2
|
||||
order = 7
|
||||
+++
|
||||
|
||||
6
website/content/learn/_todo/tools/general-tools.md
Normal file
6
website/content/learn/_todo/tools/general-tools.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
+++
|
||||
title = "General tools"
|
||||
|
||||
[extra]
|
||||
order = 1
|
||||
+++
|
||||
6
website/content/learn/_todo/tools/raster-tools.md
Normal file
6
website/content/learn/_todo/tools/raster-tools.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
+++
|
||||
title = "Raster tools"
|
||||
|
||||
[extra]
|
||||
order = 3
|
||||
+++
|
||||
6
website/content/learn/_todo/tools/vector-tools.md
Normal file
6
website/content/learn/_todo/tools/vector-tools.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
+++
|
||||
title = "Vector tools"
|
||||
|
||||
[extra]
|
||||
order = 2
|
||||
+++
|
||||
8
website/content/learn/_todo/vector-editing/_index.md
Normal file
8
website/content/learn/_todo/vector-editing/_index.md
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
+++
|
||||
title = "Vector editing"
|
||||
template = "book.html"
|
||||
page_template = "book.html"
|
||||
|
||||
[extra]
|
||||
order = 5
|
||||
+++
|
||||
6
website/content/learn/_todo/vector-editing/layers.md
Normal file
6
website/content/learn/_todo/vector-editing/layers.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
+++
|
||||
title = "Layers"
|
||||
|
||||
[extra]
|
||||
order = 2
|
||||
+++
|
||||
6
website/content/learn/_todo/vector-editing/nodes.md
Normal file
6
website/content/learn/_todo/vector-editing/nodes.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
+++
|
||||
title = "Nodes"
|
||||
|
||||
[extra]
|
||||
order = 1
|
||||
+++
|
||||
12
website/content/learn/_todo/viewport/_index.md
Normal file
12
website/content/learn/_todo/viewport/_index.md
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
+++
|
||||
title = "Viewport"
|
||||
template = "book.html"
|
||||
page_template = "book.html"
|
||||
|
||||
[extra]
|
||||
order = 3
|
||||
+++
|
||||
|
||||
- Canvas
|
||||
- Legacy layers
|
||||
- Legacy folders
|
||||
10
website/content/learn/_todo/viewport/artboards.md
Normal file
10
website/content/learn/_todo/viewport/artboards.md
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
+++
|
||||
title = "Artboards"
|
||||
|
||||
[extra]
|
||||
order = 2
|
||||
+++
|
||||
|
||||
- Infinite canvas
|
||||
- New document artboard
|
||||
- Adjusting existing artboards
|
||||
10
website/content/learn/_todo/viewport/navigation.md
Normal file
10
website/content/learn/_todo/viewport/navigation.md
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
+++
|
||||
title = "Navigation"
|
||||
|
||||
[extra]
|
||||
order = 1
|
||||
+++
|
||||
|
||||
- Pan
|
||||
- Tilt
|
||||
- Zoom
|
||||
9
website/content/learn/_todo/workflows/_index.md
Normal file
9
website/content/learn/_todo/workflows/_index.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
+++
|
||||
title = "Workflows"
|
||||
template = "book.html"
|
||||
page_template = "book.html"
|
||||
|
||||
[extra]
|
||||
order = 8
|
||||
+++
|
||||
|
||||
|
|
@ -3,18 +3,26 @@ title = "Imaginate"
|
|||
|
||||
[extra]
|
||||
order = 2
|
||||
js = ["image-interaction.js"]
|
||||
+++
|
||||
|
||||
<!-- <section id="imaginate-creative-concepts">
|
||||
<div class="diptych">
|
||||
Imaginate is a useful tool at every stage in the artistic process. Early on it provides inspiration for styles, color palettes, subjects, and composition. It lets you quickly test ideas and explore artistic directions. It's also a useful way to generate placeholder images and content for kit bashing.
|
||||
|
||||
<div class="section">
|
||||
Intermediate stages in the creative process can utilize Imaginate as an iterative back-and-forth dialogue between yourself and the tool. It can be used to improve your creation's artistic fidelity and details, evolve an idea, or inject a little controlled chaos to bring forth happy accidents. And coherency can be given to scenes built from kit bashing collages through interactively transforming its look with iterative Imaginate steps.
|
||||
|
||||
## Explore new creative concepts
|
||||
Near the end of the art process, Imaginate is useful for adding the finishing touches the beautify your creative work with small additions like textures, subtle lighting and shadow effects, and pleasant gradients to make the whole piece look its best. It can turn a sterile, flat vector drawing into a detailed final work.
|
||||
|
||||
**Get inspired** by generating endless variations of concepts and references to work from, such as:
|
||||
<!--
|
||||
Illustrate a use case:
|
||||
1. Hand draw a sketch of a scene
|
||||
2. Generate several scenes to get inspiration for the color palette
|
||||
3. Sample from those scenes and use the vector tools to ink sketch
|
||||
4. Iteratively improve the fidelity
|
||||
5. Inpaint to replace an element in the scene
|
||||
6. Outpaint to extend the scene
|
||||
-->
|
||||
|
||||
<section id="imaginate-creative-concepts-carousel" class="carousel window-size-3" data-carousel>
|
||||
<section id="imaginate-creative-concepts-carousel" class="carousel center window-size-2" data-carousel>
|
||||
<div class="carousel-slide">
|
||||
<img src="https://files.keavon.com/-/PerfumedNiceRhinoceros/capture.png" alt="" data-carousel-image />
|
||||
<img src="https://files.keavon.com/-/UnwrittenFrankHeterodontosaurus/capture.png" alt="" data-carousel-image />
|
||||
|
|
@ -25,26 +33,6 @@ order = 2
|
|||
<img src="https://files.keavon.com/-/BrownSuburbanMacaw/capture.png" alt="" data-carousel-image />
|
||||
<img src="https://files.keavon.com/-/AbsoluteAwkwardGrouse/capture.png" alt="" data-carousel-image />
|
||||
</div>
|
||||
<div class="carousel-slide torn left">
|
||||
<img src="https://files.keavon.com/-/PerfumedNiceRhinoceros/capture.png" alt="" data-carousel-image />
|
||||
<img src="https://files.keavon.com/-/UnwrittenFrankHeterodontosaurus/capture.png" alt="" data-carousel-image />
|
||||
<img src="https://files.keavon.com/-/BlindBiodegradableAlaskajingle/capture.png" alt="" data-carousel-image />
|
||||
<img src="https://files.keavon.com/-/DigitalElatedVicuna/capture.png" alt="" data-carousel-image />
|
||||
<img src="https://files.keavon.com/-/ThreadbareIncredibleFlycatcher/capture.png" alt="" data-carousel-image />
|
||||
<img src="https://files.keavon.com/-/NaughtyGracefulSquirrel/capture.png" alt="" data-carousel-image />
|
||||
<img src="https://files.keavon.com/-/BrownSuburbanMacaw/capture.png" alt="" data-carousel-image />
|
||||
<img src="https://files.keavon.com/-/AbsoluteAwkwardGrouse/capture.png" alt="" data-carousel-image />
|
||||
</div>
|
||||
<div class="carousel-slide torn right">
|
||||
<img src="https://files.keavon.com/-/PerfumedNiceRhinoceros/capture.png" alt="" data-carousel-image />
|
||||
<img src="https://files.keavon.com/-/UnwrittenFrankHeterodontosaurus/capture.png" alt="" data-carousel-image />
|
||||
<img src="https://files.keavon.com/-/BlindBiodegradableAlaskajingle/capture.png" alt="" data-carousel-image />
|
||||
<img src="https://files.keavon.com/-/DigitalElatedVicuna/capture.png" alt="" data-carousel-image />
|
||||
<img src="https://files.keavon.com/-/ThreadbareIncredibleFlycatcher/capture.png" alt="" data-carousel-image />
|
||||
<img src="https://files.keavon.com/-/NaughtyGracefulSquirrel/capture.png" alt="" data-carousel-image />
|
||||
<img src="https://files.keavon.com/-/BrownSuburbanMacaw/capture.png" alt="" data-carousel-image />
|
||||
<img src="https://files.keavon.com/-/AbsoluteAwkwardGrouse/capture.png" alt="" data-carousel-image />
|
||||
</div>
|
||||
<div class="screenshot-details">
|
||||
<div class="carousel-controls">
|
||||
<button class="direction prev" data-carousel-prev>
|
||||
|
|
@ -59,6 +47,7 @@ order = 2
|
|||
<button class="dot" data-carousel-dot></button>
|
||||
<button class="dot" data-carousel-dot></button>
|
||||
<button class="dot" data-carousel-dot></button>
|
||||
<button class="dot" data-carousel-dot></button>
|
||||
<button class="direction next" data-carousel-next>
|
||||
<svg width="40" height="40" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M20,0C8.95,0,0,8.95,0,20c0,11.05,8.95,20,20,20c11.05,0,20-8.95,20-20C40,8.95,31.05,0,20,0z M20,38c-9.93,0-18-8.07-18-18S10.07,2,20,2s18,8.07,18,18S29.93,38,20,38z" />
|
||||
|
|
@ -68,10 +57,3 @@ order = 2
|
|||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<blockquote class="balance-text">Lighthouse built on a rock outcropping in stormy high seas</blockquote>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section> -->
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
+++
|
||||
title = "Procedural editing"
|
||||
|
||||
[extra]
|
||||
order = 1
|
||||
+++
|
||||
80
website/content/learn/interface/_index.md
Normal file
80
website/content/learn/interface/_index.md
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
+++
|
||||
title = "Interface"
|
||||
template = "book.html"
|
||||
page_template = "book.html"
|
||||
|
||||
[extra]
|
||||
order = 2
|
||||
+++
|
||||
|
||||
This chapter formally introduces the concepts and terminology for the user interface (UI) of the Graphite editor. You may skip to the next chapter if you're familiar with the general layout and terms used in industry-standard graphics editors.
|
||||
|
||||
## Title bar
|
||||
|
||||
The bar running across the top of the editor is called the **title bar**. In the (forthcoming) desktop release of Graphite, this acts as the draggable window frame.
|
||||
|
||||
<p><img src="https://static.graphite.rs/content/learn/interface/title-bar.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="The title bar" /></p>
|
||||
|
||||
### Menu bar
|
||||
|
||||
On the left, the [**menu bar**](./menu-bar) provides quick access to many editor, document, and artwork related controls. Its functions are covered in detail on the next page.
|
||||
|
||||
<p><img src="https://static.graphite.rs/content/learn/interface/menu-bar.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="The menu bar" /></p>
|
||||
|
||||
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 since it was last saved.
|
||||
|
||||
<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 window. In the (forthcoming) macOS desktop release, this appears on the left side instead.
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| **Web** | A button to enter fullscreen mode is displayed.<br /><br />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 fullscreen mode: include <kbd>Alt</kbd> in the shortcut combinations for browser-reserved hotkeys.)<br /><br /><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" /> |
|
||||
| **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" /> |
|
||||
|
||||
## Workspace
|
||||
|
||||
The **workspace** is the editor's main content area. It houses the **panels** packed next to one another. The **gutter** lines between neighboring panels may be dragged to resize them.
|
||||
|
||||
<p><img src="https://static.graphite.rs/content/learn/interface/workspace.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="The workspace" /></p>
|
||||
|
||||
### Panels
|
||||
|
||||
Panels are regions of the UI dedicated to a specific purpose. [**Document**](./document-panel), [**Properties**](./properties-panel), and [**Layers**](./layers-panel) are presently the three panel types. Each will be covered later in the chapter.
|
||||
|
||||
Each panel name is shown in its **panel tab bar**. Panel tabs provide a quick way to swap between multiple panels occupying the same area (currently only documents support this). Down the road, these tabs will be dockable so the default layout may be customized.
|
||||
|
||||
Beneath the panel tab bar, the **panel body** displays the content for its panel type. Each will be described in the following pages.
|
||||
|
||||
## Status bar
|
||||
|
||||
The bar running across the bottom of the editor is called the **status bar**.
|
||||
|
||||
<p><img src="https://static.graphite.rs/content/learn/interface/status-bar.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Status bar" /></p>
|
||||
|
||||
### Input hints
|
||||
|
||||
The **input hints** are presently the only occupant of the status bar. They indicate what common keyboard and mouse inputs are valid in the current context. Hints change with each active tool as well as with the current interaction state. Keep a frequent eye on the hints to discover more features as you work.
|
||||
|
||||
Hints with a **`+`** mean that adding the indicated modifier key will change the base action. For example: in the following action, dragging with left-click held down will zoom the canvas; then additionally holding the <kbd>Ctrl</kbd> key will make the zoom action snap to whole increments.
|
||||
|
||||
<p><img src="https://static.graphite.rs/content/learn/interface/input-hints-plus.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Example hint" /></p>
|
||||
|
||||
Hints with a **`/`** mean that either indicated input combination can be used to trigger the same action. For example: in the following action, either holding the space bar while dragging with the left mouse button held down, or just dragging with the middle mouse button held down, will both pan around the document in the viewport.
|
||||
|
||||
<p><img src="https://static.graphite.rs/content/learn/interface/input-hints-slash.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Example hint" /></p>
|
||||
|
||||
The following chart describes each icon representing the mouse inputs you can perform so a hint's prescribed action occurs.
|
||||
|
||||
| | Clicks | Drags | Others |
|
||||
|-|:-:|:-:|:-:|
|
||||
| **Left<br />mouse<br />button** | Left click<br /><br /><img src="https://static.graphite.rs/content/learn/interface/mouse-input-left-click.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Left click icon" /> | Left click drag<br /><br /><img src="https://static.graphite.rs/content/learn/interface/mouse-input-left-click-drag.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Left click drag icon" /> | Left double-click<br /><br /><img src="https://static.graphite.rs/content/learn/interface/mouse-input-left-double-click.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Left double-click icon" /> |
|
||||
| **Right<br />mouse<br />button** | Right click<br /><br /><img src="https://static.graphite.rs/content/learn/interface/mouse-input-right-click.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Right click icon" /> | Right click drag<br /><br /><img src="https://static.graphite.rs/content/learn/interface/mouse-input-right-click-drag.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Right click drag icon" /> | Right double-click<br /><br /><img src="https://static.graphite.rs/content/learn/interface/mouse-input-right-double-click.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Right double-click icon" /> |
|
||||
| **Middle<br />mouse<br />button** | Middle click<br /><br /><img src="https://static.graphite.rs/content/learn/interface/mouse-input-middle-click.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Middle click icon" /> | Middle click drag<br /><br /><img src="https://static.graphite.rs/content/learn/interface/mouse-input-middle-click-drag.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Middle click drag icon" /> | Scroll up/down<br /><br /><img src="https://static.graphite.rs/content/learn/interface/mouse-input-scroll-up.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Scroll up icon" /> <img src="https://static.graphite.rs/content/learn/interface/mouse-input-scroll-down.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Scroll down icon" /> |
|
||||
149
website/content/learn/interface/document-panel.md
Normal file
149
website/content/learn/interface/document-panel.md
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
+++
|
||||
title = "Document panel"
|
||||
|
||||
[extra]
|
||||
order = 2
|
||||
+++
|
||||
|
||||
The **Document panel** is the main content area where the artwork is displayed and edited using **tools** within the **viewport**. It's also where the **node graph** can be overlaid by pressing <kbd>Ctrl</kbd><kbd>Space</kbd>. The viewport is for interactive, visual editing of the **canvas**. The node graph is where you can inspect the underlying structure of the document and edit it in a more technical way if the need arises.
|
||||
|
||||
There is one instance of the Document panel per open document file. Each has its own tab labeled with its file name. When a document has unsaved changes, an `*` is included at the end of the name.
|
||||
|
||||
The Document panel is composed of three main areas:
|
||||
|
||||
- The **top bar** runs across the top of the panel and provides controls and view options.
|
||||
- The **shelf** is the narrow vertical bar that runs down the left of the panel and lists a selection of tools or nodes.
|
||||
- The **table** fills the rest of the panel and contains the viewport and overlaid node graph.
|
||||
|
||||
The content of each depends if the viewport or node graph is visible, as described in the two sections below.
|
||||
|
||||
## Interactive viewport editing
|
||||
|
||||
### Top bar
|
||||
|
||||
While the viewport is visible, the left of the bar provides controls for the active tool and the right provides view options.
|
||||
|
||||
#### Editing modes
|
||||
|
||||
Only the default mode is currently implemented. Others will be added in the future and this dropdown is a placeholder for that.
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| <img src="https://static.graphite.rs/content/learn/interface/document-panel/editing-modes.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" onload="this.width /= 2" alt="The editing modes dropdown menu" /> | The default, **Design Mode**, is for directly editing the artwork.<br /><br />Once implemented, **Select Mode** will be where marquee selections are made to constrain the active tool's edits to a masked area of choice.<br /><br />Once implemented, **Guide Mode** will be for creating guides and constraint systems used for alignment and constraint-based layout. |
|
||||
|
||||
|
||||
|
||||
#### Tool options
|
||||
|
||||
Provides controls for the active tool. These change with each tool, and are blank for some.
|
||||
|
||||
<p><img src="https://static.graphite.rs/content/learn/interface/document-panel/tool-options.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Example of the tool options for the Select tool" /></p>
|
||||
|
||||
Pictured above is the tool options for the Select tool. It provides options related to its selection behavior and offers useful action buttons for modifying the selected layers with alignment, flipping, and (not-yet-implemented) boolean operations.
|
||||
|
||||
Each tool's options are described in the [Tools](../../tools) chapter.
|
||||
|
||||
#### Viewport options
|
||||
|
||||
Shows options for how the viewport is displayed and interacted with.
|
||||
|
||||
<p><img src="https://static.graphite.rs/content/learn/interface/document-panel/viewport-options.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="The viewport options" /></p>
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| Snapping | **Snapping is temporarily unavailable. When the feature is restored, it will behave as described below.**<br /><br />When checked (default), drawing and dragging points and layers means they will snap to the alignment points that are visualized as blue overlayed dots/lines located at points of geometric interest within other layers. When unchecked, the selection moves freely.<br /><br />Fine-grained options are available by clicking the overflow button to access its options popover menu:<br /><br /><img src="https://static.graphite.rs/content/learn/interface/document-panel/snapping-popover.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" onload="this.width /= 2" alt="Snapping options popover menu" /><ul><li>**Bounding Boxes** sets whether the *edges* and *centers* of the rectangle that encloses the bounds of each other layer is used for snapping.</li><li>**Points** sets whether the anchors and handles of vector paths are used for snapping.</li></ul> |
|
||||
| Grid | **Not yet implemented.** This is a placeholder for upcoming grid alignment and pixel-perfect snapping features. |
|
||||
| Overlays | When checked (default), overlays are shown. When unchecked, they are hidden. Overlays are the contextual visualizations that appear in blue atop the viewport when using tools. |
|
||||
| View Mode | **Normal** (default): The artwork is rendered normally.<br /><br />**Outline**: The artwork is rendered as a wireframe.<br /><br />**Pixels**: **Not implemented yet.** The artwork is rendered as it would appear when exported as a bitmap image at 100% scale regardless of the viewport zoom level. |
|
||||
| Zoom In | Zooms the viewport in to the next whole increment. |
|
||||
| Zoom Out | Zooms the viewport out to the next whole increment. |
|
||||
| Zoom to 100% | Resets the viewport zoom to 100% which matches the canvas and viewport pixel scale 1:1. |
|
||||
| Viewport Zoom | Indicates the current zoom level of the viewport and allows precise values to be chosen. |
|
||||
| Viewport Tilt | Hidden except when the viewport is tilted (use the *View* > *Tilt* menu action). Indicates the current tilt angle of the viewport and allows precise values to be chosen.
|
||||
|
||||
### Shelf
|
||||
|
||||
This narrow bar runs vertically down the left side of the Document panel beside the table where the viewport is displayed.
|
||||
|
||||
#### Tool shelf
|
||||
|
||||
Located at the top of the shelf area, the **tool shelf** provides a selection of **tools** for interactively editing the artwork.
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| <img src="https://static.graphite.rs/content/learn/interface/document-panel/tool-shelf.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" onload="this.width /= 2" alt="The tool shelf" /> | The tool shelf is split into three sections: the **general tools** (gray icons), **vector tools** (blue icons), and **raster tools** (orange icons).<br /><br />General tools are used for assorted editing tasks within the viewport.<br /><br />Vector tools are used for drawing and editing vector shapes, curves, and text.<br /><br />Raster tools are used for drawing and editing raster image content. The grayed out icons are placeholders for upcoming tools. |
|
||||
|
||||
#### Graph view button
|
||||
|
||||
Toggles the visibility of the overlaid **node graph**. It looks like this while closed:
|
||||
|
||||
<p><img src="https://static.graphite.rs/content/learn/interface/document-panel/graph-view-button-while-closed.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="The graph view button while the graph is closed" /></p>
|
||||
|
||||
#### Working colors
|
||||
|
||||
The **working colors** are the two colors used by the active tool.
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| <img src="https://static.graphite.rs/content/learn/interface/document-panel/working-colors.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="The working colors" /> | The upper circle is the **primary color**. The lower circle is the **secondary color**.<br /><br />There are two buttons located underneath: **Swap** which reverses the current color choices, and **Reset** which resets the primary color to black and the secondary color to white. |
|
||||
|
||||
Various tools provide choices for using the primary and secondary colors as controls in the tool options. For example, many vector tools have **Fill** and **Stroke** options that use the current secondary and primary colors, respectively, as defaults:
|
||||
|
||||
<p><img src="https://static.graphite.rs/content/learn/interface/document-panel/tool-options-fill-stroke-colors.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="The Fill and Stroke controls for a vector tool's options" /></p>
|
||||
|
||||
These options each allow choices of being driven by the primary working color, secondary working color, or a custom color set just for that tool.
|
||||
|
||||
### Table
|
||||
|
||||
The **table** contains the **viewport** bounded by rulers and scrollbars along its edges.
|
||||
|
||||
#### Rulers and scrollbars
|
||||
|
||||
The **rulers**, located along the top and left edges within the table, display the size and location of the viewport's visible region in canvas coordinates.
|
||||
|
||||
The **scrollbars**, located along the bottom and right edges within the table, allow scrolling the artwork to show different parts of the canvas in the viewport.
|
||||
|
||||
#### Viewport
|
||||
|
||||
The **viewport** is the view into the canvas. It is where the artwork is displayed and interactively edited using the tools.
|
||||
|
||||
## Overlaid node graph editing
|
||||
|
||||
Opening the overlaid node graph shows the structure of nodes and layers that compose the document artwork. It's a more detailed view of what the [Layers](../layers-panel) and [Properties](../properties-panel) panels show.
|
||||
|
||||
**Nodes** are the entities with left-to-right input **connectors**.
|
||||
|
||||
**Layers** are the larger entities shown with thumbnails and a bottom-to-top direction of data stacking. Their purpose is to composite sources of graphical data on top of one another in a **layer stack**. Layers take input from other nodes or layers via a connector on their left side. When that connector is fed by another layer stack, the Layers panel considers it a **group** because it combines one stack into another parent stack.
|
||||
|
||||
Layers and nodes are wired together using **links** which send data between the outputs of nodes to the inputs of others. You can wire up a node by dragging from the output connector of one node to the input connector of its destination node. But note that forming cyclic graphs, where a loop can be traced along the links of a set of nodes, is not permitted. Graphical data flows into the **Output** node which then becomes rendered to the document viewport.
|
||||
|
||||
### Top bar
|
||||
|
||||
Provides several controls for the graph and selected node or layer. The options change based on what's selected.
|
||||
|
||||
#### Node/layer controls
|
||||
|
||||
When a layer or node is selected, these buttons will show up on the right side of the top bar:
|
||||
|
||||
<p><img src="https://static.graphite.rs/content/learn/interface/document-panel/node-controls-buttons.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" onload="this.width /= 2" alt="The node/layer controls" /></p>
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| Make<span> </span>Hidden/<br />Make<span> </span>Visible | Toggles the visibility state of the layer or node. This is equivalent to the eye icon button next to each row in the Layers panel. If a node or layer is hidden, it gets bypassed in the data flow. <kbd>Ctrl</kbd><kbd>H</kbd> (macOS: <kbd>⌘</kbd><kbd>H</kbd>) is a shortcut that can be used in the graph or viewport to hide the selected. |
|
||||
| Preview/<br />End<span> </span>Preview | Temporarily moves the graph output away from the Output node and the graph output is instead provided by the previewed node. While previewing, the node is styled with a dashed, brighter border. Ending the preview returns responsibility back to the Output node. This is a handy feature for viewing part of a graph without needing to disconnect the actual Output node and manually restore it later. Clicking a node or layer while holding <kbd>Alt</kbd> is a shortcut for toggling its preview on or off. |
|
||||
|
||||
### Shelf
|
||||
|
||||
This narrow bar runs vertically down the left side of the Document panel beside the table where the graph is displayed.
|
||||
|
||||
In the future, icons for the common categories of nodes will be listed down from the top allowing quick access and browsing. For now, this area is empty.
|
||||
|
||||
#### Graph view button
|
||||
|
||||
Toggles the visibility of the overlaid node graph. It looks like this while open:
|
||||
|
||||
<p><img src="https://static.graphite.rs/content/learn/interface/document-panel/graph-view-button-while-open.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="The graph view button while the graph is open" /></p>
|
||||
|
||||
#### Working colors
|
||||
|
||||
[Same functionality](#working-colors) as when the graph overlay is closed.
|
||||
18
website/content/learn/interface/layers-panel.md
Normal file
18
website/content/learn/interface/layers-panel.md
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
+++
|
||||
title = "Layers panel"
|
||||
|
||||
[extra]
|
||||
order = 3
|
||||
+++
|
||||
|
||||
This manual page hasn't been written yet! But here is an outline for what's coming soon:
|
||||
|
||||
- About layers and folders
|
||||
- Top bar
|
||||
- Blend modes and opacity
|
||||
- Adding folders
|
||||
- Deleting the selected layers
|
||||
- The layer list
|
||||
- Editing layers
|
||||
- Selection and multi-selection
|
||||
- Rearranging the hierarchy
|
||||
113
website/content/learn/interface/menu-bar.md
Normal file
113
website/content/learn/interface/menu-bar.md
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
+++
|
||||
title = "Menu bar"
|
||||
|
||||
[extra]
|
||||
order = 1
|
||||
+++
|
||||
|
||||
The **menu bar** is the series of menus running across the top left of the editor's [**title bar**](../#title-bar). It provides organized access to many actions which are described on this page.
|
||||
|
||||
<p><img src="https://static.graphite.rs/content/learn/interface/menu-bar.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="The menu bar" /></p>
|
||||
|
||||
Clicking **File**, **Edit**, **Layer**, **Document**, **View**, and **Help** opens a dropdown menu with clickable actions. Pay attention to the keyboard shortcut listed on the right of each row in the dropdown menus. Learning to use them can help speed up your workflow.
|
||||
|
||||
The rest of this page is intended as a reference resource. Skip ahead to the next page if this is your first read-through of the manual.
|
||||
|
||||
## App button
|
||||
|
||||
<p><img src="https://static.graphite.rs/content/learn/interface/menu-bar/menu-app-button.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="The app button" /></p>
|
||||
|
||||
The **app button** shows the [Graphite logo](/logo). Clicking it opens the Graphite website [home page](/).
|
||||
|
||||
## File
|
||||
|
||||
<p><img src="https://static.graphite.rs/content/learn/interface/menu-bar/menu-file.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="The File menu" /></p>
|
||||
|
||||
The **File menu** lists actions related to file handling:
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| New… | Opens the **New Document** dialog for creating a blank canvas in a new editor tab.<br /><br /><img src="https://static.graphite.rs/content/learn/interface/menu-bar/dialog-new-document.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="The 'New Document' dialog" /> |
|
||||
| Open… | Opens the operating system file picker dialog for selecting a `.graphite` file from disk to be opened in a new editor tab. |
|
||||
| Open Demo Artwork… | Opens the **Demo Artwork** dialog for loading a choice of premade sample artwork files provided for you to explore. Click the button below each image to open it.<br /><br /><img src="https://static.graphite.rs/content/learn/interface/menu-bar/dialog-demo-artwork.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="The 'Demo Artwork' dialog" /> |
|
||||
| Close | Closes the active document. If it has unsaved changes (denoted by the `*` after the file name), you will be asked to save or discard the changes. |
|
||||
| Close All | Closes all open documents. To avoid accidentally losing unsaved work, you will be asked to confirm that you want to proceed which will discard the unsaved changes in all open documents. |
|
||||
| Save | Saves the active document by writing the `.graphite` file to disk. An operating system file download dialog may appear asking where to place it. That dialog will provide an opportunity to save over a previous version of the file, if you wish, by picking the identical name instead of saving another instance with a number after it. |
|
||||
| Import… | Opens the operating system file picker dialog for selecting an image file from disk to be placed as a new bitmap image layer into the active document. |
|
||||
| Export… | Opens the **Export** dialog for saving the artwork as a *File Type* of *PNG*, *JPG*, or *SVG*. *Scale Factor* multiplies the content's document scale, so a value of 2 would export 300x400 content as 600x800 pixels. *Bounds* picks what area to render: *All Artwork* uses the bounding box of all layers, *Selection* uses the bounding box of the currently selected layers, and an *Artboard: \[Name\]* uses the bounds of that artboard. *Transparency* exports the PNG or SVG file with transparency instead of the artboard background color.<br /><br /><img src="https://static.graphite.rs/content/learn/interface/menu-bar/dialog-export.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="The 'Export' dialog" /> |
|
||||
| Preferences… | Opens the **Editor Preferences** dialog for configuring Graphite's settings.<br /><br /><img src="https://static.graphite.rs/content/learn/interface/menu-bar/dialog-editor-preferences.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="The 'Editor Preferences' dialog" /> |
|
||||
|
||||
## Edit
|
||||
|
||||
<p><img src="https://static.graphite.rs/content/learn/interface/menu-bar/menu-edit.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="The Edit menu" /></p>
|
||||
|
||||
The **Edit menu** lists actions related to the editing workflow:
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| Undo | Steps back in the history of changes in the active document. |
|
||||
| Redo | Steps forward in the history of changes in the active document. |
|
||||
| Cut | Copies the selected layer(s) to the clipboard, then deletes them. |
|
||||
| Copy | Copies the selected layer(s) to the clipboard. |
|
||||
| Paste | Pastes the copied layer(s) from the clipboard into the document. It will end up beside a selected layer or inside a selected folder, or otherwise at the base of the folder structure.<br /><br />In the web version of Graphite, your browser will ask for permission to read from your clipboard which you must grant; using the hotkey <kbd>Ctrl</kbd><kbd>V</kbd> (macOS: <kbd>⌘</kbd><kbd>V</kbd>) works without browser permission. |
|
||||
|
||||
## Layer
|
||||
|
||||
<p><img src="https://static.graphite.rs/content/learn/interface/menu-bar/menu-layer.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="The Layer menu" /></p>
|
||||
|
||||
The **Layer menu** lists actions related to the layers within a document:
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| Select All | Selects all layers and folders in the document. |
|
||||
| Deselect All | Deselects everything in the document. |
|
||||
| Delete Selected | Removes all selected layers and folders. |
|
||||
| Grab Selected | Begin grabbing the selected layer(s) to translate (move) them around with your cursor's movement. Lock to an axis with <kbd>X</kbd> or <kbd>Y</kbd> then use the number keys to type a pixel distance value. Confirm with a left click or <kbd>Enter</kbd>. Cancel with a right click or <kbd>Esc</kbd>. |
|
||||
| Rotate Selected | Begin rotating the selected layer(s) around their pivot point with your cursor's movement. Use the number keys to type an angle value in degrees. Confirm with a left click or <kbd>Enter</kbd>. Cancel with a right click or <kbd>Esc</kbd>. |
|
||||
| Scale Selected | Begin scaling the selected layer(s) around their pivot point with your cursor's movement. Lock to an axis with <kbd>X</kbd> or <kbd>Y</kbd>. Use the number keys to type a scale multiplier value. Confirm with a left click or <kbd>Enter</kbd>. Cancel with a right click or <kbd>Esc</kbd>. |
|
||||
| Order ><br />Raise to Front | Reorders the selected layer(s) above all other layers within their same folder(s), so they appear in the layer stack and render above those other layers. |
|
||||
| Order ><br />Raise | Reorders the selected layers(s) up by one in the layer stack, so any layer that was immediately above the selected layer(s) ends up immediately below. |
|
||||
| Order ><br />Lower | Reorders the selected layers(s) down by one in the layer stack, so any layer that was immediately below the selected layer(s) ends up immediately above. |
|
||||
| Order ><br />Lower to Back | Reorders the selected layer(s) below all other layers within their same folder(s), so they appear in the layer stack and render below those other layers. |
|
||||
|
||||
## Document
|
||||
|
||||
<p><img src="https://static.graphite.rs/content/learn/interface/menu-bar/menu-document.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="The Document menu" /></p>
|
||||
|
||||
The **Document menu** lists actions related to the document and artwork:
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| Clear Artboards | Removes all artboards from the document, thus enabling an infinite canvas. |
|
||||
|
||||
## View
|
||||
|
||||
<p><img src="https://static.graphite.rs/content/learn/interface/menu-bar/menu-view.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="The View menu" /></p>
|
||||
|
||||
The **View menu** lists actions related to the view of the canvas and viewport:
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| Tilt | Begins tilting the viewport angle based on your mouse movements. Hold <kbd>Ctrl</kbd> to snap to 15° increments. Confirm with a left click or <kbd>Enter</kbd>. Cancel with a right click or <kbd>Esc</kbd>. |
|
||||
| Reset Tilt | Sets the viewport tilt angle back to 0°. |
|
||||
| Zoom In | Narrows the view to the next whole zoom increment. |
|
||||
| Zoom Out | Widens the view to the next whole zoom increment. |
|
||||
| Zoom to Fit Selection | Zooms and frames the viewport to the bounding box of the selected layer(s). |
|
||||
| Zoom to Fit All | Zooms and frames the viewport to fit all artboards, or all artwork if using infinite canvas. |
|
||||
| Zoom to 100% | Zooms the viewport in or out to 100% scale, matching 1:1 the scale of the document and viewport. |
|
||||
| Zoom to 200% | Zooms the viewport in or out to 200% scale, displaying the artwork at twice the actual size. |
|
||||
| Rulers | Toggles visibility of the rulers shown along the top and left edges of the viewport. |
|
||||
|
||||
## Help
|
||||
|
||||
<p><img src="https://static.graphite.rs/content/learn/interface/menu-bar/menu-help.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="The Help menu" /></p>
|
||||
|
||||
The **Help menu** lists actions related to information about Graphite:
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| About Graphite… | Opens the **About Graphite** dialog for displaying release and license information. |
|
||||
| User Manual | Opens this [user manual](./learn). |
|
||||
| Report a Bug | Opens a page to file a [new GitHub issue](https://github.com/GraphiteEditor/Graphite/issues/new). |
|
||||
| Visit on GitHub | Opens the [Graphite GitHub repository](https://github.com/GraphiteEditor/Graphite). |
|
||||
| *Debug section* | Developer-only actions. |
|
||||
14
website/content/learn/interface/properties-panel.md
Normal file
14
website/content/learn/interface/properties-panel.md
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
+++
|
||||
title = "Properties panel"
|
||||
|
||||
[extra]
|
||||
order = 4
|
||||
+++
|
||||
|
||||
This manual page hasn't been written yet! But here is an outline for what's coming soon:
|
||||
|
||||
- Node properties
|
||||
- Parameters
|
||||
- Expose button
|
||||
- Name
|
||||
- Value inputs
|
||||
|
|
@ -6,3 +6,15 @@ page_template = "book.html"
|
|||
[extra]
|
||||
order = 1
|
||||
+++
|
||||
|
||||
Before taking the time to read the coming chapters, let's build some context by jumping straight into a small project that you can follow along with. That way you will have a mental framework for the topics explained in the rest of this manual.
|
||||
|
||||
## A hands-on quickstart
|
||||
|
||||
You can follow along with this starter project either by watching the tutorial video or referencing the step-by-step breakdown.
|
||||
|
||||
***The tutorial isn't ready quite yet, sorry! Please check back very soon. It should be posted by mid-December.***
|
||||
|
||||
<!-- TODO -->
|
||||
<!-- - Video tutorial -->
|
||||
<!-- - Step-by-step written form -->
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
+++
|
||||
title = "Artboards"
|
||||
|
||||
[extra]
|
||||
order = 4
|
||||
+++
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
+++
|
||||
title = "Features and limitations"
|
||||
|
||||
[extra]
|
||||
order = 1
|
||||
+++
|
||||
|
||||
Please keep in mind that Graphite is alpha software, meaning it is actively changing and improving. Remember to save you work frequently because crashes are not unheard of.
|
||||
|
||||
## Current capabilities
|
||||
|
||||
### Vector illustration and graphic design
|
||||
|
||||
Vector editing is the core competency of the Graphite editor at this stage in its development. That means you can create graphic designs and shape-based vector artwork with the tools on offer, like this cactus:
|
||||
|
||||
<p><img src="https://static.graphite.rs/content/index/just-a-potted-cactus-thumbnail.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Example vector artwork of a potted cactus" /></p>
|
||||
|
||||
Primitive geometry like rectangles and ellipses can be drawn and, as desired, modified into more complex shapes using the Path tool. Fully organic shapes may also be created from scratch with the Pen tool. They can then be given colors and gradients to add visual style.
|
||||
|
||||
### Raster compositing
|
||||
|
||||
Raster image editing is a growing capability that will develop over time into the central focus of Graphite. Raster imagery is composed of pixels which are grids of color that can represent anything visual, like paintings and photographs. The current feature set lets you import images, manipulate them using the node-based compositor, and apply nondestructive effects like color adjustment filters.
|
||||
|
||||
A prototype Brush tool exists letting you draw simple doodles and sketches. However it is very limited in its capabilities and there are multiple bugs and performance issues with the feature. It can be used in a limited capacity, but don't expect to paint anything too impressive using raster brushes quite yet.
|
||||
|
||||
The raster-based Imaginate feature enables you to synthesize artwork using generative AI based on text descriptions. With it, you can also nondestructively modify your vector art and imported images. You can inpaint (or outpaint) the content in a specific masked part of an image or use it to touch up quick-and-dirty compositions.
|
||||
|
||||
### Procedural design
|
||||
|
||||
Procedural content generation workflows let you describe *how* a creative decision becomes a visual outcome rather than doing it all yourself. For example, copying a shape 50 times around the inside of a circle would be a lot of work if done by hand but it's easy for the computer to do it. And if you decide you prefer 60 instead of 50 instances, or you want to change the copied shape, or you opt for a different circle radius, you can avoid doing even more manual work by editing the parameters instead of doing all the laborious changes yourself each time. You're able to build a *procedure* that the computer carries out on your behalf.
|
||||
|
||||
The aforementioned example takes the form of the *Circular Repeat* node:
|
||||
|
||||
<p><img src="https://static.graphite.rs/content/learn/introduction/features-and-limitations/circular-repeat-node.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" onload="this.width /= 2" alt="Circular Repeat node" /></p>
|
||||
|
||||
Nodes are boxes that encode a certain operation (or function) in the procedure that generates your artwork. On the left, this node takes the input of your shape to be duplicated. On the right, the modified data (with the repeated shape) is the output. Links are wired from the outputs of nodes to the inputs of others, left to right, in the *node graph* which can be accessed by clicking this button located in the bottom left corner of the Graphite editor:
|
||||
|
||||
<p><img src="https://static.graphite.rs/content/learn/interface/document-panel/graph-view-button-while-closed.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" alt="Open node graph button" /></p>
|
||||
|
||||
The node's properties give additional controls over settings like *Angle Offset* (what angle to start at), *Radius* (how large the circle pattern should be), and *Count* (how many copies to make):
|
||||
|
||||
<p><img src="https://static.graphite.rs/content/learn/introduction/features-and-limitations/circular-repeat-node-parameters.avif" onerror="this.onerror = null; this.src = this.src.replace('.avif', '.png')" onload="this.width /= 2" alt="Circular Repeat node parameters" /></p>
|
||||
|
||||
|
||||
These parameters can also be exposed into the graph so they are driven by the calculated numerical outputs of other nodes instead of values you pick by hand.
|
||||
|
||||
## Status and limitations
|
||||
|
||||
Please make yourself aware of these factors to better understand and work around the rough edges in today's Graphite editor.
|
||||
|
||||
### Unstable document format
|
||||
|
||||
Artwork you save as a `.graphite` document file will eventually fail to open in future versions of the Graphite editor because of code changes. Since the implementations are in flux for many systems, file format stability isn't possible yet during this alpha stage of development. A redesigned file format with a `.gdd` (Graphite Design Document) extension will replace `.graphite` files and it will be built with backwards-compatability in mind.
|
||||
|
||||
Sometimes an error will appear when opening an outdated document. Other times, it may open but result in a crash or broken functionality when editing. With some technical know-how, it might be possible to manually edit the JSON serialization format, but this is not officially supported.
|
||||
|
||||
<!-- To open an outdated file, [look here](https://github.com/GraphiteEditor/Graphite/deployments/activity_log?environment=graphite-editor+%28Production%29) for the previous version of the Graphite editor that was published before the date you saved the document. Click "View deployment" to open it. -->
|
||||
|
||||
### No vector import
|
||||
|
||||
While you can export your artwork as an SVG file for use elsewhere, there is not support yet for importing an SVG file to be edited.
|
||||
|
||||
### Unstable node graph interactions
|
||||
|
||||
The node graph implementation was completed very recently. There are still a number of bugs and unexpected limitations that can arise. If the graph isn't updating, it may have become invalid. You can check if there are errors by opening the JavaScript console with the <kbd>F12</kbd> key, and if you see node graph evaluation errors, undo your changes to before the unsupported graph edit.
|
||||
|
||||
### No snapping system
|
||||
|
||||
Previous versions of Graphite had a mediocre snapping system for helping you draw with precise alignment between elements in your artwork. To accommodate implementing the node graph, this code had to be removed because it conflicted. An improved version of the feature will be [rebuilt](https://github.com/GraphiteEditor/Graphite/issues/1206) in the near future.
|
||||
|
||||
### Limited Safari support
|
||||
|
||||
Old versions of Safari lack the minimum web standards features Graphite requires to run. The latest version of the browser still won't run Graphite as well as Chrome and you may encounter extra bugs because we have limited resources to regularly test for Safari issues.
|
||||
|
||||
The latest Chrome or Chromium-based browser is recommended for the best-supported experience, although Firefox works with only some minor feature degradations.
|
||||
|
|
@ -7,6 +7,8 @@ title = "Graphite license"
|
|||
|
||||
# Graphite license
|
||||
|
||||
<article>
|
||||
|
||||
Graphite is open source software built by the community. The application is free to use by anyone for any purpose, even commercially. The artwork you produce is solely yours.
|
||||
|
||||
The source code [available on GitHub](https://github.com/GraphiteEditor/Graphite) (including the Graphite editor application, libraries, and other software materials) is provided under the Apache 2.0 license posted below, unless otherwise noted within the repository.
|
||||
|
|
@ -192,5 +194,7 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
</article>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
title = "Graphite logo"
|
||||
|
||||
[extra]
|
||||
css = ["/logo.css"]
|
||||
css = ["logo.css"]
|
||||
+++
|
||||
|
||||
<section class="reading-material">
|
||||
|
|
@ -10,6 +10,8 @@ css = ["/logo.css"]
|
|||
|
||||
# Graphite logo
|
||||
|
||||
<article>
|
||||
|
||||
Graphite's logo is represented by the end of a pencil protruding from a hexagon and drawing a sketch mark.
|
||||
|
||||
The pencil and its streak, composed of the substance graphite, signifies the software's name and its role as a drawing tool and versatile art medium.
|
||||
|
|
@ -33,6 +35,8 @@ If in doubt, please <a href="/contact">get in touch</a> by email to request clar
|
|||
|
||||
Download the complete [logo kit](https://static.graphite.rs/logos/graphite-logo-kit.zip) or a specific version in PNG or SVG format below.
|
||||
|
||||
</article>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ title = "Press resources"
|
|||
|
||||
# Press resources
|
||||
|
||||
<article>
|
||||
|
||||
Materials for journalists and creators looking to share Graphite with their audiences.
|
||||
|
||||
## Contact
|
||||
|
|
@ -19,5 +21,7 @@ Send an email to <contact@graphite.rs> and you can usually expect a quick reply.
|
|||
|
||||
Logos in PNG and SVG format are available for use in articles talking about Graphite. See the [logo](/logo) page for downloads.
|
||||
|
||||
</article>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
title = "Volunteer"
|
||||
|
||||
[extra]
|
||||
css = ["/volunteer.css"]
|
||||
css = ["volunteer.css"]
|
||||
+++
|
||||
|
||||
<section>
|
||||
|
|
@ -10,7 +10,7 @@ css = ["/volunteer.css"]
|
|||
|
||||
# Volunteer
|
||||
|
||||
Graphite is built by volunteers. Join the effort to bring great, free creative software to the world.
|
||||
**Graphite is built by volunteers.** Join the effort to bring great, free creative software to the world.
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ page_template = "book.html"
|
|||
|
||||
[extra]
|
||||
order = 2 # Chapter number
|
||||
js = ["/video-embed.js"]
|
||||
js = ["video-embed.js"]
|
||||
+++
|
||||
|
||||
<div class="video-embed aspect-16x9">
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<meta charset="utf-8">
|
||||
<title>Bezier-rs Interactive Documentation</title>
|
||||
<link rel="stylesheet" href="./style.css">
|
||||
<link rel="preconnect" href="https://rsms.me/">
|
||||
<link rel="stylesheet" href="https://rsms.me/inter/inter.css">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
|
|
|
|||
|
|
@ -25,9 +25,9 @@
|
|||
--font-size-heading-h2: 42px;
|
||||
--font-size-subheading: 24px;
|
||||
--font-size-body: 18px;
|
||||
--font-size-article-h1: 32px;
|
||||
--font-size-article-h2: 24px;
|
||||
--font-size-article-h3: 18px;
|
||||
--font-size-article-h2: 30px;
|
||||
--font-size-article-h3: 24px;
|
||||
--font-size-article-h4: 18px;
|
||||
|
||||
--max-width: 1600px;
|
||||
--max-width-plus-padding: calc(var(--max-width) + 40px * 2);
|
||||
|
|
@ -165,7 +165,8 @@ p ~ p {
|
|||
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
h3,
|
||||
h4 {
|
||||
& ~ p,
|
||||
& ~ ol li p,
|
||||
& ~ img {
|
||||
|
|
@ -177,11 +178,14 @@ h1 ~ .informational-group,
|
|||
p ~ h1,
|
||||
p ~ h2,
|
||||
p ~ h3,
|
||||
p ~ h4,
|
||||
p ~ details summary,
|
||||
p ~ blockquote,
|
||||
p ~ .informational-group,
|
||||
p ~ .image-comparison,
|
||||
p + .link,
|
||||
p + section,
|
||||
p + table,
|
||||
p ~ .video-background,
|
||||
p ~ .video-embed,
|
||||
.video-embed + p,
|
||||
|
|
@ -204,10 +208,25 @@ ol + p {
|
|||
margin-top: 0;
|
||||
}
|
||||
|
||||
li + li {
|
||||
li {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
table {
|
||||
margin: -20px;
|
||||
|
||||
th,
|
||||
td {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
td {
|
||||
vertical-align: top;
|
||||
border: 20px solid transparent;
|
||||
}
|
||||
}
|
||||
|
||||
code {
|
||||
background: var(--color-fog);
|
||||
color: var(--color-black);
|
||||
|
|
@ -333,9 +352,10 @@ kbd {
|
|||
background: var(--color-fog);
|
||||
border-radius: calc(var(--variable-px) * 2);
|
||||
outline: calc(var(--border-thickness) / 2) solid var(--color-navy);
|
||||
padding: 0 4px;
|
||||
padding: 0 8px;
|
||||
margin: 0 4px;
|
||||
color: var(--color-navy);
|
||||
color: inherit;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
summary {
|
||||
|
|
@ -355,22 +375,26 @@ summary {
|
|||
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
h3,
|
||||
h4 {
|
||||
font-family: "Inter", sans-serif;
|
||||
line-height: 1.5;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: var(--font-size-article-h1);
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: var(--font-size-article-h2);
|
||||
margin-top: 80px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: var(--font-size-article-h3);
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: var(--font-size-article-h4);
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
h1,
|
||||
|
|
@ -380,6 +404,10 @@ summary {
|
|||
h5,
|
||||
h6 {
|
||||
display: block;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -480,17 +508,17 @@ summary {
|
|||
position: absolute;
|
||||
width: 6.5px;
|
||||
height: 11px;
|
||||
top: calc(11px / -2);
|
||||
top: calc(-11px / 2);
|
||||
fill: var(--color-white);
|
||||
|
||||
@keyframes pulse-left {
|
||||
from { right: 2px; }
|
||||
to { right: 9px; }
|
||||
from { transform: translateX(3px); }
|
||||
to { transform: translateX(-3px); }
|
||||
}
|
||||
|
||||
@keyframes pulse-right {
|
||||
from { left: 1px; }
|
||||
to { left: 9px; }
|
||||
from { transform: scaleX(-1) translateX(3px); }
|
||||
to { transform: scaleX(-1) translateX(-3px); }
|
||||
}
|
||||
|
||||
@keyframes pulse-opacity {
|
||||
|
|
@ -501,14 +529,13 @@ summary {
|
|||
}
|
||||
|
||||
&:nth-of-type(1) {
|
||||
animation: 3s infinite ease-out pulse-left, 3s infinite ease-out pulse-opacity;
|
||||
right: 6px;
|
||||
animation: 3s infinite ease-out pulse-left, 3s infinite ease-out pulse-opacity;
|
||||
}
|
||||
|
||||
&:nth-of-type(2) {
|
||||
animation: 3s infinite ease-out pulse-right, 3s infinite ease-out pulse-opacity;
|
||||
left: 6px;
|
||||
transform: scaleX(-1);
|
||||
animation: 3s infinite ease-out pulse-right, 3s infinite ease-out pulse-opacity;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -516,7 +543,6 @@ summary {
|
|||
content: "";
|
||||
position: absolute;
|
||||
background: var(--color-navy);
|
||||
// border-radius: 50%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 32px;
|
||||
|
|
@ -671,16 +697,31 @@ summary {
|
|||
}
|
||||
}
|
||||
|
||||
&.center {
|
||||
.screenshot-details {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
&.window-size-1 .carousel-slide img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&.window-size-2 .carousel-slide img {
|
||||
width: calc(100% / 2);
|
||||
width: calc((100% / 2) - 10px);
|
||||
padding: 0 10px;
|
||||
|
||||
&:first-child {
|
||||
margin-left: -10px;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: -10px;
|
||||
}
|
||||
}
|
||||
|
||||
&.window-size-3 .carousel-slide img {
|
||||
width: calc((100% + 2 * 10px) / 3 - (3 - 1) * 10px);
|
||||
width: calc((100% / 3) - 10px * (4 / 3));
|
||||
padding: 0 10px;
|
||||
|
||||
&:first-child {
|
||||
|
|
@ -1010,256 +1051,257 @@ body > .page {
|
|||
box-sizing: border-box;
|
||||
min-width: 320px;
|
||||
|
||||
header {
|
||||
padding: 0 var(--page-edge-padding);
|
||||
color: var(--color-walnut);
|
||||
position: relative;
|
||||
z-index: 1000;
|
||||
header {
|
||||
padding: 0 var(--page-edge-padding);
|
||||
color: var(--color-walnut);
|
||||
position: relative;
|
||||
z-index: 1000;
|
||||
|
||||
nav {
|
||||
margin: auto;
|
||||
max-width: var(--max-width);
|
||||
nav {
|
||||
margin: auto;
|
||||
max-width: var(--max-width);
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
--nav-padding-above-below: 30px;
|
||||
padding-top: var(--nav-padding-above-below);
|
||||
padding-bottom: calc(var(--nav-padding-above-below) - 16px);
|
||||
margin-bottom: calc(var(--nav-padding-above-below) - 16px);
|
||||
// Covers up content that extends up underneath the header
|
||||
background: white;
|
||||
|
||||
@media screen and (max-width: 760px) {
|
||||
--nav-padding-above-below: 24px;
|
||||
}
|
||||
|
||||
.left,
|
||||
.right {
|
||||
z-index: 1;
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 40px;
|
||||
justify-content: space-between;
|
||||
--nav-padding-above-below: 30px;
|
||||
padding-top: var(--nav-padding-above-below);
|
||||
padding-bottom: calc(var(--nav-padding-above-below) - 16px);
|
||||
margin-bottom: calc(var(--nav-padding-above-below) - 16px);
|
||||
// Covers up content that extends up underneath the header
|
||||
background: white;
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
font-family: "Bona Nova", Palatino, serif;
|
||||
font-feature-settings: "lnum";
|
||||
line-height: 1.25;
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
--height: 60px;
|
||||
--button-padding: 24px;
|
||||
--nav-font-size: 28px; // Keep up to date with `NAV_BUTTON_INITIAL_FONT_SIZE` in navbar.js
|
||||
font-size: var(--nav-font-size);
|
||||
@media screen and (max-width: 760px) {
|
||||
--nav-padding-above-below: 24px;
|
||||
}
|
||||
|
||||
&.button.button {
|
||||
height: var(--height);
|
||||
padding-left: var(--button-padding);
|
||||
padding-right: var(--button-padding);
|
||||
line-height: calc(var(--height) - 2 * var(--border-thickness));
|
||||
.left,
|
||||
.right {
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 40px;
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
font-family: "Bona Nova", Palatino, serif;
|
||||
font-feature-settings: "lnum";
|
||||
line-height: 1.25;
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
--height: 60px;
|
||||
--button-padding: 24px;
|
||||
--nav-font-size: 28px; // Keep up to date with `NAV_BUTTON_INITIAL_FONT_SIZE` in navbar.js
|
||||
font-size: var(--nav-font-size);
|
||||
|
||||
&.button.button {
|
||||
height: var(--height);
|
||||
padding-left: var(--button-padding);
|
||||
padding-right: var(--button-padding);
|
||||
line-height: calc(var(--height) - 2 * var(--border-thickness));
|
||||
font-size: var(--nav-font-size);
|
||||
}
|
||||
|
||||
img {
|
||||
display: block;
|
||||
width: var(--height);
|
||||
height: var(--height);
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
display: block;
|
||||
width: var(--height);
|
||||
height: var(--height);
|
||||
&.left img {
|
||||
// Don't show the alt text if the image doesn't load
|
||||
font-size: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.left img {
|
||||
// Don't show the alt text if the image doesn't load
|
||||
font-size: 0;
|
||||
}
|
||||
@media screen and (max-width: 1200px) {
|
||||
gap: 30px;
|
||||
|
||||
@media screen and (max-width: 1200px) {
|
||||
gap: 30px;
|
||||
|
||||
a {
|
||||
--height: 50px;
|
||||
--button-padding: 16px;
|
||||
--nav-font-size: 24px;
|
||||
a {
|
||||
--height: 50px;
|
||||
--button-padding: 16px;
|
||||
--nav-font-size: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 960px) {
|
||||
gap: 30px;
|
||||
@media screen and (max-width: 960px) {
|
||||
gap: 30px;
|
||||
|
||||
a {
|
||||
--height: 50px;
|
||||
--button-padding: 16px;
|
||||
--nav-font-size: 20px;
|
||||
a {
|
||||
--height: 50px;
|
||||
--button-padding: 16px;
|
||||
--nav-font-size: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 880px) {
|
||||
gap: 20px;
|
||||
@media screen and (max-width: 880px) {
|
||||
gap: 20px;
|
||||
|
||||
a {
|
||||
--height: 40px;
|
||||
--button-padding: 12px;
|
||||
--nav-font-size: 16px;
|
||||
a {
|
||||
--height: 40px;
|
||||
--button-padding: 12px;
|
||||
--nav-font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 680px) {
|
||||
gap: 16px;
|
||||
@media screen and (max-width: 680px) {
|
||||
gap: 16px;
|
||||
|
||||
a {
|
||||
--height: 30px;
|
||||
--button-padding: 8px;
|
||||
--nav-font-size: 14px;
|
||||
a {
|
||||
--height: 30px;
|
||||
--button-padding: 8px;
|
||||
--nav-font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
gap: 12px;
|
||||
@media screen and (max-width: 600px) {
|
||||
gap: 12px;
|
||||
|
||||
a {
|
||||
--height: 24px;
|
||||
--button-padding: 8px;
|
||||
--nav-font-size: 13px;
|
||||
a {
|
||||
--height: 24px;
|
||||
--button-padding: 8px;
|
||||
--nav-font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 540px) {
|
||||
gap: 10px;
|
||||
@media screen and (max-width: 540px) {
|
||||
gap: 10px;
|
||||
|
||||
a {
|
||||
--height: 22px;
|
||||
--button-padding: 6px;
|
||||
--nav-font-size: 12px;
|
||||
a {
|
||||
--height: 22px;
|
||||
--button-padding: 6px;
|
||||
--nav-font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
gap: 8px;
|
||||
@media screen and (max-width: 480px) {
|
||||
gap: 8px;
|
||||
|
||||
a {
|
||||
--height: 20px;
|
||||
--button-padding: 4px;
|
||||
--nav-font-size: 11px;
|
||||
a {
|
||||
--height: 20px;
|
||||
--button-padding: 4px;
|
||||
--nav-font-size: 11px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 430px) {
|
||||
gap: 6px;
|
||||
@media screen and (max-width: 430px) {
|
||||
gap: 6px;
|
||||
|
||||
a {
|
||||
--height: 20px;
|
||||
--button-padding: 4px;
|
||||
--nav-font-size: 10px;
|
||||
a {
|
||||
--height: 20px;
|
||||
--button-padding: 4px;
|
||||
--nav-font-size: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ripple {
|
||||
display: block;
|
||||
background: none;
|
||||
// Covers up content that extends up underneath the header
|
||||
fill: white;
|
||||
stroke: currentColor;
|
||||
--ripple-height: 16px;
|
||||
height: var(--ripple-height);
|
||||
margin-top: calc(-1 * var(--ripple-height) + var(--border-thickness));
|
||||
margin-bottom: calc(-1 * var(--border-thickness));
|
||||
stroke-width: var(--border-thickness);
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
content: none;
|
||||
}
|
||||
}
|
||||
|
||||
hr {
|
||||
background: none;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1824px) {
|
||||
.ripple {
|
||||
width: calc(100% + (var(--page-edge-padding) * 2));
|
||||
margin-left: calc(-1 * var(--page-edge-padding));
|
||||
margin-right: calc(-1 * var(--page-edge-padding));
|
||||
display: block;
|
||||
background: none;
|
||||
// Covers up content that extends up underneath the header
|
||||
fill: white;
|
||||
stroke: currentColor;
|
||||
--ripple-height: 16px;
|
||||
height: var(--ripple-height);
|
||||
margin-top: calc(-1 * var(--ripple-height) + var(--border-thickness));
|
||||
margin-bottom: calc(-1 * var(--border-thickness));
|
||||
stroke-width: var(--border-thickness);
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
content: none;
|
||||
}
|
||||
}
|
||||
|
||||
hr {
|
||||
display: none;
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main {
|
||||
padding: 0 var(--page-edge-padding);
|
||||
|
||||
.content {
|
||||
padding: calc(120 * var(--variable-px)) 0;
|
||||
|
||||
section {
|
||||
max-width: var(--max-width);
|
||||
margin: 0 auto;
|
||||
// Puts the content in front of the hexagon decoration
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
~ section {
|
||||
margin-top: calc(120 * var(--variable-px));
|
||||
@media screen and (max-width: 1824px) {
|
||||
.ripple {
|
||||
width: calc(100% + (var(--page-edge-padding) * 2));
|
||||
margin-left: calc(-1 * var(--page-edge-padding));
|
||||
margin-right: calc(-1 * var(--page-edge-padding));
|
||||
}
|
||||
|
||||
p img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
pre {
|
||||
box-sizing: border-box;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
details {
|
||||
width: 100%;
|
||||
hr {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
footer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 40px;
|
||||
padding: 40px;
|
||||
padding-top: 0;
|
||||
color: var(--color-walnut);
|
||||
main {
|
||||
padding: 0 var(--page-edge-padding);
|
||||
|
||||
nav {
|
||||
.content {
|
||||
padding: calc(120 * var(--variable-px)) 0;
|
||||
|
||||
section {
|
||||
max-width: var(--max-width);
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
// Puts the content in front of the hexagon decoration
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
~ section {
|
||||
margin-top: calc(120 * var(--variable-px));
|
||||
}
|
||||
|
||||
p img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
pre {
|
||||
box-sizing: border-box;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
details {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
footer {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 8px 40px;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 40px;
|
||||
padding: 40px;
|
||||
padding-top: 0;
|
||||
color: var(--color-walnut);
|
||||
|
||||
a {
|
||||
color: var(--color-walnut);
|
||||
nav {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 8px 40px;
|
||||
|
||||
a {
|
||||
color: var(--color-walnut);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 900px) {
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 760px) {
|
||||
max-width: 440px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 400px) {
|
||||
gap: 6px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 900px) {
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 760px) {
|
||||
max-width: 440px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 400px) {
|
||||
gap: 6px 20px;
|
||||
span {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.fundraising {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,10 @@
|
|||
width: 800px;
|
||||
flex: 1 2 100%;
|
||||
|
||||
article {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.prev-next {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
|
@ -39,6 +43,11 @@
|
|||
|
||||
svg {
|
||||
fill: var(--color-navy);
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
&:last-of-type {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -159,9 +168,6 @@
|
|||
|
||||
li {
|
||||
margin-top: 0.5em;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
|
||||
a {
|
||||
color: var(--color-walnut);
|
||||
|
|
@ -187,6 +193,12 @@
|
|||
li.active a {
|
||||
color: var(--color-ale);
|
||||
}
|
||||
|
||||
ul a {
|
||||
display: block;
|
||||
padding-left: 1em;
|
||||
text-indent: -1em;
|
||||
}
|
||||
}
|
||||
|
||||
&.contents {
|
||||
|
|
@ -218,19 +230,19 @@
|
|||
|
||||
ul {
|
||||
margin-top: 0;
|
||||
text-indent: 1em;
|
||||
margin-left: 1em;
|
||||
|
||||
ul {
|
||||
text-indent: 2em;
|
||||
margin-left: 2em;
|
||||
|
||||
ul {
|
||||
text-indent: 3em;
|
||||
margin-left: 3em;
|
||||
|
||||
ul {
|
||||
text-indent: 4em;
|
||||
margin-left: 4em;
|
||||
|
||||
ul {
|
||||
text-indent: 5em;
|
||||
margin-left: 5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
.page {
|
||||
// Prevents horizontal scrollbars from appearing on the page.
|
||||
// This happens because of the masked (but not overflow: hidden) carousel images.
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
{% block rss %}
|
||||
<link rel="alternate" type="application/rss+xml" title="RSS" href="{{ get_url(path = 'blog/rss.xml', trailing_slash = false) }}">
|
||||
{% endblock %}
|
||||
<link rel="preconnect" href="https://rsms.me/">
|
||||
<link rel="stylesheet" href="https://rsms.me/inter/inter.css">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
|
|
@ -16,7 +17,7 @@
|
|||
<link rel="stylesheet" href="/syntax-highlighting.css">
|
||||
{% if this and this.extra.css %}
|
||||
{% for css in this.extra.css %}
|
||||
<link rel="stylesheet" href="{{ css | safe }}">
|
||||
<link rel="stylesheet" href="/{{ css | safe }}">
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% block head %}{% endblock head %}
|
||||
|
|
@ -60,7 +61,7 @@
|
|||
</a>
|
||||
</div>
|
||||
<div class="right">
|
||||
<!-- <a href="/learn">Learn</a> -->
|
||||
<a href="/learn">Learn</a>
|
||||
<a href="/features">Features</a>
|
||||
<a href="/about">About</a>
|
||||
<a href="/blog">Blog</a>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue