before you build 
answer this:
you feel
before you understand

are you on a tactical "treadmill"?

empty tactics are like empty calories.
quick energy. no substance.
you keep moving.
you keep doing things.
but you’re not getting anywhere.
Doing more isn’t the same as moving forward.And, eventually, that catches up with you.

do you embrace "versus"?

versus isn’t optional.
it’s your spotlight.
pick THE competitor everyone talks about.
stand in contrast.
expose what only you can deliver.
make the choice impossible to ignore.
that’s how you survive stand out.

digital only?

digital won’t win alone.it’s crowded.
it’s noisy.
the streets still matter.
real-world touchpoints build credibility.
diversify. experiment.
reach where algorithms can't.

this isn’t a pitch.

it’s where I think out loud. experiment. iterate.

most musings come
from real work.
some from things that worked.
others from things that…
well, didn’t.

this is where
i try to make sense of it all.

some will hold.
some won’t.

it’s a process.
the point is seeing
what breaks.
and what holds.

enter the insight rabbit hole. document.addEventListener('DOMContentLoaded', () => { const link = document.getElementById('insights-link'); link.addEventListener('click', (e) => { e.preventDefault(); // Toggle arrow state (like posts) link.classList.toggle('active'); // Smooth scroll to section const target = document.querySelector('#insights'); if (target) { const rect = target.getBoundingClientRect(); const scrollTop = window.pageYOffset + rect.top; window.scrollTo({ top: scrollTop, behavior: 'smooth' }); } }); });
what gets your attention?
// Function to wrap words in spans with staggered delays (function() { function wrapWords(sectionId, delayStep = 0.3, randomOffset = 0) { const container = document.getElementById(sectionId); if (!container) return; const words = container.textContent.trim().split(' '); container.textContent = ''; words.forEach((word, i) => { const span = document.createElement('span'); span.textContent = word + ' '; // Add optional random offset for subtle difference per section const offset = randomOffset ? (Math.random() * randomOffset - randomOffset/2) : 0; span.style.animationDelay = `${i * delayStep + offset}s`; container.appendChild(span); }); } function init() { wrapWords('hero-insights', 0.25, 0.1); wrapWords('hero-experiments', 0.28, 0.15); wrapWords('hero-about', 0.32, 0.1); wrapWords('hero-contact', 0.3, 0.2); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();

do you really listen?

tools won’t give you THE answers.
customers will.
talk to them.
watch them.
above all, listen.
learn what they actually value.turn that insight into a simple market model.then act.
test. iterate. repeat.

know the 95-5 rule?

that's great.
ignore it.
if someone is ready to buy, that's great!
SELL. be profitable.
But if you put all of your effort
into the 5%
you're setting yourself up
to
fail.
those other 95% you ignored because performance metrics?they are buying from your competitors.
and they have no idea you even exist.
budget accordingly.

embrace 7-11-4?

i don't know if it's really 7-11-4.
what i can guarantee is that it's not 1.
expecting people to buy
because your stuff looks cool
when they just found out about it
is setting yourself up for losing money.
it takes time.
it takes effort.
it takes more than one try.
that's where a balanced mix
comes in.
if you zero in on performance?
you are toast in the long run.

are you selling yourself short?

big players can’t be beaten on price.
lead with your price. it’s your anchor.
low prices scream cheap.
high prices signal quality.
raise prices later? you’ll break expectation (read trust) and lose clients.always charge what you’re actually worth.

think you move fast enough?

be fast. be flexible.
big players aren’t.
leverage your smaller size.
test. adapt. iterate.
do what they can’t.

mimicking what you can’t afford?

complex systems won’t make you money.
and you probably can’t afford them.
Specialise.
Profitability first.
Build what works.
Do what they can’t.

is it in the right frame?

if the frame is right, everything else follows.shiny tools won't solve what a wrong starting point caused.you pick a website.
a campaign.
a funnel.
before knowing what they actually need them to do.might “work”...
but you won't know why.
so you can't replicate it.
stop wasting time and money.build with purpose.
being seen without being understood = noise.

standing out before it counts?

don't show off too early.if no one sees you, being different means little.
if they don’t know you’re there, they won’t notice.
timing is everything.get attention.
be visible.
survive.
then you answer the question:why you, not them?clarity > gimmicks.
positioning > noise.
that order matters.

trying to get it right the first time?

stop.
it's not going to happen.
ideas might fail.
products can fail.
Campaigns will fail.
test. learn.
iterate. repeat.
perfection kills progress.
iteration beats busywork.
progress is how you win.

what if design was simple?
what happens when you cut the superfluous?

simple is can be good.
improve clarity.
and increase pressure.simplicity leaves nothing to hide behind.might be why so much of what's built online tries too hard.which way is best? still trying to figure that one out.

wanna talk about it? document.addEventListener('DOMContentLoaded', () => { const link = document.getElementById('contact-link'); link.addEventListener('click', (e) => { e.preventDefault(); // Toggle arrow state (like posts) link.classList.toggle('active'); // Smooth scroll to section const target = document.querySelector('#contact'); if (target) { const rect = target.getBoundingClientRect(); const scrollTop = window.pageYOffset + rect.top; window.scrollTo({ top: scrollTop, behavior: 'smooth' }); } }); });
what pulls you in?
// Function to wrap words in spans with staggered delays (function() { function wrapWords(sectionId, delayStep = 0.3, randomOffset = 0) { const container = document.getElementById(sectionId); if (!container) return; const words = container.textContent.trim().split(' '); container.textContent = ''; words.forEach((word, i) => { const span = document.createElement('span'); span.textContent = word + ' '; // Add optional random offset for subtle difference per section const offset = randomOffset ? (Math.random() * randomOffset - randomOffset/2) : 0; span.style.animationDelay = `${i * delayStep + offset}s`; container.appendChild(span); }); } function init() { wrapWords('hero-insights', 0.25, 0.1); wrapWords('hero-experiments', 0.28, 0.15); wrapWords('hero-about', 0.32, 0.1); wrapWords('hero-contact', 0.3, 0.2); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();

when shape breaks expectation.

symmetry is comfort.but not everything needs to be clean.
or straight.
a shift in form
is sometimes enough
to pull attention.
look at this:what did you see first?
the shape?
or the words?
did the shape distract you?
or did it guide you?
still testing how far is too far.











when environment reacts to "touch"

when you touch something physical, it doesn't usually shoot out particle effects.butit's not fixed.
it's not static.
it shifts with what's behind.
bends.
snaps.
bounces.
if it does that
and it's digital
your conscious knows it's not "real".
that you're not actually touching it.
yet something inside of you still feels the mechanics of touch.
you might not know why.
but it does.
even when you keep it simple.
→ try it (desktop only. for now)

you see before you understand.

before anything is
understood
something
happens.
your eyes move.
your attention shifts.
your body reacts.
not to meaning, no.
to colour.
to movement.
to contrast.
meaning comes later.
so what actually shaped the experience?
the meaning you took from it...
or the feeling before you got there?

wanna talk about it? document.addEventListener('DOMContentLoaded', () => { const link = document.getElementById('contact-link'); link.addEventListener('click', (e) => { e.preventDefault(); // Toggle arrow state (like posts) link.classList.toggle('active'); // Smooth scroll to section const target = document.querySelector('#contact'); if (target) { const rect = target.getBoundingClientRect(); const scrollTop = window.pageYOffset + rect.top; window.scrollTo({ top: scrollTop, behavior: 'smooth' }); } }); });
this is why

I test. I fail. I observe.
I work with ideas and people.
I think out loud so you don’t have to.

I build things that sometimes stick.
I write. I plan. I strategize.
I notice patterns. I follow hunches.

I ask questions most won’t.
I chase clarity, not certainty.
I share what I learn along the way.

Some things land. Some fall apart.
Some teach. Some surprise.
Some spark ideas. Some leave more questions.

This is my playground.
This is my process.
This is how I work.

wanna talk about it? document.addEventListener('DOMContentLoaded', () => { const link = document.getElementById('contact-link'); link.addEventListener('click', (e) => { e.preventDefault(); // Toggle arrow state (like posts) link.classList.toggle('active'); // Smooth scroll to section const target = document.querySelector('#contact'); if (target) { const rect = target.getBoundingClientRect(); const scrollTop = window.pageYOffset + rect.top; window.scrollTo({ top: scrollTop, behavior: 'smooth' }); } }); });
did it land? tell me.
// Function to wrap words in spans with staggered delays (function() { function wrapWords(sectionId, delayStep = 0.3, randomOffset = 0) { const container = document.getElementById(sectionId); if (!container) return; const words = container.textContent.trim().split(' '); container.textContent = ''; words.forEach((word, i) => { const span = document.createElement('span'); span.textContent = word + ' '; // Add optional random offset for subtle difference per section const offset = randomOffset ? (Math.random() * randomOffset - randomOffset/2) : 0; span.style.animationDelay = `${i * delayStep + offset}s`; container.appendChild(span); }); } function init() { wrapWords('hero-insights', 0.25, 0.1); wrapWords('hero-experiments', 0.28, 0.15); wrapWords('hero-about', 0.32, 0.1); wrapWords('hero-contact', 0.3, 0.2); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();

not everything here is right.but it’s all meant to be challenged.if you have something to add,
push back,
or build on,
reach out.

are you really touching it?

Hover your cursor over the texts below.

it yields.
it resists and snaps.
it affects what’s around it
it feels you coming
(function(){ function wrapLines() { const lines = document.querySelectorAll('.tactile-line'); lines.forEach(line => { const text = line.textContent; line.textContent = ''; text.split('').forEach(char => { const span = document.createElement('span'); span.textContent = char === ' ' ? '\u00A0' : char; line.appendChild(span); }); }); } /* Ripple neighbor fix (previous sibling) */ function setupRipple() { const ripple = document.querySelectorAll('.ripple span'); ripple.forEach((span, i) => { span.addEventListener('mouseenter', () => { if (ripple[i - 1]) ripple[i - 1].classList.add('prev'); }); span.addEventListener('mouseleave', () => { if (ripple[i - 1]) ripple[i - 1].classList.remove('prev'); }); }); } /* Magnetic field effect */ function setupField() { const field = document.querySelectorAll('.field span'); document.addEventListener('mousemove', (e) => { field.forEach(span => { const rect = span.getBoundingClientRect(); const dx = e.clientX - (rect.left + rect.width / 2); const dy = e.clientY - (rect.top + rect.height / 2); const dist = Math.sqrt(dx * dx + dy * dy); const maxDist = 120; if (dist < maxDist) { const force = (maxDist - dist) / maxDist; span.style.transform = `translate(${dx * -0.05 * force}px, ${dy * -0.05 * force}px)`; } else { span.style.transform = ''; } }); }); } /* Init */ function init() { wrapLines(); setupRipple(); setupField(); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();
it yields.
it resists and snaps.
it affects what’s around it
it feels you coming
(function(){ function wrapLines() { const lines = document.querySelectorAll('.tactile-line'); lines.forEach(line => { const text = line.textContent; line.textContent = ''; text.split('').forEach(char => { const span = document.createElement('span'); span.textContent = char === ' ' ? '\u00A0' : char; line.appendChild(span); }); }); } /* Ripple neighbor fix (previous + next sibling) */ function setupRipple() { const ripple = document.querySelectorAll('.ripple span'); ripple.forEach((span, i) => { span.addEventListener('mouseenter', () => { if (ripple[i - 1]) ripple[i - 1].classList.add('prev'); if (ripple[i + 1]) ripple[i + 1].classList.add('prev'); }); span.addEventListener('mouseleave', () => { if (ripple[i - 1]) ripple[i - 1].classList.remove('prev'); if (ripple[i + 1]) ripple[i + 1].classList.remove('prev'); }); }); } /* Magnetic field effect */ function setupField() { const field = document.querySelectorAll('.field span'); document.addEventListener('mousemove', (e) => { field.forEach(span => { const rect = span.getBoundingClientRect(); const dx = e.clientX - (rect.left + rect.width / 2); const dy = e.clientY - (rect.top + rect.height / 2); const dist = Math.sqrt(dx * dx + dy * dy); const maxDist = window.innerWidth < 600 ? 80 : 120; if (dist < maxDist) { const force = (maxDist - dist) / maxDist; span.style.transform = `translate(${dx * -0.05 * force}px, ${dy * -0.05 * force}px)`; } else { span.style.transform = ''; } }); }); } /* Init */ function init() { wrapLines(); setupRipple(); setupField(); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();
it yields.
it resists and snaps.
it affects what’s around it
it feels you coming
(function(){ function wrapLines() { const lines = document.querySelectorAll('.tactile-line'); lines.forEach(line => { const text = line.textContent; line.textContent = ''; text.split('').forEach(char => { const span = document.createElement('span'); span.textContent = char === ' ' ? '\u00A0' : char; line.appendChild(span); }); }); } /* Ripple neighbor fix */ function setupRipple() { const ripple = document.querySelectorAll('.ripple span'); ripple.forEach((span, i) => { span.addEventListener('mouseenter', () => { if (ripple[i - 1]) ripple[i - 1].classList.add('prev'); if (ripple[i + 1]) ripple[i + 1].classList.add('prev'); }); span.addEventListener('mouseleave', () => { if (ripple[i - 1]) ripple[i - 1].classList.remove('prev'); if (ripple[i + 1]) ripple[i + 1].classList.remove('prev'); }); }); } /* FIELD magnetic + color ripple */ function setupField() { const field = document.querySelectorAll('.field span'); document.addEventListener('mousemove', (e) => { field.forEach((span, i) => { const rect = span.getBoundingClientRect(); const dx = e.clientX - (rect.left + rect.width / 2); const dy = e.clientY - (rect.top + rect.height / 2); const dist = Math.sqrt(dx * dx + dy * dy); const maxDist = window.innerWidth < 600 ? 80 : 120; if (dist < maxDist) { const force = (maxDist - dist) / maxDist; span.style.transform = `translate(${dx * -0.05 * force}px, ${dy * -0.05 * force}px)`; // ripple color stagger const delay = i * 0.02; // stagger per letter span.style.transition = `transform 0.12s ease-out ${delay}s, color 0.12s ease-out ${delay}s`; span.style.color = '#FFCFA5'; } else { span.style.transform = ''; span.style.color = ''; span.style.transition = 'transform 0.12s ease-out, color 0.12s ease-out'; } }); }); } /* Init */ function init() { wrapLines(); setupRipple(); setupField(); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();