docs: establish canonical Spatial Canvas documentation
This commit is contained in:
parent
170bc7796b
commit
eeba4b7ac7
15 changed files with 452 additions and 510 deletions
34
CHANGELOG.md
34
CHANGELOG.md
|
|
@ -2,30 +2,20 @@
|
|||
|
||||
## Unreleased
|
||||
|
||||
### Added
|
||||
### Documentation
|
||||
|
||||
- native Mosaic / Spatial Canvas layout foundation;
|
||||
- workspace-local Mosaic state;
|
||||
- real tiled Row 0 backed by the Sway tree;
|
||||
- insertion/reflow/focus model tests;
|
||||
- `layout mosaic` support;
|
||||
- workspace-local `layout toggle mosaic`;
|
||||
- logical row scrolling and first viewport translation;
|
||||
- Mosaic IPC state in `get_tree`;
|
||||
- headless compositor validation;
|
||||
- isolated Arch packaging path for `/usr/bin/swayfx-mosaic`;
|
||||
- architecture, development, upstream and roadmap documentation.
|
||||
- Established a public landing page, original source-controlled SVG banner, canonical documentation index, UX contract, packaging contract, known limitations, and documentation-first roadmap.
|
||||
- Clarified the current single-row implementation, historical STEP evidence, package coexistence, and upstream forward-port policy.
|
||||
|
||||
### Safety
|
||||
### Existing implementation
|
||||
|
||||
- ordinary SwayFX remains installed separately and untouched;
|
||||
- no automatic session replacement;
|
||||
- no package `conflicts`, `replaces` or `provides` against SwayFX.
|
||||
- Native Mosaic layout with workspace-local state and real tiled Row 0.
|
||||
- Insertion/reflow/focus model tests and `layout mosaic` command.
|
||||
- Workspace-local `layout toggle mosaic`, logical scrolling, and first viewport scene translation.
|
||||
- Mosaic `get_tree` IPC state and headless compositor validation.
|
||||
- Isolated Arch packaging path for `/usr/bin/swayfx-mosaic`.
|
||||
|
||||
### Known limitations
|
||||
### Safety and limitations
|
||||
|
||||
- multi-output viewport clipping is not yet production-ready;
|
||||
- multi-row Canvas behavior is not implemented;
|
||||
- camera animation is not final;
|
||||
- Session V2 does not yet restore Mosaic state;
|
||||
- the final cell sizing/reflow policy is not frozen.
|
||||
- Ordinary SwayFX remains separately installed and independently updatable; no automatic session replacement.
|
||||
- Multi-output clipping, multiple runtime rows, camera animation, Session V2 restore, final cell sizing, and daily-driver qualification remain open. See [known limitations](docs/KNOWN_LIMITATIONS.md).
|
||||
|
|
|
|||
|
|
@ -1,54 +1,14 @@
|
|||
# Contributing
|
||||
|
||||
SwayFX Mosaic is experimental compositor work. Changes should stay narrowly focused on the Mosaic / Spatial Canvas layout and its packaging/tests.
|
||||
SwayFX Mosaic is an experimental native layout. Keep contributions within Mosaic behavior, its validation, documentation, patch maintenance, and isolated packaging. Unrelated SwayFX customization, personal dotfiles, QuickShell UI, and desktop themes are outside this repository's current scope.
|
||||
|
||||
## Before changing code
|
||||
## Contribution flow
|
||||
|
||||
Read:
|
||||
- `README.md`
|
||||
- `docs/ARCHITECTURE.md`
|
||||
- `docs/DEVELOPMENT.md`
|
||||
- `docs/UPSTREAM.md`
|
||||
1. Read the [documentation index](docs/README.md), [architecture](docs/ARCHITECTURE.md), and [known limitations](docs/KNOWN_LIMITATIONS.md).
|
||||
2. Document a user-visible change in [UX](docs/UX.md) and an architecture change in [Architecture](docs/ARCHITECTURE.md) **before** implementation. Packaging changes update [Packaging](docs/PACKAGING.md); upstream changes update [Upstream](docs/UPSTREAM.md).
|
||||
3. Keep the source delta focused on Mosaic and preserve real Sway containers, standard layouts, and package coexistence.
|
||||
4. Add tests that exercise changed production behavior. Run the relevant build, Meson tests, headless compositor tests, and `git diff --check` as described in [Development](docs/DEVELOPMENT.md).
|
||||
5. Report failed tests and unresolved limitations plainly. Never hide a failure or force-apply a patch to a new upstream revision.
|
||||
6. Submit a reviewable change with its contract, validation evidence, and scope. The [Forgejo repository](https://git.labfytools.com/fy59/swayfx-mosaic) is canonical; GitHub is a public mirror.
|
||||
|
||||
## Scope
|
||||
|
||||
Appropriate contributions include:
|
||||
- Mosaic layout model;
|
||||
- geometry, viewport and scene behavior;
|
||||
- focus/input behavior required by Mosaic;
|
||||
- IPC additions required to expose Mosaic state;
|
||||
- Mosaic tests;
|
||||
- patch maintenance and packaging.
|
||||
|
||||
Desktop shell features, themes, personal key bindings and unrelated SwayFX customizations belong elsewhere.
|
||||
|
||||
## Required checks
|
||||
|
||||
At minimum:
|
||||
|
||||
```sh
|
||||
meson compile -C build-mosaic -j 8
|
||||
meson test -C build-mosaic --print-errorlogs
|
||||
python tests/headless-ipc.py
|
||||
git diff --check
|
||||
```
|
||||
|
||||
For upstream rebases, also rebuild the pristine baseline and validate the standard Sway layouts.
|
||||
|
||||
## Compatibility
|
||||
|
||||
Do not introduce a package conflict with ordinary `swayfx`.
|
||||
|
||||
Do not install over `/usr/bin/sway`.
|
||||
|
||||
Do not treat QuickShell or an external daemon as the authoritative Mosaic state store.
|
||||
|
||||
## Commits
|
||||
|
||||
Keep commits reviewable and explain:
|
||||
- the compositor invariant being changed;
|
||||
- why the change belongs in Mosaic;
|
||||
- the validation performed;
|
||||
- any known limitation.
|
||||
|
||||
Never hide failed tests or force-apply the Mosaic patch to an unvalidated upstream revision.
|
||||
Do not install over `/usr/bin/sway` or make `swayfx-mosaic` conflict with ordinary SwayFX.
|
||||
|
|
|
|||
15
NOTICE.md
15
NOTICE.md
|
|
@ -1,14 +1,7 @@
|
|||
# Notice
|
||||
# Notice and attribution
|
||||
|
||||
SwayFX Mosaic is a derivative development project based on SwayFX and Sway.
|
||||
SwayFX Mosaic is an independent derivative development project based on [SwayFX](https://github.com/WillPower3309/swayfx) and [Sway](https://github.com/swaywm/sway). It is not affiliated with or endorsed by their maintainers.
|
||||
|
||||
- SwayFX: https://github.com/WillPower3309/swayfx
|
||||
- Sway: https://github.com/swaywm/sway
|
||||
The repository retains the upstream MIT license in [LICENSE](LICENSE). Inherited source and assets remain subject to their existing notices and attribution. Mosaic-specific work adds an experimental native Spatial Canvas layout, state/IPC handling, tests, documentation, and isolated packaging; it does not claim ownership of the inherited SwayFX or Sway codebase.
|
||||
|
||||
The repository retains the upstream MIT license in `LICENSE`.
|
||||
|
||||
The Mosaic-specific work adds an experimental Spatial Canvas layout, associated IPC/state handling, tests and packaging. It does not claim ownership of the Sway/SwayFX codebase or assets inherited from upstream.
|
||||
|
||||
Project repositories:
|
||||
- https://git.labfytools.com/fy59/swayfx-mosaic
|
||||
- https://github.com/labfytools/swayfx-mosaic
|
||||
The [Forgejo repository](https://git.labfytools.com/fy59/swayfx-mosaic) is canonical. The [GitHub repository](https://github.com/labfytools/swayfx-mosaic) is its public mirror. See [upstream maintenance](docs/UPSTREAM.md) for the exact base and remote policy.
|
||||
|
|
|
|||
210
README.md
210
README.md
|
|
@ -1,162 +1,128 @@
|
|||
# SwayFX Mosaic
|
||||
<p align="center">
|
||||
<img src="docs/assets/swayfx-mosaic-banner.svg" alt="SwayFX Mosaic: tiled rows extend beyond a lavender viewport frame on a logical canvas" width="100%">
|
||||
</p>
|
||||
|
||||
**SwayFX Mosaic** is an experimental SwayFX variant that adds a native **Mosaic / Spatial Canvas** tiling layout.
|
||||
<h1 align="center">SwayFX Mosaic</h1>
|
||||
|
||||
The goal is not to replace SwayFX, reimplement tiling in userspace, or turn the desktop into a floating-window canvas. Mosaic stays inside the compositor and keeps real Sway containers, workspaces, IPC, fullscreen, floating windows and scratchpad semantics.
|
||||
<p align="center">Native Spatial Canvas layout for SwayFX.</p>
|
||||
|
||||
> Status: active development. The compositor is not installed as the daily SwayFX session yet.
|
||||
<p align="center">
|
||||
<img alt="SwayFX 0.6 base" src="https://img.shields.io/badge/SwayFX-0.6%20base-cba6f7?style=flat-square">
|
||||
<img alt="C and Wayland" src="https://img.shields.io/badge/C%20%2F%20Wayland-native-89b4fa?style=flat-square">
|
||||
<img alt="Experimental" src="https://img.shields.io/badge/status-experimental-f9e2af?style=flat-square">
|
||||
<a href="LICENSE"><img alt="MIT license" src="https://img.shields.io/badge/license-MIT-a6e3a1?style=flat-square"></a>
|
||||
</p>
|
||||
|
||||
## Why Mosaic?
|
||||
<p align="center">
|
||||
<a href="#overview">Overview</a> · <a href="#the-idea">Concept</a> · <a href="#current-status">Status</a> · <a href="#architecture">Architecture</a> · <a href="#layout-switching">Usage</a> · <a href="#development">Development</a> · <a href="#documentation">Documentation</a> · <a href="docs/ROADMAP.md">Roadmap</a>
|
||||
</p>
|
||||
|
||||
Classic tiling is constrained by the physical viewport. Mosaic introduces a logical canvas made of horizontal rows that may extend beyond the visible output.
|
||||
## Overview
|
||||
|
||||
SwayFX Mosaic adds an experimental **native Spatial Canvas layout** to [SwayFX](https://github.com/WillPower3309/swayfx). A tiled row can extend beyond the physical viewport while the compositor remains authoritative for geometry, focus, input, and state.
|
||||
|
||||
Windows remain real Sway tiled containers. Mosaic is neither a floating-window simulation nor a QuickShell layout engine. It exists because a spatial layout needs the compositor's tiling tree, transactions, scene, and input model. The current implementation is a development foundation, not a validated daily-driver session.
|
||||
|
||||
## The idea
|
||||
|
||||
```text
|
||||
Workspace
|
||||
└── Mosaic Canvas
|
||||
├── Row 0: [A][B][C][D]...
|
||||
├── Row 1: [E][F][G]...
|
||||
└── ...
|
||||
Logical workspace / Row 0
|
||||
[A][B][C][D][E]...
|
||||
└── visible viewport ──┘
|
||||
|
||||
Future rows
|
||||
[F][G][H][I]... [J][K]...
|
||||
```
|
||||
|
||||
Each row owns its viewport position and last focused container. The compositor remains the source of truth for order, geometry, focus and scrolling.
|
||||
A workspace contains a Canvas; the intended Canvas contains ordered rows, each with tiled containers, a camera position (`scroll_x`), and remembered focus. **Logical order** says which container follows which. **Geometry** gives each container a logical rectangle. The **viewport** shows part of that geometry. **Focus** selects the active container and may move the viewport without changing order. Only Row 0 is connected to runtime layout today.
|
||||
|
||||
## Core rules
|
||||
## Why the compositor?
|
||||
|
||||
- real tiled Sway containers; no floating-window simulation;
|
||||
- Mosaic is opt-in per workspace;
|
||||
- standard Sway/SwayFX layouts remain available;
|
||||
- workspaces continue to exist normally;
|
||||
- Mosaic state lives in the compositor, not in QuickShell;
|
||||
- the standard `swayfx` package must remain untouched and independently updatable;
|
||||
- the Mosaic package installs a separate `/usr/bin/swayfx-mosaic` binary;
|
||||
- our production artifact is a minimal, reviewable patch on a pinned SwayFX upstream revision.
|
||||
Fake workspaces, all-floating windows, and a `swaymsg` repositioning daemon would make a second layout authority. QuickShell can visualize Mosaic later, but does not own layout. SwayFX has no stable external layout plugin ABI; injecting a runtime `.so` is not this project's model. Mosaic belongs in the compositor because it already owns tiling, transactions, rendering, focus, and input.
|
||||
|
||||
## Package model
|
||||
## Current status
|
||||
|
||||
```text
|
||||
swayfx
|
||||
└── /usr/bin/sway
|
||||
`CURRENT` means present in the development tree; `EXPERIMENTAL` means present but not validated for general use. See [known limitations](docs/KNOWN_LIMITATIONS.md).
|
||||
|
||||
swayfx-mosaic
|
||||
└── /usr/bin/swayfx-mosaic
|
||||
```
|
||||
|
||||
`swayfx-mosaic` must not declare `provides`, `conflicts` or `replaces` against SwayFX. An upstream SwayFX update must never be blocked by this project.
|
||||
|
||||
The Arch packaging path is intentionally patch-based:
|
||||
|
||||
```text
|
||||
pinned SwayFX upstream
|
||||
+
|
||||
Mosaic patch set
|
||||
↓
|
||||
/usr/bin/swayfx-mosaic
|
||||
```
|
||||
|
||||
See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) and [docs/UPSTREAM.md](docs/UPSTREAM.md).
|
||||
| Capability | Status |
|
||||
| --- | --- |
|
||||
| Native Mosaic layout and real Sway tiled containers | CURRENT |
|
||||
| Single runtime row with logical canvas geometry | EXPERIMENTAL |
|
||||
| Standard ↔ Mosaic toggle with workspace-local restore | CURRENT |
|
||||
| Logical horizontal scroll and first scene translation | EXPERIMENTAL |
|
||||
| Mosaic state in `get_tree` IPC | CURRENT |
|
||||
| Model and headless compositor tests | CURRENT |
|
||||
| Safe multi-output viewport clipping and camera animation | PLANNED |
|
||||
| Multiple runtime rows and row navigation | PLANNED |
|
||||
| Session V2 restoration and QuickShell visualization | PLANNED |
|
||||
| Daily-driver deployment | NOT YET SUPPORTED |
|
||||
|
||||
## Layout switching
|
||||
|
||||
The target desktop contract is:
|
||||
The compositor accepts `layout mosaic`, `layout toggle mosaic`, and experimental `layout mosaic scroll <signed pixels>`. The intended desktop bindings are **Super + Alt + L** for Standard ↔ Mosaic and **Super + Alt + M** for Applications. These bindings live in the user's dotfiles; this package supplies neither key bindings nor an application launcher.
|
||||
|
||||
The toggle remembers the previous standard layout on each workspace: `splith → mosaic → splith`, `tabbed → mosaic → tabbed`, and `stacking → mosaic → stacking`. Mosaic is a layout *inside* a Sway workspace, not a replacement for workspaces.
|
||||
|
||||
## Package isolation
|
||||
|
||||
```text
|
||||
Super + Alt + M → Applications
|
||||
Super + Alt + L → Standard layout ↔ Mosaic
|
||||
swayfx → /usr/bin/sway
|
||||
swayfx-mosaic → /usr/bin/swayfx-mosaic
|
||||
```
|
||||
|
||||
The compositor command is:
|
||||
Normal SwayFX remains installed, receives updates independently, and remains the fallback session. Mosaic does not overwrite `/usr/bin/sway` or declare that it replaces SwayFX. Since SwayFX has no stable external layout plugin ABI, the package builds a compositor variant from a pinned upstream revision plus the Mosaic patch. **Separate package does not mean runtime plugin.** See the [packaging contract](docs/PACKAGING.md).
|
||||
|
||||
```text
|
||||
layout toggle mosaic
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
U[SwayFX 0.6 source] --> S[Standard SwayFX package]
|
||||
U --> P[Mosaic patch]
|
||||
P --> M[swayfx-mosaic binary]
|
||||
M --> T[Sway tree]
|
||||
T --> L[Mosaic logical geometry]
|
||||
L --> X[Transactions and scene translation]
|
||||
X --> V[Output viewport]
|
||||
```
|
||||
|
||||
Each workspace remembers its previous standard layout, so a toggle behaves conceptually like:
|
||||
|
||||
```text
|
||||
tabbed → mosaic → tabbed
|
||||
splith → mosaic → splith
|
||||
```
|
||||
|
||||
The key binding itself belongs to the user's dotfiles, not to this package.
|
||||
|
||||
## Current implementation
|
||||
|
||||
The current development tree contains the native Mosaic foundation and the first single-row viewport work:
|
||||
|
||||
- native `L_MOSAIC` layout;
|
||||
- workspace-local Mosaic state;
|
||||
- ordered Row 0 backed by real `workspace->tiling` containers;
|
||||
- insertion after the active container;
|
||||
- workspace-local previous-layout memory;
|
||||
- `layout toggle mosaic`;
|
||||
- logical `scroll_x`;
|
||||
- first scene translation / single-row viewport implementation;
|
||||
- IPC exposure through `get_tree`;
|
||||
- model and headless compositor tests;
|
||||
- Arch package staging limited to `swayfx-mosaic`.
|
||||
|
||||
Multi-row behavior, robust multi-output clipping, final sizing policy, camera animation and session restore integration are still development work.
|
||||
|
||||
Technical reports:
|
||||
- [STEP20A — native foundation](docs/STEP20A.md)
|
||||
- [STEP20B — first scrollable row](docs/STEP20B.md)
|
||||
The compositor is the runtime source of truth. [Architecture](docs/ARCHITECTURE.md) explains state ownership, transactions, IPC, and the unresolved multi-output boundary.
|
||||
|
||||
## Development
|
||||
|
||||
Baseline:
|
||||
This repository is for development and headless testing. A typical Mosaic build uses a separate build directory:
|
||||
|
||||
```sh
|
||||
meson setup build-baseline -Dwerror=false -Dsd-bus-provider=libsystemd
|
||||
meson compile -C build-baseline
|
||||
```
|
||||
|
||||
Mosaic build:
|
||||
|
||||
```sh
|
||||
meson setup build-mosaic \
|
||||
-Dwerror=false \
|
||||
-Dsd-bus-provider=libsystemd \
|
||||
-Dmosaic-package=true \
|
||||
-Dprefix=/usr -Dbindir=bin \
|
||||
-Dswaybar=false -Dswaynag=false \
|
||||
-Dman-pages=disabled -Ddefault-wallpaper=false
|
||||
|
||||
meson setup build-mosaic -Dwerror=false -Dsd-bus-provider=libsystemd -Dmosaic-package=true -Dprefix=/usr -Dbindir=bin -Dswaybar=false -Dswaynag=false -Dman-pages=disabled -Ddefault-wallpaper=false
|
||||
meson compile -C build-mosaic
|
||||
meson test -C build-mosaic --print-errorlogs
|
||||
python tests/headless-ipc.py
|
||||
```
|
||||
|
||||
See [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md) for the full workflow.
|
||||
These commands do not install or switch the active session. See [Development](docs/DEVELOPMENT.md) for prerequisites, baseline validation, staging, and package checks.
|
||||
|
||||
## Repository layout
|
||||
## Documentation
|
||||
|
||||
```text
|
||||
docs/ design, roadmap and validation reports
|
||||
patches/ production delta against pinned SwayFX
|
||||
tests/ Mosaic model and headless compositor tests
|
||||
tooling/ patch/export maintenance helpers
|
||||
PKGBUILD coexistence-oriented Arch package
|
||||
```
|
||||
|
||||
The full SwayFX source remains in the development tree for compositor work. The patch set is the reviewable production delta.
|
||||
|
||||
## Upstream and license
|
||||
|
||||
SwayFX Mosaic is derived from [SwayFX](https://github.com/WillPower3309/swayfx), itself based on [Sway](https://github.com/swaywm/sway).
|
||||
|
||||
Current base:
|
||||
- SwayFX tag `0.6`;
|
||||
- commit `fd71a6bdc061bd633b488ae7b83e8a6981d22f86`;
|
||||
- Sway 1.12.0 base;
|
||||
- wlroots 0.20 series;
|
||||
- SceneFX 0.5 series.
|
||||
|
||||
The project keeps the upstream MIT license. See [LICENSE](LICENSE) and [NOTICE.md](NOTICE.md).
|
||||
| Document | Purpose |
|
||||
| --- | --- |
|
||||
| [Documentation index](docs/README.md) | Canonical map and source-of-truth hierarchy |
|
||||
| [Architecture](docs/ARCHITECTURE.md) | Runtime state, scene, IPC, boundaries |
|
||||
| [UX contract](docs/UX.md) | Interaction rules and open decisions |
|
||||
| [Packaging](docs/PACKAGING.md) | Coexistence and Arch package contract |
|
||||
| [Upstream maintenance](docs/UPSTREAM.md) | Pinning and forward-port policy |
|
||||
| [Development](docs/DEVELOPMENT.md) | Reproducible build and validation workflow |
|
||||
| [Known limitations](docs/KNOWN_LIMITATIONS.md) | Unsupported or unvalidated behavior |
|
||||
| [Roadmap](docs/ROADMAP.md) | Ordered steps and exit criteria |
|
||||
| [STEP20A](docs/STEP20A.md) · [STEP20B](docs/STEP20B.md) | Historical implementation evidence |
|
||||
| [Changelog](CHANGELOG.md) · [Contributing](CONTRIBUTING.md) | Evolution and contribution rules |
|
||||
|
||||
## Mirrors
|
||||
|
||||
Canonical development repository:
|
||||
- Forgejo: `https://git.labfytools.com/fy59/swayfx-mosaic`
|
||||
| Role | Repository |
|
||||
| --- | --- |
|
||||
| Canonical | [Forgejo](https://git.labfytools.com/fy59/swayfx-mosaic) |
|
||||
| Public mirror | [GitHub](https://github.com/labfytools/swayfx-mosaic) |
|
||||
| Upstream base, fetch only | [SwayFX](https://github.com/WillPower3309/swayfx) |
|
||||
|
||||
Public mirror:
|
||||
- GitHub: `https://github.com/labfytools/swayfx-mosaic`
|
||||
## License and attribution
|
||||
|
||||
This independent project derives from SwayFX and Sway and retains the MIT license. It is not endorsed by their maintainers. See [LICENSE](LICENSE), [NOTICE.md](NOTICE.md), and [upstream maintenance](docs/UPSTREAM.md).
|
||||
|
|
|
|||
|
|
@ -1,133 +1,68 @@
|
|||
# Architecture
|
||||
|
||||
## Scope
|
||||
This is the canonical technical contract for SwayFX Mosaic. The current implementation is an experimental single-row compositor layout. [UX](UX.md) specifies user-visible behavior; [known limitations](KNOWN_LIMITATIONS.md) identifies unvalidated boundaries.
|
||||
|
||||
Mosaic / Spatial Canvas is an additional native SwayFX layout. It is not a separate window manager model layered above IPC and it is not a QuickShell feature.
|
||||
## Scope and authority
|
||||
|
||||
The compositor owns:
|
||||
- container order;
|
||||
- row membership;
|
||||
- logical geometry;
|
||||
- active row;
|
||||
- per-row scroll position;
|
||||
- per-row focus memory;
|
||||
- scene translation;
|
||||
- hit testing consistency.
|
||||
| System | Responsibility |
|
||||
| --- | --- |
|
||||
| SwayFX Mosaic compositor | Runtime order, geometry, focus, camera, scene, input, transactions, IPC |
|
||||
| User dotfiles | Session selection and personal key bindings |
|
||||
| QuickShell | Future visualization and controls through compositor IPC; never a layout authority |
|
||||
| Session V2 | Future persistence/restoration helper; never a parallel runtime authority |
|
||||
| SwayFX upstream | Base compositor and standard SwayFX behavior; maintained separately |
|
||||
|
||||
QuickShell may display this state later, but must not duplicate or authoritatively store it.
|
||||
**The compositor is the runtime source of truth for Mosaic state.** A consumer may request a change or save a snapshot, but must not maintain an independent authoritative window arrangement.
|
||||
|
||||
## Logical model
|
||||
## Runtime model and lifetime
|
||||
|
||||
```text
|
||||
MosaicWorkspaceState
|
||||
├── active_row
|
||||
├── previous_standard_layout
|
||||
└── rows[]
|
||||
├── ordered children
|
||||
├── scroll_x
|
||||
└── focused child
|
||||
The C model uses `struct mosaic_workspace_state`, `struct mosaic_row`, and `struct mosaic_row_state` (see `include/sway/tree/mosaic.h`). A workspace owns its Mosaic state and frees it with the workspace. The state owns row objects but never Sway containers. Row 0 borrows `workspace->tiling`, preserving the Sway tree's real ordered containers. Later model rows own their lists, not their children; they are **not** connected to runtime arrangement yet. A workspace also stores `mosaic_previous_standard_layout` separately from Sway's generic split-layout history.
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
W[Sway workspace and real tiling tree] --> M[Mosaic workspace state]
|
||||
M --> R[Row 0 borrows workspace tiling order]
|
||||
R --> G[Logical pending geometry]
|
||||
G --> T[Sway pending/current transaction]
|
||||
T --> S[Scene translation by scroll_x]
|
||||
S --> O[Output viewport and hit testing]
|
||||
```
|
||||
|
||||
The first row directly borrows `workspace->tiling`, keeping the existing Sway tree authoritative.
|
||||
## Distinct state
|
||||
|
||||
Four concepts must remain separate:
|
||||
- **Logical order:** sequence in `workspace->tiling` for Row 0. Order is not inferred from screen coordinates.
|
||||
- **Row membership:** only Row 0 is a runtime row today; multiple runtime rows are planned.
|
||||
- **Geometry:** logical tiled rectangles in the workspace arrangement/transaction state. They may extend beyond the output width.
|
||||
- **Camera:** row-local `scroll_x`, clamped to the arranged extent. It changes visibility without changing order.
|
||||
- **Focus:** Sway's focus state, with a row-local remembered focused container. Focus can make an off-screen cell visible.
|
||||
- **Standard-layout history:** workspace-local restore target for `layout toggle mosaic`.
|
||||
|
||||
1. logical order;
|
||||
2. calculated geometry;
|
||||
3. viewport/camera;
|
||||
4. focus.
|
||||
Insertion after the active container and deletion reflow preserve contiguous logical order. Floating, fullscreen, and scratchpad retain Sway ownership and paths.
|
||||
|
||||
Changing the camera must not reorder containers. Changing focus must not change logical order.
|
||||
## Standard layout compatibility
|
||||
|
||||
## Layout semantics
|
||||
`layout mosaic` activates the native layout on one workspace. `layout toggle mosaic` enters Mosaic or restores that workspace's previous standard layout. Windows keep Sway node identity. When a standard tabbed or stacking layout wraps workspace windows in a root container, entering Mosaic promotes its children into Row 0; deeper groups remain one logical cell. Standard layouts remain usable in the same binary. The restore path is a layout transition, not process replacement.
|
||||
|
||||
Mosaic is opt-in per workspace through:
|
||||
## Transactions and rendering
|
||||
|
||||
```text
|
||||
layout mosaic
|
||||
```
|
||||
Sway's pending/current transaction model separates requested geometry from committed scene state. Mosaic calculates logical pending rectangles; scene positioning translates the tiling layer by `-scroll_x`. Camera updates and future animation must preserve agreement among committed scene positions, IPC geometry, and pointer hit testing. The current camera move is immediate; animated camera work is **PLANNED**.
|
||||
|
||||
The bidirectional UX command is:
|
||||
|
||||
```text
|
||||
layout toggle mosaic
|
||||
```
|
||||
|
||||
Entering Mosaic records the current standard layout. Leaving Mosaic restores that layout for the same workspace.
|
||||
|
||||
Standard layouts continue to work inside `swayfx-mosaic`; changing process or restarting the compositor is not part of layout switching.
|
||||
|
||||
## Tiling invariants
|
||||
|
||||
- containers remain Sway tiled nodes;
|
||||
- no overlaps in the logical tiling geometry;
|
||||
- no internal holes after insertion/removal;
|
||||
- insertion occurs next to the active logical container;
|
||||
- deletion triggers reflow;
|
||||
- a row can extend beyond the physical viewport;
|
||||
- `scroll_x` is bounded to the logical row extent;
|
||||
- focusing an off-screen cell may bring it into view;
|
||||
- floating, fullscreen and scratchpad use normal Sway paths and are not reimplemented as Mosaic concepts.
|
||||
|
||||
## Scene and viewport
|
||||
|
||||
The logical row may be wider than the output. Mosaic therefore needs a camera transform between logical tiled geometry and visible scene coordinates.
|
||||
|
||||
The output viewport is not the layout itself.
|
||||
|
||||
STEP20B currently proves the single-row translation path. Multi-output correctness still requires explicit clipping or an equivalent SceneFX/wlroots strategy so content from one workspace viewport cannot leak onto an adjacent output.
|
||||
|
||||
Hit testing must remain aligned with the translated scene.
|
||||
The output renders a physical viewport of a wider logical row. Single-output headless tests demonstrate visual translation. A generic scene-tree clip at workspace/output boundaries is not yet implemented. Adjacent outputs may expose content outside a workspace's intended viewport; correct clipping and matching hit testing are a STEP20C concern. Do not infer multi-output safety from output-buffer cropping on one monitor.
|
||||
|
||||
## IPC
|
||||
|
||||
Existing Sway IPC contracts remain primary:
|
||||
- `get_tree`;
|
||||
- `get_workspaces`;
|
||||
- window events;
|
||||
- workspace events.
|
||||
On a Mosaic workspace, `get_tree` reports `layout: "mosaic"` and adds a `mosaic` object with `active_row` and `rows`. Each row entry contains ordered child node IDs, `scroll_x`, and focused node ID or null. Existing Sway fields retain their shapes; normal workspace/window events and `get_workspaces` paths remain in use. This is an extension to the Sway layout vocabulary: strict IPC consumers with a closed layout enum must recognize `mosaic`. Additional rows in the model are not a promise of usable multi-row IPC behavior.
|
||||
|
||||
A Mosaic workspace exposes `layout: "mosaic"` and may expose an additional Mosaic object describing rows, focus and scroll state.
|
||||
## Package and persistence boundary
|
||||
|
||||
Consumers that treat layouts as a closed enum must explicitly add Mosaic support.
|
||||
The ordinary SwayFX package owns `/usr/bin/sway`; Mosaic owns the alternate `/usr/bin/swayfx-mosaic`. This is a pinned compositor build with a Mosaic patch, not a runtime plugin. [Packaging](PACKAGING.md) specifies coexistence and file ownership.
|
||||
|
||||
## Package isolation
|
||||
Session V2 restoration is **PLANNED**. It must restore Mosaic activation, ordered rows, row membership, active row, camera positions, remembered focus, and stable window identities through compositor-owned state. It must not become another source of runtime truth.
|
||||
|
||||
The normal package owns the normal compositor:
|
||||
## Non-goals
|
||||
|
||||
```text
|
||||
swayfx → /usr/bin/sway
|
||||
```
|
||||
|
||||
This project owns only the alternate binary and project-specific files:
|
||||
|
||||
```text
|
||||
swayfx-mosaic → /usr/bin/swayfx-mosaic
|
||||
```
|
||||
|
||||
No file owned by `swayfx` may be overwritten.
|
||||
|
||||
The package must not declare itself a replacement for SwayFX.
|
||||
|
||||
## Patch maintenance
|
||||
|
||||
The installed Mosaic build is produced from:
|
||||
1. a pinned, known SwayFX upstream commit;
|
||||
2. the Mosaic patch set;
|
||||
3. Mosaic tests;
|
||||
4. a package recipe that checks the expected upstream commit.
|
||||
|
||||
A new SwayFX version is never accepted implicitly. The patch must be rebased/reviewed and all standard-layout plus Mosaic tests rerun.
|
||||
|
||||
## Session restore
|
||||
|
||||
The existing external Session V2 system will eventually need to persist:
|
||||
- Mosaic activation;
|
||||
- ordered rows;
|
||||
- row membership;
|
||||
- active row;
|
||||
- each row's `scroll_x`;
|
||||
- each row's remembered focus;
|
||||
- stable window identities.
|
||||
|
||||
That integration belongs to a later step and must not turn Session V2 into the runtime source of truth.
|
||||
- Replacing Sway workspaces or standard layouts.
|
||||
- Replacing QuickShell or creating a new desktop shell.
|
||||
- Simulating tiling with floating windows or a repositioning daemon.
|
||||
- Embedding personal dotfiles or keyboard bindings in the package.
|
||||
- Maintaining a permanently diverged SwayFX fork instead of a reviewable delta.
|
||||
|
|
|
|||
|
|
@ -1,120 +1,74 @@
|
|||
# Development workflow
|
||||
|
||||
## Safety rule
|
||||
Use separate build directories and headless compositor tests. Ordinary development does not install into `/usr`, reload Sway, or change the active desktop session. The current package is experimental; see [Packaging](PACKAGING.md) for the file-ownership contract.
|
||||
|
||||
Development must not replace the daily SwayFX installation or reload the active desktop session.
|
||||
## Repository and remotes
|
||||
|
||||
Use separate build directories and headless compositor tests.
|
||||
| Remote | Role | Push policy |
|
||||
| --- | --- | --- |
|
||||
| `origin` | Canonical Forgejo project | Project changes |
|
||||
| `github` | Public GitHub mirror | Same reviewed project commits |
|
||||
| `upstream` | SwayFX source | Fetch only; never push Mosaic changes |
|
||||
|
||||
## Upstream
|
||||
`main` contains the project's public history: imported SwayFX 0.6 base plus Mosaic commits. The external `upstream` remote retains SwayFX history. Public instructions must not depend on a private local branch. Make focused development branches from `main`; merge or publish only after the source delta, tests, docs, and patch agree.
|
||||
|
||||
The initial supported base is SwayFX 0.6 at:
|
||||
## Base and prerequisites
|
||||
|
||||
```text
|
||||
fd71a6bdc061bd633b488ae7b83e8a6981d22f86
|
||||
```
|
||||
The pinned base is SwayFX tag `0.6`, commit `fd71a6bdc061bd633b488ae7b83e8a6981d22f86`, using wlroots 0.20 and SceneFX 0.5. Meson, Ninja, the base build dependencies, Python, and the headless test dependencies (`kitty`, `grim`) are needed for the respective checks. Review [Upstream](UPSTREAM.md) before changing the pin. The exact older local Arch package build source is not reconstructible; do not claim byte-identical provenance.
|
||||
|
||||
The `upstream` remote must point to the SwayFX repository.
|
||||
## Pristine baseline build
|
||||
|
||||
## Baseline build
|
||||
Use a pristine checkout of the pinned upstream commit for baseline validation, or an already-retained baseline build known to come from that commit. Do not treat a Mosaic-modified tree as an upstream baseline.
|
||||
|
||||
```sh
|
||||
meson setup build-baseline \
|
||||
-Dwerror=false \
|
||||
-Dsd-bus-provider=libsystemd
|
||||
|
||||
meson setup build-baseline -Dwerror=false -Dsd-bus-provider=libsystemd
|
||||
meson compile -C build-baseline -j 8
|
||||
meson test -C build-baseline --print-errorlogs
|
||||
```
|
||||
|
||||
The upstream base currently defines no Meson tests.
|
||||
The historical upstream baseline had no Meson tests. A fresh baseline build is especially important for an upstream update. The command above assumes the current working tree is the pristine baseline; use a separate checkout so the Mosaic tree is not altered.
|
||||
|
||||
## Mosaic build
|
||||
## Mosaic build and headless tests
|
||||
|
||||
From the project development tree:
|
||||
|
||||
```sh
|
||||
meson setup build-mosaic \
|
||||
-Dwerror=false \
|
||||
-Dsd-bus-provider=libsystemd \
|
||||
-Dmosaic-package=true \
|
||||
-Dprefix=/usr \
|
||||
-Dbindir=bin \
|
||||
-Dswaybar=false \
|
||||
-Dswaynag=false \
|
||||
-Dman-pages=disabled \
|
||||
-Ddefault-wallpaper=false
|
||||
|
||||
-Dwerror=false -Dsd-bus-provider=libsystemd \
|
||||
-Dmosaic-package=true -Dprefix=/usr -Dbindir=bin \
|
||||
-Dswaybar=false -Dswaynag=false \
|
||||
-Dman-pages=disabled -Ddefault-wallpaper=false
|
||||
meson compile -C build-mosaic -j 8
|
||||
meson test -C build-mosaic --print-errorlogs
|
||||
python tests/headless-ipc.py
|
||||
git diff --check
|
||||
```
|
||||
|
||||
## Package staging
|
||||
The headless script starts its own compositor socket; use its documented `MOSAIC_BINARY` environment variable for a nondefault build path. Do not send test commands to the running desktop's IPC socket. Record compiler/test failures, not only passes.
|
||||
|
||||
Never install to the live system as part of routine validation.
|
||||
## Staging and package checks
|
||||
|
||||
```sh
|
||||
rm -rf /tmp/swayfx-mosaic-stage
|
||||
meson install -C build-mosaic --destdir /tmp/swayfx-mosaic-stage
|
||||
find /tmp/swayfx-mosaic-stage -type f -print
|
||||
```
|
||||
|
||||
The staging manifest must remain limited to the Mosaic-owned artifact(s), currently `/usr/bin/swayfx-mosaic`.
|
||||
|
||||
## Patch export
|
||||
|
||||
The development tree contains the full source because compositor work is easier there. The distributable delta lives under `patches/`.
|
||||
|
||||
Use the project tooling to regenerate the patch after source changes, then verify:
|
||||
|
||||
```sh
|
||||
git apply --check patches/0001-mosaic-layout-viewport.patch
|
||||
```
|
||||
|
||||
The patch must correspond to the pinned upstream commit used by `PKGBUILD`.
|
||||
|
||||
## Arch package
|
||||
|
||||
```sh
|
||||
makepkg --printsrcinfo
|
||||
makepkg --verifysource
|
||||
```
|
||||
|
||||
A full package build is expected before a release, not necessarily after every edit.
|
||||
Inspect the staging manifest. With `mosaic-package=true`, the expected installed file is `/usr/bin/swayfx-mosaic` under the staging root. This is staging, not live installation. A full `makepkg` build is required before a release, with its own build/test output and manifest review.
|
||||
|
||||
The package must not:
|
||||
- replace `swayfx`;
|
||||
- conflict with `swayfx`;
|
||||
- provide `sway`;
|
||||
- install `/usr/bin/sway`;
|
||||
- install the user's QuickShell configuration or personal dotfiles.
|
||||
## Patch export
|
||||
|
||||
## Updating upstream
|
||||
The development tree contains full SwayFX source for editing. `patches/0001-mosaic-layout-viewport.patch` is the production delta against the pinned base. After source changes, use `tooling/export-patch.sh` to regenerate it, then verify the patch against a **clean checkout of the pinned upstream commit** with `git apply --check`. Review the patch, refresh its package checksum, and validate the package build. `git apply --check` in an already-patched development tree is not a valid forward-application check.
|
||||
|
||||
When SwayFX publishes a new version:
|
||||
## Upstream update branch
|
||||
|
||||
1. fetch `upstream`;
|
||||
2. inspect relevant compositor changes;
|
||||
3. create a dedicated rebase/update branch;
|
||||
4. update the pinned source revision;
|
||||
5. reapply or rewrite the Mosaic patch;
|
||||
6. build the new upstream baseline;
|
||||
7. build Mosaic;
|
||||
8. run model/headless tests;
|
||||
9. test standard Sway layouts;
|
||||
10. only then bump the Mosaic package version.
|
||||
1. Fetch `upstream` and identify the exact new release commit.
|
||||
2. Create a dedicated branch/checkout for the new base; inspect SwayFX changes in affected files.
|
||||
3. Update Architecture, UX, Packaging, Upstream, and limitations for any changed contract before implementing the forward port.
|
||||
4. Adapt the Mosaic delta manually if the patch conflicts. Never force or silently skip hunks.
|
||||
5. Build and test the pristine new base, then Mosaic and standard layouts on that base.
|
||||
6. Run model/headless IPC/rendering tests, stage the package, inspect file ownership, and update the pin, version, patch, and checksums together.
|
||||
7. Publish only after the new base is validated. The normal SwayFX package continues updating independently.
|
||||
|
||||
If the patch does not apply cleanly, stop and adapt it manually.
|
||||
|
||||
## Daily-session integration
|
||||
|
||||
The final package is intentionally independent from the user's desktop configuration.
|
||||
|
||||
The user's dotfiles may launch `swayfx-mosaic` in a dedicated session and bind:
|
||||
|
||||
```text
|
||||
Super+Alt+M → Applications
|
||||
Super+Alt+L → layout toggle mosaic
|
||||
```
|
||||
|
||||
Those bindings are not packaged here.
|
||||
See [Packaging](PACKAGING.md) and [Upstream](UPSTREAM.md) for release invariants. Desktop key bindings belong to user dotfiles and are not installed here.
|
||||
|
|
|
|||
19
docs/KNOWN_LIMITATIONS.md
Normal file
19
docs/KNOWN_LIMITATIONS.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# Known limitations
|
||||
|
||||
This document describes the development tree at the documentation foundation pass. `EXPERIMENTAL` means implemented but incompletely validated; `PLANNED` means absent from runtime; `NOT YET SUPPORTED` means it must not be presented as ready for general use.
|
||||
|
||||
| Area | Status | Practical implication |
|
||||
| --- | --- | --- |
|
||||
| Adjacent-output viewport clipping | NOT YET SUPPORTED | A wider row may render beyond its workspace/output boundary on another output; pointer behavior needs matching validation. |
|
||||
| Multiple runtime rows | PLANNED | Model helpers/tests exist, but only Row 0 is wired into the Sway tree, arrangement, scene, and input. |
|
||||
| Camera animation | PLANNED | Camera movement is immediate; transaction-safe timing/curve is open. |
|
||||
| Cell sizing and grouped containers | EXPERIMENTAL | The 640 px minimum is temporary; nested groups remain one cell. Final sizing/reflow policy is TBD. |
|
||||
| Resize and output migration | EXPERIMENTAL | Scroll is clamped after arrangement, but these transitions need broader headless validation. |
|
||||
| Floating, fullscreen, scratchpad edge cases | EXPERIMENTAL | Basic transitions are tested; long-running and multi-output combinations are not qualified. |
|
||||
| Session V2 Mosaic restore | PLANNED | Mosaic state is not durably restored by Session V2. |
|
||||
| QuickShell Mosaic visualization | PLANNED | No Mosaic-specific QuickShell display is supplied here. |
|
||||
| Daily-driver deployment | NOT YET SUPPORTED | Build and headless evidence do not amount to a validated live session. |
|
||||
| Forward port to a later SwayFX release | PLANNED | The patch is pinned to SwayFX 0.6; a new release requires manual review and validation. |
|
||||
| Very wide logical coordinates | NOT YET SUPPORTED | Scene positions use bounded integer coordinates; extremely wide canvases are not qualified. |
|
||||
|
||||
These limits are reflected in [UX](UX.md), [architecture](ARCHITECTURE.md), and [roadmap](ROADMAP.md). A future step must update those contracts before claiming support.
|
||||
41
docs/PACKAGING.md
Normal file
41
docs/PACKAGING.md
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
# Packaging and coexistence
|
||||
|
||||
This is the canonical package contract. **SwayFX updates must never be blocked by swayfx-mosaic.** The package is experimental; staging and package checks are development validation, not a daily-use endorsement.
|
||||
|
||||
## Why a second compositor binary?
|
||||
|
||||
SwayFX does not expose a stable external layout plugin ABI. A native layout must be compiled into a compositor variant. The maintained project delta is the Mosaic patch on a pinned SwayFX source revision, while the resulting binary contains the compositor. A separate package is **not** a runtime plugin or injected `.so`.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
U[Pinned SwayFX source] --> A[swayfx package: /usr/bin/sway]
|
||||
U --> P[Mosaic patch]
|
||||
P --> B[swayfx-mosaic package: /usr/bin/swayfx-mosaic]
|
||||
```
|
||||
|
||||
## Ownership and fallback
|
||||
|
||||
The regular `swayfx` package owns `/usr/bin/sway` and its normal files. `swayfx-mosaic` must own only its distinct binary and any future project-specific files. The current `PKGBUILD` checks that staging contains exactly `/usr/bin/swayfx-mosaic`. It must not install Sway's config, `swaymsg`, `swaybar`, `swaynag`, shared completion files, personal dotfiles, QuickShell config, or a conflicting session file.
|
||||
|
||||
The Mosaic package must not declare `provides`, `conflicts`, or `replaces` against SwayFX or Sway. The normal SwayFX session remains available as a fallback; selecting Mosaic is an explicit external session choice. Removing Mosaic must leave ordinary SwayFX intact.
|
||||
|
||||
## Version and source pin
|
||||
|
||||
Versions identify the SwayFX base and Mosaic revision, for example `swayfx 0.6` and `swayfx-mosaic 0.6+mosaic.1`. The current package pins SwayFX tag `0.6` at `fd71a6bdc061bd633b488ae7b83e8a6981d22f86`, then applies `patches/0001-mosaic-layout-viewport.patch`. The recipe checks the fetched commit and patch applicability before building. An upstream `0.7` release does not make the current patch valid for `0.7`.
|
||||
|
||||
The repository contains full source for development. Patch export provides a reviewable production delta. A patch must match its pinned upstream commit and recorded checksum; forced or silent patch application is forbidden.
|
||||
|
||||
## Arch package expectations
|
||||
|
||||
`PKGBUILD` uses the pinned Git source, the Mosaic patch, and the headless test script. It builds with `-Dmosaic-package=true` and runs Meson and headless tests. Validate source metadata with `makepkg --printsrcinfo` and `makepkg --verifysource`; perform a full package build before release. Inspect the staged file manifest before any install. A package build does not authorize switching the running session.
|
||||
|
||||
## Upgrade and rollback
|
||||
|
||||
1. Keep normal `swayfx` installed and independently updatable.
|
||||
2. On a new SwayFX release, fetch and inspect upstream; create a dedicated forward-port branch.
|
||||
3. Adapt the patch manually, update the pin/version/checksum, and test both the pristine baseline and Mosaic.
|
||||
4. Recheck standard layouts, Mosaic, headless rendering, IPC, and package file ownership.
|
||||
5. Publish only after the new base has been validated. Until then, the older pinned Mosaic package may remain available separately; it must not constrain normal SwayFX updates.
|
||||
6. If Mosaic fails, use the normal SwayFX session. Do not overwrite `/usr/bin/sway` to recover.
|
||||
|
||||
See [upstream maintenance](UPSTREAM.md) and [development](DEVELOPMENT.md) for the operational procedure.
|
||||
51
docs/README.md
Normal file
51
docs/README.md
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
# Documentation
|
||||
|
||||
Documentation is a first-class project artifact. Architecture and UX contracts are updated before implementation when behavior changes.
|
||||
|
||||
The [root README](../README.md) is the public summary. For a specific topic, use the canonical document below. Within its own subject, a canonical document takes precedence over a historical STEP report. If two canonical documents disagree, resolve the conflict before implementation; do not silently choose one.
|
||||
|
||||
## Source-of-truth order
|
||||
|
||||
1. [Architecture](ARCHITECTURE.md): compositor ownership and technical invariants.
|
||||
2. [UX contract](UX.md): user-visible behavior and interaction invariants.
|
||||
3. [Packaging](PACKAGING.md): binary and package coexistence.
|
||||
4. [Upstream maintenance](UPSTREAM.md): provenance and forward ports.
|
||||
5. [Development](DEVELOPMENT.md): reproducible workflow.
|
||||
6. [Known limitations](KNOWN_LIMITATIONS.md): current support boundary.
|
||||
7. [Roadmap](ROADMAP.md): ordered future work, not proof of implementation.
|
||||
8. [STEP20A](STEP20A.md) and [STEP20B](STEP20B.md): historical evidence.
|
||||
|
||||
## Project
|
||||
|
||||
| Document | Role | Purpose |
|
||||
| --- | --- | --- |
|
||||
| [README](../README.md) | Summary | Public landing page and current status |
|
||||
| [Contributing](../CONTRIBUTING.md) | Normative | Scope, docs-first flow, checks |
|
||||
| [Changelog](../CHANGELOG.md) | Historical | Repository evolution |
|
||||
| [Notice](../NOTICE.md) | Normative | Attribution boundary |
|
||||
|
||||
## Architecture and user experience
|
||||
|
||||
| Document | Role | Purpose |
|
||||
| --- | --- | --- |
|
||||
| [Architecture](ARCHITECTURE.md) | Normative | Runtime model, ownership, IPC, transactions, scene |
|
||||
| [UX contract](UX.md) | Normative | Interaction rules, row behavior, undecided choices |
|
||||
| [Known limitations](KNOWN_LIMITATIONS.md) | Planning/current evidence | Unsupported and unvalidated paths |
|
||||
|
||||
## Development, packaging, and upstream
|
||||
|
||||
| Document | Role | Purpose |
|
||||
| --- | --- | --- |
|
||||
| [Development](DEVELOPMENT.md) | Normative | Build, test, staging, patch workflow |
|
||||
| [Packaging](PACKAGING.md) | Normative | File ownership, versioning, fallback |
|
||||
| [Upstream maintenance](UPSTREAM.md) | Normative | SwayFX relationship, pinned base, forward ports |
|
||||
|
||||
## Roadmap and historical reports
|
||||
|
||||
| Document | Role | Purpose |
|
||||
| --- | --- | --- |
|
||||
| [Roadmap](ROADMAP.md) | Planning | Step goals, exit criteria, required documentation |
|
||||
| [STEP20A](STEP20A.md) | Historical | Native foundation implementation evidence |
|
||||
| [STEP20B](STEP20B.md) | Historical | First scrollable-row implementation evidence |
|
||||
|
||||
STEP reports record what was observed and decided at the time. They are **not** the canonical source for current behavior. When a STEP report conflicts with current canonical documentation, the canonical documentation wins. The original French reports are preserved as historical artifacts; their opening notices point here.
|
||||
101
docs/ROADMAP.md
101
docs/ROADMAP.md
|
|
@ -1,94 +1,41 @@
|
|||
# Roadmap
|
||||
|
||||
## STEP20A — compositor foundation
|
||||
This is the canonical order of work, not proof that a feature exists. **A step is not ready for implementation until its user-visible and architectural behavior is documented in the canonical docs.** Update [UX](UX.md), [architecture](ARCHITECTURE.md), and the relevant packaging/upstream documents before changing behavior. Record validation and limitations when the step closes.
|
||||
|
||||
Status: implemented.
|
||||
| Step | State | Goal |
|
||||
| --- | --- | --- |
|
||||
| STEP20A | DONE | Native compositor foundation |
|
||||
| STEP20B | EXPERIMENTAL | First scrollable runtime row |
|
||||
| STEP20C | NEXT | Viewport and multi-output correctness |
|
||||
| STEP20D | PLANNED | Multiple runtime rows |
|
||||
| STEP20E | PLANNED | Session V2 persistence |
|
||||
| STEP20F | PLANNED | QuickShell visualization |
|
||||
| STEP20G | PLANNED | Package and daily-use qualification |
|
||||
|
||||
- identify exact SwayFX baseline;
|
||||
- native Mosaic layout enum/parser;
|
||||
- workspace-local state;
|
||||
- real tiled containers;
|
||||
- insertion/removal/focus invariants;
|
||||
- IPC exposure;
|
||||
- isolated build and headless tests;
|
||||
- package staging without replacing SwayFX.
|
||||
## STEP20A — native foundation · DONE
|
||||
|
||||
See [STEP20A.md](STEP20A.md).
|
||||
**Deliverables:** native layout enum/parser, workspace-local state, real tiled Row 0, insertion/removal/focus model, IPC exposure, isolated build/staging, headless tests. **Exit evidence:** [historical report](STEP20A.md) and current source/tests. **Documentation before implementation:** original architecture, upstream base, and package coexistence contract; current canonical versions are [Architecture](ARCHITECTURE.md), [Upstream](UPSTREAM.md), and [Packaging](PACKAGING.md).
|
||||
|
||||
## STEP20B — first scrollable row
|
||||
## STEP20B — first scrollable row · EXPERIMENTAL
|
||||
|
||||
Status: experimental implementation present in the development tree.
|
||||
**Deliverables:** logical horizontal geometry, bounded `scroll_x`, scene translation, focus visibility, workspace-local standard-layout toggle, headless visual evidence, patch export. **Exit evidence:** [historical report](STEP20B.md). The single-row proof is present, but it is not a general-use viewport guarantee. **Documentation before further implementation:** [UX](UX.md) and [Architecture](ARCHITECTURE.md) must keep the temporary sizing and scene boundaries explicit.
|
||||
|
||||
- single logical row wider than the viewport;
|
||||
- workspace-local standard ↔ Mosaic toggle;
|
||||
- logical `scroll_x`;
|
||||
- scene translation;
|
||||
- focus visibility;
|
||||
- headless rendering/IPC validation;
|
||||
- package patch export.
|
||||
## STEP20C — viewport correctness · NEXT
|
||||
|
||||
See [STEP20B.md](STEP20B.md).
|
||||
**Goal:** make the single-row viewport correct at workspace and output boundaries. **Planned deliverables:** clipping or an equivalent rendering strategy, matching hit testing, adjacent-output tests, resize/migration tests, and transaction-safe camera animation. **Exit criteria:** no cross-output visual/input leakage in the tested scenarios; camera and IPC remain consistent across transactions; standard layouts still pass. **Docs first:** specify clipping ownership, animation semantics, and edge-case UX in Architecture and UX; update Known Limitations before implementation. This documentation pass does not implement STEP20C.
|
||||
|
||||
## STEP20C — viewport correctness
|
||||
## STEP20D — multi-row Spatial Canvas · PLANNED
|
||||
|
||||
Planned.
|
||||
**Goal:** connect rows to runtime tree, transactions, scene, input, and IPC. **Planned deliverables:** active-row navigation, row-local scroll/focus, deterministic insertion/reflow, in-row reorder, and between-row movement. **Exit criteria:** real tiled containers preserve identity and order across row changes; focus and camera restore correctly; headless multi-row tests pass. **Docs first:** settle exact interactions and row invariants in UX and Architecture. Unset key combinations remain TBD.
|
||||
|
||||
- robust clipping at workspace/output boundaries;
|
||||
- multi-output validation;
|
||||
- resize/output migration tests;
|
||||
- pointer/hit-testing validation;
|
||||
- camera animation without transaction divergence.
|
||||
## STEP20E — Session V2 persistence · PLANNED
|
||||
|
||||
## STEP20D — multi-row Spatial Canvas
|
||||
**Goal:** restore Mosaic workspaces across sessions without creating a second runtime authority. **Planned deliverables:** durable activation, row order/membership, active row, scroll, focus, stable identities, and restart tests. **Exit criteria:** deterministic restore and safe fallback for missing windows/older snapshots. **Docs first:** specify persistence identity, versioning, failure handling, and ownership in Architecture and UX.
|
||||
|
||||
Planned.
|
||||
## STEP20F — QuickShell visualization · PLANNED
|
||||
|
||||
- multiple native rows;
|
||||
- active-row navigation;
|
||||
- row-local scroll/focus memory;
|
||||
- move/reorder within a row;
|
||||
- move containers between rows;
|
||||
- deterministic reflow.
|
||||
**Goal:** expose compositor-owned Mosaic state in the desktop UI. **Planned deliverables:** workspace/row view and optional layout indication without duplicate QML layout state. **Exit criteria:** UI reflects IPC state and cannot contradict the compositor. **Docs first:** specify IPC consumer behavior and UI interactions in Architecture and UX.
|
||||
|
||||
Target interaction model:
|
||||
## STEP20G — package and daily-use qualification · PLANNED
|
||||
|
||||
```text
|
||||
Super + arrows navigation
|
||||
Super + Ctrl + ... reorder/modify within row
|
||||
Super + Shift + Up/Down move between rows
|
||||
```
|
||||
|
||||
Exact bindings remain subject to validation before they become permanent.
|
||||
|
||||
## STEP20E — Session V2 persistence
|
||||
|
||||
Planned.
|
||||
|
||||
Persist and restore:
|
||||
- Mosaic layout state;
|
||||
- ordered rows;
|
||||
- active row;
|
||||
- scroll positions;
|
||||
- row focus;
|
||||
- stable window identities.
|
||||
|
||||
The compositor remains the runtime source of truth.
|
||||
|
||||
## STEP20F — QuickShell integration
|
||||
|
||||
Planned.
|
||||
|
||||
- expose Mosaic state visually;
|
||||
- adapt workspace overview;
|
||||
- optional layout state indication;
|
||||
- no duplicate Mosaic state in QML.
|
||||
|
||||
## STEP20G — packaging and daily use
|
||||
|
||||
Planned.
|
||||
|
||||
- final Arch package;
|
||||
- dedicated desktop/session entry if useful;
|
||||
- standard SwayFX fallback preserved;
|
||||
- update/rebase procedure proven against a newer upstream SwayFX release;
|
||||
- documentation for installation, rollback and troubleshooting.
|
||||
**Goal:** publish a validated optional session while preserving standard SwayFX fallback. **Planned deliverables:** final Arch package, optional distinct session entry, install/rollback instructions, and a forward port proven against a newer SwayFX release. **Exit criteria:** package file ownership and coexistence verified, release build and headless/live qualification recorded, standard SwayFX updates remain independent. **Docs first:** update Packaging, Upstream, Development, UX, and Known Limitations with the intended release contract.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
# STEP20A — fondation Spatial Canvas native
|
||||
|
||||
> **Historical implementation report (native compositor foundation).** This report preserves the original French validation record and reflects the state at that step. For current behavior and decisions, use the [documentation index](README.md), [architecture](ARCHITECTURE.md), [UX contract](UX.md), and [known limitations](KNOWN_LIMITATIONS.md). Canonical documentation takes precedence if a historical statement is stale.
|
||||
|
||||
## Base et provenance
|
||||
|
||||
- Installation protégée : paquet Arch `swayfx 0.6-1`, binaire `/usr/bin/sway`, `swayfx version 0.6 (based on sway 1.12.0)`. `pacman -Qkk swayfx` : 58 fichiers, aucun altéré.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
# STEP20B — première ligne Mosaic scrollable
|
||||
|
||||
> **Historical implementation report (first scrollable row).** This report preserves the original French validation record and reflects the state at that step. For current behavior and decisions, use the [documentation index](README.md), [architecture](ARCHITECTURE.md), [UX contract](UX.md), and [known limitations](KNOWN_LIMITATIONS.md). Canonical documentation takes precedence if a historical statement is stale.
|
||||
|
||||
## Contrat et base
|
||||
|
||||
Base source : SwayFX tag `0.6`, commit `fd71a6bdc061bd633b488ae7b83e8a6981d22f86`. La correspondance byte pour byte au paquet local `swayfx 0.6-1` reste invérifiable faute de source de sa révision de paquet ; voir [STEP20A](STEP20A.md). Le fork est toujours compilé contre `wlroots-0.20` et `scenefx-0.5`. SwayFX standard conserve `/usr/bin/sway` et son cycle de mise à jour. Aucun paquet système n'a été installé.
|
||||
|
|
|
|||
|
|
@ -1,50 +1,35 @@
|
|||
# Upstream relationship
|
||||
# Upstream maintenance
|
||||
|
||||
SwayFX Mosaic is intentionally maintained as a small feature delta above SwayFX.
|
||||
SwayFX Mosaic is an independent derivative of [SwayFX](https://github.com/WillPower3309/swayfx), which is based on [Sway](https://github.com/swaywm/sway). It is not endorsed by either project's maintainers. Preserve their license and attribution; see [LICENSE](../LICENSE) and [NOTICE](../NOTICE.md).
|
||||
|
||||
## Initial base
|
||||
## Pinned source base
|
||||
|
||||
- Project: SwayFX
|
||||
- Upstream: https://github.com/WillPower3309/swayfx
|
||||
- Tag: `0.6`
|
||||
- Commit: `fd71a6bdc061bd633b488ae7b83e8a6981d22f86`
|
||||
- Sway base reported by SwayFX: 1.12.0
|
||||
- wlroots ABI used by this base: 0.20
|
||||
- SceneFX ABI used by this base: 0.5
|
||||
| Item | Current value |
|
||||
| --- | --- |
|
||||
| SwayFX tag | `0.6` |
|
||||
| Upstream commit | `fd71a6bdc061bd633b488ae7b83e8a6981d22f86` |
|
||||
| Reported Sway base | 1.12.0 |
|
||||
| wlroots series | 0.20 |
|
||||
| SceneFX series | 0.5 |
|
||||
|
||||
The original local Arch package was `swayfx 0.6-1`. Its exact build-source commit could not be reconstructed, so the signed/verifiable project base is the public upstream 0.6 tag commit rather than a claim of byte-for-byte equivalence with that package.
|
||||
The historical locally installed Arch package was `swayfx 0.6-1`, but its exact source revision could not be reconstructed from available package metadata. The public SwayFX 0.6 tag is the verifiable project base; do not claim byte-for-byte equivalence with that older package.
|
||||
|
||||
## Remote policy
|
||||
## Remote policy and history
|
||||
|
||||
Local development uses:
|
||||
`origin` is the canonical Forgejo project; `github` is the public mirror; `upstream` is SwayFX and is **fetch only**. No Mosaic branch or commit is pushed to SwayFX upstream. The project's `main` has clean public project history rooted in the imported SwayFX 0.6 base. The upstream remote remains an external source of new releases, not a project publication target.
|
||||
|
||||
```text
|
||||
upstream → SwayFX upstream
|
||||
origin → Forgejo canonical repository
|
||||
github → GitHub mirror
|
||||
```
|
||||
## Delta and versioning
|
||||
|
||||
Only the project remotes receive Mosaic commits.
|
||||
The maintained production delta is `patches/0001-mosaic-layout-viewport.patch` on the pinned source commit. The package builds the full compositor because SwayFX has no stable external layout plugin ABI, then installs a distinct binary. Example versions are `swayfx 0.6` and `swayfx-mosaic 0.6+mosaic.1`. A SwayFX `0.7` release does not automatically validate a Mosaic `0.7` package.
|
||||
|
||||
Do not push Mosaic branches to `upstream`.
|
||||
## Forward-port procedure
|
||||
|
||||
## Version policy
|
||||
1. Fetch upstream; inspect the release tag, commit, relevant source changes, and dependency versions.
|
||||
2. Open a dedicated update branch and document changed architecture/UX/package assumptions before implementation.
|
||||
3. Build the pristine upstream baseline at the candidate commit.
|
||||
4. Rebase or manually forward-port the Mosaic patch. On conflict, inspect both implementations and adapt the delta deliberately; never force automatic patch application or accept rejected hunks.
|
||||
5. Review exported patch scope; update pinned commit, package version, and checksums together.
|
||||
6. Build Mosaic, run model and headless compositor tests, verify standard layouts, IPC, rendering, and package staging/file ownership.
|
||||
7. Update [known limitations](KNOWN_LIMITATIONS.md), [roadmap](ROADMAP.md), and release notes with the observed result.
|
||||
|
||||
Mosaic versions follow the SwayFX base explicitly.
|
||||
|
||||
Example:
|
||||
|
||||
```text
|
||||
swayfx 0.6
|
||||
swayfx-mosaic 0.6+mosaic.1
|
||||
```
|
||||
|
||||
A future SwayFX 0.7 does not automatically imply a working Mosaic 0.7 package. The patch must be rebased and validated first.
|
||||
|
||||
## Why a separate binary?
|
||||
|
||||
SwayFX does not expose a stable runtime plugin ABI for injecting a new layout. Mosaic therefore cannot be shipped as a small external `.so` while leaving the running `/usr/bin/sway` binary unchanged.
|
||||
|
||||
The package instead builds the compositor with the Mosaic delta but installs it under a different executable name.
|
||||
|
||||
This preserves the operational requirement that ordinary SwayFX can continue to update and remain a safe fallback.
|
||||
A failed patch check or changed compositor contract blocks that candidate release until resolved. It does not justify modifying the ordinary SwayFX package or using an ABI-incompatible binary workaround. The normal SwayFX package must remain independently updatable.
|
||||
|
|
|
|||
71
docs/UX.md
Normal file
71
docs/UX.md
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
# Spatial Canvas UX contract
|
||||
|
||||
**Scope:** intended user experience and the current single-row implementation. `CURRENT` means present in the development tree, `EXPERIMENTAL` means present without general-use validation, `PLANNED` means not connected to runtime behavior, and `TBD` means the decision is still open.
|
||||
|
||||
## Mental model
|
||||
|
||||
```text
|
||||
Workspace
|
||||
└── Canvas
|
||||
├── Row 0: ordered real tiled containers [A][B][C][D]...
|
||||
└── Future rows: ordered real tiled containers
|
||||
└── viewport shows only part of a row
|
||||
```
|
||||
|
||||
Mosaic is a layout inside an ordinary Sway workspace. A row can be wider than the visible output. Logical order, container geometry, viewport position, and focus are distinct state. Moving the viewport does not reorder windows; focusing a window does not make it floating.
|
||||
|
||||
**CURRENT/EXPERIMENTAL:** Row 0 uses the workspace tiling list and has logical horizontal scrolling. Additional rows exist only as model helpers and tests. Their runtime tree, scene, input, and IPC behavior is **PLANNED**.
|
||||
|
||||
## Focus and movement
|
||||
|
||||
**Invariant:** Super alone never moves windows. Navigation and window movement are separate actions.
|
||||
|
||||
| Intended action | Desktop binding | Status |
|
||||
| --- | --- | --- |
|
||||
| Navigate/focus | Super + arrows | Design direction; exact mapping and row transitions TBD |
|
||||
| Reorder or modify tiling within a row | Super + Ctrl + TBD | PLANNED; exact key/action mapping TBD |
|
||||
| Move a container between rows | Super + Shift + Up/Down | PLANNED |
|
||||
|
||||
These are desktop interaction decisions, not key bindings installed by this package. Existing Sway directional focus and move commands remain available; the full Canvas mapping is not yet implemented.
|
||||
|
||||
## Layout toggle and applications
|
||||
|
||||
The intended external desktop configuration uses **Super + Alt + L** for Standard ↔ Mosaic and **Super + Alt + M** for Applications. The Mosaic compositor command is `layout toggle mosaic`. The package does not install either binding, the application launcher, or a QuickShell menu.
|
||||
|
||||
The previous standard layout is remembered per workspace: `splith → mosaic → splith`, `tabbed → mosaic → tabbed`, and `stacking → mosaic → stacking`. Toggling does not replace windows or launch another compositor.
|
||||
|
||||
## Row memory
|
||||
|
||||
Each row conceptually remembers `scroll_x` and its last focused container. Changing rows should restore that row's context. Row 0 memory exists in the current model; multi-row navigation and restoration are **PLANNED**. A camera change must preserve logical order.
|
||||
|
||||
## Insertion, closing, and reflow
|
||||
|
||||
**CURRENT:** A newly tiled container is inserted immediately after the active logical container in Row 0. For example, `A B C`, focus `A`, then open `X` gives `A X B C`. A grouped subtree remains one Row 0 unit. Additional-row insertion policy is **TBD**.
|
||||
|
||||
**CURRENT:** Removing a tiled container closes the gap in logical order: `A B C D`, close `C`, then `A B D`. Focus references must not retain removed containers. Multi-row reflow policy is **PLANNED**.
|
||||
|
||||
## Viewport and sizing
|
||||
|
||||
**CURRENT/EXPERIMENTAL:** `layout mosaic scroll <signed pixels>` changes Row 0's logical camera position. Directional focus can bring an off-screen container into view. Scene translation is immediate, with no finished camera animation. The current 640 px minimum cell width is a temporary implementation value, **not** the final UX policy. Final cell sizing, grouped-cell behavior, animation timing/curve, and row sizing remain **TBD**.
|
||||
|
||||
The viewport must remain aligned with rendered content and hit testing. Robust clipping across adjacent outputs is **PLANNED**.
|
||||
|
||||
## Floating, fullscreen, and scratchpad
|
||||
|
||||
These remain ordinary Sway concepts. Mosaic does not redefine them. Headless tests have exercised basic floating, fullscreen, scratchpad, insertion, and layout transitions; longer multi-output and resize interactions are not fully validated. See [known limitations](KNOWN_LIMITATIONS.md).
|
||||
|
||||
## Workspaces and outputs
|
||||
|
||||
Mosaic does **not** replace Sway workspaces. Layout activation, previous standard layout, Row 0 state, and scroll belong to each workspace. A workspace may be moved between outputs; the camera must be bounded to its new viewport.
|
||||
|
||||
The desired multi-output model clips each workspace's visible Mosaic content to its own output viewport and keeps pointer hit testing consistent with the visible scene. This is **PLANNED**; the present single-output proof does not establish safe adjacent-output behavior.
|
||||
|
||||
## Open decisions
|
||||
|
||||
- Final cell width and nested-group sizing.
|
||||
- Exact Super + arrows and Super + Ctrl action mapping.
|
||||
- Multi-row insertion, navigation, and reflow details.
|
||||
- Camera animation curve and timing.
|
||||
- Fullscreen, floating, scratchpad, and output-migration edge-case policy after broader validation.
|
||||
|
||||
No binding or animation policy should be treated as frozen merely because a temporary implementation value exists.
|
||||
26
docs/assets/swayfx-mosaic-banner.svg
Normal file
26
docs/assets/swayfx-mosaic-banner.svg
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 330" role="img" aria-labelledby="title desc">
|
||||
<title id="title">SwayFX Mosaic — Spatial Canvas for SwayFX</title>
|
||||
<desc id="desc">Three ordered tiled rows extend across a dark logical canvas. A lavender viewport frame shows the visible part of a wider row.</desc>
|
||||
<defs>
|
||||
<pattern id="grid" width="32" height="32" patternUnits="userSpaceOnUse"><path d="M32 0H0V32" fill="none" stroke="#313244" stroke-width="1" opacity=".35"/></pattern>
|
||||
<clipPath id="canvas"><rect x="54" y="52" width="630" height="225" rx="11"/></clipPath>
|
||||
</defs>
|
||||
<rect width="1200" height="330" rx="18" fill="#1e1e2e"/>
|
||||
<rect width="1200" height="330" rx="18" fill="url(#grid)"/>
|
||||
<text x="56" y="38" fill="#a6adc8" font-family="sans-serif" font-size="14" letter-spacing="2">LOGICAL CANVAS</text>
|
||||
<g clip-path="url(#canvas)" font-family="sans-serif" font-weight="700" font-size="20" text-anchor="middle">
|
||||
<g fill="#313244" stroke="#89b4fa" stroke-width="2"><rect x="56" y="64" width="130" height="57" rx="7"/><rect x="194" y="64" width="130" height="57" rx="7"/><rect x="332" y="64" width="130" height="57" rx="7"/><rect x="470" y="64" width="130" height="57" rx="7"/><rect x="608" y="64" width="130" height="57" rx="7"/></g>
|
||||
<g fill="#cdd6f4"><text x="121" y="100">A</text><text x="259" y="100">B</text><text x="397" y="100">C</text><text x="535" y="100">D</text><text x="673" y="100">E</text></g>
|
||||
<g fill="#313244" stroke="#a6e3a1" stroke-width="2"><rect x="56" y="133" width="130" height="57" rx="7"/><rect x="194" y="133" width="130" height="57" rx="7"/><rect x="332" y="133" width="130" height="57" rx="7"/><rect x="470" y="133" width="130" height="57" rx="7"/><rect x="608" y="133" width="130" height="57" rx="7"/></g>
|
||||
<g fill="#cdd6f4"><text x="121" y="169">F</text><text x="259" y="169">G</text><text x="397" y="169">H</text><text x="535" y="169">I</text><text x="673" y="169">J</text></g>
|
||||
<g fill="#313244" stroke="#cba6f7" stroke-width="2"><rect x="56" y="202" width="130" height="57" rx="7"/><rect x="194" y="202" width="130" height="57" rx="7"/><rect x="332" y="202" width="130" height="57" rx="7"/><rect x="470" y="202" width="130" height="57" rx="7"/><rect x="608" y="202" width="130" height="57" rx="7"/></g>
|
||||
<g fill="#cdd6f4"><text x="121" y="238">K</text><text x="259" y="238">L</text><text x="397" y="238">M</text><text x="535" y="238">N</text><text x="673" y="238">O</text></g>
|
||||
</g>
|
||||
<rect x="190" y="57" width="414" height="208" rx="11" fill="none" stroke="#cba6f7" stroke-width="3" stroke-dasharray="9 6"/>
|
||||
<path d="M190 281v14h414v-14" fill="none" stroke="#cba6f7" stroke-width="2"/>
|
||||
<text x="397" y="312" text-anchor="middle" fill="#cba6f7" font-family="sans-serif" font-size="15" letter-spacing="1">PHYSICAL VIEWPORT</text>
|
||||
<rect x="750" y="64" width="4" height="202" rx="2" fill="#cba6f7"/>
|
||||
<text x="794" y="130" fill="#cdd6f4" font-family="sans-serif" font-size="44" font-weight="700">SwayFX Mosaic</text>
|
||||
<text x="796" y="172" fill="#cba6f7" font-family="sans-serif" font-size="22">Spatial Canvas for SwayFX</text>
|
||||
<text x="796" y="225" fill="#a6adc8" font-family="sans-serif" font-size="17">Native tiled layout · Experimental</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
Loading…
Reference in a new issue