update bauhaus privacy policy and blog styling

This commit is contained in:
jwinterm
2026-02-06 13:10:15 -05:00
parent 1705497ca6
commit 375e7e2868
9 changed files with 313 additions and 93 deletions
+1
View File
@@ -28,6 +28,7 @@
"devDependencies": {
"@axe-core/playwright": "^4.11.0",
"@playwright/test": "^1.57.0",
"@tailwindcss/typography": "^0.5.19",
"@types/node": "^20.0.0",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
@@ -13,56 +13,59 @@ export default function BauhausEchoLaunchPost() {
return (
<main className="relative min-h-screen flex flex-col items-center bg-background text-foreground">
<Header />
<article id="main-content" className="z-10 w-full max-w-3xl mx-auto py-20 px-4 pb-24 md:pb-20">
<Link href="/blog" className="text-sm text-muted-foreground hover:text-foreground mb-8 inline-block">
<article id="main-content" className="z-10 w-full max-w-4xl mx-auto py-20 px-4 pb-24 md:pb-20">
<Link href="/blog" className="text-sm text-muted-foreground hover:text-emerald-600 dark:hover:text-emerald-400 mb-8 inline-flex items-center gap-2 transition-colors">
← Back to Blog
</Link>
<header className="mb-12">
<time className="text-sm text-muted-foreground">February 6, 2026</time>
<h1 className="text-3xl md:text-4xl font-bold mt-2">Bauhaus Echo is Live</h1>
</header>
<div className="glass-card mt-6">
<header className="mb-8 pb-6 border-b border-border">
<time className="text-sm text-muted-foreground">February 6, 2026</time>
<h1 className="text-3xl md:text-4xl font-bold mt-2">Bauhaus Echo is Live</h1>
<p className="text-muted-foreground mt-3">A visual memory puzzle inspired by Bauhaus design</p>
</header>
<div className="prose dark:prose-invert max-w-none">
<p>
Bauhaus Echo is now available on Google Play and the App Store. It is a visual memory game
where you memorize tile arrangements, watch them shuffle, and reconstruct the original pattern.
</p>
<div className="prose dark:prose-invert max-w-none">
<p>
Bauhaus Echo is now available on Google Play and the App Store. It is a visual memory game
where you memorize tile arrangements, watch them shuffle, and reconstruct the original pattern.
</p>
<h2>The Concept</h2>
<p>
The game shows you a grid of colorful geometric tiles inspired by Bauhaus design. You get a
few seconds to memorize their positions. Then the tiles spin, shrink, and scatter to the
bottom of the screen. Your job is to drag them back to where they belong.
</p>
<h2>The Concept</h2>
<p>
The game shows you a grid of colorful geometric tiles inspired by Bauhaus design. You get a
few seconds to memorize their positions. Then the tiles spin, shrink, and scatter to the
bottom of the screen. Your job is to drag them back to where they belong.
</p>
<h2>Four Game Modes</h2>
<ul>
<li><strong>Classic</strong> - The core experience. Memorize and reconstruct.</li>
<li><strong>Speed</strong> - Tiles appear one at a time. Place each before the next drops.</li>
<li><strong>Endless</strong> - Speed mode that loops forever. See how long you last.</li>
<li><strong>Memory</strong> - Traditional card-matching pairs.</li>
</ul>
<h2>Four Game Modes</h2>
<ul>
<li><strong>Classic</strong> — The core experience. Memorize and reconstruct.</li>
<li><strong>Speed</strong> — Tiles appear one at a time. Place each before the next drops.</li>
<li><strong>Endless</strong> — Speed mode that loops forever. See how long you last.</li>
<li><strong>Memory</strong> — Traditional card-matching pairs.</li>
</ul>
<h2>Tech Stack</h2>
<p>
Built with libGDX, a cross-platform Java game framework. The same codebase runs on Android,
iOS (via RoboVM), desktop, and web (via GWT). The tile assets are packed into a TextureAtlas
for efficient rendering.
</p>
<h2>Tech Stack</h2>
<p>
Built with libGDX, a cross-platform Java game framework. The same codebase runs on Android,
iOS (via RoboVM), desktop, and web (via GWT). The tile assets are packed into a TextureAtlas
for efficient rendering.
</p>
<h2>Download</h2>
<p>
Get it on{" "}
<a href="https://play.google.com/store/apps/details?id=com.suchsoftware.bauhausecho" target="_blank" rel="noopener noreferrer">
Google Play
</a>{" "}
or the{" "}
<a href="https://apps.apple.com/app/bauhaus-echo" target="_blank" rel="noopener noreferrer">
App Store
</a>
. Free with ads, or pay once to remove them.
</p>
<h2>Download</h2>
<p>
Get it on{" "}
<a href="https://play.google.com/store/apps/details?id=com.suchsoftware.bauhausecho" target="_blank" rel="noopener noreferrer">
Google Play
</a>{" "}
or the{" "}
<a href="https://apps.apple.com/app/bauhaus-echo" target="_blank" rel="noopener noreferrer">
App Store
</a>
. Free with ads, or pay once to remove them.
</p>
</div>
</div>
</article>
<MobileNav />
@@ -13,17 +13,19 @@ export default function SmirkWalletReleasePost() {
return (
<main className="relative min-h-screen flex flex-col items-center bg-background text-foreground">
<Header />
<article id="main-content" className="z-10 w-full max-w-3xl mx-auto py-20 px-4 pb-24 md:pb-20">
<Link href="/blog" className="text-sm text-muted-foreground hover:text-foreground mb-8 inline-block">
<article id="main-content" className="z-10 w-full max-w-4xl mx-auto py-20 px-4 pb-24 md:pb-20">
<Link href="/blog" className="text-sm text-muted-foreground hover:text-emerald-600 dark:hover:text-emerald-400 mb-8 inline-flex items-center gap-2 transition-colors">
← Back to Blog
</Link>
<header className="mb-12">
<time className="text-sm text-muted-foreground">February 6, 2026</time>
<h1 className="text-3xl md:text-4xl font-bold mt-2">Smirk Wallet v0.1.6</h1>
</header>
<div className="glass-card mt-6">
<header className="mb-8 pb-6 border-b border-border">
<time className="text-sm text-muted-foreground">February 6, 2026</time>
<h1 className="text-3xl md:text-4xl font-bold mt-2">Smirk Wallet v0.1.6</h1>
<p className="text-muted-foreground mt-3">Non-custodial social tipping for Telegram and Discord</p>
</header>
<div className="prose dark:prose-invert max-w-none">
<div className="prose dark:prose-invert max-w-none">
<p>
Smirk Wallet is a non-custodial browser extension that lets you tip people cryptocurrency
by their Telegram or Discord username. We have shipped six releases and the extension is
@@ -107,6 +109,7 @@ export default function SmirkWalletReleasePost() {
.
</p>
</div>
</div>
</article>
<MobileNav />
</main>
@@ -13,17 +13,19 @@ export default function WebsiteRelaunchPost() {
return (
<main className="relative min-h-screen flex flex-col items-center bg-background text-foreground">
<Header />
<article id="main-content" className="z-10 w-full max-w-3xl mx-auto py-20 px-4 pb-24 md:pb-20">
<Link href="/blog" className="text-sm text-muted-foreground hover:text-foreground mb-8 inline-block">
<article id="main-content" className="z-10 w-full max-w-4xl mx-auto py-20 px-4 pb-24 md:pb-20">
<Link href="/blog" className="text-sm text-muted-foreground hover:text-emerald-600 dark:hover:text-emerald-400 mb-8 inline-flex items-center gap-2 transition-colors">
← Back to Blog
</Link>
<header className="mb-12">
<time className="text-sm text-muted-foreground">February 6, 2026</time>
<h1 className="text-3xl md:text-4xl font-bold mt-2">Website Relaunch</h1>
</header>
<div className="glass-card mt-6">
<header className="mb-8 pb-6 border-b border-border">
<time className="text-sm text-muted-foreground">February 6, 2026</time>
<h1 className="text-3xl md:text-4xl font-bold mt-2">Website Relaunch</h1>
<p className="text-muted-foreground mt-3">New design, new infrastructure, same focus on quality</p>
</header>
<div className="prose dark:prose-invert max-w-none">
<div className="prose dark:prose-invert max-w-none">
<p>
We rebuilt such.software. New design, new infrastructure, same focus on performance and accessibility.
</p>
@@ -42,10 +44,10 @@ export default function WebsiteRelaunchPost() {
<h2>Procedural Graphics</h2>
<p>
The homepage features two custom procedural animations: NebulaField and DataGrid. Both are
The site features two custom procedural animations: NebulaField and DataGrid. Both are
SVG-based, theme-aware, and respect prefers-reduced-motion. NebulaField renders animated
data streams flowing toward a central icon using quadratic Bezier curves. DataGrid draws
a pulsing grid with traveling data packets.
data streams flowing toward a central icon using quadratic Bezier curves on the homepage.
DataGrid draws a pulsing grid with traveling data packets on the Services page.
</p>
<h2>Accessibility</h2>
@@ -69,6 +71,7 @@ export default function WebsiteRelaunchPost() {
covers our partnership model and consulting work. Mobile users get a bottom navigation bar.
</p>
</div>
</div>
</article>
<MobileNav />
</main>
+68
View File
@@ -99,6 +99,74 @@
.glass-card:hover {
border-color: hsl(var(--primary) / 0.3);
}
/* Typography customization for blog posts */
.prose {
--tw-prose-body: hsl(var(--foreground));
--tw-prose-headings: hsl(var(--foreground));
--tw-prose-lead: hsl(var(--muted-foreground));
--tw-prose-links: hsl(var(--primary));
--tw-prose-bold: hsl(var(--foreground));
--tw-prose-counters: hsl(var(--muted-foreground));
--tw-prose-bullets: hsl(var(--muted-foreground));
--tw-prose-hr: hsl(var(--border));
--tw-prose-quotes: hsl(var(--foreground));
--tw-prose-quote-borders: hsl(var(--border));
--tw-prose-captions: hsl(var(--muted-foreground));
--tw-prose-code: hsl(var(--foreground));
--tw-prose-pre-code: hsl(var(--foreground));
--tw-prose-pre-bg: hsl(var(--muted));
--tw-prose-th-borders: hsl(var(--border));
--tw-prose-td-borders: hsl(var(--border));
}
.prose h2 {
@apply text-xl font-semibold mt-10 mb-4 pb-2 border-b border-border;
}
.prose h3 {
@apply text-lg font-medium mt-6 mb-3;
}
.prose p {
@apply leading-relaxed mb-4;
}
.prose ul {
@apply my-4 ml-4 space-y-2;
}
.prose li {
@apply leading-relaxed;
}
.prose a {
@apply text-emerald-600 dark:text-emerald-400 underline underline-offset-2 hover:text-emerald-700 dark:hover:text-emerald-300 transition-colors;
}
.prose strong {
@apply font-semibold;
}
.prose hr {
@apply my-8 border-border;
}
.prose table {
@apply w-full my-6 text-sm;
}
.prose thead th {
@apply text-left font-semibold p-3 bg-muted/50 border-b border-border;
}
.prose tbody td {
@apply p-3 border-b border-border;
}
.prose tbody tr:hover {
@apply bg-muted/30;
}
}
/* Respect users who prefer reduced motion */
@@ -5,7 +5,7 @@ import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Privacy Policy | Bauhaus Echo | Such Software",
description: "Privacy policy for Bauhaus Echo mobile game.",
description: "Privacy policy for Bauhaus Echo mobile game. GDPR and CPRA compliant.",
alternates: { canonical: "/products/bauhaus-echo/privacy" },
};
@@ -13,20 +13,46 @@ export default function BauhausEchoPrivacyPage() {
return (
<main className="relative min-h-screen flex flex-col items-center bg-background text-foreground">
<Header />
<div id="main-content" className="z-10 w-full max-w-3xl mx-auto py-20 px-4 pb-24 md:pb-20">
<Link href="/products/bauhaus-echo" className="text-sm text-muted-foreground hover:text-foreground mb-8 inline-block">
<div id="main-content" className="z-10 w-full max-w-4xl mx-auto py-20 px-4 pb-24 md:pb-20">
<Link href="/products/bauhaus-echo" className="text-sm text-muted-foreground hover:text-emerald-600 dark:hover:text-emerald-400 mb-8 inline-flex items-center gap-2 transition-colors">
← Back to Bauhaus Echo
</Link>
<h1 className="text-3xl md:text-4xl font-bold mb-4">Privacy Policy for Bauhaus Echo</h1>
<p className="text-muted-foreground mb-8">Last Updated: January 31, 2026</p>
<div className="glass-card mt-6">
<header className="mb-8 pb-6 border-b border-border">
<h1 className="text-3xl md:text-4xl font-bold">Privacy Policy for Bauhaus Echo</h1>
<p className="text-muted-foreground mt-2">Last Updated: February 6, 2026</p>
</header>
<div className="prose dark:prose-invert max-w-none">
<p>
<strong>Such Software LLC</strong> (&quot;we,&quot; &quot;us,&quot; or &quot;our&quot;) operates the Bauhaus Echo mobile
application (the &quot;App&quot;). This page informs you of our policies regarding the collection,
use, and disclosure of personal data when you use our App.
<div className="prose dark:prose-invert max-w-none">
<p>
<strong>Such Software LLC</strong> (&quot;we,&quot; &quot;us,&quot; or &quot;our&quot;) operates the Bauhaus Echo mobile
application (the &quot;App&quot;). This page informs you of our policies regarding the collection,
use, and disclosure of personal data when you use our App.
</p>
<hr />
<h2>Your Privacy Choices (GDPR/CPRA)</h2>
<p>
<strong>We respect your privacy.</strong> When you first open the App, you may see a consent
dialog depending on your location:
</p>
<ul>
<li><strong>EU/UK Users (GDPR):</strong> You will be asked to consent before we show personalized ads. You can accept, decline, or manage your preferences.</li>
<li><strong>California/US Users (CPRA):</strong> You will have the option to opt out of the sale or sharing of your personal information.</li>
</ul>
<p><strong>Your choices:</strong></p>
<ul>
<li>If you <strong>decline</strong> consent, we will show non-personalized ads instead</li>
<li>If you <strong>accept</strong>, ads may be personalized based on your interests</li>
<li>You can <strong>change your choice</strong> at any time in the App settings</li>
</ul>
<p>
<strong>Premium Users:</strong> If you purchase &quot;Remove Ads,&quot; no advertising data is collected and no consent is required.
</p>
<hr />
<h2>Information We Collect</h2>
@@ -54,22 +80,13 @@ export default function BauhausEchoPrivacyPage() {
</p>
<h3>In-App Purchases</h3>
<p>
If you purchase the &quot;Remove Ads&quot; upgrade, your transaction is processed by Google Play (Android)
or the Apple App Store (iOS). We do not have access to your payment information. We only receive
confirmation of your purchase status.
</p>
<h3>High Scores &amp; Leaderboards</h3>
<p>If you submit scores to our online leaderboards, we collect:</p>
<p>If you purchase the &quot;Remove Ads&quot; upgrade, your transaction is processed by:</p>
<ul>
<li>Your chosen display name (anonymous by default)</li>
<li>Your game scores and statistics</li>
<li>A randomly generated anonymous player ID</li>
<li><strong>Google Play</strong> (Android) — <a href="https://policies.google.com/privacy" target="_blank" rel="noopener noreferrer">Google Play Privacy Policy</a></li>
<li><strong>Apple App Store</strong> (iOS) — <a href="https://www.apple.com/legal/privacy/" target="_blank" rel="noopener noreferrer">Apple Privacy Policy</a></li>
</ul>
<p>
We do <strong>not</strong> require or collect your real name, email, or any other personal
information to use leaderboards.
We do not have access to your payment information. We only receive confirmation of your purchase status.
</p>
<h3>Locally Stored Data</h3>
@@ -81,6 +98,8 @@ export default function BauhausEchoPrivacyPage() {
</ul>
<p>This data is not transmitted to our servers unless you use the online leaderboard feature.</p>
<hr />
<h2>How We Use Your Information</h2>
<p>We use collected data to:</p>
<ul>
@@ -90,13 +109,64 @@ export default function BauhausEchoPrivacyPage() {
<li>Improve the App experience</li>
</ul>
<hr />
<h2>Third-Party Services</h2>
<p>The App uses the following third-party services that may collect information:</p>
<div className="overflow-x-auto">
<table>
<thead>
<tr>
<th>Service</th>
<th>Purpose</th>
<th>Privacy Policy</th>
</tr>
</thead>
<tbody>
<tr>
<td>Google AdMob</td>
<td>Advertising</td>
<td><a href="https://policies.google.com/privacy" target="_blank" rel="noopener noreferrer">Link</a></td>
</tr>
<tr>
<td>Google UMP SDK</td>
<td>Consent management</td>
<td><a href="https://policies.google.com/privacy" target="_blank" rel="noopener noreferrer">Link</a></td>
</tr>
<tr>
<td>Google Play Services</td>
<td>Android platform, billing</td>
<td><a href="https://policies.google.com/privacy" target="_blank" rel="noopener noreferrer">Link</a></td>
</tr>
<tr>
<td>Apple StoreKit</td>
<td>iOS platform, billing</td>
<td><a href="https://www.apple.com/legal/privacy/" target="_blank" rel="noopener noreferrer">Link</a></td>
</tr>
</tbody>
</table>
</div>
<h3>Google AdMob Data Collection</h3>
<p>When ads are shown, Google AdMob may collect:</p>
<ul>
<li><strong>Google AdMob</strong> — Advertising</li>
<li><strong>Google Play Services</strong> — Android platform and billing</li>
<li><strong>Apple StoreKit</strong> — iOS platform and billing</li>
<li>Device advertising identifier</li>
<li>IP address (for approximate location)</li>
<li>Device information (model, OS version)</li>
<li>App usage information</li>
</ul>
<p>This data is used to:</p>
<ul>
<li>Show relevant advertisements</li>
<li>Measure ad performance</li>
<li>Prevent fraud</li>
</ul>
<p>
If you decline consent (EU/UK) or opt out (US), AdMob will show non-personalized ads and limit data collection.
</p>
<hr />
<h2>Children&apos;s Privacy</h2>
<p>
@@ -105,6 +175,8 @@ export default function BauhausEchoPrivacyPage() {
contact us immediately.
</p>
<hr />
<h2>Data Retention</h2>
<ul>
<li><strong>Advertising data</strong> is managed by Google per their retention policies</li>
@@ -112,33 +184,71 @@ export default function BauhausEchoPrivacyPage() {
<li><strong>Local data</strong> is stored on your device until you uninstall the App</li>
</ul>
<hr />
<h2>Your Rights</h2>
<p>You may:</p>
<ul>
<li><strong>Control your consent</strong> via the in-app consent dialog (shown on first launch)</li>
<li><strong>Change your privacy choices</strong> at any time via App settings (if available in your region)</li>
<li>
<strong>Opt out of personalized ads</strong> via your device settings (Android: Settings → Google → Ads;
iOS: Settings → Privacy → Tracking)
<strong>Opt out of personalized ads</strong> via your device settings:
<ul>
<li>Android: Settings → Google → Ads → Opt out of Ads Personalization</li>
<li>iOS: Settings → Privacy → Tracking → Disable tracking for Bauhaus Echo</li>
</ul>
</li>
<li><strong>Request deletion</strong> of your leaderboard data by contacting us</li>
<li><strong>Remove local data</strong> by uninstalling the App</li>
</ul>
<h3>For EU/UK Residents (GDPR)</h3>
<p>You have the right to:</p>
<ul>
<li>Access your personal data</li>
<li>Rectify inaccurate data</li>
<li>Request deletion of your data</li>
<li>Object to processing</li>
<li>Data portability</li>
</ul>
<p>To exercise these rights, contact us at the email below.</p>
<h3>For California Residents (CPRA)</h3>
<p>You have the right to:</p>
<ul>
<li>Know what personal information is collected</li>
<li>Delete your personal information</li>
<li>Opt out of the sale or sharing of personal information</li>
<li>Non-discrimination for exercising your rights</li>
</ul>
<p>To opt out, use the consent dialog shown in the App or contact us.</p>
<hr />
<h2>Changes to This Policy</h2>
<p>
We may update this Privacy Policy from time to time. We will notify you of any changes by
posting the new Privacy Policy on this page and updating the &quot;Last Updated&quot; date.
</p>
<hr />
<h2>Contact Us</h2>
<p>If you have any questions about this Privacy Policy, please contact us:</p>
<p>
<strong>Such Software LLC</strong><br />
Email: apps@such.software<br />
Website: https://such.software
Website:{" "}
<a href="https://bauhaus.such.software" target="_blank" rel="noopener noreferrer">
https://bauhaus.such.software
</a>
</p>
<h2>Consent</h2>
<p>By using Bauhaus Echo, you consent to this Privacy Policy.</p>
<hr />
<h2>Consent</h2>
<p>By using Bauhaus Echo, you consent to this Privacy Policy.</p>
</div>
</div>
</div>
<MobileNav />
+1 -1
View File
@@ -78,6 +78,6 @@ const config: Config = {
},
},
},
plugins: [require("tailwindcss-animate")],
plugins: [require("tailwindcss-animate"), require("@tailwindcss/typography")],
};
export default config;