diff --git a/.github/workflows/apply-brand-scale-fix.yml b/.github/workflows/apply-brand-scale-fix.yml deleted file mode 100644 index 57efc82..0000000 --- a/.github/workflows/apply-brand-scale-fix.yml +++ /dev/null @@ -1,316 +0,0 @@ -name: Apply Brand And Scale Fix - -on: - push: - branches: [ master ] - -permissions: - contents: write - -jobs: - apply-fix: - if: github.actor != 'github-actions[bot]' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - ref: master - fetch-depth: 0 - - - name: Restore original mark and reduce landing scale - shell: bash - run: | - python - <<'PY' - from pathlib import Path - import math - import re - import struct - import zlib - - root = Path('.') - - brand_mark = '''import React from 'react'; - -interface BrandMarkProps { - className?: string; - title?: string; -} - -export const BrandMark: React.FC = ({ - className = 'h-9 w-9', - title = 'Hardware Studio', -}) => ( - - - -); -''' - Path('src/components/BrandMark.tsx').write_text(brand_mark) - - icon_svg = ''' - - - - - - - - - -''' - Path('src/app/icon.svg').write_text(icon_svg) - - # Add explicit icon metadata so browsers consistently prefer the ICO while - # retaining the SVG for high-density surfaces. - layout_path = Path('src/app/layout.tsx') - layout = layout_path.read_text() - marker = " robots: {\n index: true,\n follow: true,\n },\n" - icons = " icons: {\n icon: [\n { url: '/favicon.ico', sizes: 'any' },\n { url: '/icon.svg', type: 'image/svg+xml' },\n ],\n shortcut: '/favicon.ico',\n },\n" - if ' icons: {' not in layout: - if marker not in layout: - raise SystemExit('Could not locate metadata insertion point') - layout = layout.replace(marker, marker + icons) - layout_path.write_text(layout) - - # Reduce landing-page visual scale without altering its composition. - page_path = Path('src/app/page.tsx') - page = page_path.read_text() - replacements = { - 'h-14 max-w-[1280px]': 'h-12 max-w-[1120px]', - 'className="flex items-center gap-2.5" aria-label="Hardware Studio home"': 'className="flex items-center gap-2" aria-label="Hardware Studio home"', - '': '', - 'text-[13px] font-semibold tracking-[-0.02em]': 'text-[12px] font-semibold tracking-[-0.02em]', - 'mt-0.5 text-[8px] uppercase tracking-[0.18em]': 'mt-0.5 text-[7px] uppercase tracking-[0.17em]', - 'gap-6 text-[11px]': 'gap-5 text-[10px]', - 'px-3.5 py-2 text-[10px]': 'px-3 py-1.5 text-[10px]', - 'max-w-[1280px] px-4 pb-14 pt-10 sm:px-6 sm:pb-16 sm:pt-14 lg:px-8 lg:pb-20 lg:pt-16': 'max-w-[1120px] px-4 pb-10 pt-8 sm:px-6 sm:pb-12 sm:pt-10 lg:px-8 lg:pb-14 lg:pt-12', - 'h-[420px] w-[760px]': 'h-[340px] w-[650px]', - 'gap-10 lg:grid-cols-[0.96fr_1.04fr] lg:gap-14': 'gap-8 lg:grid-cols-[0.94fr_1.06fr] lg:gap-10', - 'max-w-[650px]': 'max-w-[540px]', - 'mb-5 inline-flex': 'mb-4 inline-flex', - 'px-3 py-1.5 text-[9px]': 'px-2.5 py-1 text-[8px]', - 'text-[clamp(2.75rem,5.4vw,5.45rem)]': 'text-[clamp(2.35rem,4.25vw,4.25rem)]', - 'mt-6 max-w-[610px] text-[15px] leading-7 text-black/60 sm:text-base': 'mt-4 max-w-[520px] text-[13px] leading-6 text-black/60 sm:text-[14px]', - 'mt-7 flex flex-col': 'mt-5 flex flex-col', - 'h-11 items-center justify-center gap-2 rounded-full bg-[#11110f] px-5 text-[12px]': 'h-10 items-center justify-center gap-2 rounded-full bg-[#11110f] px-4 text-[11px]', - 'h-11 items-center justify-center gap-2 rounded-full border border-black/15 bg-white/48 px-5 text-[12px]': 'h-10 items-center justify-center gap-2 rounded-full border border-black/15 bg-white/48 px-4 text-[11px]', - 'mt-6 flex max-w-[610px] items-start gap-3 rounded-2xl border border-red-950/15 bg-red-50/55 p-3.5 text-[12px] leading-5': 'mt-5 flex max-w-[520px] items-start gap-2.5 rounded-xl border border-red-950/15 bg-red-50/55 p-3 text-[11px] leading-5', - 'max-w-[570px]': 'max-w-[500px]', - '-inset-6 rounded-[40px]': '-inset-4 rounded-[34px]', - 'rounded-[24px] border border-black/12 bg-[#151512] p-3': 'rounded-[22px] border border-black/12 bg-[#151512] p-2.5', - 'min-h-[350px] overflow-hidden rounded-[17px] border border-white/8 bg-[#0c0c0b] p-4 sm:min-h-[410px] sm:p-5': 'min-h-[300px] overflow-hidden rounded-[16px] border border-white/8 bg-[#0c0c0b] p-3.5 sm:min-h-[350px] sm:p-4', - 'min-h-[318px] flex-col justify-between sm:min-h-[368px]': 'min-h-[270px] flex-col justify-between sm:min-h-[310px]', - 'my-4 w-[76%] rounded-[20px]': 'my-3 w-[78%] rounded-[18px]', - 'bg-emerald-300/10 p-4 text-center': 'bg-emerald-300/10 p-3.5 text-center', - 'max-w-[1280px]': 'max-w-[1120px]', - 'px-4 py-14 sm:px-6 sm:py-16 lg:px-8 lg:py-20': 'px-4 py-11 sm:px-6 sm:py-12 lg:px-8 lg:py-14', - 'gap-8 px-4 py-14 sm:px-6 sm:py-16 lg:grid-cols-[0.82fr_1.18fr] lg:px-8 lg:py-20': 'gap-7 px-4 py-11 sm:px-6 sm:py-12 lg:grid-cols-[0.82fr_1.18fr] lg:px-8 lg:py-14', - 'mb-9 max-w-[720px]': 'mb-7 max-w-[680px]', - 'text-3xl font-semibold leading-[1.04] tracking-[-0.042em] sm:text-4xl': 'text-[1.75rem] font-semibold leading-[1.04] tracking-[-0.042em] sm:text-3xl', - 'text-3xl font-semibold tracking-[-0.042em] sm:text-4xl': 'text-[1.75rem] font-semibold tracking-[-0.042em] sm:text-3xl', - 'rounded-[20px] border border-black/10 bg-white/42 p-5': 'rounded-[18px] border border-black/10 bg-white/42 p-4', - 'mt-5 text-[17px]': 'mt-4 text-[15px]', - 'mt-10 overflow-hidden rounded-[22px]': 'mt-8 overflow-hidden rounded-[20px]', - 'p-5 text-[#f3f0e8] sm:p-6': 'p-4 text-[#f3f0e8] sm:p-5', - 'rounded-[24px] border border-black/12 bg-[#11110f] px-5 py-8': 'rounded-[22px] border border-black/12 bg-[#11110f] px-5 py-7', - 'sm:px-8 sm:py-10 lg:px-10': 'sm:px-7 sm:py-8 lg:px-8', - 'h-11 items-center justify-center gap-2 rounded-full bg-[#f3f0e8] px-5 text-[12px]': 'h-10 items-center justify-center gap-2 rounded-full bg-[#f3f0e8] px-4 text-[11px]', - 'h-11 items-center justify-center gap-2 rounded-full border border-white/15 px-5 text-[12px]': 'h-10 items-center justify-center gap-2 rounded-full border border-white/15 px-4 text-[11px]', - } - for old, new in replacements.items(): - if old in page: - page = page.replace(old, new) - page_path.write_text(page) - - # Remove all remaining private legacy branding from repository text. - targeted = [ - ('by System Alpha', 'connected engineering workspace'), - ('By System Alpha', 'Connected engineering workspace'), - ('BY SYSTEM ALPHA', 'CONNECTED ENGINEERING WORKSPACE'), - ('System Alpha External Logic', 'External Companion Logic'), - ('System Alpha Local Engine / API Server', 'Local companion engine / API server'), - ('real System Alpha host software', 'a real companion host'), - ('System Alpha host software', 'companion host software'), - ('System Alpha host', 'companion host'), - ('system-alpha-external', 'companion-software-external'), - ('SYSTEM-ALPHA', 'HARDWARE-STUDIO'), - ('system-alpha', 'hardware-studio'), - ('system_alpha', 'hardware_studio'), - ('System Alpha', 'Hardware Studio'), - ] - allowed_suffixes = {'.ts', '.tsx', '.js', '.jsx', '.json', '.md', '.txt', '.yml', '.yaml', '.html', '.css'} - for file in root.rglob('*'): - if not file.is_file() or file.suffix.lower() not in allowed_suffixes: - continue - if '.git' in file.parts or file == Path('.github/workflows/apply-brand-scale-fix.yml'): - continue - try: - text = file.read_text() - except UnicodeDecodeError: - continue - updated = text - for old, new in targeted: - updated = updated.replace(old, new) - if updated != text: - file.write_text(updated) - - # Produce a real ICO file with the same restored mark using only stdlib. - # Render at 256px, then box-average to 64px for antialiased edges. - high = 256 - out = 64 - scale = high / 64 - pixels = [(0, 0, 0, 0)] * (high * high) - - def inside_round_rect(x, y, left, top, right, bottom, radius): - if left + radius <= x <= right - radius and top <= y <= bottom: - return True - if left <= x <= right and top + radius <= y <= bottom - radius: - return True - cx = left + radius if x < left + radius else right - radius - cy = top + radius if y < top + radius else bottom - radius - return (x - cx) ** 2 + (y - cy) ** 2 <= radius ** 2 - - def blend_pixel(x, y, color): - if 0 <= x < high and 0 <= y < high: - pixels[y * high + x] = color - - for y in range(high): - for x in range(high): - if inside_round_rect(x + 0.5, y + 0.5, 0, 0, high - 1, high - 1, 64): - blend_pixel(x, y, (17, 17, 15, 255)) - - white = (243, 240, 232, 255) - stroke = 3.4 * scale - - def dist_segment(px, py, x1, y1, x2, y2): - vx, vy = x2 - x1, y2 - y1 - wx, wy = px - x1, py - y1 - c1 = vx * wx + vy * wy - if c1 <= 0: - return math.hypot(px - x1, py - y1) - c2 = vx * vx + vy * vy - if c2 <= c1: - return math.hypot(px - x2, py - y2) - b = c1 / c2 - bx, by = x1 + b * vx, y1 + b * vy - return math.hypot(px - bx, py - by) - - def draw_segment(x1, y1, x2, y2, width): - x1 *= scale; y1 *= scale; x2 *= scale; y2 *= scale - half = width * scale / 2 - xmin = max(0, int(min(x1, x2) - half - 1)); xmax = min(high - 1, int(max(x1, x2) + half + 1)) - ymin = max(0, int(min(y1, y2) - half - 1)); ymax = min(high - 1, int(max(y1, y2) + half + 1)) - for yy in range(ymin, ymax + 1): - for xx in range(xmin, xmax + 1): - if dist_segment(xx + 0.5, yy + 0.5, x1, y1, x2, y2) <= half: - blend_pixel(xx, yy, white) - - def draw_circle(cx, cy, radius, width): - cx *= scale; cy *= scale; radius *= scale; half = width * scale / 2 - xmin = max(0, int(cx - radius - half - 1)); xmax = min(high - 1, int(cx + radius + half + 1)) - ymin = max(0, int(cy - radius - half - 1)); ymax = min(high - 1, int(cy + radius + half + 1)) - for yy in range(ymin, ymax + 1): - for xx in range(xmin, xmax + 1): - d = math.hypot(xx + 0.5 - cx, yy + 0.5 - cy) - if abs(d - radius) <= half: - blend_pixel(xx, yy, white) - - # Rounded inner frame approximated with straight segments and quarter-circle arcs. - draw_segment(18, 14, 46, 14, 3.4) - draw_segment(50, 18, 50, 46, 3.4) - draw_segment(46, 50, 18, 50, 3.4) - draw_segment(14, 46, 14, 18, 3.4) - for cx, cy, a0 in [(18,18,180),(46,18,270),(46,46,0),(18,46,90)]: - pts = [] - for i in range(13): - a = math.radians(a0 + i * 90 / 12) - pts.append((cx + 4 * math.cos(a), cy + 4 * math.sin(a))) - for p1, p2 in zip(pts, pts[1:]): - draw_segment(*p1, *p2, 3.4) - - draw_segment(30, 26, 38, 26, 3.4) - # top-right bend - pts = [(38,26),(39.5,25.7),(40.8,24.8),(41.7,23.5),(42,22),(42,14)] - for p1, p2 in zip(pts, pts[1:]): draw_segment(*p1, *p2, 3.4) - draw_circle(26, 26, 4, 3.4) - draw_segment(22, 50, 22, 42, 3.4) - pts = [(22,42),(22.3,40.5),(23.2,39.2),(24.5,38.3),(26,38),(34,38)] - for p1, p2 in zip(pts, pts[1:]): draw_segment(*p1, *p2, 3.4) - draw_circle(38, 38, 4, 3.4) - - small = [] - factor = high // out - for oy in range(out): - for ox in range(out): - block = [] - for yy in range(oy * factor, (oy + 1) * factor): - for xx in range(ox * factor, (ox + 1) * factor): - block.append(pixels[yy * high + xx]) - small.append(tuple(sum(p[i] for p in block) // len(block) for i in range(4))) - - def png_bytes(width, height, rgba): - raw = bytearray() - for y in range(height): - raw.append(0) - for x in range(width): - raw.extend(rgba[y * width + x]) - def chunk(kind, data): - return struct.pack('>I', len(data)) + kind + data + struct.pack('>I', zlib.crc32(kind + data) & 0xffffffff) - return (b'\x89PNG\r\n\x1a\n' + - chunk(b'IHDR', struct.pack('>IIBBBBB', width, height, 8, 6, 0, 0, 0)) + - chunk(b'IDAT', zlib.compress(bytes(raw), 9)) + - chunk(b'IEND', b'')) - - png = png_bytes(out, out, small) - ico_header = struct.pack(' - - - - - - + + + + + + + diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 2271552..b1a8a5d 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -39,6 +39,13 @@ export const metadata: Metadata = { index: true, follow: true, }, + icons: { + icon: [ + { url: '/favicon.ico', sizes: 'any' }, + { url: '/icon.svg', type: 'image/svg+xml' }, + ], + shortcut: '/favicon.ico', + }, }; export default function RootLayout({ diff --git a/src/app/page.tsx b/src/app/page.tsx index f571970..9ad800b 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -105,18 +105,18 @@ export default function Home() { return (
-
- - +
+ +
-
Hardware Studio
-
+
Hardware Studio
+
Connected engineering workspace
-
-
-
+
+
-
-
-
+
+
+
Foundation under active construction
-

