♪ ♫ ♩ ♬ ♪ ♫

🎺 Spike Studio

0 pending
🎺

Spike's Design Studio

Give Spike a goal — you see the work live in Output (left = source, right = Spike’s draft). Accept only when it matches.

🎯 Design goal (required — “just review” is not enough)

Pick a top prompt or type what success looks like. Spike runs into Spike’s Output (live). When unsure, Spike asks you — no invented results. Design lead, still on the crew.

Binds page context when Studio is opened from a dashboard · drafts never auto-deploy

🎨 Your brand colors

Loading saved palette…

Live
Named colors

Same Brand CRM as Company Details. Demos (A.L. Plumbing, etc.) never overwrite your kit. Save also pushes CSS to your public site when you’re OV / a hosted contractor.

📄 LIVE PREVIEW Select a page to transform
✨ SPIKE'S OUTPUT Transformed Preview
🎺

You see Spike’s work here

Pick a goal above (or a quick action). Live draft appears in this pane — Accept only when you like it.

📁 Revision History (click to load into output)

v2025-12-05-v1

Tabbed categories • Current

v2025-12-04-v3

Hero section update

v2025-12-04-v2

Mobile grid fix

v2025-12-04-v1

Initial 2026 audit

📰 Newsletter Gallery Hawk + Spike Collaboration

🏠 Your website Spike drafts · Hawk checks the form · nothing publishes until you approve

Spike reads Tell Resi and Brand CRM, picks a page architecture, and shows the draft. You talk like a creative director: “keep this”, “less like that”, “more established”, “not like Facebook”, “bigger project photos”. Buttons below are overrides. Nothing publishes until you approve.

Private drafts. JWT required. Load an existing design to modify it — live /sites/ pages are not overwritten until you approve.

Direction A — Modern professional—
Direction B — Editorial portfolio—

    

📄 Client service offers Spike produces · nothing emailed

Choose a service you offer from this account. Spike produces a branded US Letter PDF and an unsent email draft. This does not create an invoice, apply a credit, or send mail.

Loading offers for this contractor…

Recent offer PDFs

📋 Studio Inventory

Platform assets Spike manages — client Brand CRM is the source of truth for public sites and gatekeeper checks.

🏷️ Brand CRM Client palette is king

Contractor logos, colors, contact, and site context. ResiHub branding stays in the footer only.

🏷️

Loading Brand CRM...

🎨 Design Elements

CSS elements Spike can redesign on dashboards and pages.

🌙 Themes & Outputs

Available themes and generated newsletter count.

🦅 Hawk's Marketing Queue Campaigns pending brand review

Review campaigns from Hawk's Marketing Studio before they go live. Ensure brand consistency and quality.

🦅

Loading Hawk's queue...

📦 Completed Deliverables Ready for download

Campaigns, reports, and designs that have been reviewed and are ready for use.

📦

Loading deliverables...

