quickshell: Archie
A black and tan dachshund who lives along the bottom of the screen, with a bowl he visits for a snack. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
9b43f5f669
commit
e11d6d4e57
1 changed files with 254 additions and 0 deletions
|
|
@ -375,6 +375,7 @@ in
|
||||||
Lock 1.0 Lock.qml
|
Lock 1.0 Lock.qml
|
||||||
Cheatsheet 1.0 Cheatsheet.qml
|
Cheatsheet 1.0 Cheatsheet.qml
|
||||||
Weird 1.0 Weird.qml
|
Weird 1.0 Weird.qml
|
||||||
|
Archie 1.0 Archie.qml
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1118,6 +1119,256 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
"quickshell/Archie.qml" = {
|
||||||
|
onChange = qsRestart;
|
||||||
|
text = ''
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
// Archie — a black and tan dachshund with a red collar, living
|
||||||
|
// along the bottom of the screen. He trots up and down, stops to
|
||||||
|
// wag, and every so often remembers his bowl and goes for a snack.
|
||||||
|
//
|
||||||
|
// The art is plain text, one character per pixel, so he can be
|
||||||
|
// redrawn by editing the picture instead of editing code. He walks
|
||||||
|
// on all fours and never limps; that was deliberate.
|
||||||
|
Item {
|
||||||
|
id: archie
|
||||||
|
anchors.fill: parent
|
||||||
|
// One dog. The bar is instantiated per monitor.
|
||||||
|
property bool primary: true
|
||||||
|
visible: primary
|
||||||
|
|
||||||
|
readonly property int cell: 6
|
||||||
|
readonly property int cols: 26
|
||||||
|
readonly property int rows: 13
|
||||||
|
|
||||||
|
// Not themed — he looked how he looked.
|
||||||
|
readonly property var pal: ({
|
||||||
|
"K": "#2b2523", // black
|
||||||
|
"T": "#a86a30", // tan
|
||||||
|
"R": "#b3322c", // collar, and his bowl
|
||||||
|
"N": "#14100f", // nose
|
||||||
|
"W": "#efe7dd", // catchlight
|
||||||
|
"B": "#96602f" // kibble
|
||||||
|
})
|
||||||
|
|
||||||
|
// Trotting: legs out at full stride, tail up.
|
||||||
|
readonly property var walkA: [
|
||||||
|
"....................KKKK..",
|
||||||
|
"...................KKKKKK.",
|
||||||
|
"...................KKTKKK.",
|
||||||
|
"KK.................KKWTTK.",
|
||||||
|
".KK................KKTTTN.",
|
||||||
|
"..KKKKKKKKKKKKKKKKRKKTTTN.",
|
||||||
|
"..KKKKKKKKKKKKKKKKRKKTTT..",
|
||||||
|
"...KKKKKKKKKKKKKKKRKKT....",
|
||||||
|
"...KKKKKKKKKKKKKTTK.......",
|
||||||
|
"....TKKKKKKKKKKKTT........",
|
||||||
|
"....TT.........TTT........",
|
||||||
|
"....TT..........TT........",
|
||||||
|
"...TTT..........TTT......."
|
||||||
|
]
|
||||||
|
// Legs gathered underneath, tail level.
|
||||||
|
readonly property var walkB: [
|
||||||
|
"....................KKKK..",
|
||||||
|
"...................KKKKKK.",
|
||||||
|
"...................KKTKKK.",
|
||||||
|
"...................KKWTTK.",
|
||||||
|
"KKK................KKTTTN.",
|
||||||
|
"..KKKKKKKKKKKKKKKKRKKTTTN.",
|
||||||
|
"..KKKKKKKKKKKKKKKKRKKTTT..",
|
||||||
|
"...KKKKKKKKKKKKKKKRKKT....",
|
||||||
|
"...KKKKKKKKKKKKKTTK.......",
|
||||||
|
"....TKKKKKKKKKKKTT........",
|
||||||
|
"......TT......TT..........",
|
||||||
|
"......TT......TT..........",
|
||||||
|
".....TTT.....TTT.........."
|
||||||
|
]
|
||||||
|
// Standing still: walkA's planted legs, walkB's tail. Flipping
|
||||||
|
// between this and walkA is the wag.
|
||||||
|
readonly property var wag: [
|
||||||
|
"....................KKKK..",
|
||||||
|
"...................KKKKKK.",
|
||||||
|
"...................KKTKKK.",
|
||||||
|
"...................KKWTTK.",
|
||||||
|
"KKK................KKTTTN.",
|
||||||
|
"..KKKKKKKKKKKKKKKKRKKTTTN.",
|
||||||
|
"..KKKKKKKKKKKKKKKKRKKTTT..",
|
||||||
|
"...KKKKKKKKKKKKKKKRKKT....",
|
||||||
|
"...KKKKKKKKKKKKKTTK.......",
|
||||||
|
"....TKKKKKKKKKKKTT........",
|
||||||
|
"....TT.........TTT........",
|
||||||
|
"....TT..........TT........",
|
||||||
|
"...TTT..........TTT......."
|
||||||
|
]
|
||||||
|
// Head down in the bowl.
|
||||||
|
readonly property var eat: [
|
||||||
|
"..........................",
|
||||||
|
"..........................",
|
||||||
|
"..........................",
|
||||||
|
"KK........................",
|
||||||
|
".KK.......................",
|
||||||
|
"..KKKKKKKKKKKKKKKKRK......",
|
||||||
|
"..KKKKKKKKKKKKKKKKRKK.....",
|
||||||
|
"...KKKKKKKKKKKKKKKRKKKK...",
|
||||||
|
"...KKKKKKKKKKKKKTTKKTKKK..",
|
||||||
|
"....TKKKKKKKKKKKTTKKWTTK..",
|
||||||
|
"....TT.........TT..KKTTTN.",
|
||||||
|
"....TT.........TT...KTTN..",
|
||||||
|
"...TTT........TTT........."
|
||||||
|
]
|
||||||
|
readonly property var bowlArt: [
|
||||||
|
"...BBB..",
|
||||||
|
"..BBBBB.",
|
||||||
|
".RBBBBBR",
|
||||||
|
".RRRRRR.",
|
||||||
|
"..RRRR.."
|
||||||
|
]
|
||||||
|
|
||||||
|
property var frame: walkA
|
||||||
|
|
||||||
|
// ── Where he lives: the strip along the bottom, the same
|
||||||
|
// floor line the worm lands on.
|
||||||
|
readonly property real floorY: archie.height - Theme.frameWidth
|
||||||
|
readonly property real roamL: Theme.barWidth + 12
|
||||||
|
readonly property real roamR: Math.max(roamL,
|
||||||
|
archie.width - Theme.frameWidth - cols * cell - 12)
|
||||||
|
// Bowl parked over toward the right, clear of the launcher.
|
||||||
|
readonly property real bowlX: Math.max(roamL, roamR - 150)
|
||||||
|
// Stand so his muzzle lands in it rather than his shoulder.
|
||||||
|
readonly property real bowlStandX: bowlX - 18 * cell
|
||||||
|
|
||||||
|
property real px: roamL
|
||||||
|
property int facing: 1 // 1 = right, -1 = left
|
||||||
|
property string mode: "walk"
|
||||||
|
property real targetX: 0
|
||||||
|
property bool toBowl: false
|
||||||
|
property int hold: 0
|
||||||
|
property int tick: 0
|
||||||
|
|
||||||
|
function wander() {
|
||||||
|
mode = "walk";
|
||||||
|
// Not if he is already standing at it — otherwise he can
|
||||||
|
// roll "go to the bowl" while stood in it and eat twice
|
||||||
|
// over without moving.
|
||||||
|
toBowl = Math.random() < 0.3 && Math.abs(px - bowlStandX) > 80;
|
||||||
|
// A short trip from wherever he is, not a random point on
|
||||||
|
// the whole screen: picking uniformly meant single walks
|
||||||
|
// most of a minute long across a wide monitor, which reads
|
||||||
|
// as a patrol. Short hops read as pottering about.
|
||||||
|
let dir = Math.random() < 0.5 ? -1 : 1;
|
||||||
|
// Turn away from an end he is already near. Clamping the
|
||||||
|
// target instead just parks him against the wall, picking
|
||||||
|
// the same spot over and over.
|
||||||
|
if (dir < 0 && px - roamL < 220) dir = 1;
|
||||||
|
if (dir > 0 && roamR - px < 220) dir = -1;
|
||||||
|
targetX = toBowl ? bowlStandX
|
||||||
|
: Math.max(roamL, Math.min(roamR,
|
||||||
|
px + dir * (150 + Math.random() * 550)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function arrive() {
|
||||||
|
if (toBowl) {
|
||||||
|
mode = "eat";
|
||||||
|
hold = 100 + Math.random() * 80;
|
||||||
|
facing = 1; // the bowl is off his nose
|
||||||
|
} else {
|
||||||
|
mode = "idle";
|
||||||
|
hold = 45 + Math.random() * 130;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Placed on the first real width, not on completion: anchors
|
||||||
|
// have not resolved yet at that point, so roamR collapses to
|
||||||
|
// roamL and he spawns pinned to the left edge.
|
||||||
|
property bool placed: false
|
||||||
|
onWidthChanged: {
|
||||||
|
if (placed || width <= 0) return;
|
||||||
|
placed = true;
|
||||||
|
px = roamL + Math.random() * (roamR - roamL);
|
||||||
|
wander();
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 33; running: archie.primary; repeat: true
|
||||||
|
onTriggered: {
|
||||||
|
archie.tick++;
|
||||||
|
if (archie.mode === "walk") {
|
||||||
|
// Arrival first: checking after the step makes him
|
||||||
|
// take a stride backwards when he is already there.
|
||||||
|
if (Math.abs(archie.targetX - archie.px) < 2) {
|
||||||
|
archie.arrive();
|
||||||
|
} else {
|
||||||
|
let dir = archie.targetX > archie.px ? 1 : -1;
|
||||||
|
archie.facing = dir;
|
||||||
|
archie.px += dir * 1.8;
|
||||||
|
// Swap legs every 6 ticks: at 1.8px a tick
|
||||||
|
// that is ~11px of ground per half-stride,
|
||||||
|
// against the 12px the feet actually move in
|
||||||
|
// the art, so he does not moonwalk.
|
||||||
|
archie.frame = archie.tick % 12 < 6 ? archie.walkA : archie.walkB;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
archie.frame = archie.mode === "eat" ? archie.eat
|
||||||
|
: (archie.tick % 26 < 13 ? archie.walkA : archie.wag);
|
||||||
|
if (--archie.hold <= 0) archie.wander();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Sprite. One Rectangle per pixel, colour looked up per
|
||||||
|
// frame; switching frames just rebinds them.
|
||||||
|
component Sprite: Item {
|
||||||
|
id: sp
|
||||||
|
property var art: []
|
||||||
|
property int w: 0
|
||||||
|
property int h: 0
|
||||||
|
width: w * archie.cell
|
||||||
|
height: h * archie.cell
|
||||||
|
Repeater {
|
||||||
|
// Delegates parent to the Repeater's PARENT, so `sp`
|
||||||
|
// is the only reliable way back to the sprite here.
|
||||||
|
model: sp.w * sp.h
|
||||||
|
Rectangle {
|
||||||
|
required property int index
|
||||||
|
readonly property int col: index % sp.w
|
||||||
|
readonly property int row: Math.floor(index / sp.w)
|
||||||
|
readonly property string ch: sp.art[row][col]
|
||||||
|
visible: ch !== "."
|
||||||
|
color: archie.pal[ch] || "transparent"
|
||||||
|
x: col * archie.cell
|
||||||
|
y: row * archie.cell
|
||||||
|
width: archie.cell
|
||||||
|
height: archie.cell
|
||||||
|
antialiasing: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Sprite {
|
||||||
|
art: archie.frame
|
||||||
|
w: archie.cols
|
||||||
|
h: archie.rows
|
||||||
|
// Snap to the pixel grid, same as the worm, or the art
|
||||||
|
// shimmers as he walks.
|
||||||
|
x: Math.round(archie.px / archie.cell) * archie.cell
|
||||||
|
y: Math.round((archie.floorY - height) / archie.cell) * archie.cell
|
||||||
|
// Mirror him when he heads back the other way.
|
||||||
|
transform: Scale { origin.x: archie.cols * archie.cell / 2; xScale: archie.facing }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drawn after him, so at the bowl his nose goes behind it.
|
||||||
|
Sprite {
|
||||||
|
art: archie.bowlArt
|
||||||
|
w: 8
|
||||||
|
h: 5
|
||||||
|
x: Math.round(archie.bowlX / archie.cell) * archie.cell
|
||||||
|
y: Math.round((archie.floorY - height) / archie.cell) * archie.cell
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
"quickshell/Commands.qml" = {
|
"quickshell/Commands.qml" = {
|
||||||
onChange = qsRestart;
|
onChange = qsRestart;
|
||||||
text = ''
|
text = ''
|
||||||
|
|
@ -6772,6 +7023,9 @@ in
|
||||||
{ rect: chromeSdf.launcher, push: Qt.point(0, -1) }
|
{ rect: chromeSdf.launcher, push: Qt.point(0, -1) }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Archie. One dog, primary screen only.
|
||||||
|
Archie { primary: bar.screen === Quickshell.screens[0] }
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue