Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/thick-lions-smile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@jolly-pixel/pixel-draw.renderer": minor
---

Add a `backgroundColor` option/property to `PixelArtCanvas`, letting callers set the canvas void color explicitly instead of relying solely on the parent element's inferred CSS `background-color`
19 changes: 18 additions & 1 deletion packages/pixel-draw-renderer/docs/PixelArtCanvas.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ interface PixelArtCanvasOptions {
colors: { odd: string; even: string; };
squareSize: number;
};
/**
* Fill color for the canvas area outside the texture bounds (the "void"
* around the drawing surface). Defaults to the parent element's own CSS
* `background-color` if it's set and non-transparent, else `#424242`.
*/
backgroundColor?: ColorInput;
brush?: BrushOptions;
select?: {
/**
Expand Down Expand Up @@ -89,7 +95,7 @@ interface PixelArtCanvasOptions {

Undocumented defaults: `texture.size` is `{ x: 64, y: 32 }` (`y` falls back to `x` when only `x` is given), `texture.maxSize` is `2048`, `zoom.default` is `4`, `zoom.min`/`zoom.max` are `1`/`32`, `zoom.sensitivity` is `0.1`, `backgroundTransparency.squareSize` is `8`, `backgroundTransparency.colors` is `{ odd: "#999", even: "#666" }`.

The background color used behind transparent texture pixels is read from `getComputedStyle(parentHtmlElement).backgroundColor` at construction time (falling back to `#555555` if unset or fully transparent); it isn't a configurable option.
The `backgroundColor` option, if given, wins outright. Otherwise it's read from `getComputedStyle(parentHtmlElement).backgroundColor` at construction time, falling back to `#424242` if that's unset or fully transparent. See the `backgroundColor` property below to change it after construction.

## Properties

Expand Down Expand Up @@ -141,6 +147,17 @@ A global fill is still committed and undoable as a single atomic edit, but is br

---

### `backgroundColor`

```ts
get backgroundColor(): string
set backgroundColor(color: ColorInput)
```

Reads or changes the fill color for the canvas area outside the texture bounds — see the `backgroundColor` constructor option above for how the initial value is resolved. The setter takes effect immediately (redraws the canvas itself); no `drawFrame()` call needed.

---

### `textureSize`

```ts
Expand Down
22 changes: 21 additions & 1 deletion packages/pixel-draw-renderer/examples/public/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,38 @@ body {
}

.resize-handle.left {
width: 4px;
position: relative;
width: 8px;
flex-shrink: 0;
background: #1a2228;
cursor: col-resize;
transition: background 0.15s;
}

.resize-handle.left::after {
content: "";
position: absolute;
top: 50%;
left: 50%;
width: 3px;
height: 22px;
transform: translate(-50%, -50%);
background-image: radial-gradient(circle, #6d8794 1.1px, transparent 1.3px);
background-size: 100% 7px;
background-repeat: repeat-y;
pointer-events: none;
}

.resize-handle.left:hover,
html.handle-dragging.vertical .resize-handle.left {
background: #4488ff;
}

.resize-handle.left:hover::after,
html.handle-dragging.vertical .resize-handle.left::after {
background-image: radial-gradient(circle, #ffffff 1.1px, transparent 1.3px);
}

html.handle-dragging.vertical {
cursor: col-resize;
}
Expand Down
10 changes: 8 additions & 2 deletions packages/pixel-draw-renderer/examples/scripts/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,22 @@ async function initRuntime(): Promise<Runtime> {
const drawPanel = document.querySelector<PixelDrawPanel>("pixel-draw-panel")!;
const canvasManager = await drawPanel.initialize({
texture: {
size: { x: 16, y: 16 }
size: {
x: 16,
y: 16
}
},
defaultMode: "paint",
backgroundColor: "#263238",
zoom: {
default: 16,
min: 1,
max: 32,
sensitivity: 1
},
brush: { size: 1 },
brush: {
size: 1
},
history: {
enabled: true
}
Expand Down
41 changes: 37 additions & 4 deletions packages/pixel-draw-renderer/examples/scripts/ui/ColorSwatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@ export class ColorSwatch extends LitElement {
button {
width: 26px;
height: 26px;
border: 2px solid var(--color-swatch-border, #666);
border: 2px solid var(--color-swatch-border, #556067);
border-radius: var(--color-swatch-radius, 4px);
cursor: pointer;
padding: 0;
background: #000000;
box-sizing: border-box;
}

button:focus-visible {
Expand Down Expand Up @@ -152,23 +153,55 @@ export class ColorSwatch extends LitElement {
}
}

/**
* Closes the picker if open. Lets a container holding multiple swatches
* (e.g. foreground/background) enforce only one open at a time.
*/
close(): void {
this.#setOpen(false);
}

#setOpen(
open: boolean
): void {
this.#open = open;
const portal = this.#portal!;
if (open) {
const rect = this.#buttonEl!.getBoundingClientRect();
portal.style.left = `${rect.left}px`;
portal.style.top = `${rect.bottom + 4}px`;
portal.style.display = "";
this.#positionPortal();
// Lets a container close sibling swatches so only one picker is open at a time.
this.dispatchEvent(new CustomEvent("swatch-opened", { bubbles: true, composed: true }));
}
else {
portal.style.display = "none";
}
this.requestUpdate();
}

/**
* Flips the popup above the button when there isn't enough room below (and
* clamps both axes to the viewport) instead of letting it run off-screen.
* getBoundingClientRect() forces the layout needed to measure the portal's
* real size right after `display` is unhidden.
*/
#positionPortal(): void {
const portal = this.#portal!;
const margin = 4;
const buttonRect = this.#buttonEl!.getBoundingClientRect();
const portalRect = portal.getBoundingClientRect();

const fitsBelow = window.innerHeight - buttonRect.bottom >= portalRect.height + margin;
const top = fitsBelow
? buttonRect.bottom + margin
: Math.max(margin, buttonRect.top - portalRect.height - margin);

const maxLeft = window.innerWidth - portalRect.width - margin;
const left = Math.min(buttonRect.left, Math.max(margin, maxLeft));

portal.style.top = `${top}px`;
portal.style.left = `${left}px`;
}

readonly #onSwatchClick = (
event: MouseEvent
): void => {
Expand Down
Loading
Loading