text:
Disconnect 4 bits
Your task: given an input string, determine whether the binary representation of that string does not have 4 1s or 0s in a row, anywhere. Furthermore, your code itself should not contain any such runs of four in a row.
Test Cases
String      Binary              Result

U3          01010101 00110011   Truthy

48          00110100 00111000   Falsy

Foobar      01000110 01101111   Falsy
            01101111 01100010
            01100001 01110010

Feeber      01000110 01100101   Truthy
            01100101 01100010
            01100101 01110010

$H          00100100 01001000   Truthy

<Empty>     -                   Truthy

Rules

Input will always be within the range of printable ASCII, including whitespace characters.

Your code may use any encoding, since it only matters at the bit level.

Because this condition prevents the use of white space and many other chars, your code actually can contain such runs of four in a row, at a 10 byte penalty for each run.

A run of 5 1s or 0s counts as two runs, 6 in a row counts as three runs, etc.

Input will be a string or char array, not any other form.
You may write a complete program or function.
You must provide the binary representation of your code in your answer.

Good luck, lowest score wins!
This script might help you with your challenge, put your code in the input and it will give you your code's binary representation, it's length, your penalty, and the total score, if you're using UTF-8.
Leaderboard
Here is a Stack Snippet to generate both a regular leaderboard and an overview of winners by language.

/* Configuration */

var QUESTION_ID = 111758; // Obtain this from the url
// It will be like https://XYZ.stackexchange.com/questions/QUESTION_ID/... on any question page
var ANSWER_FILTER = "!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe";
var COMMENT_FILTER = "!)Q2B_A2kjfAiU78X(md6BoYk";
var OVERRIDE_USER = 60042; // This should be the user ID of the challenge author.

/* App */

var answers = [], answers_hash, answer_ids, answer_page = 1, more_answers = true, comment_page;

function answersUrl(index) {
  return "https://api.stackexchange.com/2.2/questions/" +  QUESTION_ID + "/answers?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + ANSWER_FILTER;
}

function commentUrl(index, answers) {
  return "https://api.stackexchange.com/2.2/answers/" + answers.join(';') + "/comments?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + COMMENT_FILTER;
}

function getAnswers() {
  jQuery.ajax({
    url: answersUrl(answer_page++),
    method: "get",
    dataType: "jsonp",
    crossDomain: true,
    success: function (data) {
      answers.push.apply(answers, data.items);
      answers_hash = [];
      answer_ids = [];
      data.items.forEach(function(a) {
        a.comments = [];
        var id = +a.share_link.match(/\d+/);
        answer_ids.push(id);
        answers_hash[id] = a;
      });
      if (!data.has_more) more_answers = false;
      comment_page = 1;
      getComments();
    }
  });
}

function getComments() {
  jQuery.ajax({
    url: commentUrl(comment_page++, answer_ids),
    method: "get",
    dataType: "jsonp",
    crossDomain: true,
    success: function (data) {
      data.items.forEach(function(c) {
        if (c.owner.user_id === OVERRIDE_USER)
          answers_hash[c.post_id].comments.push(c);
      });
      if (data.has_more) getComments();
      else if (more_answers) getAnswers();
      else process();
    }
  });
}

getAnswers();

var SCORE_REG = /<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/;

var OVERRIDE_REG = /^Override\s*header:\s*/i;

function getAuthorName(a) {
  return a.owner.display_name;
}

function process() {
  var valid = [];

  answers.forEach(function(a) {
    var body = a.body;
    a.comments.forEach(function(c) {
      if(OVERRIDE_REG.test(c.body))
        body = '
' + c.body.replace(OVERRIDE_REG, '') + '
';
    });

    var match = body.match(SCORE_REG);
    if (match)
      valid.push({
        user: getAuthorName(a),
        size: +match[2],
        language: match[1],
        link: a.share_link,
      });

  });

  valid.sort(function (a, b) {
    var aB = a.size,
        bB = b.size;
    return aB - bB
  });

  var languages = {};
  var place = 1;
  var lastSize = null;
  var lastPlace = 1;
  valid.forEach(function (a) {
    if (a.size != lastSize)
      lastPlace = place;
    lastSize = a.size;
    ++place;

    var answer = jQuery("#answer-template").html();
    answer = answer.replace("{{PLACE}}", lastPlace + ".")
                   .replace("{{NAME}}", a.user)
                   .replace("{{LANGUAGE}}", a.language)
                   .replace("{{SIZE}}", a.size)
                   .replace("{{LINK}}", a.link);
    answer = jQuery(answer);
    jQuery("#answers").append(answer);

    var lang = a.language;
    if (/ b.lang) return 1;
    if (a.lang < b.lang) return -1;
    return 0;
  });

  for (var i = 0; i < langs.length; ++i)
  {
    var language = jQuery("#language-template").html();
    var lang = langs[i];
    language = language.replace("{{LANGUAGE}}", lang.lang)
                       .replace("{{NAME}}", lang.user)
                       .replace("{{SIZE}}", lang.size)
                       .replace("{{LINK}}", lang.link);
    language = jQuery(language);
    jQuery("#languages").append(language);
  }

}
body { text-align: left !important}

#answer-list {
  padding: 10px;
  width: 290px;
  float: left;
}

#language-list {
  padding: 10px;
  width: 290px;
  float: left;
}

table thead {
  font-weight: bold;
}

table td {
  padding: 5px;
}

<link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b">

Leaderboard

	Author	Language	Size

Winners by Language

Language	User	Score

{{PLACE}}	{{NAME}}	{{LANGUAGE}}	{{SIZE}}	Link

{{LANGUAGE}}	{{NAME}}	{{SIZE}}	Link

I'm pretty sure that snippet is buggy, e.g. I see || listed and that is 0111110001111100.

Right, good point. One second.

ok but why can I see the comment

Your tio.run link seems to exclude a bunch of valid pairs of characters (for example, lowercase letters followed by uppercase letters) ... are you using unordered pairs in your loop instead of ordered pairs?

@GregMartin Uhh, as you can maybe see, I tried to comment it out. The code was written by ConorO'Brien. Anyway, fixed the post now.

Would have been even more fun if the task was to find the score of a string.

Hmm, does "The value you output/return for truthy and falsy must be consistent." imply only a single value (unlike the standard definition of truthy and falsy)?

Do we pretend big-endianness?

@JonathanAllan well, the way I intended it, it does, but upon further reflection I don't really see a reason for that, so I'll change it.

I think this is an interesting challenge even without the source code constraint. Poor java :[

@Adám yeah, do that.

@Poke You can make a submission and try to minimize penalties. Java wasn't going to win anyway ;)

Here's a program to count penalties for ISO 8859-1 submissions.

@Pavel The scoring is not based solely on bytes if there are penalties. This makes it a [code-challenge], not [code-golf]. From the tag wiki: "If source code length is not the primary scoring criterion, consider using another tag instead." TL;DR, since the actual score =/= the program's byte count, and the shortest code doesn't mean getting the best score, it's not [code-golf].

Suggested additional test cases: , , , . Also all of those with a trailing string that on its own would be truthy (e.g. U3). I say this because my code was actually failing some of these and I had not noticed for a while.

@JonathanAllan I'm not sure what you mean by that last one, but feel free to edit it in.

Jelly, 18 bytes + 0 penalties = 18
79Ọv2;$ḅ⁹b2+4\b4FẠ

Returns 1 if there are no equal bit strings of length 4 or more in the 8-bit word representation of the ASCII string input, and 0 otherwise.
Try it online! (test suite with some extra cases added)
Using Jelly's codepage there are no length 4 or longer substrings of equal bits:
7    0x37    00110111
9    0x39    00111001
Ọ    0xB5    10110101
v    0x76    01110110
2    0x32    00110010
;    0x3B    00111011
$    0x24    00100100
ḅ    0xD4    11010100
⁹    0x89    10001001
b    0x62    01100010
2    0x32    00110010
+    0x2B    00101011
4    0x34    00110100
\    0x5C    01011100
b    0x62    01100010
4    0x34    00110100
F    0x46    01000110
Ạ    0xAB    10101011

With equal-bit run lengths of:
221323221211111312322133122121221111213121123132213111122211311332313211313211111112

How?
Tricks to avoid demerits are:

to avoid the "convert from character to ordinal" monad O by converting the number 79 to a character using Ọ followed by an "evaluation of Jelly code with input", v.
to avoid direct conversion to binary using B (0x42, 1000010) by the simple two-byte alternative b2 using the generic dyadic base conversion.
to avoid a few normal choices for counting the runs of equal bits - first choice would be "all overlapping slices of given length", ṡ (0xF5 or 11110101). A second choice might be to utilise "all sublists", Ẇ (0xCF or 11001111).
A workaround I used before the current one was to take the increments (between consecutive elements) with I (putting zeros and ones on an equal footing), and to look for any occurrence of three zeros in a row. To do that I converted all the zeros to ones by use of the binomial function with 2c i.e. 2Cx - making the -1s become 0s the 1s become 2s, and the 0s become 1s; that way the code can look for the first occurrence of the sublist [1,1,1] with w111.
However a shorter way became apparent - to mimic the action of "all overlapping slices of given length", ṡ, one can use a 4-wise overlapping reduce with some dyad, <dyad>4\. If this is performed with addition, +4\, it counts the 1s, so then any 0 or 4 being present is the indicator to return a truthy value. The issue here is that the next obvious step would be to take the modulo 4 of that to put the 0 and 4 entries on an equal footing while leaving the other possible values (1, 2, and 3) unchanged, but +\%4 has \% inside, which has bit-value 0101110000100100. In order to avoid that penalty the numbers are all converted to base 4 with b4 (mapping 0 to [0], 1 to [1], 2 to [2], 3 to [3], and 4 to [1,0]) and the whole list is flattened with F. Now the last test is simply to check if there are any 0s in the list, achievable directly with the monad Ạ.

79Ọv2;$ḅ⁹b2+4\b4FẠ - Main link: printable ASCII character list
79                 - 79
  Ọ                - character from ordinal : 'O'
   v               - evaluate as Jelly code : input -> 'O' converts the input to ordinals
      $            - last two links as a monad
    2              -     2
     ;             -     concatenate (why? see the note beneath the code block)
       ḅ⁹          - convert from base 256 : gets an integer representing the byte string
         b2        - convert to base 2 AKA binary
            4\     - 4-wise reduce with
           +       -     addition (sums all overlapping slices of length 4)
              b4   - convert to base 4 (vectorises)
                F  - flatten into a single list
                 Ạ - any falsy?

Note: The reason a 2 is concatenated with the ordinal list is to deal with the edge cases where the only run of 4 in the input string is in the leading zeros of the very first character - these characters are: tab; line-feed; and carriage-return. Without this the base 256 conversion effectively strips leading zeros from the (fully concatenated) binary string; with the leading 2 the leading zeros will be there and an extra one and zero before them. Since no printable ASCII has exactly three leading zeros there is no need to discard these extra bits before the rest of the check.

I'm assuming you could just add a negate or something similar to comply with The value you output/return for truthy and falsy must be consistent which I interpret as "same value each time for truthy" and same for falsy. Also your true/false is opposite the ones in the question.

I just enquired about that - when I originally read it (many hours ago) I took "The value you output/return for truthy and falsy must be consistent." to mean we could output either way around so long as it stayed the same way around between runs... A straight forward negate will incur demerit.

I could definitely save some as well if I don't have to do that. Down to a very low score with the new version I'm working on. I hope you're the one who's interpreted correctly :)