+

Design the whole product. Not disconnected files.

-

+

Hardware Studio is an ambitious attempt to unify product requirements, mechanical design, electronics, PCB, firmware, validation, and manufacturing release around one connected product graph.

-
+
Explore the development build @@ -164,14 +164,14 @@ export default function Home() { href="https://github.com/Ankit6149/hardware-studio" target="_blank" rel="noreferrer" - className="inline-flex h-11 items-center justify-center gap-2 rounded-full border border-black/15 bg-white/48 px-5 text-[12px] font-semibold transition hover:border-black/30 hover:bg-white" + className="inline-flex h-10 items-center justify-center gap-2 rounded-full border border-black/15 bg-white/48 px-4 text-[11px] font-semibold transition hover:border-black/30 hover:bg-white" > View the repository
-
+

Not ready for production.{' '} @@ -180,9 +180,9 @@ export default function Home() {

-
-
-
+
+
+
@@ -194,18 +194,18 @@ export default function Home() {
-
+
-
+
-
+
Canonical product graph @@ -232,12 +232,12 @@ export default function Home() {
-
+
The long-term vision
-

+

An operating environment for complete physical products.

@@ -258,15 +258,15 @@ export default function Home() {
-
-
+
+
Shared workbenches
-

+

Move through the product, not between disconnected tools.

-

+

Each workbench is intended to operate on the same durable product model. The current repository contains early foundations for these areas—not complete replacements for established engineering suites.

@@ -275,7 +275,7 @@ export default function Home() { {workbenches.map(({ icon: Icon, name, description, items }, index) => (
@@ -283,7 +283,7 @@ export default function Home() {
0{index + 1}
-

{name}

+

{name}

{description}

{items.map((item) => ( @@ -298,13 +298,13 @@ export default function Home() {
-
+
Design principles
-

+

Built around engineering state, not screenshots.

@@ -323,7 +323,7 @@ export default function Home() {

-
+
@@ -346,15 +346,15 @@ export default function Home() {
-
-
+
+
Current development status
-

+

The vision is large. The foundation is still early.

-

+

This repository is public so the system can be built in the open. It should be evaluated as an active engineering experiment—not as finished CAD, EDA, PLM, firmware, or manufacturing software.

@@ -378,14 +378,14 @@ export default function Home() {
-
-
+
+
Building in public
-

+

Follow the attempt to connect the entire hardware lifecycle.

@@ -393,11 +393,11 @@ export default function Home() {

- + Open development build - + Inspect the source @@ -408,7 +408,7 @@ export default function Home() {