From 30c2c8a154e770b3920bcfd7d553825fe9182bf4 Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Mon, 28 Sep 2026 12:57:47 -0300 Subject: Move the frame into draw.zig and the transitions out of layout.zig Pure moves, no behaviour change. draw.zig holds the whole core frame in order: render, the pane, tag, header and notice painters it calls, and the character-effect composition (Pardes.render stays a declaration alias). Presentation.zig is the panel presentation state as a file struct, and animation.zig the easing curves, transition kinds, tracks and boxes, the character effects' sources and the generic displayed-value transition, all of which lived in layout.zig. layout.zig keeps only layout. --- src/Messages.zig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/Messages.zig') diff --git a/src/Messages.zig b/src/Messages.zig index 72b3b63c..97a2f939 100644 --- a/src/Messages.zig +++ b/src/Messages.zig @@ -5,6 +5,7 @@ const pardes = @import("pardes.zig"); const memory = @import("memory.zig"); const std = @import("std"); const layout = @import("layout.zig"); +const animation = @import("animation.zig"); const ctlfs = @import("ninep/tree.zig"); const panes = @import("panes.zig"); const CellStyle = @import("surface.zig").CellStyle; @@ -285,7 +286,7 @@ pub const MessageMotion = struct { alpha: f32 = 1, slide: f32 = 0 }; /// Animation frames a message timing lasts; at least one. pub fn messageFrames(ms: u16) u16 { - return @intCast(@max(1, (@as(u32, ms) + layout.Animation.frame_ms - 1) / layout.Animation.frame_ms)); + return @intCast(@max(1, (@as(u32, ms) + animation.Animation.frame_ms - 1) / animation.Animation.frame_ms)); } pub fn messageMotion(p: *const Pardes, life: Pane.MessageLife) MessageMotion { -- cgit v1.3 From e0b5564f04aa0ae6666f29ef29c768d800fbabce Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Mon, 28 Sep 2026 13:15:41 -0300 Subject: Step core animation by the shell's clock and sleep to the next wake A shell now answers Host.now, its monotonic clock in ns, and the pump advances core animation to it: one .tick per whole 16 ms frame since core time last stood still. The same animation therefore takes the same time at 60, 120 and 144 Hz, over ssh and after a slow frame (the GUI's re-armed clock ran them ~25% slow at 144 Hz; the tty's post-frame sleep drifted). nextWake() lists every core animation in one place: a frame from now while anything moves, the end of the wait while something only waits (a message lingering, the look-hover delay), null when idle. Shells sleep exactly that long, and a wait is jumped to its end in one step, so an 800 ms linger costs one frame instead of fifty. An overshoot under 1.5 ms after a step is let go: at 60 and 120 Hz every display frame takes exactly one step (a 16 ms frame against a 16.67 ms vsync would otherwise double-step every 24th). The six tick drivers are gone: tty's timer thread only times the wait, interruptibly (a newer, shorter request cuts short a sleep still timing a longer one); the GUI's AnimationClock, web's JS tick bank (pardes_tick now takes rAF's timestamp), the detached server's and the board's ticks; grid mode steps a virtual clock straight to each wake. PARDES_TEST_CLOCK, set by the snapshot harness, gives tty and the detached server the same virtual clock. Every stepped frame is drawn. The old pump never drew the last frame of a fade (a .tick asks for no frame, and the fade was over by the check), so a theme switch stopped at 9/10 of the way until the next input: theme.golden, themesel.golden and the GUI's acme-light scene move to the theme's true colours, and nothing else changes. The frozen previous grid is captured only while a panel transition is chosen, not on every idle frame. --- docs/render-pipeline.md | 2 +- src/Messages.zig | 81 ++- src/Presentation.zig | 13 +- src/animation.zig | 261 +++++----- src/colors.zig | 8 +- src/detached/server.zig | 21 +- src/esp32p4.zig | 15 +- src/exec.zig | 4 + src/gui/gui.zig | 86 +--- src/host_io.zig | 17 + src/macos.zig | 8 +- src/pardes.zig | 151 +++++- src/tty/tty.zig | 108 +++- src/web.zig | 36 +- src/web/app.mjs | 36 +- test/gui-goldens.txt | 6 +- test/gui_golden.py | 4 +- test/pdf.zig | 2 +- test/snapshot.zig | 3 + test/snapshots/theme.golden | 1066 ++++++++++++++++++++-------------------- test/snapshots/themesel.golden | 945 ++++++++++++++++++----------------- test/web_harness.mjs | 16 +- 22 files changed, 1557 insertions(+), 1332 deletions(-) (limited to 'src/Messages.zig') diff --git a/docs/render-pipeline.md b/docs/render-pipeline.md index 2a679b8d..590a7e72 100644 --- a/docs/render-pipeline.md +++ b/docs/render-pipeline.md @@ -803,7 +803,7 @@ stripped. No visual change until stage 9 unless stated. |---|---|---| | 0 | GUI capture goldens: a handful of scenes rendered hidden in capture mode, PPM hashes checked in (same machine/driver) | the safety net the GUI stages need; machine- and driver-specific, so a LOCAL gate only, never CI | | 1 | pure moves: render → `src/draw.zig`; Presentation/animation out of layout.zig | no behaviour | -| 2a | clock plumbing: `now_ns` into pump/events, `nextWake`, `advance`, deadlines for linger/hover; all shells pass now and sleep to the wake; six tick drivers deleted; ack moves into pump; capturePrevious only when transitions are on. Animations still compute `frame = floor(elapsed / 16 ms)`, so every curve is identical | pacing is corrected (144 Hz no longer ~25% slow, ssh no longer drifts): a bug fix allowed in this phase. Unit tests step an injected clock by exactly 16 ms, so their numbers do not change. The snapshot harness runs the binary with `--test-clock` (each core-time step is exactly 16.67 ms per tick request, as today), so goldens see the same sequence and `stable` (test/snapshot.zig ~861) is unaffected by wall-time pacing | +| 2a | clock plumbing: `Host.now` (the shell's monotonic ns) and `Pardes.advance(now)`, which runs one `.tick` per whole 16 ms frame since core time last stood still; `nextWake()` lists every core animation and answers the next frame while anything moves, the wait's end while something only waits (message linger, look-hover delay), null when idle; the pump sleeps to it and draws only stepped frames. No shell posts `.tick` any more (tty's timer thread only wakes the wait; GUI's AnimationClock, web's JS tick bank and the detached server's and the board's ticks are gone; grid mode moves its virtual clock straight to the next wake). `acknowledgePanelPresentation` stays in the shells (revisit at stage 8: grid mode acks `&.{}` on purpose). capturePrevious only when transitions are on. `.tick` stays as the one-frame step `advance` and the unit tests use, so every curve and every asserted number is unchanged | pacing is corrected (144 Hz no longer ~25% slow, ssh no longer drifts): a bug fix allowed in this phase. PARDES_TEST_CLOCK (set by the snapshot harness): tty and the detached server answer a virtual clock that a timed-out wait moves exactly to the core's next wake, so goldens replay the same frame sequence on any machine load. Review fixes: tty's wake timer is interruptible (a newer, shorter request cuts short an older sleep); a wait (linger, hover delay) is jumped to its end in one step, never counted against the 240-frame catch-up cap; an overshoot under 1.5 ms after a step is let go, so 60 and 120 Hz take exactly one step per display frame. Known exceptions: the GUI still polls every 16 ms when idle (SDL events, gamepad, fs tick, smooth scroll depend on it; revisit at stage 8); a minimized GUI renders every stepped frame of a running animation (stage 8) | | 2b | (on `fx`, feel-reviewed) Tween/Spring curves, settle rules, OKLab crossfades, new durations from §8.1 | a look change, kept apart from 2a so either can be bisected | | 3 | paint functions take `s: *Surface`; delete the swap hack | mechanical, wide | | 4 | PLACE: Region list built once; renderPane/tags/notices read their rects from it | wait for tag→Text; the refactor is already replacing BOX_H with `pane.tag_rows` and `p.tagTop/bodyTop(pane, r)` — PLACE absorbs those into the region rects | diff --git a/src/Messages.zig b/src/Messages.zig index 97a2f939..7334de95 100644 --- a/src/Messages.zig +++ b/src/Messages.zig @@ -272,11 +272,35 @@ fn advanceLine(p: *const Pardes, life: *Pane.MessageLife) bool { return false; } -/// Is any message line moving (and so owed ticks)? -pub fn messagesAnimating(pane: *const Pane) bool { - if (pane.msg_len > 0 and pane.msg_life.phase != .shown) return true; - for (pane.msg_older[0..pane.msg_older_len]) |line| if (line.life.phase != .shown) return true; - return false; +/// Move every lingering message line `frames` along its linger at once: +/// how `advance` jumps a wait instead of stepping it frame by frame. +pub fn holdMessages(p: *Pardes, frames: u64) void { + const n: u16 = @intCast(@min(frames, std.math.maxInt(u16))); + for (p.panes) |slot| { + const pane = slot orelse continue; + if (pane.msg_len > 0 and pane.msg_life.phase == .lingering) pane.msg_life.frame +|= n; + for (pane.msg_older[0..pane.msg_older_len]) |*line| { + if (line.life.phase == .lingering) line.life.frame +|= n; + } + } +} + +/// Frames until this pane's message lines next change: 1 while a line +/// falls in or dissolves, the rest of its linger while one only waits, null +/// when every line just shows. +pub fn messageWake(p: *const Pardes, pane: *const Pane) ?u64 { + var soonest: ?u64 = null; + const linger = messageFrames(p.settings.message_linger_ms); + for (0..@as(usize, pane.msg_older_len) + 1) |i| { + const life = if (i < pane.msg_older_len) pane.msg_older[i].life else if (pane.msg_len > 0) pane.msg_life else continue; + const frames: u64 = switch (life.phase) { + .shown => continue, + .entering, .leaving => 1, + .lingering => @max(1, linger -| life.frame), + }; + soonest = if (soonest) |n| @min(n, frames) else frames; + } + return soonest; } /// How present a message is (1 = fully) and how far above its row it @@ -286,7 +310,7 @@ pub const MessageMotion = struct { alpha: f32 = 1, slide: f32 = 0 }; /// Animation frames a message timing lasts; at least one. pub fn messageFrames(ms: u16) u16 { - return @intCast(@max(1, (@as(u32, ms) + animation.Animation.frame_ms - 1) / animation.Animation.frame_ms)); + return @intCast(@max(1, (@as(u32, ms) + animation.frame_ms - 1) / animation.frame_ms)); } pub fn messageMotion(p: *const Pardes, life: Pane.MessageLife) MessageMotion { @@ -792,3 +816,48 @@ test "notices stack over the body's top rows without moving them" { for (p.surface.tagLayers()) |*layer| try std.testing.expect(layer.cols == 0 or layer.kind != .notice); } + +test "an idle core wants no wake and a lingering message sleeps to its linger's end" { + const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 80, .rows = 24 }); + defer p.deinit(); + while (p.nextEffect()) |_| {} + const frame = animation.frame_ns; + p.advance(1_000_000); + try std.testing.expectEqual(@as(?u64, null), p.nextWake()); + const pane = p.panes[p.active].?; + try std.testing.expect(p.executeBuiltinLine(p.active, "Msg hello")); + // Falling in: a frame from now. + try std.testing.expectEqual(@as(?u64, p.stepped_ns + frame), p.nextWake()); + const fall = messageFrames(p.settings.message_fall_ms); + p.advance(p.stepped_ns + fall * frame); + try std.testing.expectEqual(Pane.MessagePhase.shown, pane.msg_life.phase); + try std.testing.expectEqual(@as(?u64, null), p.nextWake()); + // A key starts the 800 ms linger: the core sleeps to its end, not a + // frame at a time, and the frames it jumps draw nothing. + p.update(.{ .key = .{ .cp = 'x' } }); + try std.testing.expectEqual(Pane.MessagePhase.lingering, pane.msg_life.phase); + const linger = messageFrames(p.settings.message_linger_ms); + const due = p.stepped_ns + linger * frame; + try std.testing.expectEqual(@as(?u64, due), p.nextWake()); + p.needs_frame = false; + p.advance(due - frame); + try std.testing.expectEqual(@as(?u64, due), p.nextWake()); + try std.testing.expectEqual(Pane.MessagePhase.lingering, pane.msg_life.phase); + p.advance(due); + try std.testing.expectEqual(Pane.MessagePhase.leaving, pane.msg_life.phase); + try std.testing.expectEqual(@as(?u64, due + frame), p.nextWake()); + p.advance(due + 10 * std.time.ns_per_s); + try std.testing.expectEqual(@as(usize, 0), pane.msg_len); + try std.testing.expectEqual(@as(?u64, null), p.nextWake()); + + // A long linger ends when it says, jumped in one step, not stretched by + // the cap on catching up with moving frames. + try std.testing.expect(p.executeBuiltinLine(p.active, "MessageLinger 5000")); + try std.testing.expect(p.executeBuiltinLine(p.active, "Msg again")); + p.advance(p.stepped_ns + fall * frame); + p.update(.{ .key = .{ .cp = 'x' } }); + const long_due = p.stepped_ns + messageFrames(5000) * frame; + try std.testing.expectEqual(@as(?u64, long_due), p.nextWake()); + p.advance(long_due); + try std.testing.expectEqual(Pane.MessagePhase.leaving, pane.msg_life.phase); +} diff --git a/src/Presentation.zig b/src/Presentation.zig index fe8317dd..45b196c8 100644 --- a/src/Presentation.zig +++ b/src/Presentation.zig @@ -295,11 +295,18 @@ pub fn acknowledge(self: *Presentation, p: *Pardes, tracks: []const Track) void self.tracks = @splat(null); self.closing_len = 0; self.diff_state = .none; - self.capturePrevious(p.gpa, &p.surface); + // The frozen grid exists for transitions alone: with them off, an + // idle frame copies nothing. + if (p.settings.panel_transition != .off) { + self.capturePrevious(p.gpa, &p.surface); + } else { + self.previous_valid = false; + self.previous_layout = @splat(null); + } } } -fn capturePrevious(self: *Presentation, gpa: std.mem.Allocator, surface: *const pardes.Surface) void { +pub fn capturePrevious(self: *Presentation, gpa: std.mem.Allocator, surface: *const pardes.Surface) void { self.diff_state = .none; const cells = surface.cells; if (cells.len == 0) { @@ -651,6 +658,8 @@ test "presentation submission failure preserves shown geometry until retry is ac defer p.deinit(); var frame: std.heap.ArenaAllocator = .init(std.testing.allocator); defer frame.deinit(); + // The frozen grid is kept only while a transition is chosen. + p.settings.panel_transition = .slide; _ = try p.render(frame.allocator()); p.acknowledgePanelPresentation(&.{}); const shown = p.presentation.shown; diff --git a/src/animation.zig b/src/animation.zig index b190c1a1..d6ef1ec3 100644 --- a/src/animation.zig +++ b/src/animation.zig @@ -588,157 +588,158 @@ test "dissolve has exact stable endpoints" { } } -pub const Animation = struct { - pub const frame_ms: u32 = 16; - pub const frame_ns: u64 = frame_ms * std.time.ns_per_ms; - pub const transition_steps: u16 = 10; - - pub fn Transition(comptime Value: type) type { - return struct { - const Self = @This(); - - from: Value, - to: Value, - displayed: Value, - step: u16 = transition_steps, - - pub fn init(value: Value) Self { - return .{ .from = value, .to = value, .displayed = value }; - } +pub const frame_ms: u32 = 16; +pub const frame_ns: u64 = frame_ms * std.time.ns_per_ms; +pub const transition_steps: u16 = 10; + +/// A displayed value that fades from one target to the next over +/// `transition_steps` frames; the chrome colours are one. +pub fn Fade(comptime Value: type) type { + return struct { + const Self = @This(); + + from: Value, + to: Value, + displayed: Value, + step: u16 = transition_steps, + + pub fn init(value: Value) Self { + return .{ .from = value, .to = value, .displayed = value }; + } - pub fn isActive(a: *const Self) bool { - return a.step < transition_steps; - } + pub fn isActive(a: *const Self) bool { + return a.step < transition_steps; + } - pub fn retarget(a: *Self, target: Value) void { - a.from = a.displayed; - a.to = target; - a.step = if (std.meta.eql(a.from, target)) transition_steps else 0; - if (a.step == transition_steps) a.displayed = target; - } + pub fn retarget(a: *Self, target: Value) void { + a.from = a.displayed; + a.to = target; + a.step = if (std.meta.eql(a.from, target)) transition_steps else 0; + if (a.step == transition_steps) a.displayed = target; + } - pub fn advance(a: *Self) void { - if (!a.isActive()) return; - a.step += 1; - a.displayed = if (a.step == transition_steps) - a.to - else - Value.interpolate(a.from, a.to, a.step, transition_steps); - } + pub fn advance(a: *Self) void { + if (!a.isActive()) return; + a.step += 1; + a.displayed = if (a.step == transition_steps) + a.to + else + Value.interpolate(a.from, a.to, a.step, transition_steps); + } - pub fn snap(a: *Self, value: Value) void { - a.* = init(value); - } - }; - } + pub fn snap(a: *Self, value: Value) void { + a.* = init(value); + } + }; +} - pub fn Immediate(comptime Value: type) type { - return struct { - const Self = @This(); +pub fn Immediate(comptime Value: type) type { + return struct { + const Self = @This(); - displayed: Value, + displayed: Value, - pub fn init(value: Value) Self { - return .{ .displayed = value }; - } + pub fn init(value: Value) Self { + return .{ .displayed = value }; + } - pub fn isActive(_: *const Self) bool { - return false; - } + pub fn isActive(_: *const Self) bool { + return false; + } - pub fn retarget(a: *Self, target: Value) void { - a.displayed = target; - } + pub fn retarget(a: *Self, target: Value) void { + a.displayed = target; + } - pub fn advance(_: *Self) void {} + pub fn advance(_: *Self) void {} - pub fn snap(a: *Self, value: Value) void { - a.displayed = value; - } - }; - } - - pub fn interpolateRgb(from: [3]u8, to: [3]u8, step: u16, steps: u16) [3]u8 { - if (step == 0) return from; - if (step >= steps) return to; - var out: [3]u8 = undefined; - for (&out, from, to) |*dst, a, b| { - const numerator = @as(u32, a) * (steps - step) + @as(u32, b) * step; - dst.* = @intCast((numerator + steps / 2) / steps); + pub fn snap(a: *Self, value: Value) void { + a.displayed = value; } - return out; + }; +} + +pub fn interpolateRgb(from: [3]u8, to: [3]u8, step: u16, steps: u16) [3]u8 { + if (step == 0) return from; + if (step >= steps) return to; + var out: [3]u8 = undefined; + for (&out, from, to) |*dst, a, b| { + const numerator = @as(u32, a) * (steps - step) + @as(u32, b) * step; + dst.* = @intCast((numerator + steps / 2) / steps); } + return out; +} - const TestColor = struct { - rgb: [3]u8, +const TestColor = struct { + rgb: [3]u8, - pub fn interpolate(from: TestColor, to: TestColor, step: u16, steps: u16) TestColor { - return .{ .rgb = interpolateRgb(from.rgb, to.rgb, step, steps) }; - } - }; + pub fn interpolate(from: TestColor, to: TestColor, step: u16, steps: u16) TestColor { + return .{ .rgb = interpolateRgb(from.rgb, to.rgb, step, steps) }; + } +}; - test "Immediate lands where a completed Transition lands" { - const from: TestColor = .{ .rgb = .{ 240, 3, 90 } }; - const to: TestColor = .{ .rgb = .{ 5, 222, 90 } }; +test "Immediate lands where a completed Transition lands" { + const from: TestColor = .{ .rgb = .{ 240, 3, 90 } }; + const to: TestColor = .{ .rgb = .{ 5, 222, 90 } }; - var faded = Animation.Transition(TestColor).init(from); - faded.retarget(to); - for (0..transition_steps) |_| faded.advance(); + var faded = Fade(TestColor).init(from); + faded.retarget(to); + for (0..transition_steps) |_| faded.advance(); - var instant = Immediate(TestColor).init(from); - try std.testing.expect(!instant.isActive()); - instant.retarget(to); - try std.testing.expectEqual(faded.displayed, instant.displayed); + var instant = Immediate(TestColor).init(from); + try std.testing.expect(!instant.isActive()); + instant.retarget(to); + try std.testing.expectEqual(faded.displayed, instant.displayed); - // Never active, so a frontend that renders only while something is animating stops immediately - // rather than spending ten frames discovering there is nothing to draw. - try std.testing.expect(!instant.isActive()); - instant.advance(); - try std.testing.expectEqual(to, instant.displayed); + // Never active, so a frontend that renders only while something is animating stops immediately + // rather than spending ten frames discovering there is nothing to draw. + try std.testing.expect(!instant.isActive()); + instant.advance(); + try std.testing.expectEqual(to, instant.displayed); - instant.snap(from); - try std.testing.expectEqual(from, instant.displayed); - } + instant.snap(from); + try std.testing.expectEqual(from, instant.displayed); +} - test "fixed-step interpolation has exact monotonic endpoints" { - const Tween = Animation.Transition(TestColor); - const from: TestColor = .{ .rgb = .{ 240, 3, 90 } }; - const to: TestColor = .{ .rgb = .{ 5, 222, 90 } }; - var tween = Tween.init(from); - tween.retarget(to); - try std.testing.expectEqual(from, tween.displayed); - - var previous = tween.displayed; - for (0..transition_steps) |_| { - tween.advance(); - try std.testing.expect(tween.displayed.rgb[0] <= previous.rgb[0]); - try std.testing.expect(tween.displayed.rgb[1] >= previous.rgb[1]); - try std.testing.expectEqual(@as(u8, 90), tween.displayed.rgb[2]); - previous = tween.displayed; - } - try std.testing.expect(!tween.isActive()); - try std.testing.expectEqual(to, tween.displayed); - tween.advance(); - try std.testing.expectEqual(to, tween.displayed); - } +test "fixed-step interpolation has exact monotonic endpoints" { + const Tween = Fade(TestColor); + const from: TestColor = .{ .rgb = .{ 240, 3, 90 } }; + const to: TestColor = .{ .rgb = .{ 5, 222, 90 } }; + var tween = Tween.init(from); + tween.retarget(to); + try std.testing.expectEqual(from, tween.displayed); - test "retarget starts at the currently displayed value" { - const Tween = Animation.Transition(TestColor); - const first: TestColor = .{ .rgb = .{ 0, 40, 200 } }; - const second: TestColor = .{ .rgb = .{ 200, 140, 0 } }; - const third: TestColor = .{ .rgb = .{ 20, 10, 250 } }; - var tween = Tween.init(first); - tween.retarget(second); - tween.advance(); - tween.advance(); + var previous = tween.displayed; + for (0..transition_steps) |_| { tween.advance(); - const on_screen = tween.displayed; - - tween.retarget(third); - try std.testing.expectEqual(on_screen, tween.from); - try std.testing.expectEqual(on_screen, tween.displayed); - try std.testing.expect(tween.isActive()); - for (0..transition_steps) |_| tween.advance(); - try std.testing.expectEqual(third, tween.displayed); + try std.testing.expect(tween.displayed.rgb[0] <= previous.rgb[0]); + try std.testing.expect(tween.displayed.rgb[1] >= previous.rgb[1]); + try std.testing.expectEqual(@as(u8, 90), tween.displayed.rgb[2]); + previous = tween.displayed; } -}; + try std.testing.expect(!tween.isActive()); + try std.testing.expectEqual(to, tween.displayed); + tween.advance(); + try std.testing.expectEqual(to, tween.displayed); +} + +test "retarget starts at the currently displayed value" { + const Tween = Fade(TestColor); + const first: TestColor = .{ .rgb = .{ 0, 40, 200 } }; + const second: TestColor = .{ .rgb = .{ 200, 140, 0 } }; + const third: TestColor = .{ .rgb = .{ 20, 10, 250 } }; + var tween = Tween.init(first); + tween.retarget(second); + tween.advance(); + tween.advance(); + tween.advance(); + const on_screen = tween.displayed; + + tween.retarget(third); + try std.testing.expectEqual(on_screen, tween.from); + try std.testing.expectEqual(on_screen, tween.displayed); + try std.testing.expect(tween.isActive()); + for (0..transition_steps) |_| tween.advance(); + try std.testing.expectEqual(third, tween.displayed); +} + diff --git a/src/colors.zig b/src/colors.zig index f814d55d..0065d5ef 100644 --- a/src/colors.zig +++ b/src/colors.zig @@ -186,15 +186,15 @@ pub const ChromeTheme = struct { pub fn interpolate(from: ChromeTheme, to: ChromeTheme, step: u16, steps: u16) ChromeTheme { var out: ChromeTheme = undefined; inline for (@typeInfo(ChromeTheme).@"struct".fields) |field| - @field(out, field.name) = animation.Animation.interpolateRgb(@field(from, field.name), @field(to, field.name), step, steps); + @field(out, field.name) = animation.interpolateRgb(@field(from, field.name), @field(to, field.name), step, steps); return out; } }; pub const ChromeAnimation = if (theme_animation) - animation.Animation.Transition(ChromeTheme) + animation.Fade(ChromeTheme) else - animation.Animation.Immediate(ChromeTheme); + animation.Immediate(ChromeTheme); pub const initial_chrome = ChromeTheme.fromTheme(&themes[0]); @@ -414,7 +414,7 @@ test "runtime theme changes animate chrome and retarget without a jump" { try std.testing.expectEqualStrings("acme", p.theme().name); try std.testing.expectEqual(midflight, p.chromeTheme().*); try std.testing.expect(p.animationActive()); - for (0..animation.Animation.transition_steps) |_| p.update(.tick); + for (0..animation.transition_steps) |_| p.update(.tick); try std.testing.expect(!p.animationActive()); try std.testing.expectEqual(ChromeTheme.fromTheme(p.theme()), p.chromeTheme().*); // Extra ticks are inert at the exact endpoint. diff --git a/src/detached/server.zig b/src/detached/server.zig index 5c0e1487..212c9a3d 100644 --- a/src/detached/server.zig +++ b/src/detached/server.zig @@ -140,6 +140,8 @@ pub const Session = struct { worker_gpa: std.mem.Allocator, io: std.Io, core: *pardes.Pardes, + /// PARDES_TEST_CLOCK's virtual time (host_io.testClock). + test_clock: ?u64 = null, listener: c_int = -1, path_buf: [sun_path_len]u8 = undefined, path_len: usize = 0, @@ -343,8 +345,14 @@ pub const Session = struct { return @ptrCast(@alignCast(ctx.?)); } + fn clockNow(ctx: ?*anyopaque) u64 { + const s = of(ctx); + return s.test_clock orelse host_io.monotonicNs(); + } + const vtable: host_io.Host.VTable = .{ .wait_input = waitInput, + .now = clockNow, .present = present, .poll_frame = pollFrame, .spawn = spawn, @@ -827,8 +835,9 @@ pub const Session = struct { pardes.turn.rest(); nap(if (timeout_ms == 0) 16 else timeout_ms); pardes.turn.wake(); - // An animating frame's wait is the frame: tick it. - if (timeout_ms != 0) s.core.update(.tick); + if (timeout_ms != 0) if (s.test_clock) |*virtual| { + virtual.* = @max(virtual.*, s.core.nextWake() orelse virtual.*); + }; return; } var timeout: c_int = if (timeout_ms == 0) -1 else @intCast(@min(timeout_ms, std.math.maxInt(c_int))); @@ -838,9 +847,10 @@ pub const Session = struct { const ready = libc.poll(&fds, @intCast(n), timeout); pardes.turn.wake(); if (ready > 0) s.dispatch(fds[0..n], src[0..n]); - // Animating, the frame's time is up: advance it. There is no other - // tick in a detached session, and without it an animation never ends. - if (timeout_ms != 0 and monotonicMs() -| now >= timeout_ms) s.core.update(.tick); + // The core's wake ran out; the pump advances it from `now`. + if (timeout_ms != 0 and monotonicMs() -| now >= timeout_ms) if (s.test_clock) |*virtual| { + virtual.* = @max(virtual.*, s.core.nextWake() orelse virtual.*); + }; _ = s.drainCompletions(true); s.expire(monotonicMs()); s.harvest(); @@ -1155,6 +1165,7 @@ pub fn run(init: std.process.Init, opts: pardes.Options, name: []const u8) !void .cols = options.cols, .rows = options.rows, .prompt_rcs = host_io.Shell.prepare(), + .test_clock = host_io.testClock(), }; defer session.core.deinit(); defer session.deinit(); diff --git a/src/esp32p4.zig b/src/esp32p4.zig index 0d532e1e..c583de54 100644 --- a/src/esp32p4.zig +++ b/src/esp32p4.zig @@ -572,10 +572,9 @@ export fn pardes_esp32p4_tick(now_ms: u64) callconv(.c) void { dirty = true; } } - if (c.animationActive()) { - c.update(.tick); - dirty = true; - } + // The core steps its own animations by this clock (`Host.now`). + c.advance(now_ms * std.time.ns_per_ms); + if (c.needs_frame) dirty = true; } /// How long a lone ESC waits for a second byte before it counts as the Escape key. @@ -590,7 +589,7 @@ var esc_held_at: ?u64 = null; export fn pardes_esp32p4_wants_frame() callconv(.c) bool { const c = core orelse return false; - return dirty or c.animationActive(); + return dirty or c.needs_frame; } export fn pardes_esp32p4_render() callconv(.c) u32 { @@ -607,7 +606,11 @@ export fn pardes_esp32p4_quit() callconv(.c) bool { // ------------------------------------------------------------------------------------ the host -const pardes_host: pardes.Host.VTable = .{ .present = present, .gpio_toggle = gpioToggle }; +const pardes_host: pardes.Host.VTable = .{ .now = boardNow, .present = present, .gpio_toggle = gpioToggle }; + +fn boardNow(_: ?*anyopaque) u64 { + return last_now_ms * std.time.ns_per_ms; +} /// The `Gpio` word's one seam to the board. Nothing here knows what a pad is; it forwards, and /// answers false when the firmware brought none, which is what puts "gpio: NoPads" on the message diff --git a/src/exec.zig b/src/exec.zig index b16c600c..ad0f7b9b 100644 --- a/src/exec.zig +++ b/src/exec.zig @@ -502,6 +502,10 @@ pub fn applySettingBuiltin(p: *Pardes, setting: config.Runtime.Setting, arg: ?[] if (p.settings.column_tags != previous_column_tags) { if (p.header_column != null) tagline.exitHeader(p); } + // Idle frames keep no frozen grid while transitions are off; the one + // just drawn is the baseline the first transition starts from. + if (transition_changed and previous_transition == .off) + p.presentation.capturePrevious(p.gpa, &p.surface); if (transition_changed or tagline_metrics_changed or p.settings.column_tags != previous_column_tags) { p.abandonPanelAnimations(); } diff --git a/src/gui/gui.zig b/src/gui/gui.zig index 0737bb63..a1e21dc0 100644 --- a/src/gui/gui.zig +++ b/src/gui/gui.zig @@ -200,55 +200,18 @@ const touch_click_flash_max_frames: u8 = 14; const touch_click_flash_vertices: usize = 1400; const touch_scroll_tick: f32 = 0.02; -const AnimationClock = struct { - next_ns: u64 = 0, - - fn due(clock: *AnimationClock, active: bool, now_ns: u64) bool { - if (!active) { - clock.next_ns = 0; - return false; - } - if (clock.next_ns == 0) { - clock.next_ns = now_ns +| pardes.animation.Animation.frame_ns; - return false; - } - if (now_ns < clock.next_ns) return false; - clock.next_ns = now_ns +| pardes.animation.Animation.frame_ns; - return true; - } -}; - -fn finishPresentedAnimationFrame( - clock: *AnimationClock, - core: *pardes.Pardes, - tracks: []const pardes.animation.Track, - now_ns: u64, -) void { - core.acknowledgePanelPresentation(tracks); - if (clock.due(core.animationActive(), now_ns)) core.update(.tick); -} - -test "GUI animation clock is active-only and cadence gated" { - var clock: AnimationClock = .{}; - try std.testing.expect(!clock.due(false, 100)); - try std.testing.expect(!clock.due(true, 100)); - try std.testing.expect(!clock.due(true, 100 + pardes.animation.Animation.frame_ns - 1)); - try std.testing.expect(clock.due(true, 100 + pardes.animation.Animation.frame_ns)); - try std.testing.expect(!clock.due(false, 100 + 2 * pardes.animation.Animation.frame_ns)); - try std.testing.expectEqual(@as(u64, 0), clock.next_ns); -} - test "a persistent scene presents a new panel's frame zero before advancing it" { const core = try pardes.Pardes.init(std.testing.allocator, .{ .tty_only = true }); defer core.deinit(); var arena: std.heap.ArenaAllocator = .init(std.testing.allocator); defer arena.deinit(); - var clock: AnimationClock = .{}; + const frame = pardes.animation.frame_ns; core.settings.scene_effects.crt = true; + core.advance(100); const scene_frame = try core.render(arena.allocator()); - finishPresentedAnimationFrame(&clock, core, scene_frame.panelTracks(), 100); - try std.testing.expectEqual(@as(u64, 100 + pardes.animation.Animation.frame_ns), clock.next_ns); + core.acknowledgePanelPresentation(scene_frame.panelTracks()); + try std.testing.expectEqual(@as(?u64, 100 + frame), core.nextWake()); core.settings.panel_transition = .slide; core.update(.{ .command = "Newcol" }); @@ -258,12 +221,12 @@ test "a persistent scene presents a new panel's frame zero before advancing it" try std.testing.expect(track_count > 0); for (first.panelTracks()) |track| try std.testing.expectEqual(@as(u16, 0), track.frame); - finishPresentedAnimationFrame( - &clock, - core, - first.panelTracks(), - 100 + pardes.animation.Animation.frame_ns, - ); + core.acknowledgePanelPresentation(first.panelTracks()); + // Just short of a frame is no frame at all. + core.advance(100 + frame - 1); + _ = arena.reset(.retain_capacity); + for ((try core.render(arena.allocator())).panelTracks()) |track| try std.testing.expectEqual(@as(u16, 0), track.frame); + core.advance(100 + frame); _ = arena.reset(.retain_capacity); const second = try core.render(arena.allocator()); try std.testing.expectEqual(track_count, second.panelTracks().len); @@ -3742,7 +3705,6 @@ const Shell = struct { presented: bool = false, skipped_presents: u8 = 0, surface: ?*pardes.Surface = null, - animation_clock: AnimationClock = .{}, saw_event: bool = false, dump_err: ?anyerror = null, retired_shells: [pardes.MAX_PANES]RetiredShell = @splat(.{}), @@ -3832,6 +3794,7 @@ const Shell = struct { const vtable: pardes.Host.VTable = .{ .wait_input = waitInput, + .now = guiNow, .present = present, .post_present = postPresent, .poll_frame = pollFrame, @@ -3857,6 +3820,7 @@ const Shell = struct { const grid_vtable: pardes.Host.VTable = vt: { var v = vtable; v.wait_input = null; + v.now = null; v.poll_frame = gridPollFrame; v.present = gridPresent; v.post_present = gridPostPresent; @@ -4106,20 +4070,16 @@ fn present(ctx: ?*anyopaque, surface: *const pardes.Surface) void { fn postPresent(ctx: ?*anyopaque) void { const s = shellOf(ctx); const g = s.gui orelse return; - if (!s.presented) { - // No image (a minimized window): time still passes, so a lingering - // message or a hover wait runs out instead of redrawing forever. - if (s.animation_clock.due(s.core.animationActive(), c.SDL_GetTicksNS())) s.core.update(.tick); - return; - } + // No image (a minimized window) shows no tracks; time still passes and + // the pump advances it all the same. + if (!s.presented) return; const frame = s.surface orelse return; refreshPresentedPointer(g, s.core); - finishPresentedAnimationFrame( - &s.animation_clock, - s.core, - frame.panelTracks(), - c.SDL_GetTicksNS(), - ); + s.core.acknowledgePanelPresentation(frame.panelTracks()); +} + +fn guiNow(_: ?*anyopaque) u64 { + return c.SDL_GetTicksNS(); } fn gridPollFrame(ctx: ?*anyopaque) void { @@ -4129,8 +4089,10 @@ fn gridPollFrame(ctx: ?*anyopaque) void { if (f.tick().count != 0) s.saw_event = true; } pollCwds(s.core, s.ptys); - if (s.core.animationActive()) { - s.core.update(.tick); + // Grid time is virtual: each poll moves it straight to the core's + // next wake, a frame at a time while anything moves. + if (s.core.nextWake()) |due| { + s.core.advance(due); s.saw_event = true; } } diff --git a/src/host_io.zig b/src/host_io.zig index 6009c00f..f1a4eb98 100644 --- a/src/host_io.zig +++ b/src/host_io.zig @@ -12,6 +12,9 @@ pub const Host = struct { pub const VTable = struct { wait_input: ?*const fn (ctx: ?*anyopaque, timeout_ms: u32) void = null, + /// The shell's monotonic clock in ns: the only time the core sees. + /// Without one, core animation moves only by `.tick` events. + now: ?*const fn (ctx: ?*anyopaque) u64 = null, present: ?*const fn (ctx: ?*anyopaque, surface: *const pardes.Surface) void = null, post_present: ?*const fn (ctx: ?*anyopaque) void = null, poll_frame: ?*const fn (ctx: ?*anyopaque) void = null, @@ -39,6 +42,20 @@ pub const Host = struct { }; }; +/// The shells' monotonic clock in ns, the one `Host.now` answers with. +/// PARDES_TEST_CLOCK makes a shell answer a virtual clock instead, moved +/// only when a timed wait runs out -- straight to the core's next wake -- so +/// the snapshot harness sees the same frames whatever the machine's load. +pub fn monotonicNs() u64 { + var ts: libc.timespec = undefined; + if (libc.clock_gettime(.MONOTONIC, &ts) != 0) return 0; + return @as(u64, @intCast(ts.sec)) * std.time.ns_per_s + @as(u64, @intCast(ts.nsec)); +} + +pub fn testClock() ?u64 { + return if (libc.getenv("PARDES_TEST_CLOCK")) |v| (if (std.mem.span(v).len != 0) 0 else null) else null; +} + pub const Fallback = struct { pub const dump_path = "pardes.dump.zon"; diff --git a/src/macos.zig b/src/macos.zig index 854b24f8..fce0a53e 100644 --- a/src/macos.zig +++ b/src/macos.zig @@ -118,7 +118,7 @@ const scene_frame_hz: u32 = 60; const scene_wrap_ns: u64 = 4096 * std.time.ns_per_s; -const max_tick_catch_up_ns: u64 = 4 * pardes.animation.Animation.frame_ns; +const max_tick_catch_up_ns: u64 = 4 * pardes.animation.frame_ns; const theme_watch_pane: u8 = @intCast(pardes.MAX_PANES); const watch_slot_count = pardes.MAX_PANES + 1; @@ -870,18 +870,18 @@ const TickSpend = struct { elapsed_ns: u64, steps: u32, bank_ns: u64 }; fn spendTickTime(previous_ns: u64, now_ns: u64, bank_ns: u64) TickSpend { const measured = if (previous_ns == 0 or now_ns <= previous_ns) - pardes.animation.Animation.frame_ns + pardes.animation.frame_ns else now_ns - previous_ns; const elapsed = @min(measured, max_tick_catch_up_ns); var bank = bank_ns +| elapsed; var steps: u32 = 0; - while (bank >= pardes.animation.Animation.frame_ns) : (steps += 1) bank -= pardes.animation.Animation.frame_ns; + while (bank >= pardes.animation.frame_ns) : (steps += 1) bank -= pardes.animation.frame_ns; return .{ .elapsed_ns = elapsed, .steps = steps, .bank_ns = bank }; } test "the animation clock spends real time, not callbacks" { - const frame = pardes.animation.Animation.frame_ns; + const frame = pardes.animation.frame_ns; const expectEqual = std.testing.expectEqual; const first = spendTickTime(0, 999 * std.time.ns_per_s, 0); diff --git a/src/pardes.zig b/src/pardes.zig index bfd8a4f6..161a047c 100644 --- a/src/pardes.zig +++ b/src/pardes.zig @@ -3337,9 +3337,9 @@ test "vertical close samples only a canonical baseline containing that pane" { defer p.deinit(); var frame = std.heap.ArenaAllocator.init(std.testing.allocator); defer frame.deinit(); + p.settings.panel_transition = .vertical; const boot = try p.render(frame.allocator()); p.acknowledgePanelPresentation(boot.panelTracks()); - p.settings.panel_transition = .vertical; _ = try p.newShell(1, ""); try std.testing.expect(layout.splitColumn(p, 0, 1, false)); @@ -3360,9 +3360,9 @@ test "vertical close samples only a canonical baseline containing that pane" { defer p.deinit(); var frame = std.heap.ArenaAllocator.init(std.testing.allocator); defer frame.deinit(); + p.settings.panel_transition = .vertical; const boot = try p.render(frame.allocator()); p.acknowledgePanelPresentation(boot.panelTracks()); - p.settings.panel_transition = .vertical; _ = try p.newShell(1, ""); try std.testing.expect(layout.splitColumn(p, 0, 1, false)); @@ -3386,9 +3386,9 @@ test "previous-grid animation refreshes its mask and snaps overlapping layout ch defer p.deinit(); var frame = std.heap.ArenaAllocator.init(std.testing.allocator); defer frame.deinit(); + p.settings.panel_transition = .vertical; const boot = try p.render(frame.allocator()); p.acknowledgePanelPresentation(boot.panelTracks()); - p.settings.panel_transition = .vertical; _ = try p.newShell(1, ""); try std.testing.expect(layout.splitColumn(p, 0, 1, false)); @@ -3875,6 +3875,13 @@ pub const Pardes = struct { /// Set by a shell whose present was skipped (no swapchain image): the /// frame is still owed, and the next pump draws it again. present_skipped: bool = false, + /// Core time. `now_ns` is the shell's monotonic clock as `advance` was + /// last given it; `stepped_ns` is how far animation has been stepped + /// along it, in whole frames of `animation.frame_ns`. Idle, the two are + /// the same instant. + now_ns: u64 = 0, + stepped_ns: u64 = 0, + clock_started: bool = false, /// Builtins announce themselves on the message row. Off while startup /// configuration is applied: those lines are nobody clicking, and should /// not leave the row holding the name of the last one. @@ -4647,7 +4654,17 @@ pub const Pardes = struct { pub fn pump(p: *Pardes, h: Host) !void { p.host = h; const v = h.vtable; - if (v.wait_input) |f| f(h.ctx, if (p.animationActive()) animation.Animation.frame_ms else 0); + if (v.wait_input) |f| { + // Asleep until input or until core animation next needs a + // frame; 0 is no timeout at all. + const timeout: u32 = if (p.nextWake()) |due| wake: { + const now = if (v.now) |clock| clock(h.ctx) else p.now_ns; + const ms = ((due -| now) + std.time.ns_per_ms - 1) / std.time.ns_per_ms; + break :wake @intCast(std.math.clamp(ms, 1, std.math.maxInt(u32))); + } else 0; + f(h.ctx, timeout); + } + if (v.now) |clock| p.advance(clock(h.ctx)); while (p.nextQueued()) |ev| p.update(ev); while (p.nextEffect()) |e| p.perform(e); turn.settle(); @@ -4657,7 +4674,9 @@ pub const Pardes = struct { // Nothing to draw: do not spend a frame, and above all do not block on // the display for one. This is what keeps the frame rate governing // rendering and nothing else. - if (!p.needs_frame and !p.animationActive()) return; + // A shell with a clock draws what `advance` stepped; one without + // steps its own `.tick`s and draws while anything animates. + if (!p.needs_frame and (v.now != null or !p.animationActive())) return; _ = p.frame_arena.reset(.retain_capacity); const surface = try p.render(p.frame_arena.allocator()); if (v.present) |f| f(h.ctx, surface); @@ -5717,18 +5736,85 @@ pub const Pardes = struct { return &p.chrome_animation.displayed; } - /// Whether an idle frontend should schedule another tick. All frame-based - /// core work belongs in this one predicate so TTY and GUI mature it alike. - pub fn animationActive(p: *const Pardes) bool { - if (p.chrome_animation.isActive() or p.look_hover_wait != null) return true; + /// When core animation next needs a frame, on the `stepped_ns` + /// timeline: a frame from now while anything moves, the end of the + /// wait while something only waits (a message lingering, a look-hover + /// delay), null when nothing is animating. Every frame-based animation + /// the core owns is in this one list, which is what lets every shell + /// sleep exactly as long as nothing changes. + pub fn nextWake(p: *const Pardes) ?u64 { + const next = p.stepped_ns + animation.frame_ns; + if (p.chrome_animation.isActive() or p.presentation.animating()) return next; + const scene = p.settings.scene_effects; + if (scene.crt or scene.ripple or scene.glitch) return next; + var frames: ?u64 = null; + if (p.look_hover_wait) |waiting| { + const delay = config.look_preview_delay_frames orelse return next; + frames = @max(1, delay -| waiting.frames); + } for (p.panes) |slot| if (slot) |pane| { - if (Messages.messagesAnimating(pane)) return true; + const wait = Messages.messageWake(p, pane) orelse continue; + frames = if (frames) |soonest| @min(soonest, wait) else wait; }; - const scene = p.settings.scene_effects; - if (scene.crt or scene.ripple or scene.glitch) return true; - return p.presentation.animating(); + return if (frames) |n| p.stepped_ns + n * animation.frame_ns else null; } + /// For shells that only need a yes or no: macOS and the board, which + /// keep their own frame banks. + pub fn animationActive(p: *const Pardes) bool { + return p.nextWake() != null; + } + + /// Bring core animation up to `now_ns`, the shell's monotonic clock: one + /// `.tick` for every whole frame that has passed since it last stood + /// still, so an animation takes as long on a 144 Hz display, over ssh or + /// after a slow frame as it does anywhere. A wait (a message lingering, + /// the look-hover delay) is jumped to its end in one step and drawn + /// once. Idle, time is not banked: the next animation starts from now. + pub fn advance(p: *Pardes, now_ns: u64) void { + // The first time a shell's clock is seen, core time starts there. + const started = p.clock_started; + p.clock_started = true; + p.now_ns = now_ns; + if (!started) p.stepped_ns = now_ns; + const frame = animation.frame_ns; + var moving: u32 = 0; + while (p.nextWake()) |due| { + if (due > now_ns) break; + // Only waiting until `due`: its counters move there at once. + const held = (due - p.stepped_ns) / frame; + if (held > 1) { + Messages.holdMessages(p, held - 1); + if (p.look_hover_wait) |*waiting| waiting.frames +|= @intCast(@min(held - 1, std.math.maxInt(u16))); + p.stepped_ns += (held - 1) * frame; + } + // Back from a stall, the moving frames it missed are not all + // run at once: the rest are stepped from now, at their pace. + if (moving == max_catch_up_frames) { + p.stepped_ns = now_ns; + return; + } + moving += 1; + p.stepped_ns += frame; + p.update(.tick); + // A stepped frame is a frame to draw. (A `.tick` does not ask + // for one itself: the last frame of a fade used never to be + // drawn.) + p.needs_frame = true; + } else { + p.stepped_ns = now_ns; + return; + } + // A 60 Hz display frame is 16.67 ms and ours 16: without this, every + // 24th display frame would take two steps, a hitch in every fade. + // An overshoot this small is let go; a larger one (144 Hz lands 4.8 + // ms past) is kept, so the average rate stays right. + if (moving > 0 and now_ns - p.stepped_ns < vsync_slack_ns) p.stepped_ns = now_ns; + } + + pub const vsync_slack_ns = 1500 * std.time.ns_per_us; + pub const max_catch_up_frames = 240; + pub fn noteHaptic(p: *Pardes, pulse: Haptic) void { if (comptime platform != .macos) return; if (p.haptic == .look) return; @@ -6751,9 +6837,9 @@ test "board heap: transition grids fit the budget and the surface borrows its sn defer p.deinit(); var frame: std.heap.ArenaAllocator = .init(std.testing.allocator); defer frame.deinit(); + p.settings.panel_transition = .vertical; const boot = try p.render(frame.allocator()); p.acknowledgePanelPresentation(boot.panelTracks()); - p.settings.panel_transition = .vertical; _ = try p.newShell(1, ""); try std.testing.expect(layout.splitColumn(p, 0, 1, false)); p.sync(); @@ -6864,3 +6950,40 @@ test "jump history terminal rectangle follows output and clears on reflow" { try std.testing.expect(pane.pointerSelection(pane.sel[0]) == null); try std.testing.expectEqual(.none, pane.sel[0].state); } + +test "core animation keeps wall time at 60, 120 and 144 Hz and across a stall" { + const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 80, .rows = 24 }); + defer p.deinit(); + const frame = animation.frame_ns; + // Something that animates for as long as it is on. + p.settings.scene_effects.crt = true; + for ([_]u64{ 60, 120, 144 }) |hz| { + const start: u64 = 5 * std.time.ns_per_s; + p.clock_started = false; + p.advance(start); + var steps: u64 = 0; + var at: u64 = 1; + while (at <= hz) : (at += 1) { + const before = p.stepped_ns; + p.advance(start + at * std.time.ns_per_s / hz); + const taken = (p.stepped_ns - before + frame / 2) / frame; + // Never two steps in one display frame: that is a visible hitch. + try std.testing.expect(taken <= 1); + steps += taken; + } + switch (hz) { + // One step a display frame, every display frame. + 60 => try std.testing.expectEqual(@as(u64, 60), steps), + 120 => try std.testing.expectEqual(@as(u64, 60), steps), + // The frame's own rate: 62 a second, give or take one. + else => try std.testing.expect(steps >= 61 and steps <= 63), + } + } + // A stall of minutes is not minutes of frames. + const before = p.stepped_ns; + p.advance(before + 600 * std.time.ns_per_s); + try std.testing.expectEqual(before + 600 * std.time.ns_per_s, p.stepped_ns); + p.settings.scene_effects.crt = false; + p.advance(p.stepped_ns + frame); + try std.testing.expectEqual(@as(?u64, null), p.nextWake()); +} diff --git a/src/tty/tty.zig b/src/tty/tty.zig index 66e551b1..6083f609 100644 --- a/src/tty/tty.zig +++ b/src/tty/tty.zig @@ -76,7 +76,8 @@ pub const Command = struct { pub var value: union(enum) { nop, quit, - tick, + /// A timed wait ran out: the core's next wake has come. + wake, key_press: vaxis.Key, pty_read: struct { id: usize, gen: u32, bytes: []u8 }, pty_eof: struct { id: usize, gen: u32 }, @@ -728,6 +729,7 @@ fn localSession( .paste_buf = paste_buf, .inotify_fd = file_watch.init(false), .fs = fs, + .test_clock = host_io.testClock(), }; pardes.lsp.setStatusSink(&sh, lspStatusSink); defer { @@ -775,7 +777,7 @@ fn localSession( try startInput(loop, input_cache); defer if (attached.* == null) stopInput(loop); (try std.Thread.spawn(.{}, winchWatch, .{ loop, vx, tty })).detach(); - (try std.Thread.spawn(.{}, tickWatch, .{ io, loop })).detach(); + (try std.Thread.spawn(.{}, wakeWatch, .{ io, loop })).detach(); if (fs) |f| try f.watch(loop, wakeFs); try vx.queryTerminalSend(tty.writer()); @@ -900,6 +902,10 @@ const Shell = struct { check_files: bool = false, in_paste: bool = false, tracks: []const pardes.animation.Track = &.{}, + /// PARDES_TEST_CLOCK's virtual time (host_io.testClock), and where the + /// running-out wait moves it: the core's next wake. + test_clock: ?u64 = null, + wake_to: u64 = 0, fn of(ctx: ?*anyopaque) *Shell { return @ptrCast(@alignCast(ctx.?)); @@ -911,12 +917,14 @@ const Shell = struct { const isolated_vtable: host_io.Host.VTable = .{ .wait_input = waitInput, + .now = clockNow, .present = present, .post_present = postPresent, }; const vtable: host_io.Host.VTable = .{ .wait_input = waitInput, + .now = clockNow, .present = present, .post_present = postPresent, .poll_frame = pollFrame, @@ -939,12 +947,20 @@ const Shell = struct { .pipe = pipe, }; + fn clockNow(ctx: ?*anyopaque) u64 { + const s = of(ctx); + return s.test_clock orelse host_io.monotonicNs(); + } + fn waitInput(ctx: ?*anyopaque, timeout_ms: u32) void { const s = of(ctx); var batch: usize = 0; - // The wait is the 9P connections' turn with the core. Animating, the - // frame's tick arrives through the same queue (`tickWatch`). - if (timeout_ms != 0) tick_request.set(s.io); + // The wait is the 9P connections' turn with the core. A timeout (the + // core's next wake) arrives through the same queue (`wakeWatch`). + if (timeout_ms != 0) { + s.wake_to = s.core.nextWake() orelse 0; + requestWake(s.io, timeout_ms); + } pardes.turn.rest(); const first = s.loop.nextEvent() catch { pardes.turn.wake(); @@ -984,7 +1000,9 @@ const Shell = struct { defer tz_event.end(); switch (event) { .nop => {}, - .tick => core.update(.tick), + .wake => if (s.test_clock) |*virtual| { + virtual.* = @max(virtual.*, s.wake_to); + }, .quit => { core.quit = true; return true; @@ -1523,21 +1541,77 @@ fn winchWatch(loop: *Loop, vx: *vaxis.Vaxis, tty: *vaxis.Tty) void { } } -/// Set by an animating frame's wait: post one `.tick` a frame from now. The -/// tick joins the input queue, so a key or a click that lands inside the -/// frame is handled at once instead of after a blind sleep. -var tick_request: std.Io.Event = .unset; +/// A wait with a timeout: post one `.wake` when it runs out. The wake joins +/// the input queue, so a key or a click that lands first is handled at once +/// instead of after a blind sleep; vaxis's queue has no timed wait. Each +/// request bumps `wake_gen`, which cuts short a sleep still timing an +/// earlier, longer request (an 800 ms linger interrupted by a key that +/// starts a 16 ms fall) and times the new one instead. +var wake_gen: std.atomic.Value(u32) = .init(0); +var wake_ms: std.atomic.Value(u32) = .init(0); + +fn requestWake(io: std.Io, ms: u32) void { + wake_ms.store(ms, .release); + _ = wake_gen.fetchAdd(1, .acq_rel); + io.futexWake(u32, &wake_gen.raw, 1); +} + +fn wakeWatch(io: std.Io, loop: *Loop) void { + var seen = wake_gen.load(.acquire); + while (true) { + // Asleep until a request. + while (wake_gen.load(.acquire) == seen) io.futexWaitUncancelable(u32, &wake_gen.raw, seen); + seen = wake_gen.load(.acquire); + if (timeWake(io, &seen)) loop.postEvent(.wake) catch {}; + } +} -fn tickWatch(io: std.Io, loop: *Loop) void { +/// Sleep out the latest request; true when it ran its course, false when +/// none is pending. A newer request met on the way restarts the timing. +fn timeWake(io: std.Io, seen: *u32) bool { while (true) { - tick_request.waitUncancelable(io); - tick_request.reset(); - var ts: libc.timespec = .{ .sec = 0, .nsec = @as(isize, pardes.animation.Animation.frame_ms) * std.time.ns_per_ms }; - _ = libc.nanosleep(&ts, null); - loop.postEvent(.tick) catch {}; + const ms = wake_ms.load(.acquire); + const deadline = host_io.monotonicNs() + @as(u64, ms) * std.time.ns_per_ms; + while (true) { + const now = host_io.monotonicNs(); + if (now >= deadline) return true; + io.futexWaitTimeout(u32, &wake_gen.raw, seen.*, .{ .duration = .{ + .raw = .fromNanoseconds(@intCast(deadline - now)), + .clock = .awake, + } }) catch {}; + const gen = wake_gen.load(.acquire); + if (gen != seen.*) { + seen.* = gen; + break; + } + } } } +test "a short wake request cuts short a long one still sleeping" { + const io = std.testing.io; + var seen = wake_gen.load(.acquire); + requestWake(io, 800); + seen = wake_gen.load(.acquire); + const Timer = struct { + fn run(timer_io: std.Io, start_seen: u32, done: *std.atomic.Value(u64)) void { + var local = start_seen; + _ = timeWake(timer_io, &local); + done.store(host_io.monotonicNs(), .release); + } + }; + var done: std.atomic.Value(u64) = .init(0); + const start = host_io.monotonicNs(); + const thread = try std.Thread.spawn(.{}, Timer.run, .{ io, seen, &done }); + var pause: std.c.timespec = .{ .sec = 0, .nsec = 50 * std.time.ns_per_ms }; + _ = std.c.nanosleep(&pause, null); + requestWake(io, 16); + thread.join(); + // The 16 ms request lands about 66 ms in: well before the 800 ms one + // would have, however loaded the machine. + try std.testing.expect(done.load(.acquire) - start < 700 * std.time.ns_per_ms); +} + fn wakeFs(ctx: ?*anyopaque) void { const loop: *Loop = @ptrCast(@alignCast(ctx.?)); _ = loop.tryPostEvent(.fs_ready) catch {}; @@ -1822,7 +1896,7 @@ const Attach = struct { fn apply(a: *Attach, event: @TypeOf(Command.value)) ?AttachEnd { switch (event) { - .nop, .tick, .fs_ready, .lsp_done, .lsp_status, .pipe_done, .pty_read, .pty_eof, .files_changed => {}, + .nop, .wake, .fs_ready, .lsp_done, .lsp_status, .pipe_done, .pty_read, .pty_eof, .files_changed => {}, .quit => return .none, .focus_in => {}, .focus_out => return a.send(.pointer_leave), diff --git a/src/web.zig b/src/web.zig index b77d07a6..532e3794 100644 --- a/src/web.zig +++ b/src/web.zig @@ -1,7 +1,7 @@ //! Freestanding WebAssembly boundary for the DOM backend. //! //! JavaScript owns the clock and nothing else: it calls `pardes_tick` (one -//! `Pardes.pump`) and reads the packed cell buffer `present` left behind. The +//! `Pardes.pump`, at requestAnimationFrame's timestamp) and reads the packed cell buffer `present` left behind. The //! host vtable below is only what a page genuinely has — pixels, the //! clipboard, links, downloads. Processes, a real filesystem, a language //! backend and subprocess pipes are left null, so the core answers them itself @@ -106,6 +106,9 @@ const State = struct { frame_len: usize = 0, frame_cols: u16 = 0, frame_rows: u16 = 0, + /// requestAnimationFrame's timestamp as the last tick gave it, in ns: + /// the core's clock (`Host.now`). + now_ns: u64 = 0, fn init(cols: u16, rows: u16) !State { const allocs = pardes.memory.init(gpa); @@ -276,30 +279,19 @@ export fn pardes_pointer_leave() void { s.core.update(.pointer_leave); } -/// One iteration of the core's own loop: queued input, effects, render, -/// present. JS calls it once per animation frame, after spending that frame's -/// animation ticks. -export fn pardes_tick() void { +/// One iteration of the core's own loop: queued input, effects, the frames +/// of animation `timestamp_ms` (requestAnimationFrame's clock) has brought, +/// render, present. JS calls it once per display frame; a call with no +/// timestamp (NaN) leaves the clock where it was. +export fn pardes_tick(timestamp_ms: f64) void { const s = &(state orelse return); + if (std.math.isFinite(timestamp_ms) and timestamp_ms >= 0) + s.now_ns = @intFromFloat(timestamp_ms * std.time.ns_per_ms); s.core.pump(host(s)) catch |err| { last_error = @intFromError(err); }; } -/// Spend one fixed 60 Hz animation step, the only writer of animated time in -/// this host. Separate from the pump for the reason the AppKit shell keeps them -/// separate: if every input pump also advanced the transition, a burst of keys -/// would collapse a ten-frame fade into one display frame. -export fn pardes_animation_tick() void { - const s = &(state orelse return); - s.core.update(.tick); -} - -export fn pardes_animating() u32 { - const s = &(state orelse return 0); - return @intFromBool(s.core.animationActive()); -} - /// The Exit builtin, or the last pane closing. JS stops its frame loop. export fn pardes_should_quit() u32 { const s = &(state orelse return 0); @@ -462,7 +454,13 @@ extern "pardes" fn host_download( bytes_len: usize, ) callconv(.c) void; +fn now(ctx: ?*anyopaque) u64 { + const s: *State = @ptrCast(@alignCast(ctx.?)); + return s.now_ns; +} + const vtable: pardes.Host.VTable = .{ + .now = now, .present = present, .write_file = writeFile, .write_dump = writeDump, diff --git a/src/web/app.mjs b/src/web/app.mjs index 11d8f228..280239d5 100644 --- a/src/web/app.mjs +++ b/src/web/app.mjs @@ -1,7 +1,5 @@ const CELL_SIZE = 20; const ATTR_TAGLINE = 1 << 7; -const ANIMATION_FRAME_MS = 1000 / 60; -const MAX_ANIMATION_TICKS = 4; const DEFAULT_FG = "#cccccc"; const DEFAULT_BG = "#121212"; const decoder = new TextDecoder(); @@ -325,7 +323,6 @@ export class PardesRuntime { this.running = false; this.pointer = null; this.frameHandle = 0; - this.animationClock = { last: null, lag: 0 }; this.bindEvents(); } @@ -338,7 +335,6 @@ export class PardesRuntime { this.wasm.pardes_tick(); this.renderer.render(); this.running = true; - this.animationClock = { last: null, lag: 0 }; this.frameHandle = requestAnimationFrame((timestamp) => this.frame(timestamp)); this.root.focus({ preventScroll: true }); } @@ -355,13 +351,9 @@ export class PardesRuntime { this.resize(); this.root.style.setProperty("--pardes-tagline-font-size", `${this.measuredTaglinePercent}%`); } - // JS owns the animation clock; the pump that follows applies those ticks, - // runs the core's effects and presents one frame however fast the display - // is. Both halves are needed: an idle core still has input and effects. - for (let ticks = animationTicks(this.animationClock, timestamp); ticks > 0; ticks -= 1) { - this.wasm.pardes_animation_tick(); - } - this.wasm.pardes_tick(); + // The core's clock is this timestamp: it steps its own animations + // by it, however fast the display refreshes. + this.wasm.pardes_tick(timestamp); if (this.wasm.pardes_should_quit()) this.running = false; this.renderer.render(); this.frameHandle = requestAnimationFrame((nextTimestamp) => this.frame(nextTimestamp)); @@ -559,28 +551,6 @@ export class PardesRuntime { } } -/// Spend monotonic requestAnimationFrame time as fixed 60 Hz core ticks. A -/// high-refresh display therefore renders repeated states rather than making -/// frame-count transitions run twice as fast. Long suspension is capped so a -/// returning tab cannot execute an unbounded loop before drawing. -export function animationTicks(clock, timestamp) { - if (!Number.isFinite(timestamp)) return 0; - if (clock.last === null || timestamp < clock.last) { - clock.last = timestamp; - clock.lag = 0; - return 0; - } - const elapsed = Math.min(timestamp - clock.last, ANIMATION_FRAME_MS * MAX_ANIMATION_TICKS); - clock.last = timestamp; - clock.lag += elapsed; - const ticks = Math.min(MAX_ANIMATION_TICKS, Math.floor((clock.lag + 1e-7) / ANIMATION_FRAME_MS)); - clock.lag -= ticks * ANIMATION_FRAME_MS; - return ticks; -} - -/// The four things the core asks the page for, as the module's imports. The -/// holder exists because the import object has to be built before the instance -/// whose memory those imports read. export function browserHost() { const host = { wasm: null }; const view = (ptr, len) => new Uint8Array(host.wasm.memory.buffer, ptr, len); diff --git a/test/gui-goldens.txt b/test/gui-goldens.txt index 5531b578..73aa1f86 100644 --- a/test/gui-goldens.txt +++ b/test/gui-goldens.txt @@ -3,8 +3,8 @@ 03-notice 4d59205fe6b89a4589e94c68521257f21b40917c0198ea20248925687663d9f5 04-context-rows-mid-thumb 7129ee318975f858c430b1e610b26ca756d5bb37553338c0dc6caab2290de2a4 05-body-selection 39103f3747aae07a12b5151e7e377430b88b96e504670ac2f2d0272197eb827b -06-tag-focus-selection 2bedec24842109aa2cc302226d53a994ff547791ad54d5781fe48d8eaac179ac -07-prompt-notice 6d6eda3f3a74d3ff048cb0e433e3794ca061e356184ff62a4878395c58482727 +06-tag-focus-selection 6a7f50e292f4ede92df24a817218818b93a01fd15fcf39467cf06c3772077834 +07-prompt-notice d5cdacd74ae6d29834f0b09a607bfce5a2ca8a549c259be50b76a57a2d2d3271 08-wide-glyph-edges 123a182b82a2a8c455291a5c89ccfa28e1f8ce9566172ca404c0b9c71dd33b48 09-collapsed-focus-tint ae66076fdfb0cab9a906b052df257deee5ba91a6274712d52a76d8a7adc5b415 10-tagbottom dd8ba0d3ecabf3420d000b0c9591a57278179cbd2a9060f849d283f3881d1847 @@ -12,5 +12,5 @@ 12-multiline-tag 1b9ccd331814dc76111470f18448b1ca192e1edc3d79ea6eee19a6a78a4b1831 13-image de18edee2ab2e0f2d4bf4162d86e3d8a1852fccfc344830491fa1a359095d4ea 14-theme-ink 6e733d4212373c90b860b2e41102ced8719b07480591b5da3905267c8358db18 -15-theme-acme-light 39f9256b7c8ed5187cd8d2cc3840db274efcecad263e519c4f9c79eb9efea19c +15-theme-acme-light e099dc1a351de8efa63ecd0ec0899636ea31b722a945eb40137a18abd87a82e2 16-debug e97ce74b7a3d4a08f6a529b1f0de111d62e5532c829a6b1633b966dd45218f55 diff --git a/test/gui_golden.py b/test/gui_golden.py index 6586af3a..1252014c 100644 --- a/test/gui_golden.py +++ b/test/gui_golden.py @@ -89,7 +89,9 @@ def run(args): name = 'gui-golden' config = root / 'config/pardes' config.mkdir(parents=True) - (config / 'init').write_text('Shell /bin/sh\nTheme forge\n') + # No linger: a dismissed message is gone, not caught part way, when a + # scene settles. + (config / 'init').write_text('Shell /bin/sh\nTheme forge\nMessageLinger 0\n') source = root / 'shapes.zig' source.write_bytes(ZIG) notes = root / 'notes.txt' diff --git a/test/pdf.zig b/test/pdf.zig index ed5d6908..93418727 100644 --- a/test/pdf.zig +++ b/test/pdf.zig @@ -1400,7 +1400,7 @@ test "PDF tint and tinted theme changes rebuild every visible raster only" { // Chrome animation reads a separate palette. Its ticks must never disturb // the target-theme tint key or ask MuPDF for the same pixels again. try std.testing.expect(p.animationActive()); - for (0..animation.Animation.transition_steps) |_| { + for (0..animation.transition_steps) |_| { p.update(.tick); _ = frame.reset(.retain_capacity); const tick_surface = try p.render(frame.allocator()); diff --git a/test/snapshot.zig b/test/snapshot.zig index bdabb56e..53553657 100644 --- a/test/snapshot.zig +++ b/test/snapshot.zig @@ -579,6 +579,9 @@ fn runScript(arena: std.mem.Allocator, exe_z: [:0]const u8, script_path: []const // views' durations (lsp_zls.zig hideTime) and the transient message row's // time of day (message.zig stamp) _ = setenv("PARDES_NOTIME", "1", 1); + // A virtual core clock: animation moves a frame per timed-out wait, + // whatever the machine's load (host_io.testClock). + _ = setenv("PARDES_TEST_CLOCK", "1", 1); // The protocol client must be HERMETIC under the harness: `.rs` files // speak to the deterministic mock when the build handed one over, and // every other spec is disabled outright — a script that opened a stray diff --git a/test/snapshots/theme.golden b/test/snapshots/theme.golden index 51bb77ff..02750663 100644 --- a/test/snapshots/theme.golden +++ b/test/snapshots/theme.golden @@ -53,178 +53,174 @@ |30: 0-0 d,#608269, 1-1 d,#0d1410, 2-49 #e5eee5,#0d1410, 50-50 d,#608269, 51-51 d,#0d1410, 52-99 #e5eee5,#0d1410, == snap dusk grid=100x31 cursor=4,5 == style dusk grid=100x31 -|0: 0-50 #c4b7c4,#2b262f, 51-59 #fff0eb,#654053, 60-70 #c4b7c4,#2b262f, 71-99 d,#2b262f, -|1: 0-1 #ffffff,#77795e, 2-2 d,#39303a, 3-34 #d0c3d0,#39303a, 35-49 d,#39303a, 50-51 #ffffff,#77795e, 52-52 d,#2b262f, 53-84 #c4b7c4,#2b262f, 85-99 d,#2b262f, -|2: 0-1 #000000,#e7b491, 2-2 d,#39303a, 3-29 #d0c3d0,#39303a, 30-32 #a7d3c7,#39303a, 33-49 #d0c3d0,#39303a, 50-51 #ffffff,#705667, 52-52 d,#2b262f, 53-79 #c4b7c4,#2b262f, 80-82 #9cc7bb,#2b262f, 83-99 #c4b7c4,#2b262f, -|3: 0-0 d,#89697a, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, -|4: 0-0 d,#89697a, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, -|5: 0-0 d,#89697a, 1-49 d,#39323b, 50-50 d,#89697a, 51-99 d,#39323b, -|6: 0-0 d,#89697a, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, -|7: 0-0 d,#89697a, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, -|8: 0-0 d,#89697a, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, -|9: 0-0 d,#89697a, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, -|10: 0-0 d,#89697a, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, -|11: 0-0 d,#89697a, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, -|12: 0-0 d,#89697a, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, -|13: 0-0 d,#89697a, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, -|14: 0-0 d,#89697a, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, -|15: 0-0 d,#89697a, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, -|16: 0-0 d,#89697a, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, -|17: 0-1 #ffffff,#705667, 2-2 d,#2b262f, 3-29 #c4b7c4,#2b262f, 30-32 #9cc7bb,#2b262f, 33-49 #c4b7c4,#2b262f, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, -|18: 0-0 d,#89697a, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, -|19: 0-0 d,#89697a, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, -|20: 0-0 d,#89697a, 1-49 d,#39323b, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, -|21: 0-0 d,#89697a, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, -|22: 0-0 d,#89697a, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, -|23: 0-0 d,#89697a, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, -|24: 0-0 d,#89697a, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, -|25: 0-0 d,#89697a, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, -|26: 0-0 d,#89697a, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, -|27: 0-0 d,#89697a, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, -|28: 0-0 d,#89697a, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, -|29: 0-0 d,#89697a, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, -|30: 0-0 d,#89697a, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#89697a, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|0: 0-50 #c6b6c5,#2c2630, 51-59 #fff0eb,#654053, 60-70 #c6b6c5,#2c2630, 71-99 d,#2c2630, +|1: 0-1 #ffffff,#757a5f, 2-2 d,#3b2f3b, 3-34 #d2c2d1,#3b2f3b, 35-49 d,#3b2f3b, 50-51 #ffffff,#757a5f, 52-52 d,#2c2630, 53-84 #c6b6c5,#2c2630, 85-99 d,#2c2630, +|2: 0-1 #000000,#edb092, 2-2 d,#3b2f3b, 3-29 #d2c2d1,#3b2f3b, 30-32 #a1d5c4,#3b2f3b, 33-49 #d2c2d1,#3b2f3b, 50-51 #ffffff,#745469, 52-52 d,#2c2630, 53-79 #c6b6c5,#2c2630, 80-82 #96c9b8,#2c2630, 83-99 #c6b6c5,#2c2630, +|3: 0-0 d,#8e667c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|4: 0-0 d,#8e667c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|5: 0-0 d,#8e667c, 1-49 d,#39323b, 50-50 d,#8e667c, 51-99 d,#39323b, +|6: 0-0 d,#8e667c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|7: 0-0 d,#8e667c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|8: 0-0 d,#8e667c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|9: 0-0 d,#8e667c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|10: 0-0 d,#8e667c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|11: 0-0 d,#8e667c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|12: 0-0 d,#8e667c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|13: 0-0 d,#8e667c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|14: 0-0 d,#8e667c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|15: 0-0 d,#8e667c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|16: 0-0 d,#8e667c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|17: 0-1 #ffffff,#745469, 2-2 d,#2c2630, 3-29 #c6b6c5,#2c2630, 30-32 #96c9b8,#2c2630, 33-49 #c6b6c5,#2c2630, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|18: 0-0 d,#8e667c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|19: 0-0 d,#8e667c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|20: 0-0 d,#8e667c, 1-49 d,#39323b, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|21: 0-0 d,#8e667c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|22: 0-0 d,#8e667c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|23: 0-0 d,#8e667c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|24: 0-0 d,#8e667c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|25: 0-0 d,#8e667c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|26: 0-0 d,#8e667c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|27: 0-0 d,#8e667c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|28: 0-0 d,#8e667c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|29: 0-0 d,#8e667c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, +|30: 0-0 d,#8e667c, 1-1 d,#39323b, 2-49 #c3b6c1,#39323b, 50-50 d,#8e667c, 51-51 d,#39323b, 52-99 #c3b6c1,#39323b, == snap ink grid=100x31 cursor=4,5 == style ink grid=100x31 -|0: 0-50 #d4dfed,#17222c, 51-59 #ffffff,#1b547c, 60-70 #d4dfed,#17222c, 71-99 d,#17222c, -|1: 0-1 #ffffff,#8c7d5b, 2-2 d,#253341, 3-34 #e0eaf5,#253341, 35-49 d,#253341, 50-51 #ffffff,#8c7d5b, 52-52 d,#17222c, 53-84 #d4dfed,#17222c, 85-99 d,#17222c, -|2: 0-1 #000000,#90d4f4, 2-2 d,#253341, 3-29 #e0eaf5,#253341, 30-32 #f6e8b9,#253341, 33-49 #e0eaf5,#253341, 50-51 #ffffff,#61758c, 52-52 d,#17222c, 53-79 #d4dfed,#17222c, 80-82 #ecdead,#17222c, 83-99 #d4dfed,#17222c, -|3: 0-0 d,#87a1bb, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, -|4: 0-0 d,#87a1bb, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, -|5: 0-0 d,#87a1bb, 1-49 d,#000000, 50-50 d,#87a1bb, 51-99 d,#000000, -|6: 0-0 d,#87a1bb, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, -|7: 0-0 d,#87a1bb, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, -|8: 0-0 d,#87a1bb, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, -|9: 0-0 d,#87a1bb, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, -|10: 0-0 d,#87a1bb, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, -|11: 0-0 d,#87a1bb, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, -|12: 0-0 d,#87a1bb, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, -|13: 0-0 d,#87a1bb, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, -|14: 0-0 d,#87a1bb, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, -|15: 0-0 d,#87a1bb, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, -|16: 0-0 d,#87a1bb, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, -|17: 0-1 #ffffff,#61758c, 2-2 d,#17222c, 3-29 #d4dfed,#17222c, 30-32 #ecdead,#17222c, 33-49 #d4dfed,#17222c, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, -|18: 0-0 d,#87a1bb, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, -|19: 0-0 d,#87a1bb, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, -|20: 0-0 d,#87a1bb, 1-49 d,#000000, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, -|21: 0-0 d,#87a1bb, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, -|22: 0-0 d,#87a1bb, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, -|23: 0-0 d,#87a1bb, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, -|24: 0-0 d,#87a1bb, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, -|25: 0-0 d,#87a1bb, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, -|26: 0-0 d,#87a1bb, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, -|27: 0-0 d,#87a1bb, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, -|28: 0-0 d,#87a1bb, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, -|29: 0-0 d,#87a1bb, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, -|30: 0-0 d,#87a1bb, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#87a1bb, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|0: 0-50 #d5e4f1,#15212c, 51-59 #ffffff,#1b547c, 60-70 #d5e4f1,#15212c, 71-99 d,#15212c, +|1: 0-1 #ffffff,#8f7d5b, 2-2 d,#223342, 3-34 #e1eef9,#223342, 35-49 d,#223342, 50-51 #ffffff,#8f7d5b, 52-52 d,#15212c, 53-84 #d5e4f1,#15212c, 85-99 d,#15212c, +|2: 0-1 #000000,#86d8ff, 2-2 d,#223342, 3-29 #e1eef9,#223342, 30-32 #ffeab8,#223342, 33-49 #e1eef9,#223342, 50-51 #ffffff,#5f7990, 52-52 d,#15212c, 53-79 #d5e4f1,#15212c, 80-82 #f5e0ac,#15212c, 83-99 #d5e4f1,#15212c, +|3: 0-0 d,#86a8c2, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|4: 0-0 d,#86a8c2, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|5: 0-0 d,#86a8c2, 1-49 d,#000000, 50-50 d,#86a8c2, 51-99 d,#000000, +|6: 0-0 d,#86a8c2, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|7: 0-0 d,#86a8c2, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|8: 0-0 d,#86a8c2, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|9: 0-0 d,#86a8c2, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|10: 0-0 d,#86a8c2, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|11: 0-0 d,#86a8c2, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|12: 0-0 d,#86a8c2, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|13: 0-0 d,#86a8c2, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|14: 0-0 d,#86a8c2, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|15: 0-0 d,#86a8c2, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|16: 0-0 d,#86a8c2, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|17: 0-1 #ffffff,#5f7990, 2-2 d,#15212c, 3-29 #d5e4f1,#15212c, 30-32 #f5e0ac,#15212c, 33-49 #d5e4f1,#15212c, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|18: 0-0 d,#86a8c2, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|19: 0-0 d,#86a8c2, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|20: 0-0 d,#86a8c2, 1-49 d,#000000, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|21: 0-0 d,#86a8c2, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|22: 0-0 d,#86a8c2, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|23: 0-0 d,#86a8c2, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|24: 0-0 d,#86a8c2, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|25: 0-0 d,#86a8c2, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|26: 0-0 d,#86a8c2, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|27: 0-0 d,#86a8c2, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|28: 0-0 d,#86a8c2, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|29: 0-0 d,#86a8c2, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, +|30: 0-0 d,#86a8c2, 1-1 d,#000000, 2-49 #f3f7fc,#000000, 50-50 d,#86a8c2, 51-51 d,#000000, 52-99 #f3f7fc,#000000, == snap paper grid=100x31 cursor=4,5 == style paper grid=100x31 -|0: 0-50 #5f6f69,#d3d6d1, 51-59 #203e31,#c5e2d0, 60-70 #5f6f69,#d3d6d1, 71-99 d,#d3d6d1, -|1: 0-1 #000000,#b89e7b, 2-2 d,#c9d3cd, 3-34 #596963,#c9d3cd, 35-49 d,#c9d3cd, 50-51 #000000,#b89e7b, 52-52 d,#d3d6d1, 53-84 #5f6f69,#d3d6d1, 85-99 d,#d3d6d1, -|2: 0-1 #ffffff,#3e7b68, 2-2 d,#c9d3cd, 3-29 #596963,#c9d3cd, 30-32 #785580,#c9d3cd, 33-49 #596963,#c9d3cd, 50-51 #000000,#8aa194, 52-52 d,#d3d6d1, 53-79 #5f6f69,#d3d6d1, 80-82 #7f5b87,#d3d6d1, 83-99 #5f6f69,#d3d6d1, -|3: 0-0 d,#869e90, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, -|4: 0-0 d,#869e90, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, -|5: 0-0 d,#869e90, 1-49 d,#f5f3ed, 50-50 d,#869e90, 51-99 d,#f5f3ed, -|6: 0-0 d,#869e90, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, -|7: 0-0 d,#869e90, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, -|8: 0-0 d,#869e90, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, -|9: 0-0 d,#869e90, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, -|10: 0-0 d,#869e90, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, -|11: 0-0 d,#869e90, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, -|12: 0-0 d,#869e90, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, -|13: 0-0 d,#869e90, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, -|14: 0-0 d,#869e90, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, -|15: 0-0 d,#869e90, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, -|16: 0-0 d,#869e90, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, -|17: 0-1 #000000,#8aa194, 2-2 d,#d3d6d1, 3-29 #5f6f69,#d3d6d1, 30-32 #7f5b87,#d3d6d1, 33-49 #5f6f69,#d3d6d1, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, -|18: 0-0 d,#869e90, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, -|19: 0-0 d,#869e90, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, -|20: 0-0 d,#869e90, 1-49 d,#f5f3ed, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, -|21: 0-0 d,#869e90, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, -|22: 0-0 d,#869e90, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, -|23: 0-0 d,#869e90, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, -|24: 0-0 d,#869e90, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, -|25: 0-0 d,#869e90, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, -|26: 0-0 d,#869e90, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, -|27: 0-0 d,#869e90, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, -|28: 0-0 d,#869e90, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, -|29: 0-0 d,#869e90, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, -|30: 0-0 d,#869e90, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869e90, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|0: 0-50 #52625a,#e8eae3, 51-59 #203e31,#c5e2d0, 60-70 #52625a,#e8eae3, 71-99 d,#e8eae3, +|1: 0-1 #000000,#bda27e, 2-2 d,#dce5dc, 3-34 #4a5a52,#dce5dc, 35-49 d,#dce5dc, 50-51 #000000,#bda27e, 52-52 d,#e8eae3, 53-84 #52625a,#e8eae3, 85-99 d,#e8eae3, +|2: 0-1 #ffffff,#367157, 2-2 d,#dce5dc, 3-29 #4a5a52,#dce5dc, 30-32 #69447a,#dce5dc, 33-49 #4a5a52,#dce5dc, 50-51 #000000,#8fa594, 52-52 d,#e8eae3, 53-79 #52625a,#e8eae3, 80-82 #724c83,#e8eae3, 83-99 #52625a,#e8eae3, +|3: 0-0 d,#869d8a, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|4: 0-0 d,#869d8a, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|5: 0-0 d,#869d8a, 1-49 d,#f5f3ed, 50-50 d,#869d8a, 51-99 d,#f5f3ed, +|6: 0-0 d,#869d8a, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|7: 0-0 d,#869d8a, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|8: 0-0 d,#869d8a, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|9: 0-0 d,#869d8a, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|10: 0-0 d,#869d8a, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|11: 0-0 d,#869d8a, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|12: 0-0 d,#869d8a, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|13: 0-0 d,#869d8a, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|14: 0-0 d,#869d8a, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|15: 0-0 d,#869d8a, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|16: 0-0 d,#869d8a, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|17: 0-1 #000000,#8fa594, 2-2 d,#e8eae3, 3-29 #52625a,#e8eae3, 30-32 #724c83,#e8eae3, 33-49 #52625a,#e8eae3, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|18: 0-0 d,#869d8a, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|19: 0-0 d,#869d8a, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|20: 0-0 d,#869d8a, 1-49 d,#f5f3ed, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|21: 0-0 d,#869d8a, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|22: 0-0 d,#869d8a, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|23: 0-0 d,#869d8a, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|24: 0-0 d,#869d8a, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|25: 0-0 d,#869d8a, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|26: 0-0 d,#869d8a, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|27: 0-0 d,#869d8a, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|28: 0-0 d,#869d8a, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|29: 0-0 d,#869d8a, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, +|30: 0-0 d,#869d8a, 1-1 d,#f5f3ed, 2-49 #303b3b,#f5f3ed, 50-50 d,#869d8a, 51-51 d,#f5f3ed, 52-99 #303b3b,#f5f3ed, == snap daybreak grid=100x31 cursor=4,5 == style daybreak grid=100x31 -|0: 0-50 #2d495e,#edf1f5, 51-59 #10364f,#b9dffb, 60-70 #2d495e,#edf1f5, 71-99 d,#edf1f5, -|1: 0-1 #000000,#b89b7a, 2-2 d,#dfeaf1, 3-34 #254156,#dfeaf1, 35-49 d,#dfeaf1, 50-51 #000000,#b89b7a, 52-52 d,#edf1f5, 53-84 #2d495e,#edf1f5, 85-99 d,#edf1f5, -|2: 0-1 #ffffff,#056392, 2-2 d,#dfeaf1, 3-29 #254156,#dfeaf1, 30-32 #542862,#dfeaf1, 33-49 #254156,#dfeaf1, 50-51 #000000,#7d9fb4, 52-52 d,#edf1f5, 53-79 #2d495e,#edf1f5, 80-82 #5c306a,#edf1f5, 83-99 #2d495e,#edf1f5, -|3: 0-0 d,#69879e, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, -|4: 0-0 d,#69879e, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, -|5: 0-0 d,#69879e, 1-49 d,#ffffff, 50-50 d,#69879e, 51-99 d,#ffffff, -|6: 0-0 d,#69879e, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, -|7: 0-0 d,#69879e, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, -|8: 0-0 d,#69879e, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, -|9: 0-0 d,#69879e, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, -|10: 0-0 d,#69879e, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, -|11: 0-0 d,#69879e, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, -|12: 0-0 d,#69879e, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, -|13: 0-0 d,#69879e, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, -|14: 0-0 d,#69879e, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, -|15: 0-0 d,#69879e, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, -|16: 0-0 d,#69879e, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, -|17: 0-1 #000000,#7d9fb4, 2-2 d,#edf1f5, 3-29 #2d495e,#edf1f5, 30-32 #5c306a,#edf1f5, 33-49 #2d495e,#edf1f5, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, -|18: 0-0 d,#69879e, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, -|19: 0-0 d,#69879e, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, -|20: 0-0 d,#69879e, 1-49 d,#ffffff, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, -|21: 0-0 d,#69879e, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, -|22: 0-0 d,#69879e, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, -|23: 0-0 d,#69879e, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, -|24: 0-0 d,#69879e, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, -|25: 0-0 d,#69879e, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, -|26: 0-0 d,#69879e, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, -|27: 0-0 d,#69879e, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, -|28: 0-0 d,#69879e, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, -|29: 0-0 d,#69879e, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, -|30: 0-0 d,#69879e, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#69879e, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|0: 0-50 #29465e,#edf2f7, 51-59 #10364f,#b9dffb, 60-70 #29465e,#edf2f7, 71-99 d,#edf2f7, +|1: 0-1 #000000,#b79a7a, 2-2 d,#dfeaf3, 3-34 #213e56,#dfeaf3, 35-49 d,#dfeaf3, 50-51 #000000,#b79a7a, 52-52 d,#edf2f7, 53-84 #29465e,#edf2f7, 85-99 d,#edf2f7, +|2: 0-1 #ffffff,#006198, 2-2 d,#dfeaf3, 3-29 #213e56,#dfeaf3, 30-32 #52255f,#dfeaf3, 33-49 #213e56,#dfeaf3, 50-51 #000000,#7b9eb7, 52-52 d,#edf2f7, 53-79 #29465e,#edf2f7, 80-82 #5a2d67,#edf2f7, 83-99 #29465e,#edf2f7, +|3: 0-0 d,#6685a0, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|4: 0-0 d,#6685a0, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|5: 0-0 d,#6685a0, 1-49 d,#ffffff, 50-50 d,#6685a0, 51-99 d,#ffffff, +|6: 0-0 d,#6685a0, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|7: 0-0 d,#6685a0, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|8: 0-0 d,#6685a0, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|9: 0-0 d,#6685a0, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|10: 0-0 d,#6685a0, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|11: 0-0 d,#6685a0, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|12: 0-0 d,#6685a0, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|13: 0-0 d,#6685a0, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|14: 0-0 d,#6685a0, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|15: 0-0 d,#6685a0, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|16: 0-0 d,#6685a0, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|17: 0-1 #000000,#7b9eb7, 2-2 d,#edf2f7, 3-29 #29465e,#edf2f7, 30-32 #5a2d67,#edf2f7, 33-49 #29465e,#edf2f7, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|18: 0-0 d,#6685a0, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|19: 0-0 d,#6685a0, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|20: 0-0 d,#6685a0, 1-49 d,#ffffff, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|21: 0-0 d,#6685a0, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|22: 0-0 d,#6685a0, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|23: 0-0 d,#6685a0, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|24: 0-0 d,#6685a0, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|25: 0-0 d,#6685a0, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|26: 0-0 d,#6685a0, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|27: 0-0 d,#6685a0, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|28: 0-0 d,#6685a0, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|29: 0-0 d,#6685a0, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, +|30: 0-0 d,#6685a0, 1-1 d,#ffffff, 2-49 #142d40,#ffffff, 50-50 d,#6685a0, 51-51 d,#ffffff, 52-99 #142d40,#ffffff, == snap atelier grid=100x31 cursor=4,5 == style atelier grid=100x31 -|0: 0-50 #3b5d56,#e5f0ee, 51-59 #35492d,#edf2a5, 60-70 #3b5d56,#e5f0ee, 71-99 d,#e5f0ee, -|1: 0-1 #000000,#bca380, 2-2 d,#d4e7e1, 3-34 #33554e,#d4e7e1, 35-49 d,#d4e7e1, 50-51 #000000,#bca380, 52-52 d,#e5f0ee, 53-84 #3b5d56,#e5f0ee, 85-99 d,#e5f0ee, -|2: 0-1 #ffffff,#317f70, 2-2 d,#d4e7e1, 3-29 #33554e,#d4e7e1, 30-32 #633c6a,#d4e7e1, 33-49 #33554e,#d4e7e1, 50-51 #000000,#92b7a4, 52-52 d,#e5f0ee, 53-79 #3b5d56,#e5f0ee, 80-82 #6c4473,#e5f0ee, 83-99 #3b5d56,#e5f0ee, -|3: 0-0 d,#99aa7a, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -|4: 0-0 d,#99aa7a, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -|5: 0-0 d,#99aa7a, 1-49 d,#fffdeb, 50-50 d,#99aa7a, 51-99 d,#fffdeb, -|6: 0-0 d,#99aa7a, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -|7: 0-0 d,#99aa7a, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -|8: 0-0 d,#99aa7a, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -|9: 0-0 d,#99aa7a, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -|10: 0-0 d,#99aa7a, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -|11: 0-0 d,#99aa7a, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -|12: 0-0 d,#99aa7a, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -|13: 0-0 d,#99aa7a, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -|14: 0-0 d,#99aa7a, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -|15: 0-0 d,#99aa7a, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -|16: 0-0 d,#99aa7a, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -|17: 0-1 #000000,#92b7a4, 2-2 d,#e5f0ee, 3-29 #3b5d56,#e5f0ee, 30-32 #6c4473,#e5f0ee, 33-49 #3b5d56,#e5f0ee, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -|18: 0-0 d,#99aa7a, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -|19: 0-0 d,#99aa7a, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -|20: 0-0 d,#99aa7a, 1-49 d,#fffdeb, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -|21: 0-0 d,#99aa7a, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -|22: 0-0 d,#99aa7a, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -|23: 0-0 d,#99aa7a, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -|24: 0-0 d,#99aa7a, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -|25: 0-0 d,#99aa7a, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -|26: 0-0 d,#99aa7a, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -|27: 0-0 d,#99aa7a, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -|28: 0-0 d,#99aa7a, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -|29: 0-0 d,#99aa7a, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -|30: 0-0 d,#99aa7a, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#99aa7a, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, -== snap colors-off grid=100x31 cursor=4,5 -|3: ls Colors ls -== style colors-off grid=100x31 |0: 0-50 #3d6055,#e4f0ed, 51-59 #35492d,#edf2a5, 60-70 #3d6055,#e4f0ed, 71-99 d,#e4f0ed, |1: 0-1 #000000,#bca481, 2-2 d,#d3e7df, 3-34 #35584d,#d3e7df, 35-49 d,#d3e7df, 50-51 #000000,#bca481, 52-52 d,#e4f0ed, 53-84 #3d6055,#e4f0ed, 85-99 d,#e4f0ed, |2: 0-1 #ffffff,#36826b, 2-2 d,#d3e7df, 3-29 #35584d,#d3e7df, 30-32 #653f6b,#d3e7df, 33-49 #35584d,#d3e7df, 50-51 #000000,#95baa2, 52-52 d,#e4f0ed, 53-79 #3d6055,#e4f0ed, 80-82 #6e4774,#e4f0ed, 83-99 #3d6055,#e4f0ed, +|3: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +|4: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +|5: 0-0 d,#9fae76, 1-49 d,#fffdeb, 50-50 d,#9fae76, 51-99 d,#fffdeb, +|6: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +|7: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +|8: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +|9: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +|10: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +|11: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +|12: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +|13: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +|14: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +|15: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +|16: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +|17: 0-1 #000000,#95baa2, 2-2 d,#e4f0ed, 3-29 #3d6055,#e4f0ed, 30-32 #6e4774,#e4f0ed, 33-49 #3d6055,#e4f0ed, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +|18: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +|19: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +|20: 0-0 d,#9fae76, 1-49 d,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +|21: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +|22: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +|23: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +|24: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +|25: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +|26: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +|27: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +|28: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +|29: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +|30: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-49 #293f35,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-99 #293f35,#fffdeb, +== snap colors-off grid=100x31 cursor=4,5 +|3: ls Colors ls +== style colors-off grid=100x31 |3: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-3 #293f35,#fffdeb, 4-41 d,#fffdeb, 42-42 d,#e4f0ed, 43-48 #3d6055,#e4f0ed, 49-49 d,#e4f0ed, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-53 #293f35,#fffdeb, 54-99 d,#fffdeb, |4: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-6 #293f35,#fffdeb, 7-49 d,#fffdeb, 50-50 d,#9fae76, 51-51 d,#fffdeb, 52-56 #293f35,#fffdeb, 57-99 d,#fffdeb, -|5: 0-0 d,#9fae76, 1-49 d,#fffdeb, 50-50 d,#9fae76, 51-99 d,#fffdeb, |6: 0-0 d,#9fae76, 1-49 d,#fffdeb, 50-50 d,#9fae76, 51-99 d,#fffdeb, |7: 0-0 d,#9fae76, 1-49 d,#fffdeb, 50-50 d,#9fae76, 51-99 d,#fffdeb, |8: 0-0 d,#9fae76, 1-49 d,#fffdeb, 50-50 d,#9fae76, 51-99 d,#fffdeb, @@ -253,240 +249,240 @@ == snap forge grid=100x31 cursor=4,5 |3: ls ls == style forge grid=100x31 -|0: 0-50 #b7bfc6,#35393e, 51-59 #e2eef4,#1c5172, 60-70 #b7bfc6,#35393e, 71-99 d,#35393e, -|1: 0-1 #ffffff,#727f6a, 2-2 d,#3e4650, 3-34 #c1c9d0,#3e4650, 35-49 d,#3e4650, 50-51 #ffffff,#727f6a, 52-52 d,#35393e, 53-84 #b7bfc6,#35393e, 85-99 d,#35393e, -|2: 0-1 #000000,#92bde9, 2-2 d,#3e4650, 3-29 #c1c9d0,#3e4650, 30-32 #e9bda1,#3e4650, 33-49 #c1c9d0,#3e4650, 50-51 #ffffff,#5b6d7f, 52-52 d,#35393e, 53-79 #b7bfc6,#35393e, 80-82 #dfb397,#35393e, 83-99 #b7bfc6,#35393e, -|3: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, -|4: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, -|5: 0-0 d,#758592, 1-49 d,#0c0c0e, 50-50 d,#758592, 51-99 d,#0c0c0e, -|6: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, -|7: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, -|8: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, -|9: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, -|10: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, -|11: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, -|12: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, -|13: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, -|14: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, -|15: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, -|16: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, -|17: 0-1 #ffffff,#5b6d7f, 2-2 d,#35393e, 3-29 #b7bfc6,#35393e, 30-32 #dfb397,#35393e, 33-49 #b7bfc6,#35393e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, -|18: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, -|19: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, -|20: 0-0 d,#758592, 1-49 d,#0c0c0e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, -|21: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, -|22: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, -|23: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, -|24: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, -|25: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, -|26: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, -|27: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, -|28: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, -|29: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, -|30: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#758592, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|0: 0-50 #c5c9d2,#22252b, 51-59 #e2eef4,#1c5172, 60-70 #c5c9d2,#22252b, 71-99 d,#22252b, +|1: 0-1 #ffffff,#6a7b67, 2-2 d,#2d3440, 3-34 #d1d5de,#2d3440, 35-49 d,#2d3440, 50-51 #ffffff,#6a7b67, 52-52 d,#22252b, 53-84 #c5c9d2,#22252b, 85-99 d,#22252b, +|2: 0-1 #000000,#9cc3f7, 2-2 d,#2d3440, 3-29 #d1d5de,#2d3440, 30-32 #f8cba7,#2d3440, 33-49 #d1d5de,#2d3440, 50-51 #ffffff,#55647b, 52-52 d,#22252b, 53-79 #c5c9d2,#22252b, 80-82 #ecbf9b,#22252b, 83-99 #c5c9d2,#22252b, +|3: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|4: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|5: 0-0 d,#708095, 1-49 d,#0c0c0e, 50-50 d,#708095, 51-99 d,#0c0c0e, +|6: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|7: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|8: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|9: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|10: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|11: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|12: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|13: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|14: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|15: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|16: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|17: 0-1 #ffffff,#55647b, 2-2 d,#22252b, 3-29 #c5c9d2,#22252b, 30-32 #ecbf9b,#22252b, 33-49 #c5c9d2,#22252b, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|18: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|19: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|20: 0-0 d,#708095, 1-49 d,#0c0c0e, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|21: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|22: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|23: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|24: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|25: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|26: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|27: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|28: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|29: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, +|30: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-49 #e5e5e5,#0c0c0e, 50-50 d,#708095, 51-51 d,#0c0c0e, 52-99 #e5e5e5,#0c0c0e, == snap lagoon grid=100x31 cursor=4,5 == style lagoon grid=100x31 -|0: 0-50 #bcd6cc,#28413d, 51-59 #e6f2f3,#325f6c, 60-70 #bcd6cc,#28413d, 71-99 d,#28413d, -|1: 0-1 #ffffff,#957763, 2-2 d,#33544c, 3-34 #c8e2d8,#33544c, 35-49 d,#33544c, 50-51 #ffffff,#957763, 52-52 d,#28413d, 53-84 #bcd6cc,#28413d, 85-99 d,#28413d, -|2: 0-1 #000000,#84cebd, 2-2 d,#33544c, 3-29 #c8e2d8,#33544c, 30-32 #f1cef0,#33544c, 33-49 #c8e2d8,#33544c, 50-51 #ffffff,#548073, 52-52 d,#28413d, 53-79 #bcd6cc,#28413d, 80-82 #e5c2e4,#28413d, 83-99 #bcd6cc,#28413d, -|3: 0-0 d,#6e988c, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, -|4: 0-0 d,#6e988c, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, -|5: 0-0 d,#6e988c, 1-49 d,#34464c, 50-50 d,#6e988c, 51-99 d,#34464c, -|6: 0-0 d,#6e988c, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, -|7: 0-0 d,#6e988c, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, -|8: 0-0 d,#6e988c, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, -|9: 0-0 d,#6e988c, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, -|10: 0-0 d,#6e988c, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, -|11: 0-0 d,#6e988c, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, -|12: 0-0 d,#6e988c, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, -|13: 0-0 d,#6e988c, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, -|14: 0-0 d,#6e988c, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, -|15: 0-0 d,#6e988c, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, -|16: 0-0 d,#6e988c, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, -|17: 0-1 #ffffff,#548073, 2-2 d,#28413d, 3-29 #bcd6cc,#28413d, 30-32 #e5c2e4,#28413d, 33-49 #bcd6cc,#28413d, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, -|18: 0-0 d,#6e988c, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, -|19: 0-0 d,#6e988c, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, -|20: 0-0 d,#6e988c, 1-49 d,#34464c, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, -|21: 0-0 d,#6e988c, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, -|22: 0-0 d,#6e988c, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, -|23: 0-0 d,#6e988c, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, -|24: 0-0 d,#6e988c, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, -|25: 0-0 d,#6e988c, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, -|26: 0-0 d,#6e988c, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, -|27: 0-0 d,#6e988c, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, -|28: 0-0 d,#6e988c, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, -|29: 0-0 d,#6e988c, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, -|30: 0-0 d,#6e988c, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e988c, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|0: 0-50 #bbd7cb,#29443f, 51-59 #e6f2f3,#325f6c, 60-70 #bbd7cb,#29443f, 71-99 d,#29443f, +|1: 0-1 #ffffff,#9a7662, 2-2 d,#34574d, 3-34 #c7e3d7,#34574d, 35-49 d,#34574d, 50-51 #ffffff,#9a7662, 52-52 d,#29443f, 53-84 #bbd7cb,#29443f, 85-99 d,#29443f, +|2: 0-1 #000000,#81cfb7, 2-2 d,#34574d, 3-29 #c7e3d7,#34574d, 30-32 #f0cef8,#34574d, 33-49 #c7e3d7,#34574d, 50-51 #ffffff,#548372, 52-52 d,#29443f, 53-79 #bbd7cb,#29443f, 80-82 #e4c2ec,#29443f, 83-99 #bbd7cb,#29443f, +|3: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|4: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|5: 0-0 d,#6e9b8b, 1-49 d,#34464c, 50-50 d,#6e9b8b, 51-99 d,#34464c, +|6: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|7: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|8: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|9: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|10: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|11: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|12: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|13: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|14: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|15: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|16: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|17: 0-1 #ffffff,#548372, 2-2 d,#29443f, 3-29 #bbd7cb,#29443f, 30-32 #e4c2ec,#29443f, 33-49 #bbd7cb,#29443f, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|18: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|19: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|20: 0-0 d,#6e9b8b, 1-49 d,#34464c, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|21: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|22: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|23: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|24: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|25: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|26: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|27: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|28: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|29: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, +|30: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-49 #bac9ce,#34464c, 50-50 d,#6e9b8b, 51-51 d,#34464c, 52-99 #bac9ce,#34464c, == snap solarium grid=100x31 cursor=4,5 == style solarium grid=100x31 -|0: 0-50 #c6d4be,#144043, 51-59 #eee8d5,#1f5c64, 60-70 #c6d4be,#144043, 71-99 d,#144043, -|1: 0-1 #ffffff,#3e7a94, 2-2 d,#234f50, 3-34 #d2e0ca,#234f50, 35-49 d,#234f50, 50-51 #ffffff,#3e7a94, 52-52 d,#144043, 53-84 #c6d4be,#144043, 85-99 d,#144043, -|2: 0-1 #000000,#d7c36e, 2-2 d,#234f50, 3-29 #d2e0ca,#234f50, 30-32 #f5cded,#234f50, 33-49 #d2e0ca,#234f50, 50-51 #ffffff,#477f76, 52-52 d,#144043, 53-79 #c6d4be,#144043, 80-82 #e9c1e1,#144043, 83-99 #c6d4be,#144043, -|3: 0-0 d,#66978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, -|4: 0-0 d,#66978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, -|5: 0-0 d,#66978c, 1-49 d,#173e45, 50-50 d,#66978c, 51-99 d,#173e45, -|6: 0-0 d,#66978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, -|7: 0-0 d,#66978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, -|8: 0-0 d,#66978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, -|9: 0-0 d,#66978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, -|10: 0-0 d,#66978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, -|11: 0-0 d,#66978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, -|12: 0-0 d,#66978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, -|13: 0-0 d,#66978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, -|14: 0-0 d,#66978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, -|15: 0-0 d,#66978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, -|16: 0-0 d,#66978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, -|17: 0-1 #ffffff,#477f76, 2-2 d,#144043, 3-29 #c6d4be,#144043, 30-32 #e9c1e1,#144043, 33-49 #c6d4be,#144043, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, -|18: 0-0 d,#66978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, -|19: 0-0 d,#66978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, -|20: 0-0 d,#66978c, 1-49 d,#173e45, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, -|21: 0-0 d,#66978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, -|22: 0-0 d,#66978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, -|23: 0-0 d,#66978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, -|24: 0-0 d,#66978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, -|25: 0-0 d,#66978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, -|26: 0-0 d,#66978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, -|27: 0-0 d,#66978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, -|28: 0-0 d,#66978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, -|29: 0-0 d,#66978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, -|30: 0-0 d,#66978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#66978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|0: 0-50 #c7d4bd,#123f43, 51-59 #eee8d5,#1f5c64, 60-70 #c7d4bd,#123f43, 71-99 d,#123f43, +|1: 0-1 #ffffff,#347a9a, 2-2 d,#214e50, 3-34 #d3e0c9,#214e50, 35-49 d,#214e50, 50-51 #ffffff,#347a9a, 52-52 d,#123f43, 53-84 #c7d4bd,#123f43, 85-99 d,#123f43, +|2: 0-1 #000000,#e1c266, 2-2 d,#214e50, 3-29 #d3e0c9,#214e50, 30-32 #f5cdec,#214e50, 33-49 #d3e0c9,#214e50, 50-51 #ffffff,#467f76, 52-52 d,#123f43, 53-79 #c7d4bd,#123f43, 80-82 #e9c1e0,#123f43, 83-99 #c7d4bd,#123f43, +|3: 0-0 d,#65978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|4: 0-0 d,#65978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|5: 0-0 d,#65978c, 1-49 d,#173e45, 50-50 d,#65978c, 51-99 d,#173e45, +|6: 0-0 d,#65978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|7: 0-0 d,#65978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|8: 0-0 d,#65978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|9: 0-0 d,#65978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|10: 0-0 d,#65978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|11: 0-0 d,#65978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|12: 0-0 d,#65978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|13: 0-0 d,#65978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|14: 0-0 d,#65978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|15: 0-0 d,#65978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|16: 0-0 d,#65978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|17: 0-1 #ffffff,#467f76, 2-2 d,#123f43, 3-29 #c7d4bd,#123f43, 30-32 #e9c1e0,#123f43, 33-49 #c7d4bd,#123f43, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|18: 0-0 d,#65978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|19: 0-0 d,#65978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|20: 0-0 d,#65978c, 1-49 d,#173e45, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|21: 0-0 d,#65978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|22: 0-0 d,#65978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|23: 0-0 d,#65978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|24: 0-0 d,#65978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|25: 0-0 d,#65978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|26: 0-0 d,#65978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|27: 0-0 d,#65978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|28: 0-0 d,#65978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|29: 0-0 d,#65978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, +|30: 0-0 d,#65978c, 1-1 d,#173e45, 2-49 #a7b7ae,#173e45, 50-50 d,#65978c, 51-51 d,#173e45, 52-99 #a7b7ae,#173e45, == snap spectrum grid=100x31 cursor=4,5 == style spectrum grid=100x31 -|0: 0-50 #dbd8bb,#373932, 51-59 #fcfcfa,#513f60, 60-70 #dbd8bb,#373932, 71-99 d,#373932, -|1: 0-1 #ffffff,#6a6796, 2-2 d,#494839, 3-34 #e7e4c7,#494839, 35-49 d,#494839, 50-51 #ffffff,#6a6796, 52-52 d,#373932, 53-84 #dbd8bb,#373932, 85-99 d,#373932, -|2: 0-1 #000000,#fcd666, 2-2 d,#494839, 3-29 #e7e4c7,#494839, 30-32 #dae1fd,#494839, 33-49 #e7e4c7,#494839, 50-51 #ffffff,#8a8453, 52-52 d,#373932, 53-79 #dbd8bb,#373932, 80-82 #c9d5fc,#373932, 83-99 #dbd8bb,#373932, -|3: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, -|4: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, -|5: 0-0 d,#8f8e72, 1-49 d,#100e11, 50-50 d,#8f8e72, 51-99 d,#100e11, -|6: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, -|7: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, -|8: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, -|9: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, -|10: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, -|11: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, -|12: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, -|13: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, -|14: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, -|15: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, -|16: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, -|17: 0-1 #ffffff,#8a8453, 2-2 d,#373932, 3-29 #dbd8bb,#373932, 30-32 #c9d5fc,#373932, 33-49 #dbd8bb,#373932, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, -|18: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, -|19: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, -|20: 0-0 d,#8f8e72, 1-49 d,#100e11, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, -|21: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, -|22: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, -|23: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, -|24: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, -|25: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, -|26: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, -|27: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, -|28: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, -|29: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, -|30: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#8f8e72, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|0: 0-50 #ddd8bb,#3b3830, 51-59 #fcfcfa,#513f60, 60-70 #ddd8bb,#3b3830, 71-99 d,#3b3830, +|1: 0-1 #ffffff,#706596, 2-2 d,#4d4736, 3-34 #e9e4c7,#4d4736, 35-49 d,#4d4736, 50-51 #ffffff,#706596, 52-52 d,#3b3830, 53-84 #ddd8bb,#3b3830, 85-99 d,#3b3830, +|2: 0-1 #000000,#ffd866, 2-2 d,#4d4736, 3-29 #e9e4c7,#4d4736, 30-32 #d7e3ff,#4d4736, 33-49 #e9e4c7,#4d4736, 50-51 #ffffff,#92844f, 52-52 d,#3b3830, 53-79 #ddd8bb,#3b3830, 80-82 #c5d7ff,#3b3830, 83-99 #ddd8bb,#3b3830, +|3: 0-0 d,#948d6f, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|4: 0-0 d,#948d6f, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|5: 0-0 d,#948d6f, 1-49 d,#100e11, 50-50 d,#948d6f, 51-99 d,#100e11, +|6: 0-0 d,#948d6f, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|7: 0-0 d,#948d6f, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|8: 0-0 d,#948d6f, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|9: 0-0 d,#948d6f, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|10: 0-0 d,#948d6f, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|11: 0-0 d,#948d6f, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|12: 0-0 d,#948d6f, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|13: 0-0 d,#948d6f, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|14: 0-0 d,#948d6f, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|15: 0-0 d,#948d6f, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|16: 0-0 d,#948d6f, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|17: 0-1 #ffffff,#92844f, 2-2 d,#3b3830, 3-29 #ddd8bb,#3b3830, 30-32 #c5d7ff,#3b3830, 33-49 #ddd8bb,#3b3830, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|18: 0-0 d,#948d6f, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|19: 0-0 d,#948d6f, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|20: 0-0 d,#948d6f, 1-49 d,#100e11, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|21: 0-0 d,#948d6f, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|22: 0-0 d,#948d6f, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|23: 0-0 d,#948d6f, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|24: 0-0 d,#948d6f, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|25: 0-0 d,#948d6f, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|26: 0-0 d,#948d6f, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|27: 0-0 d,#948d6f, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|28: 0-0 d,#948d6f, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|29: 0-0 d,#948d6f, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, +|30: 0-0 d,#948d6f, 1-1 d,#100e11, 2-49 #fcfcfa,#100e11, 50-50 d,#948d6f, 51-51 d,#100e11, 52-99 #fcfcfa,#100e11, == snap harvest grid=100x31 cursor=4,5 == style harvest grid=100x31 -|0: 0-50 #d6d8b8,#353b2e, 51-59 #f3f2cc,#4f5834, 60-70 #d6d8b8,#353b2e, 71-99 d,#353b2e, -|1: 0-1 #ffffff,#975948, 2-2 d,#434c38, 3-34 #e2e4c4,#434c38, 35-49 d,#434c38, 50-51 #ffffff,#975948, 52-52 d,#353b2e, 53-84 #d6d8b8,#353b2e, 85-99 d,#353b2e, -|2: 0-1 #000000,#dcc080, 2-2 d,#434c38, 3-29 #e2e4c4,#434c38, 30-32 #c7e7f8,#434c38, 33-49 #e2e4c4,#434c38, 50-51 #ffffff,#7d7f4e, 52-52 d,#353b2e, 53-79 #d6d8b8,#353b2e, 80-82 #bbdbed,#353b2e, 83-99 #d6d8b8,#353b2e, -|3: 0-0 d,#898e60, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, -|4: 0-0 d,#898e60, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, -|5: 0-0 d,#898e60, 1-49 d,#100e0b, 50-50 d,#898e60, 51-99 d,#100e0b, -|6: 0-0 d,#898e60, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, -|7: 0-0 d,#898e60, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, -|8: 0-0 d,#898e60, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, -|9: 0-0 d,#898e60, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, -|10: 0-0 d,#898e60, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, -|11: 0-0 d,#898e60, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, -|12: 0-0 d,#898e60, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, -|13: 0-0 d,#898e60, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, -|14: 0-0 d,#898e60, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, -|15: 0-0 d,#898e60, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, -|16: 0-0 d,#898e60, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, -|17: 0-1 #ffffff,#7d7f4e, 2-2 d,#353b2e, 3-29 #d6d8b8,#353b2e, 30-32 #bbdbed,#353b2e, 33-49 #d6d8b8,#353b2e, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, -|18: 0-0 d,#898e60, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, -|19: 0-0 d,#898e60, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, -|20: 0-0 d,#898e60, 1-49 d,#100e0b, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, -|21: 0-0 d,#898e60, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, -|22: 0-0 d,#898e60, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, -|23: 0-0 d,#898e60, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, -|24: 0-0 d,#898e60, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, -|25: 0-0 d,#898e60, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, -|26: 0-0 d,#898e60, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, -|27: 0-0 d,#898e60, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, -|28: 0-0 d,#898e60, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, -|29: 0-0 d,#898e60, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, -|30: 0-0 d,#898e60, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#898e60, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|0: 0-50 #d5d8b8,#343b2e, 51-59 #f3f2cc,#4f5834, 60-70 #d5d8b8,#343b2e, 71-99 d,#343b2e, +|1: 0-1 #ffffff,#9b583f, 2-2 d,#424d38, 3-34 #e1e4c4,#424d38, 35-49 d,#424d38, 50-51 #ffffff,#9b583f, 52-52 d,#343b2e, 53-84 #d5d8b8,#343b2e, 85-99 d,#343b2e, +|2: 0-1 #000000,#d8bd83, 2-2 d,#424d38, 3-29 #e1e4c4,#424d38, 30-32 #c5e7f7,#424d38, 33-49 #e1e4c4,#424d38, 50-51 #ffffff,#7b7e4e, 52-52 d,#343b2e, 53-79 #d5d8b8,#343b2e, 80-82 #badbeb,#343b2e, 83-99 #d5d8b8,#343b2e, +|3: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|4: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|5: 0-0 d,#888e5e, 1-49 d,#100e0b, 50-50 d,#888e5e, 51-99 d,#100e0b, +|6: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|7: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|8: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|9: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|10: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|11: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|12: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|13: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|14: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|15: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|16: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|17: 0-1 #ffffff,#7b7e4e, 2-2 d,#343b2e, 3-29 #d5d8b8,#343b2e, 30-32 #badbeb,#343b2e, 33-49 #d5d8b8,#343b2e, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|18: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|19: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|20: 0-0 d,#888e5e, 1-49 d,#100e0b, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|21: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|22: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|23: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|24: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|25: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|26: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|27: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|28: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|29: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, +|30: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-49 #f3f2cc,#100e0b, 50-50 d,#888e5e, 51-51 d,#100e0b, 52-99 #f3f2cc,#100e0b, == snap clay grid=100x31 cursor=4,5 == style clay grid=100x31 -|0: 0-50 #d7d6b6,#343f35, 51-59 #fbf1c7,#505c38, 60-70 #d7d6b6,#343f35, 71-99 d,#343f35, -|1: 0-1 #ffffff,#895d61, 2-2 d,#424f3f, 3-34 #e3e2c2,#424f3f, 35-49 d,#424f3f, 50-51 #ffffff,#895d61, 52-52 d,#343f35, 53-84 #d7d6b6,#343f35, 85-99 d,#343f35, -|2: 0-1 #000000,#92c776, 2-2 d,#424f3f, 3-29 #e3e2c2,#424f3f, 30-32 #b7eced,#424f3f, 33-49 #e3e2c2,#424f3f, 50-51 #ffffff,#6a7c4d, 52-52 d,#343f35, 53-79 #d7d6b6,#343f35, 80-82 #ace0e1,#343f35, 83-99 #d7d6b6,#343f35, -|3: 0-0 d,#8c9366, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, -|4: 0-0 d,#8c9366, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, -|5: 0-0 d,#8c9366, 1-49 d,#10100e, 50-50 d,#8c9366, 51-99 d,#10100e, -|6: 0-0 d,#8c9366, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, -|7: 0-0 d,#8c9366, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, -|8: 0-0 d,#8c9366, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, -|9: 0-0 d,#8c9366, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, -|10: 0-0 d,#8c9366, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, -|11: 0-0 d,#8c9366, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, -|12: 0-0 d,#8c9366, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, -|13: 0-0 d,#8c9366, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, -|14: 0-0 d,#8c9366, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, -|15: 0-0 d,#8c9366, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, -|16: 0-0 d,#8c9366, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, -|17: 0-1 #ffffff,#6a7c4d, 2-2 d,#343f35, 3-29 #d7d6b6,#343f35, 30-32 #ace0e1,#343f35, 33-49 #d7d6b6,#343f35, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, -|18: 0-0 d,#8c9366, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, -|19: 0-0 d,#8c9366, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, -|20: 0-0 d,#8c9366, 1-49 d,#10100e, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, -|21: 0-0 d,#8c9366, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, -|22: 0-0 d,#8c9366, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, -|23: 0-0 d,#8c9366, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, -|24: 0-0 d,#8c9366, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, -|25: 0-0 d,#8c9366, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, -|26: 0-0 d,#8c9366, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, -|27: 0-0 d,#8c9366, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, -|28: 0-0 d,#8c9366, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, -|29: 0-0 d,#8c9366, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, -|30: 0-0 d,#8c9366, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9366, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|0: 0-50 #d7d6b6,#343f36, 51-59 #fbf1c7,#505c38, 60-70 #d7d6b6,#343f36, 71-99 d,#343f36, +|1: 0-1 #ffffff,#875e65, 2-2 d,#424f40, 3-34 #e3e2c2,#424f40, 35-49 d,#424f40, 50-51 #ffffff,#875e65, 52-52 d,#343f36, 53-84 #d7d6b6,#343f36, 85-99 d,#343f36, +|2: 0-1 #000000,#8ac874, 2-2 d,#424f40, 3-29 #e3e2c2,#424f40, 30-32 #b5ecec,#424f40, 33-49 #e3e2c2,#424f40, 50-51 #ffffff,#687c4d, 52-52 d,#343f36, 53-79 #d7d6b6,#343f36, 80-82 #aae0e0,#343f36, 83-99 #d7d6b6,#343f36, +|3: 0-0 d,#8c9467, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|4: 0-0 d,#8c9467, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|5: 0-0 d,#8c9467, 1-49 d,#10100e, 50-50 d,#8c9467, 51-99 d,#10100e, +|6: 0-0 d,#8c9467, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|7: 0-0 d,#8c9467, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|8: 0-0 d,#8c9467, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|9: 0-0 d,#8c9467, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|10: 0-0 d,#8c9467, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|11: 0-0 d,#8c9467, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|12: 0-0 d,#8c9467, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|13: 0-0 d,#8c9467, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|14: 0-0 d,#8c9467, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|15: 0-0 d,#8c9467, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|16: 0-0 d,#8c9467, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|17: 0-1 #ffffff,#687c4d, 2-2 d,#343f36, 3-29 #d7d6b6,#343f36, 30-32 #aae0e0,#343f36, 33-49 #d7d6b6,#343f36, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|18: 0-0 d,#8c9467, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|19: 0-0 d,#8c9467, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|20: 0-0 d,#8c9467, 1-49 d,#10100e, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|21: 0-0 d,#8c9467, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|22: 0-0 d,#8c9467, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|23: 0-0 d,#8c9467, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|24: 0-0 d,#8c9467, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|25: 0-0 d,#8c9467, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|26: 0-0 d,#8c9467, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|27: 0-0 d,#8c9467, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|28: 0-0 d,#8c9467, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|29: 0-0 d,#8c9467, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, +|30: 0-0 d,#8c9467, 1-1 d,#10100e, 2-49 #f3e5bc,#10100e, 50-50 d,#8c9467, 51-51 d,#10100e, 52-99 #f3e5bc,#10100e, == snap forge-black grid=100x31 cursor=4,5 == style forge-black grid=100x31 -|0: 0-50 #c7cacf,#24282c, 51-59 #e2eef4,#1c5172, 60-70 #c7cacf,#24282c, 71-99 d,#24282c, -|1: 0-1 #ffffff,#6d7867, 2-2 d,#2f3740, 3-34 #d3d6db,#2f3740, 35-49 d,#2f3740, 50-51 #ffffff,#6d7867, 52-52 d,#24282c, 53-84 #c7cacf,#24282c, 85-99 d,#24282c, -|2: 0-1 #000000,#9ac4ea, 2-2 d,#2f3740, 3-29 #d3d6db,#2f3740, 30-32 #f1ceae,#2f3740, 33-49 #d3d6db,#2f3740, 50-51 #ffffff,#576676, 52-52 d,#24282c, 53-79 #c7cacf,#24282c, 80-82 #e5c2a2,#24282c, 83-99 #c7cacf,#24282c, -|3: 0-0 d,#738290, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, -|4: 0-0 d,#738290, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, -|5: 0-0 d,#738290, 1-49 d,#000000, 50-50 d,#738290, 51-99 d,#000000, -|6: 0-0 d,#738290, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, -|7: 0-0 d,#738290, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, -|8: 0-0 d,#738290, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, -|9: 0-0 d,#738290, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, -|10: 0-0 d,#738290, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, -|11: 0-0 d,#738290, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, -|12: 0-0 d,#738290, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, -|13: 0-0 d,#738290, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, -|14: 0-0 d,#738290, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, -|15: 0-0 d,#738290, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, -|16: 0-0 d,#738290, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, -|17: 0-1 #ffffff,#576676, 2-2 d,#24282c, 3-29 #c7cacf,#24282c, 30-32 #e5c2a2,#24282c, 33-49 #c7cacf,#24282c, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, -|18: 0-0 d,#738290, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, -|19: 0-0 d,#738290, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, -|20: 0-0 d,#738290, 1-49 d,#000000, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, -|21: 0-0 d,#738290, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, -|22: 0-0 d,#738290, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, -|23: 0-0 d,#738290, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, -|24: 0-0 d,#738290, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, -|25: 0-0 d,#738290, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, -|26: 0-0 d,#738290, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, -|27: 0-0 d,#738290, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, -|28: 0-0 d,#738290, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, -|29: 0-0 d,#738290, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, -|30: 0-0 d,#738290, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#738290, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|0: 0-50 #c5c9d2,#22252b, 51-59 #e2eef4,#1c5172, 60-70 #c5c9d2,#22252b, 71-99 d,#22252b, +|1: 0-1 #ffffff,#6a7b67, 2-2 d,#2d3440, 3-34 #d1d5de,#2d3440, 35-49 d,#2d3440, 50-51 #ffffff,#6a7b67, 52-52 d,#22252b, 53-84 #c5c9d2,#22252b, 85-99 d,#22252b, +|2: 0-1 #000000,#9cc3f7, 2-2 d,#2d3440, 3-29 #d1d5de,#2d3440, 30-32 #f8cba7,#2d3440, 33-49 #d1d5de,#2d3440, 50-51 #ffffff,#55647b, 52-52 d,#22252b, 53-79 #c5c9d2,#22252b, 80-82 #ecbf9b,#22252b, 83-99 #c5c9d2,#22252b, +|3: 0-0 d,#708095, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|4: 0-0 d,#708095, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|5: 0-0 d,#708095, 1-49 d,#000000, 50-50 d,#708095, 51-99 d,#000000, +|6: 0-0 d,#708095, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|7: 0-0 d,#708095, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|8: 0-0 d,#708095, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|9: 0-0 d,#708095, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|10: 0-0 d,#708095, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|11: 0-0 d,#708095, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|12: 0-0 d,#708095, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|13: 0-0 d,#708095, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|14: 0-0 d,#708095, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|15: 0-0 d,#708095, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|16: 0-0 d,#708095, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|17: 0-1 #ffffff,#55647b, 2-2 d,#22252b, 3-29 #c5c9d2,#22252b, 30-32 #ecbf9b,#22252b, 33-49 #c5c9d2,#22252b, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|18: 0-0 d,#708095, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|19: 0-0 d,#708095, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|20: 0-0 d,#708095, 1-49 d,#000000, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|21: 0-0 d,#708095, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|22: 0-0 d,#708095, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|23: 0-0 d,#708095, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|24: 0-0 d,#708095, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|25: 0-0 d,#708095, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|26: 0-0 d,#708095, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|27: 0-0 d,#708095, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|28: 0-0 d,#708095, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|29: 0-0 d,#708095, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, +|30: 0-0 d,#708095, 1-1 d,#000000, 2-49 #f6f6f6,#000000, 50-50 d,#708095, 51-51 d,#000000, 52-99 #f6f6f6,#000000, == snap forge-soft grid=100x31 cursor=4,5 == style forge-soft grid=100x31 -|0: 0-50 #c5c9d2,#292c33, 51-59 #e2eef4,#1c5172, 60-70 #c5c9d2,#292c33, 71-99 d,#292c33, -|1: 0-1 #ffffff,#6d7f6c, 2-2 d,#363d48, 3-34 #d1d5de,#363d48, 35-49 d,#363d48, 50-51 #ffffff,#6d7f6c, 52-52 d,#292c33, 53-84 #c5c9d2,#292c33, 85-99 d,#292c33, -|2: 0-1 #000000,#9cc3f7, 2-2 d,#363d48, 3-29 #d1d5de,#363d48, 30-32 #f8cba7,#363d48, 33-49 #d1d5de,#363d48, 50-51 #ffffff,#55647b, 52-52 d,#292c33, 53-79 #c5c9d2,#292c33, 80-82 #ecbf9b,#292c33, 83-99 #c5c9d2,#292c33, +|0: 0-50 #c5c9d2,#2a2d34, 51-59 #e2eef4,#1c5172, 60-70 #c5c9d2,#2a2d34, 71-99 d,#2a2d34, +|1: 0-1 #ffffff,#6d7f6c, 2-2 d,#373e49, 3-34 #d1d5de,#373e49, 35-49 d,#373e49, 50-51 #ffffff,#6d7f6c, 52-52 d,#2a2d34, 53-84 #c5c9d2,#2a2d34, 85-99 d,#2a2d34, +|2: 0-1 #000000,#9cc3f7, 2-2 d,#373e49, 3-29 #d1d5de,#373e49, 30-32 #f8cba7,#373e49, 33-49 #d1d5de,#373e49, 50-51 #ffffff,#55647b, 52-52 d,#2a2d34, 53-79 #c5c9d2,#2a2d34, 80-82 #ecbf9b,#2a2d34, 83-99 #c5c9d2,#2a2d34, |3: 0-0 d,#708095, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#708095, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e, |4: 0-0 d,#708095, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#708095, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e, |5: 0-0 d,#708095, 1-49 d,#35383e, 50-50 d,#708095, 51-99 d,#35383e, @@ -501,7 +497,7 @@ |14: 0-0 d,#708095, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#708095, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e, |15: 0-0 d,#708095, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#708095, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e, |16: 0-0 d,#708095, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#708095, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e, -|17: 0-1 #ffffff,#55647b, 2-2 d,#292c33, 3-29 #c5c9d2,#292c33, 30-32 #ecbf9b,#292c33, 33-49 #c5c9d2,#292c33, 50-50 d,#708095, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e, +|17: 0-1 #ffffff,#55647b, 2-2 d,#2a2d34, 3-29 #c5c9d2,#2a2d34, 30-32 #ecbf9b,#2a2d34, 33-49 #c5c9d2,#2a2d34, 50-50 d,#708095, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e, |18: 0-0 d,#708095, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#708095, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e, |19: 0-0 d,#708095, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#708095, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e, |20: 0-0 d,#708095, 1-49 d,#35383e, 50-50 d,#708095, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e, @@ -517,166 +513,166 @@ |30: 0-0 d,#708095, 1-1 d,#35383e, 2-49 #bfc3cc,#35383e, 50-50 d,#708095, 51-51 d,#35383e, 52-99 #bfc3cc,#35383e, == snap orchard-black grid=100x31 cursor=4,5 == style orchard-black grid=100x31 -|0: 0-50 #b4c4bb,#1e2926, 51-59 #f5f7ee,#3c614a, 60-70 #b4c4bb,#1e2926, 71-99 d,#1e2926, -|1: 0-1 #ffffff,#857557, 2-2 d,#283730, 3-34 #c0d0c7,#283730, 35-49 d,#283730, 50-51 #ffffff,#857557, 52-52 d,#1e2926, 53-84 #b4c4bb,#1e2926, 85-99 d,#1e2926, -|2: 0-1 #000000,#abd195, 2-2 d,#283730, 3-29 #c0d0c7,#283730, 30-32 #e2bedf,#283730, 33-49 #c0d0c7,#283730, 50-51 #ffffff,#4a665a, 52-52 d,#1e2926, 53-79 #b4c4bb,#1e2926, 80-82 #d6b2d3,#1e2926, 83-99 #b4c4bb,#1e2926, -|3: 0-0 d,#62826d, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, -|4: 0-0 d,#62826d, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, -|5: 0-0 d,#62826d, 1-49 d,#000000, 50-50 d,#62826d, 51-99 d,#000000, -|6: 0-0 d,#62826d, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, -|7: 0-0 d,#62826d, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, -|8: 0-0 d,#62826d, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, -|9: 0-0 d,#62826d, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, -|10: 0-0 d,#62826d, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, -|11: 0-0 d,#62826d, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, -|12: 0-0 d,#62826d, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, -|13: 0-0 d,#62826d, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, -|14: 0-0 d,#62826d, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, -|15: 0-0 d,#62826d, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, -|16: 0-0 d,#62826d, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, -|17: 0-1 #ffffff,#4a665a, 2-2 d,#1e2926, 3-29 #b4c4bb,#1e2926, 30-32 #d6b2d3,#1e2926, 33-49 #b4c4bb,#1e2926, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, -|18: 0-0 d,#62826d, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, -|19: 0-0 d,#62826d, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, -|20: 0-0 d,#62826d, 1-49 d,#000000, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, -|21: 0-0 d,#62826d, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, -|22: 0-0 d,#62826d, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, -|23: 0-0 d,#62826d, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, -|24: 0-0 d,#62826d, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, -|25: 0-0 d,#62826d, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, -|26: 0-0 d,#62826d, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, -|27: 0-0 d,#62826d, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, -|28: 0-0 d,#62826d, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, -|29: 0-0 d,#62826d, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, -|30: 0-0 d,#62826d, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#62826d, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|0: 0-50 #b2c3b8,#1d2824, 51-59 #f5f7ee,#3c614a, 60-70 #b2c3b8,#1d2824, 71-99 d,#1d2824, +|1: 0-1 #ffffff,#887455, 2-2 d,#26362d, 3-34 #becfc4,#26362d, 35-49 d,#26362d, 50-51 #ffffff,#887455, 52-52 d,#1d2824, 53-84 #b2c3b8,#1d2824, 85-99 d,#1d2824, +|2: 0-1 #000000,#add38a, 2-2 d,#26362d, 3-29 #becfc4,#26362d, 30-32 #dfbce5,#26362d, 33-49 #becfc4,#26362d, 50-51 #ffffff,#496656, 52-52 d,#1d2824, 53-79 #b2c3b8,#1d2824, 80-82 #d3b0d9,#1d2824, 83-99 #b2c3b8,#1d2824, +|3: 0-0 d,#608269, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|4: 0-0 d,#608269, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|5: 0-0 d,#608269, 1-49 d,#000000, 50-50 d,#608269, 51-99 d,#000000, +|6: 0-0 d,#608269, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|7: 0-0 d,#608269, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|8: 0-0 d,#608269, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|9: 0-0 d,#608269, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|10: 0-0 d,#608269, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|11: 0-0 d,#608269, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|12: 0-0 d,#608269, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|13: 0-0 d,#608269, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|14: 0-0 d,#608269, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|15: 0-0 d,#608269, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|16: 0-0 d,#608269, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|17: 0-1 #ffffff,#496656, 2-2 d,#1d2824, 3-29 #b2c3b8,#1d2824, 30-32 #d3b0d9,#1d2824, 33-49 #b2c3b8,#1d2824, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|18: 0-0 d,#608269, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|19: 0-0 d,#608269, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|20: 0-0 d,#608269, 1-49 d,#000000, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|21: 0-0 d,#608269, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|22: 0-0 d,#608269, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|23: 0-0 d,#608269, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|24: 0-0 d,#608269, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|25: 0-0 d,#608269, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|26: 0-0 d,#608269, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|27: 0-0 d,#608269, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|28: 0-0 d,#608269, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|29: 0-0 d,#608269, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, +|30: 0-0 d,#608269, 1-1 d,#000000, 2-49 #f2f8ef,#000000, 50-50 d,#608269, 51-51 d,#000000, 52-99 #f2f8ef,#000000, == snap helix grid=100x31 cursor=4,5 == style helix grid=100x31 -|0: 0-50 #979998,#131414, 51-59 #080808,#80a0ff, 60-70 #979998,#131414, 71-99 d,#131414, -|1: 0-1 #ffffff,#837048, 2-2 d,#141615, 3-34 #989a99,#141615, 35-49 d,#141615, 50-51 #ffffff,#837048, 52-52 d,#131414, 53-84 #979998,#131414, 85-99 d,#131414, -|2: 0-1 #ffffff,#6a6d66, 2-2 d,#141615, 3-29 #989a99,#141615, 30-32 #9c989c,#141615, 33-49 #989a99,#141615, 50-51 #ffffff,#2a2c2b, 52-52 d,#131414, 53-79 #979998,#131414, 80-82 #9a979b,#131414, 83-99 #979998,#131414, -|3: 0-0 d,#474a48, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, -|4: 0-0 d,#474a48, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, -|5: 0-0 d,#474a48, 1-49 d,#080808, 50-50 d,#474a48, 51-99 d,#080808, -|6: 0-0 d,#474a48, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, -|7: 0-0 d,#474a48, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, -|8: 0-0 d,#474a48, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, -|9: 0-0 d,#474a48, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, -|10: 0-0 d,#474a48, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, -|11: 0-0 d,#474a48, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, -|12: 0-0 d,#474a48, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, -|13: 0-0 d,#474a48, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, -|14: 0-0 d,#474a48, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, -|15: 0-0 d,#474a48, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, -|16: 0-0 d,#474a48, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, -|17: 0-1 #ffffff,#2a2c2b, 2-2 d,#131414, 3-29 #979998,#131414, 30-32 #9a979b,#131414, 33-49 #979998,#131414, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, -|18: 0-0 d,#474a48, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, -|19: 0-0 d,#474a48, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, -|20: 0-0 d,#474a48, 1-49 d,#080808, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, -|21: 0-0 d,#474a48, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, -|22: 0-0 d,#474a48, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, -|23: 0-0 d,#474a48, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, -|24: 0-0 d,#474a48, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, -|25: 0-0 d,#474a48, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, -|26: 0-0 d,#474a48, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, -|27: 0-0 d,#474a48, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, -|28: 0-0 d,#474a48, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, -|29: 0-0 d,#474a48, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, -|30: 0-0 d,#474a48, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#474a48, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|0: 0-50 #949494,#121212, 51-59 #080808,#80a0ff, 60-70 #949494,#121212, 71-99 d,#121212, +|1: 0-1 #ffffff,#826f46, 2-2 d,#121212, 3-34 #949494,#121212, 35-49 d,#121212, 50-51 #ffffff,#826f46, 52-52 d,#121212, 53-84 #949494,#121212, 85-99 d,#121212, +|2: 0-1 #ffffff,#626262, 2-2 d,#121212, 3-49 #949494,#121212, 50-51 #ffffff,#262626, 52-52 d,#121212, 53-99 #949494,#121212, +|3: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|4: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|5: 0-0 d,#444444, 1-49 d,#080808, 50-50 d,#444444, 51-99 d,#080808, +|6: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|7: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|8: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|9: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|10: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|11: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|12: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|13: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|14: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|15: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|16: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|17: 0-1 #ffffff,#262626, 2-2 d,#121212, 3-49 #949494,#121212, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|18: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|19: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|20: 0-0 d,#444444, 1-49 d,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|21: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|22: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|23: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|24: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|25: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|26: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|27: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|28: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|29: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, +|30: 0-0 d,#444444, 1-1 d,#080808, 2-49 #bdbdbd,#080808, 50-50 d,#444444, 51-51 d,#080808, 52-99 #bdbdbd,#080808, == snap dark grid=100x31 cursor=4,5 == style dark grid=100x31 -|0: 0-50 #969696,#29283a, 51-59 #d8c8a8,#513c17, 60-70 #969696,#29283a, 71-99 d,#29283a, -|1: 0-1 #ffffff,#86794d, 2-2 d,#29283a, 3-34 #969696,#29283a, 35-49 d,#29283a, 50-51 #ffffff,#86794d, 52-52 d,#29283a, 53-84 #969696,#29283a, 85-99 d,#29283a, -|2: 0-1 #ffffff,#6643d3, 2-2 d,#29283a, 3-49 #969696,#29283a, 50-51 #ffffff,#343853, 52-52 d,#29283a, 53-99 #969696,#29283a, -|3: 0-0 d,#515151, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, -|4: 0-0 d,#515151, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, -|5: 0-0 d,#515151, 1-49 d,d, 50-50 d,#515151, 51-99 d,d, -|6: 0-0 d,#515151, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, -|7: 0-0 d,#515151, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, -|8: 0-0 d,#515151, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, -|9: 0-0 d,#515151, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, -|10: 0-0 d,#515151, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, -|11: 0-0 d,#515151, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, -|12: 0-0 d,#515151, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, -|13: 0-0 d,#515151, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, -|14: 0-0 d,#515151, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, -|15: 0-0 d,#515151, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, -|16: 0-0 d,#515151, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, -|17: 0-1 #ffffff,#343853, 2-2 d,#29283a, 3-49 #969696,#29283a, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, -|18: 0-0 d,#515151, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, -|19: 0-0 d,#515151, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, -|20: 0-0 d,#515151, 1-49 d,d, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, -|21: 0-0 d,#515151, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, -|22: 0-0 d,#515151, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, -|23: 0-0 d,#515151, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, -|24: 0-0 d,#515151, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, -|25: 0-0 d,#515151, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, -|26: 0-0 d,#515151, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, -|27: 0-0 d,#515151, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, -|28: 0-0 d,#515151, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, -|29: 0-0 d,#515151, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, -|30: 0-0 d,#515151, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#515151, 51-51 d,d, 52-99 #969696,#2c2a3e, +|0: 0-50 #969696,#2c2a3e, 51-59 #d8c8a8,#513c17, 60-70 #969696,#2c2a3e, 71-99 d,#2c2a3e, +|1: 0-1 #ffffff,#867a4e, 2-2 d,#2c2a3e, 3-34 #969696,#2c2a3e, 35-49 d,#2c2a3e, 50-51 #ffffff,#867a4e, 52-52 d,#2c2a3e, 53-84 #969696,#2c2a3e, 85-99 d,#2c2a3e, +|2: 0-1 #ffffff,#663fe0, 2-2 d,#2c2a3e, 3-49 #969696,#2c2a3e, 50-51 #ffffff,#353a58, 52-52 d,#2c2a3e, 53-99 #969696,#2c2a3e, +|3: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, +|4: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, +|5: 0-0 d,#525252, 1-49 d,d, 50-50 d,#525252, 51-99 d,d, +|6: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, +|7: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, +|8: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, +|9: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, +|10: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, +|11: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, +|12: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, +|13: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, +|14: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, +|15: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, +|16: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, +|17: 0-1 #ffffff,#353a58, 2-2 d,#2c2a3e, 3-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, +|18: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, +|19: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, +|20: 0-0 d,#525252, 1-49 d,d, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, +|21: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, +|22: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, +|23: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, +|24: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, +|25: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, +|26: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, +|27: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, +|28: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, +|29: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, +|30: 0-0 d,#525252, 1-1 d,d, 2-49 #969696,#2c2a3e, 50-50 d,#525252, 51-51 d,d, 52-99 #969696,#2c2a3e, == snap acme grid=100x31 cursor=4,5 == style acme grid=100x31 -|0: 0-50 #0f0f0f,#d7eaec, 51-59 #000000,#fafa92, 60-70 #0f0f0f,#d7eaec, 71-99 d,#d7eaec, -|1: 0-1 #000000,#bfa37a, 2-2 d,#d7eaec, 3-34 #0f0f0f,#d7eaec, 35-49 d,#d7eaec, 50-51 #000000,#bfa37a, 52-52 d,#d7eaec, 53-84 #0f0f0f,#d7eaec, 85-99 d,#d7eaec, -|2: 0-1 #ffffff,#663fe0, 2-2 d,#d7eaec, 3-49 #0f0f0f,#d7eaec, 50-51 #ffffff,#353a58, 52-52 d,#d7eaec, 53-99 #0f0f0f,#d7eaec, -|3: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-49 #000000,#ffffea, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, -|4: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-49 #000000,#ffffea, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, -|5: 0-0 d,#eeeedb, 1-49 d,#ffffea, 50-50 d,#eeeedb, 51-99 d,#ffffea, -|6: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-49 #000000,#ffffea, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, -|7: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-49 #000000,#ffffea, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, -|8: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-49 #000000,#ffffea, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, -|9: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-49 #000000,#ffffea, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, -|10: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-49 #000000,#ffffea, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, -|11: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-49 #000000,#ffffea, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, -|12: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-49 #000000,#ffffea, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, -|13: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-49 #000000,#ffffea, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, -|14: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-49 #000000,#ffffea, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, -|15: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-49 #000000,#ffffea, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, -|16: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-49 #000000,#ffffea, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, -|17: 0-1 #ffffff,#353a58, 2-2 d,#d7eaec, 3-49 #0f0f0f,#d7eaec, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, -|18: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-49 #000000,#ffffea, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, -|19: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-49 #000000,#ffffea, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, -|20: 0-0 d,#eeeedb, 1-49 d,#ffffea, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, -|21: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-49 #000000,#ffffea, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, -|22: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-49 #000000,#ffffea, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, -|23: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-49 #000000,#ffffea, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, -|24: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-49 #000000,#ffffea, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, -|25: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-49 #000000,#ffffea, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, -|26: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-49 #000000,#ffffea, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, -|27: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-49 #000000,#ffffea, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, -|28: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-49 #000000,#ffffea, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, -|29: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-49 #000000,#ffffea, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, -|30: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-49 #000000,#ffffea, 50-50 d,#eeeedb, 51-51 d,#ffffea, 52-99 #000000,#ffffea, +|0: 0-50 #000000,#eaffff, 51-59 #000000,#fafa92, 60-70 #000000,#eaffff, 71-99 d,#eaffff, +|1: 0-1 #000000,#c5a87f, 2-2 d,#eaffff, 3-34 #000000,#eaffff, 35-49 d,#eaffff, 50-51 #000000,#c5a87f, 52-52 d,#eaffff, 53-84 #000000,#eaffff, 85-99 d,#eaffff, +|2: 0-1 #ffffff,#663fe0, 2-2 d,#eaffff, 3-49 #000000,#eaffff, 50-51 #ffffff,#353a58, 52-52 d,#eaffff, 53-99 #000000,#eaffff, +|3: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea, +|4: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea, +|5: 0-99 d,#ffffea, +|6: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea, +|7: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea, +|8: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea, +|9: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea, +|10: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea, +|11: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea, +|12: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea, +|13: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea, +|14: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea, +|15: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea, +|16: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea, +|17: 0-1 #ffffff,#353a58, 2-2 d,#eaffff, 3-49 #000000,#eaffff, 50-51 d,#ffffea, 52-99 #000000,#ffffea, +|18: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea, +|19: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea, +|20: 0-51 d,#ffffea, 52-99 #000000,#ffffea, +|21: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea, +|22: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea, +|23: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea, +|24: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea, +|25: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea, +|26: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea, +|27: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea, +|28: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea, +|29: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea, +|30: 0-1 d,#ffffea, 2-49 #000000,#ffffea, 50-51 d,#ffffea, 52-99 #000000,#ffffea, == snap generated grid=100x31 cursor=4,5 == style generated grid=100x31 -|0: 0-50 #cacaca,#323c43, 51-59 #e0e0e0,#303840, 60-70 #cacaca,#323c43, 71-99 d,#323c43, -|1: 0-1 #ffffff,#5b8094, 2-2 d,#323c43, 3-34 #cacaca,#323c43, 35-49 d,#323c43, 50-51 #ffffff,#5b8094, 52-52 d,#323c43, 53-84 #cacaca,#323c43, 85-99 d,#323c43, -|2: 0-1 #000000,#f0966d, 2-2 d,#323c43, 3-49 #cacaca,#323c43, 50-51 #ffffff,#313842, 52-52 d,#323c43, 53-99 #cacaca,#323c43, -|3: 0-0 d,#454c51, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, -|4: 0-0 d,#454c51, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, -|5: 0-0 d,#454c51, 1-49 d,#161e26, 50-50 d,#454c51, 51-99 d,#161e26, -|6: 0-0 d,#454c51, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, -|7: 0-0 d,#454c51, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, -|8: 0-0 d,#454c51, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, -|9: 0-0 d,#454c51, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, -|10: 0-0 d,#454c51, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, -|11: 0-0 d,#454c51, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, -|12: 0-0 d,#454c51, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, -|13: 0-0 d,#454c51, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, -|14: 0-0 d,#454c51, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, -|15: 0-0 d,#454c51, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, -|16: 0-0 d,#454c51, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, -|17: 0-1 #ffffff,#313842, 2-2 d,#323c43, 3-49 #cacaca,#323c43, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, -|18: 0-0 d,#454c51, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, -|19: 0-0 d,#454c51, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, -|20: 0-0 d,#454c51, 1-49 d,#161e26, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, -|21: 0-0 d,#454c51, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, -|22: 0-0 d,#454c51, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, -|23: 0-0 d,#454c51, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, -|24: 0-0 d,#454c51, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, -|25: 0-0 d,#454c51, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, -|26: 0-0 d,#454c51, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, -|27: 0-0 d,#454c51, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, -|28: 0-0 d,#454c51, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, -|29: 0-0 d,#454c51, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, -|30: 0-0 d,#454c51, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#454c51, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|0: 0-50 #e0e0e0,#1e262e, 51-59 #e0e0e0,#303840, 60-70 #e0e0e0,#1e262e, 71-99 d,#1e262e, +|1: 0-1 #ffffff,#4f7b96, 2-2 d,#1e262e, 3-34 #e0e0e0,#1e262e, 35-49 d,#1e262e, 50-51 #ffffff,#4f7b96, 52-52 d,#1e262e, 53-84 #e0e0e0,#1e262e, 85-99 d,#1e262e, +|2: 0-1 #000000,#ffa060, 2-2 d,#1e262e, 3-49 #e0e0e0,#1e262e, 50-51 #ffffff,#303840, 52-52 d,#1e262e, 53-99 #e0e0e0,#1e262e, +|3: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|4: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|5: 0-0 d,#303840, 1-49 d,#161e26, 50-50 d,#303840, 51-99 d,#161e26, +|6: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|7: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|8: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|9: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|10: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|11: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|12: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|13: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|14: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|15: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|16: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|17: 0-1 #ffffff,#303840, 2-2 d,#1e262e, 3-49 #e0e0e0,#1e262e, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|18: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|19: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|20: 0-0 d,#303840, 1-49 d,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|21: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|22: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|23: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|24: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|25: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|26: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|27: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|28: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|29: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, +|30: 0-0 d,#303840, 1-1 d,#161e26, 2-49 #e0e0e0,#161e26, 50-50 d,#303840, 51-51 d,#161e26, 52-99 #e0e0e0,#161e26, diff --git a/test/snapshots/themesel.golden b/test/snapshots/themesel.golden index b3100e27..97d3ed41 100644 --- a/test/snapshots/themesel.golden +++ b/test/snapshots/themesel.golden @@ -83,169 +83,169 @@ |30: 0-0 d,#152019, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-16 #e5eee5,#0d1410, 17-99 d,#0d1410, == snap step-dusk grid=100x31 cursor=7,20 == style step-dusk grid=100x31 -|0: 0-70 #c4b7c4,#2b262f, 71-99 d,#2b262f, -|1: 0-1 #ffffff,#77795e, 2-2 d,#39303a, 3-34 #d0c3d0,#39303a, 35-99 d,#39303a, -|2: 0-1 #ffffff,#705667, 2-2 d,#2b262f, 3-32 #c4b7c4,#2b262f, 33-37 #9cc7bb,#2b262f, 38-59 #c4b7c4,#2b262f, 60-99 d,#2b262f, -|3: 0-0 d,#89697a, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b, -|4: 0-0 d,#89697a, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b, -|5: 0-0 d,#89697a, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b, -|6: 0-0 d,#89697a, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b, -|7: 0-0 d,#39333c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b, -|8: 0-0 d,#39333c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b, -|9: 0-0 d,#39333c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b, -|10: 0-0 d,#39333c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b, -|11: 0-0 d,#39333c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b, -|12: 0-0 d,#39333c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-13 #c3b6c1,#39323b, 14-99 d,#39323b, -|13: 0-0 d,#39333c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-13 #c3b6c1,#39323b, 14-99 d,#39323b, -|14: 0-0 d,#39333c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-13 #c3b6c1,#39323b, 14-99 d,#39323b, -|15: 0-0 d,#39333c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-13 #c3b6c1,#39323b, 14-99 d,#39323b, -|16: 0-0 d,#39333c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-13 #c3b6c1,#39323b, 14-99 d,#39323b, -|17: 0-1 #000000,#e7b491, 2-2 d,#39303a, 3-32 #d0c3d0,#39303a, 33-39 #a7d3c7,#39303a, 40-61 #d0c3d0,#39303a, 62-99 d,#39303a, -|18: 0-0 d,#89697a, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-21 #c3b6c1,#39323b, 22-92 d,#39323b, 93-93 d,#2b262f, 94-98 #c4b7c4,#2b262f, 99-99 d,#2b262f, -|19: 0-0 d,#39333c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-19 #c3b6c1,#39323b, 20-99 d,#39323b, -|20: 0-0 d,#39333c, 1-1 d,#39323b, 2-6 #8a7986,#39323b,b 7-16 #c3b6c1,#39323b, 17-99 d,#39323b, -|21: 0-0 d,#39333c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-15 #c3b6c1,#39323b, 16-99 d,#39323b, -|22: 0-0 d,#39333c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-17 #c3b6c1,#39323b, 18-99 d,#39323b, -|23: 0-0 d,#39333c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-20 #c3b6c1,#39323b, 21-99 d,#39323b, -|24: 0-0 d,#39333c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-19 #c3b6c1,#39323b, 20-99 d,#39323b, -|25: 0-0 d,#39333c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-17 #c3b6c1,#39323b, 18-99 d,#39323b, -|26: 0-0 d,#39333c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-18 #c3b6c1,#39323b, 19-99 d,#39323b, -|27: 0-0 d,#39333c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-20 #c3b6c1,#39323b, 21-99 d,#39323b, -|28: 0-0 d,#39333c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-20 #c3b6c1,#39323b, 21-99 d,#39323b, -|29: 0-0 d,#39333c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-19 #c3b6c1,#39323b, 20-99 d,#39323b, -|30: 0-0 d,#39333c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-16 #c3b6c1,#39323b, 17-99 d,#39323b, +|0: 0-70 #c6b6c5,#2c2630, 71-99 d,#2c2630, +|1: 0-1 #ffffff,#757a5f, 2-2 d,#3b2f3b, 3-34 #d2c2d1,#3b2f3b, 35-99 d,#3b2f3b, +|2: 0-1 #ffffff,#745469, 2-2 d,#2c2630, 3-32 #c6b6c5,#2c2630, 33-37 #96c9b8,#2c2630, 38-59 #c6b6c5,#2c2630, 60-99 d,#2c2630, +|3: 0-0 d,#8e667c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b, +|4: 0-0 d,#8e667c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b, +|5: 0-0 d,#8e667c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b, +|6: 0-0 d,#8e667c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b, +|7: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b, +|8: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b, +|9: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b, +|10: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b, +|11: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-12 #c3b6c1,#39323b, 13-99 d,#39323b, +|12: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-13 #c3b6c1,#39323b, 14-99 d,#39323b, +|13: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-13 #c3b6c1,#39323b, 14-99 d,#39323b, +|14: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-13 #c3b6c1,#39323b, 14-99 d,#39323b, +|15: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-13 #c3b6c1,#39323b, 14-99 d,#39323b, +|16: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-13 #c3b6c1,#39323b, 14-99 d,#39323b, +|17: 0-1 #000000,#edb092, 2-2 d,#3b2f3b, 3-32 #d2c2d1,#3b2f3b, 33-39 #a1d5c4,#3b2f3b, 40-61 #d2c2d1,#3b2f3b, 62-99 d,#3b2f3b, +|18: 0-0 d,#8e667c, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-21 #c3b6c1,#39323b, 22-92 d,#39323b, 93-93 d,#2c2630, 94-98 #c6b6c5,#2c2630, 99-99 d,#2c2630, +|19: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-19 #c3b6c1,#39323b, 20-99 d,#39323b, +|20: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #8a7986,#39323b,b 7-16 #c3b6c1,#39323b, 17-99 d,#39323b, +|21: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-15 #c3b6c1,#39323b, 16-99 d,#39323b, +|22: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-17 #c3b6c1,#39323b, 18-99 d,#39323b, +|23: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-20 #c3b6c1,#39323b, 21-99 d,#39323b, +|24: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-19 #c3b6c1,#39323b, 20-99 d,#39323b, +|25: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-17 #c3b6c1,#39323b, 18-99 d,#39323b, +|26: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-18 #c3b6c1,#39323b, 19-99 d,#39323b, +|27: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-20 #c3b6c1,#39323b, 21-99 d,#39323b, +|28: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-20 #c3b6c1,#39323b, 21-99 d,#39323b, +|29: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-19 #c3b6c1,#39323b, 20-99 d,#39323b, +|30: 0-0 d,#3d3540, 1-1 d,#39323b, 2-6 #82717e,#39323b, 7-16 #c3b6c1,#39323b, 17-99 d,#39323b, == snap step-atelier grid=100x31 cursor=7,24 == style step-atelier grid=100x31 -|0: 0-70 #4b6960,#d2dcda, 71-99 d,#d2dcda, -|1: 0-1 #000000,#b5a07e, 2-2 d,#c4d5cf, 3-34 #45635a,#c4d5cf, 35-99 d,#c4d5cf, -|2: 0-1 #000000,#92b09c, 2-2 d,#d2dcda, 3-32 #4b6960,#d2dcda, 33-37 #72547b,#d2dcda, 38-59 #4b6960,#d2dcda, 60-99 d,#d2dcda, -|3: 0-0 d,#9da777, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb, -|4: 0-0 d,#9da777, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb, -|5: 0-0 d,#9da777, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb, -|6: 0-0 d,#9da777, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb, -|7: 0-0 d,#dcdac1, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb, -|8: 0-0 d,#dcdac1, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb, -|9: 0-0 d,#dcdac1, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb, -|10: 0-0 d,#dcdac1, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb, -|11: 0-0 d,#dcdac1, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb, -|12: 0-0 d,#dcdac1, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-13 #293f35,#fffdeb, 14-99 d,#fffdeb, -|13: 0-0 d,#dcdac1, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-13 #293f35,#fffdeb, 14-99 d,#fffdeb, -|14: 0-0 d,#dcdac1, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-13 #293f35,#fffdeb, 14-99 d,#fffdeb, -|15: 0-0 d,#dcdac1, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-13 #293f35,#fffdeb, 14-99 d,#fffdeb, -|16: 0-0 d,#dcdac1, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-13 #293f35,#fffdeb, 14-99 d,#fffdeb, -|17: 0-1 #ffffff,#48876f, 2-2 d,#c4d5cf, 3-32 #45635a,#c4d5cf, 33-39 #6b4e74,#c4d5cf, 40-61 #45635a,#c4d5cf, 62-99 d,#c4d5cf, -|18: 0-0 d,#9da777, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-21 #293f35,#fffdeb, 22-92 d,#fffdeb, 93-93 d,#d2dcda, 94-98 #4b6960,#d2dcda, 99-99 d,#d2dcda, -|19: 0-0 d,#dcdac1, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-19 #293f35,#fffdeb, 20-99 d,#fffdeb, -|20: 0-0 d,#dcdac1, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-16 #293f35,#fffdeb, 17-99 d,#fffdeb, -|21: 0-0 d,#dcdac1, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-15 #293f35,#fffdeb, 16-99 d,#fffdeb, -|22: 0-0 d,#dcdac1, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-17 #293f35,#fffdeb, 18-99 d,#fffdeb, -|23: 0-0 d,#dcdac1, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-20 #293f35,#fffdeb, 21-99 d,#fffdeb, -|24: 0-0 d,#dcdac1, 1-1 d,#fffdeb, 2-6 #889078,#fffdeb,b 7-19 #293f35,#fffdeb, 20-99 d,#fffdeb, -|25: 0-0 d,#dcdac1, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-17 #293f35,#fffdeb, 18-99 d,#fffdeb, -|26: 0-0 d,#dcdac1, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-18 #293f35,#fffdeb, 19-99 d,#fffdeb, -|27: 0-0 d,#dcdac1, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-20 #293f35,#fffdeb, 21-99 d,#fffdeb, -|28: 0-0 d,#dcdac1, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-20 #293f35,#fffdeb, 21-99 d,#fffdeb, -|29: 0-0 d,#dcdac1, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-19 #293f35,#fffdeb, 20-99 d,#fffdeb, -|30: 0-0 d,#dcdac1, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-16 #293f35,#fffdeb, 17-99 d,#fffdeb, +|0: 0-70 #3d6055,#e4f0ed, 71-99 d,#e4f0ed, +|1: 0-1 #000000,#bca481, 2-2 d,#d3e7df, 3-34 #35584d,#d3e7df, 35-99 d,#d3e7df, +|2: 0-1 #000000,#95baa2, 2-2 d,#e4f0ed, 3-32 #3d6055,#e4f0ed, 33-37 #6e4774,#e4f0ed, 38-59 #3d6055,#e4f0ed, 60-99 d,#e4f0ed, +|3: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb, +|4: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb, +|5: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb, +|6: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb, +|7: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb, +|8: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb, +|9: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb, +|10: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb, +|11: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-12 #293f35,#fffdeb, 13-99 d,#fffdeb, +|12: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-13 #293f35,#fffdeb, 14-99 d,#fffdeb, +|13: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-13 #293f35,#fffdeb, 14-99 d,#fffdeb, +|14: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-13 #293f35,#fffdeb, 14-99 d,#fffdeb, +|15: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-13 #293f35,#fffdeb, 14-99 d,#fffdeb, +|16: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-13 #293f35,#fffdeb, 14-99 d,#fffdeb, +|17: 0-1 #ffffff,#36826b, 2-2 d,#d3e7df, 3-32 #35584d,#d3e7df, 33-39 #653f6b,#d3e7df, 40-61 #35584d,#d3e7df, 62-99 d,#d3e7df, +|18: 0-0 d,#9fae76, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-21 #293f35,#fffdeb, 22-92 d,#fffdeb, 93-93 d,#e4f0ed, 94-98 #3d6055,#e4f0ed, 99-99 d,#e4f0ed, +|19: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-19 #293f35,#fffdeb, 20-99 d,#fffdeb, +|20: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-16 #293f35,#fffdeb, 17-99 d,#fffdeb, +|21: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-15 #293f35,#fffdeb, 16-99 d,#fffdeb, +|22: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-17 #293f35,#fffdeb, 18-99 d,#fffdeb, +|23: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-20 #293f35,#fffdeb, 21-99 d,#fffdeb, +|24: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #889078,#fffdeb,b 7-19 #293f35,#fffdeb, 20-99 d,#fffdeb, +|25: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-17 #293f35,#fffdeb, 18-99 d,#fffdeb, +|26: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-18 #293f35,#fffdeb, 19-99 d,#fffdeb, +|27: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-20 #293f35,#fffdeb, 21-99 d,#fffdeb, +|28: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-20 #293f35,#fffdeb, 21-99 d,#fffdeb, +|29: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-19 #293f35,#fffdeb, 20-99 d,#fffdeb, +|30: 0-0 d,#eeeccf, 1-1 d,#fffdeb, 2-6 #909880,#fffdeb, 7-16 #293f35,#fffdeb, 17-99 d,#fffdeb, == snap step-forge grid=100x31 cursor=7,25 == style step-forge grid=100x31 -|0: 0-70 #b7bfc6,#35393e, 71-99 d,#35393e, -|1: 0-1 #ffffff,#727f6a, 2-2 d,#3e4650, 3-34 #c1c9d0,#3e4650, 35-99 d,#3e4650, -|2: 0-1 #ffffff,#5b6d7f, 2-2 d,#35393e, 3-32 #b7bfc6,#35393e, 33-37 #dfb397,#35393e, 38-59 #b7bfc6,#35393e, 60-99 d,#35393e, -|3: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e, -|4: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e, -|5: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e, -|6: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e, -|7: 0-0 d,#2f3132, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e, -|8: 0-0 d,#2f3132, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e, -|9: 0-0 d,#2f3132, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e, -|10: 0-0 d,#2f3132, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e, -|11: 0-0 d,#2f3132, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e, -|12: 0-0 d,#2f3132, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-13 #e5e5e5,#0c0c0e, 14-99 d,#0c0c0e, -|13: 0-0 d,#2f3132, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-13 #e5e5e5,#0c0c0e, 14-99 d,#0c0c0e, -|14: 0-0 d,#2f3132, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-13 #e5e5e5,#0c0c0e, 14-99 d,#0c0c0e, -|15: 0-0 d,#2f3132, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-13 #e5e5e5,#0c0c0e, 14-99 d,#0c0c0e, -|16: 0-0 d,#2f3132, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-13 #e5e5e5,#0c0c0e, 14-99 d,#0c0c0e, -|17: 0-1 #000000,#92bde9, 2-2 d,#3e4650, 3-32 #c1c9d0,#3e4650, 33-39 #e9bda1,#3e4650, 40-61 #c1c9d0,#3e4650, 62-99 d,#3e4650, -|18: 0-0 d,#758592, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-21 #e5e5e5,#0c0c0e, 22-92 d,#0c0c0e, 93-93 d,#35393e, 94-98 #b7bfc6,#35393e, 99-99 d,#35393e, -|19: 0-0 d,#2f3132, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-19 #e5e5e5,#0c0c0e, 20-99 d,#0c0c0e, -|20: 0-0 d,#2f3132, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-16 #e5e5e5,#0c0c0e, 17-99 d,#0c0c0e, -|21: 0-0 d,#2f3132, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-15 #e5e5e5,#0c0c0e, 16-99 d,#0c0c0e, -|22: 0-0 d,#2f3132, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-17 #e5e5e5,#0c0c0e, 18-99 d,#0c0c0e, -|23: 0-0 d,#2f3132, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-20 #e5e5e5,#0c0c0e, 21-99 d,#0c0c0e, -|24: 0-0 d,#2f3132, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-19 #e5e5e5,#0c0c0e, 20-99 d,#0c0c0e, -|25: 0-0 d,#2f3132, 1-1 d,#0c0c0e, 2-6 #6a6d74,#0c0c0e,b 7-17 #e5e5e5,#0c0c0e, 18-99 d,#0c0c0e, -|26: 0-0 d,#2f3132, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-18 #e5e5e5,#0c0c0e, 19-99 d,#0c0c0e, -|27: 0-0 d,#2f3132, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-20 #e5e5e5,#0c0c0e, 21-99 d,#0c0c0e, -|28: 0-0 d,#2f3132, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-20 #e5e5e5,#0c0c0e, 21-99 d,#0c0c0e, -|29: 0-0 d,#2f3132, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-19 #e5e5e5,#0c0c0e, 20-99 d,#0c0c0e, -|30: 0-0 d,#2f3132, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-16 #e5e5e5,#0c0c0e, 17-99 d,#0c0c0e, +|0: 0-70 #c5c9d2,#22252b, 71-99 d,#22252b, +|1: 0-1 #ffffff,#6a7b67, 2-2 d,#2d3440, 3-34 #d1d5de,#2d3440, 35-99 d,#2d3440, +|2: 0-1 #ffffff,#55647b, 2-2 d,#22252b, 3-32 #c5c9d2,#22252b, 33-37 #ecbf9b,#22252b, 38-59 #c5c9d2,#22252b, 60-99 d,#22252b, +|3: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e, +|4: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e, +|5: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e, +|6: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e, +|7: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e, +|8: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e, +|9: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e, +|10: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e, +|11: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-12 #e5e5e5,#0c0c0e, 13-99 d,#0c0c0e, +|12: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-13 #e5e5e5,#0c0c0e, 14-99 d,#0c0c0e, +|13: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-13 #e5e5e5,#0c0c0e, 14-99 d,#0c0c0e, +|14: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-13 #e5e5e5,#0c0c0e, 14-99 d,#0c0c0e, +|15: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-13 #e5e5e5,#0c0c0e, 14-99 d,#0c0c0e, +|16: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-13 #e5e5e5,#0c0c0e, 14-99 d,#0c0c0e, +|17: 0-1 #000000,#9cc3f7, 2-2 d,#2d3440, 3-32 #d1d5de,#2d3440, 33-39 #f8cba7,#2d3440, 40-61 #d1d5de,#2d3440, 62-99 d,#2d3440, +|18: 0-0 d,#708095, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-21 #e5e5e5,#0c0c0e, 22-92 d,#0c0c0e, 93-93 d,#22252b, 94-98 #c5c9d2,#22252b, 99-99 d,#22252b, +|19: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-19 #e5e5e5,#0c0c0e, 20-99 d,#0c0c0e, +|20: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-16 #e5e5e5,#0c0c0e, 17-99 d,#0c0c0e, +|21: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-15 #e5e5e5,#0c0c0e, 16-99 d,#0c0c0e, +|22: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-17 #e5e5e5,#0c0c0e, 18-99 d,#0c0c0e, +|23: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-20 #e5e5e5,#0c0c0e, 21-99 d,#0c0c0e, +|24: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-19 #e5e5e5,#0c0c0e, 20-99 d,#0c0c0e, +|25: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #6a6d74,#0c0c0e,b 7-17 #e5e5e5,#0c0c0e, 18-99 d,#0c0c0e, +|26: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-18 #e5e5e5,#0c0c0e, 19-99 d,#0c0c0e, +|27: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-20 #e5e5e5,#0c0c0e, 21-99 d,#0c0c0e, +|28: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-20 #e5e5e5,#0c0c0e, 21-99 d,#0c0c0e, +|29: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-19 #e5e5e5,#0c0c0e, 20-99 d,#0c0c0e, +|30: 0-0 d,#1a1c21, 1-1 d,#0c0c0e, 2-6 #62656c,#0c0c0e, 7-16 #e5e5e5,#0c0c0e, 17-99 d,#0c0c0e, == snap step-lagoon grid=100x31 cursor=7,26 == style step-lagoon grid=100x31 -|0: 0-70 #bcd6cc,#28413d, 71-99 d,#28413d, -|1: 0-1 #ffffff,#957763, 2-2 d,#33544c, 3-34 #c8e2d8,#33544c, 35-99 d,#33544c, -|2: 0-1 #ffffff,#548073, 2-2 d,#28413d, 3-32 #bcd6cc,#28413d, 33-37 #e5c2e4,#28413d, 38-59 #bcd6cc,#28413d, 60-99 d,#28413d, -|3: 0-0 d,#6e988c, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c, -|4: 0-0 d,#6e988c, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c, -|5: 0-0 d,#6e988c, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c, -|6: 0-0 d,#6e988c, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c, -|7: 0-0 d,#37474b, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c, -|8: 0-0 d,#37474b, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c, -|9: 0-0 d,#37474b, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c, -|10: 0-0 d,#37474b, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c, -|11: 0-0 d,#37474b, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c, -|12: 0-0 d,#37474b, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-13 #bac9ce,#34464c, 14-99 d,#34464c, -|13: 0-0 d,#37474b, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-13 #bac9ce,#34464c, 14-99 d,#34464c, -|14: 0-0 d,#37474b, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-13 #bac9ce,#34464c, 14-99 d,#34464c, -|15: 0-0 d,#37474b, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-13 #bac9ce,#34464c, 14-99 d,#34464c, -|16: 0-0 d,#37474b, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-13 #bac9ce,#34464c, 14-99 d,#34464c, -|17: 0-1 #000000,#84cebd, 2-2 d,#33544c, 3-32 #c8e2d8,#33544c, 33-39 #f1cef0,#33544c, 40-61 #c8e2d8,#33544c, 62-99 d,#33544c, -|18: 0-0 d,#6e988c, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-21 #bac9ce,#34464c, 22-92 d,#34464c, 93-93 d,#28413d, 94-98 #bcd6cc,#28413d, 99-99 d,#28413d, -|19: 0-0 d,#37474b, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-19 #bac9ce,#34464c, 20-99 d,#34464c, -|20: 0-0 d,#37474b, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-16 #bac9ce,#34464c, 17-99 d,#34464c, -|21: 0-0 d,#37474b, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-15 #bac9ce,#34464c, 16-99 d,#34464c, -|22: 0-0 d,#37474b, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-17 #bac9ce,#34464c, 18-99 d,#34464c, -|23: 0-0 d,#37474b, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-20 #bac9ce,#34464c, 21-99 d,#34464c, -|24: 0-0 d,#37474b, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-19 #bac9ce,#34464c, 20-99 d,#34464c, -|25: 0-0 d,#37474b, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-17 #bac9ce,#34464c, 18-99 d,#34464c, -|26: 0-0 d,#37474b, 1-1 d,#34464c, 2-6 #83999c,#34464c,b 7-18 #bac9ce,#34464c, 19-99 d,#34464c, -|27: 0-0 d,#37474b, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-20 #bac9ce,#34464c, 21-99 d,#34464c, -|28: 0-0 d,#37474b, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-20 #bac9ce,#34464c, 21-99 d,#34464c, -|29: 0-0 d,#37474b, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-19 #bac9ce,#34464c, 20-99 d,#34464c, -|30: 0-0 d,#37474b, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-16 #bac9ce,#34464c, 17-99 d,#34464c, +|0: 0-70 #bbd7cb,#29443f, 71-99 d,#29443f, +|1: 0-1 #ffffff,#9a7662, 2-2 d,#34574d, 3-34 #c7e3d7,#34574d, 35-99 d,#34574d, +|2: 0-1 #ffffff,#548372, 2-2 d,#29443f, 3-32 #bbd7cb,#29443f, 33-37 #e4c2ec,#29443f, 38-59 #bbd7cb,#29443f, 60-99 d,#29443f, +|3: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c, +|4: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c, +|5: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c, +|6: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c, +|7: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c, +|8: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c, +|9: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c, +|10: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c, +|11: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-12 #bac9ce,#34464c, 13-99 d,#34464c, +|12: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-13 #bac9ce,#34464c, 14-99 d,#34464c, +|13: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-13 #bac9ce,#34464c, 14-99 d,#34464c, +|14: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-13 #bac9ce,#34464c, 14-99 d,#34464c, +|15: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-13 #bac9ce,#34464c, 14-99 d,#34464c, +|16: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-13 #bac9ce,#34464c, 14-99 d,#34464c, +|17: 0-1 #000000,#81cfb7, 2-2 d,#34574d, 3-32 #c7e3d7,#34574d, 33-39 #f0cef8,#34574d, 40-61 #c7e3d7,#34574d, 62-99 d,#34574d, +|18: 0-0 d,#6e9b8b, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-21 #bac9ce,#34464c, 22-92 d,#34464c, 93-93 d,#29443f, 94-98 #bbd7cb,#29443f, 99-99 d,#29443f, +|19: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-19 #bac9ce,#34464c, 20-99 d,#34464c, +|20: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-16 #bac9ce,#34464c, 17-99 d,#34464c, +|21: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-15 #bac9ce,#34464c, 16-99 d,#34464c, +|22: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-17 #bac9ce,#34464c, 18-99 d,#34464c, +|23: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-20 #bac9ce,#34464c, 21-99 d,#34464c, +|24: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-19 #bac9ce,#34464c, 20-99 d,#34464c, +|25: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-17 #bac9ce,#34464c, 18-99 d,#34464c, +|26: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #83999c,#34464c,b 7-18 #bac9ce,#34464c, 19-99 d,#34464c, +|27: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-20 #bac9ce,#34464c, 21-99 d,#34464c, +|28: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-20 #bac9ce,#34464c, 21-99 d,#34464c, +|29: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-19 #bac9ce,#34464c, 20-99 d,#34464c, +|30: 0-0 d,#3a4c50, 1-1 d,#34464c, 2-6 #7b9194,#34464c, 7-16 #bac9ce,#34464c, 17-99 d,#34464c, == snap step-solarium grid=100x31 cursor=7,27 == style step-solarium grid=100x31 -|0: 0-70 #c6d4be,#144043, 71-99 d,#144043, -|1: 0-1 #ffffff,#3e7a94, 2-2 d,#234f50, 3-34 #d2e0ca,#234f50, 35-99 d,#234f50, -|2: 0-1 #ffffff,#477f76, 2-2 d,#144043, 3-32 #c6d4be,#144043, 33-37 #e9c1e1,#144043, 38-59 #c6d4be,#144043, 60-99 d,#144043, -|3: 0-0 d,#66978c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45, -|4: 0-0 d,#66978c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45, -|5: 0-0 d,#66978c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45, -|6: 0-0 d,#66978c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45, -|7: 0-0 d,#1f464c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45, -|8: 0-0 d,#1f464c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45, -|9: 0-0 d,#1f464c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45, -|10: 0-0 d,#1f464c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45, -|11: 0-0 d,#1f464c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45, -|12: 0-0 d,#1f464c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-13 #a7b7ae,#173e45, 14-99 d,#173e45, -|13: 0-0 d,#1f464c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-13 #a7b7ae,#173e45, 14-99 d,#173e45, -|14: 0-0 d,#1f464c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-13 #a7b7ae,#173e45, 14-99 d,#173e45, -|15: 0-0 d,#1f464c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-13 #a7b7ae,#173e45, 14-99 d,#173e45, -|16: 0-0 d,#1f464c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-13 #a7b7ae,#173e45, 14-99 d,#173e45, -|17: 0-1 #000000,#d7c36e, 2-2 d,#234f50, 3-32 #d2e0ca,#234f50, 33-39 #f5cded,#234f50, 40-61 #d2e0ca,#234f50, 62-99 d,#234f50, -|18: 0-0 d,#66978c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-21 #a7b7ae,#173e45, 22-92 d,#173e45, 93-93 d,#144043, 94-98 #c6d4be,#144043, 99-99 d,#144043, -|19: 0-0 d,#1f464c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-19 #a7b7ae,#173e45, 20-99 d,#173e45, -|20: 0-0 d,#1f464c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-16 #a7b7ae,#173e45, 17-99 d,#173e45, -|21: 0-0 d,#1f464c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-15 #a7b7ae,#173e45, 16-99 d,#173e45, -|22: 0-0 d,#1f464c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-17 #a7b7ae,#173e45, 18-99 d,#173e45, -|23: 0-0 d,#1f464c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-20 #a7b7ae,#173e45, 21-99 d,#173e45, -|24: 0-0 d,#1f464c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-19 #a7b7ae,#173e45, 20-99 d,#173e45, -|25: 0-0 d,#1f464c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-17 #a7b7ae,#173e45, 18-99 d,#173e45, -|26: 0-0 d,#1f464c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-18 #a7b7ae,#173e45, 19-99 d,#173e45, -|27: 0-0 d,#1f464c, 1-1 d,#173e45, 2-6 #6c8684,#173e45,b 7-20 #a7b7ae,#173e45, 21-99 d,#173e45, -|28: 0-0 d,#1f464c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-20 #a7b7ae,#173e45, 21-99 d,#173e45, -|29: 0-0 d,#1f464c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-19 #a7b7ae,#173e45, 20-99 d,#173e45, -|30: 0-0 d,#1f464c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-16 #a7b7ae,#173e45, 17-99 d,#173e45, +|0: 0-70 #c7d4bd,#123f43, 71-99 d,#123f43, +|1: 0-1 #ffffff,#347a9a, 2-2 d,#214e50, 3-34 #d3e0c9,#214e50, 35-99 d,#214e50, +|2: 0-1 #ffffff,#467f76, 2-2 d,#123f43, 3-32 #c7d4bd,#123f43, 33-37 #e9c1e0,#123f43, 38-59 #c7d4bd,#123f43, 60-99 d,#123f43, +|3: 0-0 d,#65978c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45, +|4: 0-0 d,#65978c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45, +|5: 0-0 d,#65978c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45, +|6: 0-0 d,#65978c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45, +|7: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45, +|8: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45, +|9: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45, +|10: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45, +|11: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-12 #a7b7ae,#173e45, 13-99 d,#173e45, +|12: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-13 #a7b7ae,#173e45, 14-99 d,#173e45, +|13: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-13 #a7b7ae,#173e45, 14-99 d,#173e45, +|14: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-13 #a7b7ae,#173e45, 14-99 d,#173e45, +|15: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-13 #a7b7ae,#173e45, 14-99 d,#173e45, +|16: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-13 #a7b7ae,#173e45, 14-99 d,#173e45, +|17: 0-1 #000000,#e1c266, 2-2 d,#214e50, 3-32 #d3e0c9,#214e50, 33-39 #f5cdec,#214e50, 40-61 #d3e0c9,#214e50, 62-99 d,#214e50, +|18: 0-0 d,#65978c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-21 #a7b7ae,#173e45, 22-92 d,#173e45, 93-93 d,#123f43, 94-98 #c7d4bd,#123f43, 99-99 d,#123f43, +|19: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-19 #a7b7ae,#173e45, 20-99 d,#173e45, +|20: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-16 #a7b7ae,#173e45, 17-99 d,#173e45, +|21: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-15 #a7b7ae,#173e45, 16-99 d,#173e45, +|22: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-17 #a7b7ae,#173e45, 18-99 d,#173e45, +|23: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-20 #a7b7ae,#173e45, 21-99 d,#173e45, +|24: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-19 #a7b7ae,#173e45, 20-99 d,#173e45, +|25: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-17 #a7b7ae,#173e45, 18-99 d,#173e45, +|26: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-18 #a7b7ae,#173e45, 19-99 d,#173e45, +|27: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #6c8684,#173e45,b 7-20 #a7b7ae,#173e45, 21-99 d,#173e45, +|28: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-20 #a7b7ae,#173e45, 21-99 d,#173e45, +|29: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-19 #a7b7ae,#173e45, 20-99 d,#173e45, +|30: 0-0 d,#1c454c, 1-1 d,#173e45, 2-6 #647e7c,#173e45, 7-16 #a7b7ae,#173e45, 17-99 d,#173e45, == snap step-spectrum grid=100x31 cursor=7,27 |18: 2 Theme orchard Theme |19: 3 Theme dusk @@ -261,37 +261,37 @@ |29: 13 Theme clay |30: 14 Theme forge_black == style step-spectrum grid=100x31 -|0: 0-70 #dbd8bb,#373932, 71-99 d,#373932, -|1: 0-1 #ffffff,#6a6796, 2-2 d,#494839, 3-34 #e7e4c7,#494839, 35-99 d,#494839, -|2: 0-1 #ffffff,#8a8453, 2-2 d,#373932, 3-32 #dbd8bb,#373932, 33-37 #c9d5fc,#373932, 38-59 #dbd8bb,#373932, 60-99 d,#373932, -|3: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11, -|4: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11, -|5: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11, -|6: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11, -|7: 0-0 d,#212127, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11, -|8: 0-0 d,#212127, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11, -|9: 0-0 d,#212127, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11, -|10: 0-0 d,#212127, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11, -|11: 0-0 d,#212127, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11, -|12: 0-0 d,#212127, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-13 #fcfcfa,#100e11, 14-99 d,#100e11, -|13: 0-0 d,#212127, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-13 #fcfcfa,#100e11, 14-99 d,#100e11, -|14: 0-0 d,#212127, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-13 #fcfcfa,#100e11, 14-99 d,#100e11, -|15: 0-0 d,#212127, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-13 #fcfcfa,#100e11, 14-99 d,#100e11, -|16: 0-0 d,#212127, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-13 #fcfcfa,#100e11, 14-99 d,#100e11, -|17: 0-1 #000000,#fcd666, 2-2 d,#494839, 3-32 #e7e4c7,#494839, 33-39 #dae1fd,#494839, 40-61 #e7e4c7,#494839, 62-99 d,#494839, -|18: 0-0 d,#8f8e72, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-19 #fcfcfa,#100e11, 20-92 d,#100e11, 93-93 d,#373932, 94-98 #dbd8bb,#373932, 99-99 d,#373932, -|19: 0-0 d,#212127, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-16 #fcfcfa,#100e11, 17-99 d,#100e11, -|20: 0-0 d,#212127, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-15 #fcfcfa,#100e11, 16-99 d,#100e11, -|21: 0-0 d,#212127, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-17 #fcfcfa,#100e11, 18-99 d,#100e11, -|22: 0-0 d,#212127, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-20 #fcfcfa,#100e11, 21-99 d,#100e11, -|23: 0-0 d,#212127, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-19 #fcfcfa,#100e11, 20-99 d,#100e11, -|24: 0-0 d,#212127, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-17 #fcfcfa,#100e11, 18-99 d,#100e11, -|25: 0-0 d,#212127, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-18 #fcfcfa,#100e11, 19-99 d,#100e11, -|26: 0-0 d,#212127, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-20 #fcfcfa,#100e11, 21-99 d,#100e11, -|27: 0-0 d,#212127, 1-1 d,#100e11, 2-6 #706973,#100e11,b 7-20 #fcfcfa,#100e11, 21-99 d,#100e11, -|28: 0-0 d,#212127, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-19 #fcfcfa,#100e11, 20-99 d,#100e11, -|29: 0-0 d,#212127, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-16 #fcfcfa,#100e11, 17-99 d,#100e11, -|30: 0-0 d,#212127, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-23 #fcfcfa,#100e11, 24-99 d,#100e11, +|0: 0-70 #ddd8bb,#3b3830, 71-99 d,#3b3830, +|1: 0-1 #ffffff,#706596, 2-2 d,#4d4736, 3-34 #e9e4c7,#4d4736, 35-99 d,#4d4736, +|2: 0-1 #ffffff,#92844f, 2-2 d,#3b3830, 3-32 #ddd8bb,#3b3830, 33-37 #c5d7ff,#3b3830, 38-59 #ddd8bb,#3b3830, 60-99 d,#3b3830, +|3: 0-0 d,#948d6f, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11, +|4: 0-0 d,#948d6f, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11, +|5: 0-0 d,#948d6f, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11, +|6: 0-0 d,#948d6f, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11, +|7: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11, +|8: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11, +|9: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11, +|10: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11, +|11: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-12 #fcfcfa,#100e11, 13-99 d,#100e11, +|12: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-13 #fcfcfa,#100e11, 14-99 d,#100e11, +|13: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-13 #fcfcfa,#100e11, 14-99 d,#100e11, +|14: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-13 #fcfcfa,#100e11, 14-99 d,#100e11, +|15: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-13 #fcfcfa,#100e11, 14-99 d,#100e11, +|16: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-13 #fcfcfa,#100e11, 14-99 d,#100e11, +|17: 0-1 #000000,#ffd866, 2-2 d,#4d4736, 3-32 #e9e4c7,#4d4736, 33-39 #d7e3ff,#4d4736, 40-61 #e9e4c7,#4d4736, 62-99 d,#4d4736, +|18: 0-0 d,#948d6f, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-19 #fcfcfa,#100e11, 20-92 d,#100e11, 93-93 d,#3b3830, 94-98 #ddd8bb,#3b3830, 99-99 d,#3b3830, +|19: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-16 #fcfcfa,#100e11, 17-99 d,#100e11, +|20: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-15 #fcfcfa,#100e11, 16-99 d,#100e11, +|21: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-17 #fcfcfa,#100e11, 18-99 d,#100e11, +|22: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-20 #fcfcfa,#100e11, 21-99 d,#100e11, +|23: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-19 #fcfcfa,#100e11, 20-99 d,#100e11, +|24: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-17 #fcfcfa,#100e11, 18-99 d,#100e11, +|25: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-18 #fcfcfa,#100e11, 19-99 d,#100e11, +|26: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-20 #fcfcfa,#100e11, 21-99 d,#100e11, +|27: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #706973,#100e11,b 7-20 #fcfcfa,#100e11, 21-99 d,#100e11, +|28: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-19 #fcfcfa,#100e11, 20-99 d,#100e11, +|29: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-16 #fcfcfa,#100e11, 17-99 d,#100e11, +|30: 0-0 d,#211d23, 1-1 d,#100e11, 2-6 #68616b,#100e11, 7-23 #fcfcfa,#100e11, 24-99 d,#100e11, == snap step-harvest grid=100x31 cursor=7,27 |18: 3 Theme dusk Theme |19: 4 Theme ink @@ -307,37 +307,37 @@ |29: 14 Theme forge_black |30: 15 Theme forge_soft == style step-harvest grid=100x31 -|0: 0-70 #d6d8b8,#353b2e, 71-99 d,#353b2e, -|1: 0-1 #ffffff,#975948, 2-2 d,#434c38, 3-34 #e2e4c4,#434c38, 35-99 d,#434c38, -|2: 0-1 #ffffff,#7d7f4e, 2-2 d,#353b2e, 3-32 #d6d8b8,#353b2e, 33-37 #bbdbed,#353b2e, 38-59 #d6d8b8,#353b2e, 60-99 d,#353b2e, -|3: 0-0 d,#898e60, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b, -|4: 0-0 d,#898e60, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b, -|5: 0-0 d,#898e60, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b, -|6: 0-0 d,#898e60, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b, -|7: 0-0 d,#201d18, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b, -|8: 0-0 d,#201d18, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b, -|9: 0-0 d,#201d18, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b, -|10: 0-0 d,#201d18, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b, -|11: 0-0 d,#201d18, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b, -|12: 0-0 d,#201d18, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-13 #f3f2cc,#100e0b, 14-99 d,#100e0b, -|13: 0-0 d,#201d18, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-13 #f3f2cc,#100e0b, 14-99 d,#100e0b, -|14: 0-0 d,#201d18, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-13 #f3f2cc,#100e0b, 14-99 d,#100e0b, -|15: 0-0 d,#201d18, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-13 #f3f2cc,#100e0b, 14-99 d,#100e0b, -|16: 0-0 d,#201d18, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-13 #f3f2cc,#100e0b, 14-99 d,#100e0b, -|17: 0-1 #000000,#dcc080, 2-2 d,#434c38, 3-32 #e2e4c4,#434c38, 33-39 #c7e7f8,#434c38, 40-61 #e2e4c4,#434c38, 62-99 d,#434c38, -|18: 0-0 d,#898e60, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-16 #f3f2cc,#100e0b, 17-92 d,#100e0b, 93-93 d,#353b2e, 94-98 #d6d8b8,#353b2e, 99-99 d,#353b2e, -|19: 0-0 d,#201d18, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-15 #f3f2cc,#100e0b, 16-99 d,#100e0b, -|20: 0-0 d,#201d18, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-17 #f3f2cc,#100e0b, 18-99 d,#100e0b, -|21: 0-0 d,#201d18, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-20 #f3f2cc,#100e0b, 21-99 d,#100e0b, -|22: 0-0 d,#201d18, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-19 #f3f2cc,#100e0b, 20-99 d,#100e0b, -|23: 0-0 d,#201d18, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-17 #f3f2cc,#100e0b, 18-99 d,#100e0b, -|24: 0-0 d,#201d18, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-18 #f3f2cc,#100e0b, 19-99 d,#100e0b, -|25: 0-0 d,#201d18, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-20 #f3f2cc,#100e0b, 21-99 d,#100e0b, -|26: 0-0 d,#201d18, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-20 #f3f2cc,#100e0b, 21-99 d,#100e0b, -|27: 0-0 d,#201d18, 1-1 d,#100e0b, 2-6 #726c5e,#100e0b,b 7-19 #f3f2cc,#100e0b, 20-99 d,#100e0b, -|28: 0-0 d,#201d18, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-16 #f3f2cc,#100e0b, 17-99 d,#100e0b, -|29: 0-0 d,#201d18, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-23 #f3f2cc,#100e0b, 24-99 d,#100e0b, -|30: 0-0 d,#201d18, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-22 #f3f2cc,#100e0b, 23-99 d,#100e0b, +|0: 0-70 #d5d8b8,#343b2e, 71-99 d,#343b2e, +|1: 0-1 #ffffff,#9b583f, 2-2 d,#424d38, 3-34 #e1e4c4,#424d38, 35-99 d,#424d38, +|2: 0-1 #ffffff,#7b7e4e, 2-2 d,#343b2e, 3-32 #d5d8b8,#343b2e, 33-37 #badbeb,#343b2e, 38-59 #d5d8b8,#343b2e, 60-99 d,#343b2e, +|3: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b, +|4: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b, +|5: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b, +|6: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b, +|7: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b, +|8: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b, +|9: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b, +|10: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b, +|11: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-12 #f3f2cc,#100e0b, 13-99 d,#100e0b, +|12: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-13 #f3f2cc,#100e0b, 14-99 d,#100e0b, +|13: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-13 #f3f2cc,#100e0b, 14-99 d,#100e0b, +|14: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-13 #f3f2cc,#100e0b, 14-99 d,#100e0b, +|15: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-13 #f3f2cc,#100e0b, 14-99 d,#100e0b, +|16: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-13 #f3f2cc,#100e0b, 14-99 d,#100e0b, +|17: 0-1 #000000,#d8bd83, 2-2 d,#424d38, 3-32 #e1e4c4,#424d38, 33-39 #c5e7f7,#424d38, 40-61 #e1e4c4,#424d38, 62-99 d,#424d38, +|18: 0-0 d,#888e5e, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-16 #f3f2cc,#100e0b, 17-92 d,#100e0b, 93-93 d,#343b2e, 94-98 #d5d8b8,#343b2e, 99-99 d,#343b2e, +|19: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-15 #f3f2cc,#100e0b, 16-99 d,#100e0b, +|20: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-17 #f3f2cc,#100e0b, 18-99 d,#100e0b, +|21: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-20 #f3f2cc,#100e0b, 21-99 d,#100e0b, +|22: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-19 #f3f2cc,#100e0b, 20-99 d,#100e0b, +|23: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-17 #f3f2cc,#100e0b, 18-99 d,#100e0b, +|24: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-18 #f3f2cc,#100e0b, 19-99 d,#100e0b, +|25: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-20 #f3f2cc,#100e0b, 21-99 d,#100e0b, +|26: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-20 #f3f2cc,#100e0b, 21-99 d,#100e0b, +|27: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #726c5e,#100e0b,b 7-19 #f3f2cc,#100e0b, 20-99 d,#100e0b, +|28: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-16 #f3f2cc,#100e0b, 17-99 d,#100e0b, +|29: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-23 #f3f2cc,#100e0b, 24-99 d,#100e0b, +|30: 0-0 d,#201d17, 1-1 d,#100e0b, 2-6 #6a6456,#100e0b, 7-22 #f3f2cc,#100e0b, 23-99 d,#100e0b, == snap step-clay grid=100x31 cursor=7,27 |18: 4 Theme ink Theme |19: 5 Theme paper @@ -353,13 +353,13 @@ |29: 15 Theme forge_soft |30: 16 Theme orchard_black == style step-clay grid=100x31 -|0: 0-70 #d7d6b6,#343f35, 71-99 d,#343f35, -|1: 0-1 #ffffff,#895d61, 2-2 d,#424f3f, 3-34 #e3e2c2,#424f3f, 35-99 d,#424f3f, -|2: 0-1 #ffffff,#6a7c4d, 2-2 d,#343f35, 3-32 #d7d6b6,#343f35, 33-37 #ace0e1,#343f35, 38-59 #d7d6b6,#343f35, 60-99 d,#343f35, -|3: 0-0 d,#8c9366, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-12 #f3e5bc,#10100e, 13-99 d,#10100e, -|4: 0-0 d,#8c9366, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-12 #f3e5bc,#10100e, 13-99 d,#10100e, -|5: 0-0 d,#8c9366, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-12 #f3e5bc,#10100e, 13-99 d,#10100e, -|6: 0-0 d,#8c9366, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-12 #f3e5bc,#10100e, 13-99 d,#10100e, +|0: 0-70 #d7d6b6,#343f36, 71-99 d,#343f36, +|1: 0-1 #ffffff,#875e65, 2-2 d,#424f40, 3-34 #e3e2c2,#424f40, 35-99 d,#424f40, +|2: 0-1 #ffffff,#687c4d, 2-2 d,#343f36, 3-32 #d7d6b6,#343f36, 33-37 #aae0e0,#343f36, 38-59 #d7d6b6,#343f36, 60-99 d,#343f36, +|3: 0-0 d,#8c9467, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-12 #f3e5bc,#10100e, 13-99 d,#10100e, +|4: 0-0 d,#8c9467, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-12 #f3e5bc,#10100e, 13-99 d,#10100e, +|5: 0-0 d,#8c9467, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-12 #f3e5bc,#10100e, 13-99 d,#10100e, +|6: 0-0 d,#8c9467, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-12 #f3e5bc,#10100e, 13-99 d,#10100e, |7: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-12 #f3e5bc,#10100e, 13-99 d,#10100e, |8: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-12 #f3e5bc,#10100e, 13-99 d,#10100e, |9: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-12 #f3e5bc,#10100e, 13-99 d,#10100e, @@ -370,8 +370,8 @@ |14: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-13 #f3e5bc,#10100e, 14-99 d,#10100e, |15: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-13 #f3e5bc,#10100e, 14-99 d,#10100e, |16: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-13 #f3e5bc,#10100e, 14-99 d,#10100e, -|17: 0-1 #000000,#92c776, 2-2 d,#424f3f, 3-32 #e3e2c2,#424f3f, 33-39 #b7eced,#424f3f, 40-61 #e3e2c2,#424f3f, 62-99 d,#424f3f, -|18: 0-0 d,#8c9366, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-15 #f3e5bc,#10100e, 16-92 d,#10100e, 93-93 d,#343f35, 94-98 #d7d6b6,#343f35, 99-99 d,#343f35, +|17: 0-1 #000000,#8ac874, 2-2 d,#424f40, 3-32 #e3e2c2,#424f40, 33-39 #b5ecec,#424f40, 40-61 #e3e2c2,#424f40, 62-99 d,#424f40, +|18: 0-0 d,#8c9467, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-15 #f3e5bc,#10100e, 16-92 d,#10100e, 93-93 d,#343f36, 94-98 #d7d6b6,#343f36, 99-99 d,#343f36, |19: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-17 #f3e5bc,#10100e, 18-99 d,#10100e, |20: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-20 #f3e5bc,#10100e, 21-99 d,#10100e, |21: 0-0 d,#222119, 1-1 d,#10100e, 2-6 #696455,#10100e, 7-19 #f3e5bc,#10100e, 20-99 d,#10100e, @@ -399,37 +399,37 @@ |29: 16 Theme orchard_black |30: 17 == style step-forge-black grid=100x31 -|0: 0-70 #c7cacf,#24282c, 71-99 d,#24282c, -|1: 0-1 #ffffff,#6d7867, 2-2 d,#2f3740, 3-34 #d3d6db,#2f3740, 35-99 d,#2f3740, -|2: 0-1 #ffffff,#576676, 2-2 d,#24282c, 3-32 #c7cacf,#24282c, 33-37 #e5c2a2,#24282c, 38-59 #c7cacf,#24282c, 60-99 d,#24282c, -|3: 0-0 d,#738290, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000, -|4: 0-0 d,#738290, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000, -|5: 0-0 d,#738290, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000, -|6: 0-0 d,#738290, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000, -|7: 0-0 d,#15171a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000, -|8: 0-0 d,#15171a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000, -|9: 0-0 d,#15171a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000, -|10: 0-0 d,#15171a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000, -|11: 0-0 d,#15171a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000, -|12: 0-0 d,#15171a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-13 #f6f6f6,#000000, 14-99 d,#000000, -|13: 0-0 d,#15171a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-13 #f6f6f6,#000000, 14-99 d,#000000, -|14: 0-0 d,#15171a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-13 #f6f6f6,#000000, 14-99 d,#000000, -|15: 0-0 d,#15171a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-13 #f6f6f6,#000000, 14-99 d,#000000, -|16: 0-0 d,#15171a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-13 #f6f6f6,#000000, 14-99 d,#000000, -|17: 0-1 #000000,#9ac4ea, 2-2 d,#2f3740, 3-32 #d3d6db,#2f3740, 33-39 #f1ceae,#2f3740, 40-61 #d3d6db,#2f3740, 62-99 d,#2f3740, -|18: 0-0 d,#738290, 1-1 d,#000000, 2-6 #62656c,#000000, 7-17 #f6f6f6,#000000, 18-92 d,#000000, 93-93 d,#24282c, 94-98 #c7cacf,#24282c, 99-99 d,#24282c, -|19: 0-0 d,#15171a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-20 #f6f6f6,#000000, 21-99 d,#000000, -|20: 0-0 d,#15171a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-19 #f6f6f6,#000000, 20-99 d,#000000, -|21: 0-0 d,#15171a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-17 #f6f6f6,#000000, 18-99 d,#000000, -|22: 0-0 d,#15171a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-18 #f6f6f6,#000000, 19-99 d,#000000, -|23: 0-0 d,#15171a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-20 #f6f6f6,#000000, 21-99 d,#000000, -|24: 0-0 d,#15171a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-20 #f6f6f6,#000000, 21-99 d,#000000, -|25: 0-0 d,#15171a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-19 #f6f6f6,#000000, 20-99 d,#000000, -|26: 0-0 d,#15171a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-16 #f6f6f6,#000000, 17-99 d,#000000, -|27: 0-0 d,#15171a, 1-1 d,#000000, 2-6 #6a6d74,#000000,b 7-23 #f6f6f6,#000000, 24-99 d,#000000, -|28: 0-0 d,#15171a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-22 #f6f6f6,#000000, 23-99 d,#000000, -|29: 0-0 d,#15171a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-25 #f6f6f6,#000000, 26-99 d,#000000, -|30: 0-0 d,#15171a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-99 d,#000000, +|0: 0-70 #c5c9d2,#22252b, 71-99 d,#22252b, +|1: 0-1 #ffffff,#6a7b67, 2-2 d,#2d3440, 3-34 #d1d5de,#2d3440, 35-99 d,#2d3440, +|2: 0-1 #ffffff,#55647b, 2-2 d,#22252b, 3-32 #c5c9d2,#22252b, 33-37 #ecbf9b,#22252b, 38-59 #c5c9d2,#22252b, 60-99 d,#22252b, +|3: 0-0 d,#708095, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000, +|4: 0-0 d,#708095, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000, +|5: 0-0 d,#708095, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000, +|6: 0-0 d,#708095, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000, +|7: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000, +|8: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000, +|9: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000, +|10: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000, +|11: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-12 #f6f6f6,#000000, 13-99 d,#000000, +|12: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-13 #f6f6f6,#000000, 14-99 d,#000000, +|13: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-13 #f6f6f6,#000000, 14-99 d,#000000, +|14: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-13 #f6f6f6,#000000, 14-99 d,#000000, +|15: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-13 #f6f6f6,#000000, 14-99 d,#000000, +|16: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-13 #f6f6f6,#000000, 14-99 d,#000000, +|17: 0-1 #000000,#9cc3f7, 2-2 d,#2d3440, 3-32 #d1d5de,#2d3440, 33-39 #f8cba7,#2d3440, 40-61 #d1d5de,#2d3440, 62-99 d,#2d3440, +|18: 0-0 d,#708095, 1-1 d,#000000, 2-6 #62656c,#000000, 7-17 #f6f6f6,#000000, 18-92 d,#000000, 93-93 d,#22252b, 94-98 #c5c9d2,#22252b, 99-99 d,#22252b, +|19: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-20 #f6f6f6,#000000, 21-99 d,#000000, +|20: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-19 #f6f6f6,#000000, 20-99 d,#000000, +|21: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-17 #f6f6f6,#000000, 18-99 d,#000000, +|22: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-18 #f6f6f6,#000000, 19-99 d,#000000, +|23: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-20 #f6f6f6,#000000, 21-99 d,#000000, +|24: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-20 #f6f6f6,#000000, 21-99 d,#000000, +|25: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-19 #f6f6f6,#000000, 20-99 d,#000000, +|26: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-16 #f6f6f6,#000000, 17-99 d,#000000, +|27: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #6a6d74,#000000,b 7-23 #f6f6f6,#000000, 24-99 d,#000000, +|28: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-22 #f6f6f6,#000000, 23-99 d,#000000, +|29: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-25 #f6f6f6,#000000, 26-99 d,#000000, +|30: 0-0 d,#14161a, 1-1 d,#000000, 2-6 #62656c,#000000, 7-99 d,#000000, == snap step-forge-soft grid=100x31 cursor=7,27 |18: 6 Theme daybreak Theme |19: 7 Theme atelier @@ -445,37 +445,37 @@ |29: 17 |30: 18 # Legacy and imported themes == style step-forge-soft grid=100x31 -|0: 0-70 #c5c9d2,#292c33, 71-99 d,#292c33, -|1: 0-1 #ffffff,#6d7f6c, 2-2 d,#363d48, 3-34 #d1d5de,#363d48, 35-99 d,#363d48, -|2: 0-1 #ffffff,#55647b, 2-2 d,#292c33, 3-32 #c5c9d2,#292c33, 33-37 #ecbf9b,#292c33, 38-59 #c5c9d2,#292c33, 60-99 d,#292c33, +|0: 0-70 #c5c9d2,#2a2d34, 71-99 d,#2a2d34, +|1: 0-1 #ffffff,#6d7f6c, 2-2 d,#373e49, 3-34 #d1d5de,#373e49, 35-99 d,#373e49, +|2: 0-1 #ffffff,#55647b, 2-2 d,#2a2d34, 3-32 #c5c9d2,#2a2d34, 33-37 #ecbf9b,#2a2d34, 38-59 #c5c9d2,#2a2d34, 60-99 d,#2a2d34, |3: 0-0 d,#708095, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-12 #bfc3cc,#35383e, 13-99 d,#35383e, |4: 0-0 d,#708095, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-12 #bfc3cc,#35383e, 13-99 d,#35383e, |5: 0-0 d,#708095, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-12 #bfc3cc,#35383e, 13-99 d,#35383e, |6: 0-0 d,#708095, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-12 #bfc3cc,#35383e, 13-99 d,#35383e, -|7: 0-0 d,#393c43, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-12 #bfc3cc,#35383e, 13-99 d,#35383e, -|8: 0-0 d,#393c43, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-12 #bfc3cc,#35383e, 13-99 d,#35383e, -|9: 0-0 d,#393c43, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-12 #bfc3cc,#35383e, 13-99 d,#35383e, -|10: 0-0 d,#393c43, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-12 #bfc3cc,#35383e, 13-99 d,#35383e, -|11: 0-0 d,#393c43, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-12 #bfc3cc,#35383e, 13-99 d,#35383e, -|12: 0-0 d,#393c43, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-13 #bfc3cc,#35383e, 14-99 d,#35383e, -|13: 0-0 d,#393c43, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-13 #bfc3cc,#35383e, 14-99 d,#35383e, -|14: 0-0 d,#393c43, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-13 #bfc3cc,#35383e, 14-99 d,#35383e, -|15: 0-0 d,#393c43, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-13 #bfc3cc,#35383e, 14-99 d,#35383e, -|16: 0-0 d,#393c43, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-13 #bfc3cc,#35383e, 14-99 d,#35383e, -|17: 0-1 #000000,#9cc3f7, 2-2 d,#363d48, 3-32 #d1d5de,#363d48, 33-39 #f8cba7,#363d48, 40-61 #d1d5de,#363d48, 62-99 d,#363d48, -|18: 0-0 d,#708095, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-20 #bfc3cc,#35383e, 21-92 d,#35383e, 93-93 d,#292c33, 94-98 #c5c9d2,#292c33, 99-99 d,#292c33, -|19: 0-0 d,#393c43, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-19 #bfc3cc,#35383e, 20-99 d,#35383e, -|20: 0-0 d,#393c43, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-17 #bfc3cc,#35383e, 18-99 d,#35383e, -|21: 0-0 d,#393c43, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-18 #bfc3cc,#35383e, 19-99 d,#35383e, -|22: 0-0 d,#393c43, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-20 #bfc3cc,#35383e, 21-99 d,#35383e, -|23: 0-0 d,#393c43, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-20 #bfc3cc,#35383e, 21-99 d,#35383e, -|24: 0-0 d,#393c43, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-19 #bfc3cc,#35383e, 20-99 d,#35383e, -|25: 0-0 d,#393c43, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-16 #bfc3cc,#35383e, 17-99 d,#35383e, -|26: 0-0 d,#393c43, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-23 #bfc3cc,#35383e, 24-99 d,#35383e, -|27: 0-0 d,#393c43, 1-1 d,#35383e, 2-6 #8e9199,#35383e,b 7-22 #bfc3cc,#35383e, 23-99 d,#35383e, -|28: 0-0 d,#393c43, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-25 #bfc3cc,#35383e, 26-99 d,#35383e, -|29: 0-0 d,#393c43, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-99 d,#35383e, -|30: 0-0 d,#393c43, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-34 #bfc3cc,#35383e, 35-99 d,#35383e, +|7: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-12 #bfc3cc,#35383e, 13-99 d,#35383e, +|8: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-12 #bfc3cc,#35383e, 13-99 d,#35383e, +|9: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-12 #bfc3cc,#35383e, 13-99 d,#35383e, +|10: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-12 #bfc3cc,#35383e, 13-99 d,#35383e, +|11: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-12 #bfc3cc,#35383e, 13-99 d,#35383e, +|12: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-13 #bfc3cc,#35383e, 14-99 d,#35383e, +|13: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-13 #bfc3cc,#35383e, 14-99 d,#35383e, +|14: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-13 #bfc3cc,#35383e, 14-99 d,#35383e, +|15: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-13 #bfc3cc,#35383e, 14-99 d,#35383e, +|16: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-13 #bfc3cc,#35383e, 14-99 d,#35383e, +|17: 0-1 #000000,#9cc3f7, 2-2 d,#373e49, 3-32 #d1d5de,#373e49, 33-39 #f8cba7,#373e49, 40-61 #d1d5de,#373e49, 62-99 d,#373e49, +|18: 0-0 d,#708095, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-20 #bfc3cc,#35383e, 21-92 d,#35383e, 93-93 d,#2a2d34, 94-98 #c5c9d2,#2a2d34, 99-99 d,#2a2d34, +|19: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-19 #bfc3cc,#35383e, 20-99 d,#35383e, +|20: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-17 #bfc3cc,#35383e, 18-99 d,#35383e, +|21: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-18 #bfc3cc,#35383e, 19-99 d,#35383e, +|22: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-20 #bfc3cc,#35383e, 21-99 d,#35383e, +|23: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-20 #bfc3cc,#35383e, 21-99 d,#35383e, +|24: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-19 #bfc3cc,#35383e, 20-99 d,#35383e, +|25: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-16 #bfc3cc,#35383e, 17-99 d,#35383e, +|26: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-23 #bfc3cc,#35383e, 24-99 d,#35383e, +|27: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #8e9199,#35383e,b 7-22 #bfc3cc,#35383e, 23-99 d,#35383e, +|28: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-25 #bfc3cc,#35383e, 26-99 d,#35383e, +|29: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-99 d,#35383e, +|30: 0-0 d,#3d4047, 1-1 d,#35383e, 2-6 #868991,#35383e, 7-34 #bfc3cc,#35383e, 35-99 d,#35383e, == snap step-orchard-black grid=100x31 cursor=7,27 |18: 7 Theme atelier Theme |19: 8 Theme forge @@ -491,37 +491,37 @@ |29: 18 # Legacy and imported themes |30: 19 Theme helix == style step-orchard-black grid=100x31 -|0: 0-70 #b4c4bb,#1e2926, 71-99 d,#1e2926, -|1: 0-1 #ffffff,#857557, 2-2 d,#283730, 3-34 #c0d0c7,#283730, 35-99 d,#283730, -|2: 0-1 #ffffff,#4a665a, 2-2 d,#1e2926, 3-32 #b4c4bb,#1e2926, 33-37 #d6b2d3,#1e2926, 38-59 #b4c4bb,#1e2926, 60-99 d,#1e2926, -|3: 0-0 d,#62826d, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000, -|4: 0-0 d,#62826d, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000, -|5: 0-0 d,#62826d, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000, -|6: 0-0 d,#62826d, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000, -|7: 0-0 d,#151c18, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000, -|8: 0-0 d,#151c18, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000, -|9: 0-0 d,#151c18, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000, -|10: 0-0 d,#151c18, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000, -|11: 0-0 d,#151c18, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000, -|12: 0-0 d,#151c18, 1-1 d,#000000, 2-6 #59675c,#000000, 7-13 #f2f8ef,#000000, 14-99 d,#000000, -|13: 0-0 d,#151c18, 1-1 d,#000000, 2-6 #59675c,#000000, 7-13 #f2f8ef,#000000, 14-99 d,#000000, -|14: 0-0 d,#151c18, 1-1 d,#000000, 2-6 #59675c,#000000, 7-13 #f2f8ef,#000000, 14-99 d,#000000, -|15: 0-0 d,#151c18, 1-1 d,#000000, 2-6 #59675c,#000000, 7-13 #f2f8ef,#000000, 14-99 d,#000000, -|16: 0-0 d,#151c18, 1-1 d,#000000, 2-6 #59675c,#000000, 7-13 #f2f8ef,#000000, 14-99 d,#000000, -|17: 0-1 #000000,#abd195, 2-2 d,#283730, 3-32 #c0d0c7,#283730, 33-39 #e2bedf,#283730, 40-61 #c0d0c7,#283730, 62-99 d,#283730, -|18: 0-0 d,#62826d, 1-1 d,#000000, 2-6 #59675c,#000000, 7-19 #f2f8ef,#000000, 20-92 d,#000000, 93-93 d,#1e2926, 94-98 #b4c4bb,#1e2926, 99-99 d,#1e2926, -|19: 0-0 d,#151c18, 1-1 d,#000000, 2-6 #59675c,#000000, 7-17 #f2f8ef,#000000, 18-99 d,#000000, -|20: 0-0 d,#151c18, 1-1 d,#000000, 2-6 #59675c,#000000, 7-18 #f2f8ef,#000000, 19-99 d,#000000, -|21: 0-0 d,#151c18, 1-1 d,#000000, 2-6 #59675c,#000000, 7-20 #f2f8ef,#000000, 21-99 d,#000000, -|22: 0-0 d,#151c18, 1-1 d,#000000, 2-6 #59675c,#000000, 7-20 #f2f8ef,#000000, 21-99 d,#000000, -|23: 0-0 d,#151c18, 1-1 d,#000000, 2-6 #59675c,#000000, 7-19 #f2f8ef,#000000, 20-99 d,#000000, -|24: 0-0 d,#151c18, 1-1 d,#000000, 2-6 #59675c,#000000, 7-16 #f2f8ef,#000000, 17-99 d,#000000, -|25: 0-0 d,#151c18, 1-1 d,#000000, 2-6 #59675c,#000000, 7-23 #f2f8ef,#000000, 24-99 d,#000000, -|26: 0-0 d,#151c18, 1-1 d,#000000, 2-6 #59675c,#000000, 7-22 #f2f8ef,#000000, 23-99 d,#000000, -|27: 0-0 d,#151c18, 1-1 d,#000000, 2-6 #616f64,#000000,b 7-25 #f2f8ef,#000000, 26-99 d,#000000, -|28: 0-0 d,#151c18, 1-1 d,#000000, 2-6 #59675c,#000000, 7-99 d,#000000, -|29: 0-0 d,#151c18, 1-1 d,#000000, 2-6 #59675c,#000000, 7-34 #f2f8ef,#000000, 35-99 d,#000000, -|30: 0-0 d,#151c18, 1-1 d,#000000, 2-6 #59675c,#000000, 7-17 #f2f8ef,#000000, 18-99 d,#000000, +|0: 0-70 #b2c3b8,#1d2824, 71-99 d,#1d2824, +|1: 0-1 #ffffff,#887455, 2-2 d,#26362d, 3-34 #becfc4,#26362d, 35-99 d,#26362d, +|2: 0-1 #ffffff,#496656, 2-2 d,#1d2824, 3-32 #b2c3b8,#1d2824, 33-37 #d3b0d9,#1d2824, 38-59 #b2c3b8,#1d2824, 60-99 d,#1d2824, +|3: 0-0 d,#608269, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000, +|4: 0-0 d,#608269, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000, +|5: 0-0 d,#608269, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000, +|6: 0-0 d,#608269, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000, +|7: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000, +|8: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000, +|9: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000, +|10: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000, +|11: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-12 #f2f8ef,#000000, 13-99 d,#000000, +|12: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-13 #f2f8ef,#000000, 14-99 d,#000000, +|13: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-13 #f2f8ef,#000000, 14-99 d,#000000, +|14: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-13 #f2f8ef,#000000, 14-99 d,#000000, +|15: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-13 #f2f8ef,#000000, 14-99 d,#000000, +|16: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-13 #f2f8ef,#000000, 14-99 d,#000000, +|17: 0-1 #000000,#add38a, 2-2 d,#26362d, 3-32 #becfc4,#26362d, 33-39 #dfbce5,#26362d, 40-61 #becfc4,#26362d, 62-99 d,#26362d, +|18: 0-0 d,#608269, 1-1 d,#000000, 2-6 #59675c,#000000, 7-19 #f2f8ef,#000000, 20-92 d,#000000, 93-93 d,#1d2824, 94-98 #b2c3b8,#1d2824, 99-99 d,#1d2824, +|19: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-17 #f2f8ef,#000000, 18-99 d,#000000, +|20: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-18 #f2f8ef,#000000, 19-99 d,#000000, +|21: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-20 #f2f8ef,#000000, 21-99 d,#000000, +|22: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-20 #f2f8ef,#000000, 21-99 d,#000000, +|23: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-19 #f2f8ef,#000000, 20-99 d,#000000, +|24: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-16 #f2f8ef,#000000, 17-99 d,#000000, +|25: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-23 #f2f8ef,#000000, 24-99 d,#000000, +|26: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-22 #f2f8ef,#000000, 23-99 d,#000000, +|27: 0-0 d,#111813, 1-1 d,#000000, 2-6 #616f64,#000000,b 7-25 #f2f8ef,#000000, 26-99 d,#000000, +|28: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-99 d,#000000, +|29: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-34 #f2f8ef,#000000, 35-99 d,#000000, +|30: 0-0 d,#111813, 1-1 d,#000000, 2-6 #59675c,#000000, 7-17 #f2f8ef,#000000, 18-99 d,#000000, == snap step-helix grid=100x31 cursor=7,27 |18: 10 Theme solarium Theme |19: 11 Theme spectrum @@ -537,37 +537,37 @@ |29: 21 Theme acme |30: 22 Theme acid == style step-helix grid=100x31 -|0: 0-70 #979998,#131414, 71-99 d,#131414, -|1: 0-1 #ffffff,#837048, 2-2 d,#141615, 3-34 #989a99,#141615, 35-99 d,#141615, -|2: 0-1 #ffffff,#2a2c2b, 2-2 d,#131414, 3-32 #979998,#131414, 33-37 #9a979b,#131414, 38-59 #979998,#131414, 60-99 d,#131414, -|3: 0-0 d,#474a48, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808, -|4: 0-0 d,#474a48, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808, -|5: 0-0 d,#474a48, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808, -|6: 0-0 d,#474a48, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808, -|7: 0-0 d,#121312, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808, -|8: 0-0 d,#121312, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808, -|9: 0-0 d,#121312, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808, -|10: 0-0 d,#121312, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808, -|11: 0-0 d,#121312, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808, -|12: 0-0 d,#121312, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-99 d,#080808, -|13: 0-0 d,#121312, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-99 d,#080808, -|14: 0-0 d,#121312, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-99 d,#080808, -|15: 0-0 d,#121312, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-99 d,#080808, -|16: 0-0 d,#121312, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-99 d,#080808, -|17: 0-1 #ffffff,#6a6d66, 2-2 d,#141615, 3-32 #989a99,#141615, 33-39 #9c989c,#141615, 40-61 #989a99,#141615, 62-99 d,#141615, -|18: 0-0 d,#474a48, 1-1 d,#080808, 2-6 #626262,#080808, 7-20 #bdbdbd,#080808, 21-92 d,#080808, 93-93 d,#131414, 94-98 #979998,#131414, 99-99 d,#131414, -|19: 0-0 d,#121312, 1-1 d,#080808, 2-6 #626262,#080808, 7-20 #bdbdbd,#080808, 21-99 d,#080808, -|20: 0-0 d,#121312, 1-1 d,#080808, 2-6 #626262,#080808, 7-19 #bdbdbd,#080808, 20-99 d,#080808, -|21: 0-0 d,#121312, 1-1 d,#080808, 2-6 #626262,#080808, 7-16 #bdbdbd,#080808, 17-99 d,#080808, -|22: 0-0 d,#121312, 1-1 d,#080808, 2-6 #626262,#080808, 7-23 #bdbdbd,#080808, 24-99 d,#080808, -|23: 0-0 d,#121312, 1-1 d,#080808, 2-6 #626262,#080808, 7-22 #bdbdbd,#080808, 23-99 d,#080808, -|24: 0-0 d,#121312, 1-1 d,#080808, 2-6 #626262,#080808, 7-25 #bdbdbd,#080808, 26-99 d,#080808, -|25: 0-0 d,#121312, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808, -|26: 0-0 d,#121312, 1-1 d,#080808, 2-6 #626262,#080808, 7-34 #bdbdbd,#080808, 35-99 d,#080808, -|27: 0-0 d,#121312, 1-1 d,#080808, 2-6 #626262,#080808,b 7-17 #bdbdbd,#080808, 18-99 d,#080808, -|28: 0-0 d,#121312, 1-1 d,#080808, 2-6 #626262,#080808, 7-16 #bdbdbd,#080808, 17-99 d,#080808, -|29: 0-0 d,#121312, 1-1 d,#080808, 2-6 #626262,#080808, 7-16 #bdbdbd,#080808, 17-99 d,#080808, -|30: 0-0 d,#121312, 1-1 d,#080808, 2-6 #626262,#080808, 7-16 #bdbdbd,#080808, 17-99 d,#080808, +|0: 0-70 #949494,#121212, 71-99 d,#121212, +|1: 0-1 #ffffff,#826f46, 2-2 d,#121212, 3-34 #949494,#121212, 35-99 d,#121212, +|2: 0-1 #ffffff,#262626, 2-2 d,#121212, 3-59 #949494,#121212, 60-99 d,#121212, +|3: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808, +|4: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808, +|5: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808, +|6: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808, +|7: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808, +|8: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808, +|9: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808, +|10: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808, +|11: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-12 #bdbdbd,#080808, 13-99 d,#080808, +|12: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-99 d,#080808, +|13: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-99 d,#080808, +|14: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-99 d,#080808, +|15: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-99 d,#080808, +|16: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-13 #bdbdbd,#080808, 14-99 d,#080808, +|17: 0-1 #ffffff,#626262, 2-2 d,#121212, 3-61 #949494,#121212, 62-99 d,#121212, +|18: 0-0 d,#444444, 1-1 d,#080808, 2-6 #626262,#080808, 7-20 #bdbdbd,#080808, 21-92 d,#080808, 93-93 d,#121212, 94-98 #949494,#121212, 99-99 d,#121212, +|19: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-20 #bdbdbd,#080808, 21-99 d,#080808, +|20: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-19 #bdbdbd,#080808, 20-99 d,#080808, +|21: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-16 #bdbdbd,#080808, 17-99 d,#080808, +|22: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-23 #bdbdbd,#080808, 24-99 d,#080808, +|23: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-22 #bdbdbd,#080808, 23-99 d,#080808, +|24: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-25 #bdbdbd,#080808, 26-99 d,#080808, +|25: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-99 d,#080808, +|26: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-34 #bdbdbd,#080808, 35-99 d,#080808, +|27: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808,b 7-17 #bdbdbd,#080808, 18-99 d,#080808, +|28: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-16 #bdbdbd,#080808, 17-99 d,#080808, +|29: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-16 #bdbdbd,#080808, 17-99 d,#080808, +|30: 0-0 d,#121212, 1-1 d,#080808, 2-6 #626262,#080808, 7-16 #bdbdbd,#080808, 17-99 d,#080808, == snap step-dark grid=100x31 cursor=7,27 |18: 11 Theme spectrum Theme |19: 12 Theme harvest @@ -583,37 +583,37 @@ |29: 22 Theme acid |30: 23 Theme acme_helix == style step-dark grid=100x31 -|0: 0-70 #969696,#29283a, 71-99 d,#29283a, -|1: 0-1 #ffffff,#86794d, 2-2 d,#29283a, 3-34 #969696,#29283a, 35-99 d,#29283a, -|2: 0-1 #ffffff,#343853, 2-2 d,#29283a, 3-59 #969696,#29283a, 60-99 d,#29283a, -|3: 0-0 d,#515151, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, -|4: 0-0 d,#515151, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, -|5: 0-0 d,#515151, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, -|6: 0-0 d,#515151, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, -|7: 0-0 d,#282828, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, -|8: 0-0 d,#282828, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, -|9: 0-0 d,#282828, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, -|10: 0-0 d,#282828, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, -|11: 0-0 d,#282828, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, -|12: 0-0 d,#282828, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, -|13: 0-0 d,#282828, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, -|14: 0-0 d,#282828, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, -|15: 0-0 d,#282828, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, -|16: 0-0 d,#282828, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, -|17: 0-1 #ffffff,#6643d3, 2-2 d,#29283a, 3-61 #969696,#29283a, 62-99 d,#29283a, -|18: 0-0 d,#515151, 1-1 d,d, 2-6 #5a5a5a,d, 7-92 d,d, 93-93 d,#29283a, 94-98 #969696,#29283a, 99-99 d,#29283a, -|19: 0-0 d,#282828, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, -|20: 0-0 d,#282828, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, -|21: 0-0 d,#282828, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, -|22: 0-0 d,#282828, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, -|23: 0-0 d,#282828, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, -|24: 0-0 d,#282828, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, -|25: 0-0 d,#282828, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, -|26: 0-0 d,#282828, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, -|27: 0-0 d,#282828, 1-1 d,d, 2-6 #5a5a5a,d,b 7-99 d,d, -|28: 0-0 d,#282828, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, -|29: 0-0 d,#282828, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, -|30: 0-0 d,#282828, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, +|0: 0-70 #969696,#2c2a3e, 71-99 d,#2c2a3e, +|1: 0-1 #ffffff,#867a4e, 2-2 d,#2c2a3e, 3-34 #969696,#2c2a3e, 35-99 d,#2c2a3e, +|2: 0-1 #ffffff,#353a58, 2-2 d,#2c2a3e, 3-59 #969696,#2c2a3e, 60-99 d,#2c2a3e, +|3: 0-0 d,#525252, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, +|4: 0-0 d,#525252, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, +|5: 0-0 d,#525252, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, +|6: 0-0 d,#525252, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, +|7: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, +|8: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, +|9: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, +|10: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, +|11: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, +|12: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, +|13: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, +|14: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, +|15: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, +|16: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, +|17: 0-1 #ffffff,#663fe0, 2-2 d,#2c2a3e, 3-61 #969696,#2c2a3e, 62-99 d,#2c2a3e, +|18: 0-0 d,#525252, 1-1 d,d, 2-6 #5a5a5a,d, 7-92 d,d, 93-93 d,#2c2a3e, 94-98 #969696,#2c2a3e, 99-99 d,#2c2a3e, +|19: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, +|20: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, +|21: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, +|22: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, +|23: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, +|24: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, +|25: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, +|26: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, +|27: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d,b 7-99 d,d, +|28: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, +|29: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, +|30: 0-0 d,#2a2a2a, 1-1 d,d, 2-6 #5a5a5a,d, 7-99 d,d, == snap step-acme grid=100x31 cursor=7,27 |18: 12 Theme harvest Theme |19: 13 Theme clay @@ -629,37 +629,37 @@ |29: 23 Theme acme_helix |30: 24 Theme adwaita_dark == style step-acme grid=100x31 -|0: 0-70 #0f0f0f,#d7eaec, 71-99 d,#d7eaec, -|1: 0-1 #000000,#bfa37a, 2-2 d,#d7eaec, 3-34 #0f0f0f,#d7eaec, 35-99 d,#d7eaec, -|2: 0-1 #ffffff,#353a58, 2-2 d,#d7eaec, 3-59 #0f0f0f,#d7eaec, 60-99 d,#d7eaec, -|3: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, -|4: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, -|5: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, -|6: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, -|7: 0-0 d,#8e8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, -|8: 0-0 d,#8e8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, -|9: 0-0 d,#8e8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, -|10: 0-0 d,#8e8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, -|11: 0-0 d,#8e8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, -|12: 0-0 d,#8e8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea, -|13: 0-0 d,#8e8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea, -|14: 0-0 d,#8e8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea, -|15: 0-0 d,#8e8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea, -|16: 0-0 d,#8e8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea, -|17: 0-1 #ffffff,#663fe0, 2-2 d,#d7eaec, 3-61 #0f0f0f,#d7eaec, 62-99 d,#d7eaec, -|18: 0-0 d,#eeeedb, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-19 #000000,#ffffea, 20-92 d,#ffffea, 93-93 d,#d7eaec, 94-98 #0f0f0f,#d7eaec, 99-99 d,#d7eaec, -|19: 0-0 d,#8e8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-16 #000000,#ffffea, 17-99 d,#ffffea, -|20: 0-0 d,#8e8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-23 #000000,#ffffea, 24-99 d,#ffffea, -|21: 0-0 d,#8e8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-22 #000000,#ffffea, 23-99 d,#ffffea, -|22: 0-0 d,#8e8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-25 #000000,#ffffea, 26-99 d,#ffffea, -|23: 0-0 d,#8e8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-99 d,#ffffea, -|24: 0-0 d,#8e8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-34 #000000,#ffffea, 35-99 d,#ffffea, -|25: 0-0 d,#8e8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-17 #000000,#ffffea, 18-99 d,#ffffea, -|26: 0-0 d,#8e8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-16 #000000,#ffffea, 17-99 d,#ffffea, -|27: 0-0 d,#8e8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea,b 7-16 #000000,#ffffea, 17-99 d,#ffffea, -|28: 0-0 d,#8e8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-16 #000000,#ffffea, 17-99 d,#ffffea, -|29: 0-0 d,#8e8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-22 #000000,#ffffea, 23-99 d,#ffffea, -|30: 0-0 d,#8e8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-24 #000000,#ffffea, 25-99 d,#ffffea, +|0: 0-70 #000000,#eaffff, 71-99 d,#eaffff, +|1: 0-1 #000000,#c5a87f, 2-2 d,#eaffff, 3-34 #000000,#eaffff, 35-99 d,#eaffff, +|2: 0-1 #ffffff,#353a58, 2-2 d,#eaffff, 3-59 #000000,#eaffff, 60-99 d,#eaffff, +|3: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, +|4: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, +|5: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, +|6: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, +|7: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, +|8: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, +|9: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, +|10: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, +|11: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, +|12: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea, +|13: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea, +|14: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea, +|15: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea, +|16: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea, +|17: 0-1 #ffffff,#663fe0, 2-2 d,#eaffff, 3-61 #000000,#eaffff, 62-99 d,#eaffff, +|18: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-19 #000000,#ffffea, 20-92 d,#ffffea, 93-93 d,#eaffff, 94-98 #000000,#eaffff, 99-99 d,#eaffff, +|19: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-16 #000000,#ffffea, 17-99 d,#ffffea, +|20: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-23 #000000,#ffffea, 24-99 d,#ffffea, +|21: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-22 #000000,#ffffea, 23-99 d,#ffffea, +|22: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-25 #000000,#ffffea, 26-99 d,#ffffea, +|23: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-99 d,#ffffea, +|24: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-34 #000000,#ffffea, 35-99 d,#ffffea, +|25: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-17 #000000,#ffffea, 18-99 d,#ffffea, +|26: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-16 #000000,#ffffea, 17-99 d,#ffffea, +|27: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea,b 7-16 #000000,#ffffea, 17-99 d,#ffffea, +|28: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-16 #000000,#ffffea, 17-99 d,#ffffea, +|29: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-22 #000000,#ffffea, 23-99 d,#ffffea, +|30: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-24 #000000,#ffffea, 25-99 d,#ffffea, == snap step-generated grid=100x31 cursor=7,27 |18: 13 Theme clay Theme |19: 14 Theme forge_black @@ -675,70 +675,70 @@ |29: 24 Theme adwaita_dark |30: 25 Theme adwaita_light == style step-generated grid=100x31 -|0: 0-70 #cacaca,#323c43, 71-99 d,#323c43, -|1: 0-1 #ffffff,#5b8094, 2-2 d,#323c43, 3-34 #cacaca,#323c43, 35-99 d,#323c43, -|2: 0-1 #ffffff,#313842, 2-2 d,#323c43, 3-59 #cacaca,#323c43, 60-99 d,#323c43, -|3: 0-0 d,#454c51, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26, -|4: 0-0 d,#454c51, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26, -|5: 0-0 d,#454c51, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26, -|6: 0-0 d,#454c51, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26, -|7: 0-0 d,#2a3231, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26, -|8: 0-0 d,#2a3231, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26, -|9: 0-0 d,#2a3231, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26, -|10: 0-0 d,#2a3231, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26, -|11: 0-0 d,#2a3231, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26, -|12: 0-0 d,#2a3231, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-13 #e0e0e0,#161e26, 14-99 d,#161e26, -|13: 0-0 d,#2a3231, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-13 #e0e0e0,#161e26, 14-99 d,#161e26, -|14: 0-0 d,#2a3231, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-13 #e0e0e0,#161e26, 14-99 d,#161e26, -|15: 0-0 d,#2a3231, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-13 #e0e0e0,#161e26, 14-99 d,#161e26, -|16: 0-0 d,#2a3231, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-13 #e0e0e0,#161e26, 14-99 d,#161e26, -|17: 0-1 #000000,#f0966d, 2-2 d,#323c43, 3-61 #cacaca,#323c43, 62-99 d,#323c43, -|18: 0-0 d,#454c51, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-16 #e0e0e0,#161e26, 17-92 d,#161e26, 93-93 d,#323c43, 94-98 #cacaca,#323c43, 99-99 d,#323c43, -|19: 0-0 d,#2a3231, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-23 #e0e0e0,#161e26, 24-99 d,#161e26, -|20: 0-0 d,#2a3231, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-22 #e0e0e0,#161e26, 23-99 d,#161e26, -|21: 0-0 d,#2a3231, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-25 #e0e0e0,#161e26, 26-99 d,#161e26, -|22: 0-0 d,#2a3231, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-99 d,#161e26, -|23: 0-0 d,#2a3231, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-34 #e0e0e0,#161e26, 35-99 d,#161e26, -|24: 0-0 d,#2a3231, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-17 #e0e0e0,#161e26, 18-99 d,#161e26, -|25: 0-0 d,#2a3231, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-16 #e0e0e0,#161e26, 17-99 d,#161e26, -|26: 0-0 d,#2a3231, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-16 #e0e0e0,#161e26, 17-99 d,#161e26, -|27: 0-0 d,#2a3231, 1-1 d,#161e26, 2-6 #303840,#161e26,b 7-16 #e0e0e0,#161e26, 17-99 d,#161e26, -|28: 0-0 d,#2a3231, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-22 #e0e0e0,#161e26, 23-99 d,#161e26, -|29: 0-0 d,#2a3231, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-24 #e0e0e0,#161e26, 25-99 d,#161e26, -|30: 0-0 d,#2a3231, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-25 #e0e0e0,#161e26, 26-99 d,#161e26, +|0: 0-70 #e0e0e0,#1e262e, 71-99 d,#1e262e, +|1: 0-1 #ffffff,#4f7b96, 2-2 d,#1e262e, 3-34 #e0e0e0,#1e262e, 35-99 d,#1e262e, +|2: 0-1 #ffffff,#303840, 2-2 d,#1e262e, 3-59 #e0e0e0,#1e262e, 60-99 d,#1e262e, +|3: 0-0 d,#303840, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26, +|4: 0-0 d,#303840, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26, +|5: 0-0 d,#303840, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26, +|6: 0-0 d,#303840, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26, +|7: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26, +|8: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26, +|9: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26, +|10: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26, +|11: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-12 #e0e0e0,#161e26, 13-99 d,#161e26, +|12: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-13 #e0e0e0,#161e26, 14-99 d,#161e26, +|13: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-13 #e0e0e0,#161e26, 14-99 d,#161e26, +|14: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-13 #e0e0e0,#161e26, 14-99 d,#161e26, +|15: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-13 #e0e0e0,#161e26, 14-99 d,#161e26, +|16: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-13 #e0e0e0,#161e26, 14-99 d,#161e26, +|17: 0-1 #000000,#ffa060, 2-2 d,#1e262e, 3-61 #e0e0e0,#1e262e, 62-99 d,#1e262e, +|18: 0-0 d,#303840, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-16 #e0e0e0,#161e26, 17-92 d,#161e26, 93-93 d,#1e262e, 94-98 #e0e0e0,#1e262e, 99-99 d,#1e262e, +|19: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-23 #e0e0e0,#161e26, 24-99 d,#161e26, +|20: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-22 #e0e0e0,#161e26, 23-99 d,#161e26, +|21: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-25 #e0e0e0,#161e26, 26-99 d,#161e26, +|22: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-99 d,#161e26, +|23: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-34 #e0e0e0,#161e26, 35-99 d,#161e26, +|24: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-17 #e0e0e0,#161e26, 18-99 d,#161e26, +|25: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-16 #e0e0e0,#161e26, 17-99 d,#161e26, +|26: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-16 #e0e0e0,#161e26, 17-99 d,#161e26, +|27: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26,b 7-16 #e0e0e0,#161e26, 17-99 d,#161e26, +|28: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-22 #e0e0e0,#161e26, 23-99 d,#161e26, +|29: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-24 #e0e0e0,#161e26, 25-99 d,#161e26, +|30: 0-0 d,#1e262e, 1-1 d,#161e26, 2-6 #303840,#161e26, 7-25 #e0e0e0,#161e26, 26-99 d,#161e26, == snap step-back grid=100x31 cursor=7,26 == style step-back grid=100x31 -|0: 0-70 #161616,#d6e9ea, 71-99 d,#d6e9ea, -|1: 0-1 #000000,#b9a481, 2-2 d,#d6e9ea, 3-34 #161616,#d6e9ea, 35-99 d,#d6e9ea, -|2: 0-1 #ffffff,#353a56, 2-2 d,#d6e9ea, 3-59 #161616,#d6e9ea, 60-99 d,#d6e9ea, -|3: 0-0 d,#eaebd9, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, -|4: 0-0 d,#eaebd9, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, -|5: 0-0 d,#eaebd9, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, -|6: 0-0 d,#eaebd9, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, -|7: 0-0 d,#8d8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, -|8: 0-0 d,#8d8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, -|9: 0-0 d,#8d8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, -|10: 0-0 d,#8d8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, -|11: 0-0 d,#8d8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, -|12: 0-0 d,#8d8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea, -|13: 0-0 d,#8d8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea, -|14: 0-0 d,#8d8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea, -|15: 0-0 d,#8d8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea, -|16: 0-0 d,#8d8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea, -|17: 0-1 #ffffff,#7549d3, 2-2 d,#d6e9ea, 3-61 #161616,#d6e9ea, 62-99 d,#d6e9ea, -|18: 0-0 d,#eaebd9, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-16 #000000,#ffffea, 17-92 d,#ffffea, 93-93 d,#d6e9ea, 94-98 #161616,#d6e9ea, 99-99 d,#d6e9ea, -|19: 0-0 d,#8d8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-23 #000000,#ffffea, 24-99 d,#ffffea, -|20: 0-0 d,#8d8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-22 #000000,#ffffea, 23-99 d,#ffffea, -|21: 0-0 d,#8d8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-25 #000000,#ffffea, 26-99 d,#ffffea, -|22: 0-0 d,#8d8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-99 d,#ffffea, -|23: 0-0 d,#8d8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-34 #000000,#ffffea, 35-99 d,#ffffea, -|24: 0-0 d,#8d8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-17 #000000,#ffffea, 18-99 d,#ffffea, -|25: 0-0 d,#8d8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-16 #000000,#ffffea, 17-99 d,#ffffea, -|26: 0-0 d,#8d8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea,b 7-16 #000000,#ffffea, 17-99 d,#ffffea, -|27: 0-0 d,#8d8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-16 #000000,#ffffea, 17-99 d,#ffffea, -|28: 0-0 d,#8d8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-22 #000000,#ffffea, 23-99 d,#ffffea, -|29: 0-0 d,#8d8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-24 #000000,#ffffea, 25-99 d,#ffffea, -|30: 0-0 d,#8d8e49, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-25 #000000,#ffffea, 26-99 d,#ffffea, +|0: 0-70 #000000,#eaffff, 71-99 d,#eaffff, +|1: 0-1 #000000,#c5a87f, 2-2 d,#eaffff, 3-34 #000000,#eaffff, 35-99 d,#eaffff, +|2: 0-1 #ffffff,#353a58, 2-2 d,#eaffff, 3-59 #000000,#eaffff, 60-99 d,#eaffff, +|3: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, +|4: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, +|5: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, +|6: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, +|7: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, +|8: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, +|9: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, +|10: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, +|11: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, +|12: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea, +|13: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea, +|14: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea, +|15: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea, +|16: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-13 #000000,#ffffea, 14-99 d,#ffffea, +|17: 0-1 #ffffff,#663fe0, 2-2 d,#eaffff, 3-61 #000000,#eaffff, 62-99 d,#eaffff, +|18: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-16 #000000,#ffffea, 17-92 d,#ffffea, 93-93 d,#eaffff, 94-98 #000000,#eaffff, 99-99 d,#eaffff, +|19: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-23 #000000,#ffffea, 24-99 d,#ffffea, +|20: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-22 #000000,#ffffea, 23-99 d,#ffffea, +|21: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-25 #000000,#ffffea, 26-99 d,#ffffea, +|22: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-99 d,#ffffea, +|23: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-34 #000000,#ffffea, 35-99 d,#ffffea, +|24: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-17 #000000,#ffffea, 18-99 d,#ffffea, +|25: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-16 #000000,#ffffea, 17-99 d,#ffffea, +|26: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea,b 7-16 #000000,#ffffea, 17-99 d,#ffffea, +|27: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-16 #000000,#ffffea, 17-99 d,#ffffea, +|28: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-22 #000000,#ffffea, 23-99 d,#ffffea, +|29: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-24 #000000,#ffffea, 25-99 d,#ffffea, +|30: 0-0 d,#99994c, 1-1 d,#ffffea, 2-6 #999980,#ffffea, 7-25 #000000,#ffffea, 26-99 d,#ffffea, == snap tail grid=100x31 cursor=7,29 |18: 235 Theme wolf_alabaster_dark_bg |19: 236 Theme wolf_alabaster_dark_mono @@ -769,13 +769,8 @@ |29: 27 line 27 |30: 28 line 28 == style picked grid=100x31 -|0: 0-70 #000000,#eaffff, 71-99 d,#eaffff, -|1: 0-1 #000000,#c5a87f, 2-2 d,#eaffff, 3-34 #000000,#eaffff, 35-99 d,#eaffff, |2: 0-1 #ffffff,#663fe0, 2-2 d,#eaffff, 3-59 #000000,#eaffff, 60-99 d,#eaffff, |3: 0-1 d,#ffffea, 2-6 #999980,#ffffea,b 7-12 #000000,#ffffea, 13-99 d,#ffffea, -|4: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, -|5: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, -|6: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, |7: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, |8: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, |9: 0-1 d,#ffffea, 2-6 #999980,#ffffea, 7-12 #000000,#ffffea, 13-99 d,#ffffea, diff --git a/test/web_harness.mjs b/test/web_harness.mjs index 90dd9a19..402e41f4 100644 --- a/test/web_harness.mjs +++ b/test/web_harness.mjs @@ -17,7 +17,7 @@ async function main() { const webDir = path.resolve(process.argv[2]); const wasmBytes = await fs.readFile(path.join(webDir, "pardes.wasm")); const module = await WebAssembly.compile(wasmBytes); - const { DomRenderer, animationTicks, browserHost } = await import(pathToFileURL(path.join(webDir, "app.mjs"))); + const { DomRenderer, browserHost } = await import(pathToFileURL(path.join(webDir, "app.mjs"))); assert.deepEqual( [...new Set(WebAssembly.Module.imports(module).map((entry) => entry.module))], ["pardes"], @@ -40,7 +40,7 @@ async function main() { for (const name of [ "memory", "pardes_init", "pardes_frame", "pardes_frame_ptr", "pardes_key", "pardes_mouse", "pardes_pointer_leave", "pardes_pointer_shape", "pardes_gui_tagline_font_percent", - "pardes_paste", "pardes_tick", "pardes_animation_tick", "pardes_animating", + "pardes_paste", "pardes_tick", "pardes_should_quit", "pardes_deinit", ]) assert.ok(wasm[name], `missing wasm export ${name}`); @@ -85,18 +85,6 @@ async function main() { "DOM did not use the build-time tagline percentage", ); - for (const hz of [60, 120, 144]) { - const clock = { last: null, lag: 0 }; - let ticks = 0; - for (let frame = 0; frame <= hz; frame += 1) { - ticks += animationTicks(clock, frame * 1000 / hz); - } - assert.equal(ticks, 60, `${hz} Hz rAF did not produce 60 core ticks per second`); - } - const stalled = { last: null, lag: 0 }; - assert.equal(animationTicks(stalled, 0), 0); - assert.equal(animationTicks(stalled, 60_000), 4, "suspended tab catch-up was not bounded"); - const firstCell = renderer.cells[0]; const second = draw(); assert.equal(renderer.cells[0], firstCell, "stable frames should reuse DOM nodes"); -- cgit v1.3 From d88e381793c6505bf3f2af43705bd2fa32f55ef6 Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Mon, 28 Sep 2026 14:37:29 -0300 Subject: One Layer for tags, notices, headers and bodies; a taller tag is one layer of rows; wire v8 src/Layer.zig merges TagLayer and BodyLayer. `rows` (0 = no layer) and a cursor at {x, y}. A tag of N rows is ONE layer of N grid rows: tagHit answers the row as `line`, bodyHit keeps its meaning, and the per-line layer bases (TAG_LINE_LAYER_BASE, HEADER_LINE_LAYER_BASE) are gone, not aliased. Wire v8, the one bump: tag layers carry rows and cursor y, and the frame carries the placed region list. v7 and v9 peers are refused in both directions (server test over both, a new frontend test over both). web: tag_layer_value 11 = rows, 12 = cursor y; app.mjs lays every row. macOS: the Zig side compiles against Layer; pardes.h still sees one row per tag layer (accepted, the macOS shell is ignored for now). No visual change: snapshot goldens and the 17 GUI goldens byte-identical. Shared files touched: pardes.zig, Messages.zig, gui.zig, macos.zig, detached/client.zig, detached/server.zig, detached/wire.zig (plus web.zig, app.mjs, edit.zig, look.zig). Not touched: mouse.zig, tagline.zig, colors.zig, tty.zig, dump.zig, exec.zig, host_io.zig, panes.zig. --- docs/render-pipeline.md | 2 +- src/Layer.zig | 198 ++++++++++++++++++++++++++++++++++++++++++++++++ src/Messages.zig | 6 +- src/Presentation.zig | 12 +-- src/body_layer.zig | 117 ++-------------------------- src/detached/client.zig | 30 ++++++-- src/detached/server.zig | 3 +- src/detached/wire.zig | 118 ++++++++++++++++++++--------- src/draw.zig | 187 +++++++++++++++++++++++---------------------- src/edit.zig | 2 +- src/gui/gui.zig | 139 +++++++++++++++++---------------- src/look.zig | 2 +- src/macos.zig | 12 +-- src/pardes.zig | 40 +++++----- src/surface.zig | 15 ++-- src/tag_layer.zig | 87 ++------------------- src/web.zig | 12 ++- src/web/app.mjs | 38 ++++++---- test/column_drag.zig | 10 +-- test/panes.zig | 30 ++++---- 20 files changed, 590 insertions(+), 470 deletions(-) create mode 100644 src/Layer.zig (limited to 'src/Messages.zig') diff --git a/docs/render-pipeline.md b/docs/render-pipeline.md index f63b9a0b..a8b3f019 100644 --- a/docs/render-pipeline.md +++ b/docs/render-pipeline.md @@ -809,7 +809,7 @@ stripped. No visual change until stage 9 unless stated. | 4 | PLACE: Region list built once; renderPane/tags/notices read their rects from it | wait for tag→Text; the refactor is already replacing BOX_H with `pane.tag_rows` and `p.tagTop/bodyTop(pane, r)` — PLACE absorbs those into the region rects | | 5 | JOIN: paint tags/notices/headers once into layers, copy into grid; the grid wins where the copies disagree, and each disagreement is listed for a later decision | goldens are the oracle; wide-grapheme re-clip at the edge (§3.2) | | 6 | body layer joined the same way (paint once, copy visible rows) | riskiest join; A/B the old double paint in a temporary test with tag_bottom on and off, then delete it | -| 7 | Layer merge (TagLayer + BodyLayer), wire v8, web accessors | after the other agent lands; touches mouse hit paths; breaks the macOS shell's layer ABI (accepted: macOS build ignored for now) | +| 7 | Layer merge (TagLayer + BodyLayer), wire v8, web accessors | after the other agent lands; touches mouse hit paths; breaks the macOS shell's layer ABI (accepted: macOS build ignored for now); done: one `Layer` (src/Layer.zig) with `rows` (0 = no layer) and a `cursor{x, y}`; a tag of N rows is ONE layer of N grid rows (`tagHit` answers the row as `line`, `bodyHit` keeps its meaning), so the per-line layer bases are gone. Wire v8 ships rows, cursor y and the region list in the one bump; v7 and v9 peers are refused in both directions (tests). web: `tag_layer_value` 11 = rows, 12 = cursor y, and app.mjs lays every row. macOS: its Zig side compiles against `Layer`, but pardes.h still sees one row per tag layer (a taller tag shows its first row there) | | 8 | GUI draws from regions: role tiers with track groups in tiers 2-3, page cover, hard-edged snapped decor for rules/rails/grips (pane chrome in the pane's tier), per-instance clip; delete inference functions, `transient_on` and `mark_hover` (breaks macOS glass hover; accepted, macOS ignored for now) | stage-0 PPM goldens byte-identical (possible only because hard decor is snapped and not anti-aliased); pane chrome now also shows during transitions, which is the one allowed visible delta, listed | | 9 | post chain: glslang, Shadertoy prefix, ping-pong, ShaderAnimation, redraw levels A/B (§5.5); bundled CRT without barrel; delete scene_effects/crt.zig/crt.frag | first visual change (the CRT look) | | 10+ | `fx` bookmark: G1–G3 → feel review → G4 bundled → G5 lapis theme → P2s; tty T1–T2 → feel review → removals of audited effects (after user decision) → T3–T5 | each effect its own change, default off | diff --git a/src/Layer.zig b/src/Layer.zig new file mode 100644 index 00000000..e979eab7 --- /dev/null +++ b/src/Layer.zig @@ -0,0 +1,198 @@ +//! A band of cells a pixel shell draws over the grid at its own pitch: a +//! pane's, a column's or the workspace's tag rows, a notice chip, or a file +//! body whose compact tree-sitter context rows outnumber its grid rows. The +//! grid under it holds a copy of what fits there (draw.zig joins them), so a +//! terminal client, which has only the grid, loses nothing but the pitch. +//! +//! Its viewport is in grid cells, so compact text never moves a hit target. +//! A tag's rows are each one grid row, their glyphs at the tagline's size; a +//! body's first `context_rows` rows are stacked at the tagline's height, the +//! rest at the body's. `rows == 0` is no layer. +const std = @import("std"); +const pardes = @import("pardes.zig"); +const config = @import("config.zig"); +const limits = @import("memory.zig").limits; + +const Layer = @This(); + +/// `notice` is a pane's transient line -- a builtin's name, a pending leader +/// chord -- carried as a tagline-shaped band so it gets the tagline's height, +/// small-font metrics, band offset and border instead of being a body-grid row +/// wearing a tagline font. +pub const Kind = enum(u8) { workspace, column, pane, notice, body }; + +pub const Metrics = struct { + body_w: u16 = 1, + body_h: u16 = 1, + tagline_w: u16 = 1, + tagline_h: u16 = 1, +}; + +/// A point on a tag, notice or header layer: which row of it and which +/// column at the tagline's pitch. +pub const TagHit = struct { + kind: Kind, + id: u16, + serial: u32, + col: u16, + /// Which row of a taller tag. + line: u16 = 0, + pixel_x: f32, + pixel_y: f32, + metrics: Metrics, +}; + +kind: Kind = .body, +/// The pane slot, or the column, it belongs to. +id: u16 = 0, +serial: u32 = 0, +viewport: pardes.Rect = .{ .x = 0, .y = 0, .w = 0, .h = 0 }, +cols: u16 = 0, +rows: u16 = 0, +/// A body's compact rows, from its top. +context_rows: u16 = 0, +context_separators: std.bit_set.StaticBitSet(limits.wrap_rows) = .initEmpty(), +/// `rows * cols`, row after row. +cells: []pardes.Cell = &.{}, +cursor: ?struct { x: u16, y: u16, bar: bool = false } = null, +/// A band's fill, where its cells run out. +bg: [3]u8 = .{ 0, 0, 0 }, +/// Vertical offset in rows (negative: above its viewport), for a band +/// that is moving into place. A pixel shell draws it offset and clipped +/// to the rows below the viewport's top; the grid has no such thing. +slide: f32 = 0, +/// How present a notice band is (1 = fully) while it fades up or +/// dissolves. `bg` and the cells are already blended by it; a pixel +/// shell uses it for what it draws around the band, like its rule. +fade: f32 = 1, + +/// Tag columns a viewport this wide holds at the tagline's pitch. +pub fn capacity(layer: *const Layer, metrics: Metrics) u16 { + return @intCast(@min(std.math.maxInt(u16), @max(1, @as(u32, layer.viewport.w) * @max(1, metrics.body_w) / @max(1, metrics.tagline_w)))); +} + +pub fn setContextLines(layer: *Layer, lines: []const i32) void { + layer.context_separators = .initEmpty(); + const count = @min(lines.len, layer.context_rows); + var index: usize = 0; + while (index + 1 < count and index < limits.wrap_rows) : (index += 1) { + if (lines[index + 1] != lines[index] +| 1) layer.context_separators.set(index); + } +} + +pub fn hasContextBorderAfter(layer: *const Layer, index: usize) bool { + if (index >= layer.context_rows or index >= limits.wrap_rows) return false; + return index + 1 == layer.context_rows or layer.context_separators.isSet(index); +} + +/// Pixel top of row `index`: a body's compact rows stacked at the tagline's +/// height, every other row a grid row. +pub fn rowTop(layer: *const Layer, index: u16, body_h: f32, tagline_h: f32) f32 { + const body = @max(1, body_h); + const tag = std.math.clamp(tagline_h, 1, body); + return @as(f32, @floatFromInt(layer.viewport.y)) * body + + @as(f32, @floatFromInt(@min(index, layer.context_rows))) * tag + + @as(f32, @floatFromInt(index -| layer.context_rows)) * body; +} + +pub fn rowHeight(layer: *const Layer, index: u16, body_h: f32, tagline_h: f32) f32 { + return if (index < layer.context_rows) std.math.clamp(tagline_h, 1, @max(1, body_h)) else @max(1, body_h); +} + +const Point = struct { index: u16, col: u16, metrics: Metrics }; + +/// The row and column a window pixel lands on, each row at its own pitch: +/// a tag's at the tagline's width, a body's compact rows too. +fn pointAt(layer: *const Layer, x: f32, y: f32, body_w: f32, body_h: f32, tagline_w: f32, tagline_h: f32) ?Point { + if (layer.rows == 0 or !std.math.isFinite(x) or !std.math.isFinite(y)) return null; + // A band's hit is refused outright on metrics no host could have; a + // body's has always been floored to a pixel instead. + if (layer.kind != .body) for ([_]f32{ body_w, body_h, tagline_w, tagline_h }) |metric| + if (!std.math.isFinite(metric) or metric < 1 or metric > std.math.maxInt(u16)) return null; + const bw = @max(1, body_w); + const bh = @max(1, body_h); + const tw = std.math.clamp(tagline_w, 1, bw); + const th = std.math.clamp(tagline_h, 1, bh); + const dx = x - @as(f32, @floatFromInt(layer.viewport.x)) * bw; + const dy = y - @as(f32, @floatFromInt(layer.viewport.y)) * bh; + if (dx < 0 or dy < 0 or dx >= @as(f32, @floatFromInt(layer.viewport.w)) * bw or dy >= @as(f32, @floatFromInt(layer.viewport.h)) * bh) return null; + const headers = @as(f32, @floatFromInt(layer.context_rows)) * th; + const index: u16 = @intFromFloat(if (dy < headers) @floor(dy / th) else @as(f32, @floatFromInt(layer.context_rows)) + @floor((dy - headers) / bh)); + if (index >= layer.rows) return null; + const pitch = if (layer.kind != .body or index < layer.context_rows) tw else bw; + return .{ + .index = index, + .col = @intFromFloat(@min(@as(f32, @floatFromInt(layer.cols -| 1)), @floor(dx / pitch))), + .metrics = .{ .body_w = @intFromFloat(bw), .body_h = @intFromFloat(bh), .tagline_w = @intFromFloat(tw), .tagline_h = @intFromFloat(th) }, + }; +} + +/// A body layer's pixel as the body cell under it (grid columns, from the +/// pane's text edge). +pub fn bodyHit(layer: *const Layer, x: f32, y: f32, body_w: f32, body_h: f32, tagline_w: f32, tagline_h: f32) ?pardes.Mouse.BodyHit { + if (layer.kind != .body) return null; + const point = layer.pointAt(x, y, body_w, body_h, tagline_w, tagline_h) orelse return null; + return .{ .serial = layer.serial, .row = point.index, .col = point.col + config.GUTTER, .pixel_x = x, .pixel_y = y, .metrics = point.metrics }; +} + +/// A band's pixel as the tag cell under it. +pub fn tagHit(layer: *const Layer, x: f32, y: f32, body_w: f32, body_h: f32, tagline_w: f32, tagline_h: f32) ?TagHit { + if (layer.kind == .body) return null; + const point = layer.pointAt(x, y, body_w, body_h, tagline_w, tagline_h) orelse return null; + return .{ .kind = layer.kind, .id = layer.id, .serial = layer.serial, .line = point.index, .col = point.col, .pixel_x = x, .pixel_y = y, .metrics = point.metrics }; +} + +test "compact body layer rows fill reclaimed height and invert exact boundaries" { + const layer: Layer = .{ .serial = 7, .viewport = .{ .x = 4, .y = 3, .w = 40, .h = 10 }, .cols = 40, .rows = 15, .context_rows = 5 }; + try std.testing.expectEqual(@as(f32, 120), layer.rowTop(5, 20, 12)); + try std.testing.expectEqual(@as(f32, 240), layer.rowTop(11, 20, 12)); + try std.testing.expectEqual(@as(f32, 12), layer.rowHeight(4, 20, 12)); + try std.testing.expectEqual(@as(f32, 20), layer.rowHeight(5, 20, 12)); + for (0..12) |index| { + const r: u16 = @intCast(index); + const y = layer.rowTop(r, 20, 12) + layer.rowHeight(r, 20, 12) / 2; + const width: f32 = if (r < 5) 6 else 10; + const hit = layer.bodyHit(40 + 3.5 * width, y, 10, 20, 6, 12).?; + try std.testing.expectEqual(r, hit.row); + try std.testing.expectEqual(@as(u16, 3 + config.GUTTER), hit.col); + } + try std.testing.expectEqual(@as(u16, 4), layer.bodyHit(45, 119.99, 10, 20, 6, 12).?.row); + try std.testing.expectEqual(@as(u16, 5), layer.bodyHit(45, 120, 10, 20, 6, 12).?.row); + try std.testing.expectEqual(@as(u16, 11), layer.bodyHit(45, 259.99, 10, 20, 6, 12).?.row); + try std.testing.expect(layer.bodyHit(45, 260, 10, 20, 6, 12) == null); + try std.testing.expect(layer.bodyHit(39.99, 80, 10, 20, 6, 12) == null); + try std.testing.expect(layer.bodyHit(std.math.nan(f32), 80, 10, 20, 6, 12) == null); +} + +test "compact context borders separate source gaps and preserve multiline headers" { + var layer: Layer = .{ .context_rows = 6 }; + layer.setContextLines(&.{ 3, 4, 8, 9, 10, 17 }); + const expected = [_]bool{ false, true, false, false, true, true, false }; + for (expected, 0..) |border, index| try std.testing.expectEqual(border, layer.hasContextBorderAfter(index)); + layer.context_rows = 2; + layer.setContextLines(&.{ 9, 10 }); + try std.testing.expect(!layer.hasContextBorderAfter(0)); + try std.testing.expect(layer.hasContextBorderAfter(1)); + try std.testing.expect(!layer.hasContextBorderAfter(4)); + try std.testing.expect(!layer.context_separators.isSet(4)); +} + +test "tag text capacity uses its own pitch and excludes the physical grip" { + const layer: Layer = .{ .kind = .pane, .id = 2, .serial = 7, .viewport = .{ .x = 12, .y = 4, .w = 38, .h = 1 }, .cols = 90, .rows = 1 }; + try std.testing.expectEqual(@as(u16, 63), layer.capacity(.{ .body_w = 10, .tagline_w = 6 })); + try std.testing.expect(layer.tagHit(119.99, 85, 10, 20, 6, 12) == null); + try std.testing.expectEqual(@as(u16, 0), layer.tagHit(120, 85, 10, 20, 6, 12).?.col); + try std.testing.expectEqual(@as(u16, 50), layer.tagHit(423, 85, 10, 20, 6, 12).?.col); + try std.testing.expect(layer.tagHit(500, 85, 10, 20, 6, 12) == null); + try std.testing.expect(layer.tagHit(120, 85, std.math.nan(f32), 20, 6, 12) == null); + try std.testing.expect(layer.tagHit(120, 85, 10, 20, 0, 12) == null); +} + +test "a taller tag's rows are grid rows, each hit on its own line" { + const layer: Layer = .{ .kind = .pane, .id = 2, .serial = 7, .viewport = .{ .x = 12, .y = 4, .w = 38, .h = 3 }, .cols = 90, .rows = 3 }; + try std.testing.expectEqual(@as(u16, 0), layer.tagHit(120, 80, 10, 20, 6, 12).?.line); + try std.testing.expectEqual(@as(u16, 1), layer.tagHit(120, 100, 10, 20, 6, 12).?.line); + try std.testing.expectEqual(@as(u16, 2), layer.tagHit(120, 139.99, 10, 20, 6, 12).?.line); + try std.testing.expect(layer.tagHit(120, 140, 10, 20, 6, 12) == null); + try std.testing.expect(layer.bodyHit(120, 100, 10, 20, 6, 12) == null); +} diff --git a/src/Messages.zig b/src/Messages.zig index 7334de95..b7153e5c 100644 --- a/src/Messages.zig +++ b/src/Messages.zig @@ -747,7 +747,7 @@ test "a builtin announces itself on the message row, and Verbose silences it" { _ = try p.render(frame.allocator()); const r = p.rects[p.active]; const band = for (p.surface.tagLayers()) |*layer| { - if (layer.cols != 0 and layer.kind == .notice) break layer; + if (layer.rows != 0 and layer.kind == .notice) break layer; } else return error.NoNoticeBand; try std.testing.expectEqual(@as(u16, 1), band.viewport.h); try std.testing.expectEqual(if (p.settings.tag_bottom) r.y else r.y + BOX_H, band.viewport.y); @@ -794,7 +794,7 @@ test "notices stack over the body's top rows without moving them" { var seen: usize = 0; for (p.surface.tagLayers()) |*layer| { - if (layer.cols == 0 or layer.kind != .notice) continue; + if (layer.rows == 0 or layer.kind != .notice) continue; try std.testing.expectEqual(@as(u16, 1), layer.viewport.h); // Sized to its own message, right up against the pane's right edge -- // not the width of the pane. @@ -814,7 +814,7 @@ test "notices stack over the body's top rows without moving them" { _ = frame.reset(.retain_capacity); _ = try p.render(frame.allocator()); for (p.surface.tagLayers()) |*layer| - try std.testing.expect(layer.cols == 0 or layer.kind != .notice); + try std.testing.expect(layer.rows == 0 or layer.kind != .notice); } test "an idle core wants no wake and a lingering message sleeps to its linger's end" { diff --git a/src/Presentation.zig b/src/Presentation.zig index 45b196c8..e1f1b585 100644 --- a/src/Presentation.zig +++ b/src/Presentation.zig @@ -42,8 +42,8 @@ shown_closing_len: usize = 0, acknowledged: bool = false, pending: bool = false, previous_cells: []pardes.Cell = &.{}, -previous_body_layers: [MAX_PANES]pardes.BodyLayer = @splat(.{}), -previous_tag_layers: [pardes.MAX_TAG_LAYERS]pardes.TagLayer = @splat(.{}), +previous_body_layers: [MAX_PANES]pardes.Layer = @splat(.{}), +previous_tag_layers: [pardes.MAX_TAG_LAYERS]pardes.Layer = @splat(.{}), previous_cols: u16 = 0, previous_rows: u16 = 0, previous_valid: bool = false, @@ -335,7 +335,7 @@ pub fn capturePrevious(self: *Presentation, gpa: std.mem.Allocator, surface: *co old.cells = storage; } for (&self.previous_tag_layers, surface.tagLayers()) |*old, *current| { - const count = if (current.cols > 0) current.cells.len else 0; + const count = if (current.rows > 0) current.cells.len else 0; const storage = if (old.cells.len == count) old.cells else gpa.realloc(old.cells, count) catch { self.previous_valid = false; self.previous_layout = @splat(null); @@ -684,7 +684,7 @@ test "presentation submission failure preserves shown geometry until retry is ac } test "fractional panel inverse preserves compact header rows through slide and zoom" { - const layer: pardes.BodyLayer = .{ .serial = 7, .viewport = .{ .x = 4, .y = 3, .w = 30, .h = 10 }, .cols = 30, .rows = 15, .context_rows = 4 }; + const layer: pardes.Layer = .{ .serial = 7, .viewport = .{ .x = 4, .y = 3, .w = 30, .h = 10 }, .cols = 30, .rows = 15, .context_rows = 4 }; for ([_]Transition{ .slide, .zoom, .vertical }) |effect| { var presentation: Presentation = .{}; const track: Track = .{ .serial = 7, .effect = effect, .frame = 4, .frame_count = 10, .from = .{ .x = 2, .y = 2, .w = 20, .h = 8 }, .to = .{ .x = 3, .y = 2, .w = 32, .h = 12 } }; @@ -699,7 +699,7 @@ test "fractional panel inverse preserves compact header rows through slide and z const point = presentation.pointerFractional(80, 30, x, y).?; try std.testing.expectApproxEqAbs(source_x, point.x, 0.0001); try std.testing.expectApproxEqAbs(source_y, point.y, 0.0001); - const body_hit = layer.hitAt(point.x * 10, point.y * 20, 10, 20, 8, 10).?; + const body_hit = layer.bodyHit(point.x * 10, point.y * 20, 10, 20, 8, 10).?; try std.testing.expectEqual(row, body_hit.row); } } @@ -715,7 +715,7 @@ test "presentation snapshots own compact body and tag rows across later edits" { surface.body_layers[0] = .{ .serial = 9, .cols = 1, .rows = 2, .context_rows = 1, .cells = &body }; var tag: [1]pardes.Cell = .{.{}}; tag[0].text[0] = 'T'; - surface.tag_layers[0] = .{ .kind = .pane, .serial = 9, .cols = 1, .cells = &tag }; + surface.tag_layers[0] = .{ .kind = .pane, .serial = 9, .cols = 1, .rows = 1, .cells = &tag }; state.capturePrevious(std.testing.allocator, &surface); try std.testing.expect(state.previous_valid); tag[0].text[0] = 'U'; diff --git a/src/body_layer.zig b/src/body_layer.zig index ac87a07b..583a2e98 100644 --- a/src/body_layer.zig +++ b/src/body_layer.zig @@ -1,9 +1,6 @@ -//! A pane body as the surface shows it. A file body's logical rows can -//! outnumber its physical grid rows: hosts place the compact declaration rows -//! first and clip the remaining body rows. After the layer types come the -//! functions that draw a body into the surface: its text, colours, selections -//! and cursor; then the tags drawn beside it, a pane's and the column and -//! workspace ones, each line a tag layer of its own. +//! Drawing a pane body into a surface: its text, colours, selections and +//! cursor, and joining a body with compact context rows through its layer +//! (Layer.zig). const std = @import("std"); const pardes = @import("pardes.zig"); const normal = @import("normal.zig"); @@ -29,7 +26,7 @@ const tagline = @import("tagline.zig"); const Messages = @import("Messages.zig"); const Text = panes.Text; const MAX_PANES = pardes.MAX_PANES; -const TagKind = @import("tag_layer.zig").Kind; +const TagKind = @import("Layer.zig").Kind; const MAX_TAG_ROWS = pardes.MAX_TAG_ROWS; const NOTICE_LAYER_BASE = pardes.NOTICE_LAYER_BASE; const TAG_LINE_LAYER_BASE = pardes.TAG_LINE_LAYER_BASE; @@ -40,108 +37,7 @@ const COLBAR_H = pardes.COLBAR_H; const TAG_GAP = pardes.TAG_GAP; const wordBoundsAtCol = pardes.wordBoundsAtCol; -pub const Metrics = struct { - body_w: u16 = 1, - body_h: u16 = 1, - tagline_w: u16 = 1, - tagline_h: u16 = 1, -}; - -pub const Layer = struct { - pane: u16 = 0, - serial: u32 = 0, - viewport: pardes.Rect = .{ .x = 0, .y = 0, .w = 0, .h = 0 }, - cols: u16 = 0, - rows: u16 = 0, - context_rows: u16 = 0, - context_separators: std.bit_set.StaticBitSet(limits.wrap_rows) = .initEmpty(), - cells: []pardes.Cell = &.{}, - cursor: ?struct { x: u16, y: u16, bar: bool = false } = null, - - pub fn setContextLines(layer: *Layer, lines: []const i32) void { - layer.context_separators = .initEmpty(); - const count = @min(lines.len, layer.context_rows); - var row: usize = 0; - while (row + 1 < count and row < limits.wrap_rows) : (row += 1) { - if (lines[row + 1] != lines[row] +| 1) layer.context_separators.set(row); - } - } - - pub fn hasContextBorderAfter(layer: *const Layer, row: usize) bool { - if (row >= layer.context_rows or row >= limits.wrap_rows) return false; - return row + 1 == layer.context_rows or layer.context_separators.isSet(row); - } - - pub fn rowTop(layer: *const Layer, row: u16, body_h: f32, tagline_h: f32) f32 { - const body = @max(1, body_h); - const tag = std.math.clamp(tagline_h, 1, body); - return @as(f32, @floatFromInt(layer.viewport.y)) * body + - @as(f32, @floatFromInt(@min(row, layer.context_rows))) * tag + - @as(f32, @floatFromInt(row -| layer.context_rows)) * body; - } - - pub fn rowHeight(layer: *const Layer, row: u16, body_h: f32, tagline_h: f32) f32 { - return if (row < layer.context_rows) std.math.clamp(tagline_h, 1, @max(1, body_h)) else @max(1, body_h); - } - - pub fn hitAt(layer: *const Layer, x: f32, y: f32, body_w: f32, body_h: f32, tagline_w: f32, tagline_h: f32) ?pardes.Mouse.BodyHit { - if (layer.rows == 0 or !std.math.isFinite(x) or !std.math.isFinite(y)) return null; - const bw = @max(1, body_w); - const bh = @max(1, body_h); - const tw = std.math.clamp(tagline_w, 1, bw); - const th = std.math.clamp(tagline_h, 1, bh); - const dx = x - @as(f32, @floatFromInt(layer.viewport.x)) * bw; - const dy = y - @as(f32, @floatFromInt(layer.viewport.y)) * bh; - if (dx < 0 or dy < 0 or dx >= @as(f32, @floatFromInt(layer.viewport.w)) * bw or dy >= @as(f32, @floatFromInt(layer.viewport.h)) * bh) return null; - const headers = @as(f32, @floatFromInt(layer.context_rows)) * th; - const row: u16 = @intFromFloat(if (dy < headers) @floor(dy / th) else @as(f32, @floatFromInt(layer.context_rows)) + @floor((dy - headers) / bh)); - if (row >= layer.rows) return null; - const col: u16 = @intFromFloat(@min(@as(f32, @floatFromInt(layer.cols -| 1)), @floor(dx / (if (row < layer.context_rows) tw else bw)))); - return .{ - .serial = layer.serial, - .row = row, - .col = col + config.GUTTER, - .pixel_x = x, - .pixel_y = y, - .metrics = .{ .body_w = @intFromFloat(bw), .body_h = @intFromFloat(bh), .tagline_w = @intFromFloat(tw), .tagline_h = @intFromFloat(th) }, - }; - } -}; - -test "compact body layer rows fill reclaimed height and invert exact boundaries" { - const layer: Layer = .{ .serial = 7, .viewport = .{ .x = 4, .y = 3, .w = 40, .h = 10 }, .cols = 40, .rows = 15, .context_rows = 5 }; - try std.testing.expectEqual(@as(f32, 120), layer.rowTop(5, 20, 12)); - try std.testing.expectEqual(@as(f32, 240), layer.rowTop(11, 20, 12)); - try std.testing.expectEqual(@as(f32, 12), layer.rowHeight(4, 20, 12)); - try std.testing.expectEqual(@as(f32, 20), layer.rowHeight(5, 20, 12)); - for (0..12) |index| { - const row: u16 = @intCast(index); - const y = layer.rowTop(row, 20, 12) + layer.rowHeight(row, 20, 12) / 2; - const width: f32 = if (row < 5) 6 else 10; - const hit = layer.hitAt(40 + 3.5 * width, y, 10, 20, 6, 12).?; - try std.testing.expectEqual(row, hit.row); - try std.testing.expectEqual(@as(u16, 3 + config.GUTTER), hit.col); - } - try std.testing.expectEqual(@as(u16, 4), layer.hitAt(45, 119.99, 10, 20, 6, 12).?.row); - try std.testing.expectEqual(@as(u16, 5), layer.hitAt(45, 120, 10, 20, 6, 12).?.row); - try std.testing.expectEqual(@as(u16, 11), layer.hitAt(45, 259.99, 10, 20, 6, 12).?.row); - try std.testing.expect(layer.hitAt(45, 260, 10, 20, 6, 12) == null); - try std.testing.expect(layer.hitAt(39.99, 80, 10, 20, 6, 12) == null); - try std.testing.expect(layer.hitAt(std.math.nan(f32), 80, 10, 20, 6, 12) == null); -} - -test "compact context borders separate source gaps and preserve multiline headers" { - var layer: Layer = .{ .context_rows = 6 }; - layer.setContextLines(&.{ 3, 4, 8, 9, 10, 17 }); - const expected = [_]bool{ false, true, false, false, true, true, false }; - for (expected, 0..) |border, row| try std.testing.expectEqual(border, layer.hasContextBorderAfter(row)); - layer.context_rows = 2; - layer.setContextLines(&.{ 9, 10 }); - try std.testing.expect(!layer.hasContextBorderAfter(0)); - try std.testing.expect(layer.hasContextBorderAfter(1)); - try std.testing.expect(!layer.hasContextBorderAfter(4)); - try std.testing.expect(!layer.context_separators.isSet(4)); -} +const Layer = @import("Layer.zig"); // ---- drawing a pane body into the surface ---- @@ -305,7 +201,8 @@ pub fn joinBody(p: *Pardes, s: *Surface, arena: std.mem.Allocator, pane: *Pane, const start = (row + first_row) * r.w + config.GUTTER; @memcpy(layer.cells[row * width ..][0..width], temporary_cells[start..][0..width]); } - layer.pane = @intCast(id); + layer.kind = .body; + layer.id = @intCast(id); layer.serial = pane.serial; const body = s.region(.body, id).?; layer.viewport = .{ .x = body.rect.x, .y = body.rect.y, .w = body.rect.w - body.clip, .h = body.rect.h }; diff --git a/src/detached/client.zig b/src/detached/client.zig index 4468c961..3347f609 100644 --- a/src/detached/client.zig +++ b/src/detached/client.zig @@ -103,8 +103,10 @@ pub const Client = struct { grid: std.ArrayListUnmanaged(pardes.Cell) = .empty, cursor: ?wire.Cursor = null, pointer_shape: pardes.Surface.PointerShape = .arrow, - body_layers: [pardes.MAX_PANES]pardes.BodyLayer = @splat(.{}), - tag_layers: [pardes.MAX_TAG_LAYERS]pardes.TagLayer = @splat(.{}), + body_layers: [pardes.MAX_PANES]pardes.Layer = @splat(.{}), + tag_layers: [pardes.MAX_TAG_LAYERS]pardes.Layer = @splat(.{}), + /// The session's placed regions, as its last frame gave them. + regions: std.ArrayListUnmanaged(pardes.Region) = .empty, in: std.ArrayListUnmanaged(u8) = .empty, out: std.ArrayListUnmanaged(u8) = .empty, /// Bytes of `in` belonging to the message `next` returned last. Compacted at @@ -182,6 +184,7 @@ pub const Client = struct { layer.* = .{}; } for (&c.tag_layers) |*layer| c.gpa.free(layer.cells); + c.regions.deinit(c.gpa); c.in.deinit(c.gpa); c.out.deinit(c.gpa); } @@ -319,7 +322,7 @@ pub const Client = struct { try c.reshape(f.cols, f.rows); } try f.apply(c.grid.items); - f.applyLayers(c.gpa, &c.body_layers, &c.tag_layers) catch |err| return switch (err) { + f.applyLayers(c.gpa, &c.body_layers, &c.tag_layers, &c.regions) catch |err| return switch (err) { error.OutOfMemory => error.Closed, else => @as(wire.Error, @errorCast(err)), }; @@ -995,6 +998,12 @@ test "detached session: a frontend that dies takes nothing with it" { } test "detached session: a frontend speaking another protocol is refused, loudly" { + // The protocol before this one (v7 carried one-row tags and no regions) + // and the one after. + for ([_]u16{ wire.version - 1, wire.version + 1 }) |claimed| try refusedHello(claimed); +} + +fn refusedHello(claimed: u16) !void { var h: Harness = undefined; try h.init(60, 16); defer h.deinit(); @@ -1006,7 +1015,7 @@ test "detached session: a frontend speaking another protocol is refused, loudly" defer _ = libc.close(fd); var buf: [64]u8 = undefined; const hello = try wire.encodeClient(&buf, .{ - .hello = .{ .version = wire.version + 1, .cols = 60, .rows = 16 }, + .hello = .{ .version = claimed, .cols = 60, .rows = 16 }, }); try testing.expectEqual(@as(isize, @intCast(hello.len)), libc.send(fd, hello.ptr, hello.len, nosignal)); @@ -1024,6 +1033,17 @@ test "detached session: a frontend speaking another protocol is refused, loudly" try testing.expect(!h.core.quit); } +test "detached frontend: a session speaking another protocol is not attached to" { + for ([_]u16{ wire.version - 1, wire.version + 1 }) |claimed| { + var c: Client = .{ .gpa = testing.allocator }; + defer c.deinit(); + var buf: [64]u8 = undefined; + try c.in.appendSlice(testing.allocator, try wire.encodeServer(&buf, .{ .welcome = .{ .version = claimed, .slot = 0, .cols = 60, .rows = 16 } })); + try testing.expectError(error.Ungreeted, c.next()); + try testing.expect(!c.attached()); + } +} + test "detached session: a peer that sends garbage is dropped, not obeyed" { var h: Harness = undefined; try h.init(60, 16); @@ -1281,7 +1301,7 @@ fn pumpUntilNotice(h: *Harness, c: *Client, want: []const u8) !bool { try c.wait(5); while (try c.next()) |_| {} for (&c.tag_layers) |*layer| { - if (layer.cols == 0 or layer.kind != .notice) continue; + if (layer.rows == 0 or layer.kind != .notice) continue; var n: usize = 0; for (layer.cells[0..layer.cols]) |cell| { const g = cell.grapheme(); diff --git a/src/detached/server.zig b/src/detached/server.zig index 212c9a3d..46fb8fcf 100644 --- a/src/detached/server.zig +++ b/src/detached/server.zig @@ -739,7 +739,7 @@ pub const Session = struct { fn sendFrame(s: *Session, c: *Client, surface: *const pardes.Surface) void { const cells = surface.cells; - const want = wire.frameBound(surface.cols, surface.rows) + wire.layersBound(&surface.body_layers, &surface.tag_layers); + const want = wire.frameBound(surface.cols, surface.rows) + wire.layersBound(&surface.body_layers, &surface.tag_layers, surface.regionList()); s.scratch.ensureTotalCapacity(s.gpa, want) catch return s.close(c, .oom); const prev: []const pardes.Cell = if (c.need_full or c.mirror.items.len != cells.len) &.{} @@ -759,6 +759,7 @@ pub const Session = struct { prev, &surface.body_layers, &surface.tag_layers, + surface.regionList(), ) catch |err| { log.debug("frame {d}x{d} not encodable: {t}", .{ surface.cols, surface.rows, err }); return; diff --git a/src/detached/wire.zig b/src/detached/wire.zig index 94bd7f0b..684c869b 100644 --- a/src/detached/wire.zig +++ b/src/detached/wire.zig @@ -7,7 +7,9 @@ const limits = @import("../memory.zig").limits; /// 7: tag layers gained the `.notice` kind, so a frame can carry a tag value /// an older frontend would reject mid-session. The greeting is where that has /// to be refused, which is what this number is for. -pub const version: u16 = 7; +/// 8: one layer type: a tag band carries all its rows (not a layer per +/// line), and a frame carries the core's placed regions after its layers. +pub const version: u16 = 8; pub const Error = error{ Truncated, Overlong, BadTag, BadValue, Trailing, NoSpace }; @@ -167,7 +169,8 @@ pub const Frame = struct { nruns: u32, runs: []const u8, - pub fn applyLayers(f: Frame, gpa: std.mem.Allocator, layers: *[pardes.MAX_PANES]pardes.BodyLayer, tags: *[pardes.MAX_TAG_LAYERS]pardes.TagLayer) !void { + pub fn applyLayers(f: Frame, gpa: std.mem.Allocator, layers: *[pardes.MAX_PANES]pardes.Layer, tags: *[pardes.MAX_TAG_LAYERS]pardes.Layer, regions: *std.ArrayListUnmanaged(pardes.Region)) !void { + regions.clearRetainingCapacity(); for (layers) |*layer| { gpa.free(layer.cells); layer.* = .{}; @@ -191,13 +194,14 @@ pub const Frame = struct { const count = try r.getU16(); if (count > layers.len) return error.Overlong; for (layers[0..count]) |*layer| { - layer.pane = try r.getU16(); + layer.kind = .body; + layer.id = try r.getU16(); layer.serial = try r.getU32(); layer.viewport = .{ .x = try r.getU16(), .y = try r.getU16(), .w = try r.getU16(), .h = try r.getU16() }; layer.cols = try r.getU16(); layer.rows = try r.getU16(); layer.context_rows = try r.getU16(); - if (layer.pane >= pardes.MAX_PANES or layer.cols == 0 or layer.cols > f.cols or + if (layer.id >= pardes.MAX_PANES or layer.cols == 0 or layer.cols > f.cols or layer.rows == 0 or layer.rows > 2 * max_rows or layer.context_rows > layer.rows or layer.context_rows > limits.wrap_rows or layer.viewport.x > f.cols or layer.viewport.w > f.cols - layer.viewport.x or layer.viewport.y > f.rows or layer.viewport.h > f.rows - layer.viewport.y) return error.BadValue; @@ -217,19 +221,40 @@ pub const Frame = struct { layer.serial = try r.getU32(); layer.viewport = .{ .x = try r.getU16(), .y = try r.getU16(), .w = try r.getU16(), .h = try r.getU16() }; layer.cols = try r.getU16(); + layer.rows = try r.getU16(); for (&layer.bg) |*channel| channel.* = try r.getByte(); - if (layer.cols == 0 or layer.viewport.w == 0 or layer.viewport.h != 1 or + if (layer.cols == 0 or layer.viewport.w == 0 or layer.rows == 0 or layer.rows > pardes.MAX_TAG_ROWS or + layer.viewport.h != layer.rows or layer.viewport.x > f.cols or layer.viewport.w > f.cols - layer.viewport.x or - layer.viewport.y >= f.rows or (switch (layer.kind) { + layer.viewport.y >= f.rows or layer.viewport.h > f.rows - layer.viewport.y or (switch (layer.kind) { .workspace => layer.id != 0, .column => layer.id >= pardes.MAX_COLS, .pane, .notice => layer.id >= pardes.MAX_PANES, + .body => true, })) return error.BadValue; - const cursor = try getCursor(&r, layer.cols, 1); - layer.cursor = if (cursor) |c| .{ .col = c.x, .bar = c.bar } else null; - layer.cells = try gpa.alloc(pardes.Cell, layer.cols); + const cursor = try getCursor(&r, layer.cols, layer.rows); + layer.cursor = if (cursor) |c| .{ .x = c.x, .y = c.y, .bar = c.bar } else null; + layer.cells = try gpa.alloc(pardes.Cell, @as(usize, layer.cols) * layer.rows); for (layer.cells) |*cell| cell.* = try decodeCell(&r); } + const region_count = try r.getU16(); + if (region_count > pardes.MAX_REGIONS) return error.Overlong; + try regions.ensureTotalCapacity(gpa, region_count); + for (0..region_count) |_| { + var region: pardes.Region = .{ .kind = try r.getTag(pardes.Region.Kind), .rect = undefined }; + region.owner = try r.getByte(); + region.serial = try r.getU32(); + region.rect = .{ .x = try r.getU16(), .y = try r.getU16(), .w = try r.getU16(), .h = try r.getU16() }; + region.active = try r.getBool(); + region.thumb_y = try r.getU16(); + region.thumb_h = try r.getU16(); + region.notice = try r.getByte(); + region.clip = try r.getU16(); + if (region.rect.x > f.cols or region.rect.w > f.cols - region.rect.x or + region.rect.y > f.rows or region.rect.h > f.rows - region.rect.y or + region.clip > region.rect.w or region.thumb_y > region.rect.h or region.thumb_h > region.rect.h - region.thumb_y) return error.BadValue; + regions.appendAssumeCapacity(region); + } try r.end(); } @@ -672,21 +697,23 @@ pub fn encodeFramePointer( cells: []const pardes.Cell, prev: []const pardes.Cell, ) Error![]const u8 { - return encodeFrameLayers(out, cols, rows, cursor, pointer_shape, cells, prev, &.{}, &.{}); + return encodeFrameLayers(out, cols, rows, cursor, pointer_shape, cells, prev, &.{}, &.{}, &.{}); } -pub fn layersBound(layers: []const pardes.BodyLayer, tags: []const pardes.TagLayer) usize { - var n: usize = 4; +pub fn layersBound(layers: []const pardes.Layer, tags: []const pardes.Layer, regions: []const pardes.Region) usize { + var n: usize = 6; for (layers) |layer| if (layer.rows != 0) { n += 26 + layer.context_rows + layer.cells.len * cell_max; }; - for (tags) |layer| if (layer.cols != 0) { - n += 26 + layer.cells.len * cell_max; + for (tags) |layer| if (layer.rows != 0) { + n += 28 + layer.cells.len * cell_max; }; - return n; + return n + regions.len * region_len; } -pub fn encodeFrameLayers(out: []u8, cols: u16, rows: u16, cursor: ?Cursor, pointer_shape: pardes.Surface.PointerShape, cells: []const pardes.Cell, prev: []const pardes.Cell, layers: []const pardes.BodyLayer, tags: []const pardes.TagLayer) Error![]const u8 { +const region_len = 1 + 1 + 4 + 8 + 1 + 2 + 2 + 1 + 2; + +pub fn encodeFrameLayers(out: []u8, cols: u16, rows: u16, cursor: ?Cursor, pointer_shape: pardes.Surface.PointerShape, cells: []const pardes.Cell, prev: []const pardes.Cell, layers: []const pardes.Layer, tags: []const pardes.Layer, regions: []const pardes.Region) Error![]const u8 { // The protocol's ceiling, enforced by the ENCODER too, and BEFORE the // assert below so a caller can be told rather than tripped. `max_payload` // is derived from these two, so a larger grid is a frame this decoder @@ -708,7 +735,7 @@ pub fn encodeFrameLayers(out: []u8, cols: u16, rows: u16, cursor: ?Cursor, point const layers_len_at = w.n; try w.putU32(0); const layers_start = w.n; - if (layers.len != 0 or tags.len != 0) { + if (layers.len != 0 or tags.len != 0 or regions.len != 0) { var count: u16 = 0; for (layers) |layer| if (layer.rows != 0) { count += 1; @@ -717,7 +744,7 @@ pub fn encodeFrameLayers(out: []u8, cols: u16, rows: u16, cursor: ?Cursor, point for (layers) |layer| { if (layer.rows == 0) continue; if (layer.context_rows > limits.wrap_rows or layer.context_rows > layer.rows) return error.BadValue; - try w.putU16(layer.pane); + try w.putU16(layer.id); try w.putU32(layer.serial); try w.putU16(layer.viewport.x); try w.putU16(layer.viewport.y); @@ -731,13 +758,13 @@ pub fn encodeFrameLayers(out: []u8, cols: u16, rows: u16, cursor: ?Cursor, point for (layer.cells) |*cell| try putCell(&w, cell); } var tag_count: u16 = 0; - for (tags) |layer| if (layer.cols != 0) { + for (tags) |layer| if (layer.rows != 0) { tag_count += 1; }; try w.putU16(tag_count); for (tags) |layer| { - if (layer.cols == 0) continue; - if (layer.cells.len != layer.cols) return error.BadValue; + if (layer.rows == 0) continue; + if (layer.cells.len != @as(usize, layer.cols) * layer.rows) return error.BadValue; try w.putByte(@intFromEnum(layer.kind)); try w.putU16(layer.id); try w.putU32(layer.serial); @@ -746,10 +773,26 @@ pub fn encodeFrameLayers(out: []u8, cols: u16, rows: u16, cursor: ?Cursor, point try w.putU16(layer.viewport.w); try w.putU16(layer.viewport.h); try w.putU16(layer.cols); + try w.putU16(layer.rows); for (layer.bg) |channel| try w.putByte(channel); - try putCursor(&w, if (layer.cursor) |c| .{ .x = c.col, .y = 0, .bar = c.bar } else null, layer.cols, 1); + try putCursor(&w, if (layer.cursor) |c| .{ .x = c.x, .y = c.y, .bar = c.bar } else null, layer.cols, layer.rows); for (layer.cells) |*cell| try putCell(&w, cell); } + try w.putU16(@intCast(regions.len)); + for (regions) |region| { + try w.putByte(@intFromEnum(region.kind)); + try w.putByte(region.owner); + try w.putU32(region.serial); + try w.putU16(region.rect.x); + try w.putU16(region.rect.y); + try w.putU16(region.rect.w); + try w.putU16(region.rect.h); + try w.putBool(region.active); + try w.putU16(region.thumb_y); + try w.putU16(region.thumb_h); + try w.putByte(region.notice); + try w.putU16(region.clip); + } } std.mem.writeInt(u32, w.buf[layers_len_at..][0..4], @intCast(w.n - layers_start), .little); const nruns_at = w.n; @@ -1820,22 +1863,26 @@ test "detached wire carries compact body rows and exact pointer metrics" { var cells: [8]pardes.Cell = @splat(.{}); var logical: [12]pardes.Cell = @splat(.{}); logical[10] = .{ .text = "z".* ++ @as([6]u8, @splat(0)), .len = 1, .default = false }; - var layer: pardes.BodyLayer = .{ .pane = 0, .serial = 42, .viewport = .{ .x = 0, .y = 0, .w = 2, .h = 4 }, .cols = 2, .rows = 6, .context_rows = 2, .cells = &logical, .cursor = .{ .x = 0, .y = 5, .bar = true } }; + var layer: pardes.Layer = .{ .id = 0, .serial = 42, .viewport = .{ .x = 0, .y = 0, .w = 2, .h = 4 }, .cols = 2, .rows = 6, .context_rows = 2, .cells = &logical, .cursor = .{ .x = 0, .y = 5, .bar = true } }; layer.context_separators.set(0); var tag_cells: [3]pardes.Cell = @splat(.{}); tag_cells[2] = logical[10]; - const tag: pardes.TagLayer = .{ .kind = .column, .id = 1, .viewport = .{ .x = 0, .y = 0, .w = 2, .h = 1 }, .cols = 3, .bg = .{ 11, 22, 33 }, .cells = &tag_cells, .cursor = .{ .col = 2, .bar = true } }; - const out = try gpa.alloc(u8, frameBound(2, 4) + layersBound(&.{layer}, &.{tag})); + const tag: pardes.Layer = .{ .kind = .column, .id = 1, .viewport = .{ .x = 0, .y = 0, .w = 2, .h = 1 }, .cols = 3, .rows = 1, .bg = .{ 11, 22, 33 }, .cells = &tag_cells, .cursor = .{ .x = 2, .y = 0, .bar = true } }; + const placed = [_]pardes.Region{.{ .kind = .rail, .owner = 3, .serial = 42, .rect = .{ .x = 0, .y = 1, .w = 2, .h = 3 }, .active = true, .thumb_y = 1, .thumb_h = 2, .clip = 1 }}; + const out = try gpa.alloc(u8, frameBound(2, 4) + layersBound(&.{layer}, &.{tag}, &placed)); defer gpa.free(out); - const encoded = try encodeFrameLayers(out, 2, 4, null, .link, &cells, &cells, &.{layer}, &.{tag}); + const encoded = try encodeFrameLayers(out, 2, 4, null, .link, &cells, &cells, &.{layer}, &.{tag}, &placed); const packet = (try framed(encoded)).?; const frame = (try decodeServer(packet.tag, packet.payload)).frame; - var decoded: [pardes.MAX_PANES]pardes.BodyLayer = @splat(.{}); - var tags: [pardes.MAX_TAG_LAYERS]pardes.TagLayer = @splat(.{}); + var decoded: [pardes.MAX_PANES]pardes.Layer = @splat(.{}); + var tags: [pardes.MAX_TAG_LAYERS]pardes.Layer = @splat(.{}); defer for (&tags) |*item| gpa.free(item.cells); defer for (&decoded) |*item| gpa.free(item.cells); try frame.apply(&cells); - try frame.applyLayers(gpa, &decoded, &tags); + var regions: std.ArrayListUnmanaged(pardes.Region) = .empty; + defer regions.deinit(gpa); + try frame.applyLayers(gpa, &decoded, &tags, ®ions); + try std.testing.expectEqualDeep(placed[0..], regions.items); try std.testing.expectEqual(@as(u16, 6), decoded[0].rows); try std.testing.expect(decoded[0].context_separators.isSet(0)); try std.testing.expect(!decoded[0].context_separators.isSet(1)); @@ -1847,10 +1894,10 @@ test "detached wire carries compact body rows and exact pointer metrics" { try std.testing.expectEqual(tag.id, tags[0].id); try std.testing.expectEqual(tag.bg, tags[0].bg); try std.testing.expectEqual(tag.cols, tags[0].cols); - try std.testing.expectEqual(@as(u16, 2), tags[0].cursor.?.col); + try std.testing.expectEqual(@as(u16, 2), tags[0].cursor.?.x); try std.testing.expectEqualStrings("z", tags[0].cells[2].grapheme()); - const pointer = layer.hitAt(4, 27, 8, 16, 6, 8).?; - const tag_pointer = tag.hitAt(11, 8, 8, 16, 4, 8).?; + const pointer = layer.bodyHit(4, 27, 8, 16, 6, 8).?; + const tag_pointer = tag.tagHit(11, 8, 8, 16, 4, 8).?; const message: ClientMsg = .{ .event = .{ .mouse = .{ .col = 0, .row = 1, .button = .left, .kind = .press, .body_hit = pointer, .tag_hit = tag_pointer } } }; var mouse_bytes: [256]u8 = undefined; const mouse_encoded = try encodeClient(&mouse_bytes, message); @@ -1861,19 +1908,20 @@ test "detached wire carries compact body rows and exact pointer metrics" { try std.testing.expect(mouse_encoded.len <= clientBound(message)); var truncated = frame; truncated.layers = frame.layers[0 .. frame.layers.len - 1]; - try std.testing.expectError(error.Truncated, truncated.applyLayers(gpa, &decoded, &tags)); + try std.testing.expectError(error.Truncated, truncated.applyLayers(gpa, &decoded, &tags, ®ions)); for (decoded) |item| { try std.testing.expectEqual(@as(u16, 0), item.rows); try std.testing.expectEqual(@as(usize, 0), item.cells.len); try std.testing.expectEqual(@as(usize, 0), item.context_separators.count()); } for (tags) |item| { - try std.testing.expectEqual(@as(u16, 0), item.cols); + try std.testing.expectEqual(@as(u16, 0), item.rows); try std.testing.expectEqual(@as(usize, 0), item.cells.len); } + try std.testing.expectEqual(@as(usize, 0), regions.items.len); const no_layers = try encodeFramePointer(out, 2, 4, null, .arrow, &cells, &cells); const cleared_packet = (try framed(no_layers)).?; const cleared = (try decodeServer(cleared_packet.tag, cleared_packet.payload)).frame; - try cleared.applyLayers(gpa, &decoded, &tags); + try cleared.applyLayers(gpa, &decoded, &tags, ®ions); try std.testing.expectEqual(@as(u16, 0), decoded[0].rows); } diff --git a/src/draw.zig b/src/draw.zig index 7d91ad31..7cfe7554 100644 --- a/src/draw.zig +++ b/src/draw.zig @@ -28,7 +28,7 @@ const Pane = panes.Pane; const Text = panes.Text; const Rect = layout.Rect; const Region = @import("surface.zig").Region; -const TagKind = @import("tag_layer.zig").Kind; +const TagKind = @import("Layer.zig").Kind; const pdf_enabled = panes.Pdf.enabled; const wordBoundsAtCol = pardes.wordBoundsAtCol; const BOX_H = pardes.BOX_H; @@ -40,8 +40,6 @@ const MAX_PANES = pardes.MAX_PANES; const MAX_COLS = pardes.MAX_COLS; const MAX_TAG_ROWS = pardes.MAX_TAG_ROWS; const NOTICE_LAYER_BASE = pardes.NOTICE_LAYER_BASE; -const TAG_LINE_LAYER_BASE = pardes.TAG_LINE_LAYER_BASE; -const HEADER_LINE_LAYER_BASE = pardes.HEADER_LINE_LAYER_BASE; /// Where every part of the frame goes, decided once before anything is /// painted: the page; each pane's grip, tag, body, rail (with its thumb) @@ -172,7 +170,7 @@ pub fn render(p: *Pardes, arena: std.mem.Allocator) !*Surface { // never set. for (s.cells) |*c| c.hover = false; for (&s.body_layers) |*layer| layer.rows = 0; - for (&s.tag_layers) |*layer| layer.cols = 0; + for (&s.tag_layers) |*layer| layer.rows = 0; s.nimages = 0; s.npanel_tracks = 0; s.previous_cells = &.{}; @@ -505,11 +503,9 @@ pub fn paintHeaders(p: *Pardes, s: *Surface, arena: std.mem.Allocator) !void { tagline.revealHeader(p); if (s.region(.workspace_tag, Region.none)) |region| { const top = if (p.header_focus and p.header_column == null) p.header_top else 0; - for (0..region.rect.h) |line| { - const index = if (line == 0) MAX_PANES + MAX_COLS else HEADER_LINE_LAYER_BASE + MAX_COLS * (MAX_TAG_ROWS - 1) + line - 1; - try renderHeaderLayer(p, arena, index, .workspace, 0, @intCast(line), .{ .x = region.rect.x, .y = region.rect.y + @as(u16, @intCast(line)), .w = region.rect.w, .h = TOPBAR_H }, modal.lineSlice(tagline.topbar(p), line + top), chrome.tag_bg, chrome.tag_fg); - joinHeaderLine(s, &s.tag_layers[index], chrome.tag_fg); - } + const layer = &s.tag_layers[MAX_PANES + MAX_COLS]; + try renderHeaderLayer(p, arena, layer, .workspace, 0, region.rect, tagline.topbar(p), top, chrome.tag_bg, chrome.tag_fg); + joinHeaderRows(s, layer, chrome.tag_fg); } const column_rows = p.columnBarHeight(); if (column_rows > 0) for (0..p.ncol) |c| { @@ -531,23 +527,21 @@ pub fn paintHeaders(p: *Pardes, s: *Surface, arena: std.mem.Allocator) !void { s.fill(p.col_x[c] + grip, region.rect.y, inset - grip, column_rows, .{ .bg = .{ .rgb = bg }, .font_role = .tagline }); } const top = if (p.header_focus and p.header_column == c) p.header_top else 0; - for (0..column_rows) |line| { - const index = if (line == 0) MAX_PANES + c else HEADER_LINE_LAYER_BASE + c * (MAX_TAG_ROWS - 1) + line - 1; - try renderHeaderLayer(p, arena, index, .column, @intCast(c), @intCast(line), .{ .x = region.rect.x, .y = region.rect.y + @as(u16, @intCast(line)), .w = region.rect.w, .h = COLBAR_H }, modal.lineSlice(tagline.columnTag(p, c), line + top), bg, fg); - if (p.col_x[c] < s.cols) joinHeaderLine(s, &s.tag_layers[index], fg); - // Laid out at its full width; only shown short of the rail. - s.tag_layers[index].viewport.w -= region.clip; - } + const layer = &s.tag_layers[MAX_PANES + c]; + try renderHeaderLayer(p, arena, layer, .column, @intCast(c), region.rect, tagline.columnTag(p, c), top, bg, fg); + if (p.col_x[c] < s.cols) joinHeaderRows(s, layer, fg); + // Laid out at its full width; only shown short of the rail. + layer.viewport.w -= region.clip; }; } -/// Copy a header line's layer into the grid under it, and its caret. -fn joinHeaderLine(s: *Surface, layer: *const pardes.TagLayer, fg: [3]u8) void { +/// Copy a header's layer into the grid under it, row by row, and its caret. +fn joinHeaderRows(s: *Surface, layer: *const pardes.Layer, fg: [3]u8) void { const v = layer.viewport; const w = @min(v.w, s.cols -| v.x); - joinCells(s, v.x, v.y, layer.cells[0..layer.cols], 0, w, .{ .rgb = fg }); + for (0..layer.rows) |line| joinCells(s, v.x, v.y + @as(u16, @intCast(line)), layer.cells[line * layer.cols ..][0..layer.cols], 0, w, .{ .rgb = fg }); if (layer.cursor) |caret| { - if (caret.col < v.w) s.cursor = .{ .x = v.x + caret.col, .y = v.y, .bar = caret.bar }; + if (caret.x < v.w) s.cursor = .{ .x = v.x + caret.x, .y = v.y + caret.y, .bar = caret.bar }; } } @@ -600,77 +594,85 @@ fn tagTintRange(pane: *const Pane, tag: []const u8, prefix_len: usize) ?struct { return .{ .lo = start + basename, .hi = start + name.len }; } -/// One row of a header or a notice band as a tag layer: `text` is line -/// `line` of what it shows. -fn renderHeaderLayer(p: *Pardes, arena: std.mem.Allocator, index: usize, kind: TagKind, id: u16, line: u16, viewport: Rect, text: []const u8, bg: [3]u8, fg: [3]u8) !void { +/// A header or a notice band as a tag layer: `viewport.h` rows, line `top` +/// of `text` and on, laid out at the tagline's pitch -- as wide as its +/// widest line and never narrower than its viewport. +fn renderHeaderLayer(p: *Pardes, arena: std.mem.Allocator, layer: *pardes.Layer, kind: TagKind, id: u16, viewport: Rect, text: []const u8, top: usize, bg: [3]u8, fg: [3]u8) !void { _ = arena; - const layer = &p.surface.tag_layers[index]; - if (viewport.w == 0) { - layer.cols = 0; + if (viewport.w == 0 or viewport.h == 0) { + layer.rows = 0; return; } - const columns: u16 = @intCast(@min(std.math.maxInt(u16), @max(p.tagCapacity(viewport.w), panes.File.displayWidth(text) + 1))); - if (layer.cells.len != columns) layer.cells = try p.gpa.realloc(layer.cells, columns); + var widest: usize = 0; + for (0..viewport.h) |line| widest = @max(widest, panes.File.displayWidth(modal.lineSlice(text, line + top))); + const columns: u16 = @intCast(@min(std.math.maxInt(u16), @max(p.tagCapacity(viewport.w), widest + 1))); + const count = @as(usize, columns) * viewport.h; + if (layer.cells.len != count) layer.cells = try p.gpa.realloc(layer.cells, count); layer.kind = kind; layer.id = id; - layer.line = line; layer.serial = if (kind == .column) p.col_serial[id] else 0; layer.viewport = viewport; layer.cols = columns; + layer.rows = viewport.h; + layer.context_rows = 0; layer.bg = bg; layer.cursor = null; layer.slide = 0; layer.fade = 1; - var surface: Surface = .{ .cols = columns, .rows = 1, .cells = layer.cells }; // A notice band carries a PANE id, not a column index, so it must not // answer to the column being edited -- that would scroll and select // its text with the column tag's offsets and give it a second caret. const editing: ?*Text = if (p.header_focus and switch (kind) { .workspace => p.header_column == null, .column => p.header_column == id, - .pane, .notice => false, + .pane, .notice, .body => false, }) tagline.focusedHeader(p) else null; const scroll = if (editing != null) p.header_scroll else 0; - surface.fill(0, 0, columns, 1, .{ .bg = .{ .rgb = bg }, .font_role = .tagline }); - _ = surface.print(0, 0, columns, text[panes.File.rawAtDisplay(text, scroll)..], .{ .fg = .{ .rgb = fg }, .bg = .{ .rgb = bg }, .font_role = .tagline }); - // The word under the pointer: on a header even while it is edited, but - // not on a notice (a message is not a command line), nor on a column a - // carried column's pointer is aiming at a place over. - const hovered = p.pointer_inside and kind != .notice and !(kind == .column and p.drag == .column_move); - if (hovered) { - const tag_hit = p.pointer_tag_hit; - const col: ?usize = if (tag_hit) |pointer| - (if (pointer.kind == kind and pointer.id == id and pointer.line == line) pointer.col else null) - else if (p.hover_row == viewport.y and p.hover_col >= viewport.x and p.hover_col - viewport.x < viewport.w) - p.hover_col - viewport.x - else - null; - if (col) |hover| if (wordBoundsAtCol(text, panes.File.rawAtDisplay(text, hover + scroll))) |bounds| { - var cell = panes.File.rawDisplayCol(text, bounds.lo) -| scroll; - const end = panes.File.rawDisplayCol(text, bounds.hi) -| scroll; - while (cell < end and cell < columns) : (cell += 1) { - surface.at(@intCast(cell), 0).style.bg = .{ .rgb = p.theme().sel_bg }; - surface.at(@intCast(cell), 0).style.fg = .{ .rgb = p.theme().sel_fg }; - } - }; - } - if (editing) |t| { - if (tagline.headerSelection(t, try edit.flatSurface(p, t), line + p.header_top)) |span| { - var col = panes.File.rawDisplayCol(text, span.lo) -| scroll; - const end = panes.File.rawDisplayCol(text, span.hi) -| scroll; - while (col < end and col < columns) : (col += 1) { - surface.at(@intCast(col), 0).style.bg = .{ .rgb = p.theme().sel_bg }; - surface.at(@intCast(col), 0).style.fg = .{ .rgb = p.theme().sel_fg }; + for (0..viewport.h) |index| { + const line: u16 = @intCast(index); + const shown = modal.lineSlice(text, index + top); + var surface: Surface = .{ .cols = columns, .rows = 1, .cells = layer.cells[index * columns ..][0..columns] }; + surface.fill(0, 0, columns, 1, .{ .bg = .{ .rgb = bg }, .font_role = .tagline }); + _ = surface.print(0, 0, columns, shown[panes.File.rawAtDisplay(shown, scroll)..], .{ .fg = .{ .rgb = fg }, .bg = .{ .rgb = bg }, .font_role = .tagline }); + // The word under the pointer: on a header even while it is edited, + // but not on a notice (a message is not a command line), nor on a + // column a carried column's pointer is aiming at a place over. + const hovered = p.pointer_inside and kind != .notice and !(kind == .column and p.drag == .column_move); + if (hovered) { + const tag_hit = p.pointer_tag_hit; + const col: ?usize = if (tag_hit) |pointer| + (if (pointer.kind == kind and pointer.id == id and pointer.line == line) pointer.col else null) + else if (p.hover_row == viewport.y + line and p.hover_col >= viewport.x and p.hover_col - viewport.x < viewport.w) + p.hover_col - viewport.x + else + null; + if (col) |hover| if (wordBoundsAtCol(shown, panes.File.rawAtDisplay(shown, hover + scroll))) |bounds| { + var cell = panes.File.rawDisplayCol(shown, bounds.lo) -| scroll; + const end = panes.File.rawDisplayCol(shown, bounds.hi) -| scroll; + while (cell < end and cell < columns) : (cell += 1) { + surface.at(@intCast(cell), 0).style.bg = .{ .rgb = p.theme().sel_bg }; + surface.at(@intCast(cell), 0).style.fg = .{ .rgb = p.theme().sel_fg }; + } + }; + } + if (editing) |t| { + if (tagline.headerSelection(t, try edit.flatSurface(p, t), line + p.header_top)) |span| { + var col = panes.File.rawDisplayCol(shown, span.lo) -| scroll; + const end = panes.File.rawDisplayCol(shown, span.hi) -| scroll; + while (col < end and col < columns) : (col += 1) { + surface.at(@intCast(col), 0).style.bg = .{ .rgb = p.theme().sel_bg }; + surface.at(@intCast(col), 0).style.fg = .{ .rgb = p.theme().sel_fg }; + } } + const caret = panes.File.rawDisplayCol(shown, @min(@as(usize, @intCast(@max(0, t.cur_col))), shown.len)) -| scroll; + const asking = if (p.panes[p.active]) |active| active.prompt != .none else false; + if (!asking and t.cur_row == line + p.header_top and caret < columns) layer.cursor = .{ .x = @intCast(caret), .y = line, .bar = t.mode == .insert }; } - const caret = panes.File.rawDisplayCol(text, @min(@as(usize, @intCast(@max(0, t.cur_col))), text.len)) -| scroll; - const asking = if (p.panes[p.active]) |active| active.prompt != .none else false; - if (!asking and t.cur_row == line + p.header_top and caret < columns) layer.cursor = .{ .col = @intCast(caret), .bar = t.mode == .insert }; } } -/// A pane's tag rows, painted once into their layers, a layer to a line, -/// and copied into the grid; the grid's caret where the layer has it. +/// A pane's tag rows, painted once into their layer, a row to a line, and +/// copied into the grid; the grid's caret where the layer has it. fn joinPaneTag(p: *Pardes, s: *Surface, arena: std.mem.Allocator, pane: *Pane, r: Rect, id: usize, active: bool) !void { const capacity = p.tagCapacity(r.w -| TAG_TEXT_INSET); // Too narrow for a layer: only the grid's gap cell. @@ -692,23 +694,26 @@ fn joinPaneTag(p: *Pardes, s: *Surface, arena: std.mem.Allocator, pane: *Pane, r var temporary: Surface = .{ .cols = columns + TAG_TEXT_INSET, .rows = rows, .cells = storage }; try paintPaneTag(p, &temporary, arena, pane, .{ .x = 0, .y = 0, .w = columns + TAG_TEXT_INSET, .h = rows }, id, active, capacity); const tag_fg: Color = .{ .rgb = if (active and p.settings.focus_tint) chrome.tag_active_fg else chrome.tag_fg }; - // A layer to a line: the first in the pane's own slot, the rest in the - // slots kept for the lines of taller tags. + // One layer, a row to each line the tag shows. + const layer = &s.tag_layers[id]; + const count = @as(usize, columns) * rows; + if (layer.cells.len != count) layer.cells = try p.gpa.realloc(layer.cells, count); + layer.kind = .pane; + layer.id = @intCast(id); + layer.serial = pane.serial; + layer.viewport = .{ .x = region.rect.x + TAG_GAP, .y = region.rect.y, .w = region.rect.w - TAG_GAP - region.clip, .h = rows }; + layer.cols = columns; + layer.rows = rows; + layer.context_rows = 0; + layer.bg = if (active and p.settings.focus_tint) chrome.tag_active_bg else chrome.tag_bg; + layer.slide = 0; + layer.fade = 1; + layer.cursor = if (p.header_focus) null else if (temporary.cursor) |cursor| + .{ .x = cursor.x - TAG_TEXT_INSET, .y = cursor.y, .bar = cursor.bar } + else + null; for (0..rows) |line| { - const layer = &s.tag_layers[if (line == 0) id else TAG_LINE_LAYER_BASE + id * (MAX_TAG_ROWS - 1) + line - 1]; - if (layer.cells.len != columns) layer.cells = try p.gpa.realloc(layer.cells, columns); - @memcpy(layer.cells, storage[line * pitch + TAG_TEXT_INSET ..][0..columns]); - layer.kind = .pane; - layer.id = @intCast(id); - layer.serial = pane.serial; - layer.line = @intCast(line); - layer.viewport = .{ .x = region.rect.x + TAG_GAP, .y = region.rect.y + @as(u16, @intCast(line)), .w = region.rect.w - TAG_GAP - region.clip, .h = BOX_H }; - layer.cols = columns; - layer.bg = if (active and p.settings.focus_tint) chrome.tag_active_bg else chrome.tag_bg; - layer.cursor = if (p.header_focus) null else if (temporary.cursor) |cursor| - (if (cursor.y == line) .{ .col = cursor.x - TAG_TEXT_INSET, .bar = cursor.bar } else null) - else - null; + @memcpy(layer.cells[line * columns ..][0..columns], storage[line * pitch + TAG_TEXT_INSET ..][0..columns]); // The grid's row: the gap cell and the text, as far as the pane. joinCells(s, region.rect.x, region.rect.y + @as(u16, @intCast(line)), storage[line * pitch ..][0..pitch], config.GUTTER, region.rect.w, tag_fg); } @@ -765,9 +770,8 @@ fn joinNotice(p: *Pardes, s: *Surface, arena: std.mem.Allocator, region: Region) const line = try arena.alloc(u8, pad + kept.len); @memset(line[0..pad], ' '); @memcpy(line[pad..], kept); - const index = NOTICE_LAYER_BASE + id * Pane.Notices.max + i; - try renderHeaderLayer(p, arena, index, .notice, @intCast(id), 0, region.rect, line, bg, fg); - const layer = &s.tag_layers[index]; + const layer = &s.tag_layers[NOTICE_LAYER_BASE + id * Pane.Notices.max + i]; + try renderHeaderLayer(p, arena, layer, .notice, @intCast(id), region.rect, line, 0, bg, fg); layer.slide = motion.slide; layer.fade = motion.alpha; // The caret rides the band, where the prompt's glyphs are. @@ -775,7 +779,7 @@ fn joinNotice(p: *Pardes, s: *Surface, arena: std.mem.Allocator, region: Region) const typed = panes.File.displayWidth(text[0..@min(@as(usize, @intCast(@max(0, pane.input.cur_col))), text.len)]); const dropped = shown - panes.File.displayWidth(kept); if (typed < dropped) break :caret; - layer.cursor = .{ .col = @intCast(pad + typed - dropped), .bar = pane.input.mode == .insert }; + layer.cursor = .{ .x = @intCast(pad + typed - dropped), .y = 0, .bar = pane.input.mode == .insert }; } // The grid shows the chip's last cells of the band, where the text ends // (all of it where the tagline's pitch is the grid's). @@ -785,7 +789,7 @@ fn joinNotice(p: *Pardes, s: *Surface, arena: std.mem.Allocator, region: Region) // no ink of its own (the layer prints it as spaces in the band's ink). for (skip..@min(pad, skip + chip)) |col| s.at(region.rect.x + @as(u16, @intCast(col - skip)), region.rect.y).style.fg = .default; if (layer.cursor) |caret| { - if (caret.col >= skip) s.cursor = .{ .x = region.rect.x + caret.col - @as(u16, @intCast(skip)), .y = region.rect.y, .bar = caret.bar }; + if (caret.x >= skip) s.cursor = .{ .x = region.rect.x + caret.x - @as(u16, @intCast(skip)), .y = region.rect.y, .bar = caret.bar }; } // Laid out at its full width; only shown short of the rail. layer.viewport.w -= region.clip; @@ -960,10 +964,11 @@ test "place puts every part where the painters and layers put it, in every layou try std.testing.expectEqual(FontRole.tagline, s.at(grip.rect.x, grip.rect.y).style.font_role); const tag = s.region(.tag, id).?; try std.testing.expectEqual(Rect{ .x = r.x + config.GUTTER, .y = p.tagTop(pane, r), .w = r.w - config.GUTTER, .h = pane.tag_rows }, tag.rect); - if (r.w > TAG_TEXT_INSET) for (0..pane.tag_rows) |line| { - const layer = &s.tag_layers[if (line == 0) id else TAG_LINE_LAYER_BASE + id * (MAX_TAG_ROWS - 1) + line - 1]; - try std.testing.expectEqual(Rect{ .x = r.x + TAG_TEXT_INSET, .y = p.tagTop(pane, r) + @as(u16, @intCast(line)), .w = r.w - TAG_TEXT_INSET, .h = BOX_H }, layer.viewport); - }; + // One layer, a row to each line of the tag. + if (r.w > TAG_TEXT_INSET) { + try std.testing.expectEqual(Rect{ .x = r.x + TAG_TEXT_INSET, .y = p.tagTop(pane, r), .w = r.w - TAG_TEXT_INSET, .h = pane.tag_rows }, s.tag_layers[id].viewport); + try std.testing.expectEqual(pane.tag_rows, s.tag_layers[id].rows); + } if (pane.collapsed) { try std.testing.expect(s.region(.body, id) == null); try std.testing.expect(s.region(.rail, id) == null); diff --git a/src/edit.zig b/src/edit.zig index b2d71ed2..9044d7ed 100644 --- a/src/edit.zig +++ b/src/edit.zig @@ -17,7 +17,7 @@ const platform = pardes.platform; const Pane = panes.Pane; const Text = panes.Text; const tag_layer = @import("tag_layer.zig"); -const TagHit = tag_layer.Hit; +const TagHit = pardes.TagHit; const BOX_H = pardes.BOX_H; const TAG_TEXT_INSET = pardes.TAG_TEXT_INSET; const Mouse = pardes.Mouse; diff --git a/src/gui/gui.zig b/src/gui/gui.zig index a1e21dc0..ff99bd39 100644 --- a/src/gui/gui.zig +++ b/src/gui/gui.zig @@ -1779,8 +1779,8 @@ const Gui = struct { tagline_percent: u8, tagline_width: u32, tagline_height: u32, - attached_layers: ?*const [pardes.MAX_PANES]pardes.BodyLayer = null, - attached_tag_layers: ?*const [pardes.MAX_TAG_LAYERS]pardes.TagLayer = null, + attached_layers: ?*const [pardes.MAX_PANES]pardes.Layer = null, + attached_tag_layers: ?*const [pardes.MAX_TAG_LAYERS]pardes.Layer = null, cell_w: u32, cell_h: u32, ascent: i32, @@ -3517,7 +3517,7 @@ fn gridCellAtDimensions( var point: MouseCell = .{ .col = @intFromFloat(@min(@floor(@max(x, 0) / @max(body_w, 1)), 10_000)), .row = row }; if (core) |p| if (p.presentation.pointerFractional(p.screen_w, p.screen_h, x / @max(body_w, 1), y / @max(body_h, 1))) |mapped| { for (p.surface.tagLayers()) |*layer| { - if (layer.hitAt(mapped.x * body_w, mapped.y * body_h, body_w, body_h, tagline_w, @floatFromInt(p.row_metrics.tagline_h))) |hit| { + if (layer.tagHit(mapped.x * body_w, mapped.y * body_h, body_w, body_h, tagline_w, @floatFromInt(p.row_metrics.tagline_h))) |hit| { point.tag_hit = hit; break; } @@ -3529,19 +3529,19 @@ fn gridCellAtDimensions( fn gridCellAtPixels(g: *const Gui, core: ?*const pardes.Pardes, x: f32, y: f32) MouseCell { var point = gridCellAtDimensions(core, x, y, @floatFromInt(g.cell_w), @floatFromInt(g.cell_h), @floatFromInt(g.tagline_width)); if (core) |p| if (p.presentation.pointerFractional(p.screen_w, p.screen_h, x / @as(f32, @floatFromInt(g.cell_w)), y / @as(f32, @floatFromInt(g.cell_h)))) |mapped| for (p.surface.bodyLayers()) |*layer| { - if (layer.hitAt(mapped.x * @as(f32, @floatFromInt(g.cell_w)), mapped.y * @as(f32, @floatFromInt(g.cell_h)), @floatFromInt(g.cell_w), @floatFromInt(g.cell_h), @floatFromInt(g.tagline_width), @floatFromInt(g.tagline_height))) |hit| { + if (layer.bodyHit(mapped.x * @as(f32, @floatFromInt(g.cell_w)), mapped.y * @as(f32, @floatFromInt(g.cell_h)), @floatFromInt(g.cell_w), @floatFromInt(g.cell_h), @floatFromInt(g.tagline_width), @floatFromInt(g.tagline_height))) |hit| { point.body_hit = hit; break; } }; if (core == null) if (g.attached_layers) |layers| for (layers) |*layer| { - if (layer.hitAt(x, y, @floatFromInt(g.cell_w), @floatFromInt(g.cell_h), @floatFromInt(g.tagline_width), @floatFromInt(g.tagline_height))) |body_hit| { + if (layer.bodyHit(x, y, @floatFromInt(g.cell_w), @floatFromInt(g.cell_h), @floatFromInt(g.tagline_width), @floatFromInt(g.tagline_height))) |body_hit| { point.body_hit = body_hit; break; } }; if (core == null) if (g.attached_tag_layers) |layers| for (layers) |*layer| { - if (layer.hitAt(x, y, @floatFromInt(g.cell_w), @floatFromInt(g.cell_h), @floatFromInt(g.tagline_width), @floatFromInt(g.tagline_height))) |hit| { + if (layer.tagHit(x, y, @floatFromInt(g.cell_w), @floatFromInt(g.cell_h), @floatFromInt(g.tagline_width), @floatFromInt(g.tagline_height))) |hit| { point.tag_hit = hit; break; } @@ -5203,18 +5203,18 @@ fn renderFrame( } } for (surface.tagLayers()) |*layer| { - if (layer.cols == 0) continue; + if (layer.rows == 0) continue; const batch = &paint_plan.batches[paintBatchAt(&paint_plan, layer.viewport.x, layer.viewport.y)]; - batch.cell_count += tagLayerCellCount(g, layer) + 1; + batch.cell_count += (tagLayerCellCount(g, layer) + 1) * layer.rows; } for (paint_plan.batches[1..paint_plan.len], 1..) |batch, batch_index| { const track = batch.track.?; const under = track.effect == .vertical and track.phase == .opening; if (!under and track.phase != .closing and track.effect != .dissolve) continue; for (surface.previous_tag_layers) |*layer| { - if (layer.cols == 0 or layer.kind != .pane or layer.serial != track.serial) continue; + if (layer.rows == 0 or layer.kind != .pane or layer.serial != track.serial) continue; const destination = if (under) &paint_plan.batches[0] else &paint_plan.batches[batch_index]; - destination.cell_count += tagLayerCellCount(g, layer) + 1; + destination.cell_count += (tagLayerCellCount(g, layer) + 1) * layer.rows; } } var cell_next: [pardes.MAX_PANES * 2 + 1]u32 = @splat(0); @@ -5303,7 +5303,7 @@ fn renderFrame( emitBodyLayer(g, instances, &cell_next[batch_index], layer, win_w, win_h, paint_plan.batches[batch_index].track, page, paint_plan.len == 1, false, topbar_pane_border_rgb); } for (surface.tagLayers()) |*layer| { - if (layer.cols == 0) continue; + if (layer.rows == 0) continue; const batch_index = paintBatchAt(&paint_plan, layer.viewport.x, layer.viewport.y); emitTagLayer(g, instances, &cell_next[batch_index], layer, win_w, win_h, paint_plan.batches[batch_index].track, page, paint_plan.len == 1, false); } @@ -5312,7 +5312,7 @@ fn renderFrame( const under = track.effect == .vertical and track.phase == .opening; if (!under and track.phase != .closing and track.effect != .dissolve) continue; for (surface.previous_tag_layers) |*layer| { - if (layer.cols == 0 or layer.kind != .pane or layer.serial != track.serial) continue; + if (layer.rows == 0 or layer.kind != .pane or layer.serial != track.serial) continue; const destination: usize = if (under) 0 else batch_index; emitTagLayer(g, instances, &cell_next[destination], layer, win_w, win_h, if (under) null else track, page, false, track.effect == .dissolve); } @@ -5621,10 +5621,10 @@ test "compact column and pane underlays share focus tint without tinting the glo try std.testing.expectEqual(chrome.tag_bg, taglineBaseRgb(core, active.x, pardes.TOPBAR_H)); } -fn tagLayerIn(layers: []const pardes.TagLayer, col: u16, row: u16) ?*const pardes.TagLayer { +fn tagLayerIn(layers: []const pardes.Layer, col: u16, row: u16) ?*const pardes.Layer { for (layers) |*layer| { const r = layer.viewport; - if (layer.cols > 0 and row == r.y and col >= r.x and col - r.x < r.w) return layer; + if (layer.rows > 0 and row >= r.y and row - r.y < layer.rows and col >= r.x and col - r.x < r.w) return layer; } return null; } @@ -5633,9 +5633,9 @@ fn tagLayerIn(layers: []const pardes.TagLayer, col: u16, row: u16) ?*const parde /// themselves: the grid's cell loops skip them. Filling each layer's rectangle /// once replaces scanning every layer for every cell, which was a third of the /// gui's CPU on a full screen of text. It marks exactly the cells bodyLayerIn -/// and tagLayerIn find a layer for: a tag layer covers only its viewport's -/// first row, and a viewport past the grid covers the grid's part of it. -fn coverLayers(cover: []bool, cols: u16, rows: u16, body_layers: []const pardes.BodyLayer, tag_layers: []const pardes.TagLayer) void { +/// and tagLayerIn find a layer for: a tag layer covers its rows, and a +/// viewport past the grid covers the grid's part of it. +fn coverLayers(cover: []bool, cols: u16, rows: u16, body_layers: []const pardes.Layer, tag_layers: []const pardes.Layer) void { @memset(cover, false); for (body_layers) |*layer| { const r = layer.viewport; @@ -5647,12 +5647,13 @@ fn coverLayers(cover: []bool, cols: u16, rows: u16, body_layers: []const pardes. for (tag_layers) |*layer| { const r = layer.viewport; const right = @min(cols, @as(u32, r.x) + r.w); - if (layer.cols == 0 or r.y >= rows or r.x >= right) continue; - @memset(cover[@as(usize, r.y) * cols ..][r.x..right], true); + if (layer.rows == 0 or r.x >= right) continue; + var y: u32 = r.y; + while (y < @min(rows, @as(u32, r.y) + layer.rows)) : (y += 1) @memset(cover[y * cols ..][r.x..right], true); } } -fn expectCoverIsScan(cover: []const bool, cols: u16, rows: u16, body_layers: []const pardes.BodyLayer, tag_layers: []const pardes.TagLayer) !void { +fn expectCoverIsScan(cover: []const bool, cols: u16, rows: u16, body_layers: []const pardes.Layer, tag_layers: []const pardes.Layer) !void { for (0..rows) |row| for (0..cols) |col| { const scan = bodyLayerIn(body_layers, @intCast(col), @intCast(row)) != null or tagLayerIn(tag_layers, @intCast(col), @intCast(row)) != null; try std.testing.expectEqual(scan, cover[row * cols + col]); @@ -5685,7 +5686,7 @@ test "the layer cover is the per-cell layer scan, over a core's layouts and rand @memset(&cover, true); // what an earlier frame left coverLayers(&cover, s.cols, s.rows, s.bodyLayers(), s.tagLayers()); try expectCoverIsScan(&cover, s.cols, s.rows, s.bodyLayers(), s.tagLayers()); - for (s.tagLayers()) |layer| notices = notices or (layer.cols != 0 and layer.kind == .notice); + for (s.tagLayers()) |layer| notices = notices or (layer.rows != 0 and layer.kind == .notice); } try std.testing.expect(notices); @@ -5702,8 +5703,8 @@ test "the layer cover is the per-cell layer scan, over a core's layouts and rand }; var prng = std.Random.DefaultPrng.init(0x6c61796572); const random = prng.random(); - var body: [pardes.MAX_PANES]pardes.BodyLayer = undefined; - var tag: [pardes.MAX_TAG_LAYERS]pardes.TagLayer = undefined; + var body: [pardes.MAX_PANES]pardes.Layer = undefined; + var tag: [pardes.MAX_TAG_LAYERS]pardes.Layer = undefined; var grid: [64 * 40]bool = undefined; for (0..3000) |_| { const cols = random.intRangeAtMost(u16, 1, 64); @@ -5720,12 +5721,12 @@ test "the layer cover is the per-cell layer scan, over a core's layouts and rand } } -fn tagLayerCellCount(g: *const Gui, layer: *const pardes.TagLayer) u32 { +fn tagLayerCellCount(g: *const Gui, layer: *const pardes.Layer) u32 { const pixels = @as(u32, layer.viewport.w) * g.cell_w; return @min(layer.cols, (pixels + g.tagline_width - 1) / g.tagline_width); } -fn emitTagLayer(g: *Gui, instances: [*]CellInstance, next: *u32, layer: *const pardes.TagLayer, win_w: f32, win_h: f32, track: ?pardes.animation.Track, page: Ground, show_cursor: bool, old_layer: bool) void { +fn emitTagLayer(g: *Gui, instances: [*]CellInstance, next: *u32, layer: *const pardes.Layer, win_w: f32, win_h: f32, track: ?pardes.animation.Track, page: Ground, show_cursor: bool, old_layer: bool) void { const bw: f32 = @floatFromInt(g.cell_w); const bh: f32 = @floatFromInt(g.cell_h); const tw: f32 = @floatFromInt(g.tagline_width); @@ -5735,20 +5736,25 @@ fn emitTagLayer(g: *Gui, instances: [*]CellInstance, next: *u32, layer: *const p // A band sliding into place is drawn offset and cut at its row's top, so // it comes out from under whatever is above it. const slide = layer.slide * bh; - const top = @as(f32, @floatFromInt(layer.viewport.y)) * bh; // A window is rarely a whole number of cells wide: a band that ends at // the last column runs on through the leftover pixels to the edge. const band_right = if (win_w - right < bw) @max(right, win_w) else right; - emitInstance(g, instances, next.*, 0, layer.viewport.y, .{ .w = band_right - left, .h = bh, .x_off = left, .y_off = slide }, win_w, win_h, track, .body, (&background)[0..1], 0, null, old_layer, false, page); - if (slide != 0) clipInstanceTop(&instances[next.*], top, win_h); - next.* += 1; - const line_cursor: ?usize = if (layer.cursor) |cu| cu.col else null; - for (0..tagLayerCellCount(g, layer)) |col| { - const cursor = if (layer.cursor) |cu| show_cursor and !cu.bar and cu.col == col else false; - emitInstance(g, instances, next.*, @intCast(col), layer.viewport.y, .{ .w = tw, .h = bh, .x_off = left, .y_off = slide }, win_w, win_h, track, .tagline, layer.cells[0..layer.cols], col, line_cursor, old_layer, cursor, page); - clipInstanceRight(&instances[next.*], right, win_w); + // A row to each line, each a grid row with the tagline's glyphs. + for (0..layer.rows) |index| { + const y = layer.viewport.y + @as(u16, @intCast(index)); + const top = @as(f32, @floatFromInt(y)) * bh; + emitInstance(g, instances, next.*, 0, y, .{ .w = band_right - left, .h = bh, .x_off = left, .y_off = slide }, win_w, win_h, track, .body, (&background)[0..1], 0, null, old_layer, false, page); if (slide != 0) clipInstanceTop(&instances[next.*], top, win_h); next.* += 1; + const cells = layer.cells[index * layer.cols ..][0..layer.cols]; + const line_cursor: ?usize = if (layer.cursor) |cu| (if (cu.y == index) cu.x else null) else null; + for (0..tagLayerCellCount(g, layer)) |col| { + const cursor = if (layer.cursor) |cu| show_cursor and !cu.bar and cu.x == col and cu.y == index else false; + emitInstance(g, instances, next.*, @intCast(col), y, .{ .w = tw, .h = bh, .x_off = left, .y_off = slide }, win_w, win_h, track, .tagline, cells, col, line_cursor, old_layer, cursor, page); + clipInstanceRight(&instances[next.*], right, win_w); + if (slide != 0) clipInstanceTop(&instances[next.*], top, win_h); + next.* += 1; + } } } @@ -5760,11 +5766,11 @@ fn clipInstanceTop(instance: *CellInstance, top: f32, win_h: f32) void { instance.y0 = @max(instance.y1, limit); } -fn bodyLayerAt(surface: *const pardes.Surface, col: u16, row: u16) ?*const pardes.BodyLayer { +fn bodyLayerAt(surface: *const pardes.Surface, col: u16, row: u16) ?*const pardes.Layer { return bodyLayerIn(surface.bodyLayers(), col, row); } -fn bodyLayerIn(layers: []const pardes.BodyLayer, col: u16, row: u16) ?*const pardes.BodyLayer { +fn bodyLayerIn(layers: []const pardes.Layer, col: u16, row: u16) ?*const pardes.Layer { for (layers) |*layer| { const r = layer.viewport; if (layer.rows > 0 and col >= r.x and col - r.x < r.w and row >= r.y and row - r.y < r.h) return layer; @@ -5788,7 +5794,7 @@ fn clipBodyInstance(instance: *CellInstance, bottom: f32, win_h: f32) void { instance.y1 = limit; } -fn emitBodyLayer(g: *Gui, instances: [*]CellInstance, next: *u32, layer: *const pardes.BodyLayer, win_w: f32, win_h: f32, track: ?pardes.animation.Track, page: Ground, show_cursor: bool, old_layer: bool, border_rgb: [3]u8) void { +fn emitBodyLayer(g: *Gui, instances: [*]CellInstance, next: *u32, layer: *const pardes.Layer, win_w: f32, win_h: f32, track: ?pardes.animation.Track, page: Ground, show_cursor: bool, old_layer: bool, border_rgb: [3]u8) void { const bw: f32 = @floatFromInt(g.cell_w); const bh: f32 = @floatFromInt(g.cell_h); const tw: f32 = @floatFromInt(g.tagline_width); @@ -5851,11 +5857,11 @@ fn gripCellChanged(surface: *const pardes.Surface, col: u16, row: u16) bool { return false; } -fn paneGripCell(layers: []const pardes.TagLayer, cells: []const pardes.Cell, cols: u16, col: u16, row: u16) ?GripCell { +fn paneGripCell(layers: []const pardes.Layer, cells: []const pardes.Cell, cols: u16, col: u16, row: u16) ?GripCell { const at = @as(usize, row) * cols + col; if (at >= cells.len or cells[at].default or cells[at].style.font_role != .tagline) return null; for (layers) |layer| { - if (layer.cols == 0 or layer.kind != .pane or layer.viewport.x < pardes.TAG_TEXT_INSET or layer.viewport.y != row) continue; + if (layer.rows == 0 or layer.kind != .pane or layer.viewport.x < pardes.TAG_TEXT_INSET or row < layer.viewport.y or row - layer.viewport.y >= layer.rows) continue; const x = layer.viewport.x - pardes.TAG_TEXT_INSET; if (col < x or col - x >= config.GUTTER) continue; const index = @as(usize, row) * cols + x; @@ -6607,7 +6613,7 @@ test "pane indicator halves share dissolve changes and safe exhausted atlas" { cells[0].text[0] = '$'; var previous = cells; previous[0].text[0] = '^'; - var layers = [_]pardes.TagLayer{.{ .kind = .pane, .serial = 1, .viewport = .{ .x = pardes.TAG_TEXT_INSET, .y = 0, .w = 3, .h = 1 }, .cols = 3 }}; + var layers = [_]pardes.Layer{.{ .kind = .pane, .serial = 1, .viewport = .{ .x = pardes.TAG_TEXT_INSET, .y = 0, .w = 3, .h = 1 }, .cols = 3, .rows = 1 }}; var diffs: [12]pardes.PanelCellDiff = @splat(.unchanged); diffs[0] = pardes.PanelCellDiff.between(&previous[0], &cells[0]); var surface: pardes.Surface = .{ .cols = 6, .rows = 2, .cells = &cells, .previous_cells = &previous, .previous_tag_layers = &layers, .cell_diffs = &diffs }; @@ -7316,16 +7322,17 @@ fn buildOverlay( } }; if (transient_on) for (surface.tagLayers()) |*layer| { - if (layer.cols == 0) continue; + if (layer.rows == 0) continue; const cursor = layer.cursor orelse continue; - if (!cursor.bar or cursor.col >= layer.cols) continue; + if (!cursor.bar or cursor.x >= layer.cols or cursor.y >= layer.rows) continue; const width: f32 = @floatFromInt(g.tagline_width); const left = @as(f32, @floatFromInt(layer.viewport.x)) * layout.w; const right = left + @as(f32, @floatFromInt(layer.viewport.w)) * layout.w; - const x = left + @as(f32, @floatFromInt(cursor.col)) * width; + const x = left + @as(f32, @floatFromInt(cursor.x)) * width; if (x >= right) continue; - const top = @as(f32, @floatFromInt(layer.viewport.y)) * layout.h + @as(f32, @floatFromInt(taglineBandOffset(layer.viewport.y, builder.win_h, g.cell_h, g.tagline_height))); - builder.addRect(x, top, @min(right, x + @max(1, width / 8)), top + @as(f32, @floatFromInt(g.tagline_height)), overlayRgb(cursorColor(core, &layer.cells[cursor.col], .tagline))); + const y = layer.viewport.y + cursor.y; + const top = @as(f32, @floatFromInt(y)) * layout.h + @as(f32, @floatFromInt(taglineBandOffset(y, builder.win_h, g.cell_h, g.tagline_height))); + builder.addRect(x, top, @min(right, x + @max(1, width / 8)), top + @as(f32, @floatFromInt(g.tagline_height)), overlayRgb(cursorColor(core, &layer.cells[@as(usize, cursor.y) * layer.cols + cursor.x], .tagline))); }; if (transient_on) appendTouchOverlay(g, &builder, debug_on); return @intCast(builder.len); @@ -7506,7 +7513,7 @@ fn appendPaneChrome( // off from the text beneath it the way a tagline is: the same colour and // thickness along its bottom, running to the window edge when it does. for (surface.tagLayers()) |*layer| { - if (layer.cols == 0 or layer.kind != .notice) continue; + if (layer.rows == 0 or layer.kind != .notice) continue; const x0 = @as(f32, @floatFromInt(layer.viewport.x)) * layout.w; const x1 = x0 + @as(f32, @floatFromInt(layer.viewport.w)) * layout.w; const rule_x1 = if (builder.win_w - x1 < layout.w) @max(x1, builder.win_w) else x1; @@ -7528,21 +7535,25 @@ fn appendPaneChrome( fn appendTagGrips(g: *const Gui, surface: *const pardes.Surface, layout: CellLayout, builder: *OverlayBuilder) void { if (g.tagline_height < 6 or g.tagline_width < 3) return; for (surface.tagLayers()) |layer| { - if (layer.cols == 0 or layer.kind != .pane or layer.viewport.x < pardes.TAG_TEXT_INSET) continue; + if (layer.rows == 0 or layer.kind != .pane or layer.viewport.x < pardes.TAG_TEXT_INSET) continue; const x = layer.viewport.x - pardes.TAG_TEXT_INSET; - const y = layer.viewport.y; - if (x >= surface.cols or y >= surface.rows) continue; - const cell = &surface.cells[@as(usize, y) * surface.cols + x]; - if (cell.default or cell.printableAscii() != ' ') continue; - const rgb = switch (cell.style.fg) { - .rgb => |rgb| rgb, - else => continue, - }; - const center_x = (@as(f32, @floatFromInt(x)) + @as(f32, @floatFromInt(config.GUTTER)) / 2) * layout.w + @as(f32, @floatFromInt(anchorInset(g, y, builder.win_h) / 2)); - const center_y = @as(f32, @floatFromInt(y)) * layout.h + @as(f32, @floatFromInt(taglineBandOffset(y, builder.win_h, g.cell_h, g.tagline_height))) + @as(f32, @floatFromInt(g.tagline_height)) / 2; - const half_w = @max(1, @min(3, layout.w - 2)); - builder.addRect(@floor(center_x - half_w), @floor(center_y - 2), @floor(center_x + half_w), @floor(center_y - 1), overlayRgb(rgb)); - builder.addRect(@floor(center_x - half_w), @floor(center_y + 1), @floor(center_x + half_w), @floor(center_y + 2), overlayRgb(rgb)); + // A mark on each of the tag's rows whose grip cell is blank: every + // row but the one with the mode's glyph. + for (0..layer.rows) |index| { + const y = layer.viewport.y + @as(u16, @intCast(index)); + if (x >= surface.cols or y >= surface.rows) continue; + const cell = &surface.cells[@as(usize, y) * surface.cols + x]; + if (cell.default or cell.printableAscii() != ' ') continue; + const rgb = switch (cell.style.fg) { + .rgb => |rgb| rgb, + else => continue, + }; + const center_x = (@as(f32, @floatFromInt(x)) + @as(f32, @floatFromInt(config.GUTTER)) / 2) * layout.w + @as(f32, @floatFromInt(anchorInset(g, y, builder.win_h) / 2)); + const center_y = @as(f32, @floatFromInt(y)) * layout.h + @as(f32, @floatFromInt(taglineBandOffset(y, builder.win_h, g.cell_h, g.tagline_height))) + @as(f32, @floatFromInt(g.tagline_height)) / 2; + const half_w = @max(1, @min(3, layout.w - 2)); + builder.addRect(@floor(center_x - half_w), @floor(center_y - 2), @floor(center_x + half_w), @floor(center_y - 1), overlayRgb(rgb)); + builder.addRect(@floor(center_x - half_w), @floor(center_y + 1), @floor(center_x + half_w), @floor(center_y + 2), overlayRgb(rgb)); + } } } @@ -7553,8 +7564,8 @@ test "column grips stay unmarked while pane marks retain physical centering" { g.cell_h = 20; var cells: [80]pardes.Cell = @splat(.{ .default = false, .style = .{ .fg = .{ .rgb = .{ 100, 120, 140 } } } }); var surface: pardes.Surface = .{ .cols = 20, .rows = 4, .cells = &cells }; - surface.tag_layers[0] = .{ .kind = .column, .viewport = .{ .x = 8, .y = 1, .w = 13, .h = 1 }, .cols = 20 }; - surface.tag_layers[1] = .{ .kind = .pane, .viewport = .{ .x = 8, .y = 3, .w = 13, .h = 1 }, .cols = 20 }; + surface.tag_layers[0] = .{ .kind = .column, .viewport = .{ .x = 8, .y = 1, .w = 13, .h = 1 }, .cols = 20, .rows = 1 }; + surface.tag_layers[1] = .{ .kind = .pane, .viewport = .{ .x = 8, .y = 3, .w = 13, .h = 1 }, .cols = 20, .rows = 1 }; var vertices: [24]OverlayVertex = undefined; var builder: OverlayBuilder = .{ .vertices = &vertices, .win_w = 200, .win_h = 80 }; appendTagGrips(&g, &surface, .{ .w = 10, .h = 20, .x_off = 0, .y_off = 0 }, &builder); @@ -7927,7 +7938,7 @@ test "compact body layer rendering fills recovered rows and clips the final glyp g.tagline_height = 12; g.space_slot = .{ .u = 0, .v = 0 }; var cells: [24]pardes.Cell = @splat(.{}); - var layer: pardes.BodyLayer = .{ + var layer: pardes.Layer = .{ .viewport = .{ .x = 3, .y = 2, .w = 2, .h = 5 }, .cols = 2, .rows = 12, @@ -7967,7 +7978,7 @@ test "compact tag layers fill available width and clip at their physical edge" { g.tagline_height = 12; g.space_slot = .{ .u = 0, .v = 0 }; var cells: [6]pardes.Cell = @splat(.{}); - const layer: pardes.TagLayer = .{ .kind = .pane, .id = 0, .serial = 7, .viewport = .{ .x = 2, .y = 3, .w = 3, .h = 1 }, .cols = 6, .cells = &cells, .bg = .{ 20, 30, 40 } }; + const layer: pardes.Layer = .{ .kind = .pane, .id = 0, .serial = 7, .viewport = .{ .x = 2, .y = 3, .w = 3, .h = 1 }, .cols = 6, .rows = 1, .cells = &cells, .bg = .{ 20, 30, 40 } }; var instances: [8]CellInstance = undefined; var next: u32 = 0; emitTagLayer(&g, &instances, &next, &layer, 100, 100, null, Ground.opaqueRgb(bg_default), false, false); diff --git a/src/look.zig b/src/look.zig index 8f9e15f2..258cf8f5 100644 --- a/src/look.zig +++ b/src/look.zig @@ -21,7 +21,7 @@ const pdf = panes.Pdf.pdf; const Pane = panes.Pane; const MAX_PANES = pardes.MAX_PANES; const tag_layer = @import("tag_layer.zig"); -const TagHit = tag_layer.Hit; +const TagHit = pardes.TagHit; const BOX_H = pardes.BOX_H; const TAG_TEXT_INSET = pardes.TAG_TEXT_INSET; const pathUnder = pardes.pathUnder; diff --git a/src/macos.zig b/src/macos.zig index fce0a53e..f7e03cd4 100644 --- a/src/macos.zig +++ b/src/macos.zig @@ -1861,9 +1861,9 @@ fn clearFrame(st: *State) void { st.panel_diff_len = 0; } -fn blankTagCells(cells: []Cell, cols: u16, rows: u16, source: []const pardes.Cell, layers: []const pardes.TagLayer) void { +fn blankTagCells(cells: []Cell, cols: u16, rows: u16, source: []const pardes.Cell, layers: []const pardes.Layer) void { for (layers) |layer| { - if (layer.cols == 0 or layer.viewport.y >= rows or layer.viewport.x >= cols) continue; + if (layer.rows == 0 or layer.viewport.y >= rows or layer.viewport.x >= cols) continue; const start = @as(usize, layer.viewport.y) * cols + layer.viewport.x; const count = @min(layer.viewport.w, cols - layer.viewport.x); for (cells[start..][0..count], source[start..][0..count]) |*cell, was| { @@ -1879,7 +1879,7 @@ fn blankTagCells(cells: []Cell, cols: u16, rows: u16, source: []const pardes.Cel fn tagCursorCovered(core: *const pardes.Pardes) bool { const cursor = core.surface.cursor orelse return false; for (core.surface.tag_layers) |layer| { - if (layer.cols != 0 and cursor.y == layer.viewport.y and cursor.x >= layer.viewport.x and + if (layer.rows != 0 and cursor.y == layer.viewport.y and cursor.x >= layer.viewport.x and cursor.x - layer.viewport.x < layer.viewport.w) return true; } return false; @@ -2121,7 +2121,7 @@ export fn pardes_tag_layer_value(index: u32, field: u32) u32 { 5 => layer.viewport.y, 6 => layer.viewport.w, 7 => layer.viewport.h, - 8 => if (layer.cursor) |c| c.col else 65535, + 8 => if (layer.cursor) |c| c.x else 65535, 9 => if (layer.cursor) |c| @intFromBool(c.bar) else 0, 10 => @as(u32, layer.bg[0]) << 16 | @as(u32, layer.bg[1]) << 8 | layer.bg[2], 11 => @intFromBool(layer.kind == .pane and st.core.settings.tag_bottom), @@ -2139,7 +2139,7 @@ export fn pardes_tag_layer_cells(index: u32) ?[*]const Cell { const st = &(state orelse return null); if (index >= pardes.MAX_TAG_LAYERS) return null; const layer = &st.core.surface.tag_layers[index]; - if (layer.cols == 0) return null; + if (layer.rows == 0) return null; const cells = &st.tag_cells[index]; if (cells.len != layer.cells.len) cells.* = st.gpa.realloc(cells.*, layer.cells.len) catch return null; for (layer.cells, cells.*) |source, *out| out.* = encodeCell(source); @@ -3110,7 +3110,7 @@ test "mac tag layer ABI preserves logical capacity and physical grip" { logical[11].text[0] = 'Z'; logical[11].len = 1; logical[11].default = false; - core.surface.tag_layers[0] = .{ .kind = .pane, .id = 1, .serial = 42, .viewport = .{ .x = 2, .y = 1, .w = 6, .h = 1 }, .cols = 12, .cells = &logical, .bg = .{ 0x12, 0x34, 0x56 }, .cursor = .{ .col = 11, .bar = true } }; + core.surface.tag_layers[0] = .{ .kind = .pane, .id = 1, .serial = 42, .viewport = .{ .x = 2, .y = 1, .w = 6, .h = 1 }, .cols = 12, .rows = 1, .cells = &logical, .bg = .{ 0x12, 0x34, 0x56 }, .cursor = .{ .x = 11, .y = 0, .bar = true } }; defer core.surface.tag_layers[0] = .{}; try std.testing.expectEqual(@as(u32, 12), pardes_tag_layer_value(0, 0)); try std.testing.expectEqual(@as(u32, 0x123456), pardes_tag_layer_value(0, 10)); diff --git a/src/pardes.zig b/src/pardes.zig index 6946e123..f8087bdb 100644 --- a/src/pardes.zig +++ b/src/pardes.zig @@ -39,6 +39,7 @@ pub const ImagePatch = @import("surface.zig").ImagePatch; pub const ImagePlace = @import("surface.zig").ImagePlace; pub const Surface = @import("surface.zig").Surface; pub const Region = @import("surface.zig").Region; +pub const MAX_REGIONS = @import("surface.zig").MAX_REGIONS; pub const builtins = @import("builtins.zig"); const limits = memory.limits; const selection_pipe = @import("selection_pipe.zig"); @@ -247,21 +248,17 @@ pub const Pane = panes.Pane; const Text = panes.Text; pub const MAX_PANES = 16; -pub const BodyLayer = @import("body_layer.zig").Layer; -pub const RowMetrics = @import("body_layer.zig").Metrics; -pub const TagLayer = @import("tag_layer.zig").Layer; -pub const TagHit = @import("tag_layer.zig").Hit; -pub const TagKind = @import("tag_layer.zig").Kind; -/// Panes, then columns, then the workspace bar, then each pane's notice bands. +pub const Layer = @import("Layer.zig"); +pub const RowMetrics = Layer.Metrics; +pub const TagHit = Layer.TagHit; +pub const TagKind = Layer.Kind; /// A tag shows at most this many lines; past them it is cut, like a line /// too long for its width. pub const MAX_TAG_ROWS = 8; -pub const MAX_TAG_LAYERS = MAX_PANES + MAX_COLS + 1 + MAX_PANES * Pane.Notices.max + (MAX_PANES + MAX_COLS + 1) * (MAX_TAG_ROWS - 1); +/// Panes, then columns, then the workspace bar, then each pane's notice +/// bands: a band to a tag, however many lines it has. +pub const MAX_TAG_LAYERS = MAX_PANES + MAX_COLS + 1 + MAX_PANES * Pane.Notices.max; pub const NOTICE_LAYER_BASE = MAX_PANES + MAX_COLS + 1; -/// Where the layers for a pane tag's second and later lines start. -pub const TAG_LINE_LAYER_BASE = NOTICE_LAYER_BASE + MAX_PANES * Pane.Notices.max; -/// ...and those of a column's (by index) or the workspace's (after them). -pub const HEADER_LINE_LAYER_BASE = TAG_LINE_LAYER_BASE + MAX_PANES * (MAX_TAG_ROWS - 1); pub const PDF_PAGE_GAP_PX = panes.Pdf.page_gap_px; pub const MAX_COLS = 6; const column_weight_unit = layout.column_weight_unit; @@ -787,7 +784,7 @@ test "TreeContext tag style preserves message rows and its opt-out survives rest try std.testing.expectEqual(full_height, p.surface.body_layers[0].viewport.h); const r = p.rects[0]; const band = for (p.surface.tagLayers()) |*layer| { - if (layer.cols != 0 and layer.kind == .notice) break layer; + if (layer.rows != 0 and layer.kind == .notice) break layer; } else return error.NoNoticeBand; try std.testing.expectEqual(p.bodyTop(pane, r), band.viewport.y); try std.testing.expectEqual(p.surface.body_layers[0].viewport.y, band.viewport.y); @@ -5832,15 +5829,14 @@ pub const Pardes = struct { pub fn reprojectTagHit(p: *const Pardes, tag_hit: TagHit) ?TagHit { for (p.surface.tagLayers()) |*layer| { - if (layer.cols == 0 or layer.kind != tag_hit.kind or layer.id != tag_hit.id or layer.serial != tag_hit.serial) continue; + if (layer.rows == 0 or layer.kind != tag_hit.kind or layer.id != tag_hit.id or layer.serial != tag_hit.serial) continue; if (layer.kind == .pane) { if (layer.id >= p.panes.len) return null; const pane = p.panes[layer.id] orelse return null; if (pane.serial != layer.serial) return null; } if (layer.kind == .column and (layer.id >= p.ncol or p.col_serial[layer.id] != layer.serial)) return null; - // A taller tag has a layer per line; the point is on one of them. - return layer.hitAt(tag_hit.pixel_x, tag_hit.pixel_y, @floatFromInt(tag_hit.metrics.body_w), @floatFromInt(tag_hit.metrics.body_h), @floatFromInt(tag_hit.metrics.tagline_w), @floatFromInt(tag_hit.metrics.tagline_h)) orelse continue; + return layer.tagHit(tag_hit.pixel_x, tag_hit.pixel_y, @floatFromInt(tag_hit.metrics.body_w), @floatFromInt(tag_hit.metrics.body_h), @floatFromInt(tag_hit.metrics.tagline_w), @floatFromInt(tag_hit.metrics.tagline_h)) orelse continue; } return null; } @@ -5858,14 +5854,14 @@ pub const Pardes = struct { } pub fn tagCapacity(p: *const Pardes, physical_width: u16) u16 { - const layer: TagLayer = .{ .viewport = .{ .x = 0, .y = 0, .w = physical_width, .h = 1 } }; + const layer: Layer = .{ .kind = .pane, .viewport = .{ .x = 0, .y = 0, .w = physical_width, .h = 1 } }; return layer.capacity(p.row_metrics); } pub fn reprojectBodyHit(p: *const Pardes, body_hit: Mouse.BodyHit) ?Mouse.BodyHit { for (&p.surface.body_layers) |*layer| { if (layer.rows == 0 or layer.serial != body_hit.serial) continue; - return layer.hitAt(body_hit.pixel_x, body_hit.pixel_y, @floatFromInt(body_hit.metrics.body_w), @floatFromInt(body_hit.metrics.body_h), @floatFromInt(body_hit.metrics.tagline_w), @floatFromInt(body_hit.metrics.tagline_h)); + return layer.bodyHit(body_hit.pixel_x, body_hit.pixel_y, @floatFromInt(body_hit.metrics.body_w), @floatFromInt(body_hit.metrics.body_h), @floatFromInt(body_hit.metrics.tagline_w), @floatFromInt(body_hit.metrics.tagline_h)); } return null; } @@ -6111,12 +6107,12 @@ test "a prompt chip is a band with its caret, still on the grid, and only the ch // A pixel shell draws the prompt from its band, in the tagline's pitch, // with the caret right after the marker's last glyph. const band = for (p.surface.tagLayers()) |*layer| { - if (layer.cols != 0 and layer.kind == .notice) break layer; + if (layer.rows != 0 and layer.kind == .notice) break layer; } else return error.NoPromptBand; try std.testing.expectEqual(row, band.viewport.y); const caret = band.cursor orelse return error.MissingBandCaret; try std.testing.expect(caret.bar); - try std.testing.expectEqualStrings("/", band.cells[caret.col - 1].grapheme()); + try std.testing.expectEqualStrings("/", band.cells[caret.x - 1].grapheme()); // The chip covers only its own columns. Left of it is ordinary body, and // a sweep there still selects. @@ -6162,11 +6158,11 @@ test "a prompt is typed on its own line in the notice band and leaves the tag ro try std.testing.expect(p.surface.tag_layers[0].cursor == null); // The band carries the answer and the caret, one cell back from its end. const band = for (p.surface.tagLayers()) |*layer| { - if (layer.cols != 0 and layer.kind == .notice) break layer; + if (layer.rows != 0 and layer.kind == .notice) break layer; } else return error.NoPromptBand; const caret = band.cursor orelse return error.MissingBandCaret; - try std.testing.expectEqualStrings("t", band.cells[caret.col - 1].grapheme()); - try std.testing.expectEqualStrings("w", band.cells[caret.col].grapheme()); + try std.testing.expectEqualStrings("t", band.cells[caret.x - 1].grapheme()); + try std.testing.expectEqualStrings("w", band.cells[caret.x].grapheme()); const grid = p.surface.cursor orelse return error.MissingPromptCursor; try std.testing.expectEqual(p.bodyTop(pane, p.rects[0]), grid.y); diff --git a/src/surface.zig b/src/surface.zig index fec43e30..db7dd468 100644 --- a/src/surface.zig +++ b/src/surface.zig @@ -11,8 +11,7 @@ const config = @import("config.zig"); const pdf_enabled = panes.Pdf.enabled; const image = @import("image.zig"); const MAX_PANES = pardes.MAX_PANES; -const BodyLayer = @import("body_layer.zig").Layer; -const TagLayer = @import("tag_layer.zig").Layer; +const Layer = @import("Layer.zig"); const MAX_TAG_LAYERS = pardes.MAX_TAG_LAYERS; const CellPixels = pardes.CellPixels; @@ -380,8 +379,8 @@ pub const Surface = struct { /// paint the quiet affordance can carry the hover bit through the ABI /// without every selection painter learning a new parameter. mark_hover: bool = false, - body_layers: [MAX_PANES]BodyLayer = @splat(.{}), - tag_layers: [MAX_TAG_LAYERS]TagLayer = @splat(.{}), + body_layers: [MAX_PANES]Layer = @splat(.{}), + tag_layers: [MAX_TAG_LAYERS]Layer = @splat(.{}), cols: u16 = 0, rows: u16 = 0, regions: [MAX_REGIONS]Region = undefined, @@ -394,15 +393,15 @@ pub const Surface = struct { panel_tracks: [MAX_PANES * 2]animation.Track = undefined, npanel_tracks: usize = 0, previous_cells: []const Cell = &.{}, - previous_body_layers: []const BodyLayer = &.{}, - previous_tag_layers: []const TagLayer = &.{}, + previous_body_layers: []const Layer = &.{}, + previous_tag_layers: []const Layer = &.{}, cell_diffs: []const PanelCellDiff = &.{}, - pub fn tagLayers(s: *const Surface) []const TagLayer { + pub fn tagLayers(s: *const Surface) []const Layer { return &s.tag_layers; } - pub fn bodyLayers(s: *const Surface) []const BodyLayer { + pub fn bodyLayers(s: *const Surface) []const Layer { return &s.body_layers; } diff --git a/src/tag_layer.zig b/src/tag_layer.zig index 7cfe5bbf..213ebc07 100644 --- a/src/tag_layer.zig +++ b/src/tag_layer.zig @@ -1,83 +1,10 @@ -//! Tag text has its own horizontal pitch. Its viewport stays in physical -//! body-grid coordinates so compact text never changes pane hit targets. +//! Pointer hits on tag bands (Layer.TagHit): comparing two, and bringing one +//! that left its band back onto it. const std = @import("std"); const pardes = @import("pardes.zig"); - -/// `notice` is a pane's transient line -- a builtin's name, a pending leader -/// chord -- carried as a tagline-shaped band so it gets the tagline's height, -/// small-font metrics, band offset and border instead of being a body-grid row -/// wearing a tagline font. -pub const Kind = enum(u8) { workspace, column, pane, notice }; -pub const Hit = struct { - kind: Kind, - id: u16, - serial: u32, - col: u16, - /// Which line of a taller tag the layer draws. - line: u16 = 0, - pixel_x: f32, - pixel_y: f32, - metrics: pardes.RowMetrics, -}; -pub const Layer = struct { - kind: Kind = .workspace, - id: u16 = 0, - serial: u32 = 0, - /// A pane's tag taller than a line is drawn a layer to a line; this is - /// which one, counted from its first. - line: u16 = 0, - viewport: pardes.Rect = .{ .x = 0, .y = 0, .w = 0, .h = 0 }, - cols: u16 = 0, - bg: [3]u8 = .{ 0, 0, 0 }, - cells: []pardes.Cell = &.{}, - cursor: ?struct { col: u16, bar: bool = false } = null, - /// Vertical offset in rows (negative: above its viewport), for a band - /// that is moving into place. A pixel shell draws it offset and clipped - /// to the rows below the viewport's top; the grid has no such thing. - slide: f32 = 0, - /// How present a notice band is (1 = fully) while it fades up or - /// dissolves. `bg` and the cells are already blended by it; a pixel - /// shell uses it for what it draws around the band, like its rule. - fade: f32 = 1, - - pub fn capacity(layer: *const Layer, metrics: pardes.RowMetrics) u16 { - return @intCast(@min(std.math.maxInt(u16), @max(1, @as(u32, layer.viewport.w) * @max(1, metrics.body_w) / @max(1, metrics.tagline_w)))); - } - - pub fn hitAt(layer: *const Layer, x: f32, y: f32, body_w: f32, body_h: f32, tagline_w: f32, tagline_h: f32) ?Hit { - if (layer.cols == 0 or !std.math.isFinite(x) or !std.math.isFinite(y)) return null; - for ([_]f32{ body_w, body_h, tagline_w, tagline_h }) |metric| - if (!std.math.isFinite(metric) or metric < 1 or metric > std.math.maxInt(u16)) return null; - const bw = @max(1, body_w); - const bh = @max(1, body_h); - const tw = std.math.clamp(tagline_w, 1, bw); - const th = std.math.clamp(tagline_h, 1, bh); - const dx = x - @as(f32, @floatFromInt(layer.viewport.x)) * bw; - const dy = y - @as(f32, @floatFromInt(layer.viewport.y)) * bh; - if (dx < 0 or dy < 0 or dx >= @as(f32, @floatFromInt(layer.viewport.w)) * bw or dy >= @as(f32, @floatFromInt(layer.viewport.h)) * bh) return null; - return .{ - .kind = layer.kind, - .id = layer.id, - .serial = layer.serial, - .line = layer.line, - .col = @intFromFloat(@min(@as(f32, @floatFromInt(layer.cols - 1)), @floor(dx / tw))), - .pixel_x = x, - .pixel_y = y, - .metrics = .{ .body_w = @intFromFloat(bw), .body_h = @intFromFloat(bh), .tagline_w = @intFromFloat(tw), .tagline_h = @intFromFloat(th) }, - }; - } -}; - -test "tag text capacity uses its own pitch and excludes the physical grip" { - const layer: Layer = .{ .kind = .pane, .id = 2, .serial = 7, .viewport = .{ .x = 12, .y = 4, .w = 38, .h = 1 }, .cols = 90 }; - try std.testing.expectEqual(@as(u16, 63), layer.capacity(.{ .body_w = 10, .tagline_w = 6 })); - try std.testing.expect(layer.hitAt(119.99, 85, 10, 20, 6, 12) == null); - try std.testing.expectEqual(@as(u16, 0), layer.hitAt(120, 85, 10, 20, 6, 12).?.col); - try std.testing.expectEqual(@as(u16, 50), layer.hitAt(423, 85, 10, 20, 6, 12).?.col); - try std.testing.expect(layer.hitAt(500, 85, 10, 20, 6, 12) == null); - try std.testing.expect(layer.hitAt(120, 85, std.math.nan(f32), 20, 6, 12) == null); - try std.testing.expect(layer.hitAt(120, 85, 10, 20, 0, 12) == null); -} +const Layer = @import("Layer.zig"); +const Hit = Layer.TagHit; +const Kind = Layer.Kind; /// Whether two pointer hits name the same cell of the same tag line. pub fn sameCell(a: ?Hit, b: ?Hit) bool { @@ -92,13 +19,13 @@ pub fn columnAt(p: *const pardes.Pardes, kind: Kind, id: usize, supplied: ?Hit, var point = supplied orelse return null; if (point.kind != kind or point.id != id) return null; if (clamp) for (p.surface.tagLayers()) |*layer| { - if (layer.cols == 0 or layer.kind != kind or layer.id != id or layer.serial != point.serial or layer.line != line) continue; + if (layer.rows == 0 or layer.kind != kind or layer.id != id or layer.serial != point.serial or line >= layer.rows) continue; const bw: f32 = @floatFromInt(point.metrics.body_w); const bh: f32 = @floatFromInt(point.metrics.body_h); const left = @as(f32, @floatFromInt(layer.viewport.x)) * bw; const right = @as(f32, @floatFromInt(layer.viewport.x + layer.viewport.w)) * bw; point.pixel_x = std.math.clamp(point.pixel_x, left, @max(left, right - 0.001)); - point.pixel_y = (@as(f32, @floatFromInt(layer.viewport.y)) + 0.5) * bh; + point.pixel_y = (@as(f32, @floatFromInt(layer.viewport.y + line)) + 0.5) * bh; break; }; return if (p.reprojectTagHit(point)) |mapped| mapped.col else null; diff --git a/src/web.zig b/src/web.zig index 532e3794..ac0ecbbf 100644 --- a/src/web.zig +++ b/src/web.zig @@ -224,13 +224,13 @@ export fn pardes_mouse_pixel(button_arg: u32, kind_arg: u32, col_arg: u32, row_a var hit: ?pardes.Mouse.BodyHit = null; for (&s.core.surface.body_layers) |*layer| { const point = source orelse break; - hit = layer.hitAt(point.x * bw, point.y * bh, bw, bh, tw, th); + hit = layer.bodyHit(point.x * bw, point.y * bh, bw, bh, tw, th); if (hit != null) break; } var tag_hit: ?pardes.TagHit = null; for (&s.core.surface.tag_layers) |*layer| { const point = source orelse break; - tag_hit = layer.hitAt(point.x * bw, point.y * bh, bw, bh, tw, th); + tag_hit = layer.tagHit(point.x * bw, point.y * bh, bw, bh, tw, th); if (tag_hit != null) break; } mouseWithHit(button_arg, kind_arg, col_arg, row_arg, mods, hit, tag_hit); @@ -341,6 +341,7 @@ export fn pardes_tag_layer_value(index: u32, field: u32) u32 { const s = &(state orelse return 0); if (index >= pardes.MAX_TAG_LAYERS) return 0; const layer = &s.core.surface.tag_layers[index]; + if (layer.rows == 0) return 0; return switch (field) { 0 => layer.cols, 1 => @intFromEnum(layer.kind), @@ -350,9 +351,12 @@ export fn pardes_tag_layer_value(index: u32, field: u32) u32 { 5 => layer.viewport.y, 6 => layer.viewport.w, 7 => layer.viewport.h, - 8 => if (layer.cursor) |c| c.col else 65535, + 8 => if (layer.cursor) |c| c.x else 65535, 9 => if (layer.cursor) |c| @intFromBool(c.bar) else 0, 10 => @as(u32, layer.bg[0]) << 16 | @as(u32, layer.bg[1]) << 8 | layer.bg[2], + // A band has a row to each line of its tag: `cols * rows` cells. + 11 => layer.rows, + 12 => if (layer.cursor) |c| c.y else 65535, else => 0, }; } @@ -361,7 +365,7 @@ export fn pardes_tag_layer_cells(index: u32) ?[*]const WebCell { const s = &(state orelse return null); if (index >= pardes.MAX_TAG_LAYERS) return null; const layer = &s.core.surface.tag_layers[index]; - if (layer.cols == 0) return null; + if (layer.rows == 0) return null; const cells = &s.tag_cells[index]; if (cells.len != layer.cells.len) cells.* = gpa.realloc(cells.*, layer.cells.len) catch return null; for (layer.cells, cells.*) |source, *out| out.* = encodeWebCell(source); diff --git a/src/web/app.mjs b/src/web/app.mjs index 280239d5..03829178 100644 --- a/src/web/app.mjs +++ b/src/web/app.mjs @@ -64,13 +64,16 @@ export class DomRenderer { if (!val(0)) continue; const gripCols = this.wasm.pardes_grip_columns?.() ?? 2; const textInset = this.wasm.pardes_tag_text_inset?.() ?? gripCols; - if (val(1) !== 0 && val(4) >= textInset && this.cellHeight) { - const offset = this.wasm.pardes_tagline_band_offset(val(5),rows*this.cellHeight*256,Math.round(this.cellHeight*256),Math.round(this.taglineHeight*256))/256; - for (let x = val(4)-textInset; x < val(4); x++) tagPrefixBands.set(val(5)*cols+x,offset); - if (val(1) === 2) paneIndicators.add(val(5)*cols+val(4)-textInset); - } - for (let x = val(4); x < Math.min(cols, val(4) + val(6)); x++) { - if (val(5) < rows) tagCovered[val(5) * cols + x] = 1; + // A row to each line of a taller tag. + for (let y = val(5); y < val(5) + Math.max(1, val(11)); y++) { + if (val(1) !== 0 && val(4) >= textInset && this.cellHeight) { + const offset = this.wasm.pardes_tagline_band_offset(y,rows*this.cellHeight*256,Math.round(this.cellHeight*256),Math.round(this.taglineHeight*256))/256; + for (let x = val(4)-textInset; x < val(4); x++) tagPrefixBands.set(y*cols+x,offset); + if (val(1) === 2) paneIndicators.add(y*cols+val(4)-textInset); + } + for (let x = val(4); x < Math.min(cols, val(4) + val(6)); x++) { + if (y < rows) tagCovered[y * cols + x] = 1; + } } } } @@ -118,27 +121,35 @@ export class DomRenderer { const nodes = []; const bw = this.cellWidth, bh = this.cellHeight, tw = this.taglineWidth, th = this.taglineHeight; for (let i = 0; i < this.wasm.pardes_tag_layer_limit(); i++) { - const values = Array.from({length:11}, (_,field) => this.wasm.pardes_tag_layer_value(i,field)); - const cols = values[0]; + const layerValues = Array.from({length:13}, (_,field) => this.wasm.pardes_tag_layer_value(i,field)); + const cols = layerValues[0]; if (!cols) continue; const ptr = this.wasm.pardes_tag_layer_cells(i); if (!ptr) continue; - const bytes = new Uint8Array(this.wasm.memory.buffer,ptr,cols*CELL_SIZE); + // A row to each line of a taller tag, each drawn as a band of its own. + for (let line = 0; line < Math.max(1, layerValues[11]); line++) { + const key = i*64+line; + const values = layerValues.slice(0,11); + values[5] = layerValues[5] + line; + values[7] = 1; + values[8] = layerValues[12] === line ? layerValues[8] : 65535; + const bytes = new Uint8Array(this.wasm.memory.buffer,ptr+line*cols*CELL_SIZE,cols*CELL_SIZE); const offset = this.wasm.pardes_tagline_band_offset(values[5],this.rowCount*bh*256,Math.round(bh*256),Math.round(th*256))/256; const gripCols = this.wasm.pardes_grip_columns?.() ?? 2; const gripX = values[4] - (this.wasm.pardes_tag_text_inset?.() ?? gripCols); const gripCell = canonical[values[5]*this.cols+gripX]; const grip = values[1] === 2 && gripX >= 0 && gripCell && th >= 1 && tw >= 1; const geometry = [bw,bh,tw,th,offset,...values,grip,gripCell?.fg,gripCell?.bg,gripCell?.attrs,gripCell?.text,globalThis.devicePixelRatio].join(":"); - const cached = this.tagNodes.get(i); + const cached = this.tagNodes.get(key); if (cached && cached.geometry === geometry && cached.bytes.length === bytes.length && cached.bytes.every((byte,index)=>byte===bytes[index])) { nodes.push(cached.node); if (cached.grip) nodes.push(cached.grip); continue; } - const view = new DataView(this.wasm.memory.buffer,ptr,cols*CELL_SIZE); + const view = new DataView(this.wasm.memory.buffer,ptr+line*cols*CELL_SIZE,cols*CELL_SIZE); const layer = this.root.ownerDocument.createElement("div"); layer.dataset.tagLayer = String(i); + layer.dataset.tagLine = String(line); layer.style.cssText = `position:absolute;overflow:hidden;white-space:pre;left:${values[4]*bw}px;top:${values[5]*bh+offset}px;width:${values[6]*bw}px;height:${th}px;background:${color(values[10],DEFAULT_BG)}`; for (let col = 0; col < cols; col++) { const off = col*CELL_SIZE; @@ -171,9 +182,10 @@ export class DomRenderer { gripNode.append(mark); } } - this.tagNodes.set(i,{geometry,bytes:bytes.slice(),node:layer,grip:gripNode}); + this.tagNodes.set(key,{geometry,bytes:bytes.slice(),node:layer,grip:gripNode}); nodes.push(layer); if (gripNode) nodes.push(gripNode); + } } if (nodes.length !== this.tagRoot.childNodes.length || nodes.some((node,index)=>node!==this.tagRoot.childNodes[index])) this.tagRoot.replaceChildren(...nodes); } diff --git a/test/column_drag.zig b/test/column_drag.zig index feea1bf7..3aea4286 100644 --- a/test/column_drag.zig +++ b/test/column_drag.zig @@ -8,17 +8,17 @@ fn mouse(p: *Pardes, kind: pardes.Mouse.Kind, col: u16) void { p.update(.{ .mouse = .{ .button = .left, .kind = kind, .col = col, .row = pardes.TOPBAR_H } }); } -fn tagLayer(p: *Pardes, column: usize) !*pardes.TagLayer { +fn tagLayer(p: *Pardes, column: usize) !*pardes.Layer { for (&p.surface.tag_layers) |*layer| { - if (layer.cols > 0 and layer.kind == .column and layer.id == column) return layer; + if (layer.rows > 0 and layer.kind == .column and layer.id == column) return layer; } return error.MissingColumnTagLayer; } -fn headerMouse(layer: *const pardes.TagLayer, display_col: u16, kind: pardes.Mouse.Kind) pardes.Mouse { +fn headerMouse(layer: *const pardes.Layer, display_col: u16, kind: pardes.Mouse.Kind) pardes.Mouse { const x = @as(f32, @floatFromInt(layer.viewport.x)) * 10 + (@as(f32, @floatFromInt(display_col)) + 0.5) * 5; const y = (@as(f32, @floatFromInt(layer.viewport.y)) + 0.5) * 20; - return .{ .button = .left, .kind = kind, .col = @intFromFloat(x / 10), .row = @intFromFloat(y / 20), .tag_hit = layer.hitAt(x, y, 10, 20, 5, 10) }; + return .{ .button = .left, .kind = kind, .col = @intFromFloat(x / 10), .row = @intFromFloat(y / 20), .tag_hit = layer.tagHit(x, y, 10, 20, 5, 10) }; } const Snapshot = struct { @@ -144,7 +144,7 @@ test "column grip is separate from compact text and the resize seam" { try std.testing.expectEqual(p.col_x[column], rect.x); try std.testing.expectEqual(rect.x + pardes.TAG_TEXT_INSET, (try tagLayer(p, column)).viewport.x); for (p.surface.tagLayers()) |pane_layer| { - if (pane_layer.cols > 0 and pane_layer.kind == .pane and pane_layer.id == pane_id) + if (pane_layer.rows > 0 and pane_layer.kind == .pane and pane_layer.id == pane_id) try std.testing.expectEqual((try tagLayer(p, column)).viewport.x, pane_layer.viewport.x); } const pane_tag_y = if (p.settings.tag_bottom) rect.y + rect.h - pardes.BOX_H else rect.y; diff --git a/test/panes.zig b/test/panes.zig index 11fb750a..5e26cdd0 100644 --- a/test/panes.zig +++ b/test/panes.zig @@ -19,17 +19,17 @@ fn setTag(pane: *Pane, text: []const u8) !void { } const TagLayerTests = struct { - const Kind = @FieldType(pardes.TagLayer, "kind"); - fn findLayer(p: *Pardes, kind: Kind, id: usize) !*pardes.TagLayer { + const Kind = @FieldType(pardes.Layer, "kind"); + fn findLayer(p: *Pardes, kind: Kind, id: usize) !*pardes.Layer { for (&p.surface.tag_layers) |*layer| { - if (layer.cols > 0 and layer.kind == kind and layer.id == id) return layer; + if (layer.rows > 0 and layer.kind == kind and layer.id == id) return layer; } return error.MissingTagLayer; } - fn mouse(layer: *const pardes.TagLayer, x: f32, kind: pardes.Mouse.Kind) pardes.Mouse { + fn mouse(layer: *const pardes.Layer, x: f32, kind: pardes.Mouse.Kind) pardes.Mouse { const y = (@as(f32, @floatFromInt(layer.viewport.y)) + 0.5) * 20; - return .{ .button = .left, .kind = kind, .col = @intFromFloat(x / 10), .row = @intFromFloat(y / 20), .tag_hit = layer.hitAt(x, y, 10, 20, 5, 10) }; + return .{ .button = .left, .kind = kind, .col = @intFromFloat(x / 10), .row = @intFromFloat(y / 20), .tag_hit = layer.tagHit(x, y, 10, 20, 5, 10) }; } test "compact tag layers render and edit Unicode text beyond body column capacity" { @@ -200,14 +200,16 @@ test "a tag with a newline in it is as tall as its lines, and each line is typed const body_y = p.bodyTop(pane, r); try std.testing.expectEqual(if (bottom) r.y else r.y + 2, body_y); try std.testing.expectEqualStrings("b", surface.at(r.x + config.GUTTER + panes.File.gutterWidth(pane), body_y).grapheme()); - // a layer to a line, for a pixel shell - var lines: usize = 0; + // one layer, a row to each line, for a pixel shell + var layers: usize = 0; for (p.surface.tagLayers()) |*layer| { - if (layer.cols == 0 or layer.kind != .pane or layer.id != 0) continue; - try std.testing.expectEqual(tag_y + layer.line, layer.viewport.y); - lines += 1; + if (layer.rows == 0 or layer.kind != .pane or layer.id != 0) continue; + try std.testing.expectEqual(tag_y, layer.viewport.y); + try std.testing.expectEqual(@as(u16, 2), layer.rows); + try std.testing.expectEqual(@as(u16, 2), layer.viewport.h); + layers += 1; } - try std.testing.expectEqual(@as(usize, 2), lines); + try std.testing.expectEqual(@as(usize, 1), layers); // a click on the second line puts the tag's cursor on it p.update(.{ .key = .{ .cp = Key.escape } }); p.update(.{ .key = .{ .cp = ':' } }); @@ -541,11 +543,11 @@ const TagNavigationTests = struct { }; const BodyHitTests = struct { - fn mouse(layer: *const pardes.BodyLayer, row: u16, col: u16, kind: pardes.Mouse.Kind) pardes.Mouse { + fn mouse(layer: *const pardes.Layer, row: u16, col: u16, kind: pardes.Mouse.Kind) pardes.Mouse { const width: f32 = if (row < layer.context_rows) 8 else 10; const x = @as(f32, @floatFromInt(layer.viewport.x)) * 10 + (@as(f32, @floatFromInt(col)) + 0.5) * width; const y = layer.rowTop(row, 20, 10) + layer.rowHeight(row, 20, 10) / 2; - return .{ .button = .left, .kind = kind, .col = @intFromFloat(x / 10), .row = @intFromFloat(y / 20), .body_hit = layer.hitAt(x, y, 10, 20, 8, 10).? }; + return .{ .button = .left, .kind = kind, .col = @intFromFloat(x / 10), .row = @intFromFloat(y / 20), .body_hit = layer.bodyHit(x, y, 10, 20, 8, 10).? }; } test "compact TreeContext mouse follows source rows in reclaimed space" { @@ -673,7 +675,7 @@ const TreeContextTests = struct { const y = layer.rowTop(row, 20, 10) + 9.5; const x = @as(f32, @floatFromInt(layer.viewport.x)) * 10 + 5; // A one-pixel separator remains inside its existing header row. - try std.testing.expectEqual(row, layer.hitAt(x, y, 10, 20, 8, 10).?.row); + try std.testing.expectEqual(row, layer.bodyHit(x, y, 10, 20, 8, 10).?.row); } pane.scrollBy(-5); _ = try p.render(frame.allocator()); -- cgit v1.3