Well I've given a two byte suffix that does the trick, giving both the same way around as the examples and strictly consistent values of 0 and 1 if need be.

Nice. Looking forward to seeing how you did it. I only get down to 15 if I ignore all demerits :)

@Emigna I got it down to 15 while having it return 1 and 0 the original way around and then noticed some failed edge cases and it went back up to 18 again!

Java 7, 812 726 673 644 634 616 599 588 145 bytes + 10*44 = 585
boolean
b(char[]b){String
g="";for(char
c:b)g+=g.format("%"+(1-1)+"8d",new
Integer(Integer.toString(c,2)));return!g.matches(".*(.)\\1\\1\\1.*");}

I am using newlines instead of spaces to try to minimize penalty...
Try it online!
Binary
01100010011011110110111101101100011001010110000101101110000010100110001000101000011000110110100001100001011100100101101101011101011000100010100101111011010100110111010001110010011010010110111001100111000010100110011100111101001000100010001000111011011001100110111101110010001010000110001101101000011000010111001000001010011000110011101001100010001010010110011100101011001111010110011100101110011001100110111101110010011011010110000101110100001010000010001000100101001000100010101100101000001100010010110100110001001010010010101100100010001110000110010000100010001011000110111001100101011101110000101001001001011011100111010001100101011001110110010101110010001010000100100101101110011101000110010101100111011001010111001000101110011101000110111101010011011101000111001001101001011011100110011100101000011000110010110000110010001010010010100100101001001110110111001001100101011101000111010101110010011011100010000101100111001011100110110101100001011101000110001101101000011001010111001100101000001000100010111000101010001010000010111000101001010111000101110000110001010111000101110000110001010111000101110000110001001011100010101000100010001010010011101101111101

Old bitshifting solution 141 bytes + 10*101 = 1,151
boolean
b(char[]b){
int
o=0,p=0,i;
for(char
c:b){for(i=0;i<8;){if((c&(1<<i++))<1){o=0;p++;}else{p=0;o++;}if(3<o|3<p)return
6<5;}}return
5<6;}

Try it online!
Binary
011000100110111101101111011011000110010101100001011011100000101001100010001010000110001101101000011000010111001001011011010111010110001000101001011110110000101001101001011011100111010000001010011011110011110100110000001011000111000000111101001100000010110001101001001110110000101001100110011011110111001000101000011000110110100001100001011100100000101001100011001110100110001000101001011110110110011001101111011100100010100001101001001111010011000000111011011010010011110000111000001110110010100101111011011010010110011000101000001010000110001100100110001010000011000100111100001111000110100100101011001010110010100100101001001111000011000100101001011110110110111100111101001100000011101101110000001010110010101100111011011111010110010101101100011100110110010101111011011100000011110100110000001110110110111100101011001010110011101101111101011010010110011000101000001100110011110001101111011111000011001100111100011100000010100101110010011001010111010001110101011100100110111000001010001101100011110000110101001110110111110101111101011100100110010101110100011101010111001001101110000010100011010100111100001101100011101101111101

Nice trick with the newlines. Counting 00000/11111 as two runs, 000000/111111 as three, etc. I count 101 runs total.

@ETHproductions Fixed

This should just win since Java was never meant for this

APL (Dyalog Classic), 26 + 1 × 10 = 36 bytes
Notes
Contains one 4-run of 1s. Requires ⎕IO←0 which is default on many systems. Note that this must be run on a Classic interpreter so that strings are one byte per character.
Submission
1≠⊃⌽⌈\∊(×4\¨⍳≢⍬⍬)⍷¨⊂11⎕DR⍞
Try it online!
Binary source
0011000110101100100111001011001010010111010111001011100100101000110101110011010001011100101010001011110010111011101010111010101100101001101110101010100010011011001100010011000110001100010001000101001010001101

Explanation
⍞ Prompt for string input
11 ⎕DR convert to 1-bit Boolean (1) Data Representation
⊂ enclose so we can apply multiple things to it
(…) ⍷¨ binary indicators where each of the following sequences begin…
 × sign (no-op on binary data, but included as spacer to split runs)
 4 \¨ expand (copy) each to length four
 ⍳ the integers up to
 ≢ the tally of
 ⍬⍬  the list consisting of two empty numeric lists
∊ enlist (flatten)
⌈\ cumulative maximum
⌽ reverse
⊃ pick the first
1 ≠ is one different from? (i.e. NOT)
Walk-through
We will input "48" to the ungolfed un-de-runned version ~ ∨/ ∊ (0 0 0 0)(1 1 1 1) ⍷¨ ⊂ 11 ⎕DR ⍞:
11 ⎕DR ⍞ converts "48" to 0 0 1 1 0 1 0 0 0 0 1 1 1 0 0 0 (i.e. Dec 52 56, Hex 34 38)
(0 0 0 0)(1 1 1 1) ⍷¨ ⊂ finds beginnings of 0-runs and 1-runs; (0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0) (0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
∨/ ∊ looks if there is any Truth (i.e. any runs); 1
~ negates that; 0

Jelly 28 + 140 demerits = 168
L8_0xṭ
OBUÇ€UFŒr<4FẠ

Explanation
OB

Converts the argument to a list of their binary encodings, e.g.
“U3”OB -> [[1, 0, 1, 0, 1, 0, 1], [1, 1, 0, 0, 1, 1]]

The next piece
UÇ€U

fixes the fact that the above list can be missing characters as B does not include leading zeros. Ç€ calls the previously defined link over each element which restores that
L8_0xṭ

This link is equivalent to
lambda x: x + repeat(0, 8 - len(x))

For example
[1, 1, 0, 0, 1, 1] L8_0xṭ -> [1, 1, 0, 0, 1, 1, [0, 0]]

We upend the list before and after this operation (the two U calls in that list) to get that to be a prepend rather than an append. The next piece
FŒr

Flattens the list (F), giving the total binary string of the ASCII encoding, and run-length encodes the output (Œr). So for example
L8_0xṭ
“U3”OBUÇ€UF -> [1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0]

and
L8_0xṭ
“U3”OBUÇ€UFŒr -> [[1, 1], [0, 1], [1, 1], [0, 1], [1, 1], [0, 1], [1, 1], [0, 1], [1, 2], [0, 2], [1, 2], [0, 2]]

Finally we check whether each element is < 4 (thankfully this is always true for 0,1) with
<4F

For example
L8_0xṭ
“U3”OBUÇ€UFŒr<4F -> [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

Finally
Ạ

Returns 0 if any of those are falsy (in this case, 0).
Code Pages
In Jelly's code page this code is 20 bytes but has 27 runs worth of rule violations. In UTF-8 it is 28 bytes but with only 14 runs worth of violations.

PHP, 98 + 270 = 368 bytes
I wanted to take a different approach from what Titus proposed, and ended with a slightly longer, yet less penalized program.
$v=unpack('H*',$argv[1]);$e=base_convert($v[1],16,2);echo!stristr($e,'0000')&&!stristr($e,'1111');

Outputs 1 for truthy, nothing for falsey.
Try it here !
Binary-encoded :
0010010001110110001111010111010101101110011100000110000101100011011010110010100
0001001110100100000101010001001110010110000100100011000010111001001100111011101
1001011011001100010101110100101001001110110010010001100101001111010110001001100
0010111001101100101010111110110001101101111011011100111011001100101011100100111
0100001010000010010001110110010110110011000101011101001011000011000100110110001
0110000110010001010010011101101100101011000110110100001101111001000010111001101
1101000111001001101001011100110111010001110010001010000010010001100101001011000
0100111001100000011000000110000001100000010011100101001001001100010011000100001
0111001101110100011100100110100101110011011101000111001000101000001001000110010
1001011000010011100110001001100010011000100110001001001110010100100111011

(22 occurences of 0000 and 5 occurrences of 1111, hence 270 bytes of penalty)

05AB1E, 22 + 3 * 10 = 52
Saved 2 penalty runs borrowing the delta trick from Jonathan Allan's Jelly answer
$Ç256+bvy¦}J¥J6Ìb¦å2ÍQ

Try it online!
Explanation
$                       # push 1 and input (1 to handle the empty string)
 Ç                      # convert to list of ascii values
  256+                  # add 256 to each
      b                 # convert each to binary
       vy¦}             # chop off the leading digit of each
           J            # join to string
            ¥           # take delta's
             J          # join to string
              6Ìb¦      # push bin(6+2)[1:] = 000
                  å     # check if this exists in the delta's string
                   2ÍQ  # compare to 2-2 = 0

Binary representation of the code
00100100 11000111 00110010 00110101 00110110 00101011 01100010 01110110
01111001 10100110 01111101 01001010 10100101 01001010 00110110 11001100
01100010 10100110 11100101 00110010 11001101 01010001

The 3 penalty runs come from vy¦} which is used to chop off the first byte in each binary string, but it's still cheaper than the 4 runs we'd get from the shorter €¦.

@JonathanAllan: I mention it a bit at the end (but not in detail), but unfortunately the binary representation of € in CP-1252 is 10000000 which incurs a penalty of 4 by itself.

Ah, so you do! ...and my Python code for getting the representation was incorrect as I put # coding: cp1252 at the top >_<

Perl, 33 + 160 = 193
32 bytes of code + 1 byte for -n flag.
$_=unpack"B*";print!m+(.)\1\1\1+

