feat: rebrand app and packaging icons to new Motionity logo
Sync Gitea releases to GitHub / sync-releases (push) Canceled after 0s
Sync Gitea releases to GitHub / sync-releases (push) Canceled after 0s
Swap the small icon mark, README banner, packaged app icon, and favicon over to the new brand assets. make-icon.cjs and the new make-favicon.cjs re-derive their bar geometry/colours from src/assets/logo.svg instead of the old white-bars mark. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7eaa3cd072
commit
759b59d61d
7 files changed
+124
-20
No files matched your search
@@ -1,8 +1,6 @@
|
||||
<div align="center">
|
||||
|
||||
<img src="src/assets/logo.svg" alt="Motionity" width="72">
|
||||
|
||||
# Motionity
|
||||
<img src="src/assets/logo-full.svg" alt="Motionity" width="320">
|
||||
|
||||
**Web-based motion graphics editor** — keyframing, masking, filters, text animations.
|
||||
A free alternative to After Effects and Canva, running entirely in the browser.
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"scripts": {
|
||||
"vendor": "node scripts/vendor.mjs",
|
||||
"icons": "node scripts/make-icon.cjs",
|
||||
"favicon": "node scripts/make-favicon.cjs",
|
||||
"start": "node scripts/server.cjs",
|
||||
"dev": "electron .",
|
||||
"dist:win": "npm run vendor && npm run icons && electron-builder --win",
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env node
|
||||
// Renders src/favicon.ico (32x32) from the same geometry as
|
||||
// src/assets/logo.svg: three coloured rounded bars on the app's dark background.
|
||||
//
|
||||
// Hand-rolled so packaging needs no image toolchain (no ImageMagick, no sharp).
|
||||
|
||||
const { writeFileSync } = require('node:fs');
|
||||
const { resolve } = require('node:path');
|
||||
|
||||
const SIZE = 32;
|
||||
const SS = 8; // supersampling factor, for antialiased edges at small size
|
||||
const BG = [0x14, 0x16, 0x29];
|
||||
const BG_RADIUS = 6; // squircle-ish corner on the icon plate
|
||||
|
||||
// viewBox="0 0 157 183" in src/assets/logo.svg
|
||||
const VIEW = { w: 157, h: 183 };
|
||||
const BARS = [
|
||||
{ x: 79, y: 0, w: 79, h: 47, r: 23.5, fg: [0x75, 0x4b, 0xff] },
|
||||
{ x: 0, y: 68, w: 157, h: 47, r: 23.5, fg: [0x60, 0x2f, 0xff] },
|
||||
{ x: 0, y: 136, w: 79, h: 47, r: 23.5, fg: [0x06, 0x93, 0xc0] },
|
||||
];
|
||||
|
||||
function insideRoundedRect(px, py, { x, y, w, h, r }) {
|
||||
const dx = Math.max(x + r - px, 0, px - (x + w - r));
|
||||
const dy = Math.max(y + r - py, 0, py - (y + h - r));
|
||||
return dx * dx + dy * dy <= r * r;
|
||||
}
|
||||
|
||||
// The logo occupies 62% of the plate, centred.
|
||||
const scale = (SIZE * 0.62) / VIEW.h;
|
||||
const offsetX = (SIZE - VIEW.w * scale) / 2;
|
||||
const offsetY = (SIZE - VIEW.h * scale) / 2;
|
||||
|
||||
const plate = { x: 0, y: 0, w: SIZE, h: SIZE, r: BG_RADIUS };
|
||||
|
||||
// BGRA pixels, row-major, top-to-bottom.
|
||||
const pixels = Buffer.alloc(SIZE * SIZE * 4);
|
||||
for (let py = 0; py < SIZE; py++) {
|
||||
for (let px = 0; px < SIZE; px++) {
|
||||
let plateHits = 0;
|
||||
const colorSum = [0, 0, 0];
|
||||
for (let sy = 0; sy < SS; sy++) {
|
||||
for (let sx = 0; sx < SS; sx++) {
|
||||
const fx = px + (sx + 0.5) / SS;
|
||||
const fy = py + (sy + 0.5) / SS;
|
||||
if (!insideRoundedRect(fx, fy, plate)) continue;
|
||||
plateHits++;
|
||||
const lx = (fx - offsetX) / scale;
|
||||
const ly = (fy - offsetY) / scale;
|
||||
const bar = BARS.find((b) => insideRoundedRect(lx, ly, b));
|
||||
const pixel = bar ? bar.fg : BG;
|
||||
for (let c = 0; c < 3; c++) colorSum[c] += pixel[c];
|
||||
}
|
||||
}
|
||||
const total = SS * SS;
|
||||
const alpha = Math.round((plateHits / total) * 255);
|
||||
const o = (py * SIZE + px) * 4;
|
||||
const r = plateHits ? Math.round(colorSum[0] / plateHits) : 0;
|
||||
const g = plateHits ? Math.round(colorSum[1] / plateHits) : 0;
|
||||
const b = plateHits ? Math.round(colorSum[2] / plateHits) : 0;
|
||||
pixels[o] = b;
|
||||
pixels[o + 1] = g;
|
||||
pixels[o + 2] = r;
|
||||
pixels[o + 3] = alpha;
|
||||
}
|
||||
}
|
||||
|
||||
// Pack into a single-image .ico: ICONDIR + ICONDIRENTRY + BITMAPINFOHEADER
|
||||
// + 32bpp XOR data (bottom-up) + 1bpp AND mask (bottom-up, all-zero since
|
||||
// the XOR data already carries a full alpha channel).
|
||||
const xor = Buffer.alloc(SIZE * SIZE * 4);
|
||||
for (let py = 0; py < SIZE; py++) {
|
||||
const srcRow = py * SIZE * 4;
|
||||
const dstRow = (SIZE - 1 - py) * SIZE * 4; // bottom-up
|
||||
pixels.copy(xor, dstRow, srcRow, srcRow + SIZE * 4);
|
||||
}
|
||||
const andMaskRowBytes = Math.ceil(SIZE / 32) * 4; // 1bpp, padded to 4 bytes
|
||||
const and = Buffer.alloc(andMaskRowBytes * SIZE, 0);
|
||||
|
||||
const dib = Buffer.alloc(40);
|
||||
dib.writeUInt32LE(40, 0); // biSize
|
||||
dib.writeInt32LE(SIZE, 4); // biWidth
|
||||
dib.writeInt32LE(SIZE * 2, 8); // biHeight (XOR + AND)
|
||||
dib.writeUInt16LE(1, 12); // biPlanes
|
||||
dib.writeUInt16LE(32, 14); // biBitCount
|
||||
dib.writeUInt32LE(0, 16); // biCompression: BI_RGB
|
||||
|
||||
const imageData = Buffer.concat([dib, xor, and]);
|
||||
|
||||
const iconDir = Buffer.alloc(6);
|
||||
iconDir.writeUInt16LE(0, 0); // reserved
|
||||
iconDir.writeUInt16LE(1, 2); // type: icon
|
||||
iconDir.writeUInt16LE(1, 4); // image count
|
||||
|
||||
const entry = Buffer.alloc(16);
|
||||
entry[0] = SIZE; // width
|
||||
entry[1] = SIZE; // height
|
||||
entry[2] = 0; // color count
|
||||
entry[3] = 0; // reserved
|
||||
entry.writeUInt16LE(1, 4); // planes
|
||||
entry.writeUInt16LE(32, 6); // bit count
|
||||
entry.writeUInt32LE(imageData.length, 8); // bytes in resource
|
||||
entry.writeUInt32LE(6 + 16, 12); // image offset
|
||||
|
||||
const ico = Buffer.concat([iconDir, entry, imageData]);
|
||||
|
||||
const dest = resolve(__dirname, '..', 'src', 'favicon.ico');
|
||||
writeFileSync(dest, ico);
|
||||
console.log(`Wrote ${dest} (${SIZE}x${SIZE}, ${Math.round(ico.length / 1024)} KB)`);
|
||||
+11
-12
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
// Renders build/icon.png (512x512) from the same geometry as
|
||||
// src/assets/logo.svg: three white rounded bars on the app's dark background.
|
||||
// src/assets/logo.svg: three coloured rounded bars on the app's dark background.
|
||||
//
|
||||
// Hand-rolled so packaging needs no image toolchain (no ImageMagick, no sharp).
|
||||
// electron-builder derives the Windows .ico and the Linux icon set from it.
|
||||
@@ -12,15 +12,14 @@ const { join, resolve } = require('node:path');
|
||||
const SIZE = 512;
|
||||
const SS = 4; // supersampling factor, for antialiased edges
|
||||
const BG = [0x14, 0x16, 0x29];
|
||||
const FG = [0xff, 0xff, 0xff];
|
||||
const BG_RADIUS = 96; // squircle-ish corner on the icon plate
|
||||
|
||||
// viewBox="0 0 24 19" in src/assets/logo.svg
|
||||
const VIEW = { w: 24, h: 19 };
|
||||
// viewBox="0 0 157 183" in src/assets/logo.svg
|
||||
const VIEW = { w: 157, h: 183 };
|
||||
const BARS = [
|
||||
{ x: 17.3193, y: 8.36011, w: 6.08, h: 10.64, r: 3.04 },
|
||||
{ x: 8.95996, y: 0, w: 6.08, h: 19, r: 3.04 },
|
||||
{ x: 0.599609, y: 0, w: 6.08, h: 19, r: 3.04 },
|
||||
{ x: 79, y: 0, w: 79, h: 47, r: 23.5, fg: [0x75, 0x4b, 0xff] },
|
||||
{ x: 0, y: 68, w: 157, h: 47, r: 23.5, fg: [0x60, 0x2f, 0xff] },
|
||||
{ x: 0, y: 136, w: 79, h: 47, r: 23.5, fg: [0x06, 0x93, 0xc0] },
|
||||
];
|
||||
|
||||
function insideRoundedRect(px, py, { x, y, w, h, r }) {
|
||||
@@ -43,7 +42,7 @@ for (let py = 0; py < SIZE; py++) {
|
||||
raw[rowStart] = 0;
|
||||
for (let px = 0; px < SIZE; px++) {
|
||||
let plateHits = 0;
|
||||
let barHits = 0;
|
||||
const colorSum = [0, 0, 0];
|
||||
for (let sy = 0; sy < SS; sy++) {
|
||||
for (let sx = 0; sx < SS; sx++) {
|
||||
const fx = px + (sx + 0.5) / SS;
|
||||
@@ -52,16 +51,16 @@ for (let py = 0; py < SIZE; py++) {
|
||||
plateHits++;
|
||||
const lx = (fx - offsetX) / scale;
|
||||
const ly = (fy - offsetY) / scale;
|
||||
if (BARS.some((bar) => insideRoundedRect(lx, ly, bar))) barHits++;
|
||||
const bar = BARS.find((b) => insideRoundedRect(lx, ly, b));
|
||||
const pixel = bar ? bar.fg : BG;
|
||||
for (let c = 0; c < 3; c++) colorSum[c] += pixel[c];
|
||||
}
|
||||
}
|
||||
const total = SS * SS;
|
||||
const alpha = Math.round((plateHits / total) * 255);
|
||||
// Blend bar coverage over the plate colour; alpha carries the plate edge.
|
||||
const mix = plateHits ? barHits / plateHits : 0;
|
||||
const o = rowStart + 1 + px * 4;
|
||||
for (let c = 0; c < 3; c++) {
|
||||
raw[o + c] = Math.round(BG[c] + (FG[c] - BG[c]) * mix);
|
||||
raw[o + c] = plateHits ? Math.round(colorSum[c] / plateHits) : 0;
|
||||
}
|
||||
raw[o + 3] = alpha;
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg width="1041" xmlns="http://www.w3.org/2000/svg" height="249" id="screenshot-4511fdde-0f5d-8050-8008-831c6f87d3da" viewBox="-27 -27 1041 249" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1"><g id="shape-4511fdde-0f5d-8050-8008-831c6f87d3da" rx="0" ry="0"><g id="shape-2e51c812-4a20-800d-8008-831bec3241b0"><g class="fills" id="fills-2e51c812-4a20-800d-8008-831bec3241b0"><rect rx="0" ry="0" x="0" y="0" transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)" width="1014" height="199"/></g></g><g id="shape-2e51c812-4a20-800d-8008-830d6a6076f4" rx="0" ry="0"><g id="shape-2e51c812-4a20-800d-8008-8317dfbba269" style="opacity: 1;"><g class="fills" id="fills-2e51c812-4a20-800d-8008-8317dfbba269"><path d="M322.3599853515625,66.16213989257812L322.3599853515625,161.01779174804688L295.82000732421875,161.01779174804688L295.82000732421875,66.16213989257812C295.82000732421875,64.31163024902344,295.4666748046875,62.58092498779297,294.760009765625,60.97004699707031C294.046630859375,59.365814208984375,293.086669921875,57.9612922668457,291.8800048828125,56.7564582824707C290.67333984375,55.55162811279297,289.26666259765625,54.609718322753906,287.6600341796875,53.93075942993164C286.0533447265625,53.25179672241211,284.32000732421875,52.91231918334961,282.4599609375,52.91231918334961L282.4599609375,52.91231918334961C280.606689453125,52.91231918334961,278.87664794921875,53.25179672241211,277.27001953125,53.93075942993164C275.663330078125,54.609718322753906,274.25665283203125,55.55162811279297,273.04998779296875,56.7564582824707C271.84332275390625,57.9612922668457,270.9000244140625,59.365814208984375,270.219970703125,60.97004699707031C269.5400390625,62.58092498779297,269.20001220703125,64.31163024902344,269.20001220703125,66.16213989257812L269.20001220703125,66.16213989257812L269.20001220703125,161.01779174804688L242.57000732421875,161.01779174804688L242.57000732421875,66.16213989257812C242.57000732421875,64.31163024902344,242.22998046875,62.58092498779297,241.54998779296875,60.97004699707031C240.8699951171875,59.365814208984375,239.9266357421875,57.9612922668457,238.719970703125,56.7564582824707C237.5133056640625,55.55162811279297,236.106689453125,54.609718322753906,234.5,53.93075942993164C232.893310546875,53.25179672241211,231.1600341796875,52.91231918334961,229.29998779296875,52.91231918334961L229.29998779296875,52.91231918334961C227.4466552734375,52.91231918334961,225.7166748046875,53.25179672241211,224.1099853515625,53.93075942993164C222.5032958984375,54.609718322753906,221.0966796875,55.55162811279297,219.8900146484375,56.7564582824707C218.683349609375,57.9612922668457,217.739990234375,59.365814208984375,217.05999755859375,60.97004699707031C216.3800048828125,62.58092498779297,216.0400390625,64.31163024902344,216.0400390625,66.16213989257812L216.0400390625,66.16213989257812L216.0400390625,161.01779174804688L189.4100341796875,161.01779174804688L189.4100341796875,66.16213989257812C189.4100341796875,60.66384506225586,190.4466552734375,55.49170684814453,192.52001953125,50.645748138427734C194.59332275390625,45.79978942871094,197.4366455078125,41.56956481933594,201.04998779296875,37.95507049560547C204.6700439453125,34.340579986572266,208.90667724609375,31.501564025878906,213.760009765625,29.438034057617188C218.6199951171875,27.36785125732422,223.79998779296875,26.332763671875,229.29998779296875,26.332763671875L229.29998779296875,26.332763671875C234.2532958984375,26.332763671875,239.01666259765625,27.21142578125,243.5899658203125,28.96875C248.16998291015625,30.73272705078125,252.2833251953125,33.282188415527344,255.92999267578125,36.61711120605469L255.92999267578125,36.61711120605469C259.57666015625,33.282188415527344,263.67333984375,30.73272705078125,268.219970703125,28.96875C272.76666259765625,27.21142578125,277.5133056640625,26.332763671875,282.4599609375,26.332763671875L282.4599609375,26.332763671875C287.9666748046875,26.332763671875,293.14666748046875,27.36785125732422,298,29.438034057617188C302.8599853515625,31.501564025878906,307.0966796875,34.340579986572266,310.71002197265625,37.95507049560547C314.33001708984375,41.56956481933594,317.1766357421875,45.79978942871094,319.25,50.645748138427734C321.3233642578125,55.49170684814453,322.3599853515625,60.66384506225586,322.3599853515625,66.16213989257812L322.3599853515625,66.16213989257812L322.3599853515625,66.16213989257812M438.32000732421875,110.53462219238281L438.32000732421875,110.53462219238281C438.32000732421875,117.94335174560547,436.989990234375,124.84284973144531,434.3299560546875,131.23312377929688C431.66998291015625,137.63006591796875,428.0533447265625,143.15830993652344,423.47998046875,147.81788635253906C418.9000244140625,152.4774627685547,413.5333251953125,156.15187072753906,407.3800048828125,158.8411102294922C401.2266845703125,161.53036499023438,394.62664794921875,162.87496948242188,387.58001708984375,162.87496948242188L387.58001708984375,162.87496948242188C380.586669921875,162.87496948242188,374.0133056640625,161.53036499Line truncated
|
||||
|
After Width: | Height: | Size: 23 KiB |
+1
-5
@@ -1,5 +1 @@
|
||||
<svg width="24" height="19" viewBox="0 0 24 19" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="17.3193" y="8.36011" width="6.08" height="10.64" rx="3.04" fill="white"/>
|
||||
<rect x="8.95996" width="6.08" height="19" rx="3.04" fill="white"/>
|
||||
<rect x="0.599609" width="6.08" height="19" rx="3.04" fill="white"/>
|
||||
</svg>
|
||||
<svg width="246" xmlns="http://www.w3.org/2000/svg" height="271" id="screenshot-4511fdde-0f5d-8050-8008-831c5de8b5f2" viewBox="-32 -32 246 271" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1"><g id="shape-4511fdde-0f5d-8050-8008-831c5de8b5f2" filter="url(#filter-render-1)" rx="0" ry="0"><defs><filter id="filter-render-1" x="-0.17088607594936708" y="-0.14754098360655737" width="1.4177215189873418" height="1.360655737704918" filterUnits="objectBoundingBox" color-interpolation-filters="sRGB"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/><feOffset dx="4" dy="4"/><feGaussianBlur stdDeviation="2"/><feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0"/><feBlend mode="normal" in2="BackgroundImageFix" result="filter_2e51c812-4a20-800d-8008-830c8cbbedac"/><feBlend mode="normal" in="SourceGraphic" in2="filter_2e51c812-4a20-800d-8008-830c8cbbedac" result="shape"/></filter><filter id="filter-shadow-render-1" x="-0.17088607594936708" y="-0.14754098360655737" width="1.4177215189873418" height="1.360655737704918" filterUnits="objectBoundingBox" color-interpolation-filters="sRGB"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/><feOffset dx="4" dy="4"/><feGaussianBlur stdDeviation="2"/><feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0"/><feBlend mode="normal" in2="BackgroundImageFix" result="filter_2e51c812-4a20-800d-8008-830c8cbbedac"/><feBlend mode="normal" in="SourceGraphic" in2="filter_2e51c812-4a20-800d-8008-830c8cbbedac" result="shape"/></filter></defs><g id="shape-4511fdde-0f5d-8050-8008-831c5de8b5f3"><g class="fills" id="fills-4511fdde-0f5d-8050-8008-831c5de8b5f3"><rect rx="23.5" ry="23.5" x="79" y="0" transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)" width="79" height="47" style="fill: rgb(117, 75, 255); fill-opacity: 1;"/></g></g><g id="shape-4511fdde-0f5d-8050-8008-831c5de8b5f4"><g class="fills" id="fills-4511fdde-0f5d-8050-8008-831c5de8b5f4"><rect rx="23.5" ry="23.5" x="0" y="68" transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)" width="157" height="47" style="fill: rgb(96, 47, 255); fill-opacity: 1;"/></g></g><g id="shape-4511fdde-0f5d-8050-8008-831c5de8b5f5"><g class="fills" id="fills-4511fdde-0f5d-8050-8008-831c5de8b5f5"><rect rx="23.5" ry="23.5" x="0" y="136" transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)" width="79" height="47" style="fill: rgb(6, 147, 192); fill-opacity: 1;"/></g></g></g></svg>
|
||||
|
Before Width: | Height: | Size: 323 B After Width: | Height: | Size: 2.6 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
Reference in new issue
Block a user