`], { type: 'text/html' }); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = (currentSpikeOutput?.output || 'spike-output') + '.html'; a.click(); showToast('Downloaded Spike output HTML', 'success'); } function requestSpikeRevision() { // Just open Spike phone - user talks to Spike directly openSpikePhone(); // Play trumpet const trumpet = document.getElementById('trumpet'); if (trumpet) { trumpet.volume = 0.25; trumpet.currentTime = 0; trumpet.play().catch(() => {}); } } // ========== INITIALIZE ========== document.addEventListener('click', function(ev) { const btn = ev.target.closest && ev.target.closest('.brand-edit-colors'); if (!btn) return; let palette = {}; try { palette = JSON.parse((btn.getAttribute('data-palette') || '{}').replace(/'/g, "'")); } catch (_) {} openBrandColorEditor({ contractor_id: btn.getAttribute('data-cid'), company_name: btn.getAttribute('data-name'), logo_url: btn.getAttribute('data-logo'), palette: palette }); }); // Live swatch updates while dragging color pickers document.addEventListener('input', function(ev) { if (!ev.target || !ev.target.id) return; if (ev.target.id === 'live-brand-primary' || ev.target.id === 'live-brand-accent' || ev.target.id === 'live-brand-bg' || ev.target.id === 'live-brand-primary-hex' || ev.target.id === 'live-brand-accent-hex' || ev.target.id === 'live-brand-bg-hex') { const pickId = ev.target.id.replace(/-hex$/, ''); const pick = document.getElementById(pickId); const hex = document.getElementById(pickId + '-hex'); if (ev.target.type === 'color' && hex) hex.value = ev.target.value; if (ev.target.type === 'text' && pick) { const n = normalizeHex(ev.target.value); if (n) { pick.value = n; ev.target.value = n; } } refreshSpikeNamedAndSwatches(); } }); /** True when opened inside RHPanelSystem (dashboard parent already has Resi phone). */ function spikeStudioIsEmbedded() { try { return new URLSearchParams(window.location.search).get('embedded') === '1' || window.parent !== window; } catch (_) { return false; } } /** Standalone Spike Studio: Resi hosts, Spike takes the room (same as panel presence). * Embedded in dashboard panel: NEVER spawn a second floating phone inside the iframe. */ function activateSpikeStudioAgentPresence() { try { window.RESIHUB_ACTIVE_MODULE = 'spikestudio'; window.RESIHUB_MODULE_SPECIALIST = 'spike'; window.RESIHUB_MODULE_PAGE_CONTEXT = 'spike_studio'; sessionStorage.setItem('resi_last_page_context', 'spike_studio'); } catch (_) {} // Panel embed: parent dashboard owns the phone — only notify parent, no nested widget if (spikeStudioIsEmbedded()) { try { if (window.parent && window.parent !== window) { window.parent.postMessage({ type: 'resihub_module_presence', module: 'spikestudio', specialist: 'spike', page_context: 'spike_studio', }, '*'); } } catch (_) {} return; } // Standalone page only: open phone stack if (typeof openBigNuclearPhone === 'function') { try { openBigNuclearPhone(true); } catch (_) {} } else if (window.floatingPhone && window.floatingPhone.open) { try { window.floatingPhone.open(); } catch (_) {} } const phone = window.floatingPhone || window.floatingPhoneInstance; if (!phone) { // No phone stack yet — chat fallback still brands as Spike spikeChatFallback('Hey Spike — I just opened Spike Studio. Greet me and help with brand colors.'); return; } try { if (phone.pageContext !== undefined) phone.pageContext = 'spike_studio'; if (typeof phone.switchAgent === 'function') phone.switchAgent('resi', true); if (typeof phone.addMessage === 'function') { phone.addMessage("You're in Spike's Studio — I'll hand you to Spike for design and brand colors.", 'ai'); } setTimeout(() => { try { if (typeof phone.switchAgent === 'function') { phone.switchAgent('spike', true); phone.agentSelectedDirect = true; } const greet = "Spike on the horn. Brand colors, themes, mockups — client palette is king. What are we designing?"; if (typeof phone.addMessage === 'function') phone.addMessage(greet, 'ai'); if (typeof phone.speak === 'function') phone.speak(greet, 'spike'); } catch (e) { console.warn('Spike handoff', e); } }, 900); } catch (e) { console.warn('Spike studio presence', e); } } document.addEventListener('DOMContentLoaded', () => { try { loadSpikeGoalPrompts(); } catch (e) { console.warn('goal prompts', e); } const gin = document.getElementById('spike-goal-input'); if (gin) gin.addEventListener('keydown', function(ev){ if (ev.key === 'Enter') { ev.preventDefault(); runSpikeGoalLive(); } }); loadNewsletterGallery(); loadHawkQueue(); loadDeliverables(); loadStudioInventory(); loadMyBrandIntoConsole(); try { const params = new URLSearchParams(location.search); if (!params.get('offer') && !params.get('artifact')) { const savedTab = localStorage.getItem('spike_studio_tab'); if (savedTab && document.getElementById('tab-' + savedTab)) { showStudioTab(savedTab); } } } catch (e) {} try { if (!applyServiceOfferQuery()) { /* design tab default */ } } catch (e) { console.warn('service offers query', e); } // Default Output = platform template shell (never empty "pending upload" look) try { setTimeout(() => { try { previewSpikeTemplate('tpl_marketplace_hero'); } catch (_) { try { runTransformPreview(); } catch (__) {} } }, 400); } catch (_) {} // Hex ↔ color picker pairs try { syncSpikeHexPair('live-brand-primary', 'live-brand-primary-hex'); syncSpikeHexPair('live-brand-accent', 'live-brand-accent-hex'); syncSpikeHexPair('live-brand-bg', 'live-brand-bg-hex'); } catch (e) { console.warn('brand hex bind', e); } // Agent presence after phone scripts init setTimeout(activateSpikeStudioAgentPresence, 600); // Wire inventory theme/element chips when rendered document.body.addEventListener('click', function(ev) { const chip = ev.target.closest && ev.target.closest('.inventory-chip'); if (!chip) return; const text = (chip.textContent || '').trim().toLowerCase(); if (['bayou', 'minimal', 'dark'].includes(text)) { applyThemePreset(text); showStudioTab('design'); } else if (['header', 'sidebar', 'button', 'buttons', 'card', 'cards'].some(k => text.includes(k))) { showStudioTab('design'); runRedesignPicker(); const kind = text.includes('header') ? 'header' : text.includes('side') ? 'sidebar' : text.includes('button') ? 'button' : 'card'; setTimeout(() => previewElementRedesign(kind), 50); } }); });