(the input needs to be supplied without final newline. The Try it online link has -l flag on to remove newlines, but for a single input, it's not needed).
Try it online!
xxd dump :
00000000: 00100100 01011111 00111101 01110101 01101110 01110000  $_=unp
00000006: 01100001 01100011 01101011 00100010 01000010 00101010  ack"B*
0000000c: 00100010 00111011 01110000 01110010 01101001 01101110  ";prin
00000012: 01110100 00100001 01101101 00101011 00101000 00101110  t!m+(.
00000018: 00101001 01011100 00110001 01011100 00110001 01011100  )\1\1\
0000001e: 00110001 00101011                                      1+

A few notes:

(.)\1\1\1 saves a few penalties over (.)\1{3}, 1111|0{4} or any other regex I could think of (using 0 or {} comes at a heavy cost).
print saves ~8 points over using -p and $_= because p contains a run of 4 0 while n doesn't.
+ as a delimiter for the regex saves a run of 1 that is in /.
doing two steps instead of one with !~ saves two runs (~ is 01111110 in binary).
unpack"B*" is quite expensive (4 runs), but I couldn't find cheaper (solutions bases on ord will be even more expensive).

PHP, 86 bytes+370=456
for(;$c=ord($argn[$i++]);)$s.=sprintf("%08b",$c);echo!preg_match("#(.)\\1\\1\\1#",$s);

creates the binary string and uses a regex to detect streaks.
Output is 1 for truthy; empty for falsy.
Run with echo '<string>' | php -nR ''.
tweaks

backreferences save 100 penalty for 3 bytes. (-97 score)

abandoned ideas

join(array_map(str_split())) would cost 31 bytes and 90 penalty
and <?=/$argv[1] instead of echo/$argn cost another 2+40.
str_pad(decbin()) is costlier than sprintf: 7 bytes and 110 penalty.
strtr saves 80 penalty for 13 extra bytes, but backreferences are better.
Grouping the backreferences #(.)\\1{3} saves 3 bytes, but adds 10 penalty.
foreach costs 3+50.
No saving possible on the variable names.
output buffering costs 42+120.

Add a § at for(§; for -9.

MATL, 16 bytes + 60 = 76 bytes
8&B!1e&Y'tgw4<Z&

Try it at MATL Online

JavaScript (ES8), 91 bytes + 430 penalty = 521 total
This will output 1 for true and 0 for false.
s=>1-/(.)\1\1\1/.test([...s].map(c=>c.charCodeAt().toString(2).padStart(3+5,1-1)).join(""))

01110011001111010011111000110001001011010010111100101000001011100010100101011100001100010101110000110001010111000011000100101111001011100111010001100101011100110111010000101000010110110010111000101110001011100111001101011101001011100110110101100001011100000010100001100011001111010011111001100011001011100110001101101000011000010111001001000011011011110110010001100101010000010111010000101000001010010010111001110100011011110101001101110100011100100110100101101110011001110010100000110010001010010010111001110000011000010110010001010011011101000110000101110010011101000010100000110011001010110011010100101100001100010010110100110001001010010010100100101110011010100110111101101001011011100010100000100010001000100010100100101001

Try it

f=

s=>1-/(.)\1\1\1/.test([...s].map(c=>c.charCodeAt().toString(2).padStart(3+5,1-1)).join(""))

console.log(f("U3"))
console.log(f("48"))
console.log(f("Foobar"))
console.log(f("Feeber"))
console.log(f("$H"))
console.log(f(""))

padStart isn't in ES6.

Damnit! I keep forgetting to change to ES8 whenever I use it (same with ES7 and Array.includes()) - thanks, @Neil.

CJam, 23 bytes
Uses Jonathan Allan's idea to work with deltas.
1q256b2b2ew::-[TTT]#)g-

Try it online!
Binary representation:
00110001011100010011001000110101
00110110011000100011001001100010
00110010011001010111011100111010
00111010001011010101101101010100
01010100010101000101110100100011
001010010110011100101101

Explanation:
1     e# Push a 1 for (much) later, because we can't use ! for logical NOT.
q     e# Read input.
256b  e# Treat characters as base 256 digits.
2b    e# Convert to binary. The last two steps together give us a flat binary
      e# representation of the input, avoiding both :~ and e_ for flattening.
2ew   e# Get all pairs of consecutive bits.
::-   e# Compute their differences.
[TTT] e# Push [0 0 0].
#     e# Find its index in the list of differences, or -1 if not found.
)g    e# Increment and take signum. We've now got the result we want but
      e# with the wrong truth value.
-     e# Subtract it from the 1 we pushed earlier to negate the truth value.

JavaScript (ES6), 87 88 + 390 380 = 477 468 bytes
s=>1-/(.)\1\1\1/.test(s.replace(/[\S\s]/g,c=>(256+c.charCodeAt()).toString(2).slice(1)))

In binary:
01110011001111010011111000110001001011010010111100101000001011100010100101011100001100010101110000110001010111000011000100101111001011100111010001100101011100110111010000101000011100110010111001110010011001010111000001101100011000010110001101100101001010000010111101011011010111000101001101011100011100110101110100101111011001110010110001100011001111010011111000101000001100100011010100110110001010110110001100101110011000110110100001100001011100100100001101101111011001000110010101000001011101000010100000101001001010010010111001110100011011110101001101110100011100100110100101101110011001110010100000110010001010010010111001110011011011000110100101100011011001010010100000110001001010010010100100101001

Over half of the penalty is down to zeros in the overlap between bytes, rather than the runs in the following characters: =>//pa//=>aCoAo.
Since the /s (00101111) pay a penalty I tried a) switching from test to match b) switching from replace to map but the score always ended up higher. However I did find that [\S\s] was an improvement over [^]. Edit: Saved 9 bytes overall thanks to @Shaggy.

I think the | in the character class is not supposed to be there

@ETHproductions I got it right in my explanation...

You could shave 10 off your penalty by replacing  the ! with 1- for a total of 468. And you could make a further saving of 5 bytes by replacing [\S\s] with . for a total of 463.

@Shaggy Thanks, although I'm not sure whether newlines count as printable, so I'll play it safe for now.

Does js support a multiline regex flag? If so, you could accept Shaggy's suggestion and add the flag to still save bytes.

@Pavel Sadly JavaScript does not.

JavaScript, 173 + 89 * 10 = 1063
JavaScript is not good at converting strings to binary, but I figured I'd give this challenge a shot just for fun.
Code:
function(n){b="";for(var t=0;t<n.length;t++)c=[n.charCodeAt(t).toString(2)],c.unshift(Array(8-c[0].length+1).join(0)),b+=c.join("");return b.match(/[1]{4,}|[0]{4,}/g)?!1:!0}

Binary:
0110011001110101011011100110001101110100011010010110111101101110001010000110111000101001011110110110001000111101001000100010001000111011011001100110111101110010001010000111011001100001011100100010000001110100001111010011000000111011011101000011110001101110001011100110110001100101011011100110011101110100011010000011101101110100001010110010101100101001011000110011110101011011011011100010111001100011011010000110000101110010010000110110111101100100011001010100000101110100001010000111010000101001001011100111010001101111010100110111010001110010011010010110111001100111001010000011001000101001010111010010110001100011001011100111010101101110011100110110100001101001011001100111010000101000010000010111001001110010011000010111100100101000001110000010110101100011010110110011000001011101001011100110110001100101011011100110011101110100011010000010101100110001001010010010111001101010011011110110100101101110001010000011000000101001001010010010110001100010001010110011110101100011001011100110101001101111011010010110111000101000001000100010001000101001001110110111001001100101011101000111010101110010011011100010000001100010001011100110110101100001011101000110001101101000001010000010111101011011001100010101110101111011001101000010110001111101011111000101101100110000010111010111101100110100001011000111110100101111011001110010100100111111001000010011000100111010001000010011000001111101

Explanation:
Create a string to work with:
b="";

Loop over each character in the string:
for(var t=0;t<n.length;t++)

Create an array and convert the string to binary using character code:
c=[n.charCodeAt(t).toString(2)]

Add the leading zeros to the array:
c.unshift(Array(8-c[0].length+1).join(0))

Join the array back into a string:
b+=c.join("")

Return whether or not a string of four or more 1's or 0's was found in the binary result using a regular expression:
return b.match(/[1]{4,}|[0]{4,}/g)?!1:!0

Fiddle:
https://jsfiddle.net/vrtLh97c/
Stats:
Length: 173 bytes
Penalty: 890
Total: 1063
Code Golf is hard :)

Can you provide the binary representation of your code, and document the penalties?

This has a penalty of 890 for a total score of 1063.

Added totals to original post.

Using 1-1 instead of 0 in a few places could save you some demerits.

Pyth, 19 + 12 * 10 = 139
!|}*"0"4.BQ}*"1"4.B

Binary
00100001 01111100 01111101 00101010
00100010 00110000 00100010 00110100
00101110 01000010 01010001 01111101
00101010 00100010 00110001 00100010
00110100 00101110 01000010

Explanation
!|}*"0"4.BQ}*"1"4.B
            *"1"4     # Repeat  ; '1111'
                 .B   # Convert ; input as a binary string
           }          # In      ; '1111' in the binary repr
   *"0"4              # Repeat  ; '0000'
        .BQ           # Convert ; input as a binary string
  }                   # In      ; '0000' in the binary repr
 |                    # Or      ; 4 consequent idenical digits found
!                     # Negate  ; True if not found, False if found

Retina, 101 + 1390 = 1491
The code contains unprintable characters, but they show up in Chrome if you edit the post. - is \x01-\x7f.
¶
±
S_`
%(S`±
{2`
$`
}T01`-`_o
)Ms`.
.+
$*
+`(1+)\1
${1}0
01
1
m+`^(?!.{8})
0
0{8}|¶

M&`(.)\1{3}
0

Try it online
This code uses this ord, followed by conversion to binary and a simple check for overlapping sequences of four.
In binary:
11000010101101100000101011000010101100010000101001010011010111110110000000001010001001010010100001010011011000001100001010110001000010100111101100110010011000000000101000100100011000000000101001111101010101000011000000110001011000000000000100101101011111110110000001011111011011110000101000101001010011010111001101100000001011100000101000101110001010110000101000100100001010100000101000101011011000000010100000110001001010110010100100000001000010100010010001111011001100010111110100110000000010100011000000110001000010100011000100001010011011010010101101100000010111100010100000111111001000010010111001111011001110000111110100101001000010100011000000001010001100000111101100111000011111010111110011000010101101100000101000001010010011010010011001100000001010000010111000101001000000010111101100110011011111010000101000110000

Penalties counted with this Python program.

Please provide a hexdump and binary representation, since this contains unprintables.

I already said what/where the unprintables are, along with providing a program that can print the binary string (uncomment the line at the bottom).

Alright, then..

Pyth, 21 + 2 * 10 = 41
J-T2-4eS%2.nr.[dJ.BwJ

Try it online!
Binary representation:
01001010 00101101 010101[00 00]110010 00101101 00110100 01100101 01010011
00100101 00110010 00101110 01101110 01110010 00101110 01011011 01100100
01001010 00101110 01[0000]10 01110111 01001010

Python 2, 74 (length) + 130 (penalty) = 204
k,n=2*[1]
for[c]in(input(n)*2*2*2)[:1:-1]:n,k=k*ord(c[:n%16%15])+n/2,k*128

Output is via exit code; 0 is truthy, 1 is falsy. Produces garbage output to STDOUT and STDERR.
Try it online!
Binary dump
00000000: 01101011 00101100 01101110 00111101 00110010 00101010  k,n=2*
00000006: 01011011 00110001 01011101 00001010 01100110 01101111  [1].fo
0000000c: 01110010 01011011 01100011 01011101 01101001 01101110  r[c]in
00000012: 00101000 01101001 01101110 01110000 01110101 01110100  (input
00000018: 00101000 01101110 00101001 00101010 00110010 00101010  (n)*2*
0000001e: 00110010 00101010 00110010 00101001 01011011 00111010  2*2)[:
00000024: 00110001 00111010 00101101 00110001 01011101 00111010  1:-1]:
0000002a: 01101110 00101100 01101011 00111101 01101011 00101010  n,k=k*
00000030: 01101111 01110010 01100100 00101000 01100011 01011011  ord(c[
00000036: 00111010 01101110 00100101 00110001 00110110 00100101  :n%16%
0000003c: 00110001 00110101 01011101 00101001 00101011 01101110  15])+n
00000042: 00101111 00110010 00101100 01101011 00101010 00110001  /2,k*1
00000048: 00110010 00111000                                      28

I have found that 0 is pretty bad to include. It's better to use 1-1

@Poke I just realized my mistake. The result is unused, so I'm not sure why I picked 0 in the first place.

Pyth, 16 + 1 x 10 = 26 bytes
qZsm:.BQjk*4]dZ2
   m           2  for d being the natural numbers below 2
            ]d        [d]
          *4          [d,d,d,d]
        jk            "dddd"
    :         Z       search for the above in
     .BQ              the binary representation of the input
                      (true/false)
  s               sum the 2-element array generated above, 1 for True, 0 for False
qZ                is equal to 0

Try it online!
Binary
01110001 01011010 01110011 01101101
00111010 00101110 01[0000]10 01010001
01101010 01101011 00101010 00110100
01011101 01100100 01011010 00110010

Tricks
The following alternations are done to avoid the demerits:

Using qZ (is equal to zero) instead of ! (negate)
Using :xy0 (search for) instead of }xy (is sublist)
Using Z (variable, default to zero) instead of 0 (zero itself)

Improvements
I do not find any way to circumvent the penalty. We have these commands related to binary:

.B binary (00101110 01[0000]10)
C charcode (01[0000]11)
.O octary (00101110 0100[1111])
.H hexadecimal (00101110 01001[000)

Note that .H will also give us a penalty, because every printable character has its binary representation starting with 0. Therefore, I used the most direct one, which is .B, directly converting it to binary.
I can end with .H to avoid the penalty, but it costs me 27 bytes...
Generation
I found all allowed characters, which are those that do not contain 0000 or 1111, and that do not end with 000 (because the next character must start with 0):

"#$%&')*+,-.12345679:;DEFGIJKLMNQRSTUVWYZ[\]bcdefgijklmnqrstuvw

Here are the characters that end with 1000. They can only be used at the end:

(8HXhx

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/


text:
Rotate a camera; save an Astronaut
Note: Minor spoilers for The Martian are in this challenge. Read ahead with caution

The Martian is a Science Fiction novel about astronaut and botanist extraordinaire, Mark Watney, who has been accidentally stranded on Mars. At one point in the book, Mark tries communicating with NASA, but the only means of communication they have is a camera. Mark sends messages by writing on index cards, and, since NASA can rotate the camera 360 degrees, NASA sends replies back by pointing the camera at cards labeled "Yes" or "No".
Since the only data NASA can send is the direction the camera is facing, Mark comes up with a system where they can point at cards with alphabet characters on them to type messages. But using the letters 'a-z' would be impractical. To quote the book (from this answer, over on scifi.se):

We’ll need to talk faster than yes/no questions every half hour. The camera can rotate 360 degrees, and I have plenty of antenna parts. Time to make an alphabet. But I can’t just use the letters A through Z. Twenty-six letters plus my question card would be twenty-seven cards around the lander. Each one would only get 13 degrees of arc. Even if JPL points the camera perfectly, there’s a good chance I won’t know which letter they meant.
So I’ll have to use ASCII. That’s how computers manage characters. Each character has a numerical code between 0 and 255. Values between 0 and 255 can be expressed as 2 hexadecimal digits. By giving me pairs of hex digits, they can send any character they like, including numbers, punctuation, etc.
...
So I’ll make cards for 0 through 9, and A through F. That makes 16 cards to place around the camera, plus the question card. Seventeen cards means over 21 degrees each. Much easier to deal with.

Your goal today, as one of the top software engineers at NASA, is to write a program to encode the various angles of the camera. The seventeen cards Mark has for you to point at are (in order):
?0123456789ABCDEF

and each of these cards is 21 degrees apart, so to rotate the camera from ? to 0, you should rotate the camera 21 degrees, and 2 to 1 is -21 degrees. (It's not exactly 21, but we'll round to keep it simpler) This wraps, so to go from F to 3 is 105 degrees (5 turns, 5 * 21 = 105). This is more efficient than going -252, since the camera won't have to move as far.
Here's what your program or function must do.

Take a string as input. We'll call this string s. To keep it simple, we'll say that the input will only ever be printable ASCII. For our example, let's say that the input was STATUS
Convert each character to its hexadecimal representation. This would convert STATUS to 53 54 41 54 55 53.
Print out or return the consecutive degree turns the camera will need to make in order to point at each card and return to the "Question Card". For our example, this would be:
6  * 21 = 126   (?-5)
-2 * 21 = -42   (5-3)
2  * 21 = 42    (3-5)
-1 * 21 = -21   (5-4)
0  * 21 = 0     (4-4)
-3 * 21 = -63   (4-1)
4  * 21 = 84    (1-5)
-1 * 21 = -21   (5-4)
1  * 21 = 21    (4-4)
0  * 21 = 0     (5-5)
0  * 21 = 0     (5-5)
-2 * 21 = -42   (5-3)
-4 * 21 = -84   (3-?)

Or, in array format:
[126, -42, 42, -21, 0, -63, 84, -21, 21, 0, 0, -42, -84]

Note that you must always take the smallest of the possible rotations. So if the input was NO, which is 4E 4F, you should output:
5    * 21 = 105
-7   * 21 = -147
7    * 21 = 147
-6   * 21 = -126
1    * 21 = 21

Rather than:
 5   * 21 = 105
 10  * 21 = 210
 -10 * 21 = -210
 11  * 21 = 231
 -16 * 21 = -336

Here are some more worked examples:
Input: CROPS?
ASCII: 43 52 4F 50 53 3F
Worked Example:

5  * 21 = 105
-1 * 21 = -21
2  * 21 = 42
-3 * 21 = -63
2  * 21 = 42
-6 * 21 = -126
7  * 21 = 147
-5 * 21 = -105
5  * 21 = 105
-2 * 21 = -42
0  * 21 = 0
-5  * 21 = -105
1 * 21 = 21

Result: [105 -21 42 -63 42 -126 147 -105 105 -42 0 -105 21]

Input: DDD
ASCII: 44 44 44
Worked Example:

5   * 21 = 105
0   * 21 = 0
0   * 21 = 0
0   * 21 = 0
0   * 21 = 0
0   * 21 = 0
-5  * 21 = -105

Result: [105, 0, 0, 0, 0, 0, -105]

Input: Hello world!
ASCII: 48 65 6c 6c 6f 20 77 6f 72 6c 64 21
Worked example:

5   * 21 = 105
4   * 21 = 84
-2  * 21 = -42
-1  * 21 = -21
1   * 21 = 21
6   * 21 = 126
-6  * 21 = -126
6   * 21 = 126
-6  * 21 = -126
-8  * 21 = -168
4   * 21 = 84
-2  * 21 = -42
7   * 21 = 147
0   * 21 = 0
-1  * 21 = -21
-8  * 21 = -168
-8  * 21 = -168
-5  * 21 = -105
4   * 21 = 84
6   * 21 = 126
-6  * 21 = -126
-2  * 21 = -42
-2  * 21 = -42
-1  * 21 = -21
-2  * 21 = -42

Result: [105 84 -42 -21 21 126 -126 126 -126 -168 84 -42 147 0 -21 -168 -168 -105 84 126 -126 -42 -42 -21 -42]

Since NASA prides itself on efficiency, your goal is to write the shortest code possible. Standard loopholes apply. Now bring him home!

Side note: These test cases were made by hand, and were kind of a pain, so there might be some minor inaccuracies. Please let me know if anything looks wrong. :)

Related

JavaScript (ES6), 103 99 bytes
s=>[...s.replace(/./g,c=>c.charCodeAt().toString(16)),10].map(n=>((24-p-~(p='0x'+n))%17-8)*21,p=-1)

Test cases

let f =
s=>[...s.replace(/./g,c=>c.charCodeAt().toString(16)),10].map(n=>((24-p-~(p='0x'+n))%17-8)*21,p=-1)

let g = s => console.log(`f('${s}'): [${f(s)}]`)
g('STATUS')
g('NO')
g('CROPS?')
g('DDD')
g('Hello world!')

Would this work? s.replace(/./g, -> [...s].map(

@Luke Nope, because we need to separate out each hexadecimal digit. ...s.replace(/./g, gives e.g. "4","8","6","5","6","c"..., while. ...[...s.map( would give "48","65","6c",...

C, 212 202 199 187 bytes
3 bytes saved thanks to @KritixiLithos!
i;f(a,b){i=abs(a-b);i=8>i?i:17-i;i=a<b&a>b-8?i:a<b&a<b-8?-i:b<a&b>a-8?-i:i;i*=21;}v;g(char*s){for(v=0;*s;s+=v++%2)printf("%d ",v?v%2?f(*s%16,s[1]?s[1]/16:-1):f(*s/16,*s%16):f(-1,*s/16));}

Try it online!

I think you can do 8>i?i:17-i instead of 17-i>i?...

@KritixiLithos yup, thanks.

Python, 187 178 bytes
def g(x):w,z=map('?0123456789abcdef'.index,x);d=w-z;return min(d,d+17*(d<=0 or -1),key=abs)*21
def f(s):s=''.join(map('{:2x}'.format,s.encode()));return[*map(g,zip(s+'?','?'+s))]

Test cases
for k in ['STATUS', 'NO', 'CROPS?', 'DDD', 'Hello world!']:
    print('Input:  {}\nOutput: {}'.format(k, f(k)))

Python 2, 135 112 bytes
h=reduce(lambda l,r:l+(r/16,r%16),map(ord,input()),())
print[(((r-l+8)%17)-8)*21for l,r in zip((-1,)+h,h+(-1,))]

Try it online!

Jelly, 21 19 bytes
Ob⁴F-;;-I+8%17_8×21

Try it online!
How?
Ob⁴F-;;-I+8%17_8×21 - Main link: string s        e.g. 'e.g.'
O                   - cast to ordinals            [101,     46,       103,      46]
 b                  - convert to base
  ⁴                 -     16                   [[6,   5], [2,  14], [6,   7], [2,  14]]
   F                - flatten                   [6,   5,   2,  14,   6,   7,   2,  14]
    -;              - -1 concatenate      [-1,   6,   5,   2,  14,   6,   7,   2,  14]
      ;-            - concatenate -1      [-1,   6,   5,   2,  14,   6,   7,   2,  14,  -1]
        I           - increments            [  7,  -1,  -3,  12,  -8,   1,  -5,  12, -15]
         +8         - add 8                 [ 15,   7,   5,  20,   0,   9,   3,  20,  -7]
           %17      - mod 17                [ 15,   7,   5,   3,   0,   9,   3,   3,  10]
              _8    - subtract 8            [  7,  -1,  -3,  -5,  -8,   1,  -5,  -5,   2]
                ×21 - multiply by 21        [147, -21, -63,-105,-168,  21,-105,-105,  42]

Ohm, 20 19 bytes (CP437)
EDIT: Saved 1 byte by changing a map block to repeated single-component maps.
Would probably be quite a bit shorter if I had implicit vectorization.
`»x»}{»úΓXΓHδ▓_~21*

Explanation:
`»x»}{»úΓXΓHδ▓_~21*    Main wire, arguments: s

`»x                    Convert char codes of s to hex
   »}                  Split digit pairs
     {                 Flatten
      »ú               Convert digits back to base 10
        ΓXΓH           Append and prepend with -1
            δ          Get deltas between each element of array
             ▓         Map array over...
              _~21*      Negate, multiply by 21

PHP, 125 116 bytes:
function m($i){static$a;$a+=$d=($i-$a+10)%17-9;echo$d*21,"
";}for(;$c=ord($argv[1][$i++]);m($c%16))m($c/16|0);m(-1);

breakdown
function m($i)              // function to turn camera:
{
    static$a;                   // remember angle
    $a+=                        // add delta to angle
    $d=($i-$a+10)%17-9;         // delta: target=nibble value+1-current angle
                                // add 9, modulo 17, -9 -> shortest movement
    echo$d*21,"\n";                 // print delta * 21 and a linebreak
}
for(;$c=ord($argv[1][$i++]);// loop through input characters
    m($c%16))                   // 2. move to low nibble value
    m($c/16|0)                  // 1. move to high nibble value
;
m(-1);                      // move back to "?"

Of course, 21 is pretty inaccurate and may fail for strings longer than 14 characters; but then ... 360/17 would be four bytes longer.

An alternative solution would have been to attach a laser pointer to the camera;
  we could use all printable ascii chars and a "question" card at 3.75 degrees each with that.
Another alternative: Use 16 cards (at 22.5 degrees) with 6 characters each:
  implement some sort of T9 and we can omit the high nibble. ;)

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes


text:
ASCII Bookshelves
You know those stackable shelves that are basically just wooden boxes that can be stacked together? We're going to simulate building some bookshelves out of those with some ASCII art.
Our books are all conveniently uniform in size, and all look like the following:
|X|
|X|
|X|

The bookshelves are individual boxes, always three characters high on the inside (enough to fit a book standing upright), composed of | characters on the left and right, - characters for the top and bottom, and wide enough to fit X books (where X is an input integer). For example, here's a bookshelf of size 3:
|---------|
|         |
|         |
|         |
|---------|

because you can fit 3 books into it like so
|---------|
||X||X||X||
||X||X||X||
||X||X||X||
|---------|

The input is going to be two strictly positive integers, X and Y, where X is the width of the shelves we have (measured in books), and Y is how many books we have to stack. If we have more books than fit on a single shelf, we need to add more shelves to the top. For example, here is input 4 wide / 6 books:
|------------|
||X||X|      |
||X||X|      |
||X||X|      |
|------------|
|------------|
||X||X||X||X||
||X||X||X||X||
||X||X||X||X||
|------------|

If Y % X > 0, meaning the number of books is not an integer multiple of the shelf size, the remainder books should go on the top-most left-most position (as in the case with 4 6, above) and the remaining part of that shelf filled in with spaces.
Input

Two strictly positive integers in any convenient format, each >0.
You can take the input in either order (e.g., size of shelves first, then number of books, or vice versa). Please state in your submission the input order.
You can safely assume that neither input will be larger than your language's default [int] size (or equivalent).

Output
The resulting ASCII art representation of the books and bookshelves.
Rules

Leading or trailing newlines or whitespace are all optional, so long as the characters themselves line up correctly.
Either a full program or a function are acceptable. If a function, you can return the output rather than printing it.
If possible, please include a link to an online testing environment so other people can try out your code!
Standard loopholes are forbidden.
This is code-golf so all usual golfing rules apply, and the shortest code (in bytes) wins.

Further Examples
6 wide / 2 books
|------------------|
||X||X|            |
||X||X|            |
||X||X|            |
|------------------|

2 wide / 6 books
|------|
||X||X||
||X||X||
||X||X||
|------|
|------|
||X||X||
||X||X||
||X||X||
|------|
|------|
||X||X||
||X||X||
||X||X||
|------|

4 wide / 9 books
|------------|
||X|         |
||X|         |
||X|         |
|------------|
|------------|
||X||X||X||X||
||X||X||X||X||
||X||X||X||X||
|------------|
|------------|
||X||X||X||X||
||X||X||X||X||
||X||X||X||X||
|------------|

Can I make it so the shelf with the least amount of books is on the bottom, so like it fills top to bottom

@GoldenRatio No, the books must be filled bottom to top, left to right.

JavaScript (ES6), 100 99 98 bytes
Takes the width w and the number of books b in currying syntax (w)(b).
w=>g=(b,s=`|${'-'.repeat(w*3)}|
`,r=s.replace(/---/g,_=>b&&b--?'|X|':'   '))=>(b?g(b)+s:s)+r+r+r+s

Formatted and commented
w =>                                // main function: takes width 'w' as input, returns 'g'
  g = (                             // g = recursive function with:
    b,                              //   - b = number of books
    s = `|${'-'.repeat(w * 3)}|\n`, //   - s = top/bottom of shell, filled with '-'
    r = s.replace(                  //   - r = pattern of the current row of books,
      RegExp('---', 'g'),           //         using 's' as a template and updating
      _ => b && b-- ? '|X|' : '   ' //         'b' while building it
    )                               // NB: 'r' must be defined in the scope of 'g',
  ) =>                              //     otherwise it would be overwritten by
    (                               //     subsequent calls
      b ?                           // if there are remaining books:
        g(b) + s                    //   do a recursive call and append shell top
      :                             // else:
        s                           //   just append shell top
    ) + r + r + r + s               // append book rows and shell bottom

Test cases

let f =

w=>g=(b,s=`|${'-'.repeat(w*3)}|
`,r=s.replace(/---/g,_=>b&&b--?'|X|':'   '))=>(b?g(b)+s:s)+r+r+r+s

console.log(f(6)(2))
console.log(f(2)(6))
console.log(f(4)(9))

Bash (+utilities), 130, 108, 106 bytes
A single, continuous, shell pipeline to render your bookshelves.
Changelog:

Optimized first sed expression a bit, -12 bytes (Thx @Riley !)
Replaced printf + seq with a raw printf, -10 bytes
Refactored the second sed expression, -2 bytes

Golfed
printf %$2s\\n|fold -$1|sed "s/ /|X|/g;:;/.\{$[$1*3]\}/!s/$/ /;t;h;s/./-/gp;x;p;p;p;x"|sed 's/.*/|&|/'|tac

$./shelf 6 8
|------------------|
||X||X|            |
||X||X|            |
||X||X|            |
|------------------|
|------------------|
||X||X||X||X||X||X||
||X||X||X||X||X||X||
||X||X||X||X||X||X||
|------------------|

Try It Online !
How It Works
$./shelf 2 3
printf %$2s\\n - generate n whitespace characters, one per book (shown as _)
___
fold -$1 - fold them by the shelf length
__
_

sed "s/ /|X|/g;" - replace _ with X, add book covers
|X||X|
|X|

:;/.\{$[$1*3]\}/!s/$/ /;t - right pad with spaces (shown as _)
|X||X|
|X|___

h;s/./-/gp;x;p;p;p;x - triplicate each line, and add --- before and after it.
------
|X||X|
|X||X|
|X||X|
------
------
|X|
|X|
|X|
------

sed 's/.*/|&|/'|tac - wrap lines in | |, reverse with tac
|------|
||X|   |
||X|   |
||X|   |
|------|
|------|
||X||X||
||X||X||
||X||X||
|------|

In the first sed you can use a nameless label, and t instead of b so you don't need the {}. You can skip the s/./-/g because they are already -s. Try it Online!

@Riley That's an excellent advice, thank you !

Batch, 261 bytes
@set/an=~-%1%%%2+1,b=%1-n
@set s=
@set t=
@for /l %%i in (1,1,%2)do @call set t=---%%t%%&if %%i gtr %n% (call set s=%%s%%   )else call set s=%%s%%X
@for %%s in ("|%t%|" "|%s:X=|X|%|" "|%s:X=|X|%|" "|%s:X=|X|%|" "|%t%|")do @echo %%~s
@if %b% gtr 0 %0 %b% %2

Uses my trick from my Batch answer to Let's play tennis to easily print lots of | characters.

Python 2, 133 113 105 bytes
I'm sure there's a better way...
X,Y=input()
k='|'+'---'*X+'|'
while Y:g=Y%X or X;print k+'\n'+('|'+'|X|'*g+'   '*(X-g)+'|'+'\n')*3+k;Y-=g

Input is taken width, books
-20 bytes thanks to @ovs for noticing an unnecessary lambda function!
-8 bytes thanks to @ovs for shortening the input.

X,Y=input() is a shorter way to take the to values.

@ovs Oh wait, I put that there for my first try. Whoops. Nice catch, thanks!

@ovs Thanks, so then input is taken as X, Y, right?

I think that you can save two bytes by defining '|' as a variable.

Haskell, 100 bytes
x#y returns the string for width x and y books.
s?n=[1..n]>>s
x#y|x<y=x#(y-x)++x#x|w<-"---"?x,b<-"|X|"?y++"   "?(x-y)=[w,b,b,b,w]>>=('|':).(++"|\n")

Try it online!
The main function/operator is #. When x<y it splits the books into y-x and x, then recurses. When x>=y, w and b are the two line types, minus the outer |s and the newline.
The helper operator s?n concatenates n copies of the string s.

PowerShell, 149 134 bytes
param($w,$b)$s="|$('-'*$w*3)|"
if($a=$b%$w){,$s+,"|$('|X|'*$a)$(' '*3*($w-$a))|"*3+$s}
if($b-=$a){(,$s+,"|$('|X|'*$w)|"*3+$s)*($b/$w)}

Try it online!
Takes input $width and $books. Sets string $s to be one of the horizontal shelves. Then we have two if statements.
The first checks whether we have "remainder" books. If so, we output the shelf, the (number of books plus number of spaces)*3, and another shelf.
Next, we see if we still have books remaining after removing the remainders ($a). Same sort of setup, except we're using $w number of books. Since at this point, $b is guaranteed to be a multiple of $w (because we removed the remainder, $a), we don't need to worry about rounding.
Removed the [math]::Floor() call, saving 15 bytes
All of these strings are left on the pipeline, and implicit Write-Output happens at program completion.

Python 3, 142 bytes
Still working on it. b is for 'number of books' and w is for shelf width.
def s(b,w):
 R=b%w
 B='|\n'
 I='|'
 X='|X|'
 d=I+3*w*'-'+B
 f=I+X*w+B
 p=I+R*X+3*(w-R)*' '+B
 print(R and d+3*p+d or" ")+b//w*(d+3*f+d))

Welcome to PPCG! This doesn't work for me unless R=b%w is moved down to the next line. Also, you should be able to remove the whitespace around those three = to save some bytes.

Welcome to PPCG!

You can replace d+3*p+d if R!=0 else '' with R and d+3*p+d or''

@shooqie I'm curious, how could this evaluate to the result of d+3*p+d?

I actually asked this very question earlier on Stack Overflow:
http://stackoverflow.com/questions/39080416/x-and-y-or-z-ternary-operator

You can save a few bytes by putting all the definitions in one line using semicolons.

CJam, 62 61 bytes
q~1a*W$/W$f{0e]}{{"|X|"S3*?}%s__'-3*W$*_}%1m>W%"|
|"*"||"\*o;

Takes input as width books
Try it online!
Explanation
q~           Read and eval input (pushes width W and books B to the stack)
1a*          Push an array containing  the number 1 B times
W$/          Split it into chunks of size W
W$f{0e]}     Pad each chunk to width W by adding 0's to the right (the last chunk might be
              shorter than W)
{            Apply the following to each chunk:
 {            Apply the following to each number in the chunk:
  "|X|"S3*?    Push "|X|" if the number is 1, or "   " if it's 0
 }%           (end of block)
 s            Stringify (joins with no separator)
 __           Duplicate twice (each shelf is 3 identical lines)
 '-3*W$*_     Push a string containing '-' repeated 3×W times, then duplicate it
}%           (end of block)
              At this point we have an array containing sequences of 3 identical lines
              each followed by two lines of -'s
1m>          Rotate the array 1 to the right; brings the final line of -'s to the start
W%           Reverse the array, so that the top shelf is the partially empty one
"|\n|"*      Join the array with the string "|\n|", to build the sides of the shelves
"||"\*       Join the string "||" with the shelf string (adds the first and last | chars)
o            Print the result
;            Pop and discard W

AHK, 208 bytes
AutoTrim,Off
w=%1%
b=%2%
f:=Mod(b,w)
Loop,%w%
s=%s%---
s=|%s%|`n
If (f>0) {
Loop,%f%
t=%t%|X|
Loop,% w-f
t=%t% ` ` `
t=|%t%|`n
t:=s t t t s
}
Loop,%w%
r=%r%|X|
r=|%r%|`n
Loop,% (b-f)/w
t:=t s r r r s
Send,%t%

There are a few things frustating me from golfing further:

AutoHotkey doesn't have a built-in repeat function
You can't directly use the passed in arguments (%1% & %2%) in math functions because those expect variable or number input and it will assume the unescaped 1 to be the number one rather than the variable name
I am not very good at golfing

An easier to read version of the above looks like this:
AutoTrim,Off
w=%1%
b=%2%
f:=Mod(b,w)

Loop,%w%
   s=%s%---
s=|%s%|`n

If (f>0) {
   Loop,%f%
      t=%t%|X|
   Loop,% w-f
      t=%t% ` ` `
   t=|%t%|`n
   t:=s t t t s
}

Loop,%w%
   r=%r%|X|
r=|%r%|`n

Loop,% (b-f)/w
   t:=t s r r r s

Send,%t%

If a Loop doesn't use brackets {}, then only the next line is part of the loop. If setting a variable's value using := instead of =, you can drop the percent sign escape characters. Tilde n is the newline character.

Java 7, 230 224 222 bytes
String c(int w,int b){String r="",n="|\n",z="|";int i=0,j,k,t=b%w<1?w:b%w,x=b/w+(t!=w?1:0);for(;i++<w;z+="---");z+=n;for(i=0;i<x;i++){r+=z;for(j=0;j++<3;r+=n){r+="|";for(k=0;k<w;r+=i<1&k++>=t?"   ":"|X|");}r+=z;}return r;}

Explanation:
String c(int w, int b){                // Method with two integer parameters and String return-type
  String r = "",                       //  The return-String
         n = "|\n",                    //  Part that's used multiple times in the code
         z = "|";                      //  Shelf part of the book-boxes
  int i = 0, j, k,                     //  Indexes used in the for-loops
      t = b%w < 1 ? w : b%w,           //  Books on top shelf
      x = b/w + (t != w ? 1 : 0);      //  Amount of shelves
  for(; i++ < w; z += "---"); z += n;  //  Create the shelf-part ("|---|"; with w times "---")
  for(i = 0; i < x; i++){              //  Loop over the rows
    r += z;                            //   Append the result with the shelf-part
    for(j = 0; j++ < 3; ){             //   Loop three times (the height of the books & boxes)
      r += "|";                        //    Append the result-String with "|"
      for(k = 0; k < w;                //    Loop over the columns
          r +=                         //     And append the result-String with:
           i < 1                       //      If this is the first row:
           & k++ >= t ?                //      And the current column is larger or equal to the amount of books in the top shelf
             "   "                     //       Use an empty space
           :                           //      Else:
             "|X|"                     //       Use the book-part
            );                         //    End of columns loop
         r += n;                       //    Append the result-String with a "|" and a new-line
       }                               //   End of the loop of three
      r += z;                          //   Append the result-String with the shelf-part
    }                                  //  End of rows loop
    return r;                          //  Return the result-String
 }                                     // End of method

Test code:
Try it here.
class M{
  static String c(int w,int b){String r="",n="|\n",z="|";int i=0,j,k,t=b%w<1?w:b%w,x=b/w+(t!=w?1:0);for(;i++<w;z+="---");z+=n;for(i=0;i<x;i++){r+=z;for(j=0;j++<3;r+=n){r+="|";for(k=0;k<w;r+=i<1&k++>=t?"   ":"|X|");}r+=z;}return r;}

  public static void main(String[] a){
    System.out.println(c(6, 2));
    System.out.println(c(2, 6));
    System.out.println(c(4, 9));
  }
}

Output:
|------------------|
||X||X|            |
||X||X|            |
||X||X|            |
|------------------|

|------|
||X||X||
||X||X||
||X||X||
|------|
|------|
||X||X||
||X||X||
||X||X||
|------|
|------|
||X||X||
||X||X||
||X||X||
|------|

|------------|
||X|         |
||X|         |
||X|         |
|------------|
|------------|
||X||X||X||X||
||X||X||X||X||
||X||X||X||X||
|------------|
|------------|
||X||X||X||X||
||X||X||X||X||
||X||X||X||X||
|------------|

I don't know how, but it looks like lambdas and .repeat really, really help in this challenge.

@OlivierGrégoire Considering I posted this about about 1.5 year ago, I'm not surprised it can be golfed quite substantially. ;)

Ow... I hadn't checked the date: I only saw that this question was active and that a full other algorithm for Java was possible. My bad...

@OlivierGrégoire No problem, and well done with your answer. :) It almost feels nostalgic looking back at this answer when I was still adding the test cases and output to the answer, and answered everything in Java 7, because I didn't understand Java 8 yet. XD

PowerShell, 109 bytes
param($w,$b)for(;$b;$b-=$c){if(!($c=$b%$w)){$c=$w}($l="|$('-'*$w*3)|")
,"|$('|X|'*$c)$(' '*($w-$c)*3)|"*3
$l}

Less golfed test script:
$f = {

param($w,$b)
for(;$b;$b-=$c){
    if(!($c=$b%$w)){$c=$w}
    ($l="|$('-'*$w*3)|")
    ,"|$('|X|'*$c)$(' '*($w-$c)*3)|"*3
    $l
}

}

@(
    ,(6, 2,
    "|------------------|",
    "||X||X|            |",
    "||X||X|            |",
    "||X||X|            |",
    "|------------------|")

    ,(2, 6,
    "|------|",
    "||X||X||",
    "||X||X||",
    "||X||X||",
    "|------|",
    "|------|",
    "||X||X||",
    "||X||X||",
    "||X||X||",
    "|------|",
    "|------|",
    "||X||X||",
    "||X||X||",
    "||X||X||",
    "|------|")

    ,(4, 9,
    "|------------|",
    "||X|         |",
    "||X|         |",
    "||X|         |",
    "|------------|",
    "|------------|",
    "||X||X||X||X||",
    "||X||X||X||X||",
    "||X||X||X||X||",
    "|------------|",
    "|------------|",
    "||X||X||X||X||",
    "||X||X||X||X||",
    "||X||X||X||X||",
    "|------------|")
) | % {
    $w,$b,$expected = $_
    $result = &$f $w $b
    "$result"-eq"$expected"
    $result
}

Output:
True
|------------------|
||X||X|            |
||X||X|            |
||X||X|            |
|------------------|
True
|------|
||X||X||
||X||X||
||X||X||
|------|
|------|
||X||X||
||X||X||
||X||X||
|------|
|------|
||X||X||
||X||X||
||X||X||
|------|
True
|------------|
||X|         |
||X|         |
||X|         |
|------------|
|------------|
||X||X||X||X||
||X||X||X||X||
||X||X||X||X||
|------------|
|------------|
||X||X||X||X||
||X||X||X||X||
||X||X||X||X||
|------------|

PowerShell, 109 bytes, alternative
param($w,$b)for(;$b;$b-=$c){($l="|$('---'*$w)|")
,"|$('|X|'*($c=(($b%$w),$w-ne0)[0]))$('   '*($w-$c))|"*3
$l}

Python 2, 120 118 bytes
i,j=input()
a=j%i
n='|\n'
x='|'+'---'*i+n
print(x+('|'+'|x|'*a+' '*(i-a)*3+n)*3,'')[a<1]+(x+('|'+'|x|'*i+n)*3)*(j/i)+x

Try it online!
Have been meaning to have a go at this one for the last few days. Now that I have finally got time to do it there's already a shorter Python answer. Oh well, just posted as an alternative.
Input taken as width,books

SOGL, 64 bytes
be%→M"Q└ƨS‘*ač;┼→S%‘A |e3* -* |++M?tMSeM-9*@*a+┼Ot}be÷:?{teSa┼Ot

Explanation:
First function:
   →M  define function M which pushes
b      the book amount
  %    mod
 e     the bookshelf width

second function:
           →S  create function S (example input: 3)          [3]
"Q└ƨS‘         push the string "|||XXX|||" (the book)        [3, "|||XXX|||"]
      *        multiply by the number on stack (book count)  ["|||XXX||||||XXX||||||XXX|||"]
       a       push variable A (later defined "|||")         ["|||XXX||||||XXX||||||XXX|||", "|||"]
        č      chop into char array                          ["|||XXX||||||XXX||||||XXX|||", ["|", "|", "|"]]
         ;     swap top 2 on stack                           [["|", "|", "|"], "|||XXX||||||XXX||||||XXX|||"]
          ┼    horizontally append                           [["||X||X||X|", "||X||X||X|", "||X||X||X|"]]

this function expects a number (book count) on stack and outputs the bookshelfs books
["||X||X||X|",
 "||X||X||X|",
 "||X||X||X|"]

Further down example given is e=3 (bookshelf width) and b=8 (book amount)
%‘A              var A = "|||"
    |            push "|"                      ["|"]
     e3*         push E * 3                    ["|", 9]
         -*      push that many "-"es          ["|", "---------"]
            |+   append "|"                    ["|", "---------|"]
              +  prepend the "|"               ["|---------|"]

this is the bookshelf top/bottom line and always stays on the stack
first part (half-empty bookshelf)
First main part
M?               }               if the modulo != 0
  tM                             output the bookshelf top/bottom line
    S                            execute the S function width the modulo
     eM-                         push bookshelf width - modulo (empty space count)
        9*                       multiply by 9 (books are 3x3 so 3x3 spaces)
          @*                     get that many spaces
            a+                   append to that "|||"
              ┼                  horizontally append
               O                 output
                t                output the bookshelf top/bottom line

And the last part
be÷            floor divide book amout by width (full shelves)
   :?          if not 0 (a bug makes all loops execute once)
     {         repeat
      t        output the bookshelf top/bottom line
       eS      execute S with shelf width (full shelf)
         a┼    horizontally append "|||"
           O   output
            t  output the bookshelf top/bottom line

Java (JDK), 124 bytes
s->b->{for(int i=0;i++<(b-~s)/s*5;)System.out.printf("|%-"+s*3+"s|%n",i%5<2?"-".repeat(s*3):"|X|".repeat(i<5&b%s>0?b%s:s));}

Try it online!
Credits

-2 bytes thanks to ceilingcat

PHP>=7.1, 138 Bytes
for([,$w,$b]=$argv;$i<ceil($b/$w)*5;)echo str_pad("|".str_repeat(["","|X|"][$t=($i+1)%5>1],$i++<5&&$b%$w?$b%$w:$w),$w*3+1,"- "[$t])."|\n";

Online Version

Canvas, 33 bytes
|X|３＊×⁷３×⇵-×|３＊×╫│；２２╋Ｐ
％？％⁸｝÷［⁷⁸

Try it here!
Explanation (some characters have been replaced to look more monospace):
|X|3*×⁷3×⇵-×|3*×╫│;22╋P  helper function. Prints a shelf with X books
|X|                      push "|X|"
   3*                    repeat it 3 times vertically
     ×                   repeat that horizontally by the item (X) below on the stack
      ⁷3×                push width * 3
         ⇵               ceiling divide that by 2
          -×             repeat "-" that many times
            |3*          repeat "|" vertically 3 times (aka "|¶|¶|")
               ×         prepend that to the dashes (aka ¼ of a bookshelf)
                ╫│       quad-palindromize with horizontal overlap of the remainder
                           taken before and vertical overlap of 1
                  ;      get the books on top
                   22╋   and at coordinates (2;2) in the shelf, place them in
                      P  print that whole thing

%?%⁸}÷[⁷⁸
%?  }      if width%amount (!= 0)
  %⁸         execute the helper function with width%amount on the stack
     ÷[    repeat floor(width/amount) times
       ⁷     push width
        ⁸    execute the helper function

Pip -n, 45 bytes
Wb-:yPPZ['-X3Xa"|X|"X(Yb%a|a).sX3Xa-yRL3]WR'|

Takes the width and book count, respectively, as command-line arguments. Try it online!
Explanation
We run a loop to print the shelves one by one from top to bottom. At each iteration, we update b (the number of books to print) by subtracting y (the number of books printed on that iteration). When b reaches 0, the loop exits.
Wb-:yPPZ['-X3Xa"|X|"X(Yb%a|a).sX3Xa-yRL3]WR'|
                                               a is 1st cmdline arg (shelf width); b is 2nd cmdline
                                                 arg (# books); s is space; y is ""
                                               Note that "" becomes zero in numeric contexts
Wb-:y                                          While b decremented by y is nonzero:
                       b%a|a                    b mod a, or a if that quantity is zero
                      Y                         Yank that value into y
                     (      )                   This is the number of books on the current shelf
               "|X|"                            Book-spine string
                    X                           Repeated y times
                                  a-y           Number of empty slots on the current shelf
                              sX3X              Three spaces for each slot
                             .                  Concatenate to the book-spines string
                                     RL3        Make a list of 3 copies of that string
         '-X3Xa                                 3*a hyphens
        [                               ]       Put that string and the above list in a list
                                         WR'|   Wrap all strings in the nested list in |
      PZ                                        Palindromize the outer list (adding a copy of the
                                                hyphens to the end of it)
     P                                          Print, joining all sublists on newlines (-n flag)

Because that's a little involved, here's an example of the first iteration when a = 3, b = 8:
Yb%a|a       2
"|X|"X ^     "|X||X|"
^ .sX3Xa-y   "|X||X|   "
^ RL3        ["|X||X|   ";"|X||X|   ";"|X||X|   "]
['-X3Xa ^ ]  ["---------";["|X||X|   ";"|X||X|   ";"|X||X|   "]]
^ WR'|       ["|---------|";["||X||X|   |";"||X||X|   |";"||X||X|   |"]]
PZ ^         ["|---------|";["||X||X|   |";"||X||X|   |";"||X||X|   |"];"|---------|"]

which then prints as
|---------|
||X||X|   |
||X||X|   |
||X||X|   |
|---------|

Pyth, 56 bytes
M++GHGV_fTs*V,]Q1.DEQjCg*5\|smgL\-*L3?d"|X|""   ".[*]1N0

Accepts shelf width, book count as separate arguments in that order. Try it online here, or verify all the test cases at once here.
M++GHGV_fTs*V,]Q1.DEQjCg*5\|smgL\-*L3?d"|X|""   ".[*]1N0Q   Implicit: Q=1st arg, E=2nd arg
                                                            Trailing Q inferred
M                                                           Define a function, g(G,H):
 ++GHG                                                        Return G + H + G
                 .DEQ                                       Divmod E by Q, yields [E//Q, E%Q]
             ,]Q1                                           [[Q], 1]
           *V                                               Vectorised multiply the two previous results
                                                              This yields Q repeated E//Q times, then E%Q
          s                                                 Flatten
        fT                                                  Filter out falsey values (i.e. trailing 0 if present)
       _                                                    Reverse (to put partially filled shelf on top)
      V                                                     For N in the above:
                                                    ]1        [1]
                                                   *  N       Repeat the above N times
                                                 .[    0Q     Pad the above on the right with 0, to length Q
                             m                                Map the above, as d, using:
                                     ?d"|X|""   "               If d != 0, yield "|X|", else "   "
                                  *L3                           Multiply each char by 3
                                                                  Yields ['|||','XXX','|||'] or ['   ','   ','   ']
                              gL\-                              Use g to wrap each element in '-'
                            s                                 Flatten
                       g*5\|                                  Use g to add '|||||' to start and end of the above
                      C                                       Transpose
                     j                                        Join on newlines, implicit print

Forth (gforth), 622 bytes (minimized (remove comments, indentation, 1-char word names) to 303 bytes)
My first play with Forth :)
: bar 124 EMIT ;

: delimline ( width -- )
    bar
    3 * 0 DO 45 EMIT LOOP
    bar CR
;

: bookline ( width books -- )
    bar
    DUP 0 DO bar 88 EMIT bar LOOP
    2DUP = IF
        DROP DROP
    ELSE
        - 0 do 3 SPACES LOOP
    THEN
    bar CR
;

: shelf ( width books -- )
    DUP 0 = IF
        DROP DROP
    ELSE
        OVER delimline
        3 0 DO OVER OVER bookline LOOP
        DROP delimline
    THEN
;

: stack ( width books -- )
    CR
    OVER OVER OVER MOD shelf
    OVER /
    DUP 0 = IF
        DROP DROP
    ELSE
        0 DO DUP DUP shelf LOOP
    THEN
;

6 2 stack
2 6 stack
3 5 stack
4 4 stack

Try it online!
Output

|------------------|
||X||X|            |
||X||X|            |
||X||X|            |
|------------------|

|------|
||X||X||
||X||X||
||X||X||
|------|
|------|
||X||X||
||X||X||
||X||X||
|------|
|------|
||X||X||
||X||X||
||X||X||
|------|

|---------|
||X||X|   |
||X||X|   |
||X||X|   |
|---------|
|---------|
||X||X||X||
||X||X||X||
||X||X||X||
|---------|

|------------|
||X||X||X||X||
||X||X||X||X||
||X||X||X||X||
|------------|


text:
Find the Fibonacci Kernel
You've probably heard of the Fibonacci numbers; they're pretty famous.  Each number in the Fibonacci sequence is the sum of the last two in the sequence with the first and second numbers being 1.  The sequence looks like this:
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025 121393 196418 317811 514229 832040 1346269 2178309 3524578 5702887 9227465 14930352 24157817 39088169 63245986 102334155 165580141 267914296 433494437 701408733 1134903170 1836311903 2971215073 4807526976 7778742049 12586269025 20365011074 32951280099 53316291173 86267571272 139583862445 225851433717 365435296162 591286729879 956722026041 1548008755920 2504730781961 4052739537881 6557470319842 10610209857723 17167680177565 27777890035288 44945570212853 72723460248141 117669030460994 190392490709135 308061521170129 498454011879264 806515533049393 1304969544928657 2111485077978050 3416454622906707 5527939700884757 8944394323791464 14472334024676221 23416728348467685 37889062373143906 61305790721611591 99194853094755497 160500643816367088 259695496911122585 420196140727489673 679891637638612258 1100087778366101931 1779979416004714189 2880067194370816120 4660046610375530309 7540113804746346429 12200160415121876738 19740274219868223167 31940434634990099905 51680708854858323072 83621143489848422977 135301852344706746049 218922995834555169026 354224848179261915075 573147844013817084101 927372692193078999176 1500520536206896083277 2427893228399975082453 3928413764606871165730 6356306993006846248183 10284720757613717413913 16641027750620563662096 26925748508234281076009 43566776258854844738105 70492524767089125814114 114059301025943970552219 184551825793033096366333 298611126818977066918552 483162952612010163284885 781774079430987230203437 1264937032042997393488322

Similarly, Lucas sequences are the result of substituting the rather arbitrary 1 1 that start the Fibonacci sequence with any two arbitrary integers.  Additionally unlike the Fibonacci sequence Lucas sequences also go backwards infinitely.  For example 1 1 not only generates all of the numbers in the Fibonacci sequence but all the numbers that would lead up to it:
... 13 -8 5 -3 2 -1 1 0 1 1 2 3 5 8 13 ...

The Kernel of a Lucas sequence is the closest two consecutive members of the sequence.  For example the Kernel of the Fibonacci sequence is 1 1 because they are 0 apart and thus must be the closest two numbers.
The size of the Kernel is measured as the absolute difference between the two members of the Kernel.
Since every pair of numbers is generated by at least one Lucas Sequence, and each sequence has a unique Kernel, for each pair of numbers there is a set of Kernels that generate them.  The smallest Lucas Kernel is the smallest Kernel that generates two numbers.
For example take 8 and 21.
Here are a couple of sequences that have both 8 and 21 in them:
... 1 1 2 3 5 8 13 21 ...
... 18 -5 13 8 21 29 50 79 ...
... 21 -13 8 -5 3 -2 1 -1 0 -1 -1 ...
... 34 -13 21 8 29 37 68 ...

Now if we find the Kernels of each of these sequences we get:
1 1
13 8
-1 -1
29 37

The smallest Kernels are 1 1 and -1 -1 (they are tied).  We can know this without checking any other sequences because they are of size 0 and it is impossible to find any Kernels smaller than size 0.
Task
Given two integers determine the smallest Lucas Kernel that generates them.
This is a code-golf question so the goal is to write code that performs this task in as few bytes as possible.
Standard input and output formats are accepted and enforced.  You must handle negative numbers.
In cases where there are multiple valid solutions you need only output one
Test Cases
8   21 -> 1   1
137 66 -> 66  67
45  80 -> 43  45
-6  45 -> 39  45
37 149 -> 18  19
37  97 -> -2  -3

Related

Also related

These are the numbers that follow the smallest member in the sequence in absolute value, right?

@xnor I am not sure what you are asking.

I think what xnor is asking is how you determine which Lucas kernel is the smallest.

No, I mean how smallest is defined here. How do you compare two kernels a b and c d?

@Dennis Oh that is the absolute difference between the two members of the Kernel, I will update the question to be more explicit.

I meant that any two consecutive elements a,b are preceded by b-a, so them having the smallest absolute different means that preceding element is the smallest element in the sequence in absolute value.

@xnor I see what you are saying.  That is not True however.  If a, b is a Kernel it could also be followed by the item with the smallest absolute value.  However the converse is True, the item with the smallest absolute value will always be followed by a Kernel.

I believe the answer for the test case 45 80 should actually be 43 45, seeing as that kernel has only a difference of 2 and would generate the sequence:
... -119, 80, -39, 41, 2, 43, 45, 88 ...

@notjagan Good catch I realize where I went wrong.

Python 2, 444 391 372 bytes
Crossed out 444 is still regular 444 ;(
Huge thanks to @Dennis for a whopping -52 -71 bytes!
k=lambda c,a,b:abs(a+c*a-c*b)-c<abs(b-a)>0and k(c,b-c*a,a+b-c*b)or(a,b)
def f(*t):
 a,b=sorted(t);m=b-a+1,0;g=lambda _:min([k(1,*k(0,*s)),m][_!=b:],key=lambda(x,y):abs(x-y))
 if b<0:x,y=f(-a,-b);return-x,-y
 for c in range(-b,b+1):
    for s in(c,a),(a,c):
     x,y=s
     if min(s)>0:
        while y<b:x,y=y,x+y
        m=g(y)
     x,y=s
     while(x!=b)&((x>b)^(b>0)):x,y=y-x,x
     m=g(x)
 return m

Try it online!
The solution can be run by calling f(a, b) on the two input integers. It is based on the idea that if both a and b are within at least one of the same sequence (where a and b are ordered beforehand such that a ≤ b), it follows that there is at least one integer c equivalent to an adjacent value of a in a shared sequence of a and b for which the sequence generated by a and c contains b in it.
Furthermore, if at least one of the two integers is positive, all values of c must be bounded by -b ≤ c ≤ b for it to even be possible to generate the value of b on either side of the starting pair. Thus, the solution simply brute-forces values of c between -b and b that in combination with a are capable of generating b within the sequence, and finds the one for which the difference of the kernel values for a and c are minimal (this is possible because finding the kernel for two adjacent numbers in a sequence is trivial).
If neither a nor b is positive, the solution simply negates both and returns the negative of the kernel generated for the negated pair.

Very impressive! A few golfing suggestions.

I am a little confused by your explanation, particularly how you are defining c.

@WheatWizard To clarify my definition (which I realize now is brutally wordy), here's an example. Say we have 8 and 21, and we define a = 8 and b = 21. By the premise of the problem, they both share at least one Lucas sequence. Let's say we examine the one generated by the kernel 1, 1, which contains both 8 and 21. In this sequence, a is adjacent to both 5 and 13, meaning if we were to use either in combination with a, we inherently generate a sequence containing 21. It then just comes down to picking the best c for minimizing kernel difference.

A few more bytes. The output is different, but I think they're equivalent.

APL (Dyalog Unicode), 81 75 bytes
⌊{⌽q⊃⍨⊃⍋|-/¨q←⊃,/2,/¨p/⍨B∊¨p←2(+/⍤↑,⊢,¯2-/⍤↑⊢)⍣{∧/B≤|¯2↑1⌽⍵}¨⍺,¨(-,⊢)⍳B←⍵}⌈

-6 bytes thanks to @Adám
Try it online!
Explanation
This performs a similar algorithm as @notjagan's answer. For each C between -B and B inclusive, it produces the Lucas sequence containing A,C (where A and B are the minimum and maximum of the two arguments, respectively).
The part where this solution gets interesting is how the Lucas sequences and kernels are computed. Since a Lucas sequence is infinite, we can only generate a finite number of terms. Starting with A,C, we add one term to the beginning and one term to the end until the subsequence computed includes (at minimum) all terms with absolute value at most B (and thus B, iff the Lucas sequence contains B) and includes the kernel. This occurs if the beginning and end of the subsequence have absolute value at least B and the subsequence has at least 4 terms.
⌊{ ... B←⍵}⌈  ⍝ Find ⍺=min(x, y); B=max(x, y):
  (-,⊢)⍳B     ⍝ (-1,-2,-3...-B,1,2,3,..B)
                ⍝ (Don't need 0 since sequence from (A,0) is same as (A,A), which occurs since A≤B)
  ⍺,¨           ⍝ Prepend ⍺ to each to get all possible (A, C) pairs
   ... ¨        ⍝ For each (A, C) pair:
    2(+/⍤↑,⊢,¯2-/⍤↑⊢)     ⍝ Extend the Lucas sequence once in each direction
                          ⍝ (This is the reverse of the normal recurrence, so f(a-1) = f(a) + f(a+1)):
      +/2↑,               ⍝ Sum of the left two,
            ⊢             ⍝ Existing sequence,
              ¯2-/⍤↑⊢     ⍝ Difference of the last two
    ⍣{    ..         }  ⍝ Extend until:
      ∧/B≤|¯2↑1⌽⍵         ⍝ The element with minimum absolute value is not one of the two endpoints
                          ⍝ (At this point, the sequence must contain B if it ever will,
                          ⍝ and it must contain the element with minimum absolute value,
                          ⍝ so the kernel is just pair of elements with minimum absolute difference)
  p/⍨B∊¨p←          ⍝ Filter for those that contain B
  2,/¨              ⍝ Find all consecutive pairs of terms in each sequence
  ⌽q⊃⍨⊃⍋|-/¨q←⊃,/   ⍝ Choose the pair of terms with minimum absolute difference; it must be a kernel

Removing redundant parentheses, opening unnecessary brackets, using 18.0's atop: 75