mirror of
https://github.com/Such-Software/such.software.git
synced 2026-10-17 05:32:05 +02:00
add play and app store buttons and review vegan blog
This commit is contained in:
@@ -4,11 +4,9 @@ date: "2026-03-04"
|
||||
excerpt: "How we built a Bauhaus-inspired memory puzzle with libGDX, shipped it to five platforms, and added global leaderboards with HMAC-signed score submissions"
|
||||
---
|
||||
|
||||
Bauhaus Echo is now available on the [App Store](https://apps.apple.com/us/app/bauhaus-echo/id6759010657), [Google Play](https://play.google.com/store/apps/details?id=com.suchsoftware.bauhausecho), [itch.io](https://suchsoftware.itch.io/bauhaus-echo), and [the web](https://bauhaus.such.software). It is a visual memory game where you memorize tile arrangements, watch them shuffle, and reconstruct the original pattern.
|
||||
<BauhausEchoStoreButtons />
|
||||
|
||||
- **Mobile (free, ads removable via IAP)**: [App Store](https://apps.apple.com/us/app/bauhaus-echo/id6759010657) | [Google Play](https://play.google.com/store/apps/details?id=com.suchsoftware.bauhausecho)
|
||||
- **Desktop ($2, no ads)**: [itch.io](https://suchsoftware.itch.io/bauhaus-echo)
|
||||
- **Web (free)**: [bauhaus.such.software](https://bauhaus.such.software)
|
||||
Bauhaus Echo is now available on the [App Store](https://apps.apple.com/us/app/bauhaus-echo/id6759010657), [Google Play](https://play.google.com/store/apps/details?id=com.suchsoftware.bauhausecho), [itch.io](https://suchsoftware.itch.io/bauhaus-echo), and [the web](https://bauhaus.such.software). It is a visual memory game where you memorize tile arrangements, watch them shuffle, and reconstruct the original pattern.
|
||||
|
||||
## The Concept
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ date: "2026-03-26"
|
||||
excerpt: "AI-powered decision making app with subscriptions and ad monetization: now on Android and iOS"
|
||||
---
|
||||
|
||||
<SuchoiceStoreButtons />
|
||||
|
||||
Suchoice is now available on [Google Play](https://play.google.com/store/apps/details?id=com.suchsoftware.suchoice) and the [App Store](https://apps.apple.com/us/app/suchoice/id6759626658). Point your camera at a menu, list, or anything with options. AI reads them, loads them into a wheel, and you spin.
|
||||
|
||||
## Four Ways to Decide
|
||||
@@ -36,7 +38,6 @@ Subscription state is managed through RevenueCat with a single "premium" entitle
|
||||
|
||||
## Get It
|
||||
|
||||
- [Google Play](https://play.google.com/store/apps/details?id=com.suchsoftware.suchoice)
|
||||
- [App Store](https://apps.apple.com/us/app/suchoice/id6759626658)
|
||||
<SuchoiceStoreButtons />
|
||||
|
||||
See the [Suchoice product page](/products/suchoice) for more.
|
||||
|
||||
@@ -1,73 +1,52 @@
|
||||
---
|
||||
title: "Vegan IQ: Test Your Plant-Based Knowledge"
|
||||
title: "Vegan IQ: 1,066 Data-Backed Trivia Questions"
|
||||
date: "2026-04-08"
|
||||
excerpt: "1000+ trivia questions across 8 categories, all backed by verified data. Now on Android and iOS."
|
||||
excerpt: "A plant-based trivia game built on USDA, Oxford, NIH, and FAOSTAT data. Flutter, Python data pipeline, deterministic question generation. Android and iOS."
|
||||
---
|
||||
|
||||
Vegan IQ is a trivia game that tests what you know about plant-based food, nutrition, and sustainability. Over 1,000 questions across 8 categories, all grounded in real data from the USDA, Poore & Nemecek (2018), NIH, and FAOSTAT.
|
||||
<VeganIqStoreButtons />
|
||||
|
||||
## Why We Built It
|
||||
Vegan IQ is a trivia game about plant-based food, nutrition, and sustainability. 1,066 questions across 8 categories. Every answer traces back to a specific data source -- USDA FoodData Central, Poore & Nemecek (Science, 2018), NIH, or FAOSTAT. No LLM-generated content.
|
||||
|
||||
There is a lot of information out there about veganism, plant-based nutrition, and the environmental impact of food. Some of it is accurate, some of it is not. We wanted to make a game where every question is backed by verified data -- a fun way to learn real facts about what you eat and how it affects the planet.
|
||||
## Data Pipeline
|
||||
|
||||
No LLM-generated content. Every question traces back to a specific data source.
|
||||
Questions are generated deterministically from structured JSON data files by a Python pipeline. The pipeline pulls nutritional composition from USDA, environmental impact metrics (water, land, GHG per kg) from Poore & Nemecek, health data from NIH, and agricultural production stats from FAOSTAT.
|
||||
|
||||
Raw generation produces ~2,461 candidates. Subcategory caps, `MINIMUM_MEANINGFUL` thresholds (protein >= 5g, fiber >= 1g, iron >= 1.5mg, calcium >= 30mg, vitamin C >= 5mg), and deduplication reduce this to 1,066 curated questions. A `primary_food` field on 426 questions lets the selection engine penalize same-food repetition within a single quiz (-100 weight).
|
||||
|
||||
Template-generated questions account for 43% of the pool; the remaining 57% are hand-curated.
|
||||
|
||||
## Question Selection
|
||||
|
||||
An anti-repetition pacing engine selects questions at runtime. The algorithm tracks recently-seen questions and applies decay weights so quizzes feel fresh even across multiple sessions. A spaced repetition layer re-surfaces questions the player got wrong more frequently.
|
||||
|
||||
Category selection uses dynamic counts with a 2-column grid UI. Plant milk questions are excluded from environmental per-kg generators via `_ENV_PER_KG_EXCLUDE` to avoid misleading comparisons.
|
||||
|
||||
## v1.1.0
|
||||
|
||||
This release adds:
|
||||
|
||||
- **Streaks and stats** -- daily streaks, lifetime stats, per-category performance tracking
|
||||
- **Titles and badges** -- progression from "Sprout" to "Sage", plus category-specific badges with artist-drawn assets
|
||||
- **Share cards** -- off-screen `RepaintBoundary` renders branded PNG at 2x resolution, shared via `share_plus` with 5-minute delayed cleanup. Fallback to plain text if image generation fails.
|
||||
- **Onboarding flow** -- swipe/tap tutorial for new players
|
||||
- **Quiz length picker** -- 10, 15, or 20 questions per session
|
||||
|
||||
## 8 Categories
|
||||
|
||||
- **Nutrition**: macronutrients, vitamins, minerals, and dietary facts about plant-based foods
|
||||
- **Environment**: water use, land use, greenhouse gas emissions, and ecological impact of food production
|
||||
- **Ingredients**: what is and is not vegan, hidden animal products, and food labeling
|
||||
- **Food History**: origins and cultural history of plant-based foods
|
||||
- **Animal Welfare**: facts about farming practices and animal agriculture
|
||||
- **Health**: plant-based diets and health outcomes from peer-reviewed research
|
||||
- **Cooking**: techniques, substitutions, and preparation of plant-based foods
|
||||
- **Culture**: veganism around the world, traditions, and cultural practices
|
||||
Nutrition, Environment, Ingredients, Food History, Animal Welfare, Health, Cooking, Culture.
|
||||
|
||||
## How It Works
|
||||
## Stack
|
||||
|
||||
Swipe right for true, left for false. Tap your answer for multiple choice questions. Sound effects and haptic feedback make every answer feel satisfying. Choose your quiz length -- 10, 15, or 20 questions -- and pick any category or mix them all.
|
||||
|
||||
## What's in v1.1.0
|
||||
|
||||
- **Streaks and stats** -- daily streaks, lifetime stats, and category-level performance tracking
|
||||
- **Titles and badges** -- earn titles like "Sprout" through "Sage" as you level up, plus category-specific badges
|
||||
- **Share cards** -- share interesting facts or your score as branded images directly from the app
|
||||
- **Onboarding flow** -- new players get a quick walkthrough of how the game works
|
||||
- **Anti-repetition engine** -- smarter question selection so quizzes feel fresh every time
|
||||
- **Spaced repetition** -- questions you get wrong come back more often until you learn them
|
||||
|
||||
## Key Features
|
||||
|
||||
- **1,000+ curated questions** across 8 categories
|
||||
- **Swipe & tap gameplay** -- intuitive and fast
|
||||
- **Dark and light mode** -- play however you prefer
|
||||
- **SFX & haptics** -- satisfying audio and tactile feedback
|
||||
- **Share facts** -- send interesting questions to friends as images or text
|
||||
- **Fully offline** -- all questions bundled in the app
|
||||
- **No account required** -- open and play
|
||||
|
||||
## Data Integrity
|
||||
|
||||
All questions are generated deterministically from structured data files. The data pipeline is written in Python and pulls from:
|
||||
|
||||
- **USDA FoodData Central** for nutritional composition
|
||||
- **Poore & Nemecek, Science (2018)** for environmental impact metrics
|
||||
- **NIH** for health and dietary reference data
|
||||
- **FAOSTAT** for global agricultural statistics
|
||||
|
||||
Questions are not written by an LLM. The pipeline generates them from verified numbers and facts, ensuring accuracy.
|
||||
|
||||
## Tech
|
||||
|
||||
- **Client**: Flutter (Dart), single codebase for Android and iOS
|
||||
- **Client**: Flutter/Dart, single codebase for Android and iOS
|
||||
- **Data**: Python pipeline generating JSON question assets
|
||||
- **Ads**: Google AdMob (banner, interstitial)
|
||||
- **IAP**: Apple StoreKit and Google Play Billing via in_app_purchase
|
||||
- **Storage**: shared_preferences for local score and preference data
|
||||
- **IAP**: StoreKit + Google Play Billing via `in_app_purchase`
|
||||
- **Storage**: `shared_preferences` for local scores and preferences
|
||||
- **Share**: `share_plus` + off-screen `RepaintBoundary` for image generation
|
||||
|
||||
## Get It
|
||||
|
||||
- [Google Play](https://play.google.com/store/apps/details?id=com.veganiq.vegan_iq)
|
||||
- [App Store](https://apps.apple.com/us/app/vegan-iq-plant-based-trivia/id6761139580)
|
||||
<VeganIqStoreButtons />
|
||||
|
||||
See the [Vegan IQ product page](/products/vegan-iq) for more.
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import { Header } from "@/components/layout/header";
|
||||
import { MobileNav } from "@/components/layout/mobile-nav";
|
||||
import {
|
||||
StoreButtons,
|
||||
VeganIqStoreButtons,
|
||||
SuchoiceStoreButtons,
|
||||
BauhausEchoStoreButtons,
|
||||
} from "@/components/store-buttons";
|
||||
import Link from "next/link";
|
||||
import type { Metadata } from "next";
|
||||
import { notFound } from "next/navigation";
|
||||
@@ -58,7 +64,12 @@ export default async function BlogPost({ params }: Props) {
|
||||
</header>
|
||||
|
||||
<div className="prose dark:prose-invert max-w-none">
|
||||
<MDXRemote source={post.content} />
|
||||
<MDXRemote source={post.content} components={{
|
||||
StoreButtons,
|
||||
VeganIqStoreButtons,
|
||||
SuchoiceStoreButtons,
|
||||
BauhausEchoStoreButtons,
|
||||
}} />
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Header } from "@/components/layout/header";
|
||||
import { MobileNav } from "@/components/layout/mobile-nav";
|
||||
import { Card } from "@repo/ui/components/card";
|
||||
import { Button } from "@repo/ui/components/button";
|
||||
import { StoreButtons } from "@/components/store-buttons";
|
||||
import Link from "next/link";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
@@ -43,25 +43,17 @@ export default function BauhausEchoPage() {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap gap-4 mb-12">
|
||||
<a href="https://bauhaus.such.software" target="_blank" rel="noopener noreferrer">
|
||||
<Button size="lg">Play on Web</Button>
|
||||
</a>
|
||||
<a href="https://apps.apple.com/us/app/bauhaus-echo/id6759010657" target="_blank" rel="noopener noreferrer">
|
||||
<Button variant="outline" size="lg">
|
||||
Download on App Store
|
||||
</Button>
|
||||
</a>
|
||||
<a href="https://play.google.com/store/apps/details?id=com.suchsoftware.bauhausecho" target="_blank" rel="noopener noreferrer">
|
||||
<Button variant="outline" size="lg">
|
||||
Get it on Google Play
|
||||
</Button>
|
||||
</a>
|
||||
<a href="https://suchsoftware.itch.io/bauhaus-echo" target="_blank" rel="noopener noreferrer">
|
||||
<Button variant="outline" size="lg">
|
||||
Buy on itch.io — $2
|
||||
</Button>
|
||||
</a>
|
||||
<div className="mb-12">
|
||||
<StoreButtons
|
||||
links={[
|
||||
{ platform: "apple", href: "https://apps.apple.com/us/app/bauhaus-echo/id6759010657" },
|
||||
{ platform: "google", href: "https://play.google.com/store/apps/details?id=com.suchsoftware.bauhausecho" },
|
||||
]}
|
||||
extraLinks={[
|
||||
{ href: "https://bauhaus.such.software", label: "Play on Web" },
|
||||
{ href: "https://suchsoftware.itch.io/bauhaus-echo", label: "itch.io — $2" },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<h2 className="text-2xl font-bold mb-6">How It Works</h2>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Header } from "@/components/layout/header";
|
||||
import { MobileNav } from "@/components/layout/mobile-nav";
|
||||
import { Card } from "@repo/ui/components/card";
|
||||
import { Button } from "@repo/ui/components/button";
|
||||
import { StoreButtons } from "@/components/store-buttons";
|
||||
import Link from "next/link";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
@@ -43,17 +43,11 @@ export default function SuchoicePage() {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap gap-4 mb-12">
|
||||
<a href="https://play.google.com/store/apps/details?id=com.suchsoftware.suchoice" target="_blank" rel="noopener noreferrer">
|
||||
<Button variant="outline" size="lg">
|
||||
Google Play
|
||||
</Button>
|
||||
</a>
|
||||
<a href="https://apps.apple.com/us/app/suchoice/id6759626658" target="_blank" rel="noopener noreferrer">
|
||||
<Button variant="outline" size="lg">
|
||||
App Store
|
||||
</Button>
|
||||
</a>
|
||||
<div className="mb-12">
|
||||
<StoreButtons links={[
|
||||
{ platform: "google", href: "https://play.google.com/store/apps/details?id=com.suchsoftware.suchoice" },
|
||||
{ platform: "apple", href: "https://apps.apple.com/us/app/suchoice/id6759626658" },
|
||||
]} />
|
||||
</div>
|
||||
|
||||
<h2 className="text-2xl font-bold mb-6">Features</h2>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Header } from "@/components/layout/header";
|
||||
import { MobileNav } from "@/components/layout/mobile-nav";
|
||||
import { Card } from "@repo/ui/components/card";
|
||||
import { Button } from "@repo/ui/components/button";
|
||||
import { StoreButtons } from "@/components/store-buttons";
|
||||
import Link from "next/link";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
@@ -45,17 +45,11 @@ export default function VeganIqPage() {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap gap-4 mb-12">
|
||||
<a href="https://play.google.com/store/apps/details?id=com.veganiq.vegan_iq" target="_blank" rel="noopener noreferrer">
|
||||
<Button variant="outline" size="lg">
|
||||
Google Play
|
||||
</Button>
|
||||
</a>
|
||||
<a href="https://apps.apple.com/us/app/vegan-iq-plant-based-trivia/id6761139580" target="_blank" rel="noopener noreferrer">
|
||||
<Button variant="outline" size="lg">
|
||||
App Store
|
||||
</Button>
|
||||
</a>
|
||||
<div className="mb-12">
|
||||
<StoreButtons links={[
|
||||
{ platform: "google", href: "https://play.google.com/store/apps/details?id=com.veganiq.vegan_iq" },
|
||||
{ platform: "apple", href: "https://apps.apple.com/us/app/vegan-iq-plant-based-trivia/id6761139580" },
|
||||
]} />
|
||||
</div>
|
||||
|
||||
<h2 className="text-2xl font-bold mb-6">Features</h2>
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
'use client';
|
||||
|
||||
import { FaApple, FaGooglePlay } from "react-icons/fa6";
|
||||
import { Button } from "@repo/ui/components/button";
|
||||
|
||||
type StoreLink = {
|
||||
platform: "apple" | "google";
|
||||
href: string;
|
||||
};
|
||||
|
||||
type StoreButtonsProps = {
|
||||
links: StoreLink[];
|
||||
extraLinks?: { href: string; label: string }[];
|
||||
};
|
||||
|
||||
const platformConfig = {
|
||||
apple: { icon: FaApple, label: "App Store" },
|
||||
google: { icon: FaGooglePlay, label: "Google Play" },
|
||||
} as const;
|
||||
|
||||
export function StoreButtons({ links, extraLinks }: StoreButtonsProps) {
|
||||
return (
|
||||
<div className="flex flex-wrap gap-4 not-prose">
|
||||
{links.map(({ platform, href }) => {
|
||||
const { icon: Icon, label } = platformConfig[platform];
|
||||
return (
|
||||
<a key={platform} href={href} target="_blank" rel="noopener noreferrer">
|
||||
<Button variant="outline" size="lg">
|
||||
<Icon className="h-5 w-5 mr-2" aria-hidden="true" />
|
||||
{label}
|
||||
</Button>
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
{extraLinks?.map(({ href, label }) => (
|
||||
<a key={href} href={href} target="_blank" rel="noopener noreferrer">
|
||||
<Button variant="outline" size="lg">
|
||||
{label}
|
||||
</Button>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Pre-configured components for use in MDX blog posts
|
||||
export function VeganIqStoreButtons() {
|
||||
return (
|
||||
<StoreButtons links={[
|
||||
{ platform: "google", href: "https://play.google.com/store/apps/details?id=com.veganiq.vegan_iq" },
|
||||
{ platform: "apple", href: "https://apps.apple.com/us/app/vegan-iq-plant-based-trivia/id6761139580" },
|
||||
]} />
|
||||
);
|
||||
}
|
||||
|
||||
export function SuchoiceStoreButtons() {
|
||||
return (
|
||||
<StoreButtons links={[
|
||||
{ platform: "google", href: "https://play.google.com/store/apps/details?id=com.suchsoftware.suchoice" },
|
||||
{ platform: "apple", href: "https://apps.apple.com/us/app/suchoice/id6759626658" },
|
||||
]} />
|
||||
);
|
||||
}
|
||||
|
||||
export function BauhausEchoStoreButtons() {
|
||||
return (
|
||||
<StoreButtons
|
||||
links={[
|
||||
{ platform: "apple", href: "https://apps.apple.com/us/app/bauhaus-echo/id6759010657" },
|
||||
{ platform: "google", href: "https://play.google.com/store/apps/details?id=com.suchsoftware.bauhausecho" },
|
||||
]}
|
||||
extraLinks={[
|
||||
{ href: "https://bauhaus.such.software", label: "Play on Web" },
|
||||
{ href: "https://suchsoftware.itch.io/bauhaus-echo", label: "itch.io — $2" },
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user