chore: baseline of the live help4bis.com docroot as of 2026-10-23 (cockpit #168)
Excludes analytics/data, vendor, support, .env, ACME tokens. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,590 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- Version: 1.3.0 | Created: 2026-05-05 | Updated: 2026-08-16 -->
|
||||
<html lang="en-AU">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Running Duck Studio Case Study | HELP4BIS</title>
|
||||
<meta name="description" content="How I built rds.ink: a WooCommerce art gallery, a Flutter PWA with augmented reality painting previews, and a custom plugin suite for a working artist studio in Queensland.">
|
||||
<meta name="author" content="HELP4BIS">
|
||||
<meta name="publisher" content="Dutch Digital Dynamics Pty Ltd">
|
||||
<meta name="language" content="en-AU">
|
||||
<meta name="geo.region" content="AU-QLD">
|
||||
<link rel="canonical" href="https://help4bis.com/work/rds-ink.html">
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="https://help4bis.com/work/rds-ink.html">
|
||||
<meta property="og:site_name" content="HELP4BIS">
|
||||
<meta property="og:title" content="Running Duck Studio Case Study | HELP4BIS">
|
||||
<meta property="og:description" content="WooCommerce art gallery, augmented reality painting previews via Flutter, and custom plugin development for a working Queensland artist studio.">
|
||||
<meta property="og:image" content="https://help4bis.com/assets/images/rds-managed-wordpress.jpg">
|
||||
<meta property="og:locale" content="en_AU">
|
||||
<link rel="icon" type="image/jpeg" href="../assets/images/logo-favicon.jpg"> <link rel="stylesheet" href="../assets/css/style.css">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"@id": "https://help4bis.com/work/rds-ink.html#webpage",
|
||||
"url": "https://help4bis.com/work/rds-ink.html",
|
||||
"name": "Running Duck Studio Case Study, HELP4BIS",
|
||||
"description": "WooCommerce art gallery with Flutter PWA, AR painting previews, and custom plugin suite for Running Duck Studio.",
|
||||
"isPartOf": {"@id": "https://help4bis.com/#website"},
|
||||
"breadcrumb": {
|
||||
"@type": "BreadcrumbList",
|
||||
"itemListElement": [
|
||||
{"@type": "ListItem", "position": 1, "name": "Home", "item": "https://help4bis.com/"},
|
||||
{"@type": "ListItem", "position": 2, "name": "Our Work", "item": "https://help4bis.com/#portfolio"},
|
||||
{"@type": "ListItem", "position": 3, "name": "Running Duck Studio", "item": "https://help4bis.com/work/rds-ink.html"}
|
||||
]
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.cs-hero {
|
||||
background: linear-gradient(160deg, var(--ink) 0%, var(--ink-mid) 60%, #1a1010 100%);
|
||||
padding: var(--sp-16) 0 var(--sp-12);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.cs-hero::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -30%;
|
||||
right: -15%;
|
||||
width: 60%;
|
||||
height: 200%;
|
||||
background: radial-gradient(circle, rgba(232,53,42,.05) 0%, transparent 65%);
|
||||
pointer-events: none;
|
||||
}
|
||||
.cs-breadcrumb {
|
||||
font-size: 13px;
|
||||
color: rgba(255,255,255,.45);
|
||||
margin-bottom: var(--sp-5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.cs-breadcrumb a { color: rgba(255,255,255,.45); }
|
||||
.cs-breadcrumb a:hover { color: var(--white); }
|
||||
.cs-breadcrumb span { color: rgba(255,255,255,.25); }
|
||||
.cs-hero h1 {
|
||||
color: var(--white);
|
||||
max-width: 820px;
|
||||
margin-bottom: var(--sp-4);
|
||||
}
|
||||
.cs-hero-sub {
|
||||
font-size: clamp(16px, 2vw, 20px);
|
||||
color: rgba(255,255,255,.65);
|
||||
max-width: 680px;
|
||||
line-height: 1.65;
|
||||
margin-bottom: var(--sp-6);
|
||||
}
|
||||
.cs-hero-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.btn-red {
|
||||
background: linear-gradient(135deg, #E8352A, #b91c1c);
|
||||
color: var(--white);
|
||||
border-color: transparent;
|
||||
box-shadow: 0 4px 14px rgba(232,53,42,.30);
|
||||
}
|
||||
.btn-red:hover {
|
||||
background: linear-gradient(135deg, #b91c1c, #991b1b);
|
||||
color: var(--white);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
.cs-kpis {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 16px;
|
||||
margin-top: var(--sp-8);
|
||||
padding-top: var(--sp-8);
|
||||
border-top: 1px solid rgba(255,255,255,.08);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-kpis { grid-template-columns: repeat(4, 1fr); } }
|
||||
.cs-kpi { text-align: center; }
|
||||
.cs-kpi-value {
|
||||
font-family: var(--font-head);
|
||||
font-size: clamp(32px, 4vw, 52px);
|
||||
font-weight: 900;
|
||||
color: #E8352A;
|
||||
line-height: 1;
|
||||
letter-spacing: -0.04em;
|
||||
}
|
||||
.cs-kpi-label {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .12em;
|
||||
color: rgba(255,255,255,.45);
|
||||
margin-top: 6px;
|
||||
}
|
||||
.cs-feature-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 24px;
|
||||
margin-top: var(--sp-6);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-feature-grid { grid-template-columns: repeat(2, 1fr); } }
|
||||
@media (min-width: 900px) { .cs-feature-grid { grid-template-columns: repeat(3, 1fr); } }
|
||||
.cs-feature-card {
|
||||
background: var(--white);
|
||||
border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-lg);
|
||||
padding: 24px;
|
||||
box-shadow: var(--shadow-card);
|
||||
}
|
||||
.cs-feature-card h4 { font-size: 15px; margin-bottom: 8px; color: var(--ink); }
|
||||
.cs-feature-card p { font-size: 14px; color: var(--grey-600); line-height: 1.6; margin: 0; }
|
||||
.cs-feature-icon {
|
||||
width: 36px; height: 36px;
|
||||
background: var(--grey-50);
|
||||
border-radius: var(--r-md);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
margin-bottom: 14px; font-size: 18px;
|
||||
}
|
||||
.cs-plugin-list {
|
||||
margin: 0; padding: 0; list-style: none;
|
||||
display: grid; grid-template-columns: 1fr; gap: 12px;
|
||||
margin-top: var(--sp-5);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-plugin-list { grid-template-columns: repeat(2, 1fr); } }
|
||||
.cs-plugin-item {
|
||||
background: var(--white);
|
||||
border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-md);
|
||||
padding: 16px 18px;
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
.cs-plugin-item strong {
|
||||
display: block; font-family: var(--font-head);
|
||||
font-size: 14px; font-weight: 700; color: var(--ink); margin-bottom: 4px;
|
||||
}
|
||||
.cs-plugin-item span { font-size: 13px; color: var(--grey-600); line-height: 1.5; }
|
||||
.cs-plugin-version {
|
||||
display: inline-block; font-size: 11px; font-weight: 700;
|
||||
text-transform: uppercase; letter-spacing: .08em;
|
||||
padding: 2px 8px; border-radius: var(--r-full); margin-top: 8px;
|
||||
background: rgba(232,53,42,.1); color: #b91c1c;
|
||||
}
|
||||
.cs-stack {
|
||||
display: flex; flex-wrap: wrap; gap: 8px; margin-top: var(--sp-4);
|
||||
}
|
||||
.cs-stack-tag {
|
||||
background: var(--grey-50); border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-full); padding: 6px 14px;
|
||||
font-size: 13px; font-weight: 500; color: var(--grey-600);
|
||||
}
|
||||
.cs-divider { height: 1px; background: var(--grey-100); margin: var(--sp-8) 0; }
|
||||
.cs-two-col {
|
||||
display: grid; grid-template-columns: 1fr; gap: var(--sp-8); align-items: start;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.cs-two-col { grid-template-columns: 1fr 1fr; }
|
||||
.cs-two-col--wide { grid-template-columns: 3fr 2fr; }
|
||||
}
|
||||
.cs-quote {
|
||||
border-left: 3px solid #E8352A;
|
||||
padding: var(--sp-4) var(--sp-5);
|
||||
background: rgba(232,53,42,.04);
|
||||
border-radius: 0 var(--r-md) var(--r-md) 0;
|
||||
margin: var(--sp-5) 0;
|
||||
}
|
||||
.cs-quote p { font-size: 17px; line-height: 1.7; color: var(--grey-800); font-style: italic; margin: 0; }
|
||||
.cs-honest {
|
||||
background: var(--grey-50); border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-lg); padding: var(--sp-4) var(--sp-5); margin: var(--sp-5) 0;
|
||||
}
|
||||
.cs-honest-label {
|
||||
font-size: 11px; font-weight: 700; text-transform: uppercase;
|
||||
letter-spacing: .12em; color: var(--grey-400); margin-bottom: 8px;
|
||||
}
|
||||
.cs-honest p { font-size: 14px; color: var(--grey-600); line-height: 1.65; margin: 0; }
|
||||
.cs-cta {
|
||||
background: linear-gradient(135deg, var(--ink-mid), var(--ink));
|
||||
border-radius: var(--r-2xl); padding: var(--sp-10) var(--sp-8); text-align: center;
|
||||
}
|
||||
.cs-cta h2 { color: var(--white); margin-bottom: var(--sp-4); }
|
||||
.cs-cta p { color: rgba(255,255,255,.65); max-width: 560px; margin: 0 auto var(--sp-6); font-size: 17px; line-height: 1.7; }
|
||||
.cs-ar-flow {
|
||||
display: grid; grid-template-columns: 1fr; gap: 16px; margin-top: var(--sp-5);
|
||||
}
|
||||
@media (min-width: 640px) { .cs-ar-flow { grid-template-columns: repeat(3, 1fr); } }
|
||||
.cs-ar-step {
|
||||
background: var(--white); border: 1px solid var(--grey-100);
|
||||
border-radius: var(--r-lg); padding: 20px; box-shadow: var(--shadow-sm);
|
||||
text-align: center;
|
||||
}
|
||||
.cs-ar-step-num {
|
||||
width: 36px; height: 36px; background: #E8352A; color: var(--white);
|
||||
border-radius: 50%; display: flex; align-items: center; justify-content: center;
|
||||
font-family: var(--font-head); font-weight: 800; font-size: 16px;
|
||||
margin: 0 auto 12px;
|
||||
}
|
||||
.cs-ar-step h5 { font-size: 14px; font-weight: 700; color: var(--ink); margin-bottom: 6px; }
|
||||
.cs-ar-step p { font-size: 13px; color: var(--grey-600); line-height: 1.55; margin: 0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- NAV -->
|
||||
<nav class="nav" role="navigation" aria-label="Main navigation">
|
||||
<div class="nav__inner">
|
||||
<a class="nav__logo" href="../index.html" aria-label="HELP4BIS home">
|
||||
<img src="../assets/images/logo-cropped.jpg" alt="HELP4BIS" width="140" height="38">
|
||||
</a>
|
||||
<ul class="nav__links" id="nav-links" role="list">
|
||||
<li class="nav__dropdown">
|
||||
<button class="nav__trigger" aria-haspopup="true" aria-expanded="false">Services <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></button>
|
||||
<ul class="nav__dropdown-menu" role="menu">
|
||||
<li class="nav__menu-group">WordPress</li>
|
||||
<li><a href="../managed-wordpress.html" role="menuitem">Tailored Website Management</a></li>
|
||||
<li><a href="../care-plans.html" role="menuitem">WP Care Plans <span class="menu-price">from $49/mo</span></a></li>
|
||||
<li><a href="../sos-fix.html" role="menuitem">WP SOS Fix <span class="menu-price">$97 flat</span></a></li>
|
||||
<li><a href="../ai-integration.html" role="menuitem">AI Integration</a></li>
|
||||
<li><a href="../plugin-development.html" role="menuitem">Custom Plugin Development</a></li> </ul>
|
||||
</li>
|
||||
<li><a href="../about.html">About</a></li>
|
||||
<li><a href="../index.html#portfolio">Our Work</a></li>
|
||||
<li><a href="../index.html#pricing">Pricing</a></li>
|
||||
<li><a href="../blog/index.html">Blog</a></li>
|
||||
<li><a href="../your-first-week-with-ai.html">AI Guide</a></li>
|
||||
<li><a href="../contact.html">Contact</a></li>
|
||||
<li class="nav__cta-mobile" aria-hidden="true">
|
||||
<a href="../contact.html" class="btn btn-primary">Get Started</a>
|
||||
<a href="../sos-fix.html" class="btn btn-secondary">SOS Fix, $97</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="nav__cta">
|
||||
<a href="../sos-fix.html" class="btn btn-secondary btn-sm">SOS Fix, $97</a>
|
||||
<a href="../contact.html" class="btn btn-primary btn-sm">Get Started</a>
|
||||
</div>
|
||||
<button class="nav__burger" id="nav-burger" aria-label="Open menu" aria-expanded="false" aria-controls="nav-links">
|
||||
<span></span><span></span><span></span>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- HERO -->
|
||||
<section class="cs-hero" aria-labelledby="cs-heading">
|
||||
<div class="container">
|
||||
<div class="cs-breadcrumb">
|
||||
<a href="../index.html">Home</a>
|
||||
<span>›</span>
|
||||
<a href="../index.html#portfolio">Our Work</a>
|
||||
<span>›</span>
|
||||
<span style="color:rgba(255,255,255,.7);">Running Duck Studio</span>
|
||||
</div>
|
||||
<p class="eyebrow" style="color:rgba(232,53,42,.9);">Case Study: Art Gallery + App</p>
|
||||
<h1 id="cs-heading">Running Duck Studio.<br>Selling art online<br>is harder than it looks.</h1>
|
||||
<p class="cs-hero-sub">A WooCommerce art gallery with augmented reality painting previews, a Flutter app that shows the work in your space before you buy, and a custom plugin suite I built specifically for how a working artist studio actually sells.</p>
|
||||
<div class="cs-hero-actions">
|
||||
<a href="https://rds.ink" target="_blank" rel="noopener" class="btn btn-red">Visit rds.ink →</a>
|
||||
<a href="https://flutter.rds.ink" target="_blank" rel="noopener" class="btn btn-secondary">Open the app</a>
|
||||
</div>
|
||||
<div class="cs-kpis">
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">WC</div>
|
||||
<div class="cs-kpi-label">Sales Platform</div>
|
||||
</div>
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">5</div>
|
||||
<div class="cs-kpi-label">Custom Plugins</div>
|
||||
</div>
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">AR</div>
|
||||
<div class="cs-kpi-label">In Room Previews</div>
|
||||
</div>
|
||||
<div class="cs-kpi">
|
||||
<div class="cs-kpi-value">8.4MB</div>
|
||||
<div class="cs-kpi-label">Flutter PWA</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- OVERVIEW -->
|
||||
<section class="section" aria-labelledby="overview-heading">
|
||||
<div class="container">
|
||||
<div class="cs-two-col cs-two-col--wide">
|
||||
<div>
|
||||
<p class="eyebrow">Overview</p>
|
||||
<h2 id="overview-heading">What it actually is</h2>
|
||||
<p class="large">Danielle runs a working art studio. She paints originals, prints limited editions, and sells through the website. Standard WooCommerce wasn't built for original artwork. There's no concept of a one of a kind piece that's gone when it sells, no way to mark something as SOLD with context rather than just deleting it, and no way to show the buyer what the painting looks like at life size on their wall before they commit.</p>
|
||||
<p>So I built what was missing. A custom plugin suite that handles the art gallery's specific needs: SOLD badge display with history tracking, a commission inquiry form, an artwork dimenions field, category filtering for the gallery view, and a Related Works shortcode. On top of that I built a Flutter progressive web app with augmented reality, where the buyer can point their phone camera at their wall and see the painting at real scale.</p>
|
||||
<p>The AR feature is the part I spend the most time explaining, but it sells the hardest when people actually try it. Danielle uploads a photo of the painting and a short video. The AR target gets compiled in the browser. The Flutter app opens a camera overlay and shows the work in the room.</p>
|
||||
<div class="cs-quote">
|
||||
<p>"Selling original art online has one central problem: people can't tell how big it is or whether it will work on their wall. The AR preview solves that directly."</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<img src="../assets/images/rds-managed-wordpress.jpg" alt="Running Duck Studio website" style="width:100%;border-radius:var(--r-xl);box-shadow:var(--shadow-lg);" loading="lazy">
|
||||
<div class="cs-stack" style="margin-top:20px;">
|
||||
<span class="cs-stack-tag">WordPress</span>
|
||||
<span class="cs-stack-tag">WooCommerce</span>
|
||||
<span class="cs-stack-tag">Flutter Web</span>
|
||||
<span class="cs-stack-tag">Augmented Reality</span>
|
||||
<span class="cs-stack-tag">Gelato Print-on-Demand</span>
|
||||
<span class="cs-stack-tag">Custom Plugins</span>
|
||||
<span class="cs-stack-tag">REST API</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- AR EXPERIENCE -->
|
||||
<section class="section section--alt" aria-labelledby="ar-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Signature Feature</p>
|
||||
<h2 id="ar-heading">How the AR preview works</h2>
|
||||
<p style="max-width:640px;color:var(--grey-600);font-size:17px;line-height:1.7;margin-bottom:0;">Danielle does the entire setup from the WordPress admin. No technical knowledge required after the initial build I did. The whole pipeline runs from her laptop.</p>
|
||||
|
||||
<div class="cs-ar-flow">
|
||||
<div class="cs-ar-step">
|
||||
<div class="cs-ar-step-num">1</div>
|
||||
<h5>Upload painting + video</h5>
|
||||
<p>Danielle uploads a straight photo of the painting and a short video of it hanging in the studio. Both go into the rds-ar-manager plugin.</p>
|
||||
</div>
|
||||
<div class="cs-ar-step">
|
||||
<div class="cs-ar-step-num">2</div>
|
||||
<h5>AR target compiles in the browser</h5>
|
||||
<p>The plugin compiles the AR target in the browser. No processing on my server, no external AR service subscription. The target image descriptor is stored with the product.</p>
|
||||
</div>
|
||||
<div class="cs-ar-step">
|
||||
<div class="cs-ar-step-num">3</div>
|
||||
<h5>Buyer opens Flutter app</h5>
|
||||
<p>The Flutter PWA at flutter.rds.ink reads the product data via REST API. The buyer taps "View in your space" and the app opens a camera overlay showing the painting at real scale on their wall.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cs-honest" style="margin-top:var(--sp-6);">
|
||||
<div class="cs-honest-label">Honest note</div>
|
||||
<p>The AR feature works well on mid range Android and current iOS. Older phones with limited camera APIs see a standard overlay without full spatial tracking. It's a real improvement for most buyers, not a universal replacement for visiting the studio. I document this clearly in the app.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- PLUGIN SUITE -->
|
||||
<section class="section" aria-labelledby="plugins-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Custom Development</p>
|
||||
<h2 id="plugins-heading">Five plugins, one purpose</h2>
|
||||
<p style="max-width:640px;color:var(--grey-600);font-size:17px;line-height:1.7;margin-bottom:0;">Standard WooCommerce treats every product the same. I wrote these plugins because original artwork isn't the same as a T shirt. Each one fills a specific gap in how the gallery actually works.</p>
|
||||
|
||||
<ul class="cs-plugin-list">
|
||||
<li class="cs-plugin-item">
|
||||
<strong>rds-core</strong>
|
||||
<span>Core gallery functionality: product display, pricing, SOLD badge with history, commission inquiry form, Similar Works shortcode, category filter bar, and artwork dimensions. The plugin that makes WooCommerce behave like an art gallery rather than a general shop.</span>
|
||||
</li>
|
||||
<li class="cs-plugin-item">
|
||||
<strong>rds-ar-manager</strong>
|
||||
<span>AR experience management. Danielle uploads painting image and video via a metabox on the product edit screen. The plugin handles AR target compilation and makes it available to the Flutter app.</span>
|
||||
</li>
|
||||
<li class="cs-plugin-item">
|
||||
<strong>rds-flutter-config</strong>
|
||||
<span>Controls the look, feel, and content of the Flutter PWA from WP admin. Theme colours, featured collections, and navigation structure can all be changed without redeploying the app.</span>
|
||||
</li>
|
||||
<li class="cs-plugin-item">
|
||||
<strong>rds-image-guard</strong>
|
||||
<span class="cs-plugin-version">Active</span>
|
||||
<span>Disables right click save and drag based image theft on all gallery pages. Doesn't prevent determined copying but removes casual right click downloads. Standard protection for selling original digital previews of artwork.</span>
|
||||
</li>
|
||||
<li class="cs-plugin-item">
|
||||
<strong>rds-seo-command</strong>
|
||||
<span class="cs-plugin-version">Active</span>
|
||||
<span>SEO tooling for the gallery: auto-generates meta descriptions from product data, builds structured data markup for individual artwork pages, and handles canonical URLs across the category and tag views.</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- PRINT ON DEMAND -->
|
||||
<section class="section section--alt" aria-labelledby="pod-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Commerce Layer</p>
|
||||
<h2 id="pod-heading">Originals plus print on demand</h2>
|
||||
<p style="max-width:640px;color:var(--grey-600);font-size:17px;line-height:1.7;margin-bottom:var(--sp-6);">Running Duck Studio sells two things: original paintings at original prices, and print reproductions via Gelato. Gelato handles fulfilment. They print and ship from the production facility closest to the buyer, and the WooCommerce integration I set up connects the two.</p>
|
||||
|
||||
<div class="cs-feature-grid" style="margin-top:0;">
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🎨</div>
|
||||
<h4>Original paintings</h4>
|
||||
<p>Each original is a single WooCommerce product with a custom SOLD state I built. When it sells, the product switches to SOLD, shows the sold price and date, and remains visible as portfolio history rather than disappearing from the site.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🖨️</div>
|
||||
<h4>Gelato print on demand</h4>
|
||||
<p>Limited edition prints are fulfilled by Gelato. The buyer places a WooCommerce order; Gelato picks it up automatically and handles printing, packaging, and shipping. No inventory, no fulfilment work on Danielle's end, and nothing manual for me either.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">📦</div>
|
||||
<h4>Commission inquiries</h4>
|
||||
<p>The commission form (part of rds-core) captures buyer requirements, preferred size, colour palette, and budget. It feeds into a structured email workflow rather than a generic contact form. Danielle gets everything she needs in one message.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cs-honest" style="margin-top:var(--sp-6);">
|
||||
<div class="cs-honest-label">Honest note: Gelato</div>
|
||||
<p>Gelato's WooCommerce API has specific requirements around product variant mapping that I had to document carefully. When Gelato updates their product catalogue, variant IDs can change and previously mapped products need relinking, so it is important keep the variant mapping current. It's not a set and forget integration. I handle those updates as part of the ongoing management relationship.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FLUTTER APP -->
|
||||
<section class="section" aria-labelledby="app-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Mobile Experience</p>
|
||||
<h2 id="app-heading">The Flutter app</h2>
|
||||
<div class="cs-two-col">
|
||||
<div>
|
||||
<p>The Flutter progressive web app I wrote at <strong>flutter.rds.ink</strong> is an 8.4 MB build that runs in the browser on any device. No app store download required. The buyer opens it from their phone browser or via a QR code on the gallery page.</p>
|
||||
<p>The app reads product data from the WordPress REST API on launch. Featured collections, theme colours, and the gallery structure all come from the rds-flutter-config plugin, so the app stays in sync with the website without being redeployed every time Danielle adds a new collection.</p>
|
||||
<p>Core screens: gallery browse by category, individual artwork detail with AR trigger, Danielle's story, commission inquiry form, and a direct link to the WooCommerce cart. I run the cart in a WebView pointed at the WordPress site so I don't duplicate the payment integration.</p>
|
||||
</div>
|
||||
<div>
|
||||
<div class="cs-feature-card" style="margin-bottom:16px;">
|
||||
<div class="cs-feature-icon">📱</div>
|
||||
<h4>PWA, no app store required</h4>
|
||||
<p>Works on Android and iOS via the browser. Users can add it to their home screen and it behaves like an installed app. The service worker caches the gallery for offline browsing.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card" style="margin-bottom:16px;">
|
||||
<div class="cs-feature-icon">🔗</div>
|
||||
<h4>Live data from WordPress</h4>
|
||||
<p>The app reads the product catalogue via REST API. New artwork appears in the app automatically when published in WordPress. I don't need to redeploy anything for content updates.</p>
|
||||
</div>
|
||||
<div class="cs-feature-card">
|
||||
<div class="cs-feature-icon">🛒</div>
|
||||
<h4>Cart via WebView</h4>
|
||||
<p>Purchases complete through the WooCommerce site inside a WebView. No duplicated payment integration, no Stripe keys managed in two places.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- TECH STACK -->
|
||||
<section class="section section--alt" aria-labelledby="stack-heading">
|
||||
<div class="container">
|
||||
<p class="eyebrow">Technical Details</p>
|
||||
<h2 id="stack-heading">Full stack</h2>
|
||||
<div class="cs-two-col">
|
||||
<div>
|
||||
<h4 style="font-size:15px;margin-bottom:12px;color:var(--ink);">Web platform</h4>
|
||||
<div class="cs-stack" style="margin-top:0;">
|
||||
<span class="cs-stack-tag">WordPress 6.x</span>
|
||||
<span class="cs-stack-tag">WooCommerce</span>
|
||||
<span class="cs-stack-tag">Elementor Pro</span>
|
||||
<span class="cs-stack-tag">rds-core</span>
|
||||
<span class="cs-stack-tag">rds-ar-manager</span>
|
||||
<span class="cs-stack-tag">rds-flutter-config</span>
|
||||
<span class="cs-stack-tag">rds-image-guard</span>
|
||||
<span class="cs-stack-tag">rds-seo-command</span>
|
||||
<span class="cs-stack-tag">Gelato integration</span>
|
||||
</div>
|
||||
<h4 style="font-size:15px;margin-bottom:12px;margin-top:24px;color:var(--ink);">Mobile app</h4>
|
||||
<div class="cs-stack" style="margin-top:0;">
|
||||
<span class="cs-stack-tag">Flutter 3.x</span>
|
||||
<span class="cs-stack-tag">Dart</span>
|
||||
<span class="cs-stack-tag">WebXR AR</span>
|
||||
<span class="cs-stack-tag">Service Worker PWA</span>
|
||||
<span class="cs-stack-tag">REST API consumer</span>
|
||||
<span class="cs-stack-tag">WebView cart</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4 style="font-size:15px;margin-bottom:12px;color:var(--ink);">Infrastructure</h4>
|
||||
<div class="cs-stack" style="margin-top:0;">
|
||||
<span class="cs-stack-tag">DirectAdmin, brisbane01</span>
|
||||
<span class="cs-stack-tag">PHP 8.4</span>
|
||||
<span class="cs-stack-tag">MariaDB</span>
|
||||
<span class="cs-stack-tag">Let's Encrypt SSL</span>
|
||||
<span class="cs-stack-tag">rds.ink (WooCommerce)</span>
|
||||
<span class="cs-stack-tag">flutter.rds.ink (Flutter PWA)</span>
|
||||
</div>
|
||||
<div class="cs-honest" style="margin-top:24px;">
|
||||
<div class="cs-honest-label">What this costs to run</div>
|
||||
<p>The platform runs on shared infrastructure on the same Brisbane server as the rest of my portfolio. Total hosting cost for rds.ink and the Flutter subdomain is included in the Tailored Website Management plan at $200/month. Gelato charges per print fulfilled; there's no monthly fee for their integration.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA -->
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<div class="cs-cta">
|
||||
<h2>Want a WooCommerce store that actually fits your business?</h2>
|
||||
<p>Standard WooCommerce is a solid foundation. The question is whether it fits what you actually sell. If it doesn't, I build the parts that are missing.</p>
|
||||
<div class="cs-hero-actions" style="justify-content:center;">
|
||||
<a href="../contact.html" class="btn btn-primary btn-lg">Talk to us</a>
|
||||
<a href="../plugin-development.html" class="btn btn-secondary btn-lg">Custom plugin development</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top:var(--sp-8);text-align:center;">
|
||||
<a href="../index.html#portfolio" style="font-size:14px;color:var(--grey-400);">← Back to all work</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FOOTER -->
|
||||
<footer class="footer" aria-label="Site footer">
|
||||
<div class="container">
|
||||
<div class="footer__grid">
|
||||
<div class="footer__brand">
|
||||
<img src="../assets/images/logo-cropped.jpg" alt="HELP4BIS" width="140" height="38">
|
||||
<p>Managed WordPress hosting and maintenance for Australian small businesses. Brisbane based, personal service, WordPress specialist.</p>
|
||||
<p style="margin-top:8px; font-size:12px; color:rgba(255,255,255,.25);">Dutch Digital Dynamics Pty Ltd · ABN 86 081 237 087</p>
|
||||
</div>
|
||||
<div class="footer__col">
|
||||
<h4>Services</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="../managed-wordpress.html">Tailored Website Management</a></li>
|
||||
<li><a href="../care-plans.html">WP Care Plans</a></li>
|
||||
<li><a href="../sos-fix.html">WP SOS Fix</a></li>
|
||||
<li><a href="../ai-integration.html">AI Integration</a></li>
|
||||
<li><a href="../plugin-development.html">Plugin Development</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer__col">
|
||||
<h4>Our Work</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="dayboro-au.html">Dayboro.au</a></li>
|
||||
<li><a href="gardenbuddy-au.html">GardenBuddy.au</a></li>
|
||||
<li><a href="tawnytrails.html">Tawny Trails</a></li>
|
||||
<li><a href="rds-ink.html">Running Duck Studio</a></li>
|
||||
<li><a href="localbuddy-au.html">LocalBuddy</a></li>
|
||||
<li><a href="m8chat-au.html">M8Chat</a></li>
|
||||
<li><a href="nightcap-nm.html">Nightcap Natural Medicine</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer__col">
|
||||
<h4>Contact</h4>
|
||||
<ul class="footer__links">
|
||||
<li><a href="mailto:project@help4bis.com">project@help4bis.com</a></li>
|
||||
<li><a href="../contact.html">Submit a Brief</a></li>
|
||||
<li><a href="../sos-fix.html">Emergency Fix</a></li>
|
||||
</ul>
|
||||
<p style="margin-top:16px; font-size:12px; color:rgba(255,255,255,.3);">Brisbane, Queensland<br>Response within 24 business hours</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer__bottom">
|
||||
<span>© 2026 HELP4BIS, a trading name of Dutch Digital Dynamics Pty Ltd · ABN 86 081 237 087</span>
|
||||
<span><a href="../privacy.html">Privacy</a> · <a href="../terms.html">Terms</a></span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<button id="back-to-top" aria-label="Back to top">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"/></svg>
|
||||
</button>
|
||||
|
||||
<script src="../assets